@kaitranntt/ccs 4.3.10 → 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.
Files changed (264) hide show
  1. package/README.md +27 -42
  2. package/VERSION +1 -1
  3. package/config/base-agy.settings.json +10 -0
  4. package/config/base-codex.settings.json +10 -0
  5. package/config/base-gemini.settings.json +10 -0
  6. package/dist/auth/auth-commands.d.ts +52 -0
  7. package/dist/auth/auth-commands.d.ts.map +1 -0
  8. package/dist/auth/auth-commands.js +479 -0
  9. package/dist/auth/auth-commands.js.map +1 -0
  10. package/dist/auth/profile-detector.d.ts +68 -0
  11. package/dist/auth/profile-detector.d.ts.map +1 -0
  12. package/dist/auth/profile-detector.js +209 -0
  13. package/dist/auth/profile-detector.js.map +1 -0
  14. package/dist/auth/profile-registry.d.ts +60 -0
  15. package/dist/auth/profile-registry.d.ts.map +1 -0
  16. package/dist/auth/profile-registry.js +188 -0
  17. package/dist/auth/profile-registry.js.map +1 -0
  18. package/dist/ccs.d.ts +10 -0
  19. package/dist/ccs.d.ts.map +1 -0
  20. package/dist/ccs.js +320 -0
  21. package/dist/ccs.js.map +1 -0
  22. package/dist/cliproxy/auth-handler.d.ts +93 -0
  23. package/dist/cliproxy/auth-handler.d.ts.map +1 -0
  24. package/dist/cliproxy/auth-handler.js +402 -0
  25. package/dist/cliproxy/auth-handler.js.map +1 -0
  26. package/dist/cliproxy/base-config-loader.d.ts +42 -0
  27. package/dist/cliproxy/base-config-loader.d.ts.map +1 -0
  28. package/dist/cliproxy/base-config-loader.js +123 -0
  29. package/dist/cliproxy/base-config-loader.js.map +1 -0
  30. package/dist/cliproxy/binary-manager.d.ts +104 -0
  31. package/dist/cliproxy/binary-manager.d.ts.map +1 -0
  32. package/dist/cliproxy/binary-manager.js +567 -0
  33. package/dist/cliproxy/binary-manager.js.map +1 -0
  34. package/dist/cliproxy/cliproxy-executor.d.ts +33 -0
  35. package/dist/cliproxy/cliproxy-executor.d.ts.map +1 -0
  36. package/dist/cliproxy/cliproxy-executor.js +297 -0
  37. package/dist/cliproxy/cliproxy-executor.js.map +1 -0
  38. package/dist/cliproxy/config-generator.d.ts +89 -0
  39. package/dist/cliproxy/config-generator.d.ts.map +1 -0
  40. package/dist/cliproxy/config-generator.js +263 -0
  41. package/dist/cliproxy/config-generator.js.map +1 -0
  42. package/dist/cliproxy/index.d.ts +13 -0
  43. package/dist/cliproxy/index.d.ts.map +1 -0
  44. package/dist/cliproxy/index.js +62 -0
  45. package/dist/cliproxy/index.js.map +1 -0
  46. package/dist/cliproxy/platform-detector.d.ts +48 -0
  47. package/dist/cliproxy/platform-detector.d.ts.map +1 -0
  48. package/dist/cliproxy/platform-detector.js +118 -0
  49. package/dist/cliproxy/platform-detector.js.map +1 -0
  50. package/dist/cliproxy/types.d.ts +169 -0
  51. package/dist/cliproxy/types.d.ts.map +1 -0
  52. package/dist/cliproxy/types.js +7 -0
  53. package/dist/cliproxy/types.js.map +1 -0
  54. package/dist/commands/doctor-command.d.ts +10 -0
  55. package/dist/commands/doctor-command.d.ts.map +1 -0
  56. package/dist/commands/doctor-command.js +44 -0
  57. package/dist/commands/doctor-command.js.map +1 -0
  58. package/dist/commands/help-command.d.ts +5 -0
  59. package/dist/commands/help-command.d.ts.map +1 -0
  60. package/dist/commands/help-command.js +104 -0
  61. package/dist/commands/help-command.js.map +1 -0
  62. package/dist/commands/install-command.d.ts +14 -0
  63. package/dist/commands/install-command.d.ts.map +1 -0
  64. package/dist/commands/install-command.js +39 -0
  65. package/dist/commands/install-command.js.map +1 -0
  66. package/dist/commands/shell-completion-command.d.ts +10 -0
  67. package/dist/commands/shell-completion-command.d.ts.map +1 -0
  68. package/dist/commands/shell-completion-command.js +85 -0
  69. package/dist/commands/shell-completion-command.js.map +1 -0
  70. package/dist/commands/sync-command.d.ts +10 -0
  71. package/dist/commands/sync-command.d.ts.map +1 -0
  72. package/dist/commands/sync-command.js +59 -0
  73. package/dist/commands/sync-command.js.map +1 -0
  74. package/dist/commands/update-command.d.ts +12 -0
  75. package/dist/commands/update-command.d.ts.map +1 -0
  76. package/dist/commands/update-command.js +295 -0
  77. package/dist/commands/update-command.js.map +1 -0
  78. package/dist/commands/version-command.d.ts +10 -0
  79. package/dist/commands/version-command.d.ts.map +1 -0
  80. package/dist/commands/version-command.js +100 -0
  81. package/dist/commands/version-command.js.map +1 -0
  82. package/dist/delegation/delegation-handler.d.ts +60 -0
  83. package/dist/delegation/delegation-handler.d.ts.map +1 -0
  84. package/dist/delegation/delegation-handler.js +174 -0
  85. package/dist/delegation/delegation-handler.js.map +1 -0
  86. package/dist/delegation/headless-executor.d.ts +114 -0
  87. package/dist/delegation/headless-executor.d.ts.map +1 -0
  88. package/dist/delegation/headless-executor.js +562 -0
  89. package/dist/delegation/headless-executor.js.map +1 -0
  90. package/dist/delegation/result-formatter.d.ts +108 -0
  91. package/dist/delegation/result-formatter.d.ts.map +1 -0
  92. package/dist/delegation/result-formatter.js +391 -0
  93. package/dist/delegation/result-formatter.js.map +1 -0
  94. package/dist/delegation/session-manager.d.ts +58 -0
  95. package/dist/delegation/session-manager.d.ts.map +1 -0
  96. package/dist/delegation/session-manager.js +153 -0
  97. package/dist/delegation/session-manager.js.map +1 -0
  98. package/dist/delegation/settings-parser.d.ts +31 -0
  99. package/dist/delegation/settings-parser.d.ts.map +1 -0
  100. package/dist/delegation/settings-parser.js +107 -0
  101. package/dist/delegation/settings-parser.js.map +1 -0
  102. package/dist/glmt/delta-accumulator.d.ts +210 -0
  103. package/dist/glmt/delta-accumulator.d.ts.map +1 -0
  104. package/dist/glmt/delta-accumulator.js +351 -0
  105. package/dist/glmt/delta-accumulator.js.map +1 -0
  106. package/dist/glmt/glmt-proxy.d.ts +72 -0
  107. package/dist/glmt/glmt-proxy.d.ts.map +1 -0
  108. package/dist/glmt/glmt-proxy.js +427 -0
  109. package/dist/glmt/glmt-proxy.js.map +1 -0
  110. package/dist/glmt/glmt-transformer.d.ts +265 -0
  111. package/dist/glmt/glmt-transformer.d.ts.map +1 -0
  112. package/dist/glmt/glmt-transformer.js +832 -0
  113. package/dist/glmt/glmt-transformer.js.map +1 -0
  114. package/dist/glmt/locale-enforcer.d.ts +38 -0
  115. package/dist/glmt/locale-enforcer.d.ts.map +1 -0
  116. package/dist/glmt/locale-enforcer.js +69 -0
  117. package/dist/glmt/locale-enforcer.js.map +1 -0
  118. package/dist/glmt/reasoning-enforcer.d.ts +52 -0
  119. package/dist/glmt/reasoning-enforcer.d.ts.map +1 -0
  120. package/dist/glmt/reasoning-enforcer.js +151 -0
  121. package/dist/glmt/reasoning-enforcer.js.map +1 -0
  122. package/dist/glmt/sse-parser.d.ts +47 -0
  123. package/dist/glmt/sse-parser.d.ts.map +1 -0
  124. package/dist/glmt/sse-parser.js +93 -0
  125. package/dist/glmt/sse-parser.js.map +1 -0
  126. package/dist/management/doctor.d.ts +104 -0
  127. package/dist/management/doctor.d.ts.map +1 -0
  128. package/dist/management/doctor.js +673 -0
  129. package/dist/management/doctor.js.map +1 -0
  130. package/dist/management/instance-manager.d.ts +57 -0
  131. package/dist/management/instance-manager.d.ts.map +1 -0
  132. package/dist/management/instance-manager.js +195 -0
  133. package/dist/management/instance-manager.js.map +1 -0
  134. package/dist/management/recovery-manager.d.ts +39 -0
  135. package/dist/management/recovery-manager.d.ts.map +1 -0
  136. package/dist/management/recovery-manager.js +141 -0
  137. package/dist/management/recovery-manager.js.map +1 -0
  138. package/dist/management/shared-manager.d.ts +47 -0
  139. package/dist/management/shared-manager.d.ts.map +1 -0
  140. package/dist/management/shared-manager.js +388 -0
  141. package/dist/management/shared-manager.js.map +1 -0
  142. package/dist/types/cli.d.ts +50 -0
  143. package/dist/types/cli.d.ts.map +1 -0
  144. package/dist/types/cli.js +16 -0
  145. package/dist/types/cli.js.map +1 -0
  146. package/dist/types/config.d.ts +51 -0
  147. package/dist/types/config.d.ts.map +1 -0
  148. package/dist/types/config.js +26 -0
  149. package/dist/types/config.js.map +1 -0
  150. package/dist/types/delegation.d.ts +61 -0
  151. package/dist/types/delegation.d.ts.map +1 -0
  152. package/dist/types/delegation.js +6 -0
  153. package/dist/types/delegation.js.map +1 -0
  154. package/dist/types/glmt.d.ts +95 -0
  155. package/dist/types/glmt.d.ts.map +1 -0
  156. package/dist/types/glmt.js +7 -0
  157. package/dist/types/glmt.js.map +1 -0
  158. package/dist/types/index.d.ts +13 -0
  159. package/dist/types/index.d.ts.map +1 -0
  160. package/dist/types/index.js +16 -0
  161. package/dist/types/index.js.map +1 -0
  162. package/dist/types/utils.d.ts +36 -0
  163. package/dist/types/utils.d.ts.map +1 -0
  164. package/dist/types/utils.js +22 -0
  165. package/dist/types/utils.js.map +1 -0
  166. package/dist/utils/claude-detector.d.ts +14 -0
  167. package/dist/utils/claude-detector.d.ts.map +1 -0
  168. package/dist/utils/claude-detector.js +112 -0
  169. package/dist/utils/claude-detector.js.map +1 -0
  170. package/dist/utils/claude-dir-installer.d.ts +46 -0
  171. package/dist/utils/claude-dir-installer.d.ts.map +1 -0
  172. package/dist/utils/claude-dir-installer.js +289 -0
  173. package/dist/utils/claude-dir-installer.js.map +1 -0
  174. package/dist/utils/claude-symlink-manager.d.ts +61 -0
  175. package/dist/utils/claude-symlink-manager.d.ts.map +1 -0
  176. package/dist/utils/claude-symlink-manager.js +291 -0
  177. package/dist/utils/claude-symlink-manager.js.map +1 -0
  178. package/dist/utils/config-manager.d.ts +32 -0
  179. package/dist/utils/config-manager.d.ts.map +1 -0
  180. package/dist/utils/config-manager.js +143 -0
  181. package/dist/utils/config-manager.js.map +1 -0
  182. package/dist/utils/delegation-validator.d.ts +39 -0
  183. package/dist/utils/delegation-validator.d.ts.map +1 -0
  184. package/dist/utils/delegation-validator.js +161 -0
  185. package/dist/utils/delegation-validator.js.map +1 -0
  186. package/dist/utils/error-codes.d.ts +36 -0
  187. package/dist/utils/error-codes.d.ts.map +1 -0
  188. package/dist/utils/error-codes.js +63 -0
  189. package/dist/utils/error-codes.js.map +1 -0
  190. package/dist/utils/error-manager.d.ts +59 -0
  191. package/dist/utils/error-manager.d.ts.map +1 -0
  192. package/dist/utils/error-manager.js +228 -0
  193. package/dist/utils/error-manager.js.map +1 -0
  194. package/dist/utils/helpers.d.ts +27 -0
  195. package/dist/utils/helpers.d.ts.map +1 -0
  196. package/dist/utils/helpers.js +150 -0
  197. package/dist/utils/helpers.js.map +1 -0
  198. package/dist/utils/package-manager-detector.d.ts +14 -0
  199. package/dist/utils/package-manager-detector.d.ts.map +1 -0
  200. package/dist/utils/package-manager-detector.js +162 -0
  201. package/dist/utils/package-manager-detector.js.map +1 -0
  202. package/dist/utils/progress-indicator.d.ts +52 -0
  203. package/dist/utils/progress-indicator.d.ts.map +1 -0
  204. package/dist/utils/progress-indicator.js +102 -0
  205. package/dist/utils/progress-indicator.js.map +1 -0
  206. package/dist/utils/prompt.d.ts +29 -0
  207. package/dist/utils/prompt.d.ts.map +1 -0
  208. package/dist/utils/prompt.js +116 -0
  209. package/dist/utils/prompt.js.map +1 -0
  210. package/dist/utils/shell-completion.d.ts +52 -0
  211. package/dist/utils/shell-completion.d.ts.map +1 -0
  212. package/dist/utils/shell-completion.js +231 -0
  213. package/dist/utils/shell-completion.js.map +1 -0
  214. package/dist/utils/shell-executor.d.ts +15 -0
  215. package/dist/utils/shell-executor.d.ts.map +1 -0
  216. package/dist/utils/shell-executor.js +57 -0
  217. package/dist/utils/shell-executor.js.map +1 -0
  218. package/dist/utils/update-checker.d.ts +48 -0
  219. package/dist/utils/update-checker.d.ts.map +1 -0
  220. package/dist/utils/update-checker.js +241 -0
  221. package/dist/utils/update-checker.js.map +1 -0
  222. package/lib/ccs +21 -1907
  223. package/lib/ccs.ps1 +26 -1800
  224. package/lib/error-codes.ps1 +2 -1
  225. package/lib/prompt.ps1 +2 -2
  226. package/package.json +31 -11
  227. package/scripts/add-shebang.js +39 -0
  228. package/scripts/bump-version.sh +25 -37
  229. package/scripts/dev-install.sh +32 -11
  230. package/scripts/postinstall.js +32 -29
  231. package/README.ja.md +0 -649
  232. package/README.vi.md +0 -649
  233. package/bin/auth/auth-commands.js +0 -499
  234. package/bin/auth/profile-detector.js +0 -204
  235. package/bin/auth/profile-registry.js +0 -225
  236. package/bin/ccs.js +0 -1034
  237. package/bin/delegation/README.md +0 -191
  238. package/bin/delegation/delegation-handler.js +0 -212
  239. package/bin/delegation/headless-executor.js +0 -618
  240. package/bin/delegation/result-formatter.js +0 -485
  241. package/bin/delegation/session-manager.js +0 -157
  242. package/bin/delegation/settings-parser.js +0 -109
  243. package/bin/glmt/delta-accumulator.js +0 -276
  244. package/bin/glmt/glmt-proxy.js +0 -495
  245. package/bin/glmt/glmt-transformer.js +0 -999
  246. package/bin/glmt/locale-enforcer.js +0 -72
  247. package/bin/glmt/reasoning-enforcer.js +0 -173
  248. package/bin/glmt/sse-parser.js +0 -96
  249. package/bin/management/doctor.js +0 -599
  250. package/bin/management/instance-manager.js +0 -207
  251. package/bin/management/recovery-manager.js +0 -135
  252. package/bin/management/shared-manager.js +0 -285
  253. package/bin/utils/claude-detector.js +0 -73
  254. package/bin/utils/claude-dir-installer.js +0 -283
  255. package/bin/utils/claude-symlink-manager.js +0 -289
  256. package/bin/utils/config-manager.js +0 -103
  257. package/bin/utils/delegation-validator.js +0 -154
  258. package/bin/utils/error-codes.js +0 -59
  259. package/bin/utils/error-manager.js +0 -165
  260. package/bin/utils/helpers.js +0 -136
  261. package/bin/utils/progress-indicator.js +0 -111
  262. package/bin/utils/prompt.js +0 -134
  263. package/bin/utils/shell-completion.js +0 -256
  264. package/bin/utils/update-checker.js +0 -243
@@ -1,599 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
- const { spawn } = require('child_process');
7
- const { colored } = require('../utils/helpers');
8
- const { detectClaudeCli } = require('../utils/claude-detector');
9
-
10
- // Make ora optional (might not be available during npm install postinstall)
11
- // ora v9+ is an ES module, need to use .default for CommonJS
12
- let ora = null;
13
- try {
14
- const oraModule = require('ora');
15
- ora = oraModule.default || oraModule;
16
- } catch (e) {
17
- // ora not available, create fallback spinner that uses console.log
18
- ora = function(text) {
19
- return {
20
- start: () => ({
21
- succeed: (msg) => console.log(msg || `[OK] ${text}`),
22
- fail: (msg) => console.log(msg || `[X] ${text}`),
23
- warn: (msg) => console.log(msg || `[!] ${text}`),
24
- info: (msg) => console.log(msg || `[i] ${text}`),
25
- text: ''
26
- })
27
- };
28
- };
29
- }
30
-
31
- const Table = require('cli-table3');
32
-
33
- /**
34
- * Health check results
35
- */
36
- class HealthCheck {
37
- constructor() {
38
- this.checks = [];
39
- this.warnings = [];
40
- this.errors = [];
41
- this.details = {}; // Store detailed information for summary table
42
- }
43
-
44
- addCheck(name, status, message = '', fix = null, details = null) {
45
- this.checks.push({ name, status, message, fix });
46
-
47
- if (status === 'error') this.errors.push({ name, message, fix });
48
- if (status === 'warning') this.warnings.push({ name, message, fix });
49
-
50
- // Store details for summary table
51
- if (details) {
52
- this.details[name] = details;
53
- }
54
- }
55
-
56
- hasErrors() {
57
- return this.errors.length > 0;
58
- }
59
-
60
- hasWarnings() {
61
- return this.warnings.length > 0;
62
- }
63
-
64
- isHealthy() {
65
- return !this.hasErrors();
66
- }
67
- }
68
-
69
- /**
70
- * CCS Health Check and Diagnostics
71
- */
72
- class Doctor {
73
- constructor() {
74
- this.homedir = os.homedir();
75
- this.ccsDir = path.join(this.homedir, '.ccs');
76
- this.claudeDir = path.join(this.homedir, '.claude');
77
- this.results = new HealthCheck();
78
-
79
- // Get CCS version
80
- try {
81
- this.ccsVersion = require('../../package.json').version;
82
- } catch (e) {
83
- this.ccsVersion = 'unknown';
84
- }
85
- }
86
-
87
- /**
88
- * Run all health checks
89
- */
90
- async runAllChecks() {
91
- console.log(colored('Running CCS Health Check...', 'cyan'));
92
- console.log('');
93
-
94
- // Store CCS version in details
95
- this.results.details['CCS Version'] = { status: 'OK', info: `v${this.ccsVersion}` };
96
-
97
- // Group 1: System
98
- console.log(colored('System:', 'bold'));
99
- await this.checkClaudeCli();
100
- this.checkCcsDirectory();
101
- console.log('');
102
-
103
- // Group 2: Configuration
104
- console.log(colored('Configuration:', 'bold'));
105
- this.checkConfigFiles();
106
- this.checkClaudeSettings();
107
- console.log('');
108
-
109
- // Group 3: Profiles & Delegation
110
- console.log(colored('Profiles & Delegation:', 'bold'));
111
- this.checkProfiles();
112
- this.checkInstances();
113
- this.checkDelegation();
114
- console.log('');
115
-
116
- // Group 4: System Health
117
- console.log(colored('System Health:', 'bold'));
118
- this.checkPermissions();
119
- this.checkCcsSymlinks();
120
- console.log('');
121
-
122
- this.showReport();
123
- return this.results;
124
- }
125
-
126
- /**
127
- * Check 1: Claude CLI availability
128
- */
129
- async checkClaudeCli() {
130
- const spinner = ora('Checking Claude CLI').start();
131
-
132
- const claudeCli = detectClaudeCli();
133
-
134
- // Try to execute claude --version
135
- try {
136
- const result = await new Promise((resolve, reject) => {
137
- const child = spawn(claudeCli, ['--version'], {
138
- stdio: 'pipe',
139
- timeout: 5000
140
- });
141
-
142
- let output = '';
143
- child.stdout.on('data', data => output += data);
144
- child.stderr.on('data', data => output += data);
145
-
146
- child.on('close', code => {
147
- if (code === 0) resolve(output);
148
- else reject(new Error('Exit code ' + code));
149
- });
150
-
151
- child.on('error', reject);
152
- });
153
-
154
- // Extract version from output
155
- const versionMatch = result.match(/(\d+\.\d+\.\d+)/);
156
- const version = versionMatch ? versionMatch[1] : 'unknown';
157
-
158
- spinner.succeed(` ${'Claude CLI'.padEnd(26)}${colored('[OK]', 'green')} ${claudeCli} (v${version})`);
159
- this.results.addCheck('Claude CLI', 'success', `Found: ${claudeCli}`, null, {
160
- status: 'OK',
161
- info: `v${version} (${claudeCli})`
162
- });
163
- } catch (err) {
164
- spinner.fail(` ${'Claude CLI'.padEnd(26)}${colored('[X]', 'red')} Not found or not working`);
165
- this.results.addCheck(
166
- 'Claude CLI',
167
- 'error',
168
- 'Claude CLI not found or not working',
169
- 'Install from: https://docs.claude.com/en/docs/claude-code/installation',
170
- { status: 'ERROR', info: 'Not installed' }
171
- );
172
- }
173
- }
174
-
175
- /**
176
- * Check 2: ~/.ccs/ directory
177
- */
178
- checkCcsDirectory() {
179
- const spinner = ora('Checking ~/.ccs/ directory').start();
180
-
181
- if (fs.existsSync(this.ccsDir)) {
182
- spinner.succeed(` ${'CCS Directory'.padEnd(26)}${colored('[OK]', 'green')} ~/.ccs/`);
183
- this.results.addCheck('CCS Directory', 'success', null, null, {
184
- status: 'OK',
185
- info: '~/.ccs/'
186
- });
187
- } else {
188
- spinner.fail(` ${'CCS Directory'.padEnd(26)}${colored('[X]', 'red')} Not found`);
189
- this.results.addCheck(
190
- 'CCS Directory',
191
- 'error',
192
- '~/.ccs/ directory not found',
193
- 'Run: npm install -g @kaitranntt/ccs --force',
194
- { status: 'ERROR', info: 'Not found' }
195
- );
196
- }
197
- }
198
-
199
- /**
200
- * Check 3: Config files
201
- */
202
- checkConfigFiles() {
203
- const files = [
204
- { path: path.join(this.ccsDir, 'config.json'), name: 'config.json', key: 'config.json' },
205
- { path: path.join(this.ccsDir, 'glm.settings.json'), name: 'glm.settings.json', key: 'GLM Settings', profile: 'glm' },
206
- { path: path.join(this.ccsDir, 'kimi.settings.json'), name: 'kimi.settings.json', key: 'Kimi Settings', profile: 'kimi' }
207
- ];
208
-
209
- const { DelegationValidator } = require('../utils/delegation-validator');
210
-
211
- for (const file of files) {
212
- const spinner = ora(`Checking ${file.name}`).start();
213
-
214
- if (!fs.existsSync(file.path)) {
215
- spinner.fail(` ${file.name.padEnd(26)}${colored('[X]', 'red')} Not found`);
216
- this.results.addCheck(
217
- file.name,
218
- 'error',
219
- `${file.name} not found`,
220
- 'Run: npm install -g @kaitranntt/ccs --force',
221
- { status: 'ERROR', info: 'Not found' }
222
- );
223
- continue;
224
- }
225
-
226
- // Validate JSON
227
- try {
228
- const content = fs.readFileSync(file.path, 'utf8');
229
- const config = JSON.parse(content);
230
-
231
- // Extract useful info based on file type
232
- let info = 'Valid';
233
- let status = 'OK';
234
-
235
- if (file.profile) {
236
- // For settings files, check if API key is configured
237
- const validation = DelegationValidator.validate(file.profile);
238
-
239
- if (validation.valid) {
240
- info = 'Key configured';
241
- status = 'OK';
242
- } else if (validation.error && validation.error.includes('placeholder')) {
243
- info = 'Placeholder key (not configured)';
244
- status = 'WARN';
245
- } else {
246
- info = 'Valid JSON';
247
- status = 'OK';
248
- }
249
- }
250
-
251
- const statusIcon = status === 'OK' ? colored('[OK]', 'green') : colored('[!]', 'yellow');
252
-
253
- if (status === 'WARN') {
254
- spinner.warn(` ${file.name.padEnd(26)}${statusIcon} ${info}`);
255
- } else {
256
- spinner.succeed(` ${file.name.padEnd(26)}${statusIcon} ${info}`);
257
- }
258
-
259
- this.results.addCheck(file.name, status === 'OK' ? 'success' : 'warning', null, null, {
260
- status: status,
261
- info: info
262
- });
263
- } catch (e) {
264
- spinner.fail(` ${file.name.padEnd(26)}${colored('[X]', 'red')} Invalid JSON`);
265
- this.results.addCheck(
266
- file.name,
267
- 'error',
268
- `Invalid JSON: ${e.message}`,
269
- `Backup and recreate: mv ${file.path} ${file.path}.backup && npm install -g @kaitranntt/ccs --force`,
270
- { status: 'ERROR', info: 'Invalid JSON' }
271
- );
272
- }
273
- }
274
- }
275
-
276
- /**
277
- * Check 4: Claude settings
278
- */
279
- checkClaudeSettings() {
280
- const spinner = ora('Checking ~/.claude/settings.json').start();
281
- const settingsPath = path.join(this.claudeDir, 'settings.json');
282
-
283
- if (!fs.existsSync(settingsPath)) {
284
- spinner.warn(` ${'~/.claude/settings.json'.padEnd(26)}${colored('[!]', 'yellow')} Not found`);
285
- this.results.addCheck(
286
- 'Claude Settings',
287
- 'warning',
288
- '~/.claude/settings.json not found',
289
- 'Run: claude /login'
290
- );
291
- return;
292
- }
293
-
294
- // Validate JSON
295
- try {
296
- const content = fs.readFileSync(settingsPath, 'utf8');
297
- JSON.parse(content);
298
- spinner.succeed(` ${'~/.claude/settings.json'.padEnd(26)}${colored('[OK]', 'green')}`);
299
- this.results.addCheck('Claude Settings', 'success');
300
- } catch (e) {
301
- spinner.warn(` ${'~/.claude/settings.json'.padEnd(26)}${colored('[!]', 'yellow')} Invalid JSON`);
302
- this.results.addCheck(
303
- 'Claude Settings',
304
- 'warning',
305
- `Invalid JSON: ${e.message}`,
306
- 'Run: claude /login'
307
- );
308
- }
309
- }
310
-
311
- /**
312
- * Check 5: Profile configurations
313
- */
314
- checkProfiles() {
315
- const spinner = ora('Checking profiles').start();
316
- const configPath = path.join(this.ccsDir, 'config.json');
317
-
318
- if (!fs.existsSync(configPath)) {
319
- spinner.info(` ${'Profiles'.padEnd(26)}${colored('[SKIP]', 'cyan')} config.json not found`);
320
- return;
321
- }
322
-
323
- try {
324
- const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
325
-
326
- if (!config.profiles || typeof config.profiles !== 'object') {
327
- spinner.fail(` ${'Profiles'.padEnd(26)}${colored('[X]', 'red')} Missing profiles object`);
328
- this.results.addCheck(
329
- 'Profiles',
330
- 'error',
331
- 'config.json missing profiles object',
332
- 'Run: npm install -g @kaitranntt/ccs --force',
333
- { status: 'ERROR', info: 'Missing profiles object' }
334
- );
335
- return;
336
- }
337
-
338
- const profileCount = Object.keys(config.profiles).length;
339
- const profileNames = Object.keys(config.profiles).join(', ');
340
-
341
- spinner.succeed(` ${'Profiles'.padEnd(26)}${colored('[OK]', 'green')} ${profileCount} configured (${profileNames})`);
342
- this.results.addCheck('Profiles', 'success', `${profileCount} profiles configured`, null, {
343
- status: 'OK',
344
- info: `${profileCount} configured (${profileNames.length > 30 ? profileNames.substring(0, 27) + '...' : profileNames})`
345
- });
346
- } catch (e) {
347
- spinner.fail(` ${'Profiles'.padEnd(26)}${colored('[X]', 'red')} ${e.message}`);
348
- this.results.addCheck('Profiles', 'error', e.message, null, {
349
- status: 'ERROR',
350
- info: e.message
351
- });
352
- }
353
- }
354
-
355
- /**
356
- * Check 6: Instance directories (account-based profiles)
357
- */
358
- checkInstances() {
359
- const spinner = ora('Checking instances').start();
360
- const instancesDir = path.join(this.ccsDir, 'instances');
361
-
362
- if (!fs.existsSync(instancesDir)) {
363
- spinner.info(` ${'Instances'.padEnd(26)}${colored('[i]', 'cyan')} No account profiles`);
364
- this.results.addCheck('Instances', 'success', 'No account profiles configured');
365
- return;
366
- }
367
-
368
- const instances = fs.readdirSync(instancesDir).filter(name => {
369
- return fs.statSync(path.join(instancesDir, name)).isDirectory();
370
- });
371
-
372
- if (instances.length === 0) {
373
- spinner.info(` ${'Instances'.padEnd(26)}${colored('[i]', 'cyan')} No account profiles`);
374
- this.results.addCheck('Instances', 'success', 'No account profiles');
375
- return;
376
- }
377
-
378
- spinner.succeed(` ${'Instances'.padEnd(26)}${colored('[OK]', 'green')} ${instances.length} account profiles`);
379
- this.results.addCheck('Instances', 'success', `${instances.length} account profiles`);
380
- }
381
-
382
- /**
383
- * Check 7: Delegation system
384
- */
385
- checkDelegation() {
386
- const spinner = ora('Checking delegation').start();
387
-
388
- // Check if delegation commands exist in ~/.ccs/.claude/commands/
389
- const ccsClaudeCommandsDir = path.join(this.ccsDir, '.claude', 'commands');
390
- const hasCcsCommand = fs.existsSync(path.join(ccsClaudeCommandsDir, 'ccs.md'));
391
- const hasContinueCommand = fs.existsSync(path.join(ccsClaudeCommandsDir, 'ccs', 'continue.md'));
392
-
393
- if (!hasCcsCommand || !hasContinueCommand) {
394
- spinner.warn(` ${'Delegation'.padEnd(26)}${colored('[!]', 'yellow')} Not installed`);
395
- this.results.addCheck(
396
- 'Delegation',
397
- 'warning',
398
- 'Delegation commands not found',
399
- 'Install with: npm install -g @kaitranntt/ccs --force',
400
- { status: 'WARN', info: 'Not installed' }
401
- );
402
- return;
403
- }
404
-
405
- // Check profile validity using DelegationValidator
406
- const { DelegationValidator } = require('../utils/delegation-validator');
407
- const readyProfiles = [];
408
-
409
- for (const profile of ['glm', 'kimi']) {
410
- const validation = DelegationValidator.validate(profile);
411
- if (validation.valid) {
412
- readyProfiles.push(profile);
413
- }
414
- }
415
-
416
- if (readyProfiles.length === 0) {
417
- spinner.warn(` ${'Delegation'.padEnd(26)}${colored('[!]', 'yellow')} No profiles ready`);
418
- this.results.addCheck(
419
- 'Delegation',
420
- 'warning',
421
- 'Delegation installed but no profiles configured',
422
- 'Configure profiles with valid API keys (not placeholders)',
423
- { status: 'WARN', info: 'No profiles ready' }
424
- );
425
- return;
426
- }
427
-
428
- spinner.succeed(` ${'Delegation'.padEnd(26)}${colored('[OK]', 'green')} ${readyProfiles.length} profiles ready (${readyProfiles.join(', ')})`);
429
- this.results.addCheck(
430
- 'Delegation',
431
- 'success',
432
- `${readyProfiles.length} profile(s) ready: ${readyProfiles.join(', ')}`,
433
- null,
434
- { status: 'OK', info: `${readyProfiles.length} profiles ready` }
435
- );
436
- }
437
-
438
- /**
439
- * Check 8: File permissions
440
- */
441
- checkPermissions() {
442
- const spinner = ora('Checking permissions').start();
443
- const testFile = path.join(this.ccsDir, '.permission-test');
444
-
445
- try {
446
- fs.writeFileSync(testFile, 'test', 'utf8');
447
- fs.unlinkSync(testFile);
448
- spinner.succeed(` ${'Permissions'.padEnd(26)}${colored('[OK]', 'green')} Write access verified`);
449
- this.results.addCheck('Permissions', 'success', null, null, {
450
- status: 'OK',
451
- info: 'Write access verified'
452
- });
453
- } catch (e) {
454
- spinner.fail(` ${'Permissions'.padEnd(26)}${colored('[X]', 'red')} Cannot write to ~/.ccs/`);
455
- this.results.addCheck(
456
- 'Permissions',
457
- 'error',
458
- 'Cannot write to ~/.ccs/',
459
- 'Fix: sudo chown -R $USER ~/.ccs ~/.claude && chmod 755 ~/.ccs ~/.claude',
460
- { status: 'ERROR', info: 'Cannot write to ~/.ccs/' }
461
- );
462
- }
463
- }
464
-
465
- /**
466
- * Check 9: CCS symlinks to ~/.claude/
467
- */
468
- checkCcsSymlinks() {
469
- const spinner = ora('Checking CCS symlinks').start();
470
-
471
- try {
472
- const ClaudeSymlinkManager = require('../utils/claude-symlink-manager');
473
- const manager = new ClaudeSymlinkManager();
474
- const health = manager.checkHealth();
475
-
476
- if (health.healthy) {
477
- const itemCount = manager.ccsItems.length;
478
- spinner.succeed(` ${'CCS Symlinks'.padEnd(26)}${colored('[OK]', 'green')} ${itemCount}/${itemCount} items linked`);
479
- this.results.addCheck('CCS Symlinks', 'success', 'All CCS items properly symlinked', null, {
480
- status: 'OK',
481
- info: `${itemCount}/${itemCount} items synced`
482
- });
483
- } else {
484
- spinner.warn(` ${'CCS Symlinks'.padEnd(26)}${colored('[!]', 'yellow')} ${health.issues.length} issues found`);
485
- this.results.addCheck(
486
- 'CCS Symlinks',
487
- 'warning',
488
- health.issues.join(', '),
489
- 'Run: ccs sync',
490
- { status: 'WARN', info: `${health.issues.length} issues` }
491
- );
492
- }
493
- } catch (e) {
494
- spinner.warn(` ${'CCS Symlinks'.padEnd(26)}${colored('[!]', 'yellow')} Could not check`);
495
- this.results.addCheck(
496
- 'CCS Symlinks',
497
- 'warning',
498
- 'Could not check CCS symlinks: ' + e.message,
499
- 'Run: ccs sync',
500
- { status: 'WARN', info: 'Could not check' }
501
- );
502
- }
503
- }
504
-
505
- /**
506
- * Show health check report
507
- */
508
- showReport() {
509
- console.log('');
510
-
511
- // Calculate exact table width to match header bars
512
- // colWidths: [20, 10, 35] = 65 + borders (4) = 69 total
513
- const tableWidth = 69;
514
- const headerBar = '═'.repeat(tableWidth);
515
-
516
- console.log(colored(headerBar, 'cyan'));
517
- console.log(colored(' Health Check Summary', 'bold'));
518
- console.log(colored(headerBar, 'cyan'));
519
-
520
- // Create summary table with detailed information
521
- const table = new Table({
522
- head: [colored('Component', 'cyan'), colored('Status', 'cyan'), colored('Details', 'cyan')],
523
- colWidths: [20, 10, 35],
524
- wordWrap: true,
525
- chars: {
526
- 'top': '═', 'top-mid': '╤', 'top-left': '╔', 'top-right': '╗',
527
- 'bottom': '═', 'bottom-mid': '╧', 'bottom-left': '╚', 'bottom-right': '╝',
528
- 'left': '║', 'left-mid': '╟', 'mid': '─', 'mid-mid': '┼',
529
- 'right': '║', 'right-mid': '╢', 'middle': '│'
530
- }
531
- });
532
-
533
- // Populate table with collected details
534
- for (const [component, detail] of Object.entries(this.results.details)) {
535
- const statusColor = detail.status === 'OK' ? 'green' : detail.status === 'ERROR' ? 'red' : 'yellow';
536
- table.push([
537
- component,
538
- colored(detail.status, statusColor),
539
- detail.info || ''
540
- ]);
541
- }
542
-
543
- console.log(table.toString());
544
- console.log('');
545
-
546
- // Show errors and warnings if present
547
- if (this.results.hasErrors()) {
548
- console.log(colored('Errors:', 'red'));
549
- this.results.errors.forEach(err => {
550
- console.log(` [X] ${err.name}: ${err.message}`);
551
- if (err.fix) {
552
- console.log(` Fix: ${err.fix}`);
553
- }
554
- });
555
- console.log('');
556
- }
557
-
558
- if (this.results.hasWarnings()) {
559
- console.log(colored('Warnings:', 'yellow'));
560
- this.results.warnings.forEach(warn => {
561
- console.log(` [!] ${warn.name}: ${warn.message}`);
562
- if (warn.fix) {
563
- console.log(` Fix: ${warn.fix}`);
564
- }
565
- });
566
- console.log('');
567
- }
568
-
569
- // Final status
570
- if (this.results.isHealthy() && !this.results.hasWarnings()) {
571
- console.log(colored('[OK] All checks passed! Your CCS installation is healthy.', 'green'));
572
- } else if (this.results.hasErrors()) {
573
- console.log(colored('[X] Status: Installation has errors', 'red'));
574
- console.log('Run suggested fixes above to resolve issues.');
575
- } else {
576
- console.log(colored('[OK] Status: Installation healthy (warnings only)', 'green'));
577
- }
578
-
579
- console.log('');
580
- }
581
-
582
- /**
583
- * Generate JSON report
584
- */
585
- generateJsonReport() {
586
- return JSON.stringify({
587
- timestamp: new Date().toISOString(),
588
- platform: process.platform,
589
- nodeVersion: process.version,
590
- ccsVersion: require('../package.json').version,
591
- checks: this.results.checks,
592
- errors: this.results.errors,
593
- warnings: this.results.warnings,
594
- healthy: this.results.isHealthy()
595
- }, null, 2);
596
- }
597
- }
598
-
599
- module.exports = Doctor;