coding-tool-x 3.8.4 → 3.8.6

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 (434) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +86 -15
  3. package/dist/web/assets/AgentsDrawer-Db9wAyaZ.js +1 -0
  4. package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
  5. package/dist/web/assets/Analytics-C4gMzv7g.js +1 -0
  6. package/dist/web/assets/Analytics-CyHhR126.css +1 -0
  7. package/dist/web/assets/AssetPathField-Bd_nMFu3.js +1 -0
  8. package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
  9. package/dist/web/assets/ChatHistoryDrawer-CwzJHyNP.js +1 -0
  10. package/dist/web/assets/CollapseItem-CTCfSiue.js +1 -0
  11. package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
  12. package/dist/web/assets/CommandsDrawer-vDghB1U9.js +1 -0
  13. package/dist/web/assets/ConfigExportDrawer-C-XDvlHc.js +1 -0
  14. package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
  15. package/dist/web/assets/ConfigTemplates-CYY8XRED.js +1 -0
  16. package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
  17. package/dist/web/assets/ConfigTemplatesDrawer-CbsJp76X.js +1 -0
  18. package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +1 -0
  19. package/dist/web/assets/ConfigTemplatesPanel-liMSTh7s.js +1 -0
  20. package/dist/web/assets/Divider-D28g1gwj.js +1 -0
  21. package/dist/web/assets/DrawerContent-ChXgZ1Xm.js +1 -0
  22. package/dist/web/assets/FavoritesDrawer-CG9eI9Ay.css +1 -0
  23. package/dist/web/assets/FavoritesDrawer-D6QSiYaL.js +1 -0
  24. package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
  25. package/dist/web/assets/GatewayConvertDrawer-RvET6iNG.js +1 -0
  26. package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
  27. package/dist/web/assets/Home-P8eseZcf.js +1 -0
  28. package/dist/web/assets/MarkdownEditor-CYmLGYju.js +1 -0
  29. package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
  30. package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
  31. package/dist/web/assets/McpDrawer-Ch3bkKIq.js +1 -0
  32. package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
  33. package/dist/web/assets/McpFormDrawer-BcTlgSpN.js +1 -0
  34. package/dist/web/assets/PluginManager-Dh2o0xkZ.js +1 -0
  35. package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
  36. package/dist/web/assets/PluginsDrawer-deKQ5u3I.js +1 -0
  37. package/dist/web/assets/PluginsPanel-BofsgQgj.js +1 -0
  38. package/dist/web/assets/PluginsPanel-D6ZqITcR.css +1 -0
  39. package/dist/web/assets/ProjectList-677RLZ8O.css +1 -0
  40. package/dist/web/assets/ProjectList-DhSWJHTA.js +1 -0
  41. package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
  42. package/dist/web/assets/PromptsDrawer-Cfb2FeeU.js +1 -0
  43. package/dist/web/assets/RecentSessionsDrawer-3eXamJhr.js +1 -0
  44. package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
  45. package/dist/web/assets/SessionCard-CW0eHURI.js +1 -0
  46. package/dist/web/assets/SessionCard-aM2NHu6i.css +1 -0
  47. package/dist/web/assets/SessionList-BpYRz1cX.css +1 -0
  48. package/dist/web/assets/SessionList-DQfyDGWU.js +1 -0
  49. package/dist/web/assets/SettingsDrawer-Dw5NUgHC.css +1 -0
  50. package/dist/web/assets/SettingsDrawer-u_vwUuPS.js +1 -0
  51. package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
  52. package/dist/web/assets/SkillManager-DHMprJLA.js +1 -0
  53. package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
  54. package/dist/web/assets/SkillsDrawer-CkF3BpyC.js +1 -0
  55. package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
  56. package/dist/web/assets/SkillsPanel-DWE4pFGx.js +1 -0
  57. package/dist/web/assets/SpeedTestDrawer-BgfG1Ked.js +1 -0
  58. package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
  59. package/dist/web/assets/Upload-CNwaGOws.js +1 -0
  60. package/dist/web/assets/WorkspaceDrawer-Br5CeCzL.js +1 -0
  61. package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
  62. package/dist/web/assets/WorkspaceManager-B2O8-qIw.js +1 -0
  63. package/dist/web/assets/WorkspacePanel-5oDKit3c.js +1 -0
  64. package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
  65. package/dist/web/assets/_plugin-vue_export-helper-BeLZJZij.js +1 -0
  66. package/dist/web/assets/client-UDwXBP9i.js +1 -0
  67. package/dist/web/assets/clipboard-B46yyoz_.js +1 -0
  68. package/dist/web/assets/headers-cf-QapUq.js +1 -0
  69. package/dist/web/assets/icons-B2Vg-IOC.js +1 -0
  70. package/dist/web/assets/index-BMAUPq5K.js +2 -0
  71. package/dist/web/assets/index-Bi1MQHYX.css +1 -0
  72. package/dist/web/assets/light-Cp0t7v32.js +1 -0
  73. package/dist/web/assets/markdown-u082bbtj.js +1 -0
  74. package/dist/web/assets/platforms-CBkB45JP.js +1 -0
  75. package/dist/web/assets/platforms-FTpjxAT6.js +1 -0
  76. package/dist/web/assets/project-config-B2baPzYL.js +1 -0
  77. package/dist/web/assets/sessions-Cmy31slD.js +1 -0
  78. package/dist/web/assets/sessions-yC_oVVh8.js +1 -0
  79. package/dist/web/assets/skill-repo-input-B_fkGlUK.js +1 -0
  80. package/dist/web/assets/use-lock-html-scroll-DXIqmUW4.js +1 -0
  81. package/dist/web/assets/use-message-DoLM8C1C.js +1 -0
  82. package/dist/web/assets/useResponsiveDrawer-jbmqZuJs.js +1 -0
  83. package/dist/web/assets/vendors-D0c_0KLP.js +1 -0
  84. package/dist/web/assets/vue-vendor-BqZbbXHA.js +1 -0
  85. package/dist/web/assets/workspaces-mjyPVGS8.js +1 -0
  86. package/dist/web/assets/xml-CgY3RMlX.js +1 -0
  87. package/dist/web/index.html +12 -8
  88. package/docs/native-log-memory-2026-09-16.md +43 -0
  89. package/docs/superpowers/plans/2026-08-26-configuration-driven-cli-platform.md +1578 -0
  90. package/docs/superpowers/plans/2026-08-30-project-scoped-config-control.md +1260 -0
  91. package/docs/superpowers/plans/2026-09-01-omp-skill-refresh-boundary.md +213 -0
  92. package/docs/superpowers/plans/2026-09-01-realtime-logs-panel.md +125 -0
  93. package/docs/superpowers/plans/2026-09-02-config-driven-platform-boundary.md +86 -0
  94. package/docs/superpowers/plans/2026-09-02-platform-implementation-drivers.md +508 -0
  95. package/docs/superpowers/plans/2026-09-03-cli-platform-correctness-boundary.md +760 -0
  96. package/docs/superpowers/plans/2026-09-03-dependency-security-remediation.md +133 -0
  97. package/docs/superpowers/plans/2026-09-04-model-catalog-pricing-sync.md +1078 -0
  98. package/docs/superpowers/plans/2026-09-05-codex-project-scan-500.md +128 -0
  99. package/docs/superpowers/plans/2026-09-06-project-skill-path-fix.md +97 -0
  100. package/docs/superpowers/specs/2026-08-26-configuration-driven-cli-platform-design.md +408 -0
  101. package/docs/superpowers/specs/2026-08-30-project-scoped-config-control-design.md +467 -0
  102. package/docs/superpowers/specs/2026-09-01-claude-session-content-repair-design.md +111 -0
  103. package/docs/superpowers/specs/2026-09-01-omp-skill-refresh-boundary-design.md +83 -0
  104. package/docs/superpowers/specs/2026-09-01-realtime-logs-panel-design.md +27 -0
  105. package/docs/superpowers/specs/2026-09-02-config-driven-platform-boundary-design.md +64 -0
  106. package/docs/superpowers/specs/2026-09-02-platform-implementation-driver-boundary-design.md +123 -0
  107. package/docs/superpowers/specs/2026-09-03-cli-platform-correctness-boundary-design.md +249 -0
  108. package/docs/superpowers/specs/2026-09-03-dependency-security-remediation-design.md +87 -0
  109. package/docs/superpowers/specs/2026-09-04-model-catalog-pricing-sync-design.md +301 -0
  110. package/docs/superpowers/specs/2026-09-05-codex-project-scan-500-design.md +24 -0
  111. package/package.json +8 -4
  112. package/src/commands/channels.js +88 -191
  113. package/src/commands/cli-type.js +19 -11
  114. package/src/commands/daemon.js +104 -32
  115. package/src/commands/doctor.js +16 -9
  116. package/src/commands/export-config.js +23 -5
  117. package/src/commands/list.js +130 -52
  118. package/src/commands/logs.js +44 -27
  119. package/src/commands/platform-command-registry.js +78 -0
  120. package/src/commands/plugin.js +11 -5
  121. package/src/commands/port-config.js +34 -52
  122. package/src/commands/proxy-control.js +207 -145
  123. package/src/commands/proxy.js +2 -2
  124. package/src/commands/resume.js +87 -91
  125. package/src/commands/search.js +137 -67
  126. package/src/commands/stats.js +30 -22
  127. package/src/commands/switch.js +1 -1
  128. package/src/commands/toggle-proxy.js +94 -111
  129. package/src/commands/ui.js +67 -6
  130. package/src/commands/workspace.js +90 -8
  131. package/src/config/default.js +6 -53
  132. package/src/config/loader.js +61 -24
  133. package/src/config/model-metadata.js +49 -59
  134. package/src/config/model-metadata.json +4095 -99
  135. package/src/config/paths.js +181 -8
  136. package/src/index.js +134 -71
  137. package/src/platforms/access.js +196 -0
  138. package/src/{server/services → platforms}/agents-service.js +354 -197
  139. package/src/platforms/channel-auth-registry.js +165 -0
  140. package/src/platforms/channel-auth-service.js +107 -0
  141. package/src/{server/services → platforms}/commands-service.js +195 -115
  142. package/src/platforms/driver-registry.js +59 -0
  143. package/src/platforms/drivers/claude/api-operations.js +62 -0
  144. package/src/{server/services/channels.js → platforms/drivers/claude/channels-implementation.js} +131 -33
  145. package/src/platforms/drivers/claude/channels.js +39 -0
  146. package/src/{server/services/config-sync-service.js → platforms/drivers/claude/config-sync.js} +29 -5
  147. package/src/{server/services → platforms/drivers/claude}/health-check.js +4 -4
  148. package/src/platforms/drivers/claude/health.js +22 -0
  149. package/src/platforms/drivers/claude/mcp.js +9 -0
  150. package/src/{server/services/settings-manager.js → platforms/drivers/claude/native-config-implementation.js} +13 -4
  151. package/src/platforms/drivers/claude/native-config.js +46 -0
  152. package/src/platforms/drivers/claude/native-logs.js +72 -0
  153. package/src/{server/services/claude-openai-gateway.js → platforms/drivers/claude/openai-gateway.js} +8 -65
  154. package/src/platforms/drivers/claude/project-config.js +21 -0
  155. package/src/platforms/drivers/claude/projects.js +62 -0
  156. package/src/platforms/drivers/claude/prompts.js +9 -0
  157. package/src/{server/proxy-server.js → platforms/drivers/claude/proxy-implementation.js} +41 -278
  158. package/src/platforms/drivers/claude/proxy.js +16 -0
  159. package/src/platforms/drivers/claude/resource-sync.js +9 -0
  160. package/src/platforms/drivers/claude/session-history-adapter.js +313 -0
  161. package/src/{server/services/sessions.js → platforms/drivers/claude/sessions-implementation.js} +145 -35
  162. package/src/platforms/drivers/claude/sessions.js +76 -0
  163. package/src/{server/services/claude-statistics-service.js → platforms/drivers/claude/statistics-implementation.js} +2 -2
  164. package/src/platforms/drivers/claude/statistics.js +16 -0
  165. package/src/{server/services/claude-wire.js → platforms/drivers/claude/wire.js} +1 -1
  166. package/src/platforms/drivers/codex/api-operations.js +9 -0
  167. package/src/{server/services/codex-channels.js → platforms/drivers/codex/channels-implementation.js} +149 -14
  168. package/src/platforms/drivers/codex/channels.js +45 -0
  169. package/src/{server/services/codex-config.js → platforms/drivers/codex/config.js} +12 -2
  170. package/src/{server/services/codex-env-manager.js → platforms/drivers/codex/env-manager.js} +1 -1
  171. package/src/platforms/drivers/codex/mcp.js +9 -0
  172. package/src/{server/services/codex-settings-manager.js → platforms/drivers/codex/native-config-implementation.js} +15 -6
  173. package/src/platforms/drivers/codex/native-config.js +47 -0
  174. package/src/platforms/drivers/codex/native-logs.js +166 -0
  175. package/src/platforms/drivers/codex/project-config.js +21 -0
  176. package/src/platforms/drivers/codex/projects.js +26 -0
  177. package/src/platforms/drivers/codex/prompts.js +9 -0
  178. package/src/{server/codex-proxy-server.js → platforms/drivers/codex/proxy-implementation.js} +30 -233
  179. package/src/platforms/drivers/codex/proxy.js +16 -0
  180. package/src/platforms/drivers/codex/resource-sync.js +9 -0
  181. package/src/{server/services/session-history-adapters/codex.js → platforms/drivers/codex/session-history-adapter.js} +37 -23
  182. package/src/{server/services/codex-sessions.js → platforms/drivers/codex/sessions-implementation.js} +81 -75
  183. package/src/platforms/drivers/codex/sessions.js +36 -0
  184. package/src/{server/services/codex-statistics-service.js → platforms/drivers/codex/statistics-implementation.js} +2 -2
  185. package/src/platforms/drivers/codex/statistics.js +16 -0
  186. package/src/platforms/drivers/gemini/api-operations.js +9 -0
  187. package/src/{server/services/gemini-channels.js → platforms/drivers/gemini/channels-implementation.js} +202 -37
  188. package/src/platforms/drivers/gemini/channels.js +39 -0
  189. package/src/{server/services/gemini-config.js → platforms/drivers/gemini/config.js} +12 -2
  190. package/src/platforms/drivers/gemini/mcp.js +9 -0
  191. package/src/{server/services/gemini-settings-manager.js → platforms/drivers/gemini/native-config-implementation.js} +14 -5
  192. package/src/platforms/drivers/gemini/native-config.js +39 -0
  193. package/src/platforms/drivers/gemini/native-logs.js +180 -0
  194. package/src/platforms/drivers/gemini/project-config.js +21 -0
  195. package/src/platforms/drivers/gemini/projects.js +26 -0
  196. package/src/platforms/drivers/gemini/prompts.js +9 -0
  197. package/src/{server/gemini-proxy-server.js → platforms/drivers/gemini/proxy-implementation.js} +36 -267
  198. package/src/platforms/drivers/gemini/proxy.js +16 -0
  199. package/src/platforms/drivers/gemini/resource-sync.js +9 -0
  200. package/src/{server/services/session-history-adapters/gemini.js → platforms/drivers/gemini/session-history-adapter.js} +70 -18
  201. package/src/{server/services/gemini-sessions.js → platforms/drivers/gemini/sessions-implementation.js} +53 -37
  202. package/src/platforms/drivers/gemini/sessions.js +47 -0
  203. package/src/{server/services/gemini-statistics-service.js → platforms/drivers/gemini/statistics-implementation.js} +2 -2
  204. package/src/platforms/drivers/gemini/statistics.js +16 -0
  205. package/src/{server/services/gemini-wire.js → platforms/drivers/gemini/wire.js} +1 -1
  206. package/src/platforms/drivers/generic-filesystem.js +166 -0
  207. package/src/platforms/drivers/generic-jsonl.js +141 -0
  208. package/src/platforms/drivers/generic-mcp.js +44 -0
  209. package/src/platforms/drivers/generic-openai-compatible.js +45 -0
  210. package/src/platforms/drivers/generic-prompt.js +41 -0
  211. package/src/platforms/drivers/legacy.js +677 -0
  212. package/src/platforms/drivers/native-config-snapshot.js +125 -0
  213. package/src/platforms/drivers/native-log-utils.js +1292 -0
  214. package/src/platforms/drivers/notification-hooks.js +578 -0
  215. package/src/{server/api/omp-config.js → platforms/drivers/omp/api-operations.js} +52 -64
  216. package/src/{server/services/omp-auth-provider-worker.js → platforms/drivers/omp/auth-provider-worker.js} +1 -1
  217. package/src/{server/services/omp-auth-providers.js → platforms/drivers/omp/auth-providers.js} +1 -1
  218. package/src/{server/services/omp-channels.js → platforms/drivers/omp/channels-implementation.js} +166 -39
  219. package/src/platforms/drivers/omp/channels.js +58 -0
  220. package/src/{server/services/omp-config.js → platforms/drivers/omp/config.js} +53 -13
  221. package/src/{server/services/omp-gateway-routing.js → platforms/drivers/omp/gateway-routing.js} +14 -7
  222. package/src/{server/services/omp-gateway.js → platforms/drivers/omp/gateway.js} +4 -262
  223. package/src/platforms/drivers/omp/mcp.js +9 -0
  224. package/src/{server/services/omp-settings-manager.js → platforms/drivers/omp/native-config-implementation.js} +75 -10
  225. package/src/platforms/drivers/omp/native-config.js +46 -0
  226. package/src/platforms/drivers/omp/native-logs.js +52 -0
  227. package/src/{server/services/omp-native-plugin-adapter.js → platforms/drivers/omp/native-plugin-adapter.js} +91 -4
  228. package/src/platforms/drivers/omp/project-config.js +29 -0
  229. package/src/platforms/drivers/omp/projects.js +20 -0
  230. package/src/platforms/drivers/omp/prompts.js +9 -0
  231. package/src/{server/omp-proxy-server.js → platforms/drivers/omp/proxy-implementation.js} +6 -15
  232. package/src/platforms/drivers/omp/proxy.js +16 -0
  233. package/src/platforms/drivers/omp/resource-sync.js +9 -0
  234. package/src/{server/services/session-history-adapters/omp.js → platforms/drivers/omp/session-history-adapter.js} +42 -18
  235. package/src/{server/services/omp-sessions.js → platforms/drivers/omp/sessions-implementation.js} +130 -94
  236. package/src/platforms/drivers/omp/sessions.js +36 -0
  237. package/src/{server/services/omp-skill-discovery.js → platforms/drivers/omp/skill-discovery.js} +159 -32
  238. package/src/{server/services/omp-skill-settings-service.js → platforms/drivers/omp/skill-settings.js} +1 -1
  239. package/src/{server/services/omp-statistics-service.js → platforms/drivers/omp/statistics-implementation.js} +3 -3
  240. package/src/platforms/drivers/omp/statistics.js +16 -0
  241. package/src/platforms/drivers/opencode/api-operations.js +9 -0
  242. package/src/{server/services/opencode-channels.js → platforms/drivers/opencode/channels-implementation.js} +28 -9
  243. package/src/platforms/drivers/opencode/channels.js +40 -0
  244. package/src/platforms/drivers/opencode/conversion.js +41 -0
  245. package/src/{server/services/opencode-gateway-converter.js → platforms/drivers/opencode/gateway-converter.js} +1 -1
  246. package/src/platforms/drivers/opencode/mcp.js +9 -0
  247. package/src/{server/services/opencode-settings-manager.js → platforms/drivers/opencode/native-config-implementation.js} +17 -6
  248. package/src/platforms/drivers/opencode/native-config.js +26 -0
  249. package/src/platforms/drivers/opencode/native-logs.js +133 -0
  250. package/src/platforms/drivers/opencode/project-config.js +98 -0
  251. package/src/platforms/drivers/opencode/projects.js +20 -0
  252. package/src/platforms/drivers/opencode/prompts.js +9 -0
  253. package/src/{server/opencode-proxy-server.js → platforms/drivers/opencode/proxy-implementation.js} +27 -362
  254. package/src/platforms/drivers/opencode/proxy.js +16 -0
  255. package/src/platforms/drivers/opencode/resource-sync.js +9 -0
  256. package/src/{server/services/opencode-sessions.js → platforms/drivers/opencode/sessions-implementation.js} +211 -64
  257. package/src/platforms/drivers/opencode/sessions.js +48 -0
  258. package/src/{server/services/opencode-statistics-service.js → platforms/drivers/opencode/statistics-implementation.js} +2 -2
  259. package/src/platforms/drivers/opencode/statistics.js +16 -0
  260. package/src/platforms/drivers/secure-file-driver.js +272 -0
  261. package/src/platforms/drivers/unsupported.js +7 -0
  262. package/src/platforms/manifest-schema.js +398 -0
  263. package/src/platforms/manifests/claude.json +489 -0
  264. package/src/platforms/manifests/codex.json +448 -0
  265. package/src/platforms/manifests/gemini.json +447 -0
  266. package/src/platforms/manifests/omp.json +496 -0
  267. package/src/platforms/manifests/opencode.json +422 -0
  268. package/src/{server/services → platforms}/native-oauth-adapters.js +98 -418
  269. package/src/{server/services → platforms}/notification-hooks.js +190 -1023
  270. package/src/platforms/oauth-credentials-service.js +635 -0
  271. package/src/platforms/path-resolver.js +179 -0
  272. package/src/platforms/platform-path-context.js +305 -0
  273. package/src/platforms/registry.js +248 -0
  274. package/src/platforms/remote-notification-providers.js +678 -0
  275. package/src/platforms/runtime.js +259 -0
  276. package/src/{server/services/session-history-adapters/index.js → platforms/session-history-adapters.js} +8 -1
  277. package/src/plugins/plugin-loader.js +2 -2
  278. package/src/plugins/plugin-manager.js +2 -2
  279. package/src/plugins/registry.js +27 -10
  280. package/src/reset-config.js +21 -5
  281. package/src/server/api/agents.js +46 -72
  282. package/src/server/api/commands.js +16 -6
  283. package/src/server/api/config-registry.js +206 -59
  284. package/src/server/api/config-sync.js +3 -2
  285. package/src/server/api/config-templates.js +20 -4
  286. package/src/server/api/config.js +111 -102
  287. package/src/server/api/convert.js +54 -178
  288. package/src/server/api/dashboard.js +168 -102
  289. package/src/server/api/hooks.js +1 -1
  290. package/src/server/api/mcp.js +224 -84
  291. package/src/server/api/platform-api-config.js +102 -0
  292. package/src/server/api/platform-route-factory.js +215 -0
  293. package/src/server/api/platform-routes.js +26 -0
  294. package/src/server/api/platforms.js +110 -0
  295. package/src/server/api/plugins.js +57 -57
  296. package/src/server/api/project-config.js +168 -0
  297. package/src/server/api/prompts.js +58 -45
  298. package/src/server/api/settings.js +55 -8
  299. package/src/server/api/skills.js +262 -133
  300. package/src/server/api/ui-config.js +2 -2
  301. package/src/server/api/validation-errors.js +18 -4
  302. package/src/server/api/workspaces.js +47 -12
  303. package/src/server/index.js +164 -213
  304. package/src/server/platform-context.js +81 -0
  305. package/src/server/services/channel-balance.js +133 -24
  306. package/src/server/services/channel-health.js +21 -6
  307. package/src/server/services/channel-scheduler.js +29 -39
  308. package/src/server/services/channel-sync-utils.js +23 -13
  309. package/src/server/services/config-export-service.js +350 -319
  310. package/src/server/services/config-registry-service.js +280 -54
  311. package/src/server/services/config-sync-manager.js +172 -944
  312. package/src/server/services/config-templates-service.js +419 -353
  313. package/src/server/services/control-manifest-store.js +206 -0
  314. package/src/server/services/dashboard-snapshot-worker.js +656 -100
  315. package/src/server/services/effective-control-service.js +557 -0
  316. package/src/server/services/local-resource-index.js +314 -0
  317. package/src/server/services/mcp-service.js +607 -977
  318. package/src/server/services/model-detector.js +15 -10
  319. package/src/server/services/native-log-channel-resolver.js +214 -0
  320. package/src/server/services/native-log-observer.js +291 -0
  321. package/src/server/services/network-access.js +12 -2
  322. package/src/server/services/platform-catalog.js +82 -0
  323. package/src/server/services/platform-resolution.js +32 -29
  324. package/src/server/services/plugins-service.js +376 -122
  325. package/src/server/services/project-config-service.js +550 -0
  326. package/src/server/services/project-path-validation.js +31 -0
  327. package/src/server/services/prompts-service.js +267 -233
  328. package/src/server/services/proxy-runtime.js +7 -4
  329. package/src/server/services/remote-credential-cache.js +43 -0
  330. package/src/server/services/repo-scanner-base.js +182 -75
  331. package/src/server/services/request-logger.js +7 -4
  332. package/src/server/services/session-history-index.js +876 -214
  333. package/src/server/services/session-history-worker.js +228 -33
  334. package/src/server/services/session-snapshot-worker.js +124 -34
  335. package/src/server/services/session-snapshots.js +4 -2
  336. package/src/server/services/skill-artifact-store.js +355 -0
  337. package/src/server/services/skill-format-adapters.js +65 -0
  338. package/src/server/services/skill-projection-service.js +323 -0
  339. package/src/server/services/skill-refresh-task-service.js +275 -0
  340. package/src/server/services/skill-service.js +2020 -677
  341. package/src/server/services/snapshot-cache.js +30 -8
  342. package/src/server/services/speed-test.js +8 -8
  343. package/src/server/services/sqlite-connection.js +19 -3
  344. package/src/server/services/statistics-service.js +240 -57
  345. package/src/server/services/ui-config.js +107 -76
  346. package/src/server/services/usage-log-utils.js +98 -0
  347. package/src/server/services/web-build.js +1 -1
  348. package/src/server/services/workspace-service.js +59 -29
  349. package/src/server/utils/pricing.js +10 -19
  350. package/src/server/websocket-server.js +153 -28
  351. package/src/{server/services/base → shared}/base-channel-service.js +156 -28
  352. package/src/shared/capability-driver.js +104 -0
  353. package/src/shared/channel-auth-policy.js +27 -0
  354. package/src/shared/channel-driver.js +161 -0
  355. package/src/shared/driver-factories/api.js +180 -0
  356. package/src/shared/driver-factories/mcp.js +244 -0
  357. package/src/shared/driver-factories/projects.js +121 -0
  358. package/src/shared/driver-factories/prompts.js +58 -0
  359. package/src/shared/driver-factories/resource-sync.js +375 -0
  360. package/src/shared/driver-result.js +78 -0
  361. package/src/shared/mcp-format.js +189 -0
  362. package/src/shared/platforms.js +104 -167
  363. package/src/shared/project-config.js +512 -0
  364. package/src/shared/proxy-driver.js +57 -0
  365. package/src/{server/services/base → shared}/response-usage-parser.js +8 -4
  366. package/src/ui/menu.js +91 -67
  367. package/src/utils/port-helper.js +35 -19
  368. package/src/utils/session.js +1 -1
  369. package/dist/web/assets/Analytics-COEUXmd4.js +0 -25
  370. package/dist/web/assets/Analytics-RNn1BUbG.css +0 -1
  371. package/dist/web/assets/ConfigTemplates-DLLkS53H.js +0 -1
  372. package/dist/web/assets/Home-DCEyLzwX.js +0 -1
  373. package/dist/web/assets/Home-DYVy4cGZ.css +0 -1
  374. package/dist/web/assets/PluginManager-Oe1ZHoMO.js +0 -1
  375. package/dist/web/assets/ProjectList-CWjuAFof.js +0 -1
  376. package/dist/web/assets/ProjectList-VeMNXfgO.css +0 -1
  377. package/dist/web/assets/SessionList-C4chCPxK.css +0 -1
  378. package/dist/web/assets/SessionList-v3ehGg9U.js +0 -1
  379. package/dist/web/assets/SkillManager-BsX8Qpj0.css +0 -1
  380. package/dist/web/assets/SkillManager-DUF_qP5S.js +0 -1
  381. package/dist/web/assets/WorkspaceManager-CjAWBosO.js +0 -1
  382. package/dist/web/assets/icons-nGdSKQn2.js +0 -1
  383. package/dist/web/assets/index-D5hyHPj7.js +0 -2
  384. package/dist/web/assets/index-bJRG3RXH.css +0 -1
  385. package/dist/web/assets/markdown-BNJfEgCA.js +0 -1
  386. package/dist/web/assets/markdown-BfC0goYb.css +0 -10
  387. package/dist/web/assets/naive-ui-BALVpMgd.js +0 -1
  388. package/dist/web/assets/vendors-DQA4Hw9v.js +0 -7
  389. package/dist/web/assets/vue-vendor-B5RqjEjQ.js +0 -45
  390. package/src/config/model-pricing.js +0 -35
  391. package/src/server/api/channels.js +0 -439
  392. package/src/server/api/claude-hooks.js +0 -56
  393. package/src/server/api/claude-statistics.js +0 -57
  394. package/src/server/api/codex-channels.js +0 -491
  395. package/src/server/api/codex-projects.js +0 -117
  396. package/src/server/api/codex-proxy.js +0 -293
  397. package/src/server/api/codex-sessions.js +0 -652
  398. package/src/server/api/codex-statistics.js +0 -57
  399. package/src/server/api/gemini-channels.js +0 -392
  400. package/src/server/api/gemini-projects.js +0 -103
  401. package/src/server/api/gemini-proxy.js +0 -231
  402. package/src/server/api/gemini-sessions.js +0 -550
  403. package/src/server/api/gemini-statistics.js +0 -57
  404. package/src/server/api/health-check.js +0 -31
  405. package/src/server/api/oauth-credentials.js +0 -198
  406. package/src/server/api/omp-channels.js +0 -575
  407. package/src/server/api/omp-projects.js +0 -88
  408. package/src/server/api/omp-proxy.js +0 -125
  409. package/src/server/api/omp-sessions.js +0 -386
  410. package/src/server/api/omp-statistics.js +0 -40
  411. package/src/server/api/opencode-channels.js +0 -471
  412. package/src/server/api/opencode-projects.js +0 -110
  413. package/src/server/api/opencode-proxy.js +0 -354
  414. package/src/server/api/opencode-sessions.js +0 -466
  415. package/src/server/api/opencode-statistics.js +0 -57
  416. package/src/server/api/projects.js +0 -120
  417. package/src/server/api/proxy.js +0 -330
  418. package/src/server/api/sessions.js +0 -810
  419. package/src/server/services/oauth-credentials-service.js +0 -945
  420. package/src/server/services/omp-session-log-observer.js +0 -138
  421. package/src/server/services/opencode-gateway-adapters.js +0 -43
  422. package/src/server/services/project-snapshots.js +0 -59
  423. package/src/server/services/proxy-log-helper.js +0 -298
  424. package/src/server/services/session-cache.js +0 -127
  425. package/src/server/services/session-converter.js +0 -582
  426. package/src/server/services/session-history-adapters/claude.js +0 -235
  427. /package/src/{server/services/claude-token-recovery.js → platforms/drivers/claude/token-recovery.js} +0 -0
  428. /package/src/{server/services/codex-parser.js → platforms/drivers/codex/parser.js} +0 -0
  429. /package/src/{server/services/codex-speed-test-template.json → platforms/drivers/codex/speed-test-template.json} +0 -0
  430. /package/src/{server/services/codex-wire.js → platforms/drivers/codex/wire.js} +0 -0
  431. /package/src/{server/services/omp-auth-gateway-client.js → platforms/drivers/omp/auth-gateway-client.js} +0 -0
  432. /package/src/{server/services/opencode-normalization.js → platforms/drivers/opencode/normalization.js} +0 -0
  433. /package/src/{server/services → shared}/config-artifact-paths.js +0 -0
  434. /package/src/{server/services/base → shared}/proxy-utils.js +0 -0
@@ -15,63 +15,43 @@ function validatePort(input) {
15
15
  return true;
16
16
  }
17
17
 
18
- function buildPortQuestions(config = {}) {
18
+ function getPlatformPortDefinitions() {
19
+ const { createPlatformCommandRegistry } = require('./platform-command-registry');
20
+ return createPlatformCommandRegistry().list()
21
+ .filter(platform => platform.portKey && Number.isInteger(platform.defaultPort) && platform.defaultPort > 0);
22
+ }
23
+
24
+ function buildPortQuestions(config = {}, platformDefinitions = getPlatformPortDefinitions()) {
19
25
  const ports = config.ports || {};
20
- return [
26
+ const questions = [
21
27
  {
22
28
  type: 'input',
23
29
  name: 'webUI',
24
30
  message: 'Web UI 页面端口 (同时用于 WebSocket):',
25
31
  default: ports.webUI || 19999,
26
32
  validate: validatePort,
27
- },
28
- {
29
- type: 'input',
30
- name: 'proxy',
31
- message: 'Claude 代理服务端口:',
32
- default: ports.proxy || 20088,
33
- validate: validatePort,
34
- },
35
- {
36
- type: 'input',
37
- name: 'codexProxy',
38
- message: 'Codex 代理服务端口:',
39
- default: ports.codexProxy || 20089,
40
- validate: validatePort,
41
- },
42
- {
43
- type: 'input',
44
- name: 'geminiProxy',
45
- message: 'Gemini 代理服务端口:',
46
- default: ports.geminiProxy || 20090,
47
- validate: validatePort,
48
- },
49
- {
50
- type: 'input',
51
- name: 'opencodeProxy',
52
- message: 'OpenCode 代理服务端口:',
53
- default: ports.opencodeProxy || 20091,
54
- validate: validatePort,
55
- },
56
- {
57
- type: 'input',
58
- name: 'ompProxy',
59
- message: 'OMP 代理服务端口:',
60
- default: ports.ompProxy || 20092,
61
- validate: validatePort,
62
- },
33
+ }
63
34
  ];
35
+
36
+ for (const platform of platformDefinitions) {
37
+ questions.push({
38
+ type: 'input',
39
+ name: platform.portKey,
40
+ message: platform.portLabel || `${platform.label || platform.key} 代理服务端口:`,
41
+ default: ports[platform.portKey] || platform.defaultPort,
42
+ validate: validatePort
43
+ });
44
+ }
45
+
46
+ return questions;
64
47
  }
65
48
 
66
- function buildPortsConfig(answers = {}) {
67
- return {
68
- webUI: normalizePort(answers.webUI),
69
- proxy: normalizePort(answers.proxy),
70
- codexProxy: normalizePort(answers.codexProxy),
71
- geminiProxy: normalizePort(answers.geminiProxy),
72
- opencodeProxy: normalizePort(answers.opencodeProxy),
73
- ompProxy: normalizePort(answers.ompProxy),
74
- };
49
+ function buildPortsConfig(answers = {}, platformDefinitions = getPlatformPortDefinitions()) {
50
+ const ports = { webUI: normalizePort(answers.webUI) };
51
+ for (const platform of platformDefinitions) {
52
+ ports[platform.portKey] = normalizePort(answers[platform.portKey]);
53
+ }
54
+ return ports;
75
55
  }
76
56
 
77
57
  /**
@@ -91,13 +71,14 @@ async function handlePortConfig() {
91
71
  const config = loadConfig();
92
72
  const ports = config.ports || {};
93
73
 
74
+ const platformDefinitions = getPlatformPortDefinitions();
94
75
  console.log(chalk.cyan('当前端口配置:'));
95
76
  console.log(chalk.gray(`• Web UI 页面端口: ${ports.webUI || 19999} (同时用于 WebSocket)`));
96
- console.log(chalk.gray(`• Claude 代理端口: ${ports.proxy || 20088}`));
97
- console.log(chalk.gray(`• Codex 代理端口: ${ports.codexProxy || 20089}`));
98
- console.log(chalk.gray(`• Gemini 代理端口: ${ports.geminiProxy || 20090}`));
99
- console.log(chalk.gray(`• OpenCode 代理端口: ${ports.opencodeProxy || 20091}`));
100
- console.log(chalk.gray(`• OMP 代理端口: ${ports.ompProxy || 20092}\n`));
77
+ for (const platform of platformDefinitions) {
78
+ const label = platform.label || platform.key;
79
+ console.log(chalk.gray(`• ${label} 端口: ${ports[platform.portKey] || platform.defaultPort}`));
80
+ }
81
+ console.log('');
101
82
 
102
83
  console.log(chalk.yellow('说明:'));
103
84
  console.log(chalk.gray('• 端口范围: 1024-65535'));
@@ -134,6 +115,7 @@ module.exports = {
134
115
  _test: {
135
116
  buildPortQuestions,
136
117
  buildPortsConfig,
118
+ getPlatformPortDefinitions,
137
119
  validatePort
138
120
  }
139
121
  };
@@ -3,153 +3,180 @@ const http = require('http');
3
3
  const { loadConfig } = require('../config/loader');
4
4
  const { normalizePlatformKey } = require('../shared/platforms');
5
5
 
6
- const CHANNEL_CONFIG = {
7
- claude: {
8
- name: 'Claude',
9
- icon: '[*]',
10
- aompPath: '/api/proxy'
11
- },
12
- codex: {
13
- name: 'Codex',
14
- icon: '[*]',
15
- aompPath: '/api/codex/proxy'
16
- },
17
- gemini: {
18
- name: 'Gemini',
19
- icon: '[*]',
20
- aompPath: '/api/gemini/proxy'
21
- },
22
- opencode: {
23
- name: 'OpenCode',
24
- icon: '[*]',
25
- aompPath: '/api/opencode/proxy'
26
- },
27
- omp: {
28
- name: 'OMP',
29
- icon: '[*]',
30
- aompPath: '/api/omp/proxy',
31
- serviceLabel: 'OMP 动态切换',
32
- proxyLabel: '动态切换',
33
- startAction: '启动',
34
- stopAction: '停止',
35
- restartAction: '重启',
36
- startedMessage: 'OMP 动态切换已启用',
37
- stoppedMessage: 'OMP 已切换为单渠道直连模式',
38
- runningText: '运行中',
39
- stoppedText: '单渠道直连',
40
- portLabel: '网关端口',
41
- addressLabel: '网关地址',
42
- startTip: '启动动态切换'
43
- }
44
- };
6
+ function getDefaultRegistry() {
7
+ return require('../platforms/runtime').getPlatformRegistry();
8
+ }
45
9
 
46
- function getServiceLabel(channelInfo) {
47
- return channelInfo.serviceLabel || `${channelInfo.name} 代理服务`;
10
+ function getSupportedPlatformKeys(registry = getDefaultRegistry()) {
11
+ if (!registry || typeof registry.list !== 'function') return [];
12
+ return registry.list().map(platform => platform && platform.key).filter(Boolean);
48
13
  }
49
14
 
50
- function getProxyLabel(channelInfo) {
51
- return channelInfo.proxyLabel || '代理';
15
+ function getPlatformInfo(channel, registry = getDefaultRegistry()) {
16
+ const key = normalizePlatformKey(channel);
17
+ const definition = registry && typeof registry.resolve === 'function'
18
+ ? registry.resolve(key)
19
+ : null;
20
+ if (!definition) return null;
21
+
22
+ const labels = definition.proxyLabels && typeof definition.proxyLabels === 'object'
23
+ ? definition.proxyLabels
24
+ : {};
25
+ const configuredPath = definition.apiBasePath || `/api/platforms/${key}`;
26
+ const aompPath = configuredPath.replace(/\/+$/, '').endsWith('/proxy')
27
+ ? configuredPath.replace(/\/+$/, '')
28
+ : `${configuredPath.replace(/\/+$/, '')}/proxy`;
29
+ return {
30
+ ...labels,
31
+ key,
32
+ name: definition.label || definition.title || key,
33
+ icon: labels.icon || '[*]',
34
+ aompPath,
35
+ defaultPort: definition.defaultPort,
36
+ portKey: definition.portKey,
37
+ managedProviderConfig: definition.proxyMode === 'managed'
38
+ };
52
39
  }
53
40
 
54
- /**
55
- * HTTP 请求辅助函数
56
- */
57
- function httpRequest(method, path, data = null) {
58
- const config = loadConfig();
59
- const port = config.ports?.webUI || 19999;
60
-
61
- return new Promise((resolve, reject) => {
62
- const postData = data ? JSON.stringify(data) : null;
63
- const options = {
64
- hostname: 'localhost',
65
- port: port,
66
- path: path,
67
- method: method,
68
- headers: {
69
- 'Content-Type': 'application/json',
70
- ...(postData && { 'Content-Length': Buffer.byteLength(postData) })
71
- },
72
- timeout: 5000
73
- };
74
-
75
- const req = http.request(options, (res) => {
76
- let responseData = '';
77
-
78
- res.on('data', (chunk) => {
79
- responseData += chunk;
41
+ function createHttpRequest(loadConfigImpl = loadConfig) {
42
+ return function request(method, requestPath, data = null) {
43
+ const config = loadConfigImpl();
44
+ const port = config.ports?.webUI || 19999;
45
+
46
+ return new Promise((resolve, reject) => {
47
+ const postData = data ? JSON.stringify(data) : null;
48
+ const options = {
49
+ hostname: 'localhost',
50
+ port,
51
+ path: requestPath,
52
+ method,
53
+ headers: {
54
+ 'Content-Type': 'application/json',
55
+ ...(postData && { 'Content-Length': Buffer.byteLength(postData) })
56
+ },
57
+ timeout: 5000
58
+ };
59
+
60
+ const req = http.request(options, (res) => {
61
+ let responseData = '';
62
+
63
+ res.on('data', (chunk) => {
64
+ responseData += chunk;
65
+ });
66
+
67
+ res.on('end', () => {
68
+ try {
69
+ const json = JSON.parse(responseData);
70
+ resolve({ data: json, status: res.statusCode });
71
+ } catch (err) {
72
+ reject(new Error('Invalid JSON response'));
73
+ }
74
+ });
80
75
  });
81
76
 
82
- res.on('end', () => {
83
- try {
84
- const json = JSON.parse(responseData);
85
- resolve({ data: json, status: res.statusCode });
86
- } catch (err) {
87
- reject(new Error('Invalid JSON response'));
88
- }
77
+ req.on('error', reject);
78
+ req.on('timeout', () => {
79
+ req.destroy();
80
+ reject(new Error('Request timeout'));
89
81
  });
90
- });
91
82
 
92
- req.on('error', (err) => {
93
- reject(err);
83
+ if (postData) req.write(postData);
84
+ req.end();
94
85
  });
86
+ };
87
+ }
95
88
 
96
- req.on('timeout', () => {
97
- req.destroy();
98
- reject(new Error('Request timeout'));
99
- });
89
+ function createProxyControl({ registry = getDefaultRegistry(), httpRequest: request, loadConfig: loadConfigImpl, sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)) } = {}) {
90
+ const requestImpl = request || createHttpRequest(loadConfigImpl || loadConfig);
100
91
 
101
- if (postData) {
102
- req.write(postData);
92
+ function resolve(channel) {
93
+ const info = getPlatformInfo(channel, registry);
94
+ if (!info) {
95
+ const error = new Error(`Invalid platform: ${channel}`);
96
+ error.code = 'INVALID_PLATFORM';
97
+ throw error;
103
98
  }
99
+ return info;
100
+ }
104
101
 
105
- req.end();
106
- });
102
+ return {
103
+ resolve,
104
+ async checkUIService() {
105
+ try {
106
+ await requestImpl('GET', '/api/proxy/status');
107
+ return true;
108
+ } catch (err) {
109
+ return false;
110
+ }
111
+ },
112
+ async start(channel) {
113
+ const info = resolve(channel);
114
+ const response = await requestImpl('POST', `${info.aompPath}/start`);
115
+ return { info, response };
116
+ },
117
+ async stop(channel) {
118
+ const info = resolve(channel);
119
+ const response = await requestImpl('POST', `${info.aompPath}/stop`);
120
+ return { info, response };
121
+ },
122
+ async status(channel) {
123
+ const info = resolve(channel);
124
+ const response = await requestImpl('GET', `${info.aompPath}/status`);
125
+ return { info, response };
126
+ },
127
+ async restart(channel) {
128
+ const info = resolve(channel);
129
+ await requestImpl('POST', `${info.aompPath}/stop`);
130
+ await sleep(1000);
131
+ const response = await requestImpl('POST', `${info.aompPath}/start`);
132
+ return { info, response };
133
+ }
134
+ };
107
135
  }
108
136
 
109
- /**
110
- * 检查 UI 服务是否运行
111
- */
112
- async function checkUIService() {
113
- try {
114
- await httpRequest('GET', '/api/proxy/status');
115
- return true;
116
- } catch (err) {
117
- return false;
137
+ function printInvalidPlatform(channel, registry) {
138
+ const supported = getSupportedPlatformKeys(registry);
139
+ console.error(chalk.red(`\n[ERROR] 无效的渠道类型: ${channel}\n`));
140
+ if (supported.length > 0) {
141
+ console.log(chalk.gray(`支持的渠道: ${supported.join(', ')}\n`));
118
142
  }
119
143
  }
120
144
 
121
145
  /**
122
146
  * 启动代理
123
147
  */
124
- async function handleProxyStart(channel) {
125
- const normalizedChannel = normalizePlatformKey(channel);
126
- const channelInfo = CHANNEL_CONFIG[normalizedChannel];
127
- if (!channelInfo) {
128
- console.error(chalk.red(`\n[ERROR] 无效的渠道类型: ${channel}\n`));
129
- console.log(chalk.gray('支持的渠道: claude, codex, gemini, opencode, omp\n'));
148
+ async function handleProxyStart(channel, dependencies = {}) {
149
+ const control = createProxyControl(dependencies);
150
+ let channelInfo;
151
+ try {
152
+ channelInfo = control.resolve(channel);
153
+ } catch (error) {
154
+ printInvalidPlatform(channel, dependencies.registry);
130
155
  process.exit(1);
156
+ return;
131
157
  }
132
158
 
133
159
  console.log(chalk.cyan(`\n[START] ${channelInfo.startAction || '启动'} ${getServiceLabel(channelInfo)}...\n`));
134
160
 
135
- // 检查 UI 服务
136
- const uiRunning = await checkUIService();
161
+ const uiRunning = await control.checkUIService();
137
162
  if (!uiRunning) {
138
163
  console.error(chalk.red('[ERROR] UI 服务未运行\n'));
139
164
  console.log(chalk.yellow('[TIP] 请先启动 UI 服务:'));
140
165
  console.log(chalk.gray(' ') + chalk.cyan('ctx start') + chalk.gray(' 或 ') + chalk.cyan('ctx ui\n'));
141
166
  process.exit(1);
167
+ return;
142
168
  }
143
169
 
144
170
  try {
145
- const response = await httpRequest('POST', `${channelInfo.aompPath}/start`);
171
+ const { response } = await control.start(channel);
172
+ const payload = response.data || {};
146
173
 
147
- if (response.data.success) {
174
+ if (payload.success) {
148
175
  console.log(chalk.green(`[OK] ${channelInfo.startedMessage || `${channelInfo.name} ${getProxyLabel(channelInfo)}已启动`}\n`));
149
- console.log(chalk.gray(`${channelInfo.icon} ${channelInfo.portLabel || '代理端口'}: ${response.data.port}`));
150
- console.log(chalk.gray(`[NET] ${channelInfo.addressLabel || '代理地址'}: http://localhost:${response.data.port}\n`));
176
+ console.log(chalk.gray(`${channelInfo.icon} ${channelInfo.portLabel || '代理端口'}: ${payload.port}`));
177
+ console.log(chalk.gray(`[NET] ${channelInfo.addressLabel || '代理地址'}: http://localhost:${payload.port}\n`));
151
178
  } else {
152
- console.error(chalk.red(`[ERROR] 启动失败: ${response.data.message}\n`));
179
+ console.error(chalk.red(`[ERROR] 启动失败: ${payload.message || payload.error || 'Unknown error'}\n`));
153
180
  process.exit(1);
154
181
  }
155
182
  } catch (error) {
@@ -166,30 +193,34 @@ async function handleProxyStart(channel) {
166
193
  /**
167
194
  * 停止代理
168
195
  */
169
- async function handleProxyStop(channel) {
170
- const normalizedChannel = normalizePlatformKey(channel);
171
- const channelInfo = CHANNEL_CONFIG[normalizedChannel];
172
- if (!channelInfo) {
173
- console.error(chalk.red(`\n[ERROR] 无效的渠道类型: ${channel}\n`));
174
- console.log(chalk.gray('支持的渠道: claude, codex, gemini, opencode, omp\n'));
196
+ async function handleProxyStop(channel, dependencies = {}) {
197
+ const control = createProxyControl(dependencies);
198
+ let channelInfo;
199
+ try {
200
+ channelInfo = control.resolve(channel);
201
+ } catch (error) {
202
+ printInvalidPlatform(channel, dependencies.registry);
175
203
  process.exit(1);
204
+ return;
176
205
  }
177
206
 
178
207
  console.log(chalk.cyan(`\n[STOP] ${channelInfo.stopAction || '停止'} ${getServiceLabel(channelInfo)}...\n`));
179
208
 
180
- const uiRunning = await checkUIService();
209
+ const uiRunning = await control.checkUIService();
181
210
  if (!uiRunning) {
182
211
  console.error(chalk.red('[ERROR] UI 服务未运行,无法停止代理\n'));
183
212
  process.exit(1);
213
+ return;
184
214
  }
185
215
 
186
216
  try {
187
- const response = await httpRequest('POST', `${channelInfo.aompPath}/stop`);
217
+ const { response } = await control.stop(channel);
218
+ const payload = response.data || {};
188
219
 
189
- if (response.data.success) {
220
+ if (payload.success) {
190
221
  console.log(chalk.green(`[OK] ${channelInfo.stoppedMessage || `${channelInfo.name} ${getProxyLabel(channelInfo)}已停止`}\n`));
191
222
  } else {
192
- console.error(chalk.red(`[ERROR] 停止失败: ${response.data.message}\n`));
223
+ console.error(chalk.red(`[ERROR] 停止失败: ${payload.message || payload.error || 'Unknown error'}\n`));
193
224
  process.exit(1);
194
225
  }
195
226
  } catch (error) {
@@ -201,35 +232,55 @@ async function handleProxyStop(channel) {
201
232
  /**
202
233
  * 重启代理
203
234
  */
204
- async function handleProxyRestart(channel) {
205
- const normalizedChannel = normalizePlatformKey(channel);
206
- const channelInfo = CHANNEL_CONFIG[normalizedChannel];
207
- if (!channelInfo) {
208
- console.error(chalk.red(`\n[ERROR] 无效的渠道类型: ${channel}\n`));
209
- console.log(chalk.gray('支持的渠道: claude, codex, gemini, opencode, omp\n'));
235
+ async function handleProxyRestart(channel, dependencies = {}) {
236
+ const control = createProxyControl(dependencies);
237
+ let channelInfo;
238
+ try {
239
+ channelInfo = control.resolve(channel);
240
+ } catch (error) {
241
+ printInvalidPlatform(channel, dependencies.registry);
210
242
  process.exit(1);
243
+ return;
211
244
  }
212
245
 
213
246
  console.log(chalk.cyan(`\n[SYNC] ${channelInfo.restartAction || '重启'} ${getServiceLabel(channelInfo)}...\n`));
247
+ const uiRunning = await control.checkUIService();
248
+ if (!uiRunning) {
249
+ console.error(chalk.red('[ERROR] UI 服务未运行,无法重启代理\n'));
250
+ process.exit(1);
251
+ return;
252
+ }
214
253
 
215
- await handleProxyStop(channel);
216
- await new Promise(resolve => setTimeout(resolve, 1000));
217
- await handleProxyStart(channel);
254
+ try {
255
+ const { response } = await control.restart(channel);
256
+ const payload = response.data || {};
257
+ if (!payload.success) {
258
+ console.error(chalk.red(`[ERROR] 重启失败: ${payload.message || payload.error || 'Unknown error'}\n`));
259
+ process.exit(1);
260
+ return;
261
+ }
262
+ console.log(chalk.green(`[OK] ${channelInfo.startedMessage || `${channelInfo.name} ${getProxyLabel(channelInfo)}已重启`}\n`));
263
+ } catch (error) {
264
+ console.error(chalk.red(`[ERROR] 重启失败: ${error.message}\n`));
265
+ process.exit(1);
266
+ }
218
267
  }
219
268
 
220
269
  /**
221
270
  * 查看代理状态
222
271
  */
223
- async function handleProxyStatus(channel) {
224
- const normalizedChannel = normalizePlatformKey(channel);
225
- const channelInfo = CHANNEL_CONFIG[normalizedChannel];
226
- if (!channelInfo) {
227
- console.error(chalk.red(`\n[ERROR] 无效的渠道类型: ${channel}\n`));
228
- console.log(chalk.gray('支持的渠道: claude, codex, gemini, opencode, omp\n'));
272
+ async function handleProxyStatus(channel, dependencies = {}) {
273
+ const control = createProxyControl(dependencies);
274
+ let channelInfo;
275
+ try {
276
+ channelInfo = control.resolve(channel);
277
+ } catch (error) {
278
+ printInvalidPlatform(channel, dependencies.registry);
229
279
  process.exit(1);
280
+ return;
230
281
  }
231
282
 
232
- const uiRunning = await checkUIService();
283
+ const uiRunning = await control.checkUIService();
233
284
  if (!uiRunning) {
234
285
  console.log(chalk.bold.cyan(`\n╔======================================╗`));
235
286
  console.log(chalk.bold.cyan(`║ ${getServiceLabel(channelInfo)}状态 ║`));
@@ -240,7 +291,7 @@ async function handleProxyStatus(channel) {
240
291
  }
241
292
 
242
293
  try {
243
- const response = await httpRequest('GET', `${channelInfo.aompPath}/status`);
294
+ const { response } = await control.status(channel);
244
295
  const payload = response.data || {};
245
296
  const status = payload.proxy || payload;
246
297
 
@@ -260,18 +311,23 @@ async function handleProxyStatus(channel) {
260
311
  }
261
312
 
262
313
  console.log(chalk.bold('\n[TIP] 提示:'));
263
- console.log(chalk.gray(` • 使用 `) + chalk.cyan(`ctx ${channel} start`) + chalk.gray(` ${channelInfo.startTip || '启动代理'}`));
264
- console.log(chalk.gray(` • 使用 `) + chalk.cyan(`ctx logs ${channel}`) + chalk.gray(` 查看日志`));
265
- console.log(chalk.gray(` • 使用 `) + chalk.cyan(`ctx stats ${channel}`) + chalk.gray(` 查看统计\n`));
314
+ console.log(chalk.gray(' • 使用 ') + chalk.cyan(`ctx ${channel} start`) + chalk.gray(` ${channelInfo.startTip || '启动代理'}`));
315
+ console.log(chalk.gray(' • 使用 ') + chalk.cyan(`ctx logs ${channel}`) + chalk.gray(' 查看日志'));
316
+ console.log(chalk.gray(' • 使用 ') + chalk.cyan(`ctx stats ${channel}`) + chalk.gray(' 查看统计\n'));
266
317
  } catch (error) {
267
318
  console.error(chalk.red(`[ERROR] 查询状态失败: ${error.message}\n`));
268
319
  process.exit(1);
269
320
  }
270
321
  }
271
322
 
272
- /**
273
- * 格式化运行时长
274
- */
323
+ function getServiceLabel(channelInfo) {
324
+ return channelInfo.serviceLabel || `${channelInfo.name} 代理服务`;
325
+ }
326
+
327
+ function getProxyLabel(channelInfo) {
328
+ return channelInfo.proxyLabel || '代理';
329
+ }
330
+
275
331
  function formatRuntime(ms) {
276
332
  const seconds = Math.floor(ms / 1000);
277
333
  const minutes = Math.floor(seconds / 60);
@@ -284,14 +340,20 @@ function formatRuntime(ms) {
284
340
  return `${hours}小时 ${minutes % 60}分钟`;
285
341
  } else if (minutes > 0) {
286
342
  return `${minutes}分钟`;
287
- } else {
288
- return `${seconds}秒`;
289
343
  }
344
+ return `${seconds}秒`;
290
345
  }
291
346
 
292
347
  module.exports = {
293
348
  handleProxyStart,
294
349
  handleProxyStop,
295
350
  handleProxyRestart,
296
- handleProxyStatus
351
+ handleProxyStatus,
352
+ createProxyControl,
353
+ _test: {
354
+ createHttpRequest,
355
+ getPlatformInfo,
356
+ getSupportedPlatformKeys,
357
+ formatRuntime
358
+ }
297
359
  };
@@ -1,11 +1,11 @@
1
- const { startProxyServer, stopProxyServer, getProxyStatus } = require('../server/proxy-server');
1
+ const { startProxyServer, stopProxyServer, getProxyStatus } = require('../platforms/drivers/claude/proxy-implementation');
2
2
  const {
3
3
  setProxyConfig,
4
4
  restoreSettings,
5
5
  isProxyConfig,
6
6
  settingsExists,
7
7
  hasBackup
8
- } = require('../server/services/settings-manager');
8
+ } = require('../platforms/drivers/claude/native-config-implementation');
9
9
 
10
10
  /**
11
11
  * 启动代理