@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,134 +0,0 @@
1
- 'use strict';
2
-
3
- const readline = require('readline');
4
-
5
- /**
6
- * Interactive Prompt Utilities (NO external dependencies)
7
- *
8
- * Features:
9
- * - TTY detection (auto-confirm in non-TTY)
10
- * - --yes flag support for automation
11
- * - --no-input flag support for CI
12
- * - Safe defaults (N for destructive actions)
13
- * - Input validation with retry
14
- */
15
-
16
- class InteractivePrompt {
17
- /**
18
- * Ask for confirmation
19
- * @param {string} message - Confirmation message
20
- * @param {Object} options - Options
21
- * @param {boolean} options.default - Default value (true=Yes, false=No)
22
- * @returns {Promise<boolean>} User confirmation
23
- */
24
- static async confirm(message, options = {}) {
25
- const { default: defaultValue = false } = options;
26
-
27
- // Check for --yes flag (automation) - always returns true
28
- if (process.env.CCS_YES === '1' || process.argv.includes('--yes') || process.argv.includes('-y')) {
29
- return true;
30
- }
31
-
32
- // Check for --no-input flag (CI)
33
- if (process.env.CCS_NO_INPUT === '1' || process.argv.includes('--no-input')) {
34
- throw new Error('Interactive input required but --no-input specified');
35
- }
36
-
37
- // Non-TTY: use default
38
- if (!process.stdin.isTTY) {
39
- return defaultValue;
40
- }
41
-
42
- // Interactive prompt
43
- const rl = readline.createInterface({
44
- input: process.stdin,
45
- output: process.stderr,
46
- terminal: true
47
- });
48
-
49
- const promptText = defaultValue
50
- ? `${message} [Y/n]: `
51
- : `${message} [y/N]: `;
52
-
53
- return new Promise((resolve) => {
54
- rl.question(promptText, (answer) => {
55
- rl.close();
56
-
57
- const normalized = answer.trim().toLowerCase();
58
-
59
- // Empty answer: use default
60
- if (normalized === '') {
61
- resolve(defaultValue);
62
- return;
63
- }
64
-
65
- // Valid answers
66
- if (normalized === 'y' || normalized === 'yes') {
67
- resolve(true);
68
- return;
69
- }
70
-
71
- if (normalized === 'n' || normalized === 'no') {
72
- resolve(false);
73
- return;
74
- }
75
-
76
- // Invalid input: retry
77
- console.error('[!] Please answer y or n');
78
- resolve(InteractivePrompt.confirm(message, options));
79
- });
80
- });
81
- }
82
-
83
- /**
84
- * Get text input from user
85
- * @param {string} message - Prompt message
86
- * @param {Object} options - Options
87
- * @param {string} options.default - Default value
88
- * @param {Function} options.validate - Validation function
89
- * @returns {Promise<string>} User input
90
- */
91
- static async input(message, options = {}) {
92
- const { default: defaultValue = '', validate = null } = options;
93
-
94
- // Non-TTY: use default or error
95
- if (!process.stdin.isTTY) {
96
- if (defaultValue) {
97
- return defaultValue;
98
- }
99
- throw new Error('Interactive input required but stdin is not a TTY');
100
- }
101
-
102
- const rl = readline.createInterface({
103
- input: process.stdin,
104
- output: process.stderr,
105
- terminal: true
106
- });
107
-
108
- const promptText = defaultValue
109
- ? `${message} [${defaultValue}]: `
110
- : `${message}: `;
111
-
112
- return new Promise((resolve) => {
113
- rl.question(promptText, (answer) => {
114
- rl.close();
115
-
116
- const value = answer.trim() || defaultValue;
117
-
118
- // Validate input if validator provided
119
- if (validate) {
120
- const error = validate(value);
121
- if (error) {
122
- console.error(`[!] ${error}`);
123
- resolve(InteractivePrompt.input(message, options));
124
- return;
125
- }
126
- }
127
-
128
- resolve(value);
129
- });
130
- });
131
- }
132
- }
133
-
134
- module.exports = { InteractivePrompt };
@@ -1,256 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
- const { execSync } = require('child_process');
7
-
8
- /**
9
- * Shell Completion Installer
10
- * Auto-configures shell completion for bash, zsh, fish, PowerShell
11
- */
12
-
13
- class ShellCompletionInstaller {
14
- constructor() {
15
- this.homeDir = os.homedir();
16
- this.ccsDir = path.join(this.homeDir, '.ccs');
17
- this.completionDir = path.join(this.ccsDir, 'completions');
18
- this.scriptsDir = path.join(__dirname, '../../scripts/completion');
19
- }
20
-
21
- /**
22
- * Detect current shell
23
- */
24
- detectShell() {
25
- const shell = process.env.SHELL || '';
26
-
27
- if (shell.includes('bash')) return 'bash';
28
- if (shell.includes('zsh')) return 'zsh';
29
- if (shell.includes('fish')) return 'fish';
30
- if (process.platform === 'win32') return 'powershell';
31
-
32
- return null;
33
- }
34
-
35
- /**
36
- * Ensure completion files are in ~/.ccs/completions/
37
- */
38
- ensureCompletionFiles() {
39
- if (!fs.existsSync(this.completionDir)) {
40
- fs.mkdirSync(this.completionDir, { recursive: true });
41
- }
42
-
43
- // Copy completion scripts
44
- const files = ['ccs.bash', 'ccs.zsh', 'ccs.fish', 'ccs.ps1'];
45
- files.forEach(file => {
46
- const src = path.join(this.scriptsDir, file);
47
- const dest = path.join(this.completionDir, file);
48
-
49
- if (fs.existsSync(src)) {
50
- fs.copyFileSync(src, dest);
51
- }
52
- });
53
- }
54
-
55
- /**
56
- * Safely create directory, checking for file conflicts
57
- * @param {string} dirPath - Path to create
58
- * @throws {Error} If path exists but is a file
59
- */
60
- ensureDirectory(dirPath) {
61
- if (fs.existsSync(dirPath)) {
62
- const stat = fs.statSync(dirPath);
63
- if (!stat.isDirectory()) {
64
- throw new Error(
65
- `Cannot create directory: ${dirPath} exists but is a file.\n` +
66
- `Please remove or rename this file and try again.`
67
- );
68
- }
69
- // Directory exists, nothing to do
70
- return;
71
- }
72
-
73
- // Check parent directories recursively
74
- const parentDir = path.dirname(dirPath);
75
- if (parentDir !== dirPath) {
76
- this.ensureDirectory(parentDir);
77
- }
78
-
79
- // Create the directory
80
- fs.mkdirSync(dirPath);
81
- }
82
-
83
- /**
84
- * Install bash completion
85
- */
86
- installBash() {
87
- const rcFile = path.join(this.homeDir, '.bashrc');
88
- const completionPath = path.join(this.completionDir, 'ccs.bash');
89
-
90
- if (!fs.existsSync(completionPath)) {
91
- throw new Error('Completion file not found. Please reinstall CCS.');
92
- }
93
-
94
- const marker = '# CCS shell completion';
95
- const sourceCmd = `source "${completionPath}"`;
96
- const block = `\n${marker}\n${sourceCmd}\n`;
97
-
98
- // Check if already installed
99
- if (fs.existsSync(rcFile)) {
100
- const content = fs.readFileSync(rcFile, 'utf8');
101
- if (content.includes(marker)) {
102
- return { success: true, alreadyInstalled: true };
103
- }
104
- }
105
-
106
- // Append to .bashrc
107
- fs.appendFileSync(rcFile, block);
108
-
109
- return {
110
- success: true,
111
- message: `Added to ${rcFile}`,
112
- reload: 'source ~/.bashrc'
113
- };
114
- }
115
-
116
- /**
117
- * Install zsh completion
118
- */
119
- installZsh() {
120
- const rcFile = path.join(this.homeDir, '.zshrc');
121
- const completionPath = path.join(this.completionDir, 'ccs.zsh');
122
- const zshCompDir = path.join(this.homeDir, '.zsh', 'completion');
123
-
124
- if (!fs.existsSync(completionPath)) {
125
- throw new Error('Completion file not found. Please reinstall CCS.');
126
- }
127
-
128
- // Create zsh completion directory (with file conflict checking)
129
- this.ensureDirectory(zshCompDir);
130
-
131
- // Copy to zsh completion directory
132
- const destFile = path.join(zshCompDir, '_ccs');
133
- fs.copyFileSync(completionPath, destFile);
134
-
135
- const marker = '# CCS shell completion';
136
- const setupCmds = [
137
- 'fpath=(~/.zsh/completion $fpath)',
138
- 'autoload -Uz compinit && compinit'
139
- ];
140
- const block = `\n${marker}\n${setupCmds.join('\n')}\n`;
141
-
142
- // Check if already installed
143
- if (fs.existsSync(rcFile)) {
144
- const content = fs.readFileSync(rcFile, 'utf8');
145
- if (content.includes(marker)) {
146
- return { success: true, alreadyInstalled: true };
147
- }
148
- }
149
-
150
- // Append to .zshrc
151
- fs.appendFileSync(rcFile, block);
152
-
153
- return {
154
- success: true,
155
- message: `Added to ${rcFile}`,
156
- reload: 'source ~/.zshrc'
157
- };
158
- }
159
-
160
- /**
161
- * Install fish completion
162
- */
163
- installFish() {
164
- const completionPath = path.join(this.completionDir, 'ccs.fish');
165
- const fishCompDir = path.join(this.homeDir, '.config', 'fish', 'completions');
166
-
167
- if (!fs.existsSync(completionPath)) {
168
- throw new Error('Completion file not found. Please reinstall CCS.');
169
- }
170
-
171
- // Create fish completion directory (with file conflict checking)
172
- this.ensureDirectory(fishCompDir);
173
-
174
- // Copy to fish completion directory (fish auto-loads from here)
175
- const destFile = path.join(fishCompDir, 'ccs.fish');
176
- fs.copyFileSync(completionPath, destFile);
177
-
178
- return {
179
- success: true,
180
- message: `Installed to ${destFile}`,
181
- reload: 'Fish auto-loads completions (no reload needed)'
182
- };
183
- }
184
-
185
- /**
186
- * Install PowerShell completion
187
- */
188
- installPowerShell() {
189
- const profilePath = process.env.PROFILE || path.join(
190
- this.homeDir,
191
- 'Documents',
192
- 'PowerShell',
193
- 'Microsoft.PowerShell_profile.ps1'
194
- );
195
- const completionPath = path.join(this.completionDir, 'ccs.ps1');
196
-
197
- if (!fs.existsSync(completionPath)) {
198
- throw new Error('Completion file not found. Please reinstall CCS.');
199
- }
200
-
201
- const marker = '# CCS shell completion';
202
- const sourceCmd = `. "${completionPath.replace(/\\/g, '\\\\')}"`;
203
- const block = `\n${marker}\n${sourceCmd}\n`;
204
-
205
- // Create profile directory if needed (with file conflict checking)
206
- const profileDir = path.dirname(profilePath);
207
- this.ensureDirectory(profileDir);
208
-
209
- // Check if already installed
210
- if (fs.existsSync(profilePath)) {
211
- const content = fs.readFileSync(profilePath, 'utf8');
212
- if (content.includes(marker)) {
213
- return { success: true, alreadyInstalled: true };
214
- }
215
- }
216
-
217
- // Append to PowerShell profile
218
- fs.appendFileSync(profilePath, block);
219
-
220
- return {
221
- success: true,
222
- message: `Added to ${profilePath}`,
223
- reload: '. $PROFILE'
224
- };
225
- }
226
-
227
- /**
228
- * Install for detected or specified shell
229
- */
230
- install(shell = null) {
231
- const targetShell = shell || this.detectShell();
232
-
233
- if (!targetShell) {
234
- throw new Error('Could not detect shell. Please specify: --bash, --zsh, --fish, or --powershell');
235
- }
236
-
237
- // Ensure completion files exist
238
- this.ensureCompletionFiles();
239
-
240
- // Install for target shell
241
- switch (targetShell) {
242
- case 'bash':
243
- return this.installBash();
244
- case 'zsh':
245
- return this.installZsh();
246
- case 'fish':
247
- return this.installFish();
248
- case 'powershell':
249
- return this.installPowerShell();
250
- default:
251
- throw new Error(`Unsupported shell: ${targetShell}`);
252
- }
253
- }
254
- }
255
-
256
- module.exports = { ShellCompletionInstaller };
@@ -1,243 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
- const https = require('https');
7
- const { colored } = require('./helpers');
8
-
9
- const UPDATE_CHECK_FILE = path.join(os.homedir(), '.ccs', 'update-check.json');
10
- const CHECK_INTERVAL = 24 * 60 * 60 * 1000; // 24 hours
11
- const GITHUB_API_URL = 'https://api.github.com/repos/kaitranntt/ccs/releases/latest';
12
- const NPM_REGISTRY_URL = 'https://registry.npmjs.org/@kaitranntt/ccs/latest';
13
- const REQUEST_TIMEOUT = 5000; // 5 seconds
14
-
15
- /**
16
- * Compare semantic versions
17
- * @param {string} v1 - First version (e.g., "4.1.6")
18
- * @param {string} v2 - Second version
19
- * @returns {number} - 1 if v1 > v2, -1 if v1 < v2, 0 if equal
20
- */
21
- function compareVersions(v1, v2) {
22
- const parts1 = v1.replace(/^v/, '').split('.').map(Number);
23
- const parts2 = v2.replace(/^v/, '').split('.').map(Number);
24
-
25
- for (let i = 0; i < 3; i++) {
26
- const p1 = parts1[i] || 0;
27
- const p2 = parts2[i] || 0;
28
- if (p1 > p2) return 1;
29
- if (p1 < p2) return -1;
30
- }
31
- return 0;
32
- }
33
-
34
- /**
35
- * Fetch latest version from GitHub releases
36
- * @returns {Promise<string|null>} - Latest version or null on error
37
- */
38
- function fetchLatestVersionFromGitHub() {
39
- return new Promise((resolve) => {
40
- const req = https.get(GITHUB_API_URL, {
41
- headers: { 'User-Agent': 'CCS-Update-Checker' },
42
- timeout: REQUEST_TIMEOUT
43
- }, (res) => {
44
- let data = '';
45
-
46
- res.on('data', (chunk) => {
47
- data += chunk;
48
- });
49
-
50
- res.on('end', () => {
51
- try {
52
- if (res.statusCode !== 200) {
53
- resolve(null);
54
- return;
55
- }
56
-
57
- const release = JSON.parse(data);
58
- const version = release.tag_name?.replace(/^v/, '') || null;
59
- resolve(version);
60
- } catch (err) {
61
- resolve(null);
62
- }
63
- });
64
- });
65
-
66
- req.on('error', () => resolve(null));
67
- req.on('timeout', () => {
68
- req.destroy();
69
- resolve(null);
70
- });
71
- });
72
- }
73
-
74
- /**
75
- * Fetch latest version from npm registry
76
- * @returns {Promise<string|null>} - Latest version or null on error
77
- */
78
- function fetchLatestVersionFromNpm() {
79
- return new Promise((resolve) => {
80
- const req = https.get(NPM_REGISTRY_URL, {
81
- headers: { 'User-Agent': 'CCS-Update-Checker' },
82
- timeout: REQUEST_TIMEOUT
83
- }, (res) => {
84
- let data = '';
85
-
86
- res.on('data', (chunk) => {
87
- data += chunk;
88
- });
89
-
90
- res.on('end', () => {
91
- try {
92
- if (res.statusCode !== 200) {
93
- resolve(null);
94
- return;
95
- }
96
-
97
- const packageData = JSON.parse(data);
98
- const version = packageData.version || null;
99
- resolve(version);
100
- } catch (err) {
101
- resolve(null);
102
- }
103
- });
104
- });
105
-
106
- req.on('error', () => resolve(null));
107
- req.on('timeout', () => {
108
- req.destroy();
109
- resolve(null);
110
- });
111
- });
112
- }
113
-
114
- /**
115
- * Read update check cache
116
- * @returns {Object} - Cache object
117
- */
118
- function readCache() {
119
- try {
120
- if (!fs.existsSync(UPDATE_CHECK_FILE)) {
121
- return { last_check: 0, latest_version: null, dismissed_version: null };
122
- }
123
-
124
- const data = fs.readFileSync(UPDATE_CHECK_FILE, 'utf8');
125
- return JSON.parse(data);
126
- } catch (err) {
127
- return { last_check: 0, latest_version: null, dismissed_version: null };
128
- }
129
- }
130
-
131
- /**
132
- * Write update check cache
133
- * @param {Object} cache - Cache object to write
134
- */
135
- function writeCache(cache) {
136
- try {
137
- const ccsDir = path.join(os.homedir(), '.ccs');
138
- if (!fs.existsSync(ccsDir)) {
139
- fs.mkdirSync(ccsDir, { recursive: true, mode: 0o700 });
140
- }
141
-
142
- fs.writeFileSync(UPDATE_CHECK_FILE, JSON.stringify(cache, null, 2), 'utf8');
143
- } catch (err) {
144
- // Silently fail - not critical
145
- }
146
- }
147
-
148
- /**
149
- * Check for updates (async, non-blocking)
150
- * @param {string} currentVersion - Current CCS version
151
- * @param {boolean} force - Force check even if within interval
152
- * @param {string} installMethod - Installation method ('npm' or 'direct')
153
- * @returns {Promise<Object>} - Update result object with status and data
154
- */
155
- async function checkForUpdates(currentVersion, force = false, installMethod = 'direct') {
156
- const cache = readCache();
157
- const now = Date.now();
158
-
159
- // Check if we should check for updates
160
- if (!force && (now - cache.last_check < CHECK_INTERVAL)) {
161
- // Use cached result if available
162
- if (cache.latest_version && compareVersions(cache.latest_version, currentVersion) > 0) {
163
- // Don't show if user dismissed this version
164
- if (cache.dismissed_version === cache.latest_version) {
165
- return { status: 'no_update', reason: 'dismissed' };
166
- }
167
- return { status: 'update_available', latest: cache.latest_version, current: currentVersion };
168
- }
169
- return { status: 'no_update', reason: 'cached' };
170
- }
171
-
172
- // Fetch latest version from appropriate source
173
- let latestVersion;
174
- let fetchError = null;
175
-
176
- if (installMethod === 'npm') {
177
- latestVersion = await fetchLatestVersionFromNpm();
178
- if (!latestVersion) fetchError = 'npm_registry_error';
179
- } else {
180
- latestVersion = await fetchLatestVersionFromGitHub();
181
- if (!latestVersion) fetchError = 'github_api_error';
182
- }
183
-
184
- // Update cache
185
- cache.last_check = now;
186
- if (latestVersion) {
187
- cache.latest_version = latestVersion;
188
- }
189
- writeCache(cache);
190
-
191
- // Handle fetch errors
192
- if (fetchError) {
193
- return {
194
- status: 'check_failed',
195
- reason: fetchError,
196
- message: `Failed to check for updates: ${fetchError.replace(/_/g, ' ')}`
197
- };
198
- }
199
-
200
- // Check if update available
201
- if (latestVersion && compareVersions(latestVersion, currentVersion) > 0) {
202
- // Don't show if user dismissed this version
203
- if (cache.dismissed_version === latestVersion) {
204
- return { status: 'no_update', reason: 'dismissed' };
205
- }
206
- return { status: 'update_available', latest: latestVersion, current: currentVersion };
207
- }
208
-
209
- return { status: 'no_update', reason: 'latest' };
210
- }
211
-
212
- /**
213
- * Show update notification
214
- * @param {Object} updateInfo - Update information
215
- */
216
- function showUpdateNotification(updateInfo) {
217
- console.log('');
218
- console.log(colored('═══════════════════════════════════════════════════════', 'cyan'));
219
- console.log(colored(` Update available: ${updateInfo.current} → ${updateInfo.latest}`, 'yellow'));
220
- console.log(colored('═══════════════════════════════════════════════════════', 'cyan'));
221
- console.log('');
222
- console.log(` Run ${colored('ccs update', 'yellow')} to update`);
223
- console.log('');
224
- }
225
-
226
- /**
227
- * Dismiss update notification for a specific version
228
- * @param {string} version - Version to dismiss
229
- */
230
- function dismissUpdate(version) {
231
- const cache = readCache();
232
- cache.dismissed_version = version;
233
- writeCache(cache);
234
- }
235
-
236
- module.exports = {
237
- compareVersions,
238
- checkForUpdates,
239
- showUpdateNotification,
240
- dismissUpdate,
241
- readCache,
242
- writeCache
243
- };