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
@@ -2,13 +2,10 @@ const http = require('http');
2
2
  const https = require('https');
3
3
  const crypto = require('crypto');
4
4
  const { HttpsProxyAgent } = require('https-proxy-agent');
5
- const { broadcastLog } = require('../websocket-server');
6
- const { recordRequest } = require('./statistics-service');
7
- const { recordSuccess, recordFailure } = require('./channel-health');
8
- const { publishUsageLog, publishFailureLog } = require('./proxy-log-helper');
9
- const { createDecodedStream } = require('./response-decoder');
10
- const { parseNonStreamingUsage } = require('./base/response-usage-parser');
11
- const { convertClaudeToOpenCodePayload } = require('./opencode-gateway-converter');
5
+ const { recordSuccess, recordFailure } = require('../../../server/services/channel-health');
6
+ const { createDecodedStream } = require('../../../server/services/response-decoder');
7
+ const { parseNonStreamingUsage } = require('../../../shared/response-usage-parser');
8
+ const { convertClaudeToOpenCodePayload } = require('../opencode/gateway-converter');
12
9
 
13
10
  const REQUEST_TIMEOUT_MS = 120000;
14
11
 
@@ -299,18 +296,6 @@ function buildClaudeUsageFromTokens(tokens = {}) {
299
296
  };
300
297
  }
301
298
 
302
- function buildPublishTokensFromClaudeUsage(usage = {}) {
303
- return {
304
- input: Number(usage.input_tokens || 0),
305
- output: Number(usage.output_tokens || 0),
306
- cacheCreation: Number(usage.cache_creation_input_tokens || 0),
307
- cacheRead: Number(usage.cache_read_input_tokens || 0),
308
- cached: Number(usage.cache_read_input_tokens || 0),
309
- reasoning: 0,
310
- total: 0
311
- };
312
- }
313
-
314
299
  function mapResponsesStopReason(response, hasToolUse) {
315
300
  if (hasToolUse) return 'tool_use';
316
301
 
@@ -1086,31 +1071,8 @@ async function relayChatStreamAsClaude(upstreamResponse, res, fallbackModel = ''
1086
1071
  });
1087
1072
  }
1088
1073
 
1089
- function publishClaudeGatewayUsage(metadata, message, calculateCost) {
1090
- return publishUsageLog({
1091
- source: 'claude',
1092
- metadata,
1093
- model: message?.model || '',
1094
- tokens: buildPublishTokensFromClaudeUsage(message?.usage || {}),
1095
- calculateCost,
1096
- broadcastLog,
1097
- recordRequest,
1098
- recordSuccess,
1099
- allowBroadcast: true
1100
- });
1101
- }
1102
-
1103
- function reportGatewayFailure({ channel, metadata, res, statusCode, message, error, stage, onDone }) {
1074
+ function reportGatewayFailure({ channel, res, statusCode, message, error, onDone }) {
1104
1075
  recordFailure(channel.id, 'claude', error || new Error(message));
1105
- publishFailureLog({
1106
- source: 'claude',
1107
- metadata,
1108
- message,
1109
- error,
1110
- statusCode,
1111
- stage,
1112
- broadcastLog
1113
- });
1114
1076
  sendAnthropicError(res, statusCode, message);
1115
1077
  if (typeof onDone === 'function') {
1116
1078
  onDone();
@@ -1118,7 +1080,7 @@ function reportGatewayFailure({ channel, metadata, res, statusCode, message, err
1118
1080
  return true;
1119
1081
  }
1120
1082
 
1121
- async function handleClaudeOpenAiGatewayRequest({ req, res, channel, effectiveKey, calculateCost, onDone }) {
1083
+ async function handleClaudeOpenAiGatewayRequest({ req, res, channel, effectiveKey, onDone }) {
1122
1084
  const pathname = getRequestPathname(req?.url || '');
1123
1085
  if (!isClaudeMessagesPath(pathname)) {
1124
1086
  return false;
@@ -1132,21 +1094,12 @@ async function handleClaudeOpenAiGatewayRequest({ req, res, channel, effectiveKe
1132
1094
  return true;
1133
1095
  }
1134
1096
 
1135
- const requestId = `claude-openai-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
1136
- const startTime = Date.now();
1137
1097
  const targetApi = resolveClaudeGatewayTargetApi(channel);
1138
1098
  const converted = convertClaudeToOpenCodePayload({
1139
1099
  payload: req.body,
1140
1100
  options: { targetApi }
1141
1101
  });
1142
1102
  const upstreamModel = converted?.requestBody?.model || req.body.model || '';
1143
- const metadata = {
1144
- id: requestId,
1145
- channel: channel?.name,
1146
- channelId: channel?.id,
1147
- startTime,
1148
- requestModel: upstreamModel
1149
- };
1150
1103
  const wantsStream = req.body.stream === true;
1151
1104
  const targetUrl = buildOpenAiTargetUrl(channel?.baseUrl || '', converted.endpoint || '/v1/responses');
1152
1105
  const headers = buildOpenAiHeaders(effectiveKey, {
@@ -1171,12 +1124,10 @@ async function handleClaudeOpenAiGatewayRequest({ req, res, channel, effectiveKe
1171
1124
  const upstreamMessage = parsedError?.error?.message || parsedError?.message || rawBody || `HTTP ${upstream.statusCode}`;
1172
1125
  return reportGatewayFailure({
1173
1126
  channel,
1174
- metadata,
1175
1127
  res,
1176
1128
  statusCode: upstream.statusCode,
1177
1129
  message: String(upstreamMessage).slice(0, 1000),
1178
1130
  error: new Error(String(upstreamMessage).slice(0, 200)),
1179
- stage: 'openai_gateway_upstream',
1180
1131
  onDone
1181
1132
  });
1182
1133
  }
@@ -1185,9 +1136,7 @@ async function handleClaudeOpenAiGatewayRequest({ req, res, channel, effectiveKe
1185
1136
  ? await relayChatStreamAsClaude(upstream.response, res, upstreamModel)
1186
1137
  : await relayResponsesStreamAsClaude(upstream.response, res, upstreamModel);
1187
1138
 
1188
- if (message) {
1189
- publishClaudeGatewayUsage(metadata, message, calculateCost);
1190
- }
1139
+ recordSuccess(channel.id, 'claude');
1191
1140
  if (typeof onDone === 'function') {
1192
1141
  onDone();
1193
1142
  }
@@ -1207,12 +1156,10 @@ async function handleClaudeOpenAiGatewayRequest({ req, res, channel, effectiveKe
1207
1156
  const upstreamMessage = parsedBody?.error?.message || parsedBody?.message || upstream.rawBody || `HTTP ${upstream.statusCode}`;
1208
1157
  return reportGatewayFailure({
1209
1158
  channel,
1210
- metadata,
1211
1159
  res,
1212
1160
  statusCode: upstream.statusCode,
1213
1161
  message: String(upstreamMessage).slice(0, 1000),
1214
1162
  error: new Error(String(upstreamMessage).slice(0, 200)),
1215
- stage: 'openai_gateway_upstream',
1216
1163
  onDone
1217
1164
  });
1218
1165
  }
@@ -1220,12 +1167,10 @@ async function handleClaudeOpenAiGatewayRequest({ req, res, channel, effectiveKe
1220
1167
  if (!parsedBody || typeof parsedBody !== 'object') {
1221
1168
  return reportGatewayFailure({
1222
1169
  channel,
1223
- metadata,
1224
1170
  res,
1225
1171
  statusCode: 502,
1226
1172
  message: 'Invalid OpenAI gateway response',
1227
1173
  error: new Error('Invalid OpenAI gateway response'),
1228
- stage: 'openai_gateway_parse',
1229
1174
  onDone
1230
1175
  });
1231
1176
  }
@@ -1235,7 +1180,7 @@ async function handleClaudeOpenAiGatewayRequest({ req, res, channel, effectiveKe
1235
1180
  : buildClaudeMessageFromResponses(parsedBody, upstreamModel);
1236
1181
 
1237
1182
  res.json(message);
1238
- publishClaudeGatewayUsage(metadata, message, calculateCost);
1183
+ recordSuccess(channel.id, 'claude');
1239
1184
  if (typeof onDone === 'function') {
1240
1185
  onDone();
1241
1186
  }
@@ -1243,12 +1188,10 @@ async function handleClaudeOpenAiGatewayRequest({ req, res, channel, effectiveKe
1243
1188
  } catch (error) {
1244
1189
  return reportGatewayFailure({
1245
1190
  channel,
1246
- metadata,
1247
1191
  res,
1248
1192
  statusCode: 502,
1249
1193
  message: `OpenAI gateway network error: ${error.message}`,
1250
1194
  error,
1251
- stage: 'openai_gateway_network',
1252
1195
  onDone
1253
1196
  });
1254
1197
  }
@@ -0,0 +1,21 @@
1
+ 'use strict';
2
+
3
+ const mcpFormat = require('../../../shared/mcp-format');
4
+ const {
5
+ createProjectAdapter,
6
+ createJsonMcpHandlers
7
+ } = require('../../../shared/project-config');
8
+
9
+ function createAdapter({ manifest, fsImpl } = {}) {
10
+ const relativePath = manifest?.projectResources?.mcp?.path;
11
+ const mcpHandlers = createJsonMcpHandlers({
12
+ relativePath,
13
+ format: manifest?.projectResources?.mcp?.format || 'claude-json',
14
+ toNative: mcpFormat.extractServerSpec,
15
+ fromNative: value => ({ ...value }),
16
+ fsImpl
17
+ });
18
+ return createProjectAdapter({ manifest, fsImpl, mcpHandlers });
19
+ }
20
+
21
+ module.exports = { createAdapter };
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { createProjectsDriver } = require('../../../shared/driver-factories/projects');
6
+
7
+ function createProject({ projectName, projectPath } = {}) {
8
+ if (!projectName || !projectPath) {
9
+ const error = new Error('projectName and projectPath are required');
10
+ error.statusCode = 400;
11
+ throw error;
12
+ }
13
+ if (!fs.existsSync(projectPath)) {
14
+ const error = new Error('项目路径不存在');
15
+ error.statusCode = 400;
16
+ throw error;
17
+ }
18
+ if (!fs.statSync(projectPath).isDirectory()) {
19
+ const error = new Error('项目路径必须是一个目录');
20
+ error.statusCode = 400;
21
+ throw error;
22
+ }
23
+
24
+ const claudeDir = path.join(projectPath, '.claude');
25
+ const sessionsDir = path.join(claudeDir, 'sessions');
26
+ if (fs.existsSync(claudeDir)) {
27
+ const error = new Error('该项目已经初始化过 Claude Code');
28
+ error.statusCode = 400;
29
+ throw error;
30
+ }
31
+
32
+ fs.mkdirSync(sessionsDir, { recursive: true });
33
+ const projectConfig = {
34
+ name: projectName,
35
+ createdAt: new Date().toISOString(),
36
+ version: '1.0'
37
+ };
38
+ fs.writeFileSync(
39
+ path.join(claudeDir, 'project.json'),
40
+ JSON.stringify(projectConfig, null, 2),
41
+ 'utf8'
42
+ );
43
+
44
+ return { success: true, projectName, projectPath, claudeDir };
45
+ }
46
+
47
+ function createDriver(context = {}) {
48
+ return createProjectsDriver({
49
+ ...context,
50
+ platform: 'claude',
51
+ servicePath: './claude/sessions-implementation',
52
+ localServicePath: '../../platforms/drivers/claude/sessions-implementation',
53
+ createProject,
54
+ onSuccess: operation => {
55
+ if (['saveProjectOrder', 'createProject', 'deleteProject'].includes(operation)) {
56
+ context.sessionHistoryIndex?.invalidateSource('claude');
57
+ }
58
+ }
59
+ });
60
+ }
61
+
62
+ module.exports = { createDriver };
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const { createPromptDriver } = require('../../../shared/driver-factories/prompts');
4
+
5
+ function createDriver(context = {}) {
6
+ return createPromptDriver({ ...context, platform: 'claude' });
7
+ }
8
+
9
+ module.exports = { createDriver };
@@ -6,29 +6,20 @@ const path = require('path');
6
6
  const os = require('os');
7
7
  const chalk = require('chalk');
8
8
  const { HttpsProxyAgent } = require('https-proxy-agent');
9
- const { allocateChannel, releaseChannel, getSchedulerState } = require('./services/channel-scheduler');
10
- const { recordSuccess, recordFailure } = require('./services/channel-health');
11
- const { broadcastLog, broadcastSchedulerState } = require('./websocket-server');
12
- const { loadConfig } = require('../config/loader');
13
- const DEFAULT_CONFIG = require('../config/default');
14
- const { resolveModelPricing } = require('./utils/pricing');
15
- const { recordRequest } = require('./services/statistics-service');
16
- const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('./services/proxy-runtime');
17
- const { createDecodedStream } = require('./services/response-decoder');
18
- const eventBus = require('../plugins/event-bus');
19
- const { getEffectiveApiKey } = require('./services/channels');
20
- const { persistProxyRequestSnapshot, persistClaudeRequestTemplate } = require('./services/request-logger');
21
- const { publishUsageLog, publishFailureLog } = require('./services/proxy-log-helper');
22
- const { redirectModel, normalizeGatewaySourceType } = require('./services/base/proxy-utils');
23
- const { parseSSEUsage, parseNonStreamingUsage, mergeUsageIntoTokenData, createTokenData } = require('./services/base/response-usage-parser');
9
+ const { allocateChannel, releaseChannel, getSchedulerState } = require('../../../server/services/channel-scheduler');
10
+ const { recordSuccess, recordFailure } = require('../../../server/services/channel-health');
11
+ const { broadcastSchedulerState } = require('../../../server/websocket-server');
12
+ const { loadConfig } = require('../../../config/loader');
13
+ const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('../../../server/services/proxy-runtime');
14
+ const eventBus = require('../../../plugins/event-bus');
24
15
  const {
25
- createClaudeStreamRecoveryState,
26
- mergeClaudeStreamEvent,
27
- buildAssistantMessageFromStreamState,
28
- recoverClaudeUsageViaCountTokens
29
- } = require('./services/claude-token-recovery');
30
- const { handleClaudeOpenAiGatewayRequest } = require('./services/claude-openai-gateway');
31
- const { attachServerShutdownHandling, expediteServerShutdown } = require('./services/server-shutdown');
16
+ getEffectiveApiKey,
17
+ getClaudeProxyExcludedChannelIds = () => []
18
+ } = require('./channels-implementation');
19
+ const { persistProxyRequestSnapshot, persistClaudeRequestTemplate } = require('../../../server/services/request-logger');
20
+ const { redirectModel, normalizeGatewaySourceType } = require('../../../shared/proxy-utils');
21
+ const { handleClaudeOpenAiGatewayRequest } = require('./openai-gateway');
22
+ const { attachServerShutdownHandling, expediteServerShutdown } = require('../../../server/services/server-shutdown');
32
23
 
33
24
  let proxyServer = null;
34
25
  let proxyApp = null;
@@ -41,33 +32,6 @@ const requestMetadata = new Map();
41
32
  // 格式: { channelId: { "originalModel": "redirectedModel", ... } }
42
33
  const printedRedirectCache = new Map();
43
34
 
44
- const CLAUDE_BASE_PRICING = DEFAULT_CONFIG.pricing.claude;
45
- const ONE_MILLION = 1000000;
46
-
47
- // detectModelTier and redirectModel imported from services/base/proxy-utils
48
-
49
- /**
50
- * 计算请求成本
51
- * @param {string} model - 模型名称
52
- * @param {object} tokens - token 使用情况
53
- * @returns {number} 成本(美元)
54
- */
55
- function calculateCost(model, tokens) {
56
- const pricing = resolveModelPricing('claude', model, {}, CLAUDE_BASE_PRICING);
57
-
58
- const inputRate = typeof pricing.input === 'number' ? pricing.input : CLAUDE_BASE_PRICING.input;
59
- const outputRate = typeof pricing.output === 'number' ? pricing.output : CLAUDE_BASE_PRICING.output;
60
- const cacheCreationRate = typeof pricing.cacheCreation === 'number' ? pricing.cacheCreation : CLAUDE_BASE_PRICING.cacheCreation;
61
- const cacheReadRate = typeof pricing.cacheRead === 'number' ? pricing.cacheRead : CLAUDE_BASE_PRICING.cacheRead;
62
-
63
- return (
64
- (tokens.input || 0) * inputRate / ONE_MILLION +
65
- (tokens.output || 0) * outputRate / ONE_MILLION +
66
- (tokens.cacheCreation || 0) * cacheCreationRate / ONE_MILLION +
67
- (tokens.cacheRead || 0) * cacheReadRate / ONE_MILLION
68
- );
69
- }
70
-
71
35
  const jsonBodyParser = express.json({
72
36
  limit: '100mb',
73
37
  verify: (req, res, buf) => {
@@ -179,16 +143,6 @@ function buildClaudeRequestSummary(req, sessionId = null) {
179
143
  };
180
144
  }
181
145
 
182
- function clearTokenDataUsage(tokenData) {
183
- tokenData.inputTokens = 0;
184
- tokenData.outputTokens = 0;
185
- tokenData.cacheCreation = 0;
186
- tokenData.cacheRead = 0;
187
- tokenData.cachedTokens = 0;
188
- tokenData.reasoningTokens = 0;
189
- tokenData.totalTokens = 0;
190
- }
191
-
192
146
  async function startProxyServer(options = {}) {
193
147
  const preserveStartTime = options.preserveStartTime || false;
194
148
 
@@ -196,6 +150,13 @@ async function startProxyServer(options = {}) {
196
150
  console.log('Proxy server already running on port', currentPort);
197
151
  return { success: true, port: currentPort };
198
152
  }
153
+ const excludedChannelIds = getClaudeProxyExcludedChannelIds();
154
+ if (excludedChannelIds.length > 0) {
155
+ const error = new Error('Claude dynamic proxy supports API-key channels only; disable OAuth channels first');
156
+ error.code = 'claude_oauth_proxy_unsupported';
157
+ error.statusCode = 409;
158
+ throw error;
159
+ }
199
160
 
200
161
  try {
201
162
  const config = loadConfig();
@@ -254,7 +215,12 @@ async function startProxyServer(options = {}) {
254
215
  const sessionId = extractSessionId(req);
255
216
  const config = loadConfig();
256
217
  const enableSessionBinding = config.enableSessionBinding !== false; // 默认开启
257
- const channel = await allocateChannel({ source: 'claude', sessionId, enableSessionBinding });
218
+ const channel = await allocateChannel({
219
+ source: 'claude',
220
+ sessionId,
221
+ enableSessionBinding,
222
+ excludeChannelIds: getClaudeProxyExcludedChannelIds()
223
+ });
258
224
 
259
225
  // 广播调度状态(请求开始)
260
226
  broadcastSchedulerState('claude', getSchedulerState('claude'));
@@ -279,14 +245,6 @@ async function startProxyServer(options = {}) {
279
245
  const effectiveKey = getEffectiveApiKey(channel);
280
246
  if (!effectiveKey) {
281
247
  release();
282
- publishFailureLog({
283
- source: 'claude',
284
- channel: channel.name,
285
- message: 'API key not configured or expired. Please update your channel key.',
286
- statusCode: 401,
287
- stage: 'preflight',
288
- broadcastLog
289
- });
290
248
  return res.status(401).json({
291
249
  error: 'API key not configured or expired. Please update your channel key.',
292
250
  type: 'authentication_error'
@@ -338,7 +296,6 @@ async function startProxyServer(options = {}) {
338
296
  res,
339
297
  channel,
340
298
  effectiveKey,
341
- calculateCost,
342
299
  onDone: release
343
300
  });
344
301
  if (handled) {
@@ -362,21 +319,6 @@ async function startProxyServer(options = {}) {
362
319
  if (err) {
363
320
  // 记录请求失败
364
321
  recordFailure(channel.id, 'claude', err);
365
- const metadata = requestMetadata.get(req) || {
366
- id: null,
367
- channel: channel.name,
368
- channelId: channel.id,
369
- startTime: Date.now()
370
- };
371
- publishFailureLog({
372
- source: 'claude',
373
- metadata,
374
- message: err.message,
375
- error: err,
376
- statusCode: 502,
377
- stage: 'proxy_web',
378
- broadcastLog
379
- });
380
322
  console.error('Proxy error:', err);
381
323
  if (res && !res.headersSent) {
382
324
  res.status(502).json({
@@ -388,13 +330,6 @@ async function startProxyServer(options = {}) {
388
330
  });
389
331
  } catch (error) {
390
332
  console.error('Channel allocation error:', error);
391
- publishFailureLog({
392
- source: 'claude',
393
- message: error.message || '所有渠道暂时不可用',
394
- statusCode: 503,
395
- stage: 'allocate_channel',
396
- broadcastLog
397
- });
398
333
  if (!res.headersSent) {
399
334
  res.status(503).json({
400
335
  error: error.message || '所有渠道暂时不可用',
@@ -404,6 +339,7 @@ async function startProxyServer(options = {}) {
404
339
  }
405
340
  });
406
341
 
342
+ // 代理响应只负责维护传输健康状态;实时日志和 usage 来自 CLI 原生日志。
407
343
  proxy.on('proxyRes', (proxyRes, req, res) => {
408
344
  const metadata = requestMetadata.get(req);
409
345
  if (!metadata) return;
@@ -413,185 +349,26 @@ async function startProxyServer(options = {}) {
413
349
  return;
414
350
  }
415
351
 
416
- let isResponseClosed = false;
417
-
418
- res.on('close', () => {
419
- isResponseClosed = true;
420
- requestMetadata.delete(req);
421
- });
422
-
352
+ res.on('close', () => requestMetadata.delete(req));
423
353
  res.on('error', (err) => {
424
- isResponseClosed = true;
425
- if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') {
426
- console.error('Response error:', err);
427
- }
354
+ if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') console.error('Response error:', err);
355
+ recordFailure(metadata.channelId, 'claude', err);
428
356
  requestMetadata.delete(req);
429
357
  });
430
358
 
431
- const isSseResponse = proxyRes.headers['content-type']?.includes('text/event-stream');
432
- let buffer = '';
433
- let tokenData = createTokenData();
434
- let usageRecorded = false;
435
- const streamRecoveryState = createClaudeStreamRecoveryState();
436
- const usageObservation = {
437
- sawAnyUsage: false,
438
- sawMessageStartUsage: false,
439
- sawNonInitialUsage: false
440
- };
441
- const parsedStream = createDecodedStream(proxyRes);
442
-
443
- function recordUsageIfReady() {
444
- if (usageRecorded) return false;
445
-
446
- const result = publishUsageLog({
447
- source: 'claude',
448
- metadata,
449
- model: tokenData.model,
450
- tokens: {
451
- input: tokenData.inputTokens,
452
- output: tokenData.outputTokens,
453
- cacheCreation: tokenData.cacheCreation,
454
- cacheRead: tokenData.cacheRead,
455
- cached: tokenData.cachedTokens,
456
- reasoning: tokenData.reasoningTokens,
457
- total: tokenData.totalTokens
458
- },
459
- calculateCost,
460
- broadcastLog,
461
- recordRequest,
462
- recordSuccess,
463
- allowBroadcast: true
464
- });
465
-
466
- if (!result) return false;
467
- usageRecorded = true;
468
- return true;
469
- }
470
-
471
- parsedStream.on('data', (chunk) => {
472
- if (isResponseClosed) return;
473
-
474
- buffer += chunk.toString('utf8');
475
-
476
- if (!isSseResponse) {
477
- return;
478
- }
479
-
480
- const events = buffer.split('\n\n');
481
- buffer = events.pop() || '';
482
-
483
- events.forEach(eventText => {
484
- if (!eventText.trim()) return;
485
-
486
- try {
487
- const lines = eventText.split('\n');
488
- let eventType = '';
489
- let data = '';
490
-
491
- lines.forEach(line => {
492
- if (line.startsWith('event:')) {
493
- eventType = line.substring(6).trim();
494
- } else if (line.startsWith('data:')) {
495
- data = line.substring(5).trim();
496
- }
497
- });
498
-
499
- if (!data || data === '[DONE]') return;
500
-
501
- const parsed = JSON.parse(data);
502
- mergeClaudeStreamEvent(streamRecoveryState, eventType, parsed);
503
- const usage = parseSSEUsage(parsed, eventType);
504
- if (usage.tokens) {
505
- usageObservation.sawAnyUsage = true;
506
- if (eventType === 'message_start') {
507
- usageObservation.sawMessageStartUsage = true;
508
- } else {
509
- usageObservation.sawNonInitialUsage = true;
510
- }
511
- }
512
- mergeUsageIntoTokenData(tokenData, usage);
513
-
514
- if (usage.isDone && (!isSseResponse || usageObservation.sawNonInitialUsage)) {
515
- recordUsageIfReady();
516
- }
517
- } catch (err) {
518
- }
519
- });
520
- });
521
-
522
- const finalize = () => {
523
- if (!isResponseClosed) {
524
- requestMetadata.delete(req);
525
- }
526
- if (typeof req.__releaseChannel === 'function') {
527
- req.__releaseChannel();
359
+ const statusCode = Number(proxyRes.statusCode) || 200;
360
+ proxyRes.on('end', () => {
361
+ if (statusCode >= 400) {
362
+ recordFailure(metadata.channelId, 'claude', new Error(`Claude upstream HTTP ${statusCode}`));
363
+ } else {
364
+ recordSuccess(metadata.channelId, 'claude');
528
365
  }
529
- };
530
-
531
- parsedStream.on('end', () => {
532
- void (async () => {
533
- if (!isSseResponse) {
534
- try {
535
- const parsed = JSON.parse(buffer);
536
- const usage = parseNonStreamingUsage(parsed);
537
- mergeUsageIntoTokenData(tokenData, usage);
538
- } catch (err) {
539
- }
540
- } else {
541
- const assistantMessage = buildAssistantMessageFromStreamState(streamRecoveryState);
542
- const shouldRecoverUsage = Boolean(assistantMessage)
543
- && (!usageObservation.sawAnyUsage || (usageObservation.sawMessageStartUsage && !usageObservation.sawNonInitialUsage));
544
-
545
- if (shouldRecoverUsage) {
546
- try {
547
- const recoveredUsage = await recoverClaudeUsageViaCountTokens({
548
- baseUrl: req.selectedChannel?.baseUrl || '',
549
- apiKey: req.effectiveApiKey || '',
550
- requestBody: req.body,
551
- assistantMessage
552
- });
553
- if (recoveredUsage) {
554
- tokenData.model = tokenData.model || streamRecoveryState.model || '';
555
- tokenData.inputTokens = Number(recoveredUsage.inputTokens || 0);
556
- tokenData.outputTokens = Number(recoveredUsage.outputTokens || 0);
557
- // Let publishUsageLog recompute Claude totals from the recovered
558
- // prompt/output pair plus any cache fields already present.
559
- tokenData.totalTokens = 0;
560
- } else {
561
- tokenData.model = tokenData.model || streamRecoveryState.model || '';
562
- clearTokenDataUsage(tokenData);
563
- }
564
- } catch (error) {
565
- tokenData.model = tokenData.model || streamRecoveryState.model || '';
566
- clearTokenDataUsage(tokenData);
567
- }
568
- }
569
- }
570
-
571
- recordUsageIfReady();
572
- finalize();
573
- })();
366
+ requestMetadata.delete(req);
574
367
  });
575
-
576
- parsedStream.on('error', (err) => {
577
- if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') {
578
- console.error('Proxy response error:', err);
579
- }
580
- // 记录响应错误
581
- if (metadata && metadata.channelId) {
582
- recordFailure(metadata.channelId, 'claude', err);
583
- }
584
- publishFailureLog({
585
- source: 'claude',
586
- metadata,
587
- message: err.message,
588
- error: err,
589
- statusCode: proxyRes.statusCode,
590
- stage: 'response_stream',
591
- broadcastLog
592
- });
593
- isResponseClosed = true;
594
- finalize();
368
+ proxyRes.on('error', (err) => {
369
+ if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') console.error('Proxy response error:', err);
370
+ recordFailure(metadata.channelId, 'claude', err);
371
+ requestMetadata.delete(req);
595
372
  });
596
373
  });
597
374
 
@@ -601,20 +378,6 @@ async function startProxyServer(options = {}) {
601
378
  if (req && req.selectedChannel && req.selectedChannel.id) {
602
379
  recordFailure(req.selectedChannel.id, 'claude', err);
603
380
  }
604
- const metadata = req ? requestMetadata.get(req) : null;
605
- publishFailureLog({
606
- source: 'claude',
607
- metadata: metadata || {
608
- channel: req?.selectedChannel?.name,
609
- channelId: req?.selectedChannel?.id,
610
- model: req?.body?.model
611
- },
612
- message: err.message,
613
- error: err,
614
- statusCode: 502,
615
- stage: 'proxy',
616
- broadcastLog
617
- });
618
381
  if (res && !res.headersSent) {
619
382
  res.status(502).json({
620
383
  error: 'Proxy error: ' + err.message,