@kaitranntt/ccs 4.4.0 → 5.0.1
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 +98 -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 +95 -0
- package/dist/cliproxy/auth-handler.d.ts.map +1 -0
- package/dist/cliproxy/auth-handler.js +443 -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,402 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const os = require('os');
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* SharedManager - Manages symlinked shared directories for CCS
|
|
9
|
-
* v3.2.0: Symlink-based architecture
|
|
10
|
-
*
|
|
11
|
-
* Purpose: Eliminates duplication by symlinking:
|
|
12
|
-
* ~/.claude/ ← ~/.ccs/shared/ ← instance/
|
|
13
|
-
*/
|
|
14
|
-
class SharedManager {
|
|
15
|
-
constructor() {
|
|
16
|
-
this.homeDir = os.homedir();
|
|
17
|
-
this.sharedDir = path.join(this.homeDir, '.ccs', 'shared');
|
|
18
|
-
this.claudeDir = path.join(this.homeDir, '.claude');
|
|
19
|
-
this.instancesDir = path.join(this.homeDir, '.ccs', 'instances');
|
|
20
|
-
this.sharedItems = [
|
|
21
|
-
{ name: 'commands', type: 'directory' },
|
|
22
|
-
{ name: 'skills', type: 'directory' },
|
|
23
|
-
{ name: 'agents', type: 'directory' },
|
|
24
|
-
{ name: 'plugins', type: 'directory' },
|
|
25
|
-
{ name: 'settings.json', type: 'file' }
|
|
26
|
-
];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Detect circular symlink before creation
|
|
31
|
-
* @param {string} target - Target path to link to
|
|
32
|
-
* @param {string} linkPath - Path where symlink will be created
|
|
33
|
-
* @returns {boolean} True if circular
|
|
34
|
-
* @private
|
|
35
|
-
*/
|
|
36
|
-
_detectCircularSymlink(target, linkPath) {
|
|
37
|
-
// Check if target exists and is symlink
|
|
38
|
-
if (!fs.existsSync(target)) {
|
|
39
|
-
return false;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
const stats = fs.lstatSync(target);
|
|
44
|
-
if (!stats.isSymbolicLink()) {
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// Resolve target's link
|
|
49
|
-
const targetLink = fs.readlinkSync(target);
|
|
50
|
-
const resolvedTarget = path.resolve(path.dirname(target), targetLink);
|
|
51
|
-
|
|
52
|
-
// Check if target points back to our shared dir or link path
|
|
53
|
-
const sharedDir = path.join(this.homeDir, '.ccs', 'shared');
|
|
54
|
-
if (resolvedTarget.startsWith(sharedDir) || resolvedTarget === linkPath) {
|
|
55
|
-
console.log(`[!] Circular symlink detected: ${target} → ${resolvedTarget}`);
|
|
56
|
-
return true;
|
|
57
|
-
}
|
|
58
|
-
} catch (err) {
|
|
59
|
-
// If can't read, assume not circular
|
|
60
|
-
return false;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Ensure shared directories exist as symlinks to ~/.claude/
|
|
68
|
-
* Creates ~/.claude/ structure if missing
|
|
69
|
-
*/
|
|
70
|
-
ensureSharedDirectories() {
|
|
71
|
-
// Create ~/.claude/ if missing
|
|
72
|
-
if (!fs.existsSync(this.claudeDir)) {
|
|
73
|
-
console.log('[i] Creating ~/.claude/ directory structure');
|
|
74
|
-
fs.mkdirSync(this.claudeDir, { recursive: true, mode: 0o700 });
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Create shared directory
|
|
78
|
-
if (!fs.existsSync(this.sharedDir)) {
|
|
79
|
-
fs.mkdirSync(this.sharedDir, { recursive: true, mode: 0o700 });
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Create symlinks ~/.ccs/shared/* → ~/.claude/*
|
|
83
|
-
for (const item of this.sharedItems) {
|
|
84
|
-
const claudePath = path.join(this.claudeDir, item.name);
|
|
85
|
-
const sharedPath = path.join(this.sharedDir, item.name);
|
|
86
|
-
|
|
87
|
-
// Create in ~/.claude/ if missing
|
|
88
|
-
if (!fs.existsSync(claudePath)) {
|
|
89
|
-
if (item.type === 'directory') {
|
|
90
|
-
fs.mkdirSync(claudePath, { recursive: true, mode: 0o700 });
|
|
91
|
-
} else if (item.type === 'file') {
|
|
92
|
-
// Create empty settings.json if missing
|
|
93
|
-
fs.writeFileSync(claudePath, JSON.stringify({}, null, 2), 'utf8');
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Check for circular symlink
|
|
98
|
-
if (this._detectCircularSymlink(claudePath, sharedPath)) {
|
|
99
|
-
console.log(`[!] Skipping ${item.name}: circular symlink detected`);
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// If already a symlink pointing to correct target, skip
|
|
104
|
-
if (fs.existsSync(sharedPath)) {
|
|
105
|
-
try {
|
|
106
|
-
const stats = fs.lstatSync(sharedPath);
|
|
107
|
-
if (stats.isSymbolicLink()) {
|
|
108
|
-
const currentTarget = fs.readlinkSync(sharedPath);
|
|
109
|
-
const resolvedTarget = path.resolve(path.dirname(sharedPath), currentTarget);
|
|
110
|
-
if (resolvedTarget === claudePath) {
|
|
111
|
-
continue; // Already correct
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
} catch (err) {
|
|
115
|
-
// Continue to recreate
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Remove existing file/directory/link
|
|
119
|
-
if (item.type === 'directory') {
|
|
120
|
-
fs.rmSync(sharedPath, { recursive: true, force: true });
|
|
121
|
-
} else {
|
|
122
|
-
fs.unlinkSync(sharedPath);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Create symlink
|
|
127
|
-
try {
|
|
128
|
-
const symlinkType = item.type === 'directory' ? 'dir' : 'file';
|
|
129
|
-
fs.symlinkSync(claudePath, sharedPath, symlinkType);
|
|
130
|
-
} catch (err) {
|
|
131
|
-
// Windows fallback: copy
|
|
132
|
-
if (process.platform === 'win32') {
|
|
133
|
-
if (item.type === 'directory') {
|
|
134
|
-
this._copyDirectoryFallback(claudePath, sharedPath);
|
|
135
|
-
} else if (item.type === 'file') {
|
|
136
|
-
fs.copyFileSync(claudePath, sharedPath);
|
|
137
|
-
}
|
|
138
|
-
console.log(`[!] Symlink failed for ${item.name}, copied instead (enable Developer Mode)`);
|
|
139
|
-
} else {
|
|
140
|
-
throw err;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Link shared directories to instance
|
|
148
|
-
* @param {string} instancePath - Path to instance directory
|
|
149
|
-
*/
|
|
150
|
-
linkSharedDirectories(instancePath) {
|
|
151
|
-
this.ensureSharedDirectories();
|
|
152
|
-
|
|
153
|
-
for (const item of this.sharedItems) {
|
|
154
|
-
const linkPath = path.join(instancePath, item.name);
|
|
155
|
-
const targetPath = path.join(this.sharedDir, item.name);
|
|
156
|
-
|
|
157
|
-
// Remove existing file/directory/link
|
|
158
|
-
if (fs.existsSync(linkPath)) {
|
|
159
|
-
if (item.type === 'directory') {
|
|
160
|
-
fs.rmSync(linkPath, { recursive: true, force: true });
|
|
161
|
-
} else {
|
|
162
|
-
fs.unlinkSync(linkPath);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Create symlink
|
|
167
|
-
try {
|
|
168
|
-
const symlinkType = item.type === 'directory' ? 'dir' : 'file';
|
|
169
|
-
fs.symlinkSync(targetPath, linkPath, symlinkType);
|
|
170
|
-
} catch (err) {
|
|
171
|
-
// Windows fallback
|
|
172
|
-
if (process.platform === 'win32') {
|
|
173
|
-
if (item.type === 'directory') {
|
|
174
|
-
this._copyDirectoryFallback(targetPath, linkPath);
|
|
175
|
-
} else if (item.type === 'file') {
|
|
176
|
-
fs.copyFileSync(targetPath, linkPath);
|
|
177
|
-
}
|
|
178
|
-
console.log(`[!] Symlink failed for ${item.name}, copied instead (enable Developer Mode)`);
|
|
179
|
-
} else {
|
|
180
|
-
throw err;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Migrate from v3.1.1 (copied data in ~/.ccs/shared/) to v3.2.0 (symlinks to ~/.claude/)
|
|
188
|
-
* Runs once on upgrade
|
|
189
|
-
*/
|
|
190
|
-
migrateFromV311() {
|
|
191
|
-
// Check if migration already done (shared dirs are symlinks)
|
|
192
|
-
const commandsPath = path.join(this.sharedDir, 'commands');
|
|
193
|
-
if (fs.existsSync(commandsPath)) {
|
|
194
|
-
try {
|
|
195
|
-
if (fs.lstatSync(commandsPath).isSymbolicLink()) {
|
|
196
|
-
return; // Already migrated
|
|
197
|
-
}
|
|
198
|
-
} catch (err) {
|
|
199
|
-
// Continue with migration
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
console.log('[i] Migrating from v3.1.1 to v3.2.0...');
|
|
204
|
-
|
|
205
|
-
// Ensure ~/.claude/ exists
|
|
206
|
-
if (!fs.existsSync(this.claudeDir)) {
|
|
207
|
-
fs.mkdirSync(this.claudeDir, { recursive: true, mode: 0o700 });
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Copy user modifications from ~/.ccs/shared/ to ~/.claude/
|
|
211
|
-
for (const item of this.sharedItems) {
|
|
212
|
-
const sharedPath = path.join(this.sharedDir, item.name);
|
|
213
|
-
const claudePath = path.join(this.claudeDir, item.name);
|
|
214
|
-
|
|
215
|
-
if (!fs.existsSync(sharedPath)) continue;
|
|
216
|
-
|
|
217
|
-
try {
|
|
218
|
-
const stats = fs.lstatSync(sharedPath);
|
|
219
|
-
|
|
220
|
-
// Handle directories
|
|
221
|
-
if (item.type === 'directory' && stats.isDirectory()) {
|
|
222
|
-
// Create claude dir if missing
|
|
223
|
-
if (!fs.existsSync(claudePath)) {
|
|
224
|
-
fs.mkdirSync(claudePath, { recursive: true, mode: 0o700 });
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Copy files from shared to claude (preserve user modifications)
|
|
228
|
-
const entries = fs.readdirSync(sharedPath, { withFileTypes: true });
|
|
229
|
-
let copied = 0;
|
|
230
|
-
|
|
231
|
-
for (const entry of entries) {
|
|
232
|
-
const src = path.join(sharedPath, entry.name);
|
|
233
|
-
const dest = path.join(claudePath, entry.name);
|
|
234
|
-
|
|
235
|
-
// Skip if already exists in claude
|
|
236
|
-
if (fs.existsSync(dest)) continue;
|
|
237
|
-
|
|
238
|
-
if (entry.isDirectory()) {
|
|
239
|
-
fs.cpSync(src, dest, { recursive: true });
|
|
240
|
-
} else {
|
|
241
|
-
fs.copyFileSync(src, dest);
|
|
242
|
-
}
|
|
243
|
-
copied++;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
if (copied > 0) {
|
|
247
|
-
console.log(`[OK] Migrated ${copied} ${item.name} to ~/.claude/${item.name}`);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// Handle files (settings.json)
|
|
252
|
-
else if (item.type === 'file' && stats.isFile()) {
|
|
253
|
-
// Only copy if ~/.claude/ version doesn't exist
|
|
254
|
-
if (!fs.existsSync(claudePath)) {
|
|
255
|
-
fs.copyFileSync(sharedPath, claudePath);
|
|
256
|
-
console.log(`[OK] Migrated ${item.name} to ~/.claude/${item.name}`);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
} catch (err) {
|
|
260
|
-
console.log(`[!] Failed to migrate ${item.name}: ${err.message}`);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Now run ensureSharedDirectories to create symlinks
|
|
265
|
-
this.ensureSharedDirectories();
|
|
266
|
-
|
|
267
|
-
// Update all instances to use new symlinks
|
|
268
|
-
if (fs.existsSync(this.instancesDir)) {
|
|
269
|
-
try {
|
|
270
|
-
const instances = fs.readdirSync(this.instancesDir);
|
|
271
|
-
|
|
272
|
-
for (const instance of instances) {
|
|
273
|
-
const instancePath = path.join(this.instancesDir, instance);
|
|
274
|
-
try {
|
|
275
|
-
if (fs.statSync(instancePath).isDirectory()) {
|
|
276
|
-
this.linkSharedDirectories(instancePath);
|
|
277
|
-
}
|
|
278
|
-
} catch (err) {
|
|
279
|
-
console.log(`[!] Failed to update instance ${instance}: ${err.message}`);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
} catch (err) {
|
|
283
|
-
// No instances to update
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
console.log('[OK] Migration to v3.2.0 complete');
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Migrate existing instances from isolated to shared settings.json (v4.4+)
|
|
292
|
-
* Runs once on upgrade
|
|
293
|
-
*/
|
|
294
|
-
migrateToSharedSettings() {
|
|
295
|
-
console.log('[i] Migrating instances to shared settings.json...');
|
|
296
|
-
|
|
297
|
-
// Ensure ~/.claude/settings.json exists (authoritative source)
|
|
298
|
-
const claudeSettings = path.join(this.claudeDir, 'settings.json');
|
|
299
|
-
if (!fs.existsSync(claudeSettings)) {
|
|
300
|
-
// Create empty settings if missing
|
|
301
|
-
fs.writeFileSync(claudeSettings, JSON.stringify({}, null, 2), 'utf8');
|
|
302
|
-
console.log('[i] Created ~/.claude/settings.json');
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// Ensure shared settings.json symlink exists
|
|
306
|
-
this.ensureSharedDirectories();
|
|
307
|
-
|
|
308
|
-
// Migrate each instance
|
|
309
|
-
if (!fs.existsSync(this.instancesDir)) {
|
|
310
|
-
console.log('[i] No instances to migrate');
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const instances = fs.readdirSync(this.instancesDir).filter(name => {
|
|
315
|
-
const instancePath = path.join(this.instancesDir, name);
|
|
316
|
-
return fs.statSync(instancePath).isDirectory();
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
let migrated = 0;
|
|
320
|
-
let skipped = 0;
|
|
321
|
-
|
|
322
|
-
for (const instance of instances) {
|
|
323
|
-
const instancePath = path.join(this.instancesDir, instance);
|
|
324
|
-
const instanceSettings = path.join(instancePath, 'settings.json');
|
|
325
|
-
|
|
326
|
-
try {
|
|
327
|
-
// Check if already symlink
|
|
328
|
-
if (fs.existsSync(instanceSettings)) {
|
|
329
|
-
const stats = fs.lstatSync(instanceSettings);
|
|
330
|
-
if (stats.isSymbolicLink()) {
|
|
331
|
-
skipped++;
|
|
332
|
-
continue; // Already migrated
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// Backup existing settings
|
|
336
|
-
const backup = instanceSettings + '.pre-shared-migration';
|
|
337
|
-
if (!fs.existsSync(backup)) {
|
|
338
|
-
fs.copyFileSync(instanceSettings, backup);
|
|
339
|
-
console.log(`[i] Backed up ${instance}/settings.json`);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Remove old settings.json
|
|
343
|
-
fs.unlinkSync(instanceSettings);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Create symlink via SharedManager
|
|
347
|
-
const sharedSettings = path.join(this.sharedDir, 'settings.json');
|
|
348
|
-
|
|
349
|
-
try {
|
|
350
|
-
fs.symlinkSync(sharedSettings, instanceSettings, 'file');
|
|
351
|
-
migrated++;
|
|
352
|
-
} catch (err) {
|
|
353
|
-
// Windows fallback
|
|
354
|
-
if (process.platform === 'win32') {
|
|
355
|
-
fs.copyFileSync(sharedSettings, instanceSettings);
|
|
356
|
-
console.log(`[!] Symlink failed for ${instance}, copied instead`);
|
|
357
|
-
migrated++;
|
|
358
|
-
} else {
|
|
359
|
-
throw err;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
} catch (err) {
|
|
364
|
-
console.log(`[!] Failed to migrate ${instance}: ${err.message}`);
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
console.log(`[OK] Migrated ${migrated} instance(s), skipped ${skipped}`);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Copy directory as fallback (Windows without Developer Mode)
|
|
373
|
-
* @param {string} src - Source directory
|
|
374
|
-
* @param {string} dest - Destination directory
|
|
375
|
-
* @private
|
|
376
|
-
*/
|
|
377
|
-
_copyDirectoryFallback(src, dest) {
|
|
378
|
-
if (!fs.existsSync(src)) {
|
|
379
|
-
fs.mkdirSync(src, { recursive: true, mode: 0o700 });
|
|
380
|
-
return;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
if (!fs.existsSync(dest)) {
|
|
384
|
-
fs.mkdirSync(dest, { recursive: true, mode: 0o700 });
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
388
|
-
|
|
389
|
-
for (const entry of entries) {
|
|
390
|
-
const srcPath = path.join(src, entry.name);
|
|
391
|
-
const destPath = path.join(dest, entry.name);
|
|
392
|
-
|
|
393
|
-
if (entry.isDirectory()) {
|
|
394
|
-
this._copyDirectoryFallback(srcPath, destPath);
|
|
395
|
-
} else {
|
|
396
|
-
fs.copyFileSync(srcPath, destPath);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
module.exports = SharedManager;
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const { execSync } = require('child_process');
|
|
5
|
-
const { expandPath } = require('./helpers');
|
|
6
|
-
|
|
7
|
-
// Detect Claude CLI executable
|
|
8
|
-
function detectClaudeCli() {
|
|
9
|
-
// Priority 1: CCS_CLAUDE_PATH environment variable (if user wants custom path)
|
|
10
|
-
if (process.env.CCS_CLAUDE_PATH) {
|
|
11
|
-
const ccsPath = expandPath(process.env.CCS_CLAUDE_PATH);
|
|
12
|
-
// Basic validation: file exists
|
|
13
|
-
if (fs.existsSync(ccsPath)) {
|
|
14
|
-
return ccsPath;
|
|
15
|
-
}
|
|
16
|
-
// Invalid CCS_CLAUDE_PATH - show warning and fall back to PATH
|
|
17
|
-
console.warn('[!] Warning: CCS_CLAUDE_PATH is set but file not found:', ccsPath);
|
|
18
|
-
console.warn(' Falling back to system PATH lookup...');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Priority 2: Resolve 'claude' from PATH using which/where.exe
|
|
22
|
-
// This fixes Windows npm installation where spawn() can't resolve bare command names
|
|
23
|
-
// SECURITY: Commands are hardcoded literals with no user input - safe from injection
|
|
24
|
-
const isWindows = process.platform === 'win32';
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
const cmd = isWindows ? 'where.exe claude' : 'which claude';
|
|
28
|
-
const result = execSync(cmd, {
|
|
29
|
-
encoding: 'utf8',
|
|
30
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
31
|
-
timeout: 5000 // 5 second timeout to prevent hangs
|
|
32
|
-
}).trim();
|
|
33
|
-
|
|
34
|
-
// where.exe may return multiple lines (all matches in PATH order)
|
|
35
|
-
const matches = result.split('\n').map(p => p.trim()).filter(p => p);
|
|
36
|
-
|
|
37
|
-
if (isWindows) {
|
|
38
|
-
// On Windows, prefer executables with extensions (.exe, .cmd, .bat)
|
|
39
|
-
// where.exe often returns file without extension first, then the actual .cmd wrapper
|
|
40
|
-
const withExtension = matches.find(p => /\.(exe|cmd|bat|ps1)$/i.test(p));
|
|
41
|
-
const claudePath = withExtension || matches[0];
|
|
42
|
-
|
|
43
|
-
if (claudePath && fs.existsSync(claudePath)) {
|
|
44
|
-
return claudePath;
|
|
45
|
-
}
|
|
46
|
-
} else {
|
|
47
|
-
// On Unix, first match is fine
|
|
48
|
-
const claudePath = matches[0];
|
|
49
|
-
|
|
50
|
-
if (claudePath && fs.existsSync(claudePath)) {
|
|
51
|
-
return claudePath;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
} catch (err) {
|
|
55
|
-
// Command failed - claude not in PATH
|
|
56
|
-
// Fall through to return null
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Priority 3: Claude not found
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Show Claude not found error
|
|
64
|
-
function showClaudeNotFoundError() {
|
|
65
|
-
console.error('ERROR: Claude CLI not found in PATH');
|
|
66
|
-
console.error('Install from: https://docs.claude.com/en/docs/claude-code/installation');
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
module.exports = {
|
|
71
|
-
detectClaudeCli,
|
|
72
|
-
showClaudeNotFoundError
|
|
73
|
-
};
|