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
@@ -0,0 +1,81 @@
1
+ 'use strict';
2
+
3
+ const { createPlatformRegistry } = require('../platforms/registry');
4
+ const { getDriverRegistry } = require('../platforms/driver-registry');
5
+ const { createSessionHistoryIndex } = require('./services/session-history-index');
6
+
7
+ let defaultContext;
8
+
9
+ function getPlatformRuntimeModule() {
10
+ return require('../platforms/runtime');
11
+ }
12
+
13
+ function createLazyDependency(getValue) {
14
+ return new Proxy({}, {
15
+ get(_target, property) {
16
+ const value = getValue();
17
+ return typeof value?.[property] === 'function' ? value[property].bind(value) : value?.[property];
18
+ }
19
+ });
20
+ }
21
+
22
+ function getDefaultPlatformBindings() {
23
+ const runtimeModule = getPlatformRuntimeModule();
24
+ const registry = typeof runtimeModule.getPlatformRegistry === 'function'
25
+ ? runtimeModule.getPlatformRegistry()
26
+ : createPlatformRegistry();
27
+ const runtime = typeof runtimeModule.getPlatformRuntime === 'function'
28
+ ? runtimeModule.getPlatformRuntime()
29
+ : null;
30
+ return { registry, runtime };
31
+ }
32
+
33
+ function createPlatformContext({ registry, runtime, dependencies = {}, driverRegistry } = {}) {
34
+ const runtimeModule = getPlatformRuntimeModule();
35
+ const resolvedRegistry = registry || createPlatformRegistry();
36
+ let sessionHistoryIndex = dependencies.sessionHistoryIndex || null;
37
+ const indexDependency = sessionHistoryIndex || createLazyDependency(() => sessionHistoryIndex);
38
+ const resolvedDependencies = {
39
+ ...(typeof runtimeModule.getDefaultDependencies === 'function'
40
+ ? runtimeModule.getDefaultDependencies()
41
+ : {}),
42
+ ...dependencies,
43
+ sessionHistoryIndex: indexDependency
44
+ };
45
+ if (typeof runtimeModule.configureDefaultDependencies === 'function') {
46
+ runtimeModule.configureDefaultDependencies(resolvedDependencies);
47
+ }
48
+ const resolvedRuntime = runtime || (typeof runtimeModule.createPlatformRuntime === 'function'
49
+ ? runtimeModule.createPlatformRuntime({
50
+ registry: resolvedRegistry,
51
+ driverRegistry: driverRegistry || getDriverRegistry(),
52
+ dependencies: resolvedDependencies
53
+ })
54
+ : { getDriver: () => null });
55
+ if (!sessionHistoryIndex) {
56
+ sessionHistoryIndex = createSessionHistoryIndex({ runtime: resolvedRuntime });
57
+ }
58
+ return Object.freeze({
59
+ registry: resolvedRegistry,
60
+ runtime: resolvedRuntime,
61
+ dependencies: Object.freeze({ ...resolvedDependencies, sessionHistoryIndex })
62
+ });
63
+ }
64
+
65
+ function getPlatformContext(options = {}) {
66
+ const hasOptions = Object.keys(options).length > 0;
67
+ const bindings = hasOptions ? null : getDefaultPlatformBindings();
68
+ if (!defaultContext
69
+ || hasOptions
70
+ || (bindings.runtime && defaultContext.runtime !== bindings.runtime)
71
+ || (bindings.registry && defaultContext.registry !== bindings.registry)) {
72
+ defaultContext = createPlatformContext(hasOptions ? options : bindings);
73
+ }
74
+ return defaultContext;
75
+ }
76
+
77
+ function resetPlatformContext() {
78
+ defaultContext = undefined;
79
+ }
80
+
81
+ module.exports = { createPlatformContext, getPlatformContext, resetPlatformContext };
@@ -6,6 +6,7 @@ const path = require('path');
6
6
  const { URL } = require('url');
7
7
  const { PATHS } = require('../../config/paths');
8
8
  const { loadUIConfig } = require('./ui-config');
9
+ const { getPlatformContext } = require('../platform-context');
9
10
  const {
10
11
  getSnapshot,
11
12
  refreshSnapshot,
@@ -18,7 +19,6 @@ const MAX_RESPONSE_BYTES = 1024 * 1024;
18
19
  const QUOTA_UNIT = 500000;
19
20
  const VELOERA_QUOTA_UNIT = 1000000;
20
21
  const NEWCLI_QUOTA_UNIT = 1000000;
21
- const VALID_SOURCES = new Set(['claude', 'codex', 'gemini', 'opencode', 'omp']);
22
22
  const GATEWAY_PATH_SEGMENTS = new Set(['openai', 'anthropic', 'claude', 'gemini', 'codex']);
23
23
  const HUB_PLATFORMS = new Set(['new-api', 'one-api', 'one-hub', 'done-hub', 'veloera', 'anyrouter', 'aihubmix']);
24
24
  const UNSUPPORTED_BALANCE_PLATFORMS = new Set(['dashscope', 'modelscope']);
@@ -1622,24 +1622,16 @@ function clearChannelBalanceCache(source, channel) {
1622
1622
  writePersistedStrategyCache();
1623
1623
  }
1624
1624
  }
1625
-
1626
1625
  function getChannelsForSource(source) {
1627
- if (source === 'claude') {
1628
- return require('./channels').getAllChannels() || [];
1629
- }
1630
- if (source === 'codex') {
1631
- return require('./codex-channels').getChannels().channels || [];
1632
- }
1633
- if (source === 'gemini') {
1634
- return require('./gemini-channels').getChannels().channels || [];
1635
- }
1636
- if (source === 'opencode') {
1637
- return require('./opencode-channels').getChannels().channels || [];
1638
- }
1639
- if (source === 'omp') {
1640
- return require('./omp-channels').getChannels().channels || [];
1626
+ try {
1627
+ const driver = getPlatformContext().runtime.getDriver(source, 'channels');
1628
+ if (!driver) return [];
1629
+ const value = typeof driver.list === 'function' ? driver.list() : driver.getChannels?.();
1630
+ if (value?.status === 'ok') return value.data?.channels || value.data || [];
1631
+ return Array.isArray(value) ? value : value?.channels || [];
1632
+ } catch (_) {
1633
+ return [];
1641
1634
  }
1642
- return [];
1643
1635
  }
1644
1636
 
1645
1637
  function getEnabledBalanceChannels(source) {
@@ -1656,7 +1648,7 @@ function isBalanceDisplayEnabled() {
1656
1648
 
1657
1649
  function validateSource(source) {
1658
1650
  const normalized = String(source || '').trim().toLowerCase();
1659
- if (!VALID_SOURCES.has(normalized)) {
1651
+ if (!getPlatformContext().registry.resolve(normalized)) {
1660
1652
  throw new Error('Invalid channel balance source');
1661
1653
  }
1662
1654
  return normalized;
@@ -1737,8 +1729,7 @@ async function refreshChannelBalance(source, channelId) {
1737
1729
 
1738
1730
  const entry = await refreshSnapshot(
1739
1731
  buildBalanceSnapshotKey(normalizedSource, channel),
1740
- () => refreshChannelBalanceSnapshot(normalizedSource, channel, { force: true }),
1741
- { bypassInflight: true }
1732
+ () => refreshChannelBalanceSnapshot(normalizedSource, channel, { force: true })
1742
1733
  );
1743
1734
  const balance = entry.value;
1744
1735
  return {
@@ -16,9 +16,9 @@ const healthConfig = {
16
16
  // 渠道健康状态
17
17
  const channelHealth = new Map(); // `${source}:${channelId}` → health info
18
18
 
19
- // 冻结回调(用于通知调度器解绑会话)
20
19
  let onChannelFrozenCallback = null;
21
20
  let channelListProvider = null;
21
+ let channelHealthPolicyProvider = null;
22
22
 
23
23
  /**
24
24
  * 设置渠道冻结时的回调
@@ -31,6 +31,22 @@ function setChannelListProvider(provider) {
31
31
  channelListProvider = typeof provider === 'function' ? provider : null;
32
32
  }
33
33
 
34
+
35
+ function setChannelHealthPolicyProvider(provider) {
36
+ channelHealthPolicyProvider = typeof provider === 'function' ? provider : null;
37
+ }
38
+
39
+ function getHealthPolicy(source = 'claude') {
40
+ try {
41
+ const policy = channelHealthPolicyProvider?.(source);
42
+ if (policy && typeof policy === 'object') {
43
+ return { freezeOnFailure: policy.freezeOnFailure !== false };
44
+ }
45
+ } catch (_error) {
46
+ // Fall through to the safe default freeze policy.
47
+ }
48
+ return { freezeOnFailure: true };
49
+ }
34
50
  /**
35
51
  * 初始化渠道健康信息
36
52
  */
@@ -128,9 +144,8 @@ function recordSuccess(channelId, source = 'claude') {
128
144
  health.nextFreezeTime = healthConfig.initialFreezeTime; // 重置冻结时间
129
145
  console.log(`[ChannelHealth] Channel ${channelId} recovered and marked as healthy`);
130
146
  }
131
- }
132
147
  }
133
-
148
+ }
134
149
  /**
135
150
  * 记录失败请求
136
151
  */
@@ -142,12 +157,11 @@ function recordFailure(channelId, source = 'claude', error) {
142
157
  health.consecutiveFailures++;
143
158
  health.consecutiveSuccesses = 0;
144
159
  health.lastCheckTime = now;
145
-
146
- // omp 动态切换按请求即时回退其他渠道,失败渠道无需冻结(冻结会将其排除在后续分配之外)
147
- if (source === 'omp') {
160
+ if (!getHealthPolicy(source).freezeOnFailure) {
148
161
  return;
149
162
  }
150
163
 
164
+
151
165
  // 如果当前是健康状态或检测中状态,检查是否需要冻结
152
166
  if (health.status === 'healthy' || health.status === 'checking') {
153
167
  if (health.consecutiveFailures >= healthConfig.failureThreshold) {
@@ -291,5 +305,6 @@ module.exports = {
291
305
  resetChannelHealth,
292
306
  setOnChannelFrozen,
293
307
  setChannelListProvider,
308
+ setChannelHealthPolicyProvider,
294
309
  healthConfig,
295
310
  };
@@ -1,29 +1,25 @@
1
- const { getAllChannels } = require('./channels');
2
- const { getChannels: getCodexChannels } = require('./codex-channels');
3
- const { getChannels: getGeminiChannels } = require('./gemini-channels');
4
- const { getChannels: getOpenCodeChannels } = require('./opencode-channels');
5
- const { getChannels: getOmpChannels } = require('./omp-channels');
6
- const { isChannelAvailable, getChannelHealthStatus, setOnChannelFrozen, setChannelListProvider } = require('./channel-health');
1
+ const { getPlatformContext } = require('../platform-context');
2
+ const { isChannelAvailable, getChannelHealthStatus, setOnChannelFrozen, setChannelListProvider, setChannelHealthPolicyProvider } = require('./channel-health');
7
3
 
8
- const channelProviders = {
9
- claude: () => getAllChannels(),
10
- codex: () => {
11
- const data = getCodexChannels();
12
- return Array.isArray(data?.channels) ? data.channels : [];
13
- },
14
- gemini: () => {
15
- const data = getGeminiChannels();
16
- return Array.isArray(data?.channels) ? data.channels : [];
17
- },
18
- opencode: () => {
19
- const data = getOpenCodeChannels();
20
- return Array.isArray(data?.channels) ? data.channels : [];
21
- },
22
- omp: () => {
23
- const data = getOmpChannels();
24
- return Array.isArray(data?.channels) ? data.channels : [];
4
+ function readChannels(source = 'claude') {
5
+ try {
6
+ const driver = getPlatformContext().runtime.getDriver(source, 'channels');
7
+ if (!driver || (typeof driver.status === 'string' && driver.status !== 'ok')) {
8
+ return [];
9
+ }
10
+ const list = typeof driver.list === 'function'
11
+ ? driver.list.bind(driver)
12
+ : typeof driver.getChannels === 'function'
13
+ ? driver.getChannels.bind(driver)
14
+ : null;
15
+ if (!list) return [];
16
+ const result = list();
17
+ const payload = result?.status === 'ok' ? result.data : result;
18
+ return Array.isArray(payload) ? payload : (Array.isArray(payload?.channels) ? payload.channels : []);
19
+ } catch (_) {
20
+ return [];
25
21
  }
26
- };
22
+ }
27
23
 
28
24
  function createState() {
29
25
  return {
@@ -33,14 +29,7 @@ function createState() {
33
29
  queue: []
34
30
  };
35
31
  }
36
-
37
- const schedulerStates = {
38
- claude: createState(),
39
- codex: createState(),
40
- gemini: createState(),
41
- opencode: createState(),
42
- omp: createState()
43
- };
32
+ const schedulerStates = Object.create(null);
44
33
 
45
34
  function getState(source = 'claude') {
46
35
  if (!schedulerStates[source]) {
@@ -70,19 +59,20 @@ function unbindChannelSessions(source, channelId) {
70
59
 
71
60
  // 注册冻结回调,当渠道被冻结时解绑其会话
72
61
  setOnChannelFrozen(unbindChannelSessions);
73
- setChannelListProvider((source = 'claude') => {
74
- const provider = channelProviders[source || 'claude'];
75
- if (!provider) return [];
76
- return provider();
62
+ setChannelListProvider((source = 'claude') => readChannels(source));
63
+ setChannelHealthPolicyProvider((source = 'claude') => {
64
+ try {
65
+ return getPlatformContext().runtime.getDriver(source, 'channels')?.getHealthPolicy?.() || { freezeOnFailure: true };
66
+ } catch (_error) {
67
+ return { freezeOnFailure: true };
68
+ }
77
69
  });
78
70
 
79
71
  function refreshChannels(source = 'claude') {
80
72
  const state = getState(source);
81
- const provider = channelProviders[source];
82
- if (!provider) return;
73
+ const raw = readChannels(source);
83
74
 
84
75
  // 每次直接读取最新配置,不做缓存
85
- const raw = provider();
86
76
  state.channels = raw
87
77
  .filter(ch => ch.enabled !== false)
88
78
  .map(ch => ({
@@ -1,7 +1,7 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const crypto = require('crypto');
4
- const { PATHS, ensureStorageDirMigrated } = require('../../config/paths');
4
+ const { PATHS, ensureStorageDirMigrated, getPlatformStatePath } = require('../../config/paths');
5
5
 
6
6
  function normalizeString(value) {
7
7
  return String(value || '').trim();
@@ -74,7 +74,7 @@ function resolveApiKeyValue(value, env = process.env) {
74
74
  function readActiveChannelId(platform) {
75
75
  try {
76
76
  ensureStorageDirMigrated?.();
77
- const filePath = PATHS.activeChannel?.[platform];
77
+ const filePath = getPlatformStatePath('activeChannel', platform);
78
78
  if (!filePath || !fs.existsSync(filePath)) return null;
79
79
  const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
80
80
  return data?.activeChannelId || null;
@@ -231,12 +231,25 @@ function sanitizeChannel(channel) {
231
231
  const sanitized = {
232
232
  id: channel.id,
233
233
  name: channel.name,
234
- baseUrl: channel.baseUrl,
235
- enabled: channel.enabled !== false
234
+ baseUrl: channel.authMode === 'oauth' ? '' : channel.baseUrl,
235
+ apiKey: channel.apiKey || '',
236
+ enabled: channel.enabled !== false,
237
+ authMode: channel.authMode || 'api_key'
236
238
  };
237
239
  if (channel.providerKey) sanitized.providerKey = channel.providerKey;
238
240
  if (channel.model) sanitized.model = channel.model;
239
241
  if (channel.credentialSource) sanitized.credentialSource = channel.credentialSource;
242
+ if (channel.authMode === 'oauth') {
243
+ sanitized.authRef = {
244
+ credentialId: String(channel.authRef?.credentialId || ''),
245
+ providerId: String(channel.authRef?.providerId || ''),
246
+ accountId: String(channel.authRef?.accountId || ''),
247
+ identityKey: String(channel.authRef?.identityKey || ''),
248
+ accountEmail: String(channel.authRef?.accountEmail || '')
249
+ };
250
+ sanitized.authSource = channel.authSource || 'synced-local';
251
+ sanitized.authStatus = channel.authStatus || 'available';
252
+ }
240
253
  return sanitized;
241
254
  }
242
255
 
@@ -272,26 +285,23 @@ function upsertSyncedChannels({
272
285
  channels: [],
273
286
  warnings: []
274
287
  };
275
-
276
288
  let changed = false;
277
289
  for (const rawCandidate of candidates || []) {
278
290
  const candidate = rawCandidate || {};
279
- if (candidate.warning) {
280
- result.warnings.push(candidate.warning);
281
- }
291
+ if (candidate.warning) result.warnings.push(candidate.warning);
282
292
  if (candidate.skip) {
283
293
  result.skipped += 1;
284
294
  if (candidate.channel) result.channels.push(sanitizeChannel(candidate.channel));
285
295
  continue;
286
296
  }
287
- if (!normalizeString(candidate.baseUrl)) {
297
+ if (candidate.authMode !== 'oauth' && !normalizeString(candidate.baseUrl)) {
288
298
  result.skipped += 1;
289
299
  result.warnings.push(`${toolType}: missing baseUrl, skipped current channel sync`);
290
300
  continue;
291
301
  }
292
- if (!normalizeString(candidate.apiKey) && candidate.authMode !== 'none') {
302
+ if (!normalizeString(candidate.apiKey) && candidate.authMode !== 'oauth' && candidate.authMode !== 'none') {
293
303
  result.skipped += 1;
294
- result.warnings.push(`${toolType}: missing API key or OAuth-only config, skipped current channel sync`);
304
+ result.warnings.push(`${toolType}: missing API key, skipped current channel sync`);
295
305
  continue;
296
306
  }
297
307
 
@@ -317,7 +327,7 @@ function upsertSyncedChannels({
317
327
  const now = Date.now();
318
328
  const created = applyDefaults ? applyDefaults({
319
329
  id: candidate.id || crypto.randomUUID(),
320
- enabled: candidate.enabled !== false,
330
+ enabled: candidate.authMode === 'oauth' ? false : candidate.enabled !== false,
321
331
  weight: candidate.weight || 1,
322
332
  maxConcurrency: candidate.maxConcurrency || null,
323
333
  ...normalizedCandidate,
@@ -325,7 +335,7 @@ function upsertSyncedChannels({
325
335
  updatedAt: now
326
336
  }) : {
327
337
  id: candidate.id || crypto.randomUUID(),
328
- enabled: candidate.enabled !== false,
338
+ enabled: candidate.authMode === 'oauth' ? false : candidate.enabled !== false,
329
339
  weight: candidate.weight || 1,
330
340
  maxConcurrency: candidate.maxConcurrency || null,
331
341
  ...normalizedCandidate,