coding-tool-x 3.8.4 → 3.8.5

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-BG6P3DX-.js +1 -0
  4. package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
  5. package/dist/web/assets/Analytics--z_FmL5P.js +1 -0
  6. package/dist/web/assets/Analytics-CyHhR126.css +1 -0
  7. package/dist/web/assets/AssetPathField-CrJtRKHy.js +1 -0
  8. package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
  9. package/dist/web/assets/ChatHistoryDrawer-BiuEryJj.js +1 -0
  10. package/dist/web/assets/CollapseItem-BAYEsL_Q.js +1 -0
  11. package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
  12. package/dist/web/assets/CommandsDrawer-YJ-U7BXN.js +1 -0
  13. package/dist/web/assets/ConfigExportDrawer-Ce_hAknW.js +1 -0
  14. package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
  15. package/dist/web/assets/ConfigTemplates-Bvr1NN6K.js +1 -0
  16. package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
  17. package/dist/web/assets/ConfigTemplatesDrawer-BjIeHfF-.js +1 -0
  18. package/dist/web/assets/ConfigTemplatesPanel-AV00tm_D.js +1 -0
  19. package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +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-Cz95o4CD.js +1 -0
  24. package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
  25. package/dist/web/assets/GatewayConvertDrawer-DLlbMz27.js +1 -0
  26. package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
  27. package/dist/web/assets/Home-D7CCOFQC.js +1 -0
  28. package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
  29. package/dist/web/assets/MarkdownEditor-rEZ-c72L.js +1 -0
  30. package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
  31. package/dist/web/assets/McpDrawer-DfoCyxU2.js +1 -0
  32. package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
  33. package/dist/web/assets/McpFormDrawer-SKu8HNUR.js +1 -0
  34. package/dist/web/assets/PluginManager-BbeK-3rV.js +1 -0
  35. package/dist/web/assets/PluginsDrawer-CWVJ7yjS.js +1 -0
  36. package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
  37. package/dist/web/assets/PluginsPanel-Cm2N3StG.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-CsjnsNPv.js +1 -0
  41. package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
  42. package/dist/web/assets/PromptsDrawer-EGd3djFa.js +1 -0
  43. package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
  44. package/dist/web/assets/RecentSessionsDrawer-D1vtoLAs.js +1 -0
  45. package/dist/web/assets/SessionCard-BgLg49U3.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-TRiTklWk.js +1 -0
  49. package/dist/web/assets/SettingsDrawer-d5liXjHq.css +1 -0
  50. package/dist/web/assets/SettingsDrawer-rz2WejGY.js +1 -0
  51. package/dist/web/assets/SkillManager-BTjTUbHq.js +1 -0
  52. package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
  53. package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
  54. package/dist/web/assets/SkillsDrawer-pN0hbkK3.js +1 -0
  55. package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
  56. package/dist/web/assets/SkillsPanel-gmBWEoiF.js +1 -0
  57. package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
  58. package/dist/web/assets/SpeedTestDrawer-DcNzuVJk.js +1 -0
  59. package/dist/web/assets/Upload-v5rV0qTT.js +1 -0
  60. package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
  61. package/dist/web/assets/WorkspaceDrawer-DxmicM4U.js +1 -0
  62. package/dist/web/assets/WorkspaceManager-CJHCjARN.js +1 -0
  63. package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
  64. package/dist/web/assets/WorkspacePanel-D8_Zq-du.js +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-C0EHRym0.css +1 -0
  71. package/dist/web/assets/index-DnEocV0M.js +2 -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-B3uojyvV.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 +94 -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 +162 -0
  140. package/src/platforms/channel-auth-service.js +82 -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 +87 -417
  269. package/src/{server/services → platforms}/notification-hooks.js +140 -1023
  270. package/src/platforms/oauth-credentials-service.js +506 -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 +11 -20
  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 +1 -1
  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 +780 -213
  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
@@ -24,6 +24,19 @@ const RUNTIME_DIR = path.join(STORAGE_DIR, 'runtime');
24
24
  const CACHE_DIR = path.join(STORAGE_DIR, 'cache');
25
25
  const CACHE_SKILLS_DIR = path.join(CACHE_DIR, 'skills');
26
26
  const CACHE_PLUGINS_DIR = path.join(CACHE_DIR, 'plugins');
27
+ const OMP_PATH_CACHE_VERSION = 1;
28
+ const OMP_PATH_CACHE_FILE = path.join(CONFIG_DIR, 'omp-path.json');
29
+ const OMP_PATH_ENV_KEYS = [
30
+ 'HOME',
31
+ 'USERPROFILE',
32
+ 'APPDATA',
33
+ 'PATH',
34
+ 'OMP_COMMAND',
35
+ 'OMP_CONFIG_DIR',
36
+ 'OMP_PROFILE',
37
+ 'PI_CODING_AGENT_DIR',
38
+ 'OMP_CODING_AGENT_DIR'
39
+ ];
27
40
  const REPOS_DIR = path.join(STORAGE_DIR, 'repos');
28
41
  const REPOS_SKILLS_DIR = path.join(REPOS_DIR, 'skills');
29
42
  const REPOS_PLUGINS_DIR = path.join(REPOS_DIR, 'plugins');
@@ -37,6 +50,9 @@ const LEGACY_CONFLICTS_DIR = path.join(LEGACY_DIR, 'root-conflicts');
37
50
  const LEGACY_ROOT_BACKUPS_DIR = path.join(LEGACY_DIR, 'root-backups');
38
51
  const LEGACY_IMPORT_STATE_FILE = path.join(LEGACY_DIR, 'import-state.json');
39
52
  const LEGACY_STATS_DIR = path.join(LEGACY_DIR, 'stats');
53
+ const CONTROL_MANIFEST_PATH = path.join(CONFIG_DIR, 'effective-control.json');
54
+ const SKILL_ARTIFACTS_DIR = path.join(STORAGE_DIR, 'skill-artifacts');
55
+ const SKILL_REFRESH_TASKS_PATH = path.join(RUNTIME_DIR, 'skill-refresh-tasks.json');
40
56
 
41
57
  // 旧目录(升级时自动合并到 ~/.cc-tool)
42
58
  const LEGACY_BASE_DIRS = [
@@ -378,7 +394,9 @@ const PATHS = {
378
394
 
379
395
  // 全局配置
380
396
  configFile: path.join(CONFIG_DIR, 'config.json'),
397
+ ompPathCache: OMP_PATH_CACHE_FILE,
381
398
  uiConfig: path.join(CONFIG_DIR, 'ui-config.json'),
399
+ platforms: path.join(CONFIG_DIR, 'platforms.json'),
382
400
  prompts: path.join(CONFIG_DIR, 'prompts.json'),
383
401
  mcpConfig: path.join(CONFIG_DIR, 'mcp-servers.json'),
384
402
  mcpServers: path.join(CONFIG_DIR, 'mcp-servers.json'),
@@ -395,6 +413,9 @@ const PATHS = {
395
413
  opencodeSessionOrder: path.join(CONFIG_DIR, 'opencode-session-order.json'),
396
414
  ompProjectOrder: path.join(CONFIG_DIR, 'omp-project-order.json'),
397
415
  ompSessionOrder: path.join(CONFIG_DIR, 'omp-session-order.json'),
416
+ effectiveControlManifest: CONTROL_MANIFEST_PATH,
417
+ skillArtifacts: SKILL_ARTIFACTS_DIR,
418
+ skillRefreshTasks: SKILL_REFRESH_TASKS_PATH,
398
419
 
399
420
  // 渠道配置
400
421
  channelsDir: CHANNELS_DIR,
@@ -435,8 +456,6 @@ const PATHS = {
435
456
  // 运行时、缓存、备份
436
457
  cache: CACHE_DIR,
437
458
  snapshotCache: path.join(CACHE_DIR, 'snapshots'),
438
- sessionCache: path.join(CACHE_DIR, 'session-cache.json'),
439
- sessionHasCache: path.join(CACHE_DIR, 'session-has-cache.json'),
440
459
  channelModels: path.join(CACHE_DIR, 'channel-models.json'),
441
460
  channelBalanceStrategies: path.join(CACHE_DIR, 'channel-balance-strategies.json'),
442
461
  sessionHistoryIndex: path.join(CACHE_DIR, 'session-history.sqlite'),
@@ -519,6 +538,65 @@ const PATHS = {
519
538
  }
520
539
  };
521
540
 
541
+ const PLATFORM_STATE_KEY_PATTERN = /^[a-z0-9][a-z0-9_-]*$/;
542
+
543
+ function normalizePlatformStateKey(platformKey) {
544
+ const key = String(platformKey || '').trim().toLowerCase();
545
+ return PLATFORM_STATE_KEY_PATTERN.test(key) ? key : '';
546
+ }
547
+
548
+ function getPlatformStatePath(category, platformKey, { basePaths = PATHS } = {}) {
549
+ const key = normalizePlatformStateKey(platformKey);
550
+ if (!key) return undefined;
551
+
552
+ const categoryPaths = basePaths && basePaths[category];
553
+ if (categoryPaths && typeof categoryPaths === 'object' && !Array.isArray(categoryPaths)) {
554
+ if (typeof categoryPaths[key] === 'string') return categoryPaths[key];
555
+ }
556
+
557
+ switch (category) {
558
+ case 'channels':
559
+ return path.join(basePaths.channelsDir, `${key}.json`);
560
+ case 'activeChannel':
561
+ return path.join(basePaths.activeChannelDir, `${key}.json`);
562
+ case 'proxyRuntime':
563
+ return path.join(path.dirname(basePaths.proxyRuntime.claude), `${key}-proxy.json`);
564
+ case 'requestSnapshots':
565
+ return path.join(path.dirname(basePaths.requestSnapshots.claude), `${key}.jsonl`);
566
+ case 'localSkills':
567
+ return path.join(path.dirname(basePaths.localSkills.claude), key);
568
+ case 'skillRepos':
569
+ return path.join(path.dirname(basePaths.skillRepos.claude), `${key}.json`);
570
+ case 'skillCaches':
571
+ return path.join(path.dirname(basePaths.skillCaches.claude), `${key}.json`);
572
+ case 'pluginRepos':
573
+ return path.join(path.dirname(basePaths.pluginRepos.claude), `${key}.json`);
574
+ case 'pluginMarketCache':
575
+ return path.join(path.dirname(basePaths.pluginMarketCache.claude), `${key}-market.json`);
576
+ case 'gatewaySecret':
577
+ return path.join(path.dirname(basePaths.ompGatewaySecret), `${key}-gateway-secret`);
578
+ default:
579
+ return undefined;
580
+ }
581
+ }
582
+
583
+ function getPlatformStatePaths(platformKey, options = {}) {
584
+ const key = normalizePlatformStateKey(platformKey);
585
+ if (!key) return {};
586
+ return {
587
+ channels: getPlatformStatePath('channels', key, options),
588
+ activeChannel: getPlatformStatePath('activeChannel', key, options),
589
+ proxyRuntime: getPlatformStatePath('proxyRuntime', key, options),
590
+ requestSnapshots: getPlatformStatePath('requestSnapshots', key, options),
591
+ localSkills: getPlatformStatePath('localSkills', key, options),
592
+ skillRepos: getPlatformStatePath('skillRepos', key, options),
593
+ skillCaches: getPlatformStatePath('skillCaches', key, options),
594
+ pluginRepos: getPlatformStatePath('pluginRepos', key, options),
595
+ pluginMarketCache: getPlatformStatePath('pluginMarketCache', key, options),
596
+ gatewaySecret: getPlatformStatePath('gatewaySecret', key, options)
597
+ };
598
+ }
599
+
522
600
  const LEGACY_STORAGE_RELOCATIONS = [
523
601
  // 全局配置文件
524
602
  { source: rootEntry('config.json'), target: PATHS.configFile },
@@ -565,8 +643,6 @@ const LEGACY_STORAGE_RELOCATIONS = [
565
643
  { source: rootEntry('opencode-daily-stats'), target: PATHS.statistics.legacy.opencodeDaily },
566
644
 
567
645
  // 缓存、运行时、脚本
568
- { source: rootEntry('session-cache.json'), target: PATHS.sessionCache },
569
- { source: rootEntry('session-has-cache.json'), target: PATHS.sessionHasCache },
570
646
  { source: rootEntry('channel-models.json'), target: PATHS.channelModels },
571
647
  { source: rootEntry('proxy-runtime.json'), target: PATHS.proxyRuntime.claude },
572
648
  { source: rootEntry('claude-proxy-runtime.json'), target: PATHS.proxyRuntime.claude },
@@ -807,7 +883,66 @@ function normalizeOmpProfileName(profile = '') {
807
883
  return value && value !== 'default' ? value : '';
808
884
  }
809
885
 
886
+ function getOmpPathFingerprint(env = process.env) {
887
+ return {
888
+ homeDir: HOME_DIR,
889
+ ...Object.fromEntries(OMP_PATH_ENV_KEYS.map(key => [key, String(env[key] || '')]))
890
+ };
891
+ }
892
+
893
+ function fingerprintsMatch(left, right) {
894
+ if (!left || !right) return false;
895
+ return Object.keys(getOmpPathFingerprint()).every(key => left[key] === right[key]);
896
+ }
897
+
898
+ function readPersistedOmpAgentDir(env = process.env, options = {}) {
899
+ if (options.resolveRuntime === false) return '';
900
+ const cacheFile = options.cacheFile || OMP_PATH_CACHE_FILE;
901
+ try {
902
+ const cached = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
903
+ if (cached.version !== OMP_PATH_CACHE_VERSION
904
+ || !fingerprintsMatch(cached.fingerprint, getOmpPathFingerprint(env))) {
905
+ return '';
906
+ }
907
+ const rawAgentDir = String(cached.agentDir || '').trim();
908
+ if (!rawAgentDir) return '';
909
+ const agentDir = path.resolve(expandHomePath(rawAgentDir));
910
+ if (!fs.statSync(agentDir).isDirectory()) return '';
911
+ return agentDir;
912
+ } catch {
913
+ return '';
914
+ }
915
+ }
916
+
917
+ function canReuseInProcessOmpPath(options = {}) {
918
+ return !options.commandRunner || options.commandRunner === execFileSync;
919
+ }
920
+
921
+ let lastOmpPathResolution = null;
922
+
923
+ function rememberOmpPathResolution(agentDir, source, env) {
924
+ lastOmpPathResolution = {
925
+ agentDir,
926
+ source,
927
+ fingerprint: getOmpPathFingerprint(env)
928
+ };
929
+ }
930
+
810
931
  function getOmpAgentDir(env = process.env, options = {}) {
932
+ const persistedAgentDir = readPersistedOmpAgentDir(env, options);
933
+ if (persistedAgentDir) {
934
+ rememberOmpPathResolution(persistedAgentDir, 'cache', env);
935
+ return persistedAgentDir;
936
+ }
937
+
938
+ if (canReuseInProcessOmpPath(options)
939
+ && lastOmpPathResolution
940
+ && lastOmpPathResolution.source !== 'fallback'
941
+ && fingerprintsMatch(lastOmpPathResolution.fingerprint, getOmpPathFingerprint(env))
942
+ && fs.existsSync(lastOmpPathResolution.agentDir)) {
943
+ return lastOmpPathResolution.agentDir;
944
+ }
945
+
811
946
  if (options.resolveRuntime !== false) {
812
947
  const command = String(env.OMP_COMMAND || 'omp').trim() || 'omp';
813
948
  const commandRunner = options.commandRunner || execFileSync;
@@ -821,7 +956,12 @@ function getOmpAgentDir(env = process.env, options = {}) {
821
956
  });
822
957
  const configuredByCli = String(output || '').trim().split(/\r?\n/).find(Boolean);
823
958
  if (configuredByCli) {
824
- return path.resolve(expandHomePath(configuredByCli));
959
+ const agentDir = path.resolve(expandHomePath(configuredByCli));
960
+ rememberOmpPathResolution(agentDir, 'cli', env);
961
+ if (canReuseInProcessOmpPath(options)) {
962
+ persistOmpAgentPath(agentDir, { ...options, env });
963
+ }
964
+ return agentDir;
825
965
  }
826
966
  } catch {
827
967
  // Fall through to environment/profile compatibility paths.
@@ -835,7 +975,9 @@ function getOmpAgentDir(env = process.env, options = {}) {
835
975
  env.PI_CODING_AGENT_DIR || env.OMP_CODING_AGENT_DIR
836
976
  );
837
977
  if (configuredDir) {
838
- return path.resolve(expandHomePath(configuredDir));
978
+ const resolvedConfiguredDir = path.resolve(expandHomePath(configuredDir));
979
+ rememberOmpPathResolution(resolvedConfiguredDir, 'fallback', env);
980
+ return resolvedConfiguredDir;
839
981
  }
840
982
  const profile = normalizeOmpProfileName(env.OMP_PROFILE);
841
983
  const configRoot = expandHomePath(
@@ -844,7 +986,34 @@ function getOmpAgentDir(env = process.env, options = {}) {
844
986
  const agentDir = profile
845
987
  ? path.join(configRoot, 'profiles', profile, 'agent')
846
988
  : path.join(configRoot, 'agent');
847
- return path.resolve(agentDir);
989
+ const resolvedAgentDir = path.resolve(agentDir);
990
+ rememberOmpPathResolution(resolvedAgentDir, 'fallback', env);
991
+ return resolvedAgentDir;
992
+ }
993
+
994
+ function persistOmpAgentPath(agentDir = lastOmpPathResolution?.agentDir, options = {}) {
995
+ const resolution = lastOmpPathResolution;
996
+ const env = options.env || process.env;
997
+ const normalizedAgentDir = agentDir ? path.resolve(agentDir) : '';
998
+ if (!resolution
999
+ || resolution.source !== 'cli'
1000
+ || !normalizedAgentDir
1001
+ || normalizedAgentDir !== resolution.agentDir
1002
+ || !fingerprintsMatch(resolution.fingerprint, getOmpPathFingerprint(env))) {
1003
+ return false;
1004
+ }
1005
+
1006
+ try {
1007
+ writeJsonFile(options.cacheFile || OMP_PATH_CACHE_FILE, {
1008
+ version: OMP_PATH_CACHE_VERSION,
1009
+ agentDir: normalizedAgentDir,
1010
+ fingerprint: resolution.fingerprint,
1011
+ savedAt: new Date().toISOString()
1012
+ });
1013
+ return true;
1014
+ } catch {
1015
+ return false;
1016
+ }
848
1017
  }
849
1018
 
850
1019
  const OMP_AGENT_DIR = getOmpAgentDir();
@@ -939,5 +1108,9 @@ module.exports = {
939
1108
  getGeminiDir,
940
1109
  getOpenCodeDataDir,
941
1110
  getOpenCodeConfigDir,
942
- getOmpAgentDir
1111
+ getOmpAgentDir,
1112
+ persistOmpAgentPath,
1113
+ getPlatformStatePath,
1114
+ getPlatformStatePaths,
1115
+ normalizePlatformStateKey
943
1116
  };
package/src/index.js CHANGED
@@ -5,23 +5,57 @@
5
5
  * 主入口文件
6
6
  */
7
7
 
8
- const { loadConfig } = require('./config/loader');
9
- const { resetConfig } = require('./reset-config');
10
- const { handleStart, handleStop, handleRestart, handleStatus } = require('./commands/daemon');
11
- const { handleProxyStart: proxyStart, handleProxyStop: proxyStop, handleProxyRestart, handleProxyStatus: proxyStatus } = require('./commands/proxy-control');
12
- const { handleLogs } = require('./commands/logs');
13
- const { handleStats, handleStatsExport } = require('./commands/stats');
14
- const { handleDoctor } = require('./commands/doctor');
15
- const { handleUpdate } = require('./commands/update');
16
- const { ensureStorageDirMigrated } = require('./config/paths');
17
- const { normalizePlatformKey } = require('./shared/platforms');
18
- const PluginManager = require('./plugins/plugin-manager');
19
- const eventBus = require('./plugins/event-bus');
20
- const { hasHostFlag } = require('./utils/cli-flags');
21
8
  const chalk = require('chalk');
22
9
  const path = require('path');
23
10
  const fs = require('fs');
24
11
 
12
+ function lazyExport(modulePath, exportName) {
13
+ return (...args) => require(modulePath)[exportName](...args);
14
+ }
15
+
16
+ const loadConfig = lazyExport('./config/loader', 'loadConfig');
17
+ const resetConfig = lazyExport('./reset-config', 'resetConfig');
18
+ const handleStart = lazyExport('./commands/daemon', 'handleStart');
19
+ const handleStop = lazyExport('./commands/daemon', 'handleStop');
20
+ const handleRestart = lazyExport('./commands/daemon', 'handleRestart');
21
+ const handleStatus = lazyExport('./commands/daemon', 'handleStatus');
22
+ const proxyStart = lazyExport('./commands/proxy-control', 'handleProxyStart');
23
+ const proxyStop = lazyExport('./commands/proxy-control', 'handleProxyStop');
24
+ const handleProxyRestart = lazyExport('./commands/proxy-control', 'handleProxyRestart');
25
+ const proxyStatus = lazyExport('./commands/proxy-control', 'handleProxyStatus');
26
+ const handleLogs = lazyExport('./commands/logs', 'handleLogs');
27
+ const handleStats = lazyExport('./commands/stats', 'handleStats');
28
+ const handleStatsExport = lazyExport('./commands/stats', 'handleStatsExport');
29
+ const handleDoctor = lazyExport('./commands/doctor', 'handleDoctor');
30
+ const handleUpdate = lazyExport('./commands/update', 'handleUpdate');
31
+ const ensureStorageDirMigrated = lazyExport('./config/paths', 'ensureStorageDirMigrated');
32
+ const createPlatformCommandRegistry = lazyExport('./commands/platform-command-registry', 'createPlatformCommandRegistry');
33
+
34
+ const eventBus = {
35
+ emitSync(...args) {
36
+ return require('./plugins/event-bus').emitSync(...args);
37
+ }
38
+ };
39
+
40
+ const PluginManager = {
41
+ initializePlugins(...args) {
42
+ return require('./plugins/plugin-manager').initializePlugins(...args);
43
+ },
44
+ isPluginCommand(...args) {
45
+ return require('./plugins/plugin-manager').isPluginCommand(...args);
46
+ },
47
+ executePluginCommand(...args) {
48
+ return require('./plugins/plugin-manager').executePluginCommand(...args);
49
+ },
50
+ shutdownPlugins(...args) {
51
+ return require('./plugins/plugin-manager').shutdownPlugins(...args);
52
+ }
53
+ };
54
+
55
+ function hasHostFlag(argv = process.argv) {
56
+ return Array.isArray(argv) && (argv.includes('--host') || argv.includes('--hosts'));
57
+ }
58
+
25
59
  function getInquirer() {
26
60
  return require('inquirer');
27
61
  }
@@ -52,26 +86,25 @@ function showHelp() {
52
86
  console.log(chalk.yellow('[UI] UI 管理:'));
53
87
  console.log(' ctx ui 前台启动 Web UI(仅本地访问)');
54
88
  console.log(' ctx ui --https 前台启动 Web UI(本地 HTTPS)');
55
- console.log(' ctx ui --host 前台启动 Web UI(允许 LAN 访问,默认允许远程写操作)');
89
+ console.log(' ctx ui --host 前台启动 Web UI(允许 LAN 访问,远程写默认关闭)');
56
90
  console.log(' ctx ui --hosts 前台启动 Web UI(同 --host)');
57
91
  console.log(' ctx --hosts 前台启动 Web UI(同 ctx ui --host)');
58
92
  console.log(' ctx ui start 后台启动 Web UI');
59
93
  console.log(' ctx ui start --https 后台启动 Web UI(本地 HTTPS)');
60
- console.log(' ctx ui start --host 后台启动 Web UI(允许 LAN 访问,默认允许远程写操作)');
94
+ console.log(' ctx ui start --host 后台启动 Web UI(允许 LAN 访问,远程写默认关闭)');
61
95
  console.log(' ctx ui start --hosts 后台启动 Web UI(同 --host)');
62
96
  console.log(' ctx ui stop 停止 Web UI');
63
97
  console.log(' ctx ui restart 重启 Web UI\n');
64
- console.log(chalk.gray(' 提示: 如需禁止 LAN 远程写操作,可设置 CC_TOOL_ALLOW_REMOTE_WRITE=false\n'));
65
-
98
+ console.log(chalk.gray(' 提示: 只有显式设置 CC_TOOL_ALLOW_REMOTE_WRITE=true 才允许 LAN 远程写操作\n'));
66
99
  console.log(chalk.yellow('[PROXY] 代理管理:'));
67
- console.log(' ctx claude start 启动 Claude 代理');
68
- console.log(' ctx claude stop 停止 Claude 代理');
69
- console.log(' ctx claude status 查看 Claude 代理状态');
70
- console.log(' ctx codex start 启动 Codex 代理');
71
- console.log(' ctx gemini start 启动 Gemini 代理');
72
- console.log(' ctx opencode start 启动 OpenCode 代理');
73
- console.log(' ctx omp start 启动 OMP 动态切换');
74
- console.log(chalk.gray(' (codex/gemini/opencode/omp 命令与 claude 类似)\n'));
100
+ const platformEntries = createPlatformCommandRegistry().helpEntries();
101
+ platformEntries.filter(entry => entry.proxy).forEach((entry) => {
102
+ const proxyLabel = entry.proxyLabel || '代理';
103
+ console.log(` ctx ${entry.command} start 启动 ${entry.label} ${proxyLabel}`);
104
+ console.log(` ctx ${entry.command} stop 停止 ${entry.label} ${proxyLabel}`);
105
+ console.log(` ctx ${entry.command} status 查看 ${entry.label} ${proxyLabel}状态`);
106
+ });
107
+ console.log(chalk.gray(' (平台命令由 Registry 配置派生)\n'));
75
108
 
76
109
  console.log(chalk.yellow('[LOG] 日志管理:'));
77
110
  console.log(' ctx logs 查看所有日志');
@@ -126,6 +159,30 @@ function showHelp() {
126
159
  console.log(chalk.gray(' 问题: https://github.com/ZeaoZhang/coding-tool/issues\n'));
127
160
  }
128
161
 
162
+ async function dispatchPlatformCommand(platform, args = [], dependencies = {}) {
163
+ const action = args[0] || 'status';
164
+ const channel = platform.key;
165
+ const options = dependencies.registry ? { registry: dependencies.registry } : {};
166
+
167
+ switch (action) {
168
+ case 'start':
169
+ await proxyStart(channel, options);
170
+ return;
171
+ case 'stop':
172
+ await proxyStop(channel, options);
173
+ return;
174
+ case 'restart':
175
+ await handleProxyRestart(channel, options);
176
+ return;
177
+ case 'status':
178
+ await proxyStatus(channel, options);
179
+ return;
180
+ default:
181
+ console.log(chalk.red(`\n[ERROR] 未知操作: ${action}\n`));
182
+ console.log(chalk.gray('支持的操作: start, stop, restart, status\n'));
183
+ }
184
+ }
185
+
129
186
  let processShutdownPromise = null;
130
187
 
131
188
  async function stopOwnedOmpGatewayBeforeExit() {
@@ -133,7 +190,7 @@ async function stopOwnedOmpGatewayBeforeExit() {
133
190
  const {
134
191
  getOmpProxyStatus,
135
192
  stopOmpProxyServer
136
- } = require('./server/omp-proxy-server');
193
+ } = require('./platforms/drivers/omp/proxy-implementation');
137
194
  if (getOmpProxyStatus().running) {
138
195
  const preserveManagedMode = process.argv.includes('--daemon');
139
196
  await stopOmpProxyServer({ forceAfterMs: 1500, preserveManagedMode });
@@ -146,9 +203,30 @@ async function stopOwnedOmpGatewayBeforeExit() {
146
203
  function shutdownProcess(code = 0, error = null) {
147
204
  if (processShutdownPromise) return processShutdownPromise;
148
205
  processShutdownPromise = (async () => {
206
+ try {
207
+ require('./server/services/native-log-observer').shutdownNativeCliLogObserver();
208
+ } catch (observerError) {
209
+ console.error(chalk.yellow(`[WARN] CLI 原生会话日志退出清理失败: ${observerError.message}`));
210
+ }
149
211
  await stopOwnedOmpGatewayBeforeExit();
150
212
  eventBus.emitSync('cli:shutdown', {});
151
213
  PluginManager.shutdownPlugins();
214
+ try {
215
+ await require('./server/websocket-server').flushPendingLogs();
216
+ } catch (flushError) {
217
+ console.error(`[WARN] Log persistence flush failed during shutdown: ${flushError.message}`);
218
+ }
219
+ try {
220
+ await require('./server/services/statistics-service').shutdownStatistics();
221
+ } catch (flushError) {
222
+ console.error(`[WARN] Statistics flush failed during shutdown: ${flushError.message}`);
223
+ }
224
+ try {
225
+ require('./server/services/session-history-index').closeSessionHistoryIndex();
226
+ require('./server/services/sqlite-connection').closeAllDatabases();
227
+ } catch (databaseError) {
228
+ console.error(chalk.yellow(`[WARN] SQLite 退出清理失败: ${databaseError.message}`));
229
+ }
152
230
  if (error) {
153
231
  console.error(error);
154
232
  }
@@ -175,19 +253,10 @@ process.on('SIGTERM', () => {
175
253
  /**
176
254
  * 主函数
177
255
  */
178
- async function main() {
179
- ensureStorageDirMigrated();
180
-
256
+ async function main({ menuDependencies } = {}) {
181
257
  // 处理命令行参数
182
258
  const args = process.argv.slice(2);
183
259
 
184
- // LAN 快捷入口,等同于 ctx ui --host/--hosts
185
- if (hasHostFlag(process.argv) && !args.some((arg) => arg && !arg.startsWith('-'))) {
186
- const { handleUI } = require('./commands/ui');
187
- await handleUI();
188
- return;
189
- }
190
-
191
260
  // --version 或 -v - 显示版本号
192
261
  if (args[0] === '--version' || args[0] === '-v') {
193
262
  console.log(getVersion());
@@ -200,6 +269,15 @@ async function main() {
200
269
  return;
201
270
  }
202
271
 
272
+ ensureStorageDirMigrated();
273
+
274
+ // LAN 快捷入口,等同于 ctx ui --host/--hosts
275
+ if (hasHostFlag(process.argv) && !args.some((arg) => arg && !arg.startsWith('-'))) {
276
+ const { handleUI } = require('./commands/ui');
277
+ await handleUI();
278
+ return;
279
+ }
280
+
203
281
  // daemon 命令兼容(保持与 README 中旧命令一致)
204
282
  if (args[0] === 'daemon') {
205
283
  const subCommand = args[1] || 'status';
@@ -304,30 +382,17 @@ async function main() {
304
382
  return;
305
383
  }
306
384
 
307
- // claude/codex/gemini/opencode/omp 代理管理命令
308
- const channels = ['claude', 'codex', 'gemini', 'opencode', 'omp'];
309
- const normalizedChannel = normalizePlatformKey(args[0]);
310
- if (channels.includes(normalizedChannel)) {
311
- const channel = String(args[0] || '').trim().toLowerCase();
312
- const action = args[1] || 'status';
313
-
314
- switch (action) {
315
- case 'start':
316
- await proxyStart(channel);
317
- break;
318
- case 'stop':
319
- await proxyStop(channel);
320
- break;
321
- case 'restart':
322
- await handleProxyRestart(channel);
323
- break;
324
- case 'status':
325
- await proxyStatus(channel);
326
- break;
327
- default:
328
- console.log(chalk.red(`\n[ERROR] 未知操作: ${action}\n`));
329
- console.log(chalk.gray('支持的操作: start, stop, restart, status\n'));
330
- }
385
+ // plugin 命令 - 插件管理
386
+ if (args[0] === 'plugin') {
387
+ const { handlePluginCommand } = require('./commands/plugin');
388
+ await handlePluginCommand(args.slice(1));
389
+ return;
390
+ }
391
+ // Registry-derived platform proxy commands
392
+ const commandRegistry = createPlatformCommandRegistry();
393
+ const platform = commandRegistry.resolve(args[0]);
394
+ if (platform) {
395
+ await dispatchPlatformCommand(platform, args.slice(1), { registry: commandRegistry });
331
396
  return;
332
397
  }
333
398
 
@@ -418,12 +483,6 @@ async function main() {
418
483
  }
419
484
  }
420
485
 
421
- // plugin 命令 - 插件管理
422
- if (args[0] === 'plugin') {
423
- const { handlePluginCommand } = require('./commands/plugin');
424
- await handlePluginCommand(args.slice(1));
425
- return;
426
- }
427
486
 
428
487
  // 加载配置
429
488
  let config = loadConfig();
@@ -452,7 +511,9 @@ async function main() {
452
511
  while (true) {
453
512
  // 显示主菜单
454
513
  const { showMainMenu } = require('./ui/menu');
455
- const action = await showMainMenu(config);
514
+ const action = menuDependencies
515
+ ? await showMainMenu(config, menuDependencies)
516
+ : await showMainMenu(config);
456
517
 
457
518
  // 发送命令开始事件
458
519
  eventBus.emitSync('cli:command:before', { command: action, args: [], config });
@@ -470,7 +531,7 @@ async function main() {
470
531
  config = loadConfig();
471
532
  }
472
533
  return switched;
473
- }, true); // crossProject = true,跨项目显示最近会话
534
+ }, true, { platform: config.currentCliType || '' }); // crossProject = true,跨项目显示最近会话
474
535
  break;
475
536
 
476
537
  case 'search':
@@ -482,7 +543,7 @@ async function main() {
482
543
  config = loadConfig();
483
544
  }
484
545
  return switched;
485
- });
546
+ }, { platform: config.currentCliType || '' });
486
547
  break;
487
548
 
488
549
  case 'switch':
@@ -499,13 +560,13 @@ async function main() {
499
560
  config = loadConfig();
500
561
  }
501
562
  return switched;
502
- });
563
+ }, false, { platform: config.currentCliType || '' });
503
564
  }
504
565
  break;
505
566
 
506
567
  case 'workspace':
507
568
  const { workspaceMenu } = require('./commands/workspace');
508
- await workspaceMenu();
569
+ await workspaceMenu({ platform: config.currentCliType || '' });
509
570
  break;
510
571
 
511
572
  case 'switch-cli-type':
@@ -745,6 +806,8 @@ main().catch((error) => {
745
806
 
746
807
  module.exports = {
747
808
  _test: {
809
+ dispatchPlatformCommand,
810
+ showHelp,
748
811
  stopOwnedOmpGatewayBeforeExit
749
812
  }
750
813
  };