@kaitranntt/ccs 4.4.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -7
- package/VERSION +1 -1
- package/config/base-agy.settings.json +10 -0
- package/config/base-codex.settings.json +10 -0
- package/config/base-gemini.settings.json +10 -0
- package/dist/auth/auth-commands.d.ts +52 -0
- package/dist/auth/auth-commands.d.ts.map +1 -0
- package/dist/auth/auth-commands.js +479 -0
- package/dist/auth/auth-commands.js.map +1 -0
- package/dist/auth/profile-detector.d.ts +68 -0
- package/dist/auth/profile-detector.d.ts.map +1 -0
- package/dist/auth/profile-detector.js +209 -0
- package/dist/auth/profile-detector.js.map +1 -0
- package/dist/auth/profile-registry.d.ts +60 -0
- package/dist/auth/profile-registry.d.ts.map +1 -0
- package/dist/auth/profile-registry.js +188 -0
- package/dist/auth/profile-registry.js.map +1 -0
- package/dist/ccs.d.ts +10 -0
- package/dist/ccs.d.ts.map +1 -0
- package/dist/ccs.js +320 -0
- package/dist/ccs.js.map +1 -0
- package/dist/cliproxy/auth-handler.d.ts +93 -0
- package/dist/cliproxy/auth-handler.d.ts.map +1 -0
- package/dist/cliproxy/auth-handler.js +402 -0
- package/dist/cliproxy/auth-handler.js.map +1 -0
- package/dist/cliproxy/base-config-loader.d.ts +42 -0
- package/dist/cliproxy/base-config-loader.d.ts.map +1 -0
- package/dist/cliproxy/base-config-loader.js +123 -0
- package/dist/cliproxy/base-config-loader.js.map +1 -0
- package/dist/cliproxy/binary-manager.d.ts +104 -0
- package/dist/cliproxy/binary-manager.d.ts.map +1 -0
- package/dist/cliproxy/binary-manager.js +567 -0
- package/dist/cliproxy/binary-manager.js.map +1 -0
- package/dist/cliproxy/cliproxy-executor.d.ts +33 -0
- package/dist/cliproxy/cliproxy-executor.d.ts.map +1 -0
- package/dist/cliproxy/cliproxy-executor.js +297 -0
- package/dist/cliproxy/cliproxy-executor.js.map +1 -0
- package/dist/cliproxy/config-generator.d.ts +89 -0
- package/dist/cliproxy/config-generator.d.ts.map +1 -0
- package/dist/cliproxy/config-generator.js +263 -0
- package/dist/cliproxy/config-generator.js.map +1 -0
- package/dist/cliproxy/index.d.ts +13 -0
- package/dist/cliproxy/index.d.ts.map +1 -0
- package/dist/cliproxy/index.js +62 -0
- package/dist/cliproxy/index.js.map +1 -0
- package/dist/cliproxy/platform-detector.d.ts +48 -0
- package/dist/cliproxy/platform-detector.d.ts.map +1 -0
- package/dist/cliproxy/platform-detector.js +118 -0
- package/dist/cliproxy/platform-detector.js.map +1 -0
- package/dist/cliproxy/types.d.ts +169 -0
- package/dist/cliproxy/types.d.ts.map +1 -0
- package/dist/cliproxy/types.js +7 -0
- package/dist/cliproxy/types.js.map +1 -0
- package/dist/commands/doctor-command.d.ts +10 -0
- package/dist/commands/doctor-command.d.ts.map +1 -0
- package/dist/commands/doctor-command.js +44 -0
- package/dist/commands/doctor-command.js.map +1 -0
- package/dist/commands/help-command.d.ts +5 -0
- package/dist/commands/help-command.d.ts.map +1 -0
- package/dist/commands/help-command.js +104 -0
- package/dist/commands/help-command.js.map +1 -0
- package/dist/commands/install-command.d.ts +14 -0
- package/dist/commands/install-command.d.ts.map +1 -0
- package/dist/commands/install-command.js +39 -0
- package/dist/commands/install-command.js.map +1 -0
- package/dist/commands/shell-completion-command.d.ts +10 -0
- package/dist/commands/shell-completion-command.d.ts.map +1 -0
- package/dist/commands/shell-completion-command.js +85 -0
- package/dist/commands/shell-completion-command.js.map +1 -0
- package/dist/commands/sync-command.d.ts +10 -0
- package/dist/commands/sync-command.d.ts.map +1 -0
- package/dist/commands/sync-command.js +59 -0
- package/dist/commands/sync-command.js.map +1 -0
- package/dist/commands/update-command.d.ts +12 -0
- package/dist/commands/update-command.d.ts.map +1 -0
- package/dist/commands/update-command.js +295 -0
- package/dist/commands/update-command.js.map +1 -0
- package/dist/commands/version-command.d.ts +10 -0
- package/dist/commands/version-command.d.ts.map +1 -0
- package/dist/commands/version-command.js +100 -0
- package/dist/commands/version-command.js.map +1 -0
- package/dist/delegation/delegation-handler.d.ts +60 -0
- package/dist/delegation/delegation-handler.d.ts.map +1 -0
- package/dist/delegation/delegation-handler.js +174 -0
- package/dist/delegation/delegation-handler.js.map +1 -0
- package/dist/delegation/headless-executor.d.ts +114 -0
- package/dist/delegation/headless-executor.d.ts.map +1 -0
- package/dist/delegation/headless-executor.js +562 -0
- package/dist/delegation/headless-executor.js.map +1 -0
- package/dist/delegation/result-formatter.d.ts +108 -0
- package/dist/delegation/result-formatter.d.ts.map +1 -0
- package/dist/delegation/result-formatter.js +391 -0
- package/dist/delegation/result-formatter.js.map +1 -0
- package/dist/delegation/session-manager.d.ts +58 -0
- package/dist/delegation/session-manager.d.ts.map +1 -0
- package/dist/delegation/session-manager.js +153 -0
- package/dist/delegation/session-manager.js.map +1 -0
- package/dist/delegation/settings-parser.d.ts +31 -0
- package/dist/delegation/settings-parser.d.ts.map +1 -0
- package/dist/delegation/settings-parser.js +107 -0
- package/dist/delegation/settings-parser.js.map +1 -0
- package/dist/glmt/delta-accumulator.d.ts +210 -0
- package/dist/glmt/delta-accumulator.d.ts.map +1 -0
- package/dist/glmt/delta-accumulator.js +351 -0
- package/dist/glmt/delta-accumulator.js.map +1 -0
- package/dist/glmt/glmt-proxy.d.ts +72 -0
- package/dist/glmt/glmt-proxy.d.ts.map +1 -0
- package/dist/glmt/glmt-proxy.js +427 -0
- package/dist/glmt/glmt-proxy.js.map +1 -0
- package/dist/glmt/glmt-transformer.d.ts +265 -0
- package/dist/glmt/glmt-transformer.d.ts.map +1 -0
- package/dist/glmt/glmt-transformer.js +832 -0
- package/dist/glmt/glmt-transformer.js.map +1 -0
- package/dist/glmt/locale-enforcer.d.ts +38 -0
- package/dist/glmt/locale-enforcer.d.ts.map +1 -0
- package/dist/glmt/locale-enforcer.js +69 -0
- package/dist/glmt/locale-enforcer.js.map +1 -0
- package/dist/glmt/reasoning-enforcer.d.ts +52 -0
- package/dist/glmt/reasoning-enforcer.d.ts.map +1 -0
- package/dist/glmt/reasoning-enforcer.js +151 -0
- package/dist/glmt/reasoning-enforcer.js.map +1 -0
- package/dist/glmt/sse-parser.d.ts +47 -0
- package/dist/glmt/sse-parser.d.ts.map +1 -0
- package/dist/glmt/sse-parser.js +93 -0
- package/dist/glmt/sse-parser.js.map +1 -0
- package/dist/management/doctor.d.ts +104 -0
- package/dist/management/doctor.d.ts.map +1 -0
- package/dist/management/doctor.js +673 -0
- package/dist/management/doctor.js.map +1 -0
- package/dist/management/instance-manager.d.ts +57 -0
- package/dist/management/instance-manager.d.ts.map +1 -0
- package/dist/management/instance-manager.js +195 -0
- package/dist/management/instance-manager.js.map +1 -0
- package/dist/management/recovery-manager.d.ts +39 -0
- package/dist/management/recovery-manager.d.ts.map +1 -0
- package/dist/management/recovery-manager.js +141 -0
- package/dist/management/recovery-manager.js.map +1 -0
- package/dist/management/shared-manager.d.ts +47 -0
- package/dist/management/shared-manager.d.ts.map +1 -0
- package/dist/management/shared-manager.js +388 -0
- package/dist/management/shared-manager.js.map +1 -0
- package/dist/types/cli.d.ts +50 -0
- package/dist/types/cli.d.ts.map +1 -0
- package/dist/types/cli.js +16 -0
- package/dist/types/cli.js.map +1 -0
- package/dist/types/config.d.ts +51 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +26 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/delegation.d.ts +61 -0
- package/dist/types/delegation.d.ts.map +1 -0
- package/dist/types/delegation.js +6 -0
- package/dist/types/delegation.js.map +1 -0
- package/dist/types/glmt.d.ts +95 -0
- package/dist/types/glmt.d.ts.map +1 -0
- package/dist/types/glmt.js +7 -0
- package/dist/types/glmt.js.map +1 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +16 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/utils.d.ts +36 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/dist/types/utils.js +22 -0
- package/dist/types/utils.js.map +1 -0
- package/dist/utils/claude-detector.d.ts +14 -0
- package/dist/utils/claude-detector.d.ts.map +1 -0
- package/dist/utils/claude-detector.js +112 -0
- package/dist/utils/claude-detector.js.map +1 -0
- package/dist/utils/claude-dir-installer.d.ts +46 -0
- package/dist/utils/claude-dir-installer.d.ts.map +1 -0
- package/dist/utils/claude-dir-installer.js +289 -0
- package/dist/utils/claude-dir-installer.js.map +1 -0
- package/dist/utils/claude-symlink-manager.d.ts +61 -0
- package/dist/utils/claude-symlink-manager.d.ts.map +1 -0
- package/dist/utils/claude-symlink-manager.js +291 -0
- package/dist/utils/claude-symlink-manager.js.map +1 -0
- package/dist/utils/config-manager.d.ts +32 -0
- package/dist/utils/config-manager.d.ts.map +1 -0
- package/dist/utils/config-manager.js +143 -0
- package/dist/utils/config-manager.js.map +1 -0
- package/dist/utils/delegation-validator.d.ts +39 -0
- package/dist/utils/delegation-validator.d.ts.map +1 -0
- package/dist/utils/delegation-validator.js +161 -0
- package/dist/utils/delegation-validator.js.map +1 -0
- package/dist/utils/error-codes.d.ts +36 -0
- package/dist/utils/error-codes.d.ts.map +1 -0
- package/dist/utils/error-codes.js +63 -0
- package/dist/utils/error-codes.js.map +1 -0
- package/dist/utils/error-manager.d.ts +59 -0
- package/dist/utils/error-manager.d.ts.map +1 -0
- package/dist/utils/error-manager.js +228 -0
- package/dist/utils/error-manager.js.map +1 -0
- package/dist/utils/helpers.d.ts +27 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +150 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/package-manager-detector.d.ts +14 -0
- package/dist/utils/package-manager-detector.d.ts.map +1 -0
- package/dist/utils/package-manager-detector.js +162 -0
- package/dist/utils/package-manager-detector.js.map +1 -0
- package/dist/utils/progress-indicator.d.ts +52 -0
- package/dist/utils/progress-indicator.d.ts.map +1 -0
- package/dist/utils/progress-indicator.js +102 -0
- package/dist/utils/progress-indicator.js.map +1 -0
- package/dist/utils/prompt.d.ts +29 -0
- package/dist/utils/prompt.d.ts.map +1 -0
- package/dist/utils/prompt.js +116 -0
- package/dist/utils/prompt.js.map +1 -0
- package/dist/utils/shell-completion.d.ts +52 -0
- package/dist/utils/shell-completion.d.ts.map +1 -0
- package/dist/utils/shell-completion.js +231 -0
- package/dist/utils/shell-completion.js.map +1 -0
- package/dist/utils/shell-executor.d.ts +15 -0
- package/dist/utils/shell-executor.d.ts.map +1 -0
- package/dist/utils/shell-executor.js +57 -0
- package/dist/utils/shell-executor.js.map +1 -0
- package/dist/utils/update-checker.d.ts +48 -0
- package/dist/utils/update-checker.d.ts.map +1 -0
- package/dist/utils/update-checker.js +241 -0
- package/dist/utils/update-checker.js.map +1 -0
- package/lib/ccs +21 -1907
- package/lib/ccs.ps1 +26 -1800
- package/lib/error-codes.ps1 +2 -1
- package/lib/prompt.ps1 +2 -2
- package/package.json +31 -11
- package/scripts/add-shebang.js +39 -0
- package/scripts/bump-version.sh +25 -37
- package/scripts/dev-install.sh +32 -11
- package/scripts/postinstall.js +29 -29
- package/bin/auth/auth-commands.js +0 -499
- package/bin/auth/profile-detector.js +0 -204
- package/bin/auth/profile-registry.js +0 -225
- package/bin/ccs.js +0 -1034
- package/bin/delegation/README.md +0 -191
- package/bin/delegation/delegation-handler.js +0 -212
- package/bin/delegation/headless-executor.js +0 -618
- package/bin/delegation/result-formatter.js +0 -485
- package/bin/delegation/session-manager.js +0 -157
- package/bin/delegation/settings-parser.js +0 -109
- package/bin/glmt/delta-accumulator.js +0 -276
- package/bin/glmt/glmt-proxy.js +0 -495
- package/bin/glmt/glmt-transformer.js +0 -999
- package/bin/glmt/locale-enforcer.js +0 -72
- package/bin/glmt/reasoning-enforcer.js +0 -173
- package/bin/glmt/sse-parser.js +0 -96
- package/bin/management/doctor.js +0 -721
- package/bin/management/instance-manager.js +0 -202
- package/bin/management/recovery-manager.js +0 -135
- package/bin/management/shared-manager.js +0 -402
- package/bin/utils/claude-detector.js +0 -73
- package/bin/utils/claude-dir-installer.js +0 -283
- package/bin/utils/claude-symlink-manager.js +0 -289
- package/bin/utils/config-manager.js +0 -103
- package/bin/utils/delegation-validator.js +0 -154
- package/bin/utils/error-codes.js +0 -59
- package/bin/utils/error-manager.js +0 -165
- package/bin/utils/helpers.js +0 -136
- package/bin/utils/progress-indicator.js +0 -111
- package/bin/utils/prompt.js +0 -134
- package/bin/utils/shell-completion.js +0 -256
- package/bin/utils/update-checker.js +0 -243
|
@@ -1,283 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const os = require('os');
|
|
7
|
-
|
|
8
|
-
// Make ora optional (might not be available during npm install postinstall)
|
|
9
|
-
// ora v9+ is an ES module, need to use .default for CommonJS
|
|
10
|
-
let ora = null;
|
|
11
|
-
try {
|
|
12
|
-
const oraModule = require('ora');
|
|
13
|
-
ora = oraModule.default || oraModule;
|
|
14
|
-
} catch (e) {
|
|
15
|
-
// ora not available, create fallback spinner that uses console.log
|
|
16
|
-
ora = function(text) {
|
|
17
|
-
return {
|
|
18
|
-
start: () => ({
|
|
19
|
-
succeed: (msg) => console.log(msg || `[OK] ${text}`),
|
|
20
|
-
fail: (msg) => console.log(msg || `[X] ${text}`),
|
|
21
|
-
warn: (msg) => console.log(msg || `[!] ${text}`),
|
|
22
|
-
info: (msg) => console.log(msg || `[i] ${text}`),
|
|
23
|
-
text: ''
|
|
24
|
-
})
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const { colored } = require('./helpers');
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* ClaudeDirInstaller - Manages copying .claude/ directory from package to ~/.ccs/.claude/
|
|
33
|
-
* v4.1.1: Fix for npm install not copying .claude/ directory
|
|
34
|
-
*/
|
|
35
|
-
class ClaudeDirInstaller {
|
|
36
|
-
constructor() {
|
|
37
|
-
this.homeDir = os.homedir();
|
|
38
|
-
this.ccsClaudeDir = path.join(this.homeDir, '.ccs', '.claude');
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Copy .claude/ directory from package to ~/.ccs/.claude/
|
|
43
|
-
* @param {string} packageDir - Package installation directory (default: auto-detect)
|
|
44
|
-
* @param {boolean} silent - Suppress spinner output
|
|
45
|
-
*/
|
|
46
|
-
install(packageDir, silent = false) {
|
|
47
|
-
const spinner = (silent || !ora) ? null : ora('Copying .claude/ items to ~/.ccs/.claude/').start();
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
// Auto-detect package directory if not provided
|
|
51
|
-
if (!packageDir) {
|
|
52
|
-
// Try to find package root by going up from this file
|
|
53
|
-
packageDir = path.join(__dirname, '..', '..');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const packageClaudeDir = path.join(packageDir, '.claude');
|
|
57
|
-
|
|
58
|
-
if (!fs.existsSync(packageClaudeDir)) {
|
|
59
|
-
const msg = 'Package .claude/ directory not found';
|
|
60
|
-
if (spinner) {
|
|
61
|
-
spinner.warn(`[!] ${msg}`);
|
|
62
|
-
console.log(` Searched in: ${packageClaudeDir}`);
|
|
63
|
-
console.log(' This may be a development installation');
|
|
64
|
-
} else {
|
|
65
|
-
console.log(`[!] ${msg}`);
|
|
66
|
-
console.log(` Searched in: ${packageClaudeDir}`);
|
|
67
|
-
console.log(' This may be a development installation');
|
|
68
|
-
}
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Remove old version before copying new one
|
|
73
|
-
if (fs.existsSync(this.ccsClaudeDir)) {
|
|
74
|
-
if (spinner) spinner.text = 'Removing old .claude/ items...';
|
|
75
|
-
fs.rmSync(this.ccsClaudeDir, { recursive: true, force: true });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Use fs.cpSync for recursive copy (Node.js 16.7.0+)
|
|
79
|
-
// Fallback to manual copy for older Node.js versions
|
|
80
|
-
if (spinner) spinner.text = 'Copying .claude/ items...';
|
|
81
|
-
|
|
82
|
-
if (fs.cpSync) {
|
|
83
|
-
fs.cpSync(packageClaudeDir, this.ccsClaudeDir, { recursive: true });
|
|
84
|
-
} else {
|
|
85
|
-
// Fallback for Node.js < 16.7.0
|
|
86
|
-
this._copyDirRecursive(packageClaudeDir, this.ccsClaudeDir);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Count files and directories
|
|
90
|
-
const itemCount = this._countItems(this.ccsClaudeDir);
|
|
91
|
-
const msg = `Copied .claude/ items (${itemCount.files} files, ${itemCount.dirs} directories)`;
|
|
92
|
-
|
|
93
|
-
if (spinner) {
|
|
94
|
-
spinner.succeed(colored('[OK]', 'green') + ` ${msg}`);
|
|
95
|
-
} else {
|
|
96
|
-
console.log(`[OK] ${msg}`);
|
|
97
|
-
}
|
|
98
|
-
return true;
|
|
99
|
-
} catch (err) {
|
|
100
|
-
const msg = `Failed to copy .claude/ directory: ${err.message}`;
|
|
101
|
-
if (spinner) {
|
|
102
|
-
spinner.fail(colored('[!]', 'yellow') + ` ${msg}`);
|
|
103
|
-
console.warn(' CCS items may not be available');
|
|
104
|
-
} else {
|
|
105
|
-
console.warn(`[!] ${msg}`);
|
|
106
|
-
console.warn(' CCS items may not be available');
|
|
107
|
-
}
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Recursively copy directory (fallback for Node.js < 16.7.0)
|
|
114
|
-
* @param {string} src - Source directory
|
|
115
|
-
* @param {string} dest - Destination directory
|
|
116
|
-
* @private
|
|
117
|
-
*/
|
|
118
|
-
_copyDirRecursive(src, dest) {
|
|
119
|
-
// Create destination directory
|
|
120
|
-
if (!fs.existsSync(dest)) {
|
|
121
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Read source directory
|
|
125
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
126
|
-
|
|
127
|
-
for (const entry of entries) {
|
|
128
|
-
const srcPath = path.join(src, entry.name);
|
|
129
|
-
const destPath = path.join(dest, entry.name);
|
|
130
|
-
|
|
131
|
-
if (entry.isDirectory()) {
|
|
132
|
-
// Recursively copy subdirectory
|
|
133
|
-
this._copyDirRecursive(srcPath, destPath);
|
|
134
|
-
} else {
|
|
135
|
-
// Copy file
|
|
136
|
-
fs.copyFileSync(srcPath, destPath);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Count files and directories in a path
|
|
143
|
-
* @param {string} dirPath - Directory to count
|
|
144
|
-
* @returns {Object} { files: number, dirs: number }
|
|
145
|
-
* @private
|
|
146
|
-
*/
|
|
147
|
-
_countItems(dirPath) {
|
|
148
|
-
let files = 0;
|
|
149
|
-
let dirs = 0;
|
|
150
|
-
|
|
151
|
-
const countRecursive = (p) => {
|
|
152
|
-
const entries = fs.readdirSync(p, { withFileTypes: true });
|
|
153
|
-
for (const entry of entries) {
|
|
154
|
-
if (entry.isDirectory()) {
|
|
155
|
-
dirs++;
|
|
156
|
-
countRecursive(path.join(p, entry.name));
|
|
157
|
-
} else {
|
|
158
|
-
files++;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
try {
|
|
164
|
-
countRecursive(dirPath);
|
|
165
|
-
} catch (e) {
|
|
166
|
-
// Ignore errors
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return { files, dirs };
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Clean up deprecated files from previous installations
|
|
174
|
-
* Removes ccs-delegator.md that was deprecated in v4.3.2
|
|
175
|
-
* @param {boolean} silent - Suppress console output
|
|
176
|
-
*/
|
|
177
|
-
cleanupDeprecated(silent = false) {
|
|
178
|
-
const deprecatedFile = path.join(this.ccsClaudeDir, 'agents', 'ccs-delegator.md');
|
|
179
|
-
const userSymlinkFile = path.join(this.homeDir, '.claude', 'agents', 'ccs-delegator.md');
|
|
180
|
-
const migrationMarker = path.join(this.homeDir, '.ccs', '.migrations', 'v435-delegator-cleanup');
|
|
181
|
-
|
|
182
|
-
let cleanedFiles = [];
|
|
183
|
-
|
|
184
|
-
try {
|
|
185
|
-
// Check if cleanup already done
|
|
186
|
-
if (fs.existsSync(migrationMarker)) {
|
|
187
|
-
return { success: true, cleanedFiles: [] }; // Already cleaned
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Clean up user symlink in ~/.claude/agents/ccs-delegator.md FIRST
|
|
191
|
-
// This ensures we can detect broken symlinks before deleting the target
|
|
192
|
-
try {
|
|
193
|
-
const userStats = fs.lstatSync(userSymlinkFile);
|
|
194
|
-
if (userStats.isSymbolicLink()) {
|
|
195
|
-
fs.unlinkSync(userSymlinkFile);
|
|
196
|
-
cleanedFiles.push('user symlink');
|
|
197
|
-
} else {
|
|
198
|
-
// It's not a symlink (user created their own file), backup it
|
|
199
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
|
|
200
|
-
const backupPath = `${userSymlinkFile}.backup-${timestamp}`;
|
|
201
|
-
fs.renameSync(userSymlinkFile, backupPath);
|
|
202
|
-
if (!silent) console.log(`[i] Backed up user file to ${path.basename(backupPath)}`);
|
|
203
|
-
cleanedFiles.push('user file (backed up)');
|
|
204
|
-
}
|
|
205
|
-
} catch (err) {
|
|
206
|
-
// File doesn't exist or other error - that's okay
|
|
207
|
-
if (err.code !== 'ENOENT' && !silent) {
|
|
208
|
-
console.log(`[!] Failed to remove user symlink: ${err.message}`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Clean up package copy in ~/.ccs/.claude/agents/ccs-delegator.md
|
|
213
|
-
if (fs.existsSync(deprecatedFile)) {
|
|
214
|
-
try {
|
|
215
|
-
// Check if file was modified by user (compare with expected content)
|
|
216
|
-
const shouldBackup = this._shouldBackupDeprecatedFile(deprecatedFile);
|
|
217
|
-
|
|
218
|
-
if (shouldBackup) {
|
|
219
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
|
|
220
|
-
const backupPath = `${deprecatedFile}.backup-${timestamp}`;
|
|
221
|
-
fs.renameSync(deprecatedFile, backupPath);
|
|
222
|
-
if (!silent) console.log(`[i] Backed up modified deprecated file to ${path.basename(backupPath)}`);
|
|
223
|
-
} else {
|
|
224
|
-
fs.rmSync(deprecatedFile, { force: true });
|
|
225
|
-
}
|
|
226
|
-
cleanedFiles.push('package copy');
|
|
227
|
-
} catch (err) {
|
|
228
|
-
if (!silent) console.log(`[!] Failed to remove package copy: ${err.message}`);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Create migration marker
|
|
233
|
-
if (cleanedFiles.length > 0) {
|
|
234
|
-
const migrationsDir = path.dirname(migrationMarker);
|
|
235
|
-
if (!fs.existsSync(migrationsDir)) {
|
|
236
|
-
fs.mkdirSync(migrationsDir, { recursive: true, mode: 0o700 });
|
|
237
|
-
}
|
|
238
|
-
fs.writeFileSync(migrationMarker, new Date().toISOString());
|
|
239
|
-
|
|
240
|
-
if (!silent) {
|
|
241
|
-
console.log(`[OK] Cleaned up deprecated agent files: ${cleanedFiles.join(', ')}`);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return { success: true, cleanedFiles };
|
|
246
|
-
} catch (err) {
|
|
247
|
-
if (!silent) console.log(`[!] Cleanup failed: ${err.message}`);
|
|
248
|
-
return { success: false, error: err.message, cleanedFiles };
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Check if deprecated file should be backed up (user modified)
|
|
254
|
-
* @param {string} filePath - Path to check
|
|
255
|
-
* @returns {boolean} True if file should be backed up
|
|
256
|
-
* @private
|
|
257
|
-
*/
|
|
258
|
-
_shouldBackupDeprecatedFile(filePath) {
|
|
259
|
-
try {
|
|
260
|
-
// Simple heuristic: if file size differs significantly from expected, assume user modified
|
|
261
|
-
// Expected size for ccs-delegator.md was around 2-3KB
|
|
262
|
-
const stats = fs.statSync(filePath);
|
|
263
|
-
const expectedMinSize = 1000; // 1KB minimum
|
|
264
|
-
const expectedMaxSize = 10000; // 10KB maximum
|
|
265
|
-
|
|
266
|
-
// If size is outside expected range, likely user modified
|
|
267
|
-
return stats.size < expectedMinSize || stats.size > expectedMaxSize;
|
|
268
|
-
} catch (err) {
|
|
269
|
-
// If we can't determine, err on side of caution and backup
|
|
270
|
-
return true;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Check if ~/.ccs/.claude/ exists and is valid
|
|
276
|
-
* @returns {boolean} True if directory exists
|
|
277
|
-
*/
|
|
278
|
-
isInstalled() {
|
|
279
|
-
return fs.existsSync(this.ccsClaudeDir);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
module.exports = ClaudeDirInstaller;
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const os = require('os');
|
|
6
|
-
|
|
7
|
-
// Make ora optional (might not be available during npm install postinstall)
|
|
8
|
-
// ora v9+ is an ES module, need to use .default for CommonJS
|
|
9
|
-
let ora = null;
|
|
10
|
-
try {
|
|
11
|
-
const oraModule = require('ora');
|
|
12
|
-
ora = oraModule.default || oraModule;
|
|
13
|
-
} catch (e) {
|
|
14
|
-
// ora not available, create fallback spinner that uses console.log
|
|
15
|
-
ora = function(text) {
|
|
16
|
-
return {
|
|
17
|
-
start: () => ({
|
|
18
|
-
succeed: (msg) => console.log(msg || `[OK] ${text}`),
|
|
19
|
-
fail: (msg) => console.log(msg || `[X] ${text}`),
|
|
20
|
-
warn: (msg) => console.log(msg || `[!] ${text}`),
|
|
21
|
-
info: (msg) => console.log(msg || `[i] ${text}`),
|
|
22
|
-
text: ''
|
|
23
|
-
})
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const { colored } = require('./helpers');
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* ClaudeSymlinkManager - Manages selective symlinks from ~/.ccs/.claude/ to ~/.claude/
|
|
32
|
-
* v4.1.0: Selective symlinking for CCS items
|
|
33
|
-
*
|
|
34
|
-
* Purpose: Ship CCS items (.claude/) with package and symlink them to user's ~/.claude/
|
|
35
|
-
* Architecture:
|
|
36
|
-
* - ~/.ccs/.claude/* (source, ships with CCS)
|
|
37
|
-
* - ~/.claude/* (target, gets selective symlinks)
|
|
38
|
-
* - ~/.ccs/shared/ (UNTOUCHED, existing profile mechanism)
|
|
39
|
-
*
|
|
40
|
-
* Symlink Chain:
|
|
41
|
-
* profile -> ~/.ccs/shared/ -> ~/.claude/ (which has symlinks to ~/.ccs/.claude/)
|
|
42
|
-
*/
|
|
43
|
-
class ClaudeSymlinkManager {
|
|
44
|
-
constructor() {
|
|
45
|
-
this.homeDir = os.homedir();
|
|
46
|
-
this.ccsClaudeDir = path.join(this.homeDir, '.ccs', '.claude');
|
|
47
|
-
this.userClaudeDir = path.join(this.homeDir, '.claude');
|
|
48
|
-
|
|
49
|
-
// CCS items to symlink (selective, item-level)
|
|
50
|
-
this.ccsItems = [
|
|
51
|
-
{ source: 'commands/ccs.md', target: 'commands/ccs.md', type: 'file' },
|
|
52
|
-
{ source: 'commands/ccs', target: 'commands/ccs', type: 'directory' },
|
|
53
|
-
{ source: 'skills/ccs-delegation', target: 'skills/ccs-delegation', type: 'directory' }
|
|
54
|
-
];
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Install CCS items to user's ~/.claude/ via selective symlinks
|
|
59
|
-
* Safe: backs up existing files before creating symlinks
|
|
60
|
-
*/
|
|
61
|
-
install(silent = false) {
|
|
62
|
-
const spinner = (silent || !ora) ? null : ora('Installing CCS items to ~/.claude/').start();
|
|
63
|
-
|
|
64
|
-
// Ensure ~/.ccs/.claude/ exists (should be shipped with package)
|
|
65
|
-
if (!fs.existsSync(this.ccsClaudeDir)) {
|
|
66
|
-
const msg = 'CCS .claude/ directory not found, skipping symlink installation';
|
|
67
|
-
if (spinner) {
|
|
68
|
-
spinner.warn(`[!] ${msg}`);
|
|
69
|
-
} else {
|
|
70
|
-
console.log(`[!] ${msg}`);
|
|
71
|
-
}
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Create ~/.claude/ if missing
|
|
76
|
-
if (!fs.existsSync(this.userClaudeDir)) {
|
|
77
|
-
if (!silent) {
|
|
78
|
-
if (spinner) spinner.text = 'Creating ~/.claude/ directory';
|
|
79
|
-
}
|
|
80
|
-
fs.mkdirSync(this.userClaudeDir, { recursive: true, mode: 0o700 });
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Install each CCS item
|
|
84
|
-
let installed = 0;
|
|
85
|
-
for (const item of this.ccsItems) {
|
|
86
|
-
if (!silent && spinner) {
|
|
87
|
-
spinner.text = `Installing ${item.target}...`;
|
|
88
|
-
}
|
|
89
|
-
const result = this._installItem(item, silent);
|
|
90
|
-
if (result) installed++;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const msg = `${installed}/${this.ccsItems.length} items installed to ~/.claude/`;
|
|
94
|
-
if (spinner) {
|
|
95
|
-
spinner.succeed(colored('[OK]', 'green') + ` ${msg}`);
|
|
96
|
-
} else {
|
|
97
|
-
console.log(`[OK] ${msg}`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Install a single CCS item with conflict handling
|
|
103
|
-
* @param {Object} item - Item descriptor {source, target, type}
|
|
104
|
-
* @param {boolean} silent - Suppress individual item messages
|
|
105
|
-
* @returns {boolean} True if installed successfully
|
|
106
|
-
* @private
|
|
107
|
-
*/
|
|
108
|
-
_installItem(item, silent = false) {
|
|
109
|
-
const sourcePath = path.join(this.ccsClaudeDir, item.source);
|
|
110
|
-
const targetPath = path.join(this.userClaudeDir, item.target);
|
|
111
|
-
const targetDir = path.dirname(targetPath);
|
|
112
|
-
|
|
113
|
-
// Ensure source exists
|
|
114
|
-
if (!fs.existsSync(sourcePath)) {
|
|
115
|
-
if (!silent) console.log(`[!] Source not found: ${item.source}, skipping`);
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Create target parent directory if needed
|
|
120
|
-
if (!fs.existsSync(targetDir)) {
|
|
121
|
-
fs.mkdirSync(targetDir, { recursive: true, mode: 0o700 });
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Check if target already exists
|
|
125
|
-
if (fs.existsSync(targetPath)) {
|
|
126
|
-
// Check if it's already the correct symlink
|
|
127
|
-
if (this._isOurSymlink(targetPath, sourcePath)) {
|
|
128
|
-
return true; // Already correct, counts as success
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Backup existing file/directory
|
|
132
|
-
this._backupItem(targetPath, silent);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Create symlink
|
|
136
|
-
try {
|
|
137
|
-
const symlinkType = item.type === 'directory' ? 'dir' : 'file';
|
|
138
|
-
fs.symlinkSync(sourcePath, targetPath, symlinkType);
|
|
139
|
-
if (!silent) console.log(`[OK] Symlinked ${item.target}`);
|
|
140
|
-
return true;
|
|
141
|
-
} catch (err) {
|
|
142
|
-
// Windows fallback: stub for now, full implementation in v4.2
|
|
143
|
-
if (process.platform === 'win32') {
|
|
144
|
-
if (!silent) {
|
|
145
|
-
console.log(`[!] Symlink failed for ${item.target} (Windows fallback deferred to v4.2)`);
|
|
146
|
-
console.log(`[i] Enable Developer Mode or wait for next update`);
|
|
147
|
-
}
|
|
148
|
-
} else {
|
|
149
|
-
if (!silent) console.log(`[!] Failed to symlink ${item.target}: ${err.message}`);
|
|
150
|
-
}
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Check if target is already the correct symlink pointing to source
|
|
157
|
-
* @param {string} targetPath - Target path to check
|
|
158
|
-
* @param {string} expectedSource - Expected source path
|
|
159
|
-
* @returns {boolean} True if target is correct symlink
|
|
160
|
-
* @private
|
|
161
|
-
*/
|
|
162
|
-
_isOurSymlink(targetPath, expectedSource) {
|
|
163
|
-
try {
|
|
164
|
-
const stats = fs.lstatSync(targetPath);
|
|
165
|
-
|
|
166
|
-
if (!stats.isSymbolicLink()) {
|
|
167
|
-
return false;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const actualTarget = fs.readlinkSync(targetPath);
|
|
171
|
-
const resolvedTarget = path.resolve(path.dirname(targetPath), actualTarget);
|
|
172
|
-
|
|
173
|
-
return resolvedTarget === expectedSource;
|
|
174
|
-
} catch (err) {
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Backup existing item before replacing with symlink
|
|
181
|
-
* @param {string} itemPath - Path to item to backup
|
|
182
|
-
* @param {boolean} silent - Suppress backup messages
|
|
183
|
-
* @private
|
|
184
|
-
*/
|
|
185
|
-
_backupItem(itemPath, silent = false) {
|
|
186
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
|
|
187
|
-
const backupPath = `${itemPath}.backup-${timestamp}`;
|
|
188
|
-
|
|
189
|
-
try {
|
|
190
|
-
// If backup already exists, use counter
|
|
191
|
-
let finalBackupPath = backupPath;
|
|
192
|
-
let counter = 1;
|
|
193
|
-
while (fs.existsSync(finalBackupPath)) {
|
|
194
|
-
finalBackupPath = `${backupPath}-${counter}`;
|
|
195
|
-
counter++;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
fs.renameSync(itemPath, finalBackupPath);
|
|
199
|
-
if (!silent) console.log(`[i] Backed up existing item to ${path.basename(finalBackupPath)}`);
|
|
200
|
-
} catch (err) {
|
|
201
|
-
if (!silent) console.log(`[!] Failed to backup ${itemPath}: ${err.message}`);
|
|
202
|
-
throw err; // Don't proceed if backup fails
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Uninstall CCS items from ~/.claude/ (remove symlinks only)
|
|
208
|
-
* Safe: only removes items that are CCS symlinks
|
|
209
|
-
*/
|
|
210
|
-
uninstall() {
|
|
211
|
-
let removed = 0;
|
|
212
|
-
|
|
213
|
-
for (const item of this.ccsItems) {
|
|
214
|
-
const targetPath = path.join(this.userClaudeDir, item.target);
|
|
215
|
-
const sourcePath = path.join(this.ccsClaudeDir, item.source);
|
|
216
|
-
|
|
217
|
-
// Only remove if it's our symlink
|
|
218
|
-
if (fs.existsSync(targetPath) && this._isOurSymlink(targetPath, sourcePath)) {
|
|
219
|
-
try {
|
|
220
|
-
fs.unlinkSync(targetPath);
|
|
221
|
-
console.log(`[OK] Removed ${item.target}`);
|
|
222
|
-
removed++;
|
|
223
|
-
} catch (err) {
|
|
224
|
-
console.log(`[!] Failed to remove ${item.target}: ${err.message}`);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (removed > 0) {
|
|
230
|
-
console.log(`[OK] Removed ${removed} delegation commands and skills from ~/.claude/`);
|
|
231
|
-
} else {
|
|
232
|
-
console.log('[i] No delegation commands or skills to remove');
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Check symlink health and report issues
|
|
238
|
-
* Used by 'ccs doctor' command
|
|
239
|
-
* @returns {Object} Health check results {healthy: boolean, issues: string[]}
|
|
240
|
-
*/
|
|
241
|
-
checkHealth() {
|
|
242
|
-
const issues = [];
|
|
243
|
-
let healthy = true;
|
|
244
|
-
|
|
245
|
-
// Check if ~/.ccs/.claude/ exists
|
|
246
|
-
if (!fs.existsSync(this.ccsClaudeDir)) {
|
|
247
|
-
issues.push('CCS .claude/ directory missing (reinstall CCS)');
|
|
248
|
-
healthy = false;
|
|
249
|
-
return { healthy, issues };
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Check each item
|
|
253
|
-
for (const item of this.ccsItems) {
|
|
254
|
-
const sourcePath = path.join(this.ccsClaudeDir, item.source);
|
|
255
|
-
const targetPath = path.join(this.userClaudeDir, item.target);
|
|
256
|
-
|
|
257
|
-
// Check source exists
|
|
258
|
-
if (!fs.existsSync(sourcePath)) {
|
|
259
|
-
issues.push(`Source missing: ${item.source}`);
|
|
260
|
-
healthy = false;
|
|
261
|
-
continue;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Check target
|
|
265
|
-
if (!fs.existsSync(targetPath)) {
|
|
266
|
-
issues.push(`Not installed: ${item.target} (run 'ccs sync' to install)`);
|
|
267
|
-
healthy = false;
|
|
268
|
-
} else if (!this._isOurSymlink(targetPath, sourcePath)) {
|
|
269
|
-
issues.push(`Not a CCS symlink: ${item.target} (run 'ccs sync' to fix)`);
|
|
270
|
-
healthy = false;
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return { healthy, issues };
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Sync delegation commands and skills to ~/.claude/ (used by 'ccs sync' command)
|
|
279
|
-
* Same as install() but with explicit sync message
|
|
280
|
-
*/
|
|
281
|
-
sync() {
|
|
282
|
-
console.log('');
|
|
283
|
-
console.log(colored('Syncing CCS Components...', 'cyan'));
|
|
284
|
-
console.log('');
|
|
285
|
-
this.install(false);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
module.exports = ClaudeSymlinkManager;
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const os = require('os');
|
|
6
|
-
const { error, expandPath } = require('./helpers');
|
|
7
|
-
const { ErrorManager } = require('./error-manager');
|
|
8
|
-
|
|
9
|
-
// Get config file path
|
|
10
|
-
function getConfigPath() {
|
|
11
|
-
return process.env.CCS_CONFIG || path.join(os.homedir(), '.ccs', 'config.json');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// Read and parse config
|
|
15
|
-
function readConfig() {
|
|
16
|
-
const configPath = getConfigPath();
|
|
17
|
-
|
|
18
|
-
// Check config exists
|
|
19
|
-
if (!fs.existsSync(configPath)) {
|
|
20
|
-
// Attempt recovery
|
|
21
|
-
const RecoveryManager = require('./recovery-manager');
|
|
22
|
-
const recovery = new RecoveryManager();
|
|
23
|
-
recovery.ensureConfigJson();
|
|
24
|
-
|
|
25
|
-
if (!fs.existsSync(configPath)) {
|
|
26
|
-
ErrorManager.showInvalidConfig(configPath, 'File not found');
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// Read and parse JSON
|
|
32
|
-
let config;
|
|
33
|
-
try {
|
|
34
|
-
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
35
|
-
config = JSON.parse(configContent);
|
|
36
|
-
} catch (e) {
|
|
37
|
-
ErrorManager.showInvalidConfig(configPath, `Invalid JSON: ${e.message}`);
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Validate config has profiles object
|
|
42
|
-
if (!config.profiles || typeof config.profiles !== 'object') {
|
|
43
|
-
ErrorManager.showInvalidConfig(configPath, "Missing 'profiles' object");
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return config;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Get settings path for profile
|
|
51
|
-
function getSettingsPath(profile) {
|
|
52
|
-
const config = readConfig();
|
|
53
|
-
|
|
54
|
-
// Get settings path
|
|
55
|
-
const settingsPath = config.profiles[profile];
|
|
56
|
-
|
|
57
|
-
if (!settingsPath) {
|
|
58
|
-
const availableProfiles = Object.keys(config.profiles);
|
|
59
|
-
const profileList = availableProfiles.map(p => ` - ${p}`);
|
|
60
|
-
ErrorManager.showProfileNotFound(profile, profileList);
|
|
61
|
-
process.exit(1);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Expand path
|
|
65
|
-
const expandedPath = expandPath(settingsPath);
|
|
66
|
-
|
|
67
|
-
// Validate settings file exists
|
|
68
|
-
if (!fs.existsSync(expandedPath)) {
|
|
69
|
-
// Auto-create if it's ~/.claude/settings.json
|
|
70
|
-
if (expandedPath.includes('.claude') && expandedPath.endsWith('settings.json')) {
|
|
71
|
-
const RecoveryManager = require('./recovery-manager');
|
|
72
|
-
const recovery = new RecoveryManager();
|
|
73
|
-
recovery.ensureClaudeSettings();
|
|
74
|
-
|
|
75
|
-
if (!fs.existsSync(expandedPath)) {
|
|
76
|
-
ErrorManager.showSettingsNotFound(expandedPath);
|
|
77
|
-
process.exit(1);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
console.log('[i] Auto-created missing settings file');
|
|
81
|
-
} else {
|
|
82
|
-
ErrorManager.showSettingsNotFound(expandedPath);
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Validate settings file is valid JSON
|
|
88
|
-
try {
|
|
89
|
-
const settingsContent = fs.readFileSync(expandedPath, 'utf8');
|
|
90
|
-
JSON.parse(settingsContent);
|
|
91
|
-
} catch (e) {
|
|
92
|
-
ErrorManager.showInvalidConfig(expandedPath, `Invalid JSON: ${e.message}`);
|
|
93
|
-
process.exit(1);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return expandedPath;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
module.exports = {
|
|
100
|
-
getConfigPath,
|
|
101
|
-
readConfig,
|
|
102
|
-
getSettingsPath
|
|
103
|
-
};
|