mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 12:14:19 +00:00
fix(postinstall): handle broken symlinks during npm install
When upgrading from older CCS versions, ~/.ccs/shared/* directories may exist as broken symlinks (dangling symlinks pointing to deleted targets). Problem: - fs.existsSync() returns false for broken symlinks - fs.mkdirSync() fails with ENOENT because path exists as broken symlink Solution: - Added removeIfBrokenSymlink() helper that detects and removes dangling symlinks using lstatSync (doesn't follow symlinks) + statSync (follows) - Applied to shared directory and all subdirectories before mkdir Fixes npm install error: ENOENT: no such file or directory, mkdir
This commit is contained in:
1 parent
7af0473bc8
commit
81add5a05e
1 file changed
+33
@@ -24,6 +24,35 @@ function getCcsHome() {
|
|||||||
return process.env.CCS_HOME || os.homedir();
|
return process.env.CCS_HOME || os.homedir();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if path is a broken symlink and remove it if so
|
||||||
|
* Fixes: ENOENT error when mkdir tries to create over a dangling symlink
|
||||||
|
* @param {string} targetPath - Path to check
|
||||||
|
* @returns {boolean} true if broken symlink was removed
|
||||||
|
*/
|
||||||
|
function removeIfBrokenSymlink(targetPath) {
|
||||||
|
try {
|
||||||
|
// lstatSync doesn't follow symlinks - it checks the link itself
|
||||||
|
const stats = fs.lstatSync(targetPath);
|
||||||
|
if (stats.isSymbolicLink()) {
|
||||||
|
// Check if symlink target exists
|
||||||
|
try {
|
||||||
|
fs.statSync(targetPath); // This follows symlinks
|
||||||
|
return false; // Symlink is valid
|
||||||
|
} catch {
|
||||||
|
// Target doesn't exist - broken symlink
|
||||||
|
fs.unlinkSync(targetPath);
|
||||||
|
console.log(`[!] Removed broken symlink: ${targetPath}`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch {
|
||||||
|
// Path doesn't exist at all
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate created configuration files
|
* Validate created configuration files
|
||||||
* @returns {object} { success: boolean, errors: string[], warnings: string[] }
|
* @returns {object} { success: boolean, errors: string[], warnings: string[] }
|
||||||
@@ -85,6 +114,8 @@ function createConfigFiles() {
|
|||||||
|
|
||||||
// Create ~/.ccs/shared/ directory structure (Phase 1)
|
// Create ~/.ccs/shared/ directory structure (Phase 1)
|
||||||
const sharedDir = path.join(ccsDir, 'shared');
|
const sharedDir = path.join(ccsDir, 'shared');
|
||||||
|
// Handle broken symlinks (common when upgrading from older versions)
|
||||||
|
removeIfBrokenSymlink(sharedDir);
|
||||||
if (!fs.existsSync(sharedDir)) {
|
if (!fs.existsSync(sharedDir)) {
|
||||||
fs.mkdirSync(sharedDir, { recursive: true, mode: 0o755 });
|
fs.mkdirSync(sharedDir, { recursive: true, mode: 0o755 });
|
||||||
console.log('[OK] Created directory: ~/.ccs/shared/');
|
console.log('[OK] Created directory: ~/.ccs/shared/');
|
||||||
@@ -94,6 +125,8 @@ function createConfigFiles() {
|
|||||||
const sharedSubdirs = ['commands', 'skills', 'agents', 'plugins'];
|
const sharedSubdirs = ['commands', 'skills', 'agents', 'plugins'];
|
||||||
for (const subdir of sharedSubdirs) {
|
for (const subdir of sharedSubdirs) {
|
||||||
const subdirPath = path.join(sharedDir, subdir);
|
const subdirPath = path.join(sharedDir, subdir);
|
||||||
|
// Handle broken symlinks before creating directory
|
||||||
|
removeIfBrokenSymlink(subdirPath);
|
||||||
if (!fs.existsSync(subdirPath)) {
|
if (!fs.existsSync(subdirPath)) {
|
||||||
fs.mkdirSync(subdirPath, { recursive: true, mode: 0o755 });
|
fs.mkdirSync(subdirPath, { recursive: true, mode: 0o755 });
|
||||||
console.log(`[OK] Created directory: ~/.ccs/shared/${subdir}/`);
|
console.log(`[OK] Created directory: ~/.ccs/shared/${subdir}/`);
|
||||||
|
|||||||
Reference in new issue
Block a user