@kaitranntt/ccs 4.4.0 → 5.0.0

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