@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
package/bin/ccs.js
DELETED
|
@@ -1,1034 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const { spawn } = require('child_process');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const fs = require('fs');
|
|
7
|
-
const os = require('os');
|
|
8
|
-
const { error, colored } = require('./utils/helpers');
|
|
9
|
-
const { detectClaudeCli, showClaudeNotFoundError } = require('./utils/claude-detector');
|
|
10
|
-
const { getSettingsPath, getConfigPath } = require('./utils/config-manager');
|
|
11
|
-
const { ErrorManager } = require('./utils/error-manager');
|
|
12
|
-
const RecoveryManager = require('./management/recovery-manager');
|
|
13
|
-
|
|
14
|
-
// Version (sync with package.json)
|
|
15
|
-
const CCS_VERSION = require('../package.json').version;
|
|
16
|
-
|
|
17
|
-
// Helper: Escape arguments for shell execution
|
|
18
|
-
function escapeShellArg(arg) {
|
|
19
|
-
// Windows: escape double quotes and wrap in double quotes
|
|
20
|
-
return '"' + String(arg).replace(/"/g, '""') + '"';
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// Execute Claude CLI with unified spawn logic
|
|
24
|
-
function execClaude(claudeCli, args, envVars = null) {
|
|
25
|
-
const isWindows = process.platform === 'win32';
|
|
26
|
-
const needsShell = isWindows && /\.(cmd|bat|ps1)$/i.test(claudeCli);
|
|
27
|
-
|
|
28
|
-
// Prepare environment (merge with process.env if envVars provided)
|
|
29
|
-
const env = envVars ? { ...process.env, ...envVars } : process.env;
|
|
30
|
-
|
|
31
|
-
let child;
|
|
32
|
-
if (needsShell) {
|
|
33
|
-
// When shell needed: concatenate into string to avoid DEP0190 warning
|
|
34
|
-
const cmdString = [claudeCli, ...args].map(escapeShellArg).join(' ');
|
|
35
|
-
child = spawn(cmdString, {
|
|
36
|
-
stdio: 'inherit',
|
|
37
|
-
windowsHide: true,
|
|
38
|
-
shell: true,
|
|
39
|
-
env
|
|
40
|
-
});
|
|
41
|
-
} else {
|
|
42
|
-
// When no shell needed: use array form (faster, no shell overhead)
|
|
43
|
-
child = spawn(claudeCli, args, {
|
|
44
|
-
stdio: 'inherit',
|
|
45
|
-
windowsHide: true,
|
|
46
|
-
env
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
child.on('exit', (code, signal) => {
|
|
51
|
-
if (signal) process.kill(process.pid, signal);
|
|
52
|
-
else process.exit(code || 0);
|
|
53
|
-
});
|
|
54
|
-
child.on('error', () => {
|
|
55
|
-
showClaudeNotFoundError();
|
|
56
|
-
process.exit(1);
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Special command handlers
|
|
61
|
-
function handleVersionCommand() {
|
|
62
|
-
// Title
|
|
63
|
-
console.log(colored(`CCS (Claude Code Switch) v${CCS_VERSION}`, 'bold'));
|
|
64
|
-
console.log('');
|
|
65
|
-
|
|
66
|
-
// Installation section with table-like formatting
|
|
67
|
-
console.log(colored('Installation:', 'cyan'));
|
|
68
|
-
|
|
69
|
-
// Location
|
|
70
|
-
const installLocation = process.argv[1] || '(not found)';
|
|
71
|
-
console.log(` ${colored('Location:'.padEnd(17), 'cyan')} ${installLocation}`);
|
|
72
|
-
|
|
73
|
-
// .ccs/ directory location
|
|
74
|
-
const ccsDir = path.join(os.homedir(), '.ccs');
|
|
75
|
-
console.log(` ${colored('CCS Directory:'.padEnd(17), 'cyan')} ${ccsDir}`);
|
|
76
|
-
|
|
77
|
-
// Config path
|
|
78
|
-
const configPath = getConfigPath();
|
|
79
|
-
console.log(` ${colored('Config:'.padEnd(17), 'cyan')} ${configPath}`);
|
|
80
|
-
|
|
81
|
-
// Profiles.json location
|
|
82
|
-
const profilesJson = path.join(os.homedir(), '.ccs', 'profiles.json');
|
|
83
|
-
console.log(` ${colored('Profiles:'.padEnd(17), 'cyan')} ${profilesJson}`);
|
|
84
|
-
|
|
85
|
-
// Delegation status - check multiple indicators
|
|
86
|
-
const delegationSessionsPath = path.join(os.homedir(), '.ccs', 'delegation-sessions.json');
|
|
87
|
-
const delegationConfigured = fs.existsSync(delegationSessionsPath);
|
|
88
|
-
|
|
89
|
-
let readyProfiles = [];
|
|
90
|
-
|
|
91
|
-
// Check for profiles with valid API keys
|
|
92
|
-
for (const profile of ['glm', 'kimi']) {
|
|
93
|
-
const settingsPath = path.join(os.homedir(), '.ccs', `${profile}.settings.json`);
|
|
94
|
-
if (fs.existsSync(settingsPath)) {
|
|
95
|
-
try {
|
|
96
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
97
|
-
const apiKey = settings.env?.ANTHROPIC_AUTH_TOKEN;
|
|
98
|
-
if (apiKey && !apiKey.match(/YOUR_.*_API_KEY_HERE/) && !apiKey.match(/sk-test.*/)) {
|
|
99
|
-
readyProfiles.push(profile);
|
|
100
|
-
}
|
|
101
|
-
} catch (error) {
|
|
102
|
-
// Invalid JSON, skip
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const hasValidApiKeys = readyProfiles.length > 0;
|
|
108
|
-
const delegationEnabled = delegationConfigured || hasValidApiKeys;
|
|
109
|
-
|
|
110
|
-
if (delegationEnabled) {
|
|
111
|
-
console.log(` ${colored('Delegation:'.padEnd(17), 'cyan')} Enabled`);
|
|
112
|
-
} else {
|
|
113
|
-
console.log(` ${colored('Delegation:'.padEnd(17), 'cyan')} Not configured`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
console.log('');
|
|
117
|
-
|
|
118
|
-
// Ready Profiles section - make it more prominent
|
|
119
|
-
if (readyProfiles.length > 0) {
|
|
120
|
-
console.log(colored('Delegation Ready:', 'cyan'));
|
|
121
|
-
console.log(` ${colored('✓', 'yellow')} ${readyProfiles.join(', ')} profiles are ready for delegation`);
|
|
122
|
-
console.log('');
|
|
123
|
-
} else if (delegationEnabled) {
|
|
124
|
-
console.log(colored('Delegation Ready:', 'cyan'));
|
|
125
|
-
console.log(` ${colored('!', 'yellow')} Delegation configured but no valid API keys found`);
|
|
126
|
-
console.log('');
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Documentation
|
|
130
|
-
console.log(`${colored('Documentation:', 'cyan')} https://github.com/kaitranntt/ccs`);
|
|
131
|
-
console.log(`${colored('License:', 'cyan')} MIT`);
|
|
132
|
-
console.log('');
|
|
133
|
-
|
|
134
|
-
// Help hint
|
|
135
|
-
console.log(colored('Run \'ccs --help\' for usage information', 'yellow'));
|
|
136
|
-
|
|
137
|
-
process.exit(0);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function handleHelpCommand() {
|
|
141
|
-
// Title
|
|
142
|
-
console.log(colored('CCS (Claude Code Switch) - Instant profile switching for Claude CLI', 'bold'));
|
|
143
|
-
console.log('');
|
|
144
|
-
|
|
145
|
-
// Usage
|
|
146
|
-
console.log(colored('Usage:', 'cyan'));
|
|
147
|
-
console.log(` ${colored('ccs', 'yellow')} [profile] [claude-args...]`);
|
|
148
|
-
console.log(` ${colored('ccs', 'yellow')} [flags]`);
|
|
149
|
-
console.log('');
|
|
150
|
-
|
|
151
|
-
// Description
|
|
152
|
-
console.log(colored('Description:', 'cyan'));
|
|
153
|
-
console.log(' Switch between multiple Claude accounts and alternative models');
|
|
154
|
-
console.log(' (GLM, Kimi) instantly. Run different Claude CLI sessions concurrently');
|
|
155
|
-
console.log(' with auto-recovery. Zero downtime.');
|
|
156
|
-
console.log('');
|
|
157
|
-
|
|
158
|
-
// Model Switching
|
|
159
|
-
console.log(colored('Model Switching:', 'cyan'));
|
|
160
|
-
console.log(` ${colored('ccs', 'yellow')} Use default Claude account`);
|
|
161
|
-
console.log(` ${colored('ccs glm', 'yellow')} Switch to GLM 4.6 model`);
|
|
162
|
-
console.log(` ${colored('ccs glmt', 'yellow')} Switch to GLM with thinking mode`);
|
|
163
|
-
console.log(` ${colored('ccs glmt --verbose', 'yellow')} Enable debug logging`);
|
|
164
|
-
console.log(` ${colored('ccs kimi', 'yellow')} Switch to Kimi for Coding`);
|
|
165
|
-
console.log(` ${colored('ccs glm', 'yellow')} "debug this code" Use GLM and run command`);
|
|
166
|
-
console.log('');
|
|
167
|
-
|
|
168
|
-
// Account Management
|
|
169
|
-
console.log(colored('Account Management:', 'cyan'));
|
|
170
|
-
console.log(` ${colored('ccs auth --help', 'yellow')} Run multiple Claude accounts concurrently`);
|
|
171
|
-
console.log('');
|
|
172
|
-
|
|
173
|
-
// Delegation (inside Claude Code CLI)
|
|
174
|
-
console.log(colored('Delegation (inside Claude Code CLI):', 'cyan'));
|
|
175
|
-
console.log(` ${colored('/ccs "task"', 'yellow')} Delegate task (auto-selects best profile)`);
|
|
176
|
-
console.log(` ${colored('/ccs --glm "task"', 'yellow')} Force GLM-4.6 for simple tasks`);
|
|
177
|
-
console.log(` ${colored('/ccs --kimi "task"', 'yellow')} Force Kimi for long context`);
|
|
178
|
-
console.log(` ${colored('/ccs:continue "follow-up"', 'yellow')} Continue last delegation session`);
|
|
179
|
-
console.log(' Save tokens by delegating simple tasks to cost-optimized models');
|
|
180
|
-
console.log('');
|
|
181
|
-
|
|
182
|
-
// Diagnostics
|
|
183
|
-
console.log(colored('Diagnostics:', 'cyan'));
|
|
184
|
-
console.log(` ${colored('ccs doctor', 'yellow')} Run health check and diagnostics`);
|
|
185
|
-
console.log(` ${colored('ccs sync', 'yellow')} Sync delegation commands and skills`);
|
|
186
|
-
console.log(` ${colored('ccs update', 'yellow')} Update CCS to latest version`);
|
|
187
|
-
console.log('');
|
|
188
|
-
|
|
189
|
-
// Flags
|
|
190
|
-
console.log(colored('Flags:', 'cyan'));
|
|
191
|
-
console.log(` ${colored('-h, --help', 'yellow')} Show this help message`);
|
|
192
|
-
console.log(` ${colored('-v, --version', 'yellow')} Show version and installation info`);
|
|
193
|
-
console.log(` ${colored('-sc, --shell-completion', 'yellow')} Install shell auto-completion`);
|
|
194
|
-
console.log('');
|
|
195
|
-
|
|
196
|
-
// Configuration
|
|
197
|
-
console.log(colored('Configuration:', 'cyan'));
|
|
198
|
-
console.log(' Config File: ~/.ccs/config.json');
|
|
199
|
-
console.log(' Profiles: ~/.ccs/profiles.json');
|
|
200
|
-
console.log(' Instances: ~/.ccs/instances/');
|
|
201
|
-
console.log(' Settings: ~/.ccs/*.settings.json');
|
|
202
|
-
console.log(' Environment: CCS_CONFIG (override config path)');
|
|
203
|
-
console.log('');
|
|
204
|
-
|
|
205
|
-
// Shared Data
|
|
206
|
-
console.log(colored('Shared Data:', 'cyan'));
|
|
207
|
-
console.log(' Commands: ~/.ccs/shared/commands/');
|
|
208
|
-
console.log(' Skills: ~/.ccs/shared/skills/');
|
|
209
|
-
console.log(' Agents: ~/.ccs/shared/agents/');
|
|
210
|
-
console.log(' Plugins: ~/.ccs/shared/plugins/');
|
|
211
|
-
console.log(' Note: Commands, skills, agents, and plugins are symlinked across all profiles');
|
|
212
|
-
console.log('');
|
|
213
|
-
|
|
214
|
-
// Examples
|
|
215
|
-
console.log(colored('Examples:', 'cyan'));
|
|
216
|
-
console.log(` ${colored('$ ccs', 'yellow')} # Use default account`);
|
|
217
|
-
console.log(` ${colored('$ ccs glm "implement API"', 'yellow')} # Cost-optimized model`);
|
|
218
|
-
console.log('');
|
|
219
|
-
console.log(` For more: ${colored('https://github.com/kaitranntt/ccs/blob/main/README.md', 'cyan')}`);
|
|
220
|
-
console.log('');
|
|
221
|
-
|
|
222
|
-
// Uninstall
|
|
223
|
-
console.log(colored('Uninstall:', 'yellow'));
|
|
224
|
-
console.log(' npm: npm uninstall -g @kaitranntt/ccs');
|
|
225
|
-
console.log(' macOS/Linux: curl -fsSL ccs.kaitran.ca/uninstall | bash');
|
|
226
|
-
console.log(' Windows: irm ccs.kaitran.ca/uninstall | iex');
|
|
227
|
-
console.log('');
|
|
228
|
-
|
|
229
|
-
// Documentation
|
|
230
|
-
console.log(colored('Documentation:', 'cyan'));
|
|
231
|
-
console.log(` GitHub: ${colored('https://github.com/kaitranntt/ccs', 'cyan')}`);
|
|
232
|
-
console.log(' Docs: https://github.com/kaitranntt/ccs/blob/main/README.md');
|
|
233
|
-
console.log(' Issues: https://github.com/kaitranntt/ccs/issues');
|
|
234
|
-
console.log('');
|
|
235
|
-
|
|
236
|
-
// License
|
|
237
|
-
console.log(`${colored('License:', 'cyan')} MIT`);
|
|
238
|
-
|
|
239
|
-
process.exit(0);
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
function handleInstallCommand() {
|
|
243
|
-
console.log('');
|
|
244
|
-
console.log('Feature not available');
|
|
245
|
-
console.log('');
|
|
246
|
-
console.log('The --install flag is currently under development.');
|
|
247
|
-
console.log('.claude/ integration testing is not complete.');
|
|
248
|
-
console.log('');
|
|
249
|
-
console.log('For updates: https://github.com/kaitranntt/ccs/issues');
|
|
250
|
-
console.log('');
|
|
251
|
-
process.exit(0);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function handleUninstallCommand() {
|
|
255
|
-
console.log('');
|
|
256
|
-
console.log('Feature not available');
|
|
257
|
-
console.log('');
|
|
258
|
-
console.log('The --uninstall flag is currently under development.');
|
|
259
|
-
console.log('.claude/ integration testing is not complete.');
|
|
260
|
-
console.log('');
|
|
261
|
-
console.log('For updates: https://github.com/kaitranntt/ccs/issues');
|
|
262
|
-
console.log('');
|
|
263
|
-
process.exit(0);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
async function handleDoctorCommand() {
|
|
267
|
-
const Doctor = require('./management/doctor');
|
|
268
|
-
const doctor = new Doctor();
|
|
269
|
-
|
|
270
|
-
await doctor.runAllChecks();
|
|
271
|
-
|
|
272
|
-
// Exit with error code if unhealthy
|
|
273
|
-
process.exit(doctor.results.isHealthy() ? 0 : 1);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
async function handleSyncCommand() {
|
|
277
|
-
const { colored } = require('./utils/helpers');
|
|
278
|
-
|
|
279
|
-
console.log('');
|
|
280
|
-
console.log(colored('Syncing CCS Components...', 'cyan'));
|
|
281
|
-
console.log('');
|
|
282
|
-
|
|
283
|
-
// First, copy .claude/ directory from package to ~/.ccs/.claude/
|
|
284
|
-
const ClaudeDirInstaller = require('./utils/claude-dir-installer');
|
|
285
|
-
const installer = new ClaudeDirInstaller();
|
|
286
|
-
installer.install();
|
|
287
|
-
|
|
288
|
-
console.log('');
|
|
289
|
-
|
|
290
|
-
const cleanupResult = installer.cleanupDeprecated();
|
|
291
|
-
if (cleanupResult.success && cleanupResult.cleanedFiles.length > 0) {
|
|
292
|
-
console.log('');
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Then, create symlinks from ~/.ccs/.claude/ to ~/.claude/
|
|
296
|
-
const ClaudeSymlinkManager = require('./utils/claude-symlink-manager');
|
|
297
|
-
const manager = new ClaudeSymlinkManager();
|
|
298
|
-
manager.install(false);
|
|
299
|
-
|
|
300
|
-
console.log('');
|
|
301
|
-
console.log(colored('[OK] Sync complete!', 'green'));
|
|
302
|
-
console.log('');
|
|
303
|
-
|
|
304
|
-
process.exit(0);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Detect installation method
|
|
309
|
-
* @returns {'npm'|'direct'} - Installation method
|
|
310
|
-
*/
|
|
311
|
-
function detectInstallationMethod() {
|
|
312
|
-
const scriptPath = process.argv[1];
|
|
313
|
-
|
|
314
|
-
// Method 1: Check if script is inside node_modules
|
|
315
|
-
if (scriptPath.includes('node_modules')) {
|
|
316
|
-
return 'npm';
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
// Method 2: Check if script is in npm global bin directory
|
|
320
|
-
// Common patterns for npm global installations
|
|
321
|
-
const npmGlobalBinPatterns = [
|
|
322
|
-
/\.npm\/global\/bin\//, // ~/.npm/global/bin/ccs
|
|
323
|
-
/\/\.nvm\/versions\/node\/[^\/]+\/bin\//, // ~/.nvm/versions/node/v22.19.0/bin/ccs
|
|
324
|
-
/\/usr\/local\/bin\//, // /usr/local/bin/ccs (if npm global prefix is /usr/local)
|
|
325
|
-
/\/usr\/bin\// // /usr/bin/ccs (if npm global prefix is /usr)
|
|
326
|
-
];
|
|
327
|
-
|
|
328
|
-
for (const pattern of npmGlobalBinPatterns) {
|
|
329
|
-
if (pattern.test(scriptPath)) {
|
|
330
|
-
// Verify this is actually CCS by checking the linked target
|
|
331
|
-
try {
|
|
332
|
-
const binDir = path.dirname(scriptPath);
|
|
333
|
-
const nodeModulesDir = path.join(binDir, '..', 'lib', 'node_modules', '@kaitranntt', 'ccs');
|
|
334
|
-
const globalModulesDir = path.join(binDir, '..', 'node_modules', '@kaitranntt', 'ccs');
|
|
335
|
-
|
|
336
|
-
if (fs.existsSync(nodeModulesDir) || fs.existsSync(globalModulesDir)) {
|
|
337
|
-
return 'npm';
|
|
338
|
-
}
|
|
339
|
-
} catch (err) {
|
|
340
|
-
// Continue checking other patterns
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
// Method 3: Check if package.json exists in parent directory (development mode)
|
|
346
|
-
const packageJsonPath = path.join(__dirname, '..', 'package.json');
|
|
347
|
-
|
|
348
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
349
|
-
try {
|
|
350
|
-
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
351
|
-
// If package.json has name "@kaitranntt/ccs", it's npm install
|
|
352
|
-
if (pkg.name === '@kaitranntt/ccs') {
|
|
353
|
-
return 'npm';
|
|
354
|
-
}
|
|
355
|
-
} catch (err) {
|
|
356
|
-
// Ignore parse errors
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Method 4: Check if script is a symlink pointing to node_modules
|
|
361
|
-
try {
|
|
362
|
-
const stats = fs.lstatSync(scriptPath);
|
|
363
|
-
if (stats.isSymbolicLink()) {
|
|
364
|
-
const targetPath = fs.readlinkSync(scriptPath);
|
|
365
|
-
if (targetPath.includes('node_modules') || targetPath.includes('@kaitranntt/ccs')) {
|
|
366
|
-
return 'npm';
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
} catch (err) {
|
|
370
|
-
// Continue to default
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
// Default to direct installation
|
|
374
|
-
return 'direct';
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Detect which package manager was used for installation
|
|
379
|
-
* @returns {'npm'|'yarn'|'pnpm'|'bun'|'unknown'}
|
|
380
|
-
*/
|
|
381
|
-
function detectPackageManager() {
|
|
382
|
-
const scriptPath = process.argv[1];
|
|
383
|
-
|
|
384
|
-
// Check if script path contains package manager indicators
|
|
385
|
-
if (scriptPath.includes('.pnpm')) return 'pnpm';
|
|
386
|
-
if (scriptPath.includes('yarn')) return 'yarn';
|
|
387
|
-
if (scriptPath.includes('bun')) return 'bun';
|
|
388
|
-
|
|
389
|
-
// Check parent directories for lock files
|
|
390
|
-
const binDir = path.dirname(scriptPath);
|
|
391
|
-
const fs = require('fs');
|
|
392
|
-
|
|
393
|
-
// Check global node_modules parent for lock files
|
|
394
|
-
let checkDir = binDir;
|
|
395
|
-
for (let i = 0; i < 5; i++) {
|
|
396
|
-
if (fs.existsSync(path.join(checkDir, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
397
|
-
if (fs.existsSync(path.join(checkDir, 'yarn.lock'))) return 'yarn';
|
|
398
|
-
if (fs.existsSync(path.join(checkDir, 'bun.lockb'))) return 'bun';
|
|
399
|
-
checkDir = path.dirname(checkDir);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// Check if package managers are available on the system
|
|
403
|
-
const { spawnSync } = require('child_process');
|
|
404
|
-
|
|
405
|
-
// Try yarn global list to see if CCS is installed via yarn
|
|
406
|
-
try {
|
|
407
|
-
const yarnResult = spawnSync('yarn', ['global', 'list', '--pattern', '@kaitranntt/ccs'], {
|
|
408
|
-
encoding: 'utf8',
|
|
409
|
-
shell: true,
|
|
410
|
-
timeout: 5000
|
|
411
|
-
});
|
|
412
|
-
if (yarnResult.status === 0 && yarnResult.stdout.includes('@kaitranntt/ccs')) {
|
|
413
|
-
return 'yarn';
|
|
414
|
-
}
|
|
415
|
-
} catch (err) {
|
|
416
|
-
// Continue to next check
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// Try pnpm list -g to see if CCS is installed via pnpm
|
|
420
|
-
try {
|
|
421
|
-
const pnpmResult = spawnSync('pnpm', ['list', '-g', '--pattern', '@kaitranntt/ccs'], {
|
|
422
|
-
encoding: 'utf8',
|
|
423
|
-
shell: true,
|
|
424
|
-
timeout: 5000
|
|
425
|
-
});
|
|
426
|
-
if (pnpmResult.status === 0 && pnpmResult.stdout.includes('@kaitranntt/ccs')) {
|
|
427
|
-
return 'pnpm';
|
|
428
|
-
}
|
|
429
|
-
} catch (err) {
|
|
430
|
-
// Continue to next check
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// Try bun pm ls -g to see if CCS is installed via bun
|
|
434
|
-
try {
|
|
435
|
-
const bunResult = spawnSync('bun', ['pm', 'ls', '-g', '--pattern', '@kaitranntt/ccs'], {
|
|
436
|
-
encoding: 'utf8',
|
|
437
|
-
shell: true,
|
|
438
|
-
timeout: 5000
|
|
439
|
-
});
|
|
440
|
-
if (bunResult.status === 0 && bunResult.stdout.includes('@kaitranntt/ccs')) {
|
|
441
|
-
return 'bun';
|
|
442
|
-
}
|
|
443
|
-
} catch (err) {
|
|
444
|
-
// Continue to default
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// Default to npm
|
|
448
|
-
return 'npm';
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
async function handleUpdateCommand() {
|
|
452
|
-
const { checkForUpdates } = require('./utils/update-checker');
|
|
453
|
-
const { spawn } = require('child_process');
|
|
454
|
-
|
|
455
|
-
console.log('');
|
|
456
|
-
console.log(colored('Checking for updates...', 'cyan'));
|
|
457
|
-
console.log('');
|
|
458
|
-
|
|
459
|
-
// Detect installation method for proper update source
|
|
460
|
-
const installMethod = detectInstallationMethod();
|
|
461
|
-
const isNpmInstall = installMethod === 'npm';
|
|
462
|
-
|
|
463
|
-
// Check for updates (force check)
|
|
464
|
-
const updateResult = await checkForUpdates(CCS_VERSION, true, installMethod);
|
|
465
|
-
|
|
466
|
-
if (updateResult.status === 'check_failed') {
|
|
467
|
-
console.log(colored(`[X] ${updateResult.message}`, 'red'));
|
|
468
|
-
console.log('');
|
|
469
|
-
console.log(colored('[i] Possible causes:', 'yellow'));
|
|
470
|
-
console.log(' • Network connection issues');
|
|
471
|
-
console.log(' • Firewall blocking requests');
|
|
472
|
-
console.log(' • GitHub/npm API temporarily unavailable');
|
|
473
|
-
console.log('');
|
|
474
|
-
console.log('Try again later or update manually:');
|
|
475
|
-
if (isNpmInstall) {
|
|
476
|
-
const packageManager = detectPackageManager();
|
|
477
|
-
let manualCommand;
|
|
478
|
-
|
|
479
|
-
switch (packageManager) {
|
|
480
|
-
case 'npm':
|
|
481
|
-
manualCommand = 'npm install -g @kaitranntt/ccs@latest';
|
|
482
|
-
break;
|
|
483
|
-
case 'yarn':
|
|
484
|
-
manualCommand = 'yarn global add @kaitranntt/ccs@latest';
|
|
485
|
-
break;
|
|
486
|
-
case 'pnpm':
|
|
487
|
-
manualCommand = 'pnpm add -g @kaitranntt/ccs@latest';
|
|
488
|
-
break;
|
|
489
|
-
case 'bun':
|
|
490
|
-
manualCommand = 'bun add -g @kaitranntt/ccs@latest';
|
|
491
|
-
break;
|
|
492
|
-
default:
|
|
493
|
-
manualCommand = 'npm install -g @kaitranntt/ccs@latest';
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
console.log(colored(` ${manualCommand}`, 'yellow'));
|
|
497
|
-
} else {
|
|
498
|
-
const isWindows = process.platform === 'win32';
|
|
499
|
-
if (isWindows) {
|
|
500
|
-
console.log(colored(' irm ccs.kaitran.ca/install | iex', 'yellow'));
|
|
501
|
-
} else {
|
|
502
|
-
console.log(colored(' curl -fsSL ccs.kaitran.ca/install | bash', 'yellow'));
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
console.log('');
|
|
506
|
-
process.exit(1);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
if (updateResult.status === 'no_update') {
|
|
510
|
-
let message = `You are already on the latest version (${CCS_VERSION})`;
|
|
511
|
-
|
|
512
|
-
// Add context for why no update is shown
|
|
513
|
-
switch (updateResult.reason) {
|
|
514
|
-
case 'dismissed':
|
|
515
|
-
message = `Update dismissed. You are on version ${CCS_VERSION}`;
|
|
516
|
-
console.log(colored(`[i] ${message}`, 'yellow'));
|
|
517
|
-
break;
|
|
518
|
-
case 'cached':
|
|
519
|
-
message = `No updates available (cached result). You are on version ${CCS_VERSION}`;
|
|
520
|
-
console.log(colored(`[i] ${message}`, 'cyan'));
|
|
521
|
-
break;
|
|
522
|
-
default:
|
|
523
|
-
console.log(colored(`[OK] ${message}`, 'green'));
|
|
524
|
-
}
|
|
525
|
-
console.log('');
|
|
526
|
-
process.exit(0);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
// Update available
|
|
530
|
-
console.log(colored(`[i] Update available: ${updateResult.current} → ${updateResult.latest}`, 'yellow'));
|
|
531
|
-
console.log('');
|
|
532
|
-
|
|
533
|
-
if (isNpmInstall) {
|
|
534
|
-
// npm installation - detect package manager and update
|
|
535
|
-
const packageManager = detectPackageManager();
|
|
536
|
-
let updateCommand, updateArgs, cacheCommand, cacheArgs;
|
|
537
|
-
|
|
538
|
-
switch (packageManager) {
|
|
539
|
-
case 'npm':
|
|
540
|
-
updateCommand = 'npm';
|
|
541
|
-
updateArgs = ['install', '-g', '@kaitranntt/ccs@latest'];
|
|
542
|
-
cacheCommand = 'npm';
|
|
543
|
-
cacheArgs = ['cache', 'clean', '--force'];
|
|
544
|
-
break;
|
|
545
|
-
case 'yarn':
|
|
546
|
-
updateCommand = 'yarn';
|
|
547
|
-
updateArgs = ['global', 'add', '@kaitranntt/ccs@latest'];
|
|
548
|
-
cacheCommand = 'yarn';
|
|
549
|
-
cacheArgs = ['cache', 'clean'];
|
|
550
|
-
break;
|
|
551
|
-
case 'pnpm':
|
|
552
|
-
updateCommand = 'pnpm';
|
|
553
|
-
updateArgs = ['add', '-g', '@kaitranntt/ccs@latest'];
|
|
554
|
-
cacheCommand = 'pnpm';
|
|
555
|
-
cacheArgs = ['store', 'prune'];
|
|
556
|
-
break;
|
|
557
|
-
case 'bun':
|
|
558
|
-
updateCommand = 'bun';
|
|
559
|
-
updateArgs = ['add', '-g', '@kaitranntt/ccs@latest'];
|
|
560
|
-
cacheCommand = null; // bun doesn't need explicit cache clearing
|
|
561
|
-
cacheArgs = null;
|
|
562
|
-
break;
|
|
563
|
-
default:
|
|
564
|
-
updateCommand = 'npm';
|
|
565
|
-
updateArgs = ['install', '-g', '@kaitranntt/ccs@latest'];
|
|
566
|
-
cacheCommand = 'npm';
|
|
567
|
-
cacheArgs = ['cache', 'clean', '--force'];
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
console.log(colored(`Updating via ${packageManager}...`, 'cyan'));
|
|
571
|
-
console.log('');
|
|
572
|
-
|
|
573
|
-
// Clear package manager cache first to ensure fresh download
|
|
574
|
-
if (cacheCommand) {
|
|
575
|
-
console.log(colored('Clearing package cache...', 'cyan'));
|
|
576
|
-
const cacheChild = spawn(cacheCommand, cacheArgs, {
|
|
577
|
-
stdio: 'inherit'
|
|
578
|
-
});
|
|
579
|
-
|
|
580
|
-
cacheChild.on('exit', (code) => {
|
|
581
|
-
if (code !== 0) {
|
|
582
|
-
console.log(colored('[!] Cache clearing failed, proceeding anyway...', 'yellow'));
|
|
583
|
-
}
|
|
584
|
-
// Continue with update regardless of cache clearing result
|
|
585
|
-
performUpdate();
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
cacheChild.on('error', (err) => {
|
|
589
|
-
console.log(colored('[!] Cache clearing failed, proceeding anyway...', 'yellow'));
|
|
590
|
-
// Continue with update regardless of cache clearing result
|
|
591
|
-
performUpdate();
|
|
592
|
-
});
|
|
593
|
-
} else {
|
|
594
|
-
// No cache clearing needed, proceed directly
|
|
595
|
-
performUpdate();
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
function performUpdate() {
|
|
599
|
-
const child = spawn(updateCommand, updateArgs, {
|
|
600
|
-
stdio: 'inherit'
|
|
601
|
-
// No shell needed for direct commands
|
|
602
|
-
});
|
|
603
|
-
|
|
604
|
-
child.on('exit', (code) => {
|
|
605
|
-
if (code === 0) {
|
|
606
|
-
console.log('');
|
|
607
|
-
console.log(colored('[OK] Update successful!', 'green'));
|
|
608
|
-
console.log('');
|
|
609
|
-
console.log(`Run ${colored('ccs --version', 'yellow')} to verify`);
|
|
610
|
-
console.log('');
|
|
611
|
-
} else {
|
|
612
|
-
console.log('');
|
|
613
|
-
console.log(colored('[X] Update failed', 'red'));
|
|
614
|
-
console.log('');
|
|
615
|
-
console.log('Try manually:');
|
|
616
|
-
console.log(colored(` ${updateCommand} ${updateArgs.join(' ')}`, 'yellow'));
|
|
617
|
-
console.log('');
|
|
618
|
-
}
|
|
619
|
-
process.exit(code || 0);
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
child.on('error', (err) => {
|
|
623
|
-
console.log('');
|
|
624
|
-
console.log(colored(`[X] Failed to run ${packageManager} update`, 'red'));
|
|
625
|
-
console.log('');
|
|
626
|
-
console.log('Try manually:');
|
|
627
|
-
console.log(colored(` ${updateCommand} ${updateArgs.join(' ')}`, 'yellow'));
|
|
628
|
-
console.log('');
|
|
629
|
-
process.exit(1);
|
|
630
|
-
});
|
|
631
|
-
}
|
|
632
|
-
} else {
|
|
633
|
-
// Direct installation - re-run installer
|
|
634
|
-
console.log(colored('Updating via installer...', 'cyan'));
|
|
635
|
-
console.log('');
|
|
636
|
-
|
|
637
|
-
const isWindows = process.platform === 'win32';
|
|
638
|
-
let command, args;
|
|
639
|
-
|
|
640
|
-
if (isWindows) {
|
|
641
|
-
// PowerShell
|
|
642
|
-
command = 'powershell.exe';
|
|
643
|
-
args = ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command',
|
|
644
|
-
'irm ccs.kaitran.ca/install | iex'];
|
|
645
|
-
} else {
|
|
646
|
-
// Unix (bash with proper shell invocation)
|
|
647
|
-
command = '/bin/bash';
|
|
648
|
-
args = ['-c', 'curl -fsSL ccs.kaitran.ca/install | bash'];
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
const child = spawn(command, args, {
|
|
652
|
-
stdio: 'inherit'
|
|
653
|
-
// Do NOT use shell: true
|
|
654
|
-
});
|
|
655
|
-
|
|
656
|
-
child.on('exit', (code) => {
|
|
657
|
-
if (code === 0) {
|
|
658
|
-
console.log('');
|
|
659
|
-
console.log(colored('[OK] Update successful!', 'green'));
|
|
660
|
-
console.log('');
|
|
661
|
-
console.log(`Run ${colored('ccs --version', 'yellow')} to verify`);
|
|
662
|
-
console.log('');
|
|
663
|
-
} else {
|
|
664
|
-
console.log('');
|
|
665
|
-
console.log(colored('[X] Update failed', 'red'));
|
|
666
|
-
console.log('');
|
|
667
|
-
console.log('Try manually:');
|
|
668
|
-
if (isWindows) {
|
|
669
|
-
console.log(colored(' irm ccs.kaitran.ca/install | iex', 'yellow'));
|
|
670
|
-
} else {
|
|
671
|
-
console.log(colored(' curl -fsSL ccs.kaitran.ca/install | bash', 'yellow'));
|
|
672
|
-
}
|
|
673
|
-
console.log('');
|
|
674
|
-
}
|
|
675
|
-
process.exit(code || 0);
|
|
676
|
-
});
|
|
677
|
-
|
|
678
|
-
child.on('error', (err) => {
|
|
679
|
-
console.log('');
|
|
680
|
-
console.log(colored('[X] Failed to run installer', 'red'));
|
|
681
|
-
console.log('');
|
|
682
|
-
console.log('Try manually:');
|
|
683
|
-
if (isWindows) {
|
|
684
|
-
console.log(colored(' irm ccs.kaitran.ca/install | iex', 'yellow'));
|
|
685
|
-
} else {
|
|
686
|
-
console.log(colored(' curl -fsSL ccs.kaitran.ca/install | bash', 'yellow'));
|
|
687
|
-
}
|
|
688
|
-
console.log('');
|
|
689
|
-
process.exit(1);
|
|
690
|
-
});
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
// Smart profile detection
|
|
695
|
-
function detectProfile(args) {
|
|
696
|
-
if (args.length === 0 || args[0].startsWith('-')) {
|
|
697
|
-
// No args or first arg is a flag → use default profile
|
|
698
|
-
return { profile: 'default', remainingArgs: args };
|
|
699
|
-
} else {
|
|
700
|
-
// First arg doesn't start with '-' → treat as profile name
|
|
701
|
-
return { profile: args[0], remainingArgs: args.slice(1) };
|
|
702
|
-
}
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
// Execute Claude CLI with embedded proxy (for GLMT profile)
|
|
706
|
-
async function execClaudeWithProxy(claudeCli, profileName, args) {
|
|
707
|
-
const { getSettingsPath } = require('./utils/config-manager');
|
|
708
|
-
|
|
709
|
-
// 1. Read settings to get API key
|
|
710
|
-
const settingsPath = getSettingsPath(profileName);
|
|
711
|
-
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
712
|
-
const apiKey = settings.env.ANTHROPIC_AUTH_TOKEN;
|
|
713
|
-
|
|
714
|
-
if (!apiKey || apiKey === 'YOUR_GLM_API_KEY_HERE') {
|
|
715
|
-
console.error('[X] GLMT profile requires Z.AI API key');
|
|
716
|
-
console.error(' Edit ~/.ccs/glmt.settings.json and set ANTHROPIC_AUTH_TOKEN');
|
|
717
|
-
process.exit(1);
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
// Detect verbose flag
|
|
721
|
-
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
722
|
-
|
|
723
|
-
// 2. Spawn embedded proxy with verbose flag
|
|
724
|
-
const proxyPath = path.join(__dirname, 'glmt', 'glmt-proxy.js');
|
|
725
|
-
const proxyArgs = verbose ? ['--verbose'] : [];
|
|
726
|
-
// Use process.execPath for Windows compatibility (CVE-2024-27980)
|
|
727
|
-
const proxy = spawn(process.execPath, [proxyPath, ...proxyArgs], {
|
|
728
|
-
stdio: ['ignore', 'pipe', verbose ? 'pipe' : 'inherit']
|
|
729
|
-
});
|
|
730
|
-
|
|
731
|
-
// 3. Wait for proxy ready signal (with timeout)
|
|
732
|
-
const { ProgressIndicator } = require('./utils/progress-indicator');
|
|
733
|
-
const spinner = new ProgressIndicator('Starting GLMT proxy');
|
|
734
|
-
spinner.start();
|
|
735
|
-
|
|
736
|
-
let port;
|
|
737
|
-
try {
|
|
738
|
-
port = await new Promise((resolve, reject) => {
|
|
739
|
-
const timeout = setTimeout(() => {
|
|
740
|
-
reject(new Error('Proxy startup timeout (5s)'));
|
|
741
|
-
}, 5000);
|
|
742
|
-
|
|
743
|
-
proxy.stdout.on('data', (data) => {
|
|
744
|
-
const match = data.toString().match(/PROXY_READY:(\d+)/);
|
|
745
|
-
if (match) {
|
|
746
|
-
clearTimeout(timeout);
|
|
747
|
-
resolve(parseInt(match[1]));
|
|
748
|
-
}
|
|
749
|
-
});
|
|
750
|
-
|
|
751
|
-
proxy.on('error', (error) => {
|
|
752
|
-
clearTimeout(timeout);
|
|
753
|
-
reject(error);
|
|
754
|
-
});
|
|
755
|
-
|
|
756
|
-
proxy.on('exit', (code) => {
|
|
757
|
-
if (code !== 0 && code !== null) {
|
|
758
|
-
clearTimeout(timeout);
|
|
759
|
-
reject(new Error(`Proxy exited with code ${code}`));
|
|
760
|
-
}
|
|
761
|
-
});
|
|
762
|
-
});
|
|
763
|
-
|
|
764
|
-
spinner.succeed(`GLMT proxy ready on port ${port}`);
|
|
765
|
-
} catch (error) {
|
|
766
|
-
spinner.fail('Failed to start GLMT proxy');
|
|
767
|
-
console.error('[X] Error:', error.message);
|
|
768
|
-
console.error('');
|
|
769
|
-
console.error('Possible causes:');
|
|
770
|
-
console.error(' 1. Port conflict (unlikely with random port)');
|
|
771
|
-
console.error(' 2. Node.js permission issue');
|
|
772
|
-
console.error(' 3. Firewall blocking localhost');
|
|
773
|
-
console.error('');
|
|
774
|
-
console.error('Workarounds:');
|
|
775
|
-
console.error(' - Use non-thinking mode: ccs glm "prompt"');
|
|
776
|
-
console.error(' - Enable verbose logging: ccs glmt --verbose "prompt"');
|
|
777
|
-
console.error(' - Check proxy logs in ~/.ccs/logs/ (if debug enabled)');
|
|
778
|
-
console.error('');
|
|
779
|
-
proxy.kill();
|
|
780
|
-
process.exit(1);
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
// 4. Spawn Claude CLI with proxy URL
|
|
784
|
-
const envVars = {
|
|
785
|
-
ANTHROPIC_BASE_URL: `http://127.0.0.1:${port}`,
|
|
786
|
-
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
787
|
-
ANTHROPIC_MODEL: 'glm-4.6'
|
|
788
|
-
};
|
|
789
|
-
|
|
790
|
-
// Use existing execClaude helper for consistent Windows handling
|
|
791
|
-
const isWindows = process.platform === 'win32';
|
|
792
|
-
const needsShell = isWindows && /\.(cmd|bat|ps1)$/i.test(claudeCli);
|
|
793
|
-
const env = { ...process.env, ...envVars };
|
|
794
|
-
|
|
795
|
-
let claude;
|
|
796
|
-
if (needsShell) {
|
|
797
|
-
// When shell needed: concatenate into string to avoid DEP0190 warning
|
|
798
|
-
const cmdString = [claudeCli, ...args].map(escapeShellArg).join(' ');
|
|
799
|
-
claude = spawn(cmdString, {
|
|
800
|
-
stdio: 'inherit',
|
|
801
|
-
windowsHide: true,
|
|
802
|
-
shell: true,
|
|
803
|
-
env
|
|
804
|
-
});
|
|
805
|
-
} else {
|
|
806
|
-
// When no shell needed: use array form (faster, no shell overhead)
|
|
807
|
-
claude = spawn(claudeCli, args, {
|
|
808
|
-
stdio: 'inherit',
|
|
809
|
-
windowsHide: true,
|
|
810
|
-
env
|
|
811
|
-
});
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
// 5. Cleanup: kill proxy when Claude exits
|
|
815
|
-
claude.on('exit', (code, signal) => {
|
|
816
|
-
proxy.kill('SIGTERM');
|
|
817
|
-
if (signal) process.kill(process.pid, signal);
|
|
818
|
-
else process.exit(code || 0);
|
|
819
|
-
});
|
|
820
|
-
|
|
821
|
-
claude.on('error', (error) => {
|
|
822
|
-
console.error('[X] Claude CLI error:', error);
|
|
823
|
-
proxy.kill('SIGTERM');
|
|
824
|
-
process.exit(1);
|
|
825
|
-
});
|
|
826
|
-
|
|
827
|
-
// Also handle parent process termination (use .once to avoid duplicates)
|
|
828
|
-
process.once('SIGTERM', () => {
|
|
829
|
-
proxy.kill('SIGTERM');
|
|
830
|
-
claude.kill('SIGTERM');
|
|
831
|
-
});
|
|
832
|
-
|
|
833
|
-
process.once('SIGINT', () => {
|
|
834
|
-
proxy.kill('SIGTERM');
|
|
835
|
-
claude.kill('SIGTERM');
|
|
836
|
-
});
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
/**
|
|
840
|
-
* Handle shell completion installation
|
|
841
|
-
*/
|
|
842
|
-
async function handleShellCompletionCommand(args) {
|
|
843
|
-
const { ShellCompletionInstaller } = require('./utils/shell-completion');
|
|
844
|
-
const { colored } = require('./utils/helpers');
|
|
845
|
-
|
|
846
|
-
console.log(colored('Shell Completion Installer', 'bold'));
|
|
847
|
-
console.log('');
|
|
848
|
-
|
|
849
|
-
// Parse flags
|
|
850
|
-
let targetShell = null;
|
|
851
|
-
if (args.includes('--bash')) targetShell = 'bash';
|
|
852
|
-
else if (args.includes('--zsh')) targetShell = 'zsh';
|
|
853
|
-
else if (args.includes('--fish')) targetShell = 'fish';
|
|
854
|
-
else if (args.includes('--powershell')) targetShell = 'powershell';
|
|
855
|
-
|
|
856
|
-
try {
|
|
857
|
-
const installer = new ShellCompletionInstaller();
|
|
858
|
-
const result = installer.install(targetShell);
|
|
859
|
-
|
|
860
|
-
if (result.alreadyInstalled) {
|
|
861
|
-
console.log(colored('[OK] Shell completion already installed', 'green'));
|
|
862
|
-
console.log('');
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
console.log(colored('[OK] Shell completion installed successfully!', 'green'));
|
|
867
|
-
console.log('');
|
|
868
|
-
console.log(result.message);
|
|
869
|
-
console.log('');
|
|
870
|
-
console.log(colored('To activate:', 'cyan'));
|
|
871
|
-
console.log(` ${result.reload}`);
|
|
872
|
-
console.log('');
|
|
873
|
-
console.log(colored('Then test:', 'cyan'));
|
|
874
|
-
console.log(' ccs <TAB> # See available profiles');
|
|
875
|
-
console.log(' ccs auth <TAB> # See auth subcommands');
|
|
876
|
-
console.log('');
|
|
877
|
-
} catch (error) {
|
|
878
|
-
console.error(colored('[X] Error:', 'red'), error.message);
|
|
879
|
-
console.error('');
|
|
880
|
-
console.error(colored('Usage:', 'yellow'));
|
|
881
|
-
console.error(' ccs --shell-completion # Auto-detect shell');
|
|
882
|
-
console.error(' ccs --shell-completion --bash # Install for bash');
|
|
883
|
-
console.error(' ccs --shell-completion --zsh # Install for zsh');
|
|
884
|
-
console.error(' ccs --shell-completion --fish # Install for fish');
|
|
885
|
-
console.error(' ccs --shell-completion --powershell # Install for PowerShell');
|
|
886
|
-
console.error('');
|
|
887
|
-
process.exit(1);
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
// Main execution
|
|
892
|
-
async function main() {
|
|
893
|
-
const args = process.argv.slice(2);
|
|
894
|
-
|
|
895
|
-
// Special case: version command (check BEFORE profile detection)
|
|
896
|
-
const firstArg = args[0];
|
|
897
|
-
if (firstArg === 'version' || firstArg === '--version' || firstArg === '-v') {
|
|
898
|
-
handleVersionCommand();
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
// Special case: help command
|
|
902
|
-
if (firstArg === '--help' || firstArg === '-h' || firstArg === 'help') {
|
|
903
|
-
handleHelpCommand();
|
|
904
|
-
return;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
// Special case: install command
|
|
908
|
-
if (firstArg === '--install') {
|
|
909
|
-
handleInstallCommand();
|
|
910
|
-
return;
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
// Special case: uninstall command
|
|
914
|
-
if (firstArg === '--uninstall') {
|
|
915
|
-
handleUninstallCommand();
|
|
916
|
-
return;
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
// Special case: shell completion installer
|
|
920
|
-
if (firstArg === '--shell-completion' || firstArg === '-sc') {
|
|
921
|
-
await handleShellCompletionCommand(args.slice(1));
|
|
922
|
-
return;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
// Special case: doctor command
|
|
926
|
-
if (firstArg === 'doctor' || firstArg === '--doctor') {
|
|
927
|
-
await handleDoctorCommand();
|
|
928
|
-
return;
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
// Special case: sync command (sync delegation commands and skills to ~/.claude/)
|
|
932
|
-
if (firstArg === 'sync' || firstArg === '--sync') {
|
|
933
|
-
await handleSyncCommand();
|
|
934
|
-
return;
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
// Special case: update command (update CCS to latest version)
|
|
938
|
-
if (firstArg === 'update' || firstArg === '--update') {
|
|
939
|
-
await handleUpdateCommand();
|
|
940
|
-
return;
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
// Special case: auth command (multi-account management)
|
|
944
|
-
if (firstArg === 'auth') {
|
|
945
|
-
const AuthCommands = require('./auth/auth-commands');
|
|
946
|
-
const authCommands = new AuthCommands();
|
|
947
|
-
await authCommands.route(args.slice(1));
|
|
948
|
-
return;
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
// Special case: headless delegation (-p flag)
|
|
952
|
-
if (args.includes('-p') || args.includes('--prompt')) {
|
|
953
|
-
const DelegationHandler = require('./delegation/delegation-handler');
|
|
954
|
-
const handler = new DelegationHandler();
|
|
955
|
-
await handler.route(args);
|
|
956
|
-
return;
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
// Auto-recovery for missing configuration
|
|
960
|
-
const recovery = new RecoveryManager();
|
|
961
|
-
const recovered = recovery.recoverAll();
|
|
962
|
-
|
|
963
|
-
if (recovered) {
|
|
964
|
-
recovery.showRecoveryHints();
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
// Detect profile
|
|
968
|
-
const { profile, remainingArgs } = detectProfile(args);
|
|
969
|
-
|
|
970
|
-
// Detect Claude CLI first (needed for all paths)
|
|
971
|
-
const claudeCli = detectClaudeCli();
|
|
972
|
-
if (!claudeCli) {
|
|
973
|
-
ErrorManager.showClaudeNotFound();
|
|
974
|
-
process.exit(1);
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
// Use ProfileDetector to determine profile type
|
|
978
|
-
const ProfileDetector = require('./auth/profile-detector');
|
|
979
|
-
const InstanceManager = require('./management/instance-manager');
|
|
980
|
-
const ProfileRegistry = require('./auth/profile-registry');
|
|
981
|
-
const { getSettingsPath } = require('./utils/config-manager');
|
|
982
|
-
|
|
983
|
-
const detector = new ProfileDetector();
|
|
984
|
-
|
|
985
|
-
try {
|
|
986
|
-
const profileInfo = detector.detectProfileType(profile);
|
|
987
|
-
|
|
988
|
-
if (profileInfo.type === 'settings') {
|
|
989
|
-
// Check if this is GLMT profile (requires proxy)
|
|
990
|
-
if (profileInfo.name === 'glmt') {
|
|
991
|
-
// GLMT FLOW: Settings-based with embedded proxy for thinking support
|
|
992
|
-
await execClaudeWithProxy(claudeCli, profileInfo.name, remainingArgs);
|
|
993
|
-
} else {
|
|
994
|
-
// EXISTING FLOW: Settings-based profile (glm, kimi)
|
|
995
|
-
// Use --settings flag (backward compatible)
|
|
996
|
-
const expandedSettingsPath = getSettingsPath(profileInfo.name);
|
|
997
|
-
execClaude(claudeCli, ['--settings', expandedSettingsPath, ...remainingArgs]);
|
|
998
|
-
}
|
|
999
|
-
} else if (profileInfo.type === 'account') {
|
|
1000
|
-
// NEW FLOW: Account-based profile (work, personal)
|
|
1001
|
-
// All platforms: Use instance isolation with CLAUDE_CONFIG_DIR
|
|
1002
|
-
const registry = new ProfileRegistry();
|
|
1003
|
-
const instanceMgr = new InstanceManager();
|
|
1004
|
-
|
|
1005
|
-
// Ensure instance exists (lazy init if needed)
|
|
1006
|
-
const instancePath = instanceMgr.ensureInstance(profileInfo.name);
|
|
1007
|
-
|
|
1008
|
-
// Update last_used timestamp
|
|
1009
|
-
registry.touchProfile(profileInfo.name);
|
|
1010
|
-
|
|
1011
|
-
// Execute Claude with instance isolation
|
|
1012
|
-
const envVars = { CLAUDE_CONFIG_DIR: instancePath };
|
|
1013
|
-
execClaude(claudeCli, remainingArgs, envVars);
|
|
1014
|
-
} else {
|
|
1015
|
-
// DEFAULT: No profile configured, use Claude's own defaults
|
|
1016
|
-
execClaude(claudeCli, remainingArgs);
|
|
1017
|
-
}
|
|
1018
|
-
} catch (error) {
|
|
1019
|
-
// Check if this is a profile not found error with suggestions
|
|
1020
|
-
if (error.profileName && error.availableProfiles !== undefined) {
|
|
1021
|
-
const allProfiles = error.availableProfiles.split('\n');
|
|
1022
|
-
ErrorManager.showProfileNotFound(error.profileName, allProfiles, error.suggestions);
|
|
1023
|
-
} else {
|
|
1024
|
-
console.error(`[X] ${error.message}`);
|
|
1025
|
-
}
|
|
1026
|
-
process.exit(1);
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
// Run main
|
|
1031
|
-
main().catch(error => {
|
|
1032
|
-
console.error('Fatal error:', error.message);
|
|
1033
|
-
process.exit(1);
|
|
1034
|
-
});
|