@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,207 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
- const SharedManager = require('./shared-manager');
7
-
8
- /**
9
- * Instance Manager (Simplified)
10
- *
11
- * Manages isolated Claude CLI instances per profile for concurrent sessions.
12
- * Each instance is an isolated CLAUDE_CONFIG_DIR where users login directly.
13
- * No credential copying/encryption - Claude manages credentials per instance.
14
- */
15
- class InstanceManager {
16
- constructor() {
17
- this.instancesDir = path.join(os.homedir(), '.ccs', 'instances');
18
- this.sharedManager = new SharedManager();
19
- }
20
-
21
- /**
22
- * Ensure instance exists for profile (lazy init only)
23
- * @param {string} profileName - Profile name
24
- * @returns {string} Instance path
25
- */
26
- ensureInstance(profileName) {
27
- const instancePath = this.getInstancePath(profileName);
28
-
29
- // Lazy initialization
30
- if (!fs.existsSync(instancePath)) {
31
- this.initializeInstance(profileName, instancePath);
32
- }
33
-
34
- // Validate structure (auto-fix missing dirs)
35
- this.validateInstance(instancePath);
36
-
37
- return instancePath;
38
- }
39
-
40
- /**
41
- * Get instance path for profile
42
- * @param {string} profileName - Profile name
43
- * @returns {string} Instance directory path
44
- */
45
- getInstancePath(profileName) {
46
- const safeName = this._sanitizeName(profileName);
47
- return path.join(this.instancesDir, safeName);
48
- }
49
-
50
- /**
51
- * Initialize new instance directory
52
- * @param {string} profileName - Profile name
53
- * @param {string} instancePath - Instance directory path
54
- * @throws {Error} If initialization fails
55
- */
56
- initializeInstance(profileName, instancePath) {
57
- try {
58
- // Create base directory
59
- fs.mkdirSync(instancePath, { recursive: true, mode: 0o700 });
60
-
61
- // Create Claude-expected subdirectories (profile-specific only)
62
- const subdirs = [
63
- 'session-env',
64
- 'todos',
65
- 'logs',
66
- 'file-history',
67
- 'shell-snapshots',
68
- 'debug',
69
- '.anthropic'
70
- ];
71
-
72
- subdirs.forEach(dir => {
73
- const dirPath = path.join(instancePath, dir);
74
- if (!fs.existsSync(dirPath)) {
75
- fs.mkdirSync(dirPath, { recursive: true, mode: 0o700 });
76
- }
77
- });
78
-
79
- // Symlink shared directories (Phase 1: commands, skills)
80
- this.sharedManager.linkSharedDirectories(instancePath);
81
-
82
- // Copy global configs if exist (settings.json only)
83
- this._copyGlobalConfigs(instancePath);
84
- } catch (error) {
85
- throw new Error(`Failed to initialize instance for ${profileName}: ${error.message}`);
86
- }
87
- }
88
-
89
- /**
90
- * Validate instance directory structure (auto-fix missing directories)
91
- * @param {string} instancePath - Instance path
92
- */
93
- validateInstance(instancePath) {
94
- // Check required directories (auto-create if missing for migration)
95
- const requiredDirs = [
96
- 'session-env',
97
- 'todos',
98
- 'logs',
99
- 'file-history',
100
- 'shell-snapshots',
101
- 'debug',
102
- '.anthropic'
103
- ];
104
-
105
- for (const dir of requiredDirs) {
106
- const dirPath = path.join(instancePath, dir);
107
- if (!fs.existsSync(dirPath)) {
108
- // Auto-create missing directory (migration from older versions)
109
- fs.mkdirSync(dirPath, { recursive: true, mode: 0o700 });
110
- }
111
- }
112
-
113
- // Note: Credentials managed by Claude CLI in instance (no validation needed)
114
- }
115
-
116
- /**
117
- * Delete instance for profile
118
- * @param {string} profileName - Profile name
119
- */
120
- deleteInstance(profileName) {
121
- const instancePath = this.getInstancePath(profileName);
122
-
123
- if (!fs.existsSync(instancePath)) {
124
- return;
125
- }
126
-
127
- // Recursive delete
128
- fs.rmSync(instancePath, { recursive: true, force: true });
129
- }
130
-
131
- /**
132
- * List all instance names
133
- * @returns {Array<string>} Instance names
134
- */
135
- listInstances() {
136
- if (!fs.existsSync(this.instancesDir)) {
137
- return [];
138
- }
139
-
140
- return fs.readdirSync(this.instancesDir)
141
- .filter(name => {
142
- const instancePath = path.join(this.instancesDir, name);
143
- return fs.statSync(instancePath).isDirectory();
144
- });
145
- }
146
-
147
- /**
148
- * Check if instance exists for profile
149
- * @param {string} profileName - Profile name
150
- * @returns {boolean} True if exists
151
- */
152
- hasInstance(profileName) {
153
- const instancePath = this.getInstancePath(profileName);
154
- return fs.existsSync(instancePath);
155
- }
156
-
157
- /**
158
- * Copy global configs to instance (optional)
159
- * @param {string} instancePath - Instance path
160
- */
161
- _copyGlobalConfigs(instancePath) {
162
- const globalConfigDir = path.join(os.homedir(), '.claude');
163
-
164
- // Copy settings.json only (commands/skills are now symlinked to shared/)
165
- const globalSettings = path.join(globalConfigDir, 'settings.json');
166
- if (fs.existsSync(globalSettings)) {
167
- const instanceSettings = path.join(instancePath, 'settings.json');
168
- fs.copyFileSync(globalSettings, instanceSettings);
169
- }
170
- }
171
-
172
- /**
173
- * Copy directory recursively
174
- * @param {string} src - Source directory
175
- * @param {string} dest - Destination directory
176
- */
177
- _copyDirectory(src, dest) {
178
- if (!fs.existsSync(dest)) {
179
- fs.mkdirSync(dest, { recursive: true, mode: 0o700 });
180
- }
181
-
182
- const entries = fs.readdirSync(src, { withFileTypes: true });
183
-
184
- for (const entry of entries) {
185
- const srcPath = path.join(src, entry.name);
186
- const destPath = path.join(dest, entry.name);
187
-
188
- if (entry.isDirectory()) {
189
- this._copyDirectory(srcPath, destPath);
190
- } else {
191
- fs.copyFileSync(srcPath, destPath);
192
- }
193
- }
194
- }
195
-
196
- /**
197
- * Sanitize profile name for filesystem
198
- * @param {string} name - Profile name
199
- * @returns {string} Safe name
200
- */
201
- _sanitizeName(name) {
202
- // Replace unsafe characters with dash
203
- return name.replace(/[^a-zA-Z0-9_-]/g, '-').toLowerCase();
204
- }
205
- }
206
-
207
- module.exports = InstanceManager;
@@ -1,135 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
-
7
- /**
8
- * Auto-recovery for missing or corrupted configuration
9
- */
10
- class RecoveryManager {
11
- constructor() {
12
- this.homedir = os.homedir();
13
- this.ccsDir = path.join(this.homedir, '.ccs');
14
- this.claudeDir = path.join(this.homedir, '.claude');
15
- this.recovered = [];
16
- }
17
-
18
- /**
19
- * Ensure ~/.ccs/ directory exists
20
- */
21
- ensureCcsDirectory() {
22
- if (!fs.existsSync(this.ccsDir)) {
23
- fs.mkdirSync(this.ccsDir, { recursive: true, mode: 0o755 });
24
- this.recovered.push('Created ~/.ccs/ directory');
25
- return true;
26
- }
27
- return false;
28
- }
29
-
30
- /**
31
- * Ensure ~/.ccs/config.json exists with defaults
32
- */
33
- ensureConfigJson() {
34
- const configPath = path.join(this.ccsDir, 'config.json');
35
-
36
- // Check if exists and valid
37
- if (fs.existsSync(configPath)) {
38
- try {
39
- const content = fs.readFileSync(configPath, 'utf8');
40
- JSON.parse(content); // Validate JSON
41
- return false; // No recovery needed
42
- } catch (e) {
43
- // Corrupted - backup and recreate
44
- const backupPath = `${configPath}.backup.${Date.now()}`;
45
- fs.renameSync(configPath, backupPath);
46
- this.recovered.push(`Backed up corrupted config.json to ${path.basename(backupPath)}`);
47
- }
48
- }
49
-
50
- // Create default config
51
- const defaultConfig = {
52
- profiles: {
53
- glm: '~/.ccs/glm.settings.json',
54
- kimi: '~/.ccs/kimi.settings.json',
55
- default: '~/.claude/settings.json'
56
- }
57
- };
58
-
59
- const tmpPath = `${configPath}.tmp`;
60
- fs.writeFileSync(tmpPath, JSON.stringify(defaultConfig, null, 2) + '\n', 'utf8');
61
- fs.renameSync(tmpPath, configPath);
62
-
63
- this.recovered.push('Created ~/.ccs/config.json');
64
- return true;
65
- }
66
-
67
- /**
68
- * Ensure ~/.claude/settings.json exists
69
- */
70
- ensureClaudeSettings() {
71
- const claudeSettingsPath = path.join(this.claudeDir, 'settings.json');
72
-
73
- // Create ~/.claude/ if missing
74
- if (!fs.existsSync(this.claudeDir)) {
75
- fs.mkdirSync(this.claudeDir, { recursive: true, mode: 0o755 });
76
- this.recovered.push('Created ~/.claude/ directory');
77
- }
78
-
79
- // Create settings.json if missing
80
- if (!fs.existsSync(claudeSettingsPath)) {
81
- const tmpPath = `${claudeSettingsPath}.tmp`;
82
- fs.writeFileSync(tmpPath, '{}\n', 'utf8');
83
- fs.renameSync(tmpPath, claudeSettingsPath);
84
-
85
- this.recovered.push('Created ~/.claude/settings.json');
86
- return true;
87
- }
88
-
89
- return false;
90
- }
91
-
92
- /**
93
- * Run all recovery operations
94
- * @returns {boolean} True if any recovery performed
95
- */
96
- recoverAll() {
97
- this.recovered = [];
98
-
99
- this.ensureCcsDirectory();
100
- this.ensureConfigJson();
101
- this.ensureClaudeSettings();
102
-
103
- return this.recovered.length > 0;
104
- }
105
-
106
- /**
107
- * Get recovery summary
108
- * @returns {string[]} List of recovery actions performed
109
- */
110
- getRecoverySummary() {
111
- return this.recovered;
112
- }
113
-
114
- /**
115
- * Show recovery hints
116
- */
117
- showRecoveryHints() {
118
- if (this.recovered.length === 0) return;
119
-
120
- console.log('');
121
- console.log('[i] Auto-recovery completed:');
122
- this.recovered.forEach(msg => console.log(` - ${msg}`));
123
-
124
- // Show login hint if created Claude settings
125
- if (this.recovered.some(msg => msg.includes('settings.json'))) {
126
- console.log('');
127
- console.log('[i] Next step: Login to Claude CLI');
128
- console.log(' Run: claude /login');
129
- }
130
-
131
- console.log('');
132
- }
133
- }
134
-
135
- module.exports = RecoveryManager;
@@ -1,285 +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.sharedDirs = ['commands', 'skills', 'agents', 'plugins'];
21
- }
22
-
23
- /**
24
- * Detect circular symlink before creation
25
- * @param {string} target - Target path to link to
26
- * @param {string} linkPath - Path where symlink will be created
27
- * @returns {boolean} True if circular
28
- * @private
29
- */
30
- _detectCircularSymlink(target, linkPath) {
31
- // Check if target exists and is symlink
32
- if (!fs.existsSync(target)) {
33
- return false;
34
- }
35
-
36
- try {
37
- const stats = fs.lstatSync(target);
38
- if (!stats.isSymbolicLink()) {
39
- return false;
40
- }
41
-
42
- // Resolve target's link
43
- const targetLink = fs.readlinkSync(target);
44
- const resolvedTarget = path.resolve(path.dirname(target), targetLink);
45
-
46
- // Check if target points back to our shared dir or link path
47
- const sharedDir = path.join(this.homeDir, '.ccs', 'shared');
48
- if (resolvedTarget.startsWith(sharedDir) || resolvedTarget === linkPath) {
49
- console.log(`[!] Circular symlink detected: ${target} → ${resolvedTarget}`);
50
- return true;
51
- }
52
- } catch (err) {
53
- // If can't read, assume not circular
54
- return false;
55
- }
56
-
57
- return false;
58
- }
59
-
60
- /**
61
- * Ensure shared directories exist as symlinks to ~/.claude/
62
- * Creates ~/.claude/ structure if missing
63
- */
64
- ensureSharedDirectories() {
65
- // Create ~/.claude/ if missing
66
- if (!fs.existsSync(this.claudeDir)) {
67
- console.log('[i] Creating ~/.claude/ directory structure');
68
- fs.mkdirSync(this.claudeDir, { recursive: true, mode: 0o700 });
69
- }
70
-
71
- // Create shared directory
72
- if (!fs.existsSync(this.sharedDir)) {
73
- fs.mkdirSync(this.sharedDir, { recursive: true, mode: 0o700 });
74
- }
75
-
76
- // Create symlinks ~/.ccs/shared/* → ~/.claude/*
77
- for (const dir of this.sharedDirs) {
78
- const claudePath = path.join(this.claudeDir, dir);
79
- const sharedPath = path.join(this.sharedDir, dir);
80
-
81
- // Create directory in ~/.claude/ if missing
82
- if (!fs.existsSync(claudePath)) {
83
- fs.mkdirSync(claudePath, { recursive: true, mode: 0o700 });
84
- }
85
-
86
- // Check for circular symlink
87
- if (this._detectCircularSymlink(claudePath, sharedPath)) {
88
- console.log(`[!] Skipping ${dir}: circular symlink detected`);
89
- continue;
90
- }
91
-
92
- // If already a symlink pointing to correct target, skip
93
- if (fs.existsSync(sharedPath)) {
94
- try {
95
- const stats = fs.lstatSync(sharedPath);
96
- if (stats.isSymbolicLink()) {
97
- const currentTarget = fs.readlinkSync(sharedPath);
98
- const resolvedTarget = path.resolve(path.dirname(sharedPath), currentTarget);
99
- if (resolvedTarget === claudePath) {
100
- continue; // Already correct
101
- }
102
- }
103
- } catch (err) {
104
- // Continue to recreate
105
- }
106
-
107
- // Remove existing directory/link
108
- fs.rmSync(sharedPath, { recursive: true, force: true });
109
- }
110
-
111
- // Create symlink
112
- try {
113
- fs.symlinkSync(claudePath, sharedPath, 'dir');
114
- } catch (err) {
115
- // Windows fallback: copy directory
116
- if (process.platform === 'win32') {
117
- this._copyDirectoryFallback(claudePath, sharedPath);
118
- console.log(`[!] Symlink failed for ${dir}, copied instead (enable Developer Mode)`);
119
- } else {
120
- throw err;
121
- }
122
- }
123
- }
124
- }
125
-
126
- /**
127
- * Link shared directories to instance
128
- * @param {string} instancePath - Path to instance directory
129
- */
130
- linkSharedDirectories(instancePath) {
131
- this.ensureSharedDirectories();
132
-
133
- for (const dir of this.sharedDirs) {
134
- const linkPath = path.join(instancePath, dir);
135
- const targetPath = path.join(this.sharedDir, dir);
136
-
137
- // Remove existing directory/link
138
- if (fs.existsSync(linkPath)) {
139
- fs.rmSync(linkPath, { recursive: true, force: true });
140
- }
141
-
142
- // Create symlink
143
- try {
144
- fs.symlinkSync(targetPath, linkPath, 'dir');
145
- } catch (err) {
146
- // Windows fallback
147
- if (process.platform === 'win32') {
148
- this._copyDirectoryFallback(targetPath, linkPath);
149
- console.log(`[!] Symlink failed for ${dir}, copied instead (enable Developer Mode)`);
150
- } else {
151
- throw err;
152
- }
153
- }
154
- }
155
- }
156
-
157
- /**
158
- * Migrate from v3.1.1 (copied data in ~/.ccs/shared/) to v3.2.0 (symlinks to ~/.claude/)
159
- * Runs once on upgrade
160
- */
161
- migrateFromV311() {
162
- // Check if migration already done (shared dirs are symlinks)
163
- const commandsPath = path.join(this.sharedDir, 'commands');
164
- if (fs.existsSync(commandsPath)) {
165
- try {
166
- if (fs.lstatSync(commandsPath).isSymbolicLink()) {
167
- return; // Already migrated
168
- }
169
- } catch (err) {
170
- // Continue with migration
171
- }
172
- }
173
-
174
- console.log('[i] Migrating from v3.1.1 to v3.2.0...');
175
-
176
- // Ensure ~/.claude/ exists
177
- if (!fs.existsSync(this.claudeDir)) {
178
- fs.mkdirSync(this.claudeDir, { recursive: true, mode: 0o700 });
179
- }
180
-
181
- // Copy user modifications from ~/.ccs/shared/ to ~/.claude/
182
- for (const dir of this.sharedDirs) {
183
- const sharedPath = path.join(this.sharedDir, dir);
184
- const claudePath = path.join(this.claudeDir, dir);
185
-
186
- if (!fs.existsSync(sharedPath)) continue;
187
-
188
- try {
189
- const stats = fs.lstatSync(sharedPath);
190
- if (!stats.isDirectory()) continue;
191
- } catch (err) {
192
- continue;
193
- }
194
-
195
- // Create claude dir if missing
196
- if (!fs.existsSync(claudePath)) {
197
- fs.mkdirSync(claudePath, { recursive: true, mode: 0o700 });
198
- }
199
-
200
- // Copy files from shared to claude (preserve user modifications)
201
- try {
202
- const entries = fs.readdirSync(sharedPath, { withFileTypes: true });
203
- let copied = 0;
204
-
205
- for (const entry of entries) {
206
- const src = path.join(sharedPath, entry.name);
207
- const dest = path.join(claudePath, entry.name);
208
-
209
- // Skip if already exists in claude
210
- if (fs.existsSync(dest)) continue;
211
-
212
- if (entry.isDirectory()) {
213
- fs.cpSync(src, dest, { recursive: true });
214
- } else {
215
- fs.copyFileSync(src, dest);
216
- }
217
- copied++;
218
- }
219
-
220
- if (copied > 0) {
221
- console.log(`[OK] Migrated ${copied} ${dir} to ~/.claude/${dir}`);
222
- }
223
- } catch (err) {
224
- console.log(`[!] Failed to migrate ${dir}: ${err.message}`);
225
- }
226
- }
227
-
228
- // Now run ensureSharedDirectories to create symlinks
229
- this.ensureSharedDirectories();
230
-
231
- // Update all instances to use new symlinks
232
- if (fs.existsSync(this.instancesDir)) {
233
- try {
234
- const instances = fs.readdirSync(this.instancesDir);
235
-
236
- for (const instance of instances) {
237
- const instancePath = path.join(this.instancesDir, instance);
238
- try {
239
- if (fs.statSync(instancePath).isDirectory()) {
240
- this.linkSharedDirectories(instancePath);
241
- }
242
- } catch (err) {
243
- console.log(`[!] Failed to update instance ${instance}: ${err.message}`);
244
- }
245
- }
246
- } catch (err) {
247
- // No instances to update
248
- }
249
- }
250
-
251
- console.log('[OK] Migration to v3.2.0 complete');
252
- }
253
-
254
- /**
255
- * Copy directory as fallback (Windows without Developer Mode)
256
- * @param {string} src - Source directory
257
- * @param {string} dest - Destination directory
258
- * @private
259
- */
260
- _copyDirectoryFallback(src, dest) {
261
- if (!fs.existsSync(src)) {
262
- fs.mkdirSync(src, { recursive: true, mode: 0o700 });
263
- return;
264
- }
265
-
266
- if (!fs.existsSync(dest)) {
267
- fs.mkdirSync(dest, { recursive: true, mode: 0o700 });
268
- }
269
-
270
- const entries = fs.readdirSync(src, { withFileTypes: true });
271
-
272
- for (const entry of entries) {
273
- const srcPath = path.join(src, entry.name);
274
- const destPath = path.join(dest, entry.name);
275
-
276
- if (entry.isDirectory()) {
277
- this._copyDirectoryFallback(srcPath, destPath);
278
- } else {
279
- fs.copyFileSync(srcPath, destPath);
280
- }
281
- }
282
- }
283
- }
284
-
285
- 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
- };