@kaitranntt/ccs 4.4.0 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/README.md +98 -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 +95 -0
  23. package/dist/cliproxy/auth-handler.d.ts.map +1 -0
  24. package/dist/cliproxy/auth-handler.js +443 -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,283 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('fs');
5
- const path = require('path');
6
- const os = require('os');
7
-
8
- // Make ora optional (might not be available during npm install postinstall)
9
- // ora v9+ is an ES module, need to use .default for CommonJS
10
- let ora = null;
11
- try {
12
- const oraModule = require('ora');
13
- ora = oraModule.default || oraModule;
14
- } catch (e) {
15
- // ora not available, create fallback spinner that uses console.log
16
- ora = function(text) {
17
- return {
18
- start: () => ({
19
- succeed: (msg) => console.log(msg || `[OK] ${text}`),
20
- fail: (msg) => console.log(msg || `[X] ${text}`),
21
- warn: (msg) => console.log(msg || `[!] ${text}`),
22
- info: (msg) => console.log(msg || `[i] ${text}`),
23
- text: ''
24
- })
25
- };
26
- };
27
- }
28
-
29
- const { colored } = require('./helpers');
30
-
31
- /**
32
- * ClaudeDirInstaller - Manages copying .claude/ directory from package to ~/.ccs/.claude/
33
- * v4.1.1: Fix for npm install not copying .claude/ directory
34
- */
35
- class ClaudeDirInstaller {
36
- constructor() {
37
- this.homeDir = os.homedir();
38
- this.ccsClaudeDir = path.join(this.homeDir, '.ccs', '.claude');
39
- }
40
-
41
- /**
42
- * Copy .claude/ directory from package to ~/.ccs/.claude/
43
- * @param {string} packageDir - Package installation directory (default: auto-detect)
44
- * @param {boolean} silent - Suppress spinner output
45
- */
46
- install(packageDir, silent = false) {
47
- const spinner = (silent || !ora) ? null : ora('Copying .claude/ items to ~/.ccs/.claude/').start();
48
-
49
- try {
50
- // Auto-detect package directory if not provided
51
- if (!packageDir) {
52
- // Try to find package root by going up from this file
53
- packageDir = path.join(__dirname, '..', '..');
54
- }
55
-
56
- const packageClaudeDir = path.join(packageDir, '.claude');
57
-
58
- if (!fs.existsSync(packageClaudeDir)) {
59
- const msg = 'Package .claude/ directory not found';
60
- if (spinner) {
61
- spinner.warn(`[!] ${msg}`);
62
- console.log(` Searched in: ${packageClaudeDir}`);
63
- console.log(' This may be a development installation');
64
- } else {
65
- console.log(`[!] ${msg}`);
66
- console.log(` Searched in: ${packageClaudeDir}`);
67
- console.log(' This may be a development installation');
68
- }
69
- return false;
70
- }
71
-
72
- // Remove old version before copying new one
73
- if (fs.existsSync(this.ccsClaudeDir)) {
74
- if (spinner) spinner.text = 'Removing old .claude/ items...';
75
- fs.rmSync(this.ccsClaudeDir, { recursive: true, force: true });
76
- }
77
-
78
- // Use fs.cpSync for recursive copy (Node.js 16.7.0+)
79
- // Fallback to manual copy for older Node.js versions
80
- if (spinner) spinner.text = 'Copying .claude/ items...';
81
-
82
- if (fs.cpSync) {
83
- fs.cpSync(packageClaudeDir, this.ccsClaudeDir, { recursive: true });
84
- } else {
85
- // Fallback for Node.js < 16.7.0
86
- this._copyDirRecursive(packageClaudeDir, this.ccsClaudeDir);
87
- }
88
-
89
- // Count files and directories
90
- const itemCount = this._countItems(this.ccsClaudeDir);
91
- const msg = `Copied .claude/ items (${itemCount.files} files, ${itemCount.dirs} directories)`;
92
-
93
- if (spinner) {
94
- spinner.succeed(colored('[OK]', 'green') + ` ${msg}`);
95
- } else {
96
- console.log(`[OK] ${msg}`);
97
- }
98
- return true;
99
- } catch (err) {
100
- const msg = `Failed to copy .claude/ directory: ${err.message}`;
101
- if (spinner) {
102
- spinner.fail(colored('[!]', 'yellow') + ` ${msg}`);
103
- console.warn(' CCS items may not be available');
104
- } else {
105
- console.warn(`[!] ${msg}`);
106
- console.warn(' CCS items may not be available');
107
- }
108
- return false;
109
- }
110
- }
111
-
112
- /**
113
- * Recursively copy directory (fallback for Node.js < 16.7.0)
114
- * @param {string} src - Source directory
115
- * @param {string} dest - Destination directory
116
- * @private
117
- */
118
- _copyDirRecursive(src, dest) {
119
- // Create destination directory
120
- if (!fs.existsSync(dest)) {
121
- fs.mkdirSync(dest, { recursive: true });
122
- }
123
-
124
- // Read source directory
125
- const entries = fs.readdirSync(src, { withFileTypes: true });
126
-
127
- for (const entry of entries) {
128
- const srcPath = path.join(src, entry.name);
129
- const destPath = path.join(dest, entry.name);
130
-
131
- if (entry.isDirectory()) {
132
- // Recursively copy subdirectory
133
- this._copyDirRecursive(srcPath, destPath);
134
- } else {
135
- // Copy file
136
- fs.copyFileSync(srcPath, destPath);
137
- }
138
- }
139
- }
140
-
141
- /**
142
- * Count files and directories in a path
143
- * @param {string} dirPath - Directory to count
144
- * @returns {Object} { files: number, dirs: number }
145
- * @private
146
- */
147
- _countItems(dirPath) {
148
- let files = 0;
149
- let dirs = 0;
150
-
151
- const countRecursive = (p) => {
152
- const entries = fs.readdirSync(p, { withFileTypes: true });
153
- for (const entry of entries) {
154
- if (entry.isDirectory()) {
155
- dirs++;
156
- countRecursive(path.join(p, entry.name));
157
- } else {
158
- files++;
159
- }
160
- }
161
- };
162
-
163
- try {
164
- countRecursive(dirPath);
165
- } catch (e) {
166
- // Ignore errors
167
- }
168
-
169
- return { files, dirs };
170
- }
171
-
172
- /**
173
- * Clean up deprecated files from previous installations
174
- * Removes ccs-delegator.md that was deprecated in v4.3.2
175
- * @param {boolean} silent - Suppress console output
176
- */
177
- cleanupDeprecated(silent = false) {
178
- const deprecatedFile = path.join(this.ccsClaudeDir, 'agents', 'ccs-delegator.md');
179
- const userSymlinkFile = path.join(this.homeDir, '.claude', 'agents', 'ccs-delegator.md');
180
- const migrationMarker = path.join(this.homeDir, '.ccs', '.migrations', 'v435-delegator-cleanup');
181
-
182
- let cleanedFiles = [];
183
-
184
- try {
185
- // Check if cleanup already done
186
- if (fs.existsSync(migrationMarker)) {
187
- return { success: true, cleanedFiles: [] }; // Already cleaned
188
- }
189
-
190
- // Clean up user symlink in ~/.claude/agents/ccs-delegator.md FIRST
191
- // This ensures we can detect broken symlinks before deleting the target
192
- try {
193
- const userStats = fs.lstatSync(userSymlinkFile);
194
- if (userStats.isSymbolicLink()) {
195
- fs.unlinkSync(userSymlinkFile);
196
- cleanedFiles.push('user symlink');
197
- } else {
198
- // It's not a symlink (user created their own file), backup it
199
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
200
- const backupPath = `${userSymlinkFile}.backup-${timestamp}`;
201
- fs.renameSync(userSymlinkFile, backupPath);
202
- if (!silent) console.log(`[i] Backed up user file to ${path.basename(backupPath)}`);
203
- cleanedFiles.push('user file (backed up)');
204
- }
205
- } catch (err) {
206
- // File doesn't exist or other error - that's okay
207
- if (err.code !== 'ENOENT' && !silent) {
208
- console.log(`[!] Failed to remove user symlink: ${err.message}`);
209
- }
210
- }
211
-
212
- // Clean up package copy in ~/.ccs/.claude/agents/ccs-delegator.md
213
- if (fs.existsSync(deprecatedFile)) {
214
- try {
215
- // Check if file was modified by user (compare with expected content)
216
- const shouldBackup = this._shouldBackupDeprecatedFile(deprecatedFile);
217
-
218
- if (shouldBackup) {
219
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
220
- const backupPath = `${deprecatedFile}.backup-${timestamp}`;
221
- fs.renameSync(deprecatedFile, backupPath);
222
- if (!silent) console.log(`[i] Backed up modified deprecated file to ${path.basename(backupPath)}`);
223
- } else {
224
- fs.rmSync(deprecatedFile, { force: true });
225
- }
226
- cleanedFiles.push('package copy');
227
- } catch (err) {
228
- if (!silent) console.log(`[!] Failed to remove package copy: ${err.message}`);
229
- }
230
- }
231
-
232
- // Create migration marker
233
- if (cleanedFiles.length > 0) {
234
- const migrationsDir = path.dirname(migrationMarker);
235
- if (!fs.existsSync(migrationsDir)) {
236
- fs.mkdirSync(migrationsDir, { recursive: true, mode: 0o700 });
237
- }
238
- fs.writeFileSync(migrationMarker, new Date().toISOString());
239
-
240
- if (!silent) {
241
- console.log(`[OK] Cleaned up deprecated agent files: ${cleanedFiles.join(', ')}`);
242
- }
243
- }
244
-
245
- return { success: true, cleanedFiles };
246
- } catch (err) {
247
- if (!silent) console.log(`[!] Cleanup failed: ${err.message}`);
248
- return { success: false, error: err.message, cleanedFiles };
249
- }
250
- }
251
-
252
- /**
253
- * Check if deprecated file should be backed up (user modified)
254
- * @param {string} filePath - Path to check
255
- * @returns {boolean} True if file should be backed up
256
- * @private
257
- */
258
- _shouldBackupDeprecatedFile(filePath) {
259
- try {
260
- // Simple heuristic: if file size differs significantly from expected, assume user modified
261
- // Expected size for ccs-delegator.md was around 2-3KB
262
- const stats = fs.statSync(filePath);
263
- const expectedMinSize = 1000; // 1KB minimum
264
- const expectedMaxSize = 10000; // 10KB maximum
265
-
266
- // If size is outside expected range, likely user modified
267
- return stats.size < expectedMinSize || stats.size > expectedMaxSize;
268
- } catch (err) {
269
- // If we can't determine, err on side of caution and backup
270
- return true;
271
- }
272
- }
273
-
274
- /**
275
- * Check if ~/.ccs/.claude/ exists and is valid
276
- * @returns {boolean} True if directory exists
277
- */
278
- isInstalled() {
279
- return fs.existsSync(this.ccsClaudeDir);
280
- }
281
- }
282
-
283
- module.exports = ClaudeDirInstaller;
@@ -1,289 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
-
7
- // Make ora optional (might not be available during npm install postinstall)
8
- // ora v9+ is an ES module, need to use .default for CommonJS
9
- let ora = null;
10
- try {
11
- const oraModule = require('ora');
12
- ora = oraModule.default || oraModule;
13
- } catch (e) {
14
- // ora not available, create fallback spinner that uses console.log
15
- ora = function(text) {
16
- return {
17
- start: () => ({
18
- succeed: (msg) => console.log(msg || `[OK] ${text}`),
19
- fail: (msg) => console.log(msg || `[X] ${text}`),
20
- warn: (msg) => console.log(msg || `[!] ${text}`),
21
- info: (msg) => console.log(msg || `[i] ${text}`),
22
- text: ''
23
- })
24
- };
25
- };
26
- }
27
-
28
- const { colored } = require('./helpers');
29
-
30
- /**
31
- * ClaudeSymlinkManager - Manages selective symlinks from ~/.ccs/.claude/ to ~/.claude/
32
- * v4.1.0: Selective symlinking for CCS items
33
- *
34
- * Purpose: Ship CCS items (.claude/) with package and symlink them to user's ~/.claude/
35
- * Architecture:
36
- * - ~/.ccs/.claude/* (source, ships with CCS)
37
- * - ~/.claude/* (target, gets selective symlinks)
38
- * - ~/.ccs/shared/ (UNTOUCHED, existing profile mechanism)
39
- *
40
- * Symlink Chain:
41
- * profile -> ~/.ccs/shared/ -> ~/.claude/ (which has symlinks to ~/.ccs/.claude/)
42
- */
43
- class ClaudeSymlinkManager {
44
- constructor() {
45
- this.homeDir = os.homedir();
46
- this.ccsClaudeDir = path.join(this.homeDir, '.ccs', '.claude');
47
- this.userClaudeDir = path.join(this.homeDir, '.claude');
48
-
49
- // CCS items to symlink (selective, item-level)
50
- this.ccsItems = [
51
- { source: 'commands/ccs.md', target: 'commands/ccs.md', type: 'file' },
52
- { source: 'commands/ccs', target: 'commands/ccs', type: 'directory' },
53
- { source: 'skills/ccs-delegation', target: 'skills/ccs-delegation', type: 'directory' }
54
- ];
55
- }
56
-
57
- /**
58
- * Install CCS items to user's ~/.claude/ via selective symlinks
59
- * Safe: backs up existing files before creating symlinks
60
- */
61
- install(silent = false) {
62
- const spinner = (silent || !ora) ? null : ora('Installing CCS items to ~/.claude/').start();
63
-
64
- // Ensure ~/.ccs/.claude/ exists (should be shipped with package)
65
- if (!fs.existsSync(this.ccsClaudeDir)) {
66
- const msg = 'CCS .claude/ directory not found, skipping symlink installation';
67
- if (spinner) {
68
- spinner.warn(`[!] ${msg}`);
69
- } else {
70
- console.log(`[!] ${msg}`);
71
- }
72
- return;
73
- }
74
-
75
- // Create ~/.claude/ if missing
76
- if (!fs.existsSync(this.userClaudeDir)) {
77
- if (!silent) {
78
- if (spinner) spinner.text = 'Creating ~/.claude/ directory';
79
- }
80
- fs.mkdirSync(this.userClaudeDir, { recursive: true, mode: 0o700 });
81
- }
82
-
83
- // Install each CCS item
84
- let installed = 0;
85
- for (const item of this.ccsItems) {
86
- if (!silent && spinner) {
87
- spinner.text = `Installing ${item.target}...`;
88
- }
89
- const result = this._installItem(item, silent);
90
- if (result) installed++;
91
- }
92
-
93
- const msg = `${installed}/${this.ccsItems.length} items installed to ~/.claude/`;
94
- if (spinner) {
95
- spinner.succeed(colored('[OK]', 'green') + ` ${msg}`);
96
- } else {
97
- console.log(`[OK] ${msg}`);
98
- }
99
- }
100
-
101
- /**
102
- * Install a single CCS item with conflict handling
103
- * @param {Object} item - Item descriptor {source, target, type}
104
- * @param {boolean} silent - Suppress individual item messages
105
- * @returns {boolean} True if installed successfully
106
- * @private
107
- */
108
- _installItem(item, silent = false) {
109
- const sourcePath = path.join(this.ccsClaudeDir, item.source);
110
- const targetPath = path.join(this.userClaudeDir, item.target);
111
- const targetDir = path.dirname(targetPath);
112
-
113
- // Ensure source exists
114
- if (!fs.existsSync(sourcePath)) {
115
- if (!silent) console.log(`[!] Source not found: ${item.source}, skipping`);
116
- return false;
117
- }
118
-
119
- // Create target parent directory if needed
120
- if (!fs.existsSync(targetDir)) {
121
- fs.mkdirSync(targetDir, { recursive: true, mode: 0o700 });
122
- }
123
-
124
- // Check if target already exists
125
- if (fs.existsSync(targetPath)) {
126
- // Check if it's already the correct symlink
127
- if (this._isOurSymlink(targetPath, sourcePath)) {
128
- return true; // Already correct, counts as success
129
- }
130
-
131
- // Backup existing file/directory
132
- this._backupItem(targetPath, silent);
133
- }
134
-
135
- // Create symlink
136
- try {
137
- const symlinkType = item.type === 'directory' ? 'dir' : 'file';
138
- fs.symlinkSync(sourcePath, targetPath, symlinkType);
139
- if (!silent) console.log(`[OK] Symlinked ${item.target}`);
140
- return true;
141
- } catch (err) {
142
- // Windows fallback: stub for now, full implementation in v4.2
143
- if (process.platform === 'win32') {
144
- if (!silent) {
145
- console.log(`[!] Symlink failed for ${item.target} (Windows fallback deferred to v4.2)`);
146
- console.log(`[i] Enable Developer Mode or wait for next update`);
147
- }
148
- } else {
149
- if (!silent) console.log(`[!] Failed to symlink ${item.target}: ${err.message}`);
150
- }
151
- return false;
152
- }
153
- }
154
-
155
- /**
156
- * Check if target is already the correct symlink pointing to source
157
- * @param {string} targetPath - Target path to check
158
- * @param {string} expectedSource - Expected source path
159
- * @returns {boolean} True if target is correct symlink
160
- * @private
161
- */
162
- _isOurSymlink(targetPath, expectedSource) {
163
- try {
164
- const stats = fs.lstatSync(targetPath);
165
-
166
- if (!stats.isSymbolicLink()) {
167
- return false;
168
- }
169
-
170
- const actualTarget = fs.readlinkSync(targetPath);
171
- const resolvedTarget = path.resolve(path.dirname(targetPath), actualTarget);
172
-
173
- return resolvedTarget === expectedSource;
174
- } catch (err) {
175
- return false;
176
- }
177
- }
178
-
179
- /**
180
- * Backup existing item before replacing with symlink
181
- * @param {string} itemPath - Path to item to backup
182
- * @param {boolean} silent - Suppress backup messages
183
- * @private
184
- */
185
- _backupItem(itemPath, silent = false) {
186
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
187
- const backupPath = `${itemPath}.backup-${timestamp}`;
188
-
189
- try {
190
- // If backup already exists, use counter
191
- let finalBackupPath = backupPath;
192
- let counter = 1;
193
- while (fs.existsSync(finalBackupPath)) {
194
- finalBackupPath = `${backupPath}-${counter}`;
195
- counter++;
196
- }
197
-
198
- fs.renameSync(itemPath, finalBackupPath);
199
- if (!silent) console.log(`[i] Backed up existing item to ${path.basename(finalBackupPath)}`);
200
- } catch (err) {
201
- if (!silent) console.log(`[!] Failed to backup ${itemPath}: ${err.message}`);
202
- throw err; // Don't proceed if backup fails
203
- }
204
- }
205
-
206
- /**
207
- * Uninstall CCS items from ~/.claude/ (remove symlinks only)
208
- * Safe: only removes items that are CCS symlinks
209
- */
210
- uninstall() {
211
- let removed = 0;
212
-
213
- for (const item of this.ccsItems) {
214
- const targetPath = path.join(this.userClaudeDir, item.target);
215
- const sourcePath = path.join(this.ccsClaudeDir, item.source);
216
-
217
- // Only remove if it's our symlink
218
- if (fs.existsSync(targetPath) && this._isOurSymlink(targetPath, sourcePath)) {
219
- try {
220
- fs.unlinkSync(targetPath);
221
- console.log(`[OK] Removed ${item.target}`);
222
- removed++;
223
- } catch (err) {
224
- console.log(`[!] Failed to remove ${item.target}: ${err.message}`);
225
- }
226
- }
227
- }
228
-
229
- if (removed > 0) {
230
- console.log(`[OK] Removed ${removed} delegation commands and skills from ~/.claude/`);
231
- } else {
232
- console.log('[i] No delegation commands or skills to remove');
233
- }
234
- }
235
-
236
- /**
237
- * Check symlink health and report issues
238
- * Used by 'ccs doctor' command
239
- * @returns {Object} Health check results {healthy: boolean, issues: string[]}
240
- */
241
- checkHealth() {
242
- const issues = [];
243
- let healthy = true;
244
-
245
- // Check if ~/.ccs/.claude/ exists
246
- if (!fs.existsSync(this.ccsClaudeDir)) {
247
- issues.push('CCS .claude/ directory missing (reinstall CCS)');
248
- healthy = false;
249
- return { healthy, issues };
250
- }
251
-
252
- // Check each item
253
- for (const item of this.ccsItems) {
254
- const sourcePath = path.join(this.ccsClaudeDir, item.source);
255
- const targetPath = path.join(this.userClaudeDir, item.target);
256
-
257
- // Check source exists
258
- if (!fs.existsSync(sourcePath)) {
259
- issues.push(`Source missing: ${item.source}`);
260
- healthy = false;
261
- continue;
262
- }
263
-
264
- // Check target
265
- if (!fs.existsSync(targetPath)) {
266
- issues.push(`Not installed: ${item.target} (run 'ccs sync' to install)`);
267
- healthy = false;
268
- } else if (!this._isOurSymlink(targetPath, sourcePath)) {
269
- issues.push(`Not a CCS symlink: ${item.target} (run 'ccs sync' to fix)`);
270
- healthy = false;
271
- }
272
- }
273
-
274
- return { healthy, issues };
275
- }
276
-
277
- /**
278
- * Sync delegation commands and skills to ~/.claude/ (used by 'ccs sync' command)
279
- * Same as install() but with explicit sync message
280
- */
281
- sync() {
282
- console.log('');
283
- console.log(colored('Syncing CCS Components...', 'cyan'));
284
- console.log('');
285
- this.install(false);
286
- }
287
- }
288
-
289
- module.exports = ClaudeSymlinkManager;
@@ -1,103 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
- const { error, expandPath } = require('./helpers');
7
- const { ErrorManager } = require('./error-manager');
8
-
9
- // Get config file path
10
- function getConfigPath() {
11
- return process.env.CCS_CONFIG || path.join(os.homedir(), '.ccs', 'config.json');
12
- }
13
-
14
- // Read and parse config
15
- function readConfig() {
16
- const configPath = getConfigPath();
17
-
18
- // Check config exists
19
- if (!fs.existsSync(configPath)) {
20
- // Attempt recovery
21
- const RecoveryManager = require('./recovery-manager');
22
- const recovery = new RecoveryManager();
23
- recovery.ensureConfigJson();
24
-
25
- if (!fs.existsSync(configPath)) {
26
- ErrorManager.showInvalidConfig(configPath, 'File not found');
27
- process.exit(1);
28
- }
29
- }
30
-
31
- // Read and parse JSON
32
- let config;
33
- try {
34
- const configContent = fs.readFileSync(configPath, 'utf8');
35
- config = JSON.parse(configContent);
36
- } catch (e) {
37
- ErrorManager.showInvalidConfig(configPath, `Invalid JSON: ${e.message}`);
38
- process.exit(1);
39
- }
40
-
41
- // Validate config has profiles object
42
- if (!config.profiles || typeof config.profiles !== 'object') {
43
- ErrorManager.showInvalidConfig(configPath, "Missing 'profiles' object");
44
- process.exit(1);
45
- }
46
-
47
- return config;
48
- }
49
-
50
- // Get settings path for profile
51
- function getSettingsPath(profile) {
52
- const config = readConfig();
53
-
54
- // Get settings path
55
- const settingsPath = config.profiles[profile];
56
-
57
- if (!settingsPath) {
58
- const availableProfiles = Object.keys(config.profiles);
59
- const profileList = availableProfiles.map(p => ` - ${p}`);
60
- ErrorManager.showProfileNotFound(profile, profileList);
61
- process.exit(1);
62
- }
63
-
64
- // Expand path
65
- const expandedPath = expandPath(settingsPath);
66
-
67
- // Validate settings file exists
68
- if (!fs.existsSync(expandedPath)) {
69
- // Auto-create if it's ~/.claude/settings.json
70
- if (expandedPath.includes('.claude') && expandedPath.endsWith('settings.json')) {
71
- const RecoveryManager = require('./recovery-manager');
72
- const recovery = new RecoveryManager();
73
- recovery.ensureClaudeSettings();
74
-
75
- if (!fs.existsSync(expandedPath)) {
76
- ErrorManager.showSettingsNotFound(expandedPath);
77
- process.exit(1);
78
- }
79
-
80
- console.log('[i] Auto-created missing settings file');
81
- } else {
82
- ErrorManager.showSettingsNotFound(expandedPath);
83
- process.exit(1);
84
- }
85
- }
86
-
87
- // Validate settings file is valid JSON
88
- try {
89
- const settingsContent = fs.readFileSync(expandedPath, 'utf8');
90
- JSON.parse(settingsContent);
91
- } catch (e) {
92
- ErrorManager.showInvalidConfig(expandedPath, `Invalid JSON: ${e.message}`);
93
- process.exit(1);
94
- }
95
-
96
- return expandedPath;
97
- }
98
-
99
- module.exports = {
100
- getConfigPath,
101
- readConfig,
102
- getSettingsPath
103
- };