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
@@ -1,945 +0,0 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const crypto = require('crypto');
4
- const { PATHS } = require('../../config/paths');
5
- const claudeSettingsManager = require('./settings-manager');
6
- const codexSettingsManager = require('./codex-settings-manager');
7
- const geminiSettingsManager = require('./gemini-settings-manager');
8
- const opencodeSettingsManager = require('./opencode-settings-manager');
9
- const {
10
- SUPPORTED_TOOLS,
11
- fingerprintFor,
12
- inspectTool,
13
- readAllNativeOAuth,
14
- clearNativeOAuth,
15
- disableNativeOAuthCredential,
16
- applyOAuthCredential
17
- } = require('./native-oauth-adapters');
18
- const { maskToken, decodeJwtPayload, removeFileIfExists } = require('./oauth-utils');
19
-
20
- function createEmptyStore() {
21
- return {
22
- version: 1,
23
- tools: Object.fromEntries(SUPPORTED_TOOLS.map((tool) => [tool, {
24
- defaultCredentialId: null,
25
- credentials: []
26
- }]))
27
- };
28
- }
29
-
30
- function ensureStoreDir() {
31
- fs.mkdirSync(path.dirname(PATHS.oauthCredentials), { recursive: true });
32
- }
33
-
34
- function readStore() {
35
- ensureStoreDir();
36
- if (!fs.existsSync(PATHS.oauthCredentials)) {
37
- return createEmptyStore();
38
- }
39
-
40
- try {
41
- const payload = JSON.parse(fs.readFileSync(PATHS.oauthCredentials, 'utf8'));
42
- const next = createEmptyStore();
43
- if (payload && typeof payload === 'object' && payload.tools && typeof payload.tools === 'object') {
44
- SUPPORTED_TOOLS.forEach((tool) => {
45
- const rawToolData = payload.tools[tool];
46
- if (!rawToolData || typeof rawToolData !== 'object') {
47
- return;
48
- }
49
- next.tools[tool] = {
50
- defaultCredentialId: rawToolData.defaultCredentialId || null,
51
- credentials: Array.isArray(rawToolData.credentials) ? rawToolData.credentials : []
52
- };
53
- });
54
- }
55
- return next;
56
- } catch {
57
- return createEmptyStore();
58
- }
59
- }
60
-
61
- function writeStore(store) {
62
- ensureStoreDir();
63
- fs.writeFileSync(PATHS.oauthCredentials, JSON.stringify(store, null, 2), 'utf8');
64
- if (process.platform !== 'win32') {
65
- try {
66
- fs.chmodSync(PATHS.oauthCredentials, 0o600);
67
- } catch {
68
- // ignore chmod failures
69
- }
70
- }
71
- }
72
-
73
- function assertSupportedTool(tool) {
74
- if (!SUPPORTED_TOOLS.includes(tool)) {
75
- throw new Error(`Unsupported OAuth tool: ${tool}`);
76
- }
77
- }
78
-
79
- function safeString(value) {
80
- return String(value || '').trim();
81
- }
82
-
83
- function safeNumber(value) {
84
- const num = Number(value);
85
- return Number.isFinite(num) && num > 0 ? num : null;
86
- }
87
-
88
- function tryParseJson(text) {
89
- try {
90
- return JSON.parse(text);
91
- } catch {
92
- return null;
93
- }
94
- }
95
-
96
- function extractEnvValue(text, key) {
97
- const pattern = new RegExp(`${key}\\s*=\\s*([^\\n\\r]+)`);
98
- const match = String(text || '').match(pattern);
99
- return match ? safeString(match[1]).replace(/^['"]|['"]$/g, '') : '';
100
- }
101
-
102
- function parseClaudeImport(rawText) {
103
- const text = safeString(rawText);
104
- const parsed = tryParseJson(text);
105
- const payload = parsed?.claudeAiOauth && typeof parsed.claudeAiOauth === 'object'
106
- ? parsed.claudeAiOauth
107
- : parsed;
108
-
109
- if (payload && typeof payload === 'object') {
110
- const accessToken = safeString(
111
- payload.accessToken
112
- || payload.access_token
113
- || payload.authToken
114
- || payload.token
115
- );
116
- if (!accessToken) {
117
- throw new Error('Claude OAuth 导入缺少 accessToken。');
118
- }
119
- return {
120
- accessToken,
121
- refreshToken: safeString(payload.refreshToken || payload.refresh_token),
122
- expiresAt: safeNumber(payload.expiresAt || payload.expiry_date || payload.expiryDate),
123
- primaryToken: accessToken
124
- };
125
- }
126
-
127
- const envToken = extractEnvValue(text, 'ANTHROPIC_AUTH_TOKEN')
128
- || extractEnvValue(text, 'CLAUDE_CODE_OAUTH_TOKEN');
129
- if (envToken) {
130
- return {
131
- accessToken: envToken,
132
- refreshToken: '',
133
- expiresAt: null,
134
- primaryToken: envToken
135
- };
136
- }
137
-
138
- if (!text.includes('\n') && !text.includes(' ')) {
139
- return {
140
- accessToken: text,
141
- refreshToken: '',
142
- expiresAt: null,
143
- primaryToken: text
144
- };
145
- }
146
-
147
- throw new Error('无法识别 Claude OAuth 导入格式。');
148
- }
149
-
150
- function parseCodexImport(rawText) {
151
- const parsed = tryParseJson(rawText);
152
- if (!parsed || typeof parsed !== 'object') {
153
- throw new Error('Codex OAuth 仅支持 JSON 导入。');
154
- }
155
-
156
- const authPayload = parsed.tokens ? parsed : {
157
- auth_mode: parsed.auth_mode || 'chatgpt',
158
- tokens: parsed
159
- };
160
- const tokens = authPayload.tokens && typeof authPayload.tokens === 'object'
161
- ? authPayload.tokens
162
- : null;
163
-
164
- if (!tokens?.access_token) {
165
- throw new Error('Codex OAuth 导入缺少 tokens.access_token。');
166
- }
167
-
168
- const idTokenPayload = decodeJwtPayload(tokens.id_token);
169
- return {
170
- authMode: safeString(authPayload.auth_mode || 'chatgpt') || 'chatgpt',
171
- accessToken: safeString(tokens.access_token),
172
- refreshToken: safeString(tokens.refresh_token),
173
- idToken: safeString(tokens.id_token),
174
- accountId: safeString(tokens.account_id),
175
- accountEmail: safeString(idTokenPayload?.email),
176
- lastRefresh: authPayload.last_refresh || null,
177
- primaryToken: safeString(tokens.access_token)
178
- };
179
- }
180
-
181
- function parseGeminiImport(rawText) {
182
- const parsed = tryParseJson(rawText);
183
- if (!parsed || typeof parsed !== 'object') {
184
- throw new Error('Gemini OAuth 仅支持 JSON 导入。');
185
- }
186
-
187
- const payload = parsed.token && typeof parsed.token === 'object'
188
- ? parsed
189
- : parsed.access_token
190
- ? {
191
- token: {
192
- accessToken: parsed.access_token,
193
- refreshToken: parsed.refresh_token || '',
194
- tokenType: parsed.token_type || 'Bearer',
195
- scope: parsed.scope || '',
196
- expiresAt: parsed.expiry_date || null
197
- }
198
- }
199
- : null;
200
-
201
- if (!payload?.token?.accessToken) {
202
- throw new Error('Gemini OAuth 导入缺少 access_token。');
203
- }
204
-
205
- return {
206
- accessToken: safeString(payload.token.accessToken),
207
- refreshToken: safeString(payload.token.refreshToken),
208
- tokenType: safeString(payload.token.tokenType || 'Bearer') || 'Bearer',
209
- scope: safeString(payload.token.scope),
210
- expiresAt: safeNumber(payload.token.expiresAt),
211
- accountEmail: safeString(parsed.accountEmail || parsed.email),
212
- primaryToken: safeString(payload.token.accessToken)
213
- };
214
- }
215
-
216
- function parseOpenCodeImport(rawText) {
217
- const parsed = tryParseJson(rawText);
218
- if (!parsed || typeof parsed !== 'object') {
219
- throw new Error('OpenCode OAuth 仅支持 JSON 导入。');
220
- }
221
-
222
- const oauthEntry = parsed.openai && typeof parsed.openai === 'object'
223
- ? ['openai', parsed.openai]
224
- : Object.entries(parsed).find(([, value]) => value && typeof value === 'object' && value.type === 'oauth')
225
- || [parsed.providerId || 'openai', parsed];
226
- const providerId = safeString(oauthEntry[0]) || 'openai';
227
- const payload = oauthEntry[1];
228
- if (payload.type !== 'oauth' && !payload.access) {
229
- throw new Error('OpenCode OAuth 导入缺少 access 或 openai.oauth 结构。');
230
- }
231
-
232
- return {
233
- providerId,
234
- accessToken: safeString(payload.access),
235
- refreshToken: safeString(payload.refresh),
236
- expiresAt: safeNumber(payload.expires),
237
- accountId: safeString(payload.accountId),
238
- enterpriseUrl: safeString(payload.enterpriseUrl),
239
- primaryToken: safeString(payload.access)
240
- };
241
- }
242
-
243
- function pickOmpCredentialEntry(parsed) {
244
- if (Array.isArray(parsed)) {
245
- return parsed.find(item => item && typeof item === 'object') || null;
246
- }
247
- if (!parsed || typeof parsed !== 'object') {
248
- return null;
249
- }
250
- if (parsed.provider || parsed.providerId || parsed.provider_id || parsed.providerKey || parsed.credential_type || parsed.data) {
251
- return parsed;
252
- }
253
- const entry = Object.entries(parsed).find(([, value]) => value && typeof value === 'object');
254
- return entry ? { provider: entry[0], ...entry[1] } : parsed;
255
- }
256
-
257
- function parseOmpImport(rawText) {
258
- const parsed = tryParseJson(rawText);
259
- if (!parsed || typeof parsed !== 'object') {
260
- throw new Error('OMP OAuth 仅支持 JSON 导入。');
261
- }
262
-
263
- const entry = pickOmpCredentialEntry(parsed);
264
- if (!entry || typeof entry !== 'object') {
265
- throw new Error('OMP OAuth 导入缺少 provider。');
266
- }
267
-
268
- const data = entry.data && typeof entry.data === 'object' ? entry.data : entry;
269
- const providerId = safeString(
270
- entry.providerId
271
- || entry.provider_id
272
- || entry.providerKey
273
- || entry.provider
274
- || data.providerId
275
- || data.provider
276
- );
277
- if (!providerId) {
278
- throw new Error('OMP OAuth 导入缺少 providerId。');
279
- }
280
-
281
- const accessToken = safeString(
282
- data.accessToken
283
- || data.access_token
284
- || data.access
285
- || data.token
286
- || data.authToken
287
- );
288
- const credentialType = safeString(entry.credentialType || entry.credential_type || data.type || 'oauth') || 'oauth';
289
- if (credentialType === 'oauth' && !accessToken && !entry.data) {
290
- throw new Error('OMP OAuth 导入缺少 access/accessToken。');
291
- }
292
-
293
- return {
294
- providerId,
295
- credentialType,
296
- accessToken,
297
- refreshToken: safeString(data.refreshToken || data.refresh_token || data.refresh),
298
- expiresAt: safeNumber(data.expiresAt || data.expiry_date || data.expiryDate || data.expires),
299
- accountId: safeString(data.accountId || data.account_id || entry.accountId || entry.account_id),
300
- accountEmail: safeString(data.accountEmail || data.email || entry.accountEmail || entry.email),
301
- identityKey: safeString(entry.identityKey || entry.identity_key || data.identityKey || data.identity_key),
302
- importPayload: parsed,
303
- primaryToken: accessToken
304
- };
305
- }
306
-
307
- function parseCredentialInput(tool, rawText) {
308
- switch (tool) {
309
- case 'claude':
310
- return parseClaudeImport(rawText);
311
- case 'codex':
312
- return parseCodexImport(rawText);
313
- case 'gemini':
314
- return parseGeminiImport(rawText);
315
- case 'opencode':
316
- return parseOpenCodeImport(rawText);
317
- case 'omp':
318
- return parseOmpImport(rawText);
319
- default:
320
- throw new Error(`Unsupported OAuth tool: ${tool}`);
321
- }
322
- }
323
-
324
- function buildCredentialName(tool, metadata, providedName = '') {
325
- const explicit = safeString(providedName);
326
- if (explicit) {
327
- return explicit;
328
- }
329
-
330
- if ((tool === 'opencode' || tool === 'omp') && safeString(metadata.providerId)) {
331
- const accountLabel = safeString(metadata.accountId || metadata.accountEmail);
332
- return accountLabel
333
- ? `${tool} - ${metadata.providerId} - ${accountLabel}`
334
- : `${tool} - ${metadata.providerId}`;
335
- }
336
-
337
- const accountLabel = safeString(metadata.accountId || metadata.accountEmail);
338
- if (accountLabel) {
339
- return `${tool} - ${accountLabel}`;
340
- }
341
-
342
- return `${tool} - ${new Date().toISOString().slice(0, 10)}`;
343
- }
344
-
345
- function sanitizeCredential(entry, defaultCredentialId) {
346
- const primaryToken = entry?.secrets?.primaryToken
347
- || entry?.secrets?.accessToken
348
- || entry?.secrets?.token
349
- || '';
350
-
351
- return {
352
- id: entry.id,
353
- tool: entry.tool,
354
- name: entry.name,
355
- source: entry.source,
356
- storage: entry.storage || '',
357
- providerId: entry.providerId || '',
358
- accountId: entry.accountId || '',
359
- accountEmail: entry.accountEmail || '',
360
- expiresAt: entry.expiresAt || null,
361
- lastRefresh: entry.lastRefresh || null,
362
- lastUsedAt: entry.lastUsedAt || null,
363
- createdAt: entry.createdAt,
364
- updatedAt: entry.updatedAt,
365
- tokenPreview: maskToken(primaryToken),
366
- isDefault: defaultCredentialId === entry.id
367
- };
368
- }
369
-
370
- function sanitizeNativeCredential(entry = {}) {
371
- const primaryToken = entry.primaryToken
372
- || entry.accessToken
373
- || entry.token
374
- || '';
375
-
376
- return {
377
- providerId: entry.providerId || '',
378
- accountId: entry.accountId || '',
379
- accountEmail: entry.accountEmail || '',
380
- expiresAt: entry.expiresAt || null,
381
- lastRefresh: entry.lastRefresh || null,
382
- storage: entry.storage || '',
383
- tokenPreview: maskToken(primaryToken)
384
- };
385
- }
386
-
387
- function sanitizeToolSummary(tool, toolStore) {
388
- const credentials = (toolStore.credentials || [])
389
- .map((entry) => sanitizeCredential(entry, toolStore.defaultCredentialId))
390
- .sort((a, b) => {
391
- const aTime = a.lastUsedAt || 0;
392
- const bTime = b.lastUsedAt || 0;
393
- if (aTime !== bTime) return bTime - aTime;
394
- return (b.createdAt || 0) - (a.createdAt || 0);
395
- });
396
- const nativeState = inspectTool(tool);
397
- const nativeCredentials = readAllNativeOAuth(tool).map((entry) => sanitizeNativeCredential(entry));
398
- return {
399
- tool,
400
- defaultCredentialId: toolStore.defaultCredentialId || null,
401
- credentials,
402
- nativeState: {
403
- ...nativeState,
404
- nativeCredentials
405
- }
406
- };
407
- }
408
-
409
- function getToolStore(store, tool) {
410
- assertSupportedTool(tool);
411
- if (!store.tools[tool]) {
412
- store.tools[tool] = { defaultCredentialId: null, credentials: [] };
413
- }
414
- return store.tools[tool];
415
- }
416
-
417
- function extractSecrets(tool, metadata) {
418
- // 只保留真正的 secret 字段,不污染非敏感数据
419
- switch (tool) {
420
- case 'claude':
421
- return {
422
- accessToken: metadata.accessToken || '',
423
- refreshToken: metadata.refreshToken || '',
424
- expiresAt: metadata.expiresAt || null,
425
- primaryToken: metadata.primaryToken || metadata.accessToken || ''
426
- };
427
- case 'codex':
428
- return {
429
- authMode: metadata.authMode || 'chatgpt',
430
- accessToken: metadata.accessToken || '',
431
- refreshToken: metadata.refreshToken || '',
432
- idToken: metadata.idToken || '',
433
- accountId: metadata.accountId || '',
434
- lastRefresh: metadata.lastRefresh || null,
435
- primaryToken: metadata.primaryToken || metadata.accessToken || ''
436
- };
437
- case 'gemini':
438
- return {
439
- accessToken: metadata.accessToken || '',
440
- refreshToken: metadata.refreshToken || '',
441
- tokenType: metadata.tokenType || 'Bearer',
442
- scope: metadata.scope || '',
443
- expiresAt: metadata.expiresAt || null,
444
- primaryToken: metadata.primaryToken || metadata.accessToken || ''
445
- };
446
- case 'opencode':
447
- return {
448
- accessToken: metadata.accessToken || '',
449
- refreshToken: metadata.refreshToken || '',
450
- expiresAt: metadata.expiresAt || null,
451
- accountId: metadata.accountId || '',
452
- enterpriseUrl: metadata.enterpriseUrl || '',
453
- primaryToken: metadata.primaryToken || metadata.accessToken || ''
454
- };
455
- case 'omp':
456
- return {
457
- providerId: metadata.providerId || '',
458
- credentialType: metadata.credentialType || 'oauth',
459
- accessToken: metadata.accessToken || '',
460
- refreshToken: metadata.refreshToken || '',
461
- expiresAt: metadata.expiresAt || null,
462
- accountId: metadata.accountId || '',
463
- accountEmail: metadata.accountEmail || '',
464
- identityKey: metadata.identityKey || '',
465
- importPayload: metadata.importPayload || null,
466
- primaryToken: metadata.primaryToken || metadata.accessToken || ''
467
- };
468
- default:
469
- return { primaryToken: metadata.primaryToken || metadata.accessToken || '' };
470
- }
471
- }
472
-
473
- function stableFingerprintValue(tool, metadata) {
474
- // 优先使用稳定标识符,避免 access token 轮换导致重复记录
475
- const stableId = metadata.accountEmail
476
- || metadata.accountId
477
- || ((tool === 'opencode' || tool === 'omp') ? metadata.providerId : '')
478
- || metadata.refreshToken
479
- || metadata.primaryToken
480
- || metadata.accessToken
481
- || '';
482
- return stableId;
483
- }
484
-
485
- function resolveFingerprintValue(tool, metadata, options = {}) {
486
- if (options.fingerprintMode === 'primary-token') {
487
- return metadata.primaryToken
488
- || metadata.accessToken
489
- || stableFingerprintValue(tool, metadata);
490
- }
491
- return stableFingerprintValue(tool, metadata);
492
- }
493
-
494
- function upsertCredential(tool, metadata, options = {}) {
495
- const store = readStore();
496
- const toolStore = getToolStore(store, tool);
497
- const now = Date.now();
498
- const primaryToken = metadata.primaryToken || metadata.accessToken || '';
499
- const fingerprint = fingerprintFor(tool, resolveFingerprintValue(tool, metadata, options));
500
- const existingIndex = toolStore.credentials.findIndex((item) => item.fingerprint === fingerprint);
501
- const existing = existingIndex >= 0 ? toolStore.credentials[existingIndex] : null;
502
-
503
- const entry = {
504
- id: existing?.id || crypto.randomUUID(),
505
- tool,
506
- name: buildCredentialName(tool, metadata, options.name),
507
- source: options.source || existing?.source || 'manual',
508
- storage: metadata.storage || existing?.storage || '',
509
- providerId: metadata.providerId || existing?.providerId || '',
510
- accountId: metadata.accountId || existing?.accountId || '',
511
- accountEmail: metadata.accountEmail || existing?.accountEmail || '',
512
- expiresAt: metadata.expiresAt || existing?.expiresAt || null,
513
- lastRefresh: metadata.lastRefresh || existing?.lastRefresh || null,
514
- createdAt: existing?.createdAt || now,
515
- updatedAt: now,
516
- fingerprint,
517
- secrets: extractSecrets(tool, { ...existing?.secrets, ...metadata, primaryToken })
518
- };
519
-
520
- if (existingIndex >= 0) {
521
- toolStore.credentials.splice(existingIndex, 1, entry);
522
- } else {
523
- toolStore.credentials.unshift(entry);
524
- }
525
-
526
- if (!toolStore.defaultCredentialId) {
527
- toolStore.defaultCredentialId = entry.id;
528
- }
529
-
530
- writeStore(store);
531
- return sanitizeCredential(entry, toolStore.defaultCredentialId);
532
- }
533
-
534
- function getAllToolSummaries() {
535
- const store = readStore();
536
- return Object.fromEntries(SUPPORTED_TOOLS.map((tool) => {
537
- const toolStore = getToolStore(store, tool);
538
- return [tool, sanitizeToolSummary(tool, toolStore)];
539
- }));
540
- }
541
-
542
- function getToolSummary(tool) {
543
- const store = readStore();
544
- const toolStore = getToolStore(store, tool);
545
- return sanitizeToolSummary(tool, toolStore);
546
- }
547
-
548
- function importCredential(tool, payload = {}) {
549
- assertSupportedTool(tool);
550
- const raw = safeString(payload.raw);
551
- if (!raw) {
552
- throw new Error('缺少导入内容。');
553
- }
554
-
555
- const metadata = parseCredentialInput(tool, raw);
556
- return upsertCredential(tool, metadata, {
557
- name: payload.name,
558
- source: payload.source || 'manual'
559
- });
560
- }
561
-
562
- function syncLocalCredential(tool) {
563
- assertSupportedTool(tool);
564
- const nativeCredentials = readAllNativeOAuth(tool);
565
- if (!nativeCredentials.length) {
566
- throw new Error('当前本地未检测到可同步的 OAuth 凭证。');
567
- }
568
-
569
- const credentials = nativeCredentials.map((metadata) => upsertCredential(tool, metadata, {
570
- source: 'synced-local',
571
- fingerprintMode: 'primary-token'
572
- }));
573
-
574
- return {
575
- credential: credentials[0] || null,
576
- credentials,
577
- summary: getToolSummary(tool)
578
- };
579
- }
580
-
581
- function setDefaultCredential(tool, credentialId) {
582
- const store = readStore();
583
- const toolStore = getToolStore(store, tool);
584
- const target = toolStore.credentials.find((item) => item.id === credentialId);
585
- if (!target) {
586
- throw new Error('OAuth 凭证不存在。');
587
- }
588
-
589
- toolStore.defaultCredentialId = credentialId;
590
- writeStore(store);
591
- return sanitizeToolSummary(tool, toolStore);
592
- }
593
-
594
- function deleteCredential(tool, credentialId) {
595
- const store = readStore();
596
- const toolStore = getToolStore(store, tool);
597
- const nextCredentials = toolStore.credentials.filter((item) => item.id !== credentialId);
598
- if (nextCredentials.length === toolStore.credentials.length) {
599
- throw new Error('OAuth 凭证不存在。');
600
- }
601
-
602
- toolStore.credentials = nextCredentials;
603
- if (toolStore.defaultCredentialId === credentialId) {
604
- toolStore.defaultCredentialId = nextCredentials[0]?.id || null;
605
- }
606
-
607
- writeStore(store);
608
- return sanitizeToolSummary(tool, toolStore);
609
- }
610
-
611
- function findStoredCredential(tool, credentialId) {
612
- const store = readStore();
613
- const toolStore = getToolStore(store, tool);
614
- const entry = toolStore.credentials.find((item) => item.id === credentialId);
615
- if (!entry) {
616
- throw new Error('OAuth 凭证不存在。');
617
- }
618
- return entry;
619
- }
620
-
621
- function cleanupManagedArtifacts(tool) {
622
- removeFileIfExists(PATHS.activeChannel?.[tool]);
623
-
624
- if (tool === 'claude') {
625
- claudeSettingsManager.deleteBackup?.();
626
- return;
627
- }
628
-
629
- if (tool === 'codex') {
630
- codexSettingsManager.deleteBackup?.();
631
- return;
632
- }
633
-
634
- if (tool === 'gemini') {
635
- geminiSettingsManager.deleteBackup?.();
636
- return;
637
- }
638
-
639
- if (tool === 'opencode') {
640
- opencodeSettingsManager.deleteBackup?.();
641
- return;
642
- }
643
-
644
- if (tool === 'omp') {
645
- return;
646
- }
647
- }
648
-
649
- async function stopProxyIfRunning(tool) {
650
- switch (tool) {
651
- case 'claude': {
652
- const { stopProxyServer } = require('../proxy-server');
653
- const { getProxyStatus } = require('../proxy-server');
654
- if (getProxyStatus().running) {
655
- await stopProxyServer();
656
- return true;
657
- }
658
- return false;
659
- }
660
- case 'codex': {
661
- const { stopCodexProxyServer, getCodexProxyStatus } = require('../codex-proxy-server');
662
- if (getCodexProxyStatus().running) {
663
- await stopCodexProxyServer();
664
- return true;
665
- }
666
- return false;
667
- }
668
- case 'gemini': {
669
- const { stopGeminiProxyServer, getGeminiProxyStatus } = require('../gemini-proxy-server');
670
- if (getGeminiProxyStatus().running) {
671
- await stopGeminiProxyServer();
672
- return true;
673
- }
674
- return false;
675
- }
676
- case 'opencode': {
677
- const { stopOpenCodeProxyServer, getOpenCodeProxyStatus } = require('../opencode-proxy-server');
678
- if (getOpenCodeProxyStatus().running) {
679
- await stopOpenCodeProxyServer();
680
- return true;
681
- }
682
- return false;
683
- }
684
- case 'omp': {
685
- const { stopOmpProxyServer, getOmpProxyStatus } = require('../omp-proxy-server');
686
- if (getOmpProxyStatus().running) {
687
- await stopOmpProxyServer();
688
- return true;
689
- }
690
- return false;
691
- }
692
- default:
693
- throw new Error(`Unsupported OAuth tool: ${tool}`);
694
- }
695
- }
696
-
697
- function disableAllChannelsForTool(tool) {
698
- try {
699
- switch (tool) {
700
- case 'claude': {
701
- const { disableAllChannels } = require('./channels');
702
- disableAllChannels();
703
- break;
704
- }
705
- case 'codex': {
706
- const { disableAllChannels } = require('./codex-channels');
707
- disableAllChannels();
708
- break;
709
- }
710
- case 'gemini': {
711
- const { disableAllChannels } = require('./gemini-channels');
712
- disableAllChannels();
713
- break;
714
- }
715
- case 'opencode': {
716
- const { disableAllChannels } = require('./opencode-channels');
717
- disableAllChannels();
718
- break;
719
- }
720
- case 'omp': {
721
- const { disableAllChannels } = require('./omp-channels');
722
- disableAllChannels();
723
- break;
724
- }
725
- }
726
- } catch (err) {
727
- console.warn(`[OAuth] Failed to disable channels for ${tool}:`, err.message);
728
- }
729
- }
730
-
731
- async function applyStoredCredential(tool, credentialId) {
732
- const entry = findStoredCredential(tool, credentialId);
733
- const proxyStopped = await stopProxyIfRunning(tool);
734
- cleanupManagedArtifacts(tool);
735
- if (tool !== 'opencode' && tool !== 'omp') {
736
- disableAllChannelsForTool(tool);
737
- }
738
- applyOAuthCredential(tool, entry.secrets);
739
-
740
- // 记录最近使用时间
741
- const store = readStore();
742
- const toolStore = getToolStore(store, tool);
743
- const stored = toolStore.credentials.find((item) => item.id === credentialId);
744
- if (stored) {
745
- stored.lastUsedAt = Date.now();
746
- writeStore(store);
747
- }
748
-
749
- return {
750
- proxyStopped,
751
- credential: sanitizeCredential(entry, readStore().tools[tool]?.defaultCredentialId || null),
752
- toolSummary: getToolSummary(tool)
753
- };
754
- }
755
-
756
- function disableStoredCredential(tool, credentialId) {
757
- assertSupportedTool(tool);
758
- const entry = findStoredCredential(tool, credentialId);
759
- disableNativeOAuthCredential(tool, {
760
- ...(entry.secrets || {}),
761
- providerId: entry.providerId || entry.secrets?.providerId || '',
762
- accountId: entry.accountId || entry.secrets?.accountId || ''
763
- });
764
-
765
- return {
766
- credential: sanitizeCredential(entry, readStore().tools[tool]?.defaultCredentialId || null),
767
- toolSummary: getToolSummary(tool),
768
- nativeState: inspectTool(tool)
769
- };
770
- }
771
-
772
- function clearNativeOAuthState(tool) {
773
- assertSupportedTool(tool);
774
- clearNativeOAuth(tool);
775
- return inspectTool(tool);
776
- }
777
-
778
- function httpGet(url, headers = {}) {
779
- return new Promise((resolve, reject) => {
780
- const https = require('https');
781
- const urlObj = new URL(url);
782
- const options = {
783
- hostname: urlObj.hostname,
784
- path: urlObj.pathname + urlObj.search,
785
- method: 'GET',
786
- headers,
787
- timeout: 15000
788
- };
789
- const req = https.request(options, (res) => {
790
- let body = '';
791
- res.on('data', (chunk) => { body += chunk; });
792
- res.on('end', () => resolve({ statusCode: res.statusCode, body }));
793
- });
794
- req.on('error', reject);
795
- req.on('timeout', () => { req.destroy(); reject(new Error('请求超时')); });
796
- req.end();
797
- });
798
- }
799
-
800
- function httpPost(url, body, headers = {}) {
801
- return new Promise((resolve, reject) => {
802
- const https = require('https');
803
- const urlObj = new URL(url);
804
- const options = {
805
- hostname: urlObj.hostname,
806
- path: urlObj.pathname + urlObj.search,
807
- method: 'POST',
808
- headers: { ...headers, 'Content-Length': Buffer.byteLength(body) },
809
- timeout: 15000
810
- };
811
- const req = https.request(options, (res) => {
812
- let data = '';
813
- res.on('data', (chunk) => { data += chunk; });
814
- res.on('end', () => resolve({ statusCode: res.statusCode, body: data }));
815
- });
816
- req.on('error', reject);
817
- req.on('timeout', () => { req.destroy(); reject(new Error('请求超时')); });
818
- req.write(body);
819
- req.end();
820
- });
821
- }
822
-
823
- async function fetchClaudeUsage(accessToken) {
824
- try {
825
- const result = await httpGet('https://api.anthropic.com/api/oauth/usage', {
826
- 'Authorization': `Bearer ${accessToken}`,
827
- 'anthropic-beta': 'oauth-2025-04-20',
828
- 'anthropic-version': '2023-06-01',
829
- 'User-Agent': 'claude-cli/1.0'
830
- });
831
- const data = JSON.parse(result.body);
832
- return { raw: data, provider: 'claude', statusCode: result.statusCode };
833
- } catch (err) {
834
- return { error: err.message, provider: 'claude' };
835
- }
836
- }
837
-
838
- async function fetchCodexUsage(accessToken) {
839
- // Codex uses JWT id_token; decode it to extract user info directly
840
- try {
841
- const { decodeJwtPayload } = require('./oauth-utils');
842
- const payload = decodeJwtPayload(accessToken);
843
- if (payload && (payload.email || payload.sub)) {
844
- return {
845
- raw: {
846
- email: payload.email || '',
847
- accountId: payload.sub || '',
848
- name: payload.name || ''
849
- },
850
- provider: 'codex',
851
- statusCode: 200
852
- };
853
- }
854
- } catch (_) {
855
- // fall through to API call
856
- }
857
- try {
858
- const result = await httpGet('https://api.openai.com/v1/me', {
859
- 'Authorization': `Bearer ${accessToken}`,
860
- 'User-Agent': 'openai-node/4.0.0'
861
- });
862
- const data = JSON.parse(result.body);
863
- return { raw: data, provider: 'codex', statusCode: result.statusCode };
864
- } catch (err) {
865
- return { error: err.message, provider: 'codex' };
866
- }
867
- }
868
-
869
- async function fetchGeminiUsage(accessToken) {
870
- try {
871
- const body = JSON.stringify({
872
- metadata: {
873
- ideType: 'ANTIGRAVITY',
874
- platform: 'PLATFORM_UNSPECIFIED',
875
- pluginType: 'GEMINI'
876
- }
877
- });
878
- const result = await httpPost('https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist', body, {
879
- 'Authorization': `Bearer ${accessToken}`,
880
- 'Content-Type': 'application/json',
881
- 'User-Agent': 'google-api-nodejs-client/9.15.1',
882
- 'X-Goog-Api-Client': 'google-cloud-sdk vscode_cloudshelleditor/0.1',
883
- 'Client-Metadata': '{"ideType":"IDE_UNSPECIFIED","platform":"PLATFORM_UNSPECIFIED","pluginType":"GEMINI"}'
884
- });
885
- const data = JSON.parse(result.body);
886
- return { raw: data, provider: 'gemini', statusCode: result.statusCode };
887
- } catch (err) {
888
- return { error: err.message, provider: 'gemini' };
889
- }
890
- }
891
-
892
- async function fetchCredentialUsage(tool, credentialId) {
893
- const entry = findStoredCredential(tool, credentialId);
894
- const secrets = entry.secrets || {};
895
- const accessToken = secrets.accessToken || secrets.primaryToken || '';
896
-
897
- if (!accessToken) {
898
- return { error: '无有效 token' };
899
- }
900
-
901
- switch (tool) {
902
- case 'claude':
903
- return await fetchClaudeUsage(accessToken);
904
- case 'codex':
905
- return await fetchCodexUsage(secrets.idToken || accessToken);
906
- case 'gemini':
907
- return await fetchGeminiUsage(accessToken);
908
- case 'opencode': {
909
- const providerId = entry.providerId || 'openai';
910
- if (providerId.includes('claude') || providerId.includes('anthropic')) {
911
- return await fetchClaudeUsage(accessToken);
912
- } else if (providerId.includes('gemini') || providerId.includes('google')) {
913
- return await fetchGeminiUsage(accessToken);
914
- } else {
915
- return await fetchCodexUsage(accessToken);
916
- }
917
- }
918
- case 'omp': {
919
- const providerId = entry.providerId || secrets.providerId || '';
920
- if (providerId.includes('claude') || providerId.includes('anthropic')) {
921
- return await fetchClaudeUsage(accessToken);
922
- } else if (providerId.includes('gemini') || providerId.includes('google')) {
923
- return await fetchGeminiUsage(accessToken);
924
- } else {
925
- return await fetchCodexUsage(accessToken);
926
- }
927
- }
928
- default:
929
- return { error: `不支持的工具: ${tool}` };
930
- }
931
- }
932
-
933
- module.exports = {
934
- SUPPORTED_TOOLS,
935
- getAllToolSummaries,
936
- getToolSummary,
937
- importCredential,
938
- syncLocalCredential,
939
- setDefaultCredential,
940
- deleteCredential,
941
- applyStoredCredential,
942
- disableStoredCredential,
943
- clearNativeOAuthState,
944
- fetchCredentialUsage
945
- };