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
@@ -3,6 +3,24 @@ const path = require('path');
3
3
  const archiver = require('archiver');
4
4
  const chalk = require('chalk');
5
5
  const { HOME_DIR } = require('../config/paths');
6
+ const { getPlatformContext } = require('../server/platform-context');
7
+
8
+ function resolveClaudeExportPaths(options = {}) {
9
+ const registry = options.registry || getPlatformContext().registry;
10
+ const pathContext = options.pathContext
11
+ || registry?.resolvePathContext?.('claude', options.pathOptions || {});
12
+ const homeDir = pathContext?.home || HOME_DIR;
13
+ const native = pathContext?.native || {};
14
+ const claudeDir = native.dir || path.join(homeDir, '.claude');
15
+
16
+ return {
17
+ homeDir,
18
+ claudeDir,
19
+ prompt: native.prompt || path.join(claudeDir, 'CLAUDE.md'),
20
+ settings: native.settings || path.join(claudeDir, 'settings.json'),
21
+ skills: native.skills || path.join(claudeDir, 'skills')
22
+ };
23
+ }
6
24
 
7
25
  /**
8
26
  * 导出 Claude Code 配置为 ZIP 压缩包
@@ -14,8 +32,8 @@ async function exportConfig(options = {}) {
14
32
  try {
15
33
  console.log(chalk.blue('[START] 开始导出 Claude Code 配置...'));
16
34
 
17
- const homeDir = HOME_DIR;
18
- const claudeDir = path.join(homeDir, '.claude');
35
+ const exportPaths = resolveClaudeExportPaths(options);
36
+ const { homeDir, claudeDir } = exportPaths;
19
37
  const currentDir = process.cwd();
20
38
 
21
39
  // 检查 .claude 目录是否存在
@@ -54,7 +72,7 @@ async function exportConfig(options = {}) {
54
72
  };
55
73
 
56
74
  // 1. 导出全局 CLAUDE.md
57
- const globalClaudeMd = path.join(claudeDir, 'CLAUDE.md');
75
+ const globalClaudeMd = exportPaths.prompt;
58
76
  if (fs.existsSync(globalClaudeMd)) {
59
77
  archive.file(globalClaudeMd, { name: 'global/CLAUDE.md' });
60
78
  manifest.globalConfig.claudeMd = true;
@@ -63,7 +81,7 @@ async function exportConfig(options = {}) {
63
81
  }
64
82
 
65
83
  // 2. 导出 settings.json
66
- const settingsJson = path.join(claudeDir, 'settings.json');
84
+ const settingsJson = exportPaths.settings;
67
85
  if (fs.existsSync(settingsJson)) {
68
86
  archive.file(settingsJson, { name: 'global/settings.json' });
69
87
  manifest.globalConfig.settings = true;
@@ -89,7 +107,7 @@ async function exportConfig(options = {}) {
89
107
  }
90
108
 
91
109
  // 3. 导出 Skills
92
- const skillsDir = path.join(claudeDir, 'skills');
110
+ const skillsDir = exportPaths.skills;
93
111
  if (fs.existsSync(skillsDir)) {
94
112
  const skills = fs.readdirSync(skillsDir).filter(f => !f.startsWith('.'));
95
113
  if (skills.length > 0) {
@@ -2,22 +2,101 @@
2
2
  const chalk = require('chalk');
3
3
  const ora = require('ora');
4
4
  const inquirer = require('inquirer');
5
- const { getAllSessions, parseSessionInfoFast } = require('../utils/session');
6
5
  const { formatTime, formatSize, truncate } = require('../utils/format');
7
6
  const { promptSelectSession, promptForkConfirm } = require('../ui/prompts');
8
7
  const { resumeSession } = require('./resume');
9
8
  const { loadAliases } = require('../server/services/alias');
10
- const { getRecentSessions } = require('../server/services/sessions');
9
+ const { resolveOperation } = require('../platforms/access');
10
+
11
+ function isDriverResult(value) {
12
+ return value && typeof value === 'object' && typeof value.status === 'string';
13
+ }
14
+
15
+ function unwrapDriverResult(value) {
16
+ if (!isDriverResult(value) || value.status !== 'ok') return value;
17
+ return value.data;
18
+ }
19
+
20
+ function createFailureResult(error, platform, operation) {
21
+ const result = {
22
+ status: error?.code || 'failed',
23
+ platform: error?.platform || platform || 'claude',
24
+ capability: 'sessions',
25
+ operation,
26
+ error: error?.message || String(error)
27
+ };
28
+ if (error?.cause) {
29
+ Object.defineProperty(result, 'cause', { value: error.cause, enumerable: false });
30
+ }
31
+ return result;
32
+ }
33
+
34
+ async function invokeSessionOperation(config, operation, args, options = {}) {
35
+ const platform = options.platform || config.currentCliType || '';
36
+ let resolved;
37
+ try {
38
+ resolved = resolveOperation(platform, 'sessions', operation, {
39
+ ...options,
40
+ fallback: 'claude'
41
+ });
42
+ } catch (error) {
43
+ return createFailureResult(error, platform, operation);
44
+ }
45
+
46
+ try {
47
+ const result = await resolved.operation(...args);
48
+ return unwrapDriverResult(result);
49
+ } catch (error) {
50
+ return createFailureResult(error, resolved.key, operation);
51
+ }
52
+ }
53
+
54
+ function normalizeSessionCollection(value) {
55
+ const unwrapped = unwrapDriverResult(value);
56
+ if (isDriverResult(unwrapped)) return unwrapped;
57
+ if (Array.isArray(unwrapped)) return unwrapped;
58
+ return Array.isArray(unwrapped?.sessions) ? unwrapped.sessions : [];
59
+ }
60
+
61
+ function normalizeSession(session = {}) {
62
+ const metadata = session.meta || session.metadata || {};
63
+ return {
64
+ ...session,
65
+ sessionId: String(session.sessionId || session.id || ''),
66
+ mtime: session.mtime || session.updatedAt || session.timestamp || Date.now(),
67
+ size: Number(session.size ?? session.fileSize ?? metadata.size ?? 0) || 0,
68
+ gitBranch: session.gitBranch || metadata.gitBranch || null,
69
+ firstMessage: session.firstMessage || session.preview || session.summary || metadata.firstMessage || null
70
+ };
71
+ }
72
+
73
+ function reportDriverFailure(result) {
74
+ if (!isDriverResult(result)) return;
75
+ const message = result.error || `会话操作 ${result.operation || 'unknown'} 不可用`;
76
+ console.log(chalk.yellow(`\n[WARN] ${message}\n`));
77
+ }
11
78
 
12
79
  /**
13
80
  * 列出会话
14
81
  */
15
- async function listSessions(config, limit = null) {
16
- const maxSessions = limit || config.maxDisplaySessions;
82
+ async function listSessions(config = {}, limit = null, options = {}) {
83
+ const maxSessions = limit || config.maxDisplaySessions || 15;
17
84
  const spinner = ora('加载会话列表...').start();
85
+ const result = await invokeSessionOperation(
86
+ config,
87
+ 'listSessions',
88
+ [config.currentProject, { config }],
89
+ options
90
+ );
91
+ const collection = normalizeSessionCollection(result);
92
+
93
+ if (isDriverResult(collection)) {
94
+ spinner.stop();
95
+ spinner.clear();
96
+ return collection;
97
+ }
18
98
 
19
- const sessions = getAllSessions(config).slice(0, maxSessions);
20
-
99
+ const sessions = collection.slice(0, maxSessions).map(normalizeSession);
21
100
  if (sessions.length === 0) {
22
101
  spinner.fail('暂无会话记录');
23
102
  return [];
@@ -25,22 +104,15 @@ async function listSessions(config, limit = null) {
25
104
 
26
105
  spinner.text = '解析会话信息...';
27
106
 
28
- // 加载别名
29
107
  const aliases = loadAliases();
30
-
31
108
  const choices = sessions.map((session, index) => {
32
- const info = parseSessionInfoFast(session.filePath);
33
109
  const time = formatTime(session.mtime);
34
110
  const size = formatSize(session.size);
35
- const alias = aliases[session.sessionId];
111
+ const alias = session.alias || aliases[session.sessionId];
36
112
 
37
- // 构建显示名称 - 清爽的单行布局
38
113
  let displayName = '';
39
-
40
- // 格式:序号. [别名] 时间 │ 大小 │ 分支 │ 第一条消息
41
114
  displayName += chalk.bold.white(`${index + 1}. `);
42
115
 
43
- // 如果有别名,优先显示别名
44
116
  if (alias) {
45
117
  displayName += chalk.yellow.bold(`[${alias}] `);
46
118
  }
@@ -48,8 +120,8 @@ async function listSessions(config, limit = null) {
48
120
  displayName += chalk.cyan(`${time.padEnd(10)}`);
49
121
  displayName += chalk.gray(` │ ${size.padEnd(9)}`);
50
122
 
51
- if (info.gitBranch) {
52
- const branchName = info.gitBranch
123
+ if (session.gitBranch) {
124
+ const branchName = session.gitBranch
53
125
  .replace('feature/', '')
54
126
  .replace('feat/', '')
55
127
  .replace('fix/', '')
@@ -59,23 +131,21 @@ async function listSessions(config, limit = null) {
59
131
  displayName += chalk.gray(` │ ${''.padEnd(25)}`);
60
132
  }
61
133
 
62
- // 只显示第一条用户消息(你说明这个会话是干嘛的)
63
- if (info.firstMessage && info.firstMessage !== 'Warmup') {
64
- const firstMsg = truncate(info.firstMessage, 50);
134
+ if (session.firstMessage && session.firstMessage !== 'Warmup') {
135
+ const firstMsg = truncate(String(session.firstMessage), 50);
65
136
  displayName += chalk.gray(' │ ') + chalk.white(firstMsg);
66
137
  }
67
138
 
68
139
  return {
69
140
  name: displayName,
70
141
  value: session.sessionId,
71
- short: alias ? `${alias} (${session.sessionId.substring(0, 8)})` : `会话 ${session.sessionId.substring(0, 8)}`,
142
+ short: alias ? `${alias} (${session.sessionId.substring(0, 8)})` : `会话 ${session.sessionId.substring(0, 8)}`
72
143
  };
73
144
  });
74
145
 
75
146
  spinner.stop();
76
147
  spinner.clear();
77
148
 
78
- // 清屏并重新显示,避免之前的输出干扰
79
149
  console.clear();
80
150
  console.log(chalk.green(`\n[NEW] 找到 ${sessions.length} 个会话\n`));
81
151
 
@@ -85,12 +155,24 @@ async function listSessions(config, limit = null) {
85
155
  /**
86
156
  * 列出跨项目的最近会话
87
157
  */
88
- async function listRecentSessionsAcrossProjects(config, limit = null) {
89
- const maxSessions = limit || 15; // 默认显示15条最新对话
158
+ async function listRecentSessionsAcrossProjects(config = {}, limit = null, options = {}) {
159
+ const maxSessions = limit || 15;
90
160
  const spinner = ora('加载最新对话...').start();
161
+ const result = await invokeSessionOperation(
162
+ config,
163
+ 'recent',
164
+ [maxSessions, { config }],
165
+ options
166
+ );
167
+ const collection = normalizeSessionCollection(result);
168
+
169
+ if (isDriverResult(collection)) {
170
+ spinner.stop();
171
+ spinner.clear();
172
+ return collection;
173
+ }
91
174
 
92
- const sessions = await getRecentSessions(config, maxSessions);
93
-
175
+ const sessions = collection.slice(0, maxSessions).map(normalizeSession);
94
176
  if (sessions.length === 0) {
95
177
  spinner.fail('暂无会话记录');
96
178
  return [];
@@ -98,22 +180,18 @@ async function listRecentSessionsAcrossProjects(config, limit = null) {
98
180
 
99
181
  spinner.text = '解析会话信息...';
100
182
 
183
+ const aliases = loadAliases();
101
184
  const choices = sessions.map((session, index) => {
102
185
  const time = formatTime(session.mtime);
103
186
  const size = formatSize(session.size);
104
- const alias = session.alias;
187
+ const alias = session.alias || aliases[session.sessionId];
105
188
 
106
- // 构建显示名称 - 清爽的单行布局
107
189
  let displayName = '';
108
-
109
- // 格式:序号. [项目名] [别名] 时间 │ 大小 │ 分支 │ 第一条消息
110
190
  displayName += chalk.bold.white(`${index + 1}. `);
111
191
 
112
- // 项目名(高亮显示)
113
- const projectName = session.projectDisplayName || session.projectName;
192
+ const projectName = session.projectDisplayName || session.projectName || '未知项目';
114
193
  displayName += chalk.magenta.bold(`[${projectName}] `);
115
194
 
116
- // 如果有别名,显示别名
117
195
  if (alias) {
118
196
  displayName += chalk.yellow.bold(`[${alias}] `);
119
197
  }
@@ -132,23 +210,21 @@ async function listRecentSessionsAcrossProjects(config, limit = null) {
132
210
  displayName += chalk.gray(` │ ${''.padEnd(25)}`);
133
211
  }
134
212
 
135
- // 只显示第一条用户消息
136
213
  if (session.firstMessage && session.firstMessage !== 'Warmup') {
137
- const firstMsg = truncate(session.firstMessage, 50);
214
+ const firstMsg = truncate(String(session.firstMessage), 50);
138
215
  displayName += chalk.gray(' │ ') + chalk.white(firstMsg);
139
216
  }
140
217
 
141
218
  return {
142
219
  name: displayName,
143
220
  value: { sessionId: session.sessionId, projectName: session.projectName },
144
- short: alias ? `${alias} (${session.sessionId.substring(0, 8)})` : `会话 ${session.sessionId.substring(0, 8)}`,
221
+ short: alias ? `${alias} (${session.sessionId.substring(0, 8)})` : `会话 ${session.sessionId.substring(0, 8)}`
145
222
  };
146
223
  });
147
224
 
148
225
  spinner.stop();
149
226
  spinner.clear();
150
227
 
151
- // 清屏并重新显示,避免之前的输出干扰
152
228
  console.clear();
153
229
  console.log(chalk.green(`\n[NEW] 找到 ${sessions.length} 个最新对话(跨所有项目)\n`));
154
230
 
@@ -158,22 +234,25 @@ async function listRecentSessionsAcrossProjects(config, limit = null) {
158
234
  /**
159
235
  * 处理列出会话
160
236
  */
161
- async function handleList(config, switchProjectCallback, crossProject = false) {
237
+ async function handleList(config, switchProjectCallback, crossProject = false, options = {}) {
162
238
  while (true) {
163
- // 根据模式选择不同的列表函数
164
- const choices = crossProject
165
- ? await listRecentSessionsAcrossProjects(config)
166
- : await listSessions(config);
239
+ const result = crossProject
240
+ ? await listRecentSessionsAcrossProjects(config, null, options)
241
+ : await listSessions(config, null, options);
242
+
243
+ if (isDriverResult(result)) {
244
+ reportDriverFailure(result);
245
+ return;
246
+ }
167
247
 
248
+ const choices = Array.isArray(result) ? result : [];
168
249
  if (choices.length === 0) {
169
250
  return;
170
251
  }
171
252
 
172
- // 添加操作选项
173
253
  choices.push(new inquirer.Separator(chalk.gray('─'.repeat(50))));
174
254
  choices.push({ name: chalk.blue('[<-] 返回主菜单'), value: 'back' });
175
255
 
176
- // 跨项目模式不显示切换项目选项(因为已经是跨所有项目了)
177
256
  if (!crossProject) {
178
257
  choices.push({ name: chalk.magenta('[SWITCH] 切换项目'), value: 'switch' });
179
258
  }
@@ -187,36 +266,35 @@ async function handleList(config, switchProjectCallback, crossProject = false) {
187
266
  if (selected === 'switch') {
188
267
  const switched = await switchProjectCallback();
189
268
  if (!switched) {
190
- return; // 用户取消切换,返回主菜单
269
+ return;
191
270
  }
192
- continue; // 切换后重新加载列表
271
+ continue;
193
272
  }
194
273
 
195
- // 跨项目模式:selected 是 { sessionId, projectName }
196
- // 单项目模式:selected 是 sessionId
197
274
  let sessionId, projectName;
198
275
  if (crossProject) {
199
276
  sessionId = selected.sessionId;
200
277
  projectName = selected.projectName;
201
- // 切换到该项目
202
278
  config.currentProject = projectName;
203
279
  } else {
204
280
  sessionId = selected;
205
281
  }
206
282
 
207
- // 询问是否 fork
208
283
  const action = await promptForkConfirm();
209
284
 
210
285
  if (action === 'back') {
211
- continue; // 返回列表重新选择
286
+ continue;
212
287
  }
213
288
 
214
289
  const fork = action === 'fork';
215
- await resumeSession(config, sessionId, fork);
290
+ await resumeSession(config, sessionId, fork, {
291
+ ...options,
292
+ platform: options.platform || config.currentCliType || ''
293
+ });
216
294
  }
217
295
  }
218
296
 
219
297
  module.exports = {
220
298
  listSessions,
221
- handleList,
299
+ listRecentSessionsAcrossProjects,
222
300
  };
@@ -6,23 +6,40 @@ const { PATHS } = require('../config/paths');
6
6
  const { normalizePlatformKey } = require('../shared/platforms');
7
7
 
8
8
  const LOGS_DIR = PATHS.logs;
9
+ const UI_LOG_FILE = 'cc-tool-out.log';
9
10
 
10
- const LOG_FILES = {
11
- ui: 'cc-tool-out.log',
12
- claude: 'claude-proxy.log',
13
- codex: 'codex-proxy.log',
14
- gemini: 'gemini-proxy.log',
15
- opencode: 'opencode-proxy.log'
16
- };
17
- const LOG_ALIASES = {
18
- omp: 'ui'
19
- };
20
- const LOG_ALIAS_NOTES = {
21
- omp: 'OMP 受管 provider 配置没有独立请求代理日志,相关活动记录在 UI/server 日志中。'
22
- };
11
+ function getCommandRegistry() {
12
+ return require('./platform-command-registry').createPlatformCommandRegistry();
13
+ }
14
+
15
+ function getLogDefinitions() {
16
+ return getCommandRegistry().list().filter(platform => platform.logFile || platform.logAliases?.length);
17
+ }
18
+
19
+ function getLogFiles() {
20
+ return {
21
+ ui: UI_LOG_FILE,
22
+ ...Object.fromEntries(getLogDefinitions()
23
+ .filter(platform => platform.logFile && !(platform.logAliases || []).includes('ui'))
24
+ .map(platform => [platform.key, platform.logFile]))
25
+ };
26
+ }
27
+
28
+ function getLogAliases() {
29
+ return Object.fromEntries(getLogDefinitions()
30
+ .flatMap(platform => (platform.logAliases || []).map(alias => [platform.key, alias])));
31
+ }
32
+
33
+ function getLogAliasNotes() {
34
+ return Object.fromEntries(getLogDefinitions()
35
+ .filter(platform => platform.logNote)
36
+ .map(platform => [platform.key, platform.logNote]));
37
+ }
23
38
 
24
39
  function getSupportedLogTypes() {
25
- return [...Object.keys(LOG_FILES), 'omp'];
40
+ const files = getLogFiles();
41
+ const platformKeys = getLogDefinitions().map(platform => platform.key);
42
+ return [...new Set([...Object.keys(files), ...platformKeys])];
26
43
  }
27
44
 
28
45
  function resolveLogType(type) {
@@ -30,14 +47,17 @@ function resolveLogType(type) {
30
47
  if (!normalized) {
31
48
  return { requestedType: type, type: null, file: null, note: null };
32
49
  }
33
- const aliasTarget = LOG_ALIASES[normalized];
50
+ const aliases = getLogAliases();
51
+ const files = getLogFiles();
52
+ const notes = getLogAliasNotes();
53
+ const aliasTarget = aliases[normalized];
34
54
  const resolvedType = aliasTarget || normalized;
35
55
  return {
36
56
  requestedType: type,
37
57
  normalizedType: normalized,
38
58
  type: resolvedType,
39
- file: LOG_FILES[resolvedType] || null,
40
- note: LOG_ALIAS_NOTES[normalized] || null
59
+ file: files[resolvedType] || null,
60
+ note: notes[normalized] || null
41
61
  };
42
62
  }
43
63
 
@@ -113,7 +133,7 @@ function showAllLogs(lines, follow) {
113
133
  const allLogs = [];
114
134
 
115
135
  // 读取所有日志文件
116
- Object.entries(LOG_FILES).forEach(([type, filename]) => {
136
+ Object.entries(getLogFiles()).forEach(([type, filename]) => {
117
137
  const logPath = path.join(LOGS_DIR, filename);
118
138
  if (fs.existsSync(logPath)) {
119
139
  try {
@@ -241,7 +261,7 @@ function clearLogs(type) {
241
261
  console.log(chalk.cyan('\n[DEL] 清空所有日志...\n'));
242
262
 
243
263
  let cleared = 0;
244
- Object.entries(LOG_FILES).forEach(([logType, filename]) => {
264
+ Object.entries(getLogFiles()).forEach(([logType, filename]) => {
245
265
  const logPath = path.join(LOGS_DIR, filename);
246
266
  if (fs.existsSync(logPath)) {
247
267
  try {
@@ -314,14 +334,11 @@ function extractTimestamp(line) {
314
334
  * 获取类型颜色
315
335
  */
316
336
  function getTypeColor(type) {
317
- const colors = {
318
- ui: chalk.blue,
319
- claude: chalk.green,
320
- codex: chalk.cyan,
321
- gemini: chalk.magenta,
322
- opencode: chalk.yellow
323
- };
324
- return colors[type] || chalk.gray;
337
+ if (type === 'ui') return chalk.blue;
338
+ const normalized = normalizePlatformKey(type);
339
+ const platform = getLogDefinitions().find(item => item.key === normalized);
340
+ const color = platform?.logColor || platform?.terminalColor;
341
+ return color && typeof chalk[color] === 'function' ? chalk[color] : chalk.gray;
325
342
  }
326
343
 
327
344
  module.exports = {
@@ -0,0 +1,78 @@
1
+ 'use strict';
2
+
3
+ const { normalizePlatformKey } = require('../shared/platforms');
4
+ const platformRuntime = require('../platforms/runtime');
5
+
6
+ function normalizePlatformDefinition(platform) {
7
+ if (!platform || typeof platform !== 'object' || !platform.key) return null;
8
+ return platform;
9
+ }
10
+
11
+ function createPlatformCommandRegistry({ registry = platformRuntime.getPlatformRegistry(), platforms } = {}) {
12
+ const source = Array.isArray(platforms)
13
+ ? platforms
14
+ : (registry && typeof registry.list === 'function' ? registry.list({ enabledOnly: true }) : []);
15
+ const definitions = new Map(
16
+ source
17
+ .map(normalizePlatformDefinition)
18
+ .filter(Boolean)
19
+ .map(platform => [normalizePlatformKey(platform.key), platform])
20
+ );
21
+ const commands = new Map(
22
+ [...definitions.values()]
23
+ .filter(platform => platform.command)
24
+ .map(platform => [normalizePlatformKey(platform.command), platform])
25
+ );
26
+
27
+ const list = () => [...definitions.values()];
28
+ const hasCapability = (platform, capability) => {
29
+ const value = platform?.capabilities?.[capability];
30
+ return value !== undefined && value !== null && value !== 'unsupported';
31
+ };
32
+ return {
33
+ resolve(key) {
34
+ const normalized = normalizePlatformKey(key);
35
+ return definitions.get(normalized) || commands.get(normalized) || null;
36
+ },
37
+ platformKeys() {
38
+ return list().map(platform => platform.key);
39
+ },
40
+ list() {
41
+ return list().map(platform => ({ ...platform }));
42
+ },
43
+ logTypes() {
44
+ return list()
45
+ .filter(platform => platform.logFile || platform.logAliases?.length)
46
+ .map(platform => platform.key);
47
+ },
48
+ portKeys() {
49
+ return list()
50
+ .filter(platform => platform.portKey && platform.defaultPort)
51
+ .map(platform => platform.portKey);
52
+ },
53
+ statsTypes() {
54
+ return list().filter(platform => hasCapability(platform, 'statistics')).map(platform => platform.key);
55
+ },
56
+ selectableTypes() {
57
+ return list()
58
+ .filter(platform => platform.cliSelectable !== false)
59
+ .map(platform => platform.key);
60
+ },
61
+ helpEntries() {
62
+ return list().map(platform => ({
63
+ key: platform.key,
64
+ command: platform.command || platform.key,
65
+ label: platform.helpLabel || platform.label || platform.title || platform.key,
66
+ proxyLabel: platform.proxyLabels?.proxyLabel || '代理',
67
+ proxy: hasCapability(platform, 'proxy'),
68
+ log: Boolean(platform.logFile || platform.logAliases?.length),
69
+ stats: hasCapability(platform, 'statistics'),
70
+ portKey: platform.portKey || null
71
+ }));
72
+ }
73
+ };
74
+ }
75
+
76
+ module.exports = {
77
+ createPlatformCommandRegistry
78
+ };
@@ -1,8 +1,12 @@
1
1
  const chalk = require('chalk');
2
- const inquirer = require('inquirer');
3
- const { installPlugin, uninstallPlugin, updatePlugin, updateAllPlugins } = require('../plugins/plugin-installer');
2
+ function getInquirer() {
3
+ return require('inquirer');
4
+ }
5
+
6
+ function getPluginInstaller() {
7
+ return require('../plugins/plugin-installer');
8
+ }
4
9
  const { listPlugins, getPlugin, updatePlugin: updatePluginRegistry } = require('../plugins/registry');
5
- const { createPluginContext } = require('../plugins/plugin-api');
6
10
  const fs = require('fs');
7
11
  const path = require('path');
8
12
  const { INSTALLED_DIR } = require('../plugins/constants');
@@ -70,6 +74,7 @@ async function handleInstall(args) {
70
74
  }
71
75
 
72
76
  console.log(chalk.cyan(`\n[PKG] Installing plugin from ${url}...\n`));
77
+ const { installPlugin } = getPluginInstaller();
73
78
 
74
79
  const result = await installPlugin(url);
75
80
 
@@ -111,8 +116,7 @@ async function handleRemove(args) {
111
116
  process.exit(1);
112
117
  }
113
118
 
114
- // Confirm uninstall
115
- const { confirmed } = await inquirer.prompt([
119
+ const { confirmed } = await getInquirer().prompt([
116
120
  {
117
121
  type: 'confirm',
118
122
  name: 'confirmed',
@@ -126,6 +130,7 @@ async function handleRemove(args) {
126
130
  return;
127
131
  }
128
132
 
133
+ const { uninstallPlugin } = getPluginInstaller();
129
134
  console.log(chalk.cyan(`\n[DEL] Uninstalling plugin "${name}"...\n`));
130
135
 
131
136
  const result = uninstallPlugin(name);
@@ -477,6 +482,7 @@ async function handleUpdate(args) {
477
482
  console.log(chalk.gray(' ctx plugin update --all\n'));
478
483
  process.exit(1);
479
484
  }
485
+ const { updatePlugin, updateAllPlugins } = getPluginInstaller();
480
486
 
481
487
  if (isUpdateAll) {
482
488
  console.log(chalk.cyan('\n[SYNC] Updating all plugins...\n'));