@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
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Binary Manager for CLIProxyAPI
3
+ *
4
+ * Download-on-demand binary manager:
5
+ * - Downloads platform-specific binary from GitHub releases
6
+ * - Verifies SHA256 checksum
7
+ * - Extracts and caches binary locally
8
+ * - Supports retry logic with exponential backoff
9
+ *
10
+ * Pattern: Mirrors npm install behavior (fast check, download only when needed)
11
+ */
12
+ import { BinaryInfo, BinaryManagerConfig } from './types';
13
+ /**
14
+ * Binary Manager class for CLIProxyAPI binary lifecycle
15
+ */
16
+ export declare class BinaryManager {
17
+ private config;
18
+ private verbose;
19
+ constructor(config?: Partial<BinaryManagerConfig>);
20
+ /**
21
+ * Ensure binary is available (download if missing)
22
+ * @returns Path to executable binary
23
+ */
24
+ ensureBinary(): Promise<string>;
25
+ /**
26
+ * Get full path to binary executable
27
+ */
28
+ getBinaryPath(): string;
29
+ /**
30
+ * Check if binary exists
31
+ */
32
+ isBinaryInstalled(): boolean;
33
+ /**
34
+ * Get binary info if installed
35
+ */
36
+ getBinaryInfo(): Promise<BinaryInfo | null>;
37
+ /**
38
+ * Download and install binary
39
+ */
40
+ private downloadAndInstall;
41
+ /**
42
+ * Download file with retry logic and exponential backoff
43
+ */
44
+ private downloadWithRetry;
45
+ /**
46
+ * Download file from URL with progress tracking
47
+ */
48
+ private downloadFile;
49
+ /**
50
+ * Verify file checksum against checksums.txt
51
+ */
52
+ private verifyChecksum;
53
+ /**
54
+ * Parse checksum from checksums.txt content
55
+ */
56
+ private parseChecksum;
57
+ /**
58
+ * Compute SHA256 checksum of file
59
+ */
60
+ private computeChecksum;
61
+ /**
62
+ * Fetch text content from URL
63
+ */
64
+ private fetchText;
65
+ /**
66
+ * Extract archive (tar.gz or zip)
67
+ */
68
+ private extractArchive;
69
+ /**
70
+ * Extract tar.gz archive using Node.js built-in modules
71
+ */
72
+ private extractTarGz;
73
+ /**
74
+ * Extract zip archive using Node.js (simple implementation)
75
+ */
76
+ private extractZip;
77
+ /**
78
+ * Delete binary (for cleanup or reinstall)
79
+ */
80
+ deleteBinary(): void;
81
+ /**
82
+ * Sleep helper
83
+ */
84
+ private sleep;
85
+ /**
86
+ * Log message if verbose
87
+ */
88
+ private log;
89
+ }
90
+ /**
91
+ * Convenience function to ensure binary is available
92
+ * @returns Path to CLIProxyAPI executable
93
+ */
94
+ export declare function ensureCLIProxyBinary(verbose?: boolean): Promise<string>;
95
+ /**
96
+ * Check if CLIProxyAPI binary is installed
97
+ */
98
+ export declare function isCLIProxyInstalled(): boolean;
99
+ /**
100
+ * Get CLIProxyAPI binary path (may not exist)
101
+ */
102
+ export declare function getCLIProxyPath(): string;
103
+ export default BinaryManager;
104
+ //# sourceMappingURL=binary-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binary-manager.d.ts","sourceRoot":"","sources":["../../src/cliproxy/binary-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,OAAO,EACL,UAAU,EACV,mBAAmB,EAIpB,MAAM,SAAS,CAAC;AAmBjB;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,OAAO,CAAU;gBAEb,MAAM,GAAE,OAAO,CAAC,mBAAmB,CAAM;IAKrD;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAgBrC;;OAEG;IACH,aAAa,IAAI,MAAM;IAKvB;;OAEG;IACH,iBAAiB,IAAI,OAAO;IAI5B;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAiBjD;;OAEG;YACW,kBAAkB;IAwEhC;;OAEG;YACW,iBAAiB;IA6B/B;;OAEG;IACH,OAAO,CAAC,YAAY;IAqEpB;;OAEG;YACW,cAAc;IAwB5B;;OAEG;IACH,OAAO,CAAC,aAAa;IAYrB;;OAEG;IACH,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,OAAO,CAAC,SAAS;IAmCjB;;OAEG;YACW,cAAc;IAQ5B;;OAEG;IACH,OAAO,CAAC,YAAY;IA0GpB;;OAEG;IACH,OAAO,CAAC,UAAU;IA2FlB;;OAEG;IACH,YAAY,IAAI,IAAI;IAQpB;;OAEG;IACH,OAAO,CAAC,KAAK;IAIb;;OAEG;IACH,OAAO,CAAC,GAAG;CAKZ;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CAAC,OAAO,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAG3E;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAG7C;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAGxC;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,567 @@
1
+ "use strict";
2
+ /**
3
+ * Binary Manager for CLIProxyAPI
4
+ *
5
+ * Download-on-demand binary manager:
6
+ * - Downloads platform-specific binary from GitHub releases
7
+ * - Verifies SHA256 checksum
8
+ * - Extracts and caches binary locally
9
+ * - Supports retry logic with exponential backoff
10
+ *
11
+ * Pattern: Mirrors npm install behavior (fast check, download only when needed)
12
+ */
13
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ var desc = Object.getOwnPropertyDescriptor(m, k);
16
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
+ desc = { enumerable: true, get: function() { return m[k]; } };
18
+ }
19
+ Object.defineProperty(o, k2, desc);
20
+ }) : (function(o, m, k, k2) {
21
+ if (k2 === undefined) k2 = k;
22
+ o[k2] = m[k];
23
+ }));
24
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
26
+ }) : function(o, v) {
27
+ o["default"] = v;
28
+ });
29
+ var __importStar = (this && this.__importStar) || function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.getCLIProxyPath = exports.isCLIProxyInstalled = exports.ensureCLIProxyBinary = exports.BinaryManager = void 0;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const https = __importStar(require("https"));
41
+ const http = __importStar(require("http"));
42
+ const crypto = __importStar(require("crypto"));
43
+ const zlib = __importStar(require("zlib"));
44
+ const progress_indicator_1 = require("../utils/progress-indicator");
45
+ const config_generator_1 = require("./config-generator");
46
+ const platform_detector_1 = require("./platform-detector");
47
+ /** Default configuration */
48
+ const DEFAULT_CONFIG = {
49
+ version: platform_detector_1.CLIPROXY_VERSION,
50
+ releaseUrl: 'https://github.com/router-for-me/CLIProxyAPI/releases/download',
51
+ binPath: (0, config_generator_1.getBinDir)(),
52
+ maxRetries: 3,
53
+ verbose: false,
54
+ };
55
+ /**
56
+ * Binary Manager class for CLIProxyAPI binary lifecycle
57
+ */
58
+ class BinaryManager {
59
+ constructor(config = {}) {
60
+ this.config = { ...DEFAULT_CONFIG, ...config };
61
+ this.verbose = this.config.verbose;
62
+ }
63
+ /**
64
+ * Ensure binary is available (download if missing)
65
+ * @returns Path to executable binary
66
+ */
67
+ async ensureBinary() {
68
+ const binaryPath = this.getBinaryPath();
69
+ // Check if binary already exists
70
+ if (fs.existsSync(binaryPath)) {
71
+ this.log(`Binary exists: ${binaryPath}`);
72
+ return binaryPath;
73
+ }
74
+ // Download, verify, extract
75
+ this.log('Binary not found, downloading...');
76
+ await this.downloadAndInstall();
77
+ return binaryPath;
78
+ }
79
+ /**
80
+ * Get full path to binary executable
81
+ */
82
+ getBinaryPath() {
83
+ const execName = (0, platform_detector_1.getExecutableName)();
84
+ return path.join(this.config.binPath, execName);
85
+ }
86
+ /**
87
+ * Check if binary exists
88
+ */
89
+ isBinaryInstalled() {
90
+ return fs.existsSync(this.getBinaryPath());
91
+ }
92
+ /**
93
+ * Get binary info if installed
94
+ */
95
+ async getBinaryInfo() {
96
+ const binaryPath = this.getBinaryPath();
97
+ if (!fs.existsSync(binaryPath)) {
98
+ return null;
99
+ }
100
+ const platform = (0, platform_detector_1.detectPlatform)();
101
+ const checksum = await this.computeChecksum(binaryPath);
102
+ return {
103
+ path: binaryPath,
104
+ version: this.config.version,
105
+ platform,
106
+ checksum,
107
+ };
108
+ }
109
+ /**
110
+ * Download and install binary
111
+ */
112
+ async downloadAndInstall() {
113
+ const platform = (0, platform_detector_1.detectPlatform)();
114
+ const downloadUrl = (0, platform_detector_1.getDownloadUrl)(this.config.version);
115
+ const checksumsUrl = (0, platform_detector_1.getChecksumsUrl)(this.config.version);
116
+ // Ensure bin directory exists
117
+ fs.mkdirSync(this.config.binPath, { recursive: true });
118
+ // Download archive
119
+ const archivePath = path.join(this.config.binPath, `cliproxy-archive.${platform.extension}`);
120
+ const spinner = new progress_indicator_1.ProgressIndicator(`Downloading CLIProxyAPI v${this.config.version}`);
121
+ spinner.start();
122
+ try {
123
+ // Download with retry
124
+ const result = await this.downloadWithRetry(downloadUrl, archivePath);
125
+ if (!result.success) {
126
+ spinner.fail('Download failed');
127
+ throw new Error(result.error || 'Download failed after retries');
128
+ }
129
+ spinner.succeed('Download complete');
130
+ // Verify checksum
131
+ const verifySpinner = new progress_indicator_1.ProgressIndicator('Verifying checksum');
132
+ verifySpinner.start();
133
+ const checksumResult = await this.verifyChecksum(archivePath, platform.binaryName, checksumsUrl);
134
+ if (!checksumResult.valid) {
135
+ verifySpinner.fail('Checksum mismatch');
136
+ fs.unlinkSync(archivePath);
137
+ throw new Error(`Checksum mismatch for ${platform.binaryName}\n` +
138
+ `Expected: ${checksumResult.expected}\n` +
139
+ `Actual: ${checksumResult.actual}\n\n` +
140
+ `Manual download: ${downloadUrl}`);
141
+ }
142
+ verifySpinner.succeed('Checksum verified');
143
+ // Extract archive
144
+ const extractSpinner = new progress_indicator_1.ProgressIndicator('Extracting binary');
145
+ extractSpinner.start();
146
+ await this.extractArchive(archivePath, platform.extension);
147
+ extractSpinner.succeed('Extraction complete');
148
+ // Cleanup archive
149
+ fs.unlinkSync(archivePath);
150
+ // Make executable (Unix only)
151
+ const binaryPath = this.getBinaryPath();
152
+ if (platform.os !== 'windows' && fs.existsSync(binaryPath)) {
153
+ fs.chmodSync(binaryPath, 0o755);
154
+ this.log(`Set executable permissions: ${binaryPath}`);
155
+ }
156
+ console.log(`[OK] CLIProxyAPI v${this.config.version} installed successfully`);
157
+ }
158
+ catch (error) {
159
+ spinner.fail('Installation failed');
160
+ throw error;
161
+ }
162
+ }
163
+ /**
164
+ * Download file with retry logic and exponential backoff
165
+ */
166
+ async downloadWithRetry(url, destPath) {
167
+ let lastError = '';
168
+ let retries = 0;
169
+ while (retries < this.config.maxRetries) {
170
+ try {
171
+ await this.downloadFile(url, destPath);
172
+ return { success: true, filePath: destPath, retries };
173
+ }
174
+ catch (error) {
175
+ const err = error;
176
+ lastError = err.message;
177
+ retries++;
178
+ if (retries < this.config.maxRetries) {
179
+ // Exponential backoff: 1s, 2s, 4s
180
+ const delay = Math.pow(2, retries - 1) * 1000;
181
+ this.log(`Retry ${retries}/${this.config.maxRetries} after ${delay}ms: ${lastError}`);
182
+ await this.sleep(delay);
183
+ }
184
+ }
185
+ }
186
+ return {
187
+ success: false,
188
+ error: `Download failed after ${retries} attempts: ${lastError}`,
189
+ retries,
190
+ };
191
+ }
192
+ /**
193
+ * Download file from URL with progress tracking
194
+ */
195
+ downloadFile(url, destPath, onProgress) {
196
+ return new Promise((resolve, reject) => {
197
+ const handleResponse = (res) => {
198
+ // Handle redirects (GitHub releases use 302)
199
+ if (res.statusCode === 301 || res.statusCode === 302) {
200
+ const redirectUrl = res.headers.location;
201
+ if (!redirectUrl) {
202
+ reject(new Error('Redirect without location header'));
203
+ return;
204
+ }
205
+ this.log(`Following redirect: ${redirectUrl}`);
206
+ this.downloadFile(redirectUrl, destPath, onProgress).then(resolve).catch(reject);
207
+ return;
208
+ }
209
+ if (res.statusCode !== 200) {
210
+ reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage}`));
211
+ return;
212
+ }
213
+ const totalBytes = parseInt(res.headers['content-length'] || '0', 10);
214
+ let downloadedBytes = 0;
215
+ const fileStream = fs.createWriteStream(destPath);
216
+ res.on('data', (chunk) => {
217
+ downloadedBytes += chunk.length;
218
+ if (onProgress && totalBytes > 0) {
219
+ onProgress({
220
+ total: totalBytes,
221
+ downloaded: downloadedBytes,
222
+ percentage: Math.round((downloadedBytes / totalBytes) * 100),
223
+ });
224
+ }
225
+ });
226
+ res.pipe(fileStream);
227
+ fileStream.on('finish', () => {
228
+ fileStream.close();
229
+ resolve();
230
+ });
231
+ fileStream.on('error', (err) => {
232
+ fs.unlink(destPath, () => { }); // Cleanup partial file
233
+ reject(err);
234
+ });
235
+ res.on('error', (err) => {
236
+ fs.unlink(destPath, () => { });
237
+ reject(err);
238
+ });
239
+ };
240
+ const protocol = url.startsWith('https') ? https : http;
241
+ const req = protocol.get(url, handleResponse);
242
+ req.on('error', reject);
243
+ req.setTimeout(60000, () => {
244
+ req.destroy();
245
+ reject(new Error('Download timeout (60s)'));
246
+ });
247
+ });
248
+ }
249
+ /**
250
+ * Verify file checksum against checksums.txt
251
+ */
252
+ async verifyChecksum(filePath, binaryName, checksumsUrl) {
253
+ // Download checksums.txt
254
+ const checksumsContent = await this.fetchText(checksumsUrl);
255
+ // Parse expected checksum
256
+ const expectedHash = this.parseChecksum(checksumsContent, binaryName);
257
+ if (!expectedHash) {
258
+ throw new Error(`Checksum not found for ${binaryName} in checksums.txt`);
259
+ }
260
+ // Compute actual checksum
261
+ const actualHash = await this.computeChecksum(filePath);
262
+ return {
263
+ valid: actualHash === expectedHash,
264
+ expected: expectedHash,
265
+ actual: actualHash,
266
+ };
267
+ }
268
+ /**
269
+ * Parse checksum from checksums.txt content
270
+ */
271
+ parseChecksum(content, binaryName) {
272
+ const lines = content.split('\n');
273
+ for (const line of lines) {
274
+ // Format: "hash filename" or "hash filename"
275
+ const parts = line.trim().split(/\s+/);
276
+ if (parts.length >= 2 && parts[1] === binaryName) {
277
+ return parts[0].toLowerCase();
278
+ }
279
+ }
280
+ return null;
281
+ }
282
+ /**
283
+ * Compute SHA256 checksum of file
284
+ */
285
+ computeChecksum(filePath) {
286
+ return new Promise((resolve, reject) => {
287
+ const hash = crypto.createHash('sha256');
288
+ const stream = fs.createReadStream(filePath);
289
+ stream.on('data', (data) => hash.update(data));
290
+ stream.on('end', () => resolve(hash.digest('hex')));
291
+ stream.on('error', reject);
292
+ });
293
+ }
294
+ /**
295
+ * Fetch text content from URL
296
+ */
297
+ fetchText(url) {
298
+ return new Promise((resolve, reject) => {
299
+ const handleResponse = (res) => {
300
+ // Handle redirects
301
+ if (res.statusCode === 301 || res.statusCode === 302) {
302
+ const redirectUrl = res.headers.location;
303
+ if (!redirectUrl) {
304
+ reject(new Error('Redirect without location header'));
305
+ return;
306
+ }
307
+ this.fetchText(redirectUrl).then(resolve).catch(reject);
308
+ return;
309
+ }
310
+ if (res.statusCode !== 200) {
311
+ reject(new Error(`HTTP ${res.statusCode}: ${res.statusMessage}`));
312
+ return;
313
+ }
314
+ let data = '';
315
+ res.on('data', (chunk) => (data += chunk));
316
+ res.on('end', () => resolve(data));
317
+ res.on('error', reject);
318
+ };
319
+ const protocol = url.startsWith('https') ? https : http;
320
+ const req = protocol.get(url, handleResponse);
321
+ req.on('error', reject);
322
+ req.setTimeout(30000, () => {
323
+ req.destroy();
324
+ reject(new Error('Request timeout (30s)'));
325
+ });
326
+ });
327
+ }
328
+ /**
329
+ * Extract archive (tar.gz or zip)
330
+ */
331
+ async extractArchive(archivePath, extension) {
332
+ if (extension === 'tar.gz') {
333
+ await this.extractTarGz(archivePath);
334
+ }
335
+ else {
336
+ await this.extractZip(archivePath);
337
+ }
338
+ }
339
+ /**
340
+ * Extract tar.gz archive using Node.js built-in modules
341
+ */
342
+ extractTarGz(archivePath) {
343
+ return new Promise((resolve, reject) => {
344
+ const destDir = this.config.binPath;
345
+ const execName = (0, platform_detector_1.getExecutableName)();
346
+ const archiveBinaryName = (0, platform_detector_1.getArchiveBinaryName)();
347
+ // Read and decompress
348
+ const gunzip = zlib.createGunzip();
349
+ const input = fs.createReadStream(archivePath);
350
+ let headerBuffer = Buffer.alloc(0);
351
+ let currentFile = null;
352
+ let bytesRead = 0;
353
+ let fileBuffer = Buffer.alloc(0);
354
+ const processData = (data) => {
355
+ headerBuffer = Buffer.concat([headerBuffer, data]);
356
+ while (headerBuffer.length >= 512) {
357
+ if (!currentFile) {
358
+ // Parse tar header
359
+ const header = headerBuffer.subarray(0, 512);
360
+ headerBuffer = headerBuffer.subarray(512);
361
+ // Check for empty header (end of archive)
362
+ if (header.every((b) => b === 0)) {
363
+ return;
364
+ }
365
+ // Extract filename (bytes 0-99)
366
+ let name = '';
367
+ for (let i = 0; i < 100 && header[i] !== 0; i++) {
368
+ name += String.fromCharCode(header[i]);
369
+ }
370
+ // Extract size (bytes 124-135, octal)
371
+ let sizeStr = '';
372
+ for (let i = 124; i < 136 && header[i] !== 0; i++) {
373
+ sizeStr += String.fromCharCode(header[i]);
374
+ }
375
+ const size = parseInt(sizeStr.trim(), 8) || 0;
376
+ if (name && size > 0) {
377
+ // Extract just the filename (handle directories)
378
+ const baseName = path.basename(name);
379
+ if (baseName === execName ||
380
+ baseName === archiveBinaryName ||
381
+ baseName === 'cli-proxy-api') {
382
+ currentFile = { name: baseName, size };
383
+ fileBuffer = Buffer.alloc(0);
384
+ bytesRead = 0;
385
+ }
386
+ else {
387
+ // Skip this file's data
388
+ const paddedSize = Math.ceil(size / 512) * 512;
389
+ if (headerBuffer.length >= paddedSize) {
390
+ headerBuffer = headerBuffer.subarray(paddedSize);
391
+ }
392
+ else {
393
+ // Need to skip data in chunks
394
+ currentFile = { name: '', size: paddedSize };
395
+ bytesRead = 0;
396
+ }
397
+ }
398
+ }
399
+ }
400
+ else {
401
+ // Read file data
402
+ const remaining = currentFile.size - bytesRead;
403
+ const chunk = headerBuffer.subarray(0, Math.min(remaining, headerBuffer.length));
404
+ headerBuffer = headerBuffer.subarray(chunk.length);
405
+ if (currentFile.name) {
406
+ fileBuffer = Buffer.concat([fileBuffer, chunk]);
407
+ }
408
+ bytesRead += chunk.length;
409
+ if (bytesRead >= currentFile.size) {
410
+ // File complete
411
+ if (currentFile.name) {
412
+ const destPath = path.join(destDir, execName);
413
+ fs.writeFileSync(destPath, fileBuffer);
414
+ this.log(`Extracted: ${currentFile.name} -> ${destPath}`);
415
+ }
416
+ // Skip padding to 512-byte boundary
417
+ const paddedSize = Math.ceil(currentFile.size / 512) * 512;
418
+ const padding = paddedSize - currentFile.size;
419
+ if (headerBuffer.length >= padding) {
420
+ headerBuffer = headerBuffer.subarray(padding);
421
+ }
422
+ currentFile = null;
423
+ fileBuffer = Buffer.alloc(0);
424
+ }
425
+ }
426
+ }
427
+ };
428
+ input.pipe(gunzip);
429
+ gunzip.on('data', processData);
430
+ gunzip.on('end', resolve);
431
+ gunzip.on('error', reject);
432
+ input.on('error', reject);
433
+ });
434
+ }
435
+ /**
436
+ * Extract zip archive using Node.js (simple implementation)
437
+ */
438
+ extractZip(archivePath) {
439
+ return new Promise((resolve, reject) => {
440
+ const destDir = this.config.binPath;
441
+ const execName = (0, platform_detector_1.getExecutableName)();
442
+ const archiveBinaryName = (0, platform_detector_1.getArchiveBinaryName)();
443
+ const buffer = fs.readFileSync(archivePath);
444
+ // Find End of Central Directory record (EOCD)
445
+ let eocdOffset = buffer.length - 22;
446
+ while (eocdOffset >= 0) {
447
+ if (buffer.readUInt32LE(eocdOffset) === 0x06054b50) {
448
+ break;
449
+ }
450
+ eocdOffset--;
451
+ }
452
+ if (eocdOffset < 0) {
453
+ reject(new Error('Invalid ZIP file: EOCD not found'));
454
+ return;
455
+ }
456
+ const centralDirOffset = buffer.readUInt32LE(eocdOffset + 16);
457
+ let offset = centralDirOffset;
458
+ // Parse central directory
459
+ while (offset < eocdOffset) {
460
+ const sig = buffer.readUInt32LE(offset);
461
+ if (sig !== 0x02014b50)
462
+ break;
463
+ const compressionMethod = buffer.readUInt16LE(offset + 10);
464
+ const compressedSize = buffer.readUInt32LE(offset + 20);
465
+ const uncompressedSize = buffer.readUInt32LE(offset + 24);
466
+ const fileNameLength = buffer.readUInt16LE(offset + 28);
467
+ const extraFieldLength = buffer.readUInt16LE(offset + 30);
468
+ const commentLength = buffer.readUInt16LE(offset + 32);
469
+ const localHeaderOffset = buffer.readUInt32LE(offset + 42);
470
+ const fileName = buffer.toString('utf8', offset + 46, offset + 46 + fileNameLength);
471
+ const baseName = path.basename(fileName);
472
+ // Check if this is the executable we want
473
+ if (baseName === execName ||
474
+ baseName === archiveBinaryName ||
475
+ baseName === 'cli-proxy-api.exe') {
476
+ // Read from local file header
477
+ const localOffset = localHeaderOffset;
478
+ const localSig = buffer.readUInt32LE(localOffset);
479
+ if (localSig !== 0x04034b50) {
480
+ reject(new Error('Invalid local file header'));
481
+ return;
482
+ }
483
+ const localFileNameLength = buffer.readUInt16LE(localOffset + 26);
484
+ const localExtraLength = buffer.readUInt16LE(localOffset + 28);
485
+ const dataOffset = localOffset + 30 + localFileNameLength + localExtraLength;
486
+ let fileData;
487
+ if (compressionMethod === 0) {
488
+ // Stored (no compression)
489
+ fileData = buffer.subarray(dataOffset, dataOffset + compressedSize);
490
+ }
491
+ else if (compressionMethod === 8) {
492
+ // Deflate
493
+ const compressed = buffer.subarray(dataOffset, dataOffset + compressedSize);
494
+ fileData = zlib.inflateRawSync(compressed);
495
+ }
496
+ else {
497
+ reject(new Error(`Unsupported compression method: ${compressionMethod}`));
498
+ return;
499
+ }
500
+ if (fileData.length !== uncompressedSize) {
501
+ reject(new Error('Decompression size mismatch'));
502
+ return;
503
+ }
504
+ const destPath = path.join(destDir, execName);
505
+ fs.writeFileSync(destPath, fileData);
506
+ this.log(`Extracted: ${fileName} -> ${destPath}`);
507
+ resolve();
508
+ return;
509
+ }
510
+ offset += 46 + fileNameLength + extraFieldLength + commentLength;
511
+ }
512
+ reject(new Error(`Executable not found in archive: ${execName}`));
513
+ });
514
+ }
515
+ /**
516
+ * Delete binary (for cleanup or reinstall)
517
+ */
518
+ deleteBinary() {
519
+ const binaryPath = this.getBinaryPath();
520
+ if (fs.existsSync(binaryPath)) {
521
+ fs.unlinkSync(binaryPath);
522
+ this.log(`Deleted: ${binaryPath}`);
523
+ }
524
+ }
525
+ /**
526
+ * Sleep helper
527
+ */
528
+ sleep(ms) {
529
+ return new Promise((resolve) => setTimeout(resolve, ms));
530
+ }
531
+ /**
532
+ * Log message if verbose
533
+ */
534
+ log(message) {
535
+ if (this.verbose) {
536
+ console.error(`[cliproxy] ${message}`);
537
+ }
538
+ }
539
+ }
540
+ exports.BinaryManager = BinaryManager;
541
+ /**
542
+ * Convenience function to ensure binary is available
543
+ * @returns Path to CLIProxyAPI executable
544
+ */
545
+ async function ensureCLIProxyBinary(verbose = false) {
546
+ const manager = new BinaryManager({ verbose });
547
+ return manager.ensureBinary();
548
+ }
549
+ exports.ensureCLIProxyBinary = ensureCLIProxyBinary;
550
+ /**
551
+ * Check if CLIProxyAPI binary is installed
552
+ */
553
+ function isCLIProxyInstalled() {
554
+ const manager = new BinaryManager();
555
+ return manager.isBinaryInstalled();
556
+ }
557
+ exports.isCLIProxyInstalled = isCLIProxyInstalled;
558
+ /**
559
+ * Get CLIProxyAPI binary path (may not exist)
560
+ */
561
+ function getCLIProxyPath() {
562
+ const manager = new BinaryManager();
563
+ return manager.getBinaryPath();
564
+ }
565
+ exports.getCLIProxyPath = getCLIProxyPath;
566
+ exports.default = BinaryManager;
567
+ //# sourceMappingURL=binary-manager.js.map