coding-tool-x 3.8.3 → 3.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +86 -15
  3. package/dist/web/assets/AgentsDrawer-BG6P3DX-.js +1 -0
  4. package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
  5. package/dist/web/assets/Analytics--z_FmL5P.js +1 -0
  6. package/dist/web/assets/Analytics-CyHhR126.css +1 -0
  7. package/dist/web/assets/AssetPathField-CrJtRKHy.js +1 -0
  8. package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
  9. package/dist/web/assets/ChatHistoryDrawer-BiuEryJj.js +1 -0
  10. package/dist/web/assets/CollapseItem-BAYEsL_Q.js +1 -0
  11. package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
  12. package/dist/web/assets/CommandsDrawer-YJ-U7BXN.js +1 -0
  13. package/dist/web/assets/ConfigExportDrawer-Ce_hAknW.js +1 -0
  14. package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
  15. package/dist/web/assets/ConfigTemplates-Bvr1NN6K.js +1 -0
  16. package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
  17. package/dist/web/assets/ConfigTemplatesDrawer-BjIeHfF-.js +1 -0
  18. package/dist/web/assets/ConfigTemplatesPanel-AV00tm_D.js +1 -0
  19. package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +1 -0
  20. package/dist/web/assets/Divider-D28g1gwj.js +1 -0
  21. package/dist/web/assets/DrawerContent-ChXgZ1Xm.js +1 -0
  22. package/dist/web/assets/FavoritesDrawer-CG9eI9Ay.css +1 -0
  23. package/dist/web/assets/FavoritesDrawer-Cz95o4CD.js +1 -0
  24. package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
  25. package/dist/web/assets/GatewayConvertDrawer-DLlbMz27.js +1 -0
  26. package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
  27. package/dist/web/assets/Home-D7CCOFQC.js +1 -0
  28. package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
  29. package/dist/web/assets/MarkdownEditor-rEZ-c72L.js +1 -0
  30. package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
  31. package/dist/web/assets/McpDrawer-DfoCyxU2.js +1 -0
  32. package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
  33. package/dist/web/assets/McpFormDrawer-SKu8HNUR.js +1 -0
  34. package/dist/web/assets/PluginManager-BbeK-3rV.js +1 -0
  35. package/dist/web/assets/PluginsDrawer-CWVJ7yjS.js +1 -0
  36. package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
  37. package/dist/web/assets/PluginsPanel-Cm2N3StG.js +1 -0
  38. package/dist/web/assets/PluginsPanel-D6ZqITcR.css +1 -0
  39. package/dist/web/assets/ProjectList-677RLZ8O.css +1 -0
  40. package/dist/web/assets/ProjectList-CsjnsNPv.js +1 -0
  41. package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
  42. package/dist/web/assets/PromptsDrawer-EGd3djFa.js +1 -0
  43. package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
  44. package/dist/web/assets/RecentSessionsDrawer-D1vtoLAs.js +1 -0
  45. package/dist/web/assets/SessionCard-BgLg49U3.js +1 -0
  46. package/dist/web/assets/SessionCard-aM2NHu6i.css +1 -0
  47. package/dist/web/assets/SessionList-BpYRz1cX.css +1 -0
  48. package/dist/web/assets/SessionList-TRiTklWk.js +1 -0
  49. package/dist/web/assets/SettingsDrawer-d5liXjHq.css +1 -0
  50. package/dist/web/assets/SettingsDrawer-rz2WejGY.js +1 -0
  51. package/dist/web/assets/SkillManager-BTjTUbHq.js +1 -0
  52. package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
  53. package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
  54. package/dist/web/assets/SkillsDrawer-pN0hbkK3.js +1 -0
  55. package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
  56. package/dist/web/assets/SkillsPanel-gmBWEoiF.js +1 -0
  57. package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
  58. package/dist/web/assets/SpeedTestDrawer-DcNzuVJk.js +1 -0
  59. package/dist/web/assets/Upload-v5rV0qTT.js +1 -0
  60. package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
  61. package/dist/web/assets/WorkspaceDrawer-DxmicM4U.js +1 -0
  62. package/dist/web/assets/WorkspaceManager-CJHCjARN.js +1 -0
  63. package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
  64. package/dist/web/assets/WorkspacePanel-D8_Zq-du.js +1 -0
  65. package/dist/web/assets/_plugin-vue_export-helper-BeLZJZij.js +1 -0
  66. package/dist/web/assets/client-UDwXBP9i.js +1 -0
  67. package/dist/web/assets/clipboard-B46yyoz_.js +1 -0
  68. package/dist/web/assets/headers-cf-QapUq.js +1 -0
  69. package/dist/web/assets/icons-B2Vg-IOC.js +1 -0
  70. package/dist/web/assets/index-C0EHRym0.css +1 -0
  71. package/dist/web/assets/index-DnEocV0M.js +2 -0
  72. package/dist/web/assets/light-Cp0t7v32.js +1 -0
  73. package/dist/web/assets/markdown-u082bbtj.js +1 -0
  74. package/dist/web/assets/platforms-CBkB45JP.js +1 -0
  75. package/dist/web/assets/platforms-FTpjxAT6.js +1 -0
  76. package/dist/web/assets/project-config-B2baPzYL.js +1 -0
  77. package/dist/web/assets/sessions-Cmy31slD.js +1 -0
  78. package/dist/web/assets/sessions-yC_oVVh8.js +1 -0
  79. package/dist/web/assets/skill-repo-input-B_fkGlUK.js +1 -0
  80. package/dist/web/assets/use-lock-html-scroll-DXIqmUW4.js +1 -0
  81. package/dist/web/assets/use-message-DoLM8C1C.js +1 -0
  82. package/dist/web/assets/useResponsiveDrawer-B3uojyvV.js +1 -0
  83. package/dist/web/assets/vendors-D0c_0KLP.js +1 -0
  84. package/dist/web/assets/vue-vendor-BqZbbXHA.js +1 -0
  85. package/dist/web/assets/workspaces-mjyPVGS8.js +1 -0
  86. package/dist/web/assets/xml-CgY3RMlX.js +1 -0
  87. package/dist/web/index.html +12 -8
  88. package/docs/native-log-memory-2026-09-16.md +43 -0
  89. package/docs/superpowers/plans/2026-08-26-configuration-driven-cli-platform.md +1578 -0
  90. package/docs/superpowers/plans/2026-08-30-project-scoped-config-control.md +1260 -0
  91. package/docs/superpowers/plans/2026-09-01-omp-skill-refresh-boundary.md +213 -0
  92. package/docs/superpowers/plans/2026-09-01-realtime-logs-panel.md +125 -0
  93. package/docs/superpowers/plans/2026-09-02-config-driven-platform-boundary.md +86 -0
  94. package/docs/superpowers/plans/2026-09-02-platform-implementation-drivers.md +508 -0
  95. package/docs/superpowers/plans/2026-09-03-cli-platform-correctness-boundary.md +760 -0
  96. package/docs/superpowers/plans/2026-09-03-dependency-security-remediation.md +133 -0
  97. package/docs/superpowers/plans/2026-09-04-model-catalog-pricing-sync.md +1078 -0
  98. package/docs/superpowers/plans/2026-09-05-codex-project-scan-500.md +128 -0
  99. package/docs/superpowers/plans/2026-09-06-project-skill-path-fix.md +97 -0
  100. package/docs/superpowers/specs/2026-08-26-configuration-driven-cli-platform-design.md +408 -0
  101. package/docs/superpowers/specs/2026-08-30-project-scoped-config-control-design.md +467 -0
  102. package/docs/superpowers/specs/2026-09-01-claude-session-content-repair-design.md +111 -0
  103. package/docs/superpowers/specs/2026-09-01-omp-skill-refresh-boundary-design.md +83 -0
  104. package/docs/superpowers/specs/2026-09-01-realtime-logs-panel-design.md +27 -0
  105. package/docs/superpowers/specs/2026-09-02-config-driven-platform-boundary-design.md +64 -0
  106. package/docs/superpowers/specs/2026-09-02-platform-implementation-driver-boundary-design.md +123 -0
  107. package/docs/superpowers/specs/2026-09-03-cli-platform-correctness-boundary-design.md +249 -0
  108. package/docs/superpowers/specs/2026-09-03-dependency-security-remediation-design.md +87 -0
  109. package/docs/superpowers/specs/2026-09-04-model-catalog-pricing-sync-design.md +301 -0
  110. package/docs/superpowers/specs/2026-09-05-codex-project-scan-500-design.md +24 -0
  111. package/package.json +13 -8
  112. package/src/commands/channels.js +88 -191
  113. package/src/commands/cli-type.js +19 -11
  114. package/src/commands/daemon.js +94 -32
  115. package/src/commands/doctor.js +16 -9
  116. package/src/commands/export-config.js +23 -5
  117. package/src/commands/list.js +130 -52
  118. package/src/commands/logs.js +44 -27
  119. package/src/commands/platform-command-registry.js +78 -0
  120. package/src/commands/plugin.js +11 -5
  121. package/src/commands/port-config.js +34 -52
  122. package/src/commands/proxy-control.js +207 -145
  123. package/src/commands/proxy.js +2 -2
  124. package/src/commands/resume.js +87 -91
  125. package/src/commands/search.js +137 -67
  126. package/src/commands/stats.js +30 -22
  127. package/src/commands/switch.js +1 -1
  128. package/src/commands/toggle-proxy.js +94 -111
  129. package/src/commands/ui.js +67 -6
  130. package/src/commands/workspace.js +90 -8
  131. package/src/config/default.js +6 -53
  132. package/src/config/loader.js +61 -24
  133. package/src/config/model-metadata.js +49 -59
  134. package/src/config/model-metadata.json +4095 -99
  135. package/src/config/paths.js +181 -8
  136. package/src/index.js +134 -71
  137. package/src/platforms/access.js +196 -0
  138. package/src/{server/services → platforms}/agents-service.js +354 -197
  139. package/src/platforms/channel-auth-registry.js +162 -0
  140. package/src/platforms/channel-auth-service.js +82 -0
  141. package/src/{server/services → platforms}/commands-service.js +195 -115
  142. package/src/platforms/driver-registry.js +59 -0
  143. package/src/platforms/drivers/claude/api-operations.js +62 -0
  144. package/src/{server/services/channels.js → platforms/drivers/claude/channels-implementation.js} +131 -33
  145. package/src/platforms/drivers/claude/channels.js +39 -0
  146. package/src/{server/services/config-sync-service.js → platforms/drivers/claude/config-sync.js} +29 -5
  147. package/src/{server/services → platforms/drivers/claude}/health-check.js +4 -4
  148. package/src/platforms/drivers/claude/health.js +22 -0
  149. package/src/platforms/drivers/claude/mcp.js +9 -0
  150. package/src/{server/services/settings-manager.js → platforms/drivers/claude/native-config-implementation.js} +13 -4
  151. package/src/platforms/drivers/claude/native-config.js +46 -0
  152. package/src/platforms/drivers/claude/native-logs.js +72 -0
  153. package/src/{server/services/claude-openai-gateway.js → platforms/drivers/claude/openai-gateway.js} +8 -65
  154. package/src/platforms/drivers/claude/project-config.js +21 -0
  155. package/src/platforms/drivers/claude/projects.js +62 -0
  156. package/src/platforms/drivers/claude/prompts.js +9 -0
  157. package/src/{server/proxy-server.js → platforms/drivers/claude/proxy-implementation.js} +41 -278
  158. package/src/platforms/drivers/claude/proxy.js +16 -0
  159. package/src/platforms/drivers/claude/resource-sync.js +9 -0
  160. package/src/platforms/drivers/claude/session-history-adapter.js +313 -0
  161. package/src/{server/services/sessions.js → platforms/drivers/claude/sessions-implementation.js} +145 -35
  162. package/src/platforms/drivers/claude/sessions.js +76 -0
  163. package/src/{server/services/claude-statistics-service.js → platforms/drivers/claude/statistics-implementation.js} +2 -2
  164. package/src/platforms/drivers/claude/statistics.js +16 -0
  165. package/src/{server/services/claude-wire.js → platforms/drivers/claude/wire.js} +1 -1
  166. package/src/platforms/drivers/codex/api-operations.js +9 -0
  167. package/src/{server/services/codex-channels.js → platforms/drivers/codex/channels-implementation.js} +149 -14
  168. package/src/platforms/drivers/codex/channels.js +45 -0
  169. package/src/{server/services/codex-config.js → platforms/drivers/codex/config.js} +12 -2
  170. package/src/{server/services/codex-env-manager.js → platforms/drivers/codex/env-manager.js} +1 -1
  171. package/src/platforms/drivers/codex/mcp.js +9 -0
  172. package/src/{server/services/codex-settings-manager.js → platforms/drivers/codex/native-config-implementation.js} +15 -6
  173. package/src/platforms/drivers/codex/native-config.js +47 -0
  174. package/src/platforms/drivers/codex/native-logs.js +166 -0
  175. package/src/platforms/drivers/codex/project-config.js +21 -0
  176. package/src/platforms/drivers/codex/projects.js +26 -0
  177. package/src/platforms/drivers/codex/prompts.js +9 -0
  178. package/src/{server/codex-proxy-server.js → platforms/drivers/codex/proxy-implementation.js} +30 -233
  179. package/src/platforms/drivers/codex/proxy.js +16 -0
  180. package/src/platforms/drivers/codex/resource-sync.js +9 -0
  181. package/src/{server/services/session-history-adapters/codex.js → platforms/drivers/codex/session-history-adapter.js} +37 -23
  182. package/src/{server/services/codex-sessions.js → platforms/drivers/codex/sessions-implementation.js} +81 -75
  183. package/src/platforms/drivers/codex/sessions.js +36 -0
  184. package/src/{server/services/codex-statistics-service.js → platforms/drivers/codex/statistics-implementation.js} +2 -2
  185. package/src/platforms/drivers/codex/statistics.js +16 -0
  186. package/src/platforms/drivers/gemini/api-operations.js +9 -0
  187. package/src/{server/services/gemini-channels.js → platforms/drivers/gemini/channels-implementation.js} +202 -37
  188. package/src/platforms/drivers/gemini/channels.js +39 -0
  189. package/src/{server/services/gemini-config.js → platforms/drivers/gemini/config.js} +12 -2
  190. package/src/platforms/drivers/gemini/mcp.js +9 -0
  191. package/src/{server/services/gemini-settings-manager.js → platforms/drivers/gemini/native-config-implementation.js} +14 -5
  192. package/src/platforms/drivers/gemini/native-config.js +39 -0
  193. package/src/platforms/drivers/gemini/native-logs.js +180 -0
  194. package/src/platforms/drivers/gemini/project-config.js +21 -0
  195. package/src/platforms/drivers/gemini/projects.js +26 -0
  196. package/src/platforms/drivers/gemini/prompts.js +9 -0
  197. package/src/{server/gemini-proxy-server.js → platforms/drivers/gemini/proxy-implementation.js} +36 -267
  198. package/src/platforms/drivers/gemini/proxy.js +16 -0
  199. package/src/platforms/drivers/gemini/resource-sync.js +9 -0
  200. package/src/{server/services/session-history-adapters/gemini.js → platforms/drivers/gemini/session-history-adapter.js} +70 -18
  201. package/src/{server/services/gemini-sessions.js → platforms/drivers/gemini/sessions-implementation.js} +53 -37
  202. package/src/platforms/drivers/gemini/sessions.js +47 -0
  203. package/src/{server/services/gemini-statistics-service.js → platforms/drivers/gemini/statistics-implementation.js} +2 -2
  204. package/src/platforms/drivers/gemini/statistics.js +16 -0
  205. package/src/{server/services/gemini-wire.js → platforms/drivers/gemini/wire.js} +1 -1
  206. package/src/platforms/drivers/generic-filesystem.js +166 -0
  207. package/src/platforms/drivers/generic-jsonl.js +141 -0
  208. package/src/platforms/drivers/generic-mcp.js +44 -0
  209. package/src/platforms/drivers/generic-openai-compatible.js +45 -0
  210. package/src/platforms/drivers/generic-prompt.js +41 -0
  211. package/src/platforms/drivers/legacy.js +677 -0
  212. package/src/platforms/drivers/native-config-snapshot.js +125 -0
  213. package/src/platforms/drivers/native-log-utils.js +1292 -0
  214. package/src/platforms/drivers/notification-hooks.js +578 -0
  215. package/src/{server/api/omp-config.js → platforms/drivers/omp/api-operations.js} +52 -64
  216. package/src/{server/services/omp-auth-provider-worker.js → platforms/drivers/omp/auth-provider-worker.js} +1 -1
  217. package/src/{server/services/omp-auth-providers.js → platforms/drivers/omp/auth-providers.js} +1 -1
  218. package/src/{server/services/omp-channels.js → platforms/drivers/omp/channels-implementation.js} +166 -39
  219. package/src/platforms/drivers/omp/channels.js +58 -0
  220. package/src/{server/services/omp-config.js → platforms/drivers/omp/config.js} +53 -13
  221. package/src/{server/services/omp-gateway-routing.js → platforms/drivers/omp/gateway-routing.js} +14 -7
  222. package/src/{server/services/omp-gateway.js → platforms/drivers/omp/gateway.js} +4 -262
  223. package/src/platforms/drivers/omp/mcp.js +9 -0
  224. package/src/{server/services/omp-settings-manager.js → platforms/drivers/omp/native-config-implementation.js} +75 -10
  225. package/src/platforms/drivers/omp/native-config.js +46 -0
  226. package/src/platforms/drivers/omp/native-logs.js +52 -0
  227. package/src/{server/services/omp-native-plugin-adapter.js → platforms/drivers/omp/native-plugin-adapter.js} +91 -4
  228. package/src/platforms/drivers/omp/project-config.js +29 -0
  229. package/src/platforms/drivers/omp/projects.js +20 -0
  230. package/src/platforms/drivers/omp/prompts.js +9 -0
  231. package/src/{server/omp-proxy-server.js → platforms/drivers/omp/proxy-implementation.js} +6 -15
  232. package/src/platforms/drivers/omp/proxy.js +16 -0
  233. package/src/platforms/drivers/omp/resource-sync.js +9 -0
  234. package/src/{server/services/session-history-adapters/omp.js → platforms/drivers/omp/session-history-adapter.js} +42 -18
  235. package/src/{server/services/omp-sessions.js → platforms/drivers/omp/sessions-implementation.js} +130 -94
  236. package/src/platforms/drivers/omp/sessions.js +36 -0
  237. package/src/{server/services/omp-skill-discovery.js → platforms/drivers/omp/skill-discovery.js} +159 -32
  238. package/src/{server/services/omp-skill-settings-service.js → platforms/drivers/omp/skill-settings.js} +1 -1
  239. package/src/{server/services/omp-statistics-service.js → platforms/drivers/omp/statistics-implementation.js} +3 -3
  240. package/src/platforms/drivers/omp/statistics.js +16 -0
  241. package/src/platforms/drivers/opencode/api-operations.js +9 -0
  242. package/src/{server/services/opencode-channels.js → platforms/drivers/opencode/channels-implementation.js} +28 -9
  243. package/src/platforms/drivers/opencode/channels.js +40 -0
  244. package/src/platforms/drivers/opencode/conversion.js +41 -0
  245. package/src/{server/services/opencode-gateway-converter.js → platforms/drivers/opencode/gateway-converter.js} +1 -1
  246. package/src/platforms/drivers/opencode/mcp.js +9 -0
  247. package/src/{server/services/opencode-settings-manager.js → platforms/drivers/opencode/native-config-implementation.js} +17 -6
  248. package/src/platforms/drivers/opencode/native-config.js +26 -0
  249. package/src/platforms/drivers/opencode/native-logs.js +133 -0
  250. package/src/platforms/drivers/opencode/project-config.js +98 -0
  251. package/src/platforms/drivers/opencode/projects.js +20 -0
  252. package/src/platforms/drivers/opencode/prompts.js +9 -0
  253. package/src/{server/opencode-proxy-server.js → platforms/drivers/opencode/proxy-implementation.js} +27 -362
  254. package/src/platforms/drivers/opencode/proxy.js +16 -0
  255. package/src/platforms/drivers/opencode/resource-sync.js +9 -0
  256. package/src/{server/services/opencode-sessions.js → platforms/drivers/opencode/sessions-implementation.js} +211 -64
  257. package/src/platforms/drivers/opencode/sessions.js +48 -0
  258. package/src/{server/services/opencode-statistics-service.js → platforms/drivers/opencode/statistics-implementation.js} +2 -2
  259. package/src/platforms/drivers/opencode/statistics.js +16 -0
  260. package/src/platforms/drivers/secure-file-driver.js +272 -0
  261. package/src/platforms/drivers/unsupported.js +7 -0
  262. package/src/platforms/manifest-schema.js +398 -0
  263. package/src/platforms/manifests/claude.json +489 -0
  264. package/src/platforms/manifests/codex.json +448 -0
  265. package/src/platforms/manifests/gemini.json +447 -0
  266. package/src/platforms/manifests/omp.json +496 -0
  267. package/src/platforms/manifests/opencode.json +422 -0
  268. package/src/{server/services → platforms}/native-oauth-adapters.js +87 -417
  269. package/src/{server/services → platforms}/notification-hooks.js +140 -1023
  270. package/src/platforms/oauth-credentials-service.js +506 -0
  271. package/src/platforms/path-resolver.js +179 -0
  272. package/src/platforms/platform-path-context.js +305 -0
  273. package/src/platforms/registry.js +248 -0
  274. package/src/platforms/remote-notification-providers.js +678 -0
  275. package/src/platforms/runtime.js +259 -0
  276. package/src/{server/services/session-history-adapters/index.js → platforms/session-history-adapters.js} +8 -1
  277. package/src/plugins/plugin-loader.js +2 -2
  278. package/src/plugins/plugin-manager.js +2 -2
  279. package/src/plugins/registry.js +27 -10
  280. package/src/reset-config.js +21 -5
  281. package/src/server/api/agents.js +46 -72
  282. package/src/server/api/commands.js +16 -6
  283. package/src/server/api/config-registry.js +206 -59
  284. package/src/server/api/config-sync.js +3 -2
  285. package/src/server/api/config-templates.js +20 -4
  286. package/src/server/api/config.js +111 -102
  287. package/src/server/api/convert.js +54 -178
  288. package/src/server/api/dashboard.js +168 -102
  289. package/src/server/api/hooks.js +1 -1
  290. package/src/server/api/mcp.js +224 -84
  291. package/src/server/api/platform-api-config.js +102 -0
  292. package/src/server/api/platform-route-factory.js +215 -0
  293. package/src/server/api/platform-routes.js +26 -0
  294. package/src/server/api/platforms.js +110 -0
  295. package/src/server/api/plugins.js +57 -57
  296. package/src/server/api/project-config.js +168 -0
  297. package/src/server/api/prompts.js +58 -45
  298. package/src/server/api/settings.js +55 -8
  299. package/src/server/api/skills.js +262 -133
  300. package/src/server/api/ui-config.js +2 -2
  301. package/src/server/api/validation-errors.js +18 -4
  302. package/src/server/api/workspaces.js +47 -12
  303. package/src/server/index.js +164 -213
  304. package/src/server/platform-context.js +81 -0
  305. package/src/server/services/channel-balance.js +11 -20
  306. package/src/server/services/channel-health.js +21 -6
  307. package/src/server/services/channel-scheduler.js +29 -39
  308. package/src/server/services/channel-sync-utils.js +23 -13
  309. package/src/server/services/config-export-service.js +350 -319
  310. package/src/server/services/config-registry-service.js +280 -54
  311. package/src/server/services/config-sync-manager.js +172 -944
  312. package/src/server/services/config-templates-service.js +419 -353
  313. package/src/server/services/control-manifest-store.js +206 -0
  314. package/src/server/services/dashboard-snapshot-worker.js +656 -100
  315. package/src/server/services/effective-control-service.js +557 -0
  316. package/src/server/services/local-resource-index.js +314 -0
  317. package/src/server/services/mcp-service.js +607 -977
  318. package/src/server/services/model-detector.js +15 -10
  319. package/src/server/services/native-log-channel-resolver.js +214 -0
  320. package/src/server/services/native-log-observer.js +291 -0
  321. package/src/server/services/network-access.js +1 -1
  322. package/src/server/services/platform-catalog.js +82 -0
  323. package/src/server/services/platform-resolution.js +32 -29
  324. package/src/server/services/plugins-service.js +376 -122
  325. package/src/server/services/project-config-service.js +550 -0
  326. package/src/server/services/project-path-validation.js +31 -0
  327. package/src/server/services/prompts-service.js +267 -233
  328. package/src/server/services/proxy-runtime.js +7 -4
  329. package/src/server/services/remote-credential-cache.js +43 -0
  330. package/src/server/services/repo-scanner-base.js +182 -75
  331. package/src/server/services/request-logger.js +7 -4
  332. package/src/server/services/session-history-index.js +780 -213
  333. package/src/server/services/session-history-worker.js +228 -33
  334. package/src/server/services/session-snapshot-worker.js +124 -34
  335. package/src/server/services/session-snapshots.js +4 -2
  336. package/src/server/services/skill-artifact-store.js +355 -0
  337. package/src/server/services/skill-format-adapters.js +65 -0
  338. package/src/server/services/skill-projection-service.js +323 -0
  339. package/src/server/services/skill-refresh-task-service.js +275 -0
  340. package/src/server/services/skill-service.js +2020 -677
  341. package/src/server/services/snapshot-cache.js +30 -8
  342. package/src/server/services/speed-test.js +8 -8
  343. package/src/server/services/sqlite-connection.js +19 -3
  344. package/src/server/services/statistics-service.js +240 -57
  345. package/src/server/services/ui-config.js +107 -76
  346. package/src/server/services/usage-log-utils.js +98 -0
  347. package/src/server/services/web-build.js +1 -1
  348. package/src/server/services/workspace-service.js +59 -29
  349. package/src/server/utils/pricing.js +10 -19
  350. package/src/server/websocket-server.js +153 -28
  351. package/src/{server/services/base → shared}/base-channel-service.js +156 -28
  352. package/src/shared/capability-driver.js +104 -0
  353. package/src/shared/channel-auth-policy.js +27 -0
  354. package/src/shared/channel-driver.js +161 -0
  355. package/src/shared/driver-factories/api.js +180 -0
  356. package/src/shared/driver-factories/mcp.js +244 -0
  357. package/src/shared/driver-factories/projects.js +121 -0
  358. package/src/shared/driver-factories/prompts.js +58 -0
  359. package/src/shared/driver-factories/resource-sync.js +375 -0
  360. package/src/shared/driver-result.js +78 -0
  361. package/src/shared/mcp-format.js +189 -0
  362. package/src/shared/platforms.js +104 -167
  363. package/src/shared/project-config.js +512 -0
  364. package/src/shared/proxy-driver.js +57 -0
  365. package/src/{server/services/base → shared}/response-usage-parser.js +8 -4
  366. package/src/ui/menu.js +91 -67
  367. package/src/utils/port-helper.js +35 -19
  368. package/src/utils/session.js +1 -1
  369. package/dist/web/assets/Analytics-COEUXmd4.js +0 -25
  370. package/dist/web/assets/Analytics-RNn1BUbG.css +0 -1
  371. package/dist/web/assets/ConfigTemplates-DLLkS53H.js +0 -1
  372. package/dist/web/assets/Home-DCEyLzwX.js +0 -1
  373. package/dist/web/assets/Home-DYVy4cGZ.css +0 -1
  374. package/dist/web/assets/PluginManager-Oe1ZHoMO.js +0 -1
  375. package/dist/web/assets/ProjectList-CWjuAFof.js +0 -1
  376. package/dist/web/assets/ProjectList-VeMNXfgO.css +0 -1
  377. package/dist/web/assets/SessionList-C4chCPxK.css +0 -1
  378. package/dist/web/assets/SessionList-v3ehGg9U.js +0 -1
  379. package/dist/web/assets/SkillManager-BsX8Qpj0.css +0 -1
  380. package/dist/web/assets/SkillManager-DUF_qP5S.js +0 -1
  381. package/dist/web/assets/WorkspaceManager-CjAWBosO.js +0 -1
  382. package/dist/web/assets/icons-nGdSKQn2.js +0 -1
  383. package/dist/web/assets/index-D5hyHPj7.js +0 -2
  384. package/dist/web/assets/index-bJRG3RXH.css +0 -1
  385. package/dist/web/assets/markdown-BNJfEgCA.js +0 -1
  386. package/dist/web/assets/markdown-BfC0goYb.css +0 -10
  387. package/dist/web/assets/naive-ui-BALVpMgd.js +0 -1
  388. package/dist/web/assets/vendors-DQA4Hw9v.js +0 -7
  389. package/dist/web/assets/vue-vendor-B5RqjEjQ.js +0 -45
  390. package/src/config/model-pricing.js +0 -35
  391. package/src/server/api/channels.js +0 -439
  392. package/src/server/api/claude-hooks.js +0 -56
  393. package/src/server/api/claude-statistics.js +0 -57
  394. package/src/server/api/codex-channels.js +0 -491
  395. package/src/server/api/codex-projects.js +0 -117
  396. package/src/server/api/codex-proxy.js +0 -293
  397. package/src/server/api/codex-sessions.js +0 -652
  398. package/src/server/api/codex-statistics.js +0 -57
  399. package/src/server/api/gemini-channels.js +0 -392
  400. package/src/server/api/gemini-projects.js +0 -103
  401. package/src/server/api/gemini-proxy.js +0 -231
  402. package/src/server/api/gemini-sessions.js +0 -550
  403. package/src/server/api/gemini-statistics.js +0 -57
  404. package/src/server/api/health-check.js +0 -31
  405. package/src/server/api/oauth-credentials.js +0 -198
  406. package/src/server/api/omp-channels.js +0 -575
  407. package/src/server/api/omp-projects.js +0 -88
  408. package/src/server/api/omp-proxy.js +0 -125
  409. package/src/server/api/omp-sessions.js +0 -386
  410. package/src/server/api/omp-statistics.js +0 -40
  411. package/src/server/api/opencode-channels.js +0 -471
  412. package/src/server/api/opencode-projects.js +0 -110
  413. package/src/server/api/opencode-proxy.js +0 -354
  414. package/src/server/api/opencode-sessions.js +0 -466
  415. package/src/server/api/opencode-statistics.js +0 -57
  416. package/src/server/api/projects.js +0 -120
  417. package/src/server/api/proxy.js +0 -330
  418. package/src/server/api/sessions.js +0 -810
  419. package/src/server/services/oauth-credentials-service.js +0 -945
  420. package/src/server/services/omp-session-log-observer.js +0 -138
  421. package/src/server/services/opencode-gateway-adapters.js +0 -43
  422. package/src/server/services/project-snapshots.js +0 -59
  423. package/src/server/services/proxy-log-helper.js +0 -298
  424. package/src/server/services/session-cache.js +0 -127
  425. package/src/server/services/session-converter.js +0 -582
  426. package/src/server/services/session-history-adapters/claude.js +0 -235
  427. /package/src/{server/services/claude-token-recovery.js → platforms/drivers/claude/token-recovery.js} +0 -0
  428. /package/src/{server/services/codex-parser.js → platforms/drivers/codex/parser.js} +0 -0
  429. /package/src/{server/services/codex-speed-test-template.json → platforms/drivers/codex/speed-test-template.json} +0 -0
  430. /package/src/{server/services/codex-wire.js → platforms/drivers/codex/wire.js} +0 -0
  431. /package/src/{server/services/omp-auth-gateway-client.js → platforms/drivers/omp/auth-gateway-client.js} +0 -0
  432. /package/src/{server/services/opencode-normalization.js → platforms/drivers/opencode/normalization.js} +0 -0
  433. /package/src/{server/services → shared}/config-artifact-paths.js +0 -0
  434. /package/src/{server/services/base → shared}/proxy-utils.js +0 -0
@@ -8,34 +8,24 @@ const path = require('path');
8
8
  const crypto = require('crypto');
9
9
  const zlib = require('zlib');
10
10
  const chalk = require('chalk');
11
- const { broadcastLog, broadcastSchedulerState } = require('./websocket-server');
12
- const { allocateChannel, releaseChannel, getSchedulerState } = require('./services/channel-scheduler');
13
- const { recordSuccess, recordFailure } = require('./services/channel-health');
14
- const { loadConfig } = require('../config/loader');
15
- const DEFAULT_CONFIG = require('../config/default');
16
- const { PATHS, ensureStorageDirMigrated } = require('../config/paths');
17
- const { resolveModelPricing, calculateTokenCost } = require('./utils/pricing');
18
- const { recordRequest: recordOpenCodeRequest } = require('./services/opencode-statistics-service');
19
- const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('./services/proxy-runtime');
20
- const { getEnabledChannels, getEffectiveApiKey } = require('./services/opencode-channels');
21
- const { persistProxyRequestSnapshot, loadClaudeRequestTemplate } = require('./services/request-logger');
22
- const { probeModelAvailability, fetchModelsFromProvider } = require('./services/model-detector');
23
- const { publishUsageLog, publishFailureLog } = require('./services/proxy-log-helper');
11
+ const { broadcastSchedulerState } = require('../../../server/websocket-server');
12
+ const { allocateChannel, releaseChannel, getSchedulerState } = require('../../../server/services/channel-scheduler');
13
+ const { recordSuccess, recordFailure } = require('../../../server/services/channel-health');
14
+ const { loadConfig } = require('../../../config/loader');
15
+ const { PATHS, ensureStorageDirMigrated } = require('../../../config/paths');
16
+ const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('../../../server/services/proxy-runtime');
17
+ const { getEnabledChannels, getEffectiveApiKey } = require('./channels-implementation');
18
+ const { persistProxyRequestSnapshot, loadClaudeRequestTemplate } = require('../../../server/services/request-logger');
19
+ const { probeModelAvailability, fetchModelsFromProvider } = require('../../../server/services/model-detector');
24
20
  const {
25
21
  redirectModel,
26
22
  resolveTargetUrl,
27
23
  ensureOpenAiStreamUsage
28
- } = require('./services/base/proxy-utils');
29
- const { attachServerShutdownHandling, expediteServerShutdown } = require('./services/server-shutdown');
30
- const { buildCodexTargetUrl, createCodexRequest } = require('./services/codex-wire');
31
- const {
32
- parseSSEUsage,
33
- parseNonStreamingUsage,
34
- mergeUsageIntoTokenData,
35
- createTokenData
36
- } = require('./services/base/response-usage-parser');
37
- const { createClaudeRequest, buildClaudeTargetUrl, buildClaudeCountTokensTargetUrl, buildClaudeCountTokensHeaders } = require('./services/claude-wire');
38
- const { createGeminiRequest, buildGeminiTargetUrl, shouldUseGeminiCliFormat } = require('./services/gemini-wire');
24
+ } = require('../../../shared/proxy-utils');
25
+ const { attachServerShutdownHandling, expediteServerShutdown } = require('../../../server/services/server-shutdown');
26
+ const { buildCodexTargetUrl, createCodexRequest } = require('../codex/wire');
27
+ const { createClaudeRequest, buildClaudeTargetUrl, buildClaudeCountTokensTargetUrl, buildClaudeCountTokensHeaders } = require('../claude/wire');
28
+ const { createGeminiRequest, buildGeminiTargetUrl, shouldUseGeminiCliFormat } = require('../gemini/wire');
39
29
 
40
30
  let proxyServer = null;
41
31
  let proxyApp = null;
@@ -48,24 +38,6 @@ const requestMetadata = new Map();
48
38
  // 格式: { channelId: { "originalModel": "redirectedModel", ... } }
49
39
  const printedRedirectCache = new Map();
50
40
 
51
- // OpenAI 模型定价(每百万 tokens 的价格,单位:美元)
52
- // Claude 模型使用 config/model-pricing.js 中的集中定价
53
- const PRICING = {
54
- 'gpt-4o': { input: 2.5, output: 10 },
55
- 'gpt-4o-2024-11-20': { input: 2.5, output: 10 },
56
- 'gpt-4o-mini': { input: 0.15, output: 0.6 },
57
- 'gpt-4-turbo': { input: 10, output: 30 },
58
- 'gpt-4': { input: 30, output: 60 },
59
- 'gpt-3.5-turbo': { input: 0.5, output: 1.5 },
60
- 'o1': { input: 15, output: 60 },
61
- 'o1-mini': { input: 3, output: 12 },
62
- 'o1-pro': { input: 150, output: 600 },
63
- 'o3': { input: 10, output: 40 },
64
- 'o3-mini': { input: 1.1, output: 4.4 },
65
- 'o4-mini': { input: 1.1, output: 4.4 }
66
- };
67
-
68
- const OPENCODE_BASE_PRICING = DEFAULT_CONFIG.pricing.opencode || DEFAULT_CONFIG.pricing.codex;
69
41
  const CLAUDE_SESSION_USER_ID_TTL_MS = 60 * 60 * 1000;
70
42
  const CLAUDE_SESSION_USER_ID_CACHE_MAX = 2000;
71
43
  const claudeSessionUserIdCache = new Map();
@@ -74,43 +46,9 @@ const CLAUDE_USER_ID_FULL_RE = /^user_[0-9a-f]{64}_account__session_[a-z0-9._-]+
74
46
  let cachedClaudeAccountId = '';
75
47
  let cachedClaudeUserId = '';
76
48
 
77
- // detectModelTier, redirectModel, resolveTargetUrl imported from services/base/proxy-utils
49
+ // detectModelTier, redirectModel, resolveTargetUrl imported from shared/proxy-utils
78
50
  const resolveOpenCodeTarget = resolveTargetUrl;
79
51
 
80
- /**
81
- * 计算请求成本
82
- */
83
- function calculateCost(model, tokens) {
84
- let fallbackPricing = PRICING[model];
85
- if (!fallbackPricing) {
86
- const modelLower = String(model || '').toLowerCase();
87
- if (modelLower.includes('gpt-4o-mini')) {
88
- fallbackPricing = PRICING['gpt-4o-mini'];
89
- } else if (modelLower.includes('gpt-4o')) {
90
- fallbackPricing = PRICING['gpt-4o'];
91
- } else if (modelLower.includes('gpt-4')) {
92
- fallbackPricing = PRICING['gpt-4'];
93
- } else if (modelLower.includes('gpt-3.5')) {
94
- fallbackPricing = PRICING['gpt-3.5-turbo'];
95
- } else if (modelLower.includes('o1-mini')) {
96
- fallbackPricing = PRICING['o1-mini'];
97
- } else if (modelLower.includes('o1-pro')) {
98
- fallbackPricing = PRICING['o1-pro'];
99
- } else if (modelLower.includes('o1')) {
100
- fallbackPricing = PRICING['o1'];
101
- } else if (modelLower.includes('o3-mini')) {
102
- fallbackPricing = PRICING['o3-mini'];
103
- } else if (modelLower.includes('o3')) {
104
- fallbackPricing = PRICING['o3'];
105
- } else if (modelLower.includes('o4-mini')) {
106
- fallbackPricing = PRICING['o4-mini'];
107
- }
108
- }
109
-
110
- const pricing = resolveModelPricing('opencode', model, fallbackPricing, OPENCODE_BASE_PRICING);
111
- return calculateTokenCost(pricing, tokens, OPENCODE_BASE_PRICING);
112
- }
113
-
114
52
  const jsonBodyParser = express.json({
115
53
  limit: '100mb',
116
54
  verify: (req, res, buf) => {
@@ -932,59 +870,12 @@ function reportOpenCodeGatewayFailure({
932
870
  recordFailure(channel.id, 'opencode', error);
933
871
  }
934
872
 
935
- publishFailureLog({
936
- source: 'opencode',
937
- metadata: (req && requestMetadata.get(req)) || {
938
- channel: channel?.name,
939
- channelId: channel?.id,
940
- model: model || req?.body?.model
941
- },
942
- channel: channel?.name,
943
- model: model || req?.body?.model || '',
944
- message,
945
- error,
946
- statusCode,
947
- stage,
948
- broadcastLog
949
- });
950
-
951
873
  if (!res.headersSent) {
952
874
  sendOpenAiStyleError(res, statusCode, message, type);
953
875
  }
954
876
  return true;
955
877
  }
956
878
 
957
- function publishOpenCodeUsageLog({ requestId, channel, model, usage, startTime }) {
958
- const parsedUsage = parseNonStreamingUsage({
959
- model: model || '',
960
- usage: usage && typeof usage === 'object' ? usage : {}
961
- });
962
- const parsedTokens = parsedUsage.tokens || {};
963
-
964
- return publishUsageLog({
965
- source: 'opencode',
966
- metadata: {
967
- id: requestId,
968
- channel: channel?.name,
969
- channelId: channel?.id,
970
- startTime
971
- },
972
- model: parsedUsage.model || model || '',
973
- tokens: {
974
- input: Number(parsedTokens.input || 0),
975
- output: Number(parsedTokens.output || 0),
976
- cacheCreation: Number(parsedTokens.cacheCreation || 0),
977
- cacheRead: Number(parsedTokens.cacheRead || 0),
978
- cached: Number(parsedTokens.cached || 0),
979
- reasoning: Number(parsedTokens.reasoning || 0),
980
- total: Number(parsedTokens.total || 0)
981
- },
982
- calculateCost,
983
- broadcastLog,
984
- recordRequest: recordOpenCodeRequest
985
- });
986
- }
987
-
988
879
  function setSseHeaders(res) {
989
880
  res.status(200);
990
881
  res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
@@ -1942,8 +1833,6 @@ async function handleClaudeGatewayRequest(req, res, channel, effectiveKey) {
1942
1833
  });
1943
1834
  }
1944
1835
 
1945
- const requestId = `opencode-${Date.now()}-${Math.random()}`;
1946
- const startTime = Date.now();
1947
1836
  const originalPayload = (req.body && typeof req.body === 'object') ? req.body : {};
1948
1837
  const wantsStream = !!originalPayload.stream;
1949
1838
  const streamResponses = wantsStream && isResponsesPath(pathname);
@@ -2019,13 +1908,6 @@ async function handleClaudeGatewayRequest(req, res, channel, effectiveKey) {
2019
1908
 
2020
1909
  try {
2021
1910
  const streamedResponseObject = await relayClaudeResponsesStream(streamUpstream.response, res, originalPayload.model || '');
2022
- publishOpenCodeUsageLog({
2023
- requestId,
2024
- channel,
2025
- model: streamedResponseObject?.model || originalPayload.model || '',
2026
- usage: streamedResponseObject?.usage || {},
2027
- startTime
2028
- });
2029
1911
  recordSuccess(channel.id, 'opencode');
2030
1912
  } catch (error) {
2031
1913
  reportOpenCodeGatewayFailure({
@@ -2100,31 +1982,16 @@ async function handleClaudeGatewayRequest(req, res, channel, effectiveKey) {
2100
1982
  } else {
2101
1983
  res.json(responseObject);
2102
1984
  }
2103
- publishOpenCodeUsageLog({
2104
- requestId,
2105
- channel,
2106
- model: responseObject.model,
2107
- usage: responseObject.usage,
2108
- startTime
2109
- });
2110
1985
  recordSuccess(channel.id, 'opencode');
2111
1986
  return true;
2112
1987
  }
2113
1988
 
2114
1989
  const chatResponseObject = buildOpenAiChatCompletionsObject(parsedBody, originalPayload.model);
2115
- const loggingUsage = buildOpenAiResponsesObject(parsedBody, originalPayload.model).usage;
2116
1990
  if (wantsStream) {
2117
1991
  sendChatCompletionsSse(res, chatResponseObject);
2118
1992
  } else {
2119
1993
  res.json(chatResponseObject);
2120
1994
  }
2121
- publishOpenCodeUsageLog({
2122
- requestId,
2123
- channel,
2124
- model: chatResponseObject.model,
2125
- usage: loggingUsage,
2126
- startTime
2127
- });
2128
1995
  recordSuccess(channel.id, 'opencode');
2129
1996
  return true;
2130
1997
  }
@@ -2146,8 +2013,6 @@ async function handleCodexGatewayRequest(req, res, channel, effectiveKey) {
2146
2013
  });
2147
2014
  }
2148
2015
 
2149
- const requestId = `opencode-${Date.now()}-${Math.random()}`;
2150
- const startTime = Date.now();
2151
2016
  const originalPayload = (req.body && typeof req.body === 'object') ? req.body : {};
2152
2017
  const wantsStream = !!originalPayload.stream;
2153
2018
  const sessionId = extractSessionIdFromRequest(req, originalPayload);
@@ -2230,13 +2095,6 @@ async function handleCodexGatewayRequest(req, res, channel, effectiveKey) {
2230
2095
  try {
2231
2096
  if (wantsStream) {
2232
2097
  const completedResponse = await relayCodexResponsesStream(streamUpstream.response, res, originalPayload);
2233
- publishOpenCodeUsageLog({
2234
- requestId,
2235
- channel,
2236
- model: completedResponse?.model || targetModel,
2237
- usage: completedResponse?.usage || {},
2238
- startTime
2239
- });
2240
2098
  recordSuccess(channel.id, 'opencode');
2241
2099
  return true;
2242
2100
  }
@@ -2255,13 +2113,6 @@ async function handleCodexGatewayRequest(req, res, channel, effectiveKey) {
2255
2113
  });
2256
2114
  }
2257
2115
  res.json(responseObject);
2258
- publishOpenCodeUsageLog({
2259
- requestId,
2260
- channel,
2261
- model: responseObject.model || targetModel,
2262
- usage: responseObject.usage || {},
2263
- startTime
2264
- });
2265
2116
  recordSuccess(channel.id, 'opencode');
2266
2117
  return true;
2267
2118
  } catch (error) {
@@ -2950,8 +2801,6 @@ async function handleGeminiGatewayRequest(req, res, channel, effectiveKey) {
2950
2801
  });
2951
2802
  }
2952
2803
 
2953
- const requestId = `opencode-${Date.now()}-${Math.random()}`;
2954
- const startTime = Date.now();
2955
2804
  const originalPayload = (req.body && typeof req.body === 'object') ? req.body : {};
2956
2805
  const wantsStream = !!originalPayload.stream;
2957
2806
  const streamResponses = wantsStream && isResponsesPath(pathname);
@@ -3049,13 +2898,6 @@ async function handleGeminiGatewayRequest(req, res, channel, effectiveKey) {
3049
2898
 
3050
2899
  try {
3051
2900
  const streamedResponseObject = await relayGeminiResponsesStream(streamUpstream.response, res, originalPayload.model || targetModel);
3052
- publishOpenCodeUsageLog({
3053
- requestId,
3054
- channel,
3055
- model: streamedResponseObject?.model || originalPayload.model || targetModel || '',
3056
- usage: streamedResponseObject?.usage || {},
3057
- startTime
3058
- });
3059
2901
  recordSuccess(channel.id, 'opencode');
3060
2902
  } catch (error) {
3061
2903
  reportOpenCodeGatewayFailure({
@@ -3126,31 +2968,16 @@ async function handleGeminiGatewayRequest(req, res, channel, effectiveKey) {
3126
2968
  if (isResponsesPath(pathname)) {
3127
2969
  const responseObject = buildOpenAiResponsesObjectFromGemini(parsedBody, targetModel);
3128
2970
  res.json(responseObject);
3129
- publishOpenCodeUsageLog({
3130
- requestId,
3131
- channel,
3132
- model: responseObject.model,
3133
- usage: responseObject.usage,
3134
- startTime
3135
- });
3136
2971
  recordSuccess(channel.id, 'opencode');
3137
2972
  return true;
3138
2973
  }
3139
2974
 
3140
2975
  const chatResponseObject = buildOpenAiChatCompletionsObjectFromGemini(parsedBody, targetModel);
3141
- const loggingUsage = buildOpenAiResponsesObjectFromGemini(parsedBody, targetModel).usage;
3142
2976
  if (wantsStream) {
3143
2977
  sendChatCompletionsSse(res, chatResponseObject);
3144
2978
  } else {
3145
2979
  res.json(chatResponseObject);
3146
2980
  }
3147
- publishOpenCodeUsageLog({
3148
- requestId,
3149
- channel,
3150
- model: chatResponseObject.model,
3151
- usage: loggingUsage,
3152
- startTime
3153
- });
3154
2981
  recordSuccess(channel.id, 'opencode');
3155
2982
  return true;
3156
2983
  }
@@ -3306,14 +3133,6 @@ async function startOpenCodeProxyServer(options = {}) {
3306
3133
  if (!effectiveKey) {
3307
3134
  releaseChannel(channel.id, 'opencode');
3308
3135
  broadcastSchedulerState('opencode', getSchedulerState('opencode'));
3309
- publishFailureLog({
3310
- source: 'opencode',
3311
- channel: channel.name,
3312
- message: 'API key not configured or expired. Please update your channel key.',
3313
- statusCode: 401,
3314
- stage: 'preflight',
3315
- broadcastLog
3316
- });
3317
3136
  return res.status(401).json({
3318
3137
  error: {
3319
3138
  message: 'API key not configured or expired. Please update your channel key.',
@@ -3422,20 +3241,6 @@ async function startOpenCodeProxyServer(options = {}) {
3422
3241
  release();
3423
3242
  if (err) {
3424
3243
  recordFailure(channel.id, 'opencode', err);
3425
- const metadata = requestMetadata.get(req) || {
3426
- channel: channel.name,
3427
- channelId: channel.id,
3428
- startTime: Date.now()
3429
- };
3430
- publishFailureLog({
3431
- source: 'opencode',
3432
- metadata,
3433
- message: err.message,
3434
- error: err,
3435
- statusCode: 502,
3436
- stage: 'proxy_web',
3437
- broadcastLog
3438
- });
3439
3244
  console.error('OpenCode proxy error:', err);
3440
3245
  if (res && !res.headersSent) {
3441
3246
  res.status(502).json({
@@ -3449,13 +3254,6 @@ async function startOpenCodeProxyServer(options = {}) {
3449
3254
  });
3450
3255
  } catch (error) {
3451
3256
  console.error('OpenCode channel allocation error:', error);
3452
- publishFailureLog({
3453
- source: 'opencode',
3454
- message: error.message || 'No OpenCode channel available',
3455
- statusCode: 503,
3456
- stage: 'allocate_channel',
3457
- broadcastLog
3458
- });
3459
3257
  if (!res.headersSent) {
3460
3258
  res.status(503).json({
3461
3259
  error: {
@@ -3467,154 +3265,35 @@ async function startOpenCodeProxyServer(options = {}) {
3467
3265
  }
3468
3266
  });
3469
3267
 
3470
- // 监听代理响应 (OpenAI 格式)
3268
+ // 代理响应只负责维护传输健康状态;实时日志和 usage 来自 CLI 原生日志。
3471
3269
  proxy.on('proxyRes', (proxyRes, req, res) => {
3472
3270
  const metadata = requestMetadata.get(req);
3473
- if (!metadata) {
3474
- return;
3475
- }
3271
+ if (!metadata) return;
3476
3272
 
3477
- // 检查响应是否已关闭
3478
3273
  if (res.writableEnded || res.destroyed) {
3479
3274
  requestMetadata.delete(req);
3480
3275
  return;
3481
3276
  }
3482
3277
 
3483
- // 标记响应是否已关闭
3484
- let isResponseClosed = false;
3485
-
3486
- // 监听响应关闭事件
3487
- res.on('close', () => {
3488
- isResponseClosed = true;
3489
- requestMetadata.delete(req);
3490
- });
3491
-
3492
- // 监听响应错误事件
3278
+ res.on('close', () => requestMetadata.delete(req));
3493
3279
  res.on('error', (err) => {
3494
- isResponseClosed = true;
3495
- // 忽略客户端断开连接的常见错误
3496
- if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') {
3497
- console.error('Response error:', err);
3498
- }
3280
+ if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') console.error('Response error:', err);
3281
+ recordFailure(metadata.channelId, 'opencode', err);
3499
3282
  requestMetadata.delete(req);
3500
3283
  });
3501
3284
 
3502
- let buffer = '';
3503
- let tokenData = createTokenData();
3504
- let usageRecorded = false;
3505
-
3506
- function recordUsageIfReady() {
3507
- if (usageRecorded) {
3508
- return false;
3509
- }
3510
-
3511
- const result = publishUsageLog({
3512
- source: 'opencode',
3513
- metadata,
3514
- model: tokenData.model,
3515
- tokens: {
3516
- input: tokenData.inputTokens,
3517
- output: tokenData.outputTokens,
3518
- cacheCreation: tokenData.cacheCreation,
3519
- cacheRead: tokenData.cacheRead,
3520
- cached: tokenData.cachedTokens,
3521
- reasoning: tokenData.reasoningTokens,
3522
- total: tokenData.totalTokens
3523
- },
3524
- calculateCost,
3525
- broadcastLog,
3526
- recordRequest: recordOpenCodeRequest,
3527
- recordSuccess,
3528
- allowBroadcast: true
3529
- });
3530
-
3531
- if (!result) {
3532
- return false;
3533
- }
3534
-
3535
- usageRecorded = true;
3536
- return true;
3537
- }
3538
-
3539
- proxyRes.on('data', (chunk) => {
3540
- if (isResponseClosed) {
3541
- return;
3542
- }
3543
-
3544
- buffer += chunk.toString();
3545
-
3546
- // 检查是否是 SSE 流
3547
- if (proxyRes.headers['content-type']?.includes('text/event-stream')) {
3548
- const events = buffer.split('\n\n');
3549
- buffer = events.pop() || '';
3550
-
3551
- events.forEach((eventText) => {
3552
- if (!eventText.trim()) return;
3553
-
3554
- try {
3555
- const lines = eventText.split('\n');
3556
- let eventType = '';
3557
- let data = '';
3558
-
3559
- lines.forEach(line => {
3560
- if (line.startsWith('event:')) {
3561
- eventType = line.substring(6).trim();
3562
- } else if (line.startsWith('data:')) {
3563
- data = line.substring(5).trim();
3564
- }
3565
- });
3566
-
3567
- if (!data || data === '[DONE]') return;
3568
-
3569
- const parsed = JSON.parse(data);
3570
- const usage = parseSSEUsage(parsed, eventType);
3571
- mergeUsageIntoTokenData(tokenData, usage);
3572
-
3573
- if (usage.isDone) {
3574
- recordUsageIfReady();
3575
- }
3576
- } catch (err) {
3577
- // 忽略解析错误
3578
- }
3579
- });
3580
- }
3581
- });
3582
-
3285
+ const statusCode = Number(proxyRes.statusCode) || 200;
3583
3286
  proxyRes.on('end', () => {
3584
- // 如果不是流式响应,尝试从完整响应中解析
3585
- if (!proxyRes.headers['content-type']?.includes('text/event-stream')) {
3586
- try {
3587
- const parsed = JSON.parse(buffer);
3588
- const usage = parseNonStreamingUsage(parsed);
3589
- mergeUsageIntoTokenData(tokenData, usage);
3590
- } catch (err) {
3591
- // 忽略解析错误
3592
- }
3593
- }
3594
-
3595
- recordUsageIfReady();
3596
-
3597
- if (!isResponseClosed) {
3598
- requestMetadata.delete(req);
3287
+ if (statusCode >= 400) {
3288
+ recordFailure(metadata.channelId, 'opencode', new Error(`OpenCode upstream HTTP ${statusCode}`));
3289
+ } else {
3290
+ recordSuccess(metadata.channelId, 'opencode');
3599
3291
  }
3292
+ requestMetadata.delete(req);
3600
3293
  });
3601
-
3602
3294
  proxyRes.on('error', (err) => {
3603
- // 忽略代理响应错误(可能是网络问题)
3604
- if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') {
3605
- console.error('Proxy response error:', err);
3606
- }
3607
- isResponseClosed = true;
3295
+ if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') console.error('Proxy response error:', err);
3608
3296
  recordFailure(metadata.channelId, 'opencode', err);
3609
- publishFailureLog({
3610
- source: 'opencode',
3611
- metadata,
3612
- message: err.message,
3613
- error: err,
3614
- statusCode: proxyRes.statusCode,
3615
- stage: 'response_stream',
3616
- broadcastLog
3617
- });
3618
3297
  requestMetadata.delete(req);
3619
3298
  });
3620
3299
  });
@@ -3627,19 +3306,6 @@ async function startOpenCodeProxyServer(options = {}) {
3627
3306
  releaseChannel(req.selectedChannel.id, 'opencode');
3628
3307
  broadcastSchedulerState('opencode', getSchedulerState('opencode'));
3629
3308
  }
3630
- publishFailureLog({
3631
- source: 'opencode',
3632
- metadata: (req && requestMetadata.get(req)) || {
3633
- channel: req?.selectedChannel?.name,
3634
- channelId: req?.selectedChannel?.id,
3635
- model: req?.body?.model
3636
- },
3637
- message: err.message,
3638
- error: err,
3639
- statusCode: 502,
3640
- stage: 'proxy',
3641
- broadcastLog
3642
- });
3643
3309
  if (res && !res.headersSent) {
3644
3310
  res.status(502).json({
3645
3311
  error: {
@@ -3753,5 +3419,4 @@ module.exports = {
3753
3419
  getOpenCodeProxyStatus,
3754
3420
  clearOpenCodeRedirectCache,
3755
3421
  collectProxyModelList,
3756
- calculateCost
3757
3422
  };
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ const { createProxyDriver } = require('../../../shared/proxy-driver');
4
+
5
+ function createDriver(context = {}) {
6
+ return createProxyDriver({
7
+ ...context,
8
+ platform: 'opencode',
9
+ servicePath: './opencode/proxy-implementation',
10
+ localServicePath: '../opencode/proxy-implementation',
11
+ exports: { status: 'getOpenCodeProxyStatus', start: 'startOpenCodeProxyServer', stop: 'stopOpenCodeProxyServer' },
12
+ cliMetadata: { defaultPort: 20091 }
13
+ });
14
+ }
15
+
16
+ module.exports = { createDriver };
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const { createResourceSyncDriver } = require('../../../shared/driver-factories/resource-sync');
4
+
5
+ function createDriver(context = {}) {
6
+ return createResourceSyncDriver({ ...context, platform: 'opencode' });
7
+ }
8
+
9
+ module.exports = { createDriver };