coding-tool-x 3.8.4 → 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 +15 -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 +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 +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
@@ -3,10 +3,11 @@
3
3
  */
4
4
 
5
5
  const express = require('express');
6
- const { ConfigSyncService } = require('../services/config-sync-service');
6
+ const { ConfigSyncService } = require('../../platforms/drivers/claude/config-sync');
7
+ const { getPlatformContext } = require('../platform-context');
7
8
 
8
9
  const router = express.Router();
9
- const configSyncService = new ConfigSyncService();
10
+ const configSyncService = new ConfigSyncService({ registry: getPlatformContext().registry });
10
11
 
11
12
  /**
12
13
  * 获取可同步的配置列表
@@ -185,7 +185,7 @@ router.delete('/:id', (req, res) => {
185
185
  * POST /api/config-templates/:id/apply
186
186
  * 应用模板到项目目录
187
187
  */
188
- router.post('/:id/apply', (req, res) => {
188
+ router.post('/:id/apply', async (req, res) => {
189
189
  try {
190
190
  const { targetPath, aiConfigType, aiConfigTypes } = req.body;
191
191
  if (!targetPath) {
@@ -194,12 +194,20 @@ router.post('/:id/apply', (req, res) => {
194
194
  message: '目标路径不能为空'
195
195
  });
196
196
  }
197
+ const { validateKnownProjectCwd } = require('../services/project-path-validation');
198
+ const validatedTargetPath = await validateKnownProjectCwd(targetPath);
199
+ if (!validatedTargetPath) {
200
+ return res.status(400).json({
201
+ success: false,
202
+ message: '目标路径不能为空'
203
+ });
204
+ }
197
205
  const options = {};
198
206
  const normalizedAiConfigTypes = normalizeAiConfigTypes(aiConfigTypes, aiConfigType);
199
207
  if (normalizedAiConfigTypes.length > 0) {
200
208
  options.aiConfigTypes = normalizedAiConfigTypes;
201
209
  }
202
- const result = templatesService.applyTemplateToProject(targetPath, req.params.id, options);
210
+ const result = await templatesService.applyTemplateToProject(validatedTargetPath, req.params.id, options);
203
211
  const skippedCount = result?.results?.skipped?.length || 0;
204
212
  res.json({
205
213
  success: true,
@@ -218,7 +226,7 @@ router.post('/:id/apply', (req, res) => {
218
226
  * POST /api/config-templates/:id/preview
219
227
  * 预览模板应用效果
220
228
  */
221
- router.post('/:id/preview', (req, res) => {
229
+ router.post('/:id/preview', async (req, res) => {
222
230
  try {
223
231
  const { targetPath, aiConfigType, aiConfigTypes } = req.body;
224
232
  if (!targetPath) {
@@ -227,12 +235,20 @@ router.post('/:id/preview', (req, res) => {
227
235
  message: '目标路径不能为空'
228
236
  });
229
237
  }
238
+ const { validateKnownProjectCwd } = require('../services/project-path-validation');
239
+ const validatedTargetPath = await validateKnownProjectCwd(targetPath);
240
+ if (!validatedTargetPath) {
241
+ return res.status(400).json({
242
+ success: false,
243
+ message: '目标路径不能为空'
244
+ });
245
+ }
230
246
  const options = {};
231
247
  const normalizedAiConfigTypes = normalizeAiConfigTypes(aiConfigTypes, aiConfigType);
232
248
  if (normalizedAiConfigTypes.length > 0) {
233
249
  options.aiConfigTypes = normalizedAiConfigTypes;
234
250
  }
235
- const preview = templatesService.previewTemplateApplication(targetPath, req.params.id, options);
251
+ const preview = await templatesService.previewTemplateApplication(validatedTargetPath, req.params.id, options);
236
252
  res.json({
237
253
  success: true,
238
254
  data: preview
@@ -1,46 +1,11 @@
1
1
  const express = require('express');
2
2
  const router = express.Router();
3
- const { loadConfig, saveConfig } = require('../../config/loader');
3
+ const { loadConfig, saveConfig, normalizeNativeCliLogs } = require('../../config/loader');
4
4
  const DEFAULT_CONFIG = require('../../config/default');
5
- const { getAllChannels } = require('../services/channels');
6
- const { getChannels: getCodexChannels } = require('../services/codex-channels');
7
- const { getChannels: getGeminiChannels } = require('../services/gemini-channels');
8
- const {
9
- probeModelAvailability,
10
- fetchModelsFromProvider
11
- } = require('../services/model-detector');
12
-
13
- function clampNumber(value, fallback) {
14
- const num = typeof value === 'number' ? value : parseFloat(value);
15
- if (!Number.isFinite(num)) {
16
- return fallback;
17
- }
18
- if (num < 0) return 0;
19
- if (num > 1000) return 1000;
20
- return Math.round(num * 1000000) / 1000000;
21
- }
22
-
23
- function sanitizePricing(inputPricing, currentPricing) {
24
- const defaults = DEFAULT_CONFIG.pricing;
25
- const sanitized = {};
26
-
27
- Object.keys(defaults).forEach((toolKey) => {
28
- const defaultValue = defaults[toolKey];
29
- const existingValue = currentPricing?.[toolKey] || {};
30
- const payload = inputPricing?.[toolKey] || {};
31
-
32
- const mode = payload.mode === 'custom' ? 'custom' : (existingValue.mode || defaultValue.mode || 'auto');
33
- sanitized[toolKey] = { mode };
34
-
35
- Object.keys(defaultValue)
36
- .filter((key) => key !== 'mode')
37
- .forEach((rateKey) => {
38
- const fallback = existingValue[rateKey] !== undefined ? existingValue[rateKey] : defaultValue[rateKey];
39
- sanitized[toolKey][rateKey] = clampNumber(payload[rateKey], fallback);
40
- });
41
- });
42
-
43
- return sanitized;
5
+ const { getPlatformCatalog } = require('../services/platform-catalog');
6
+ const { probeModelAvailability } = require('../services/model-detector');
7
+ function getModelCatalogKey(platform) {
8
+ return getPlatformCatalog().get(platform)?.modelConfig?.catalogKey || platform;
44
9
  }
45
10
 
46
11
  function normalizeModelDiscovery(modelDiscovery, currentValue = DEFAULT_CONFIG.modelDiscovery) {
@@ -61,6 +26,25 @@ function normalizeModelDiscovery(modelDiscovery, currentValue = DEFAULT_CONFIG.m
61
26
  };
62
27
  }
63
28
 
29
+ function isPlainObject(value) {
30
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
31
+ }
32
+
33
+ function validateNativeCliLogs(value) {
34
+ if (!isPlainObject(value)) {
35
+ return 'nativeCliLogs must be an object';
36
+ }
37
+ if (Object.prototype.hasOwnProperty.call(value, 'enabled') && typeof value.enabled !== 'boolean') {
38
+ return 'nativeCliLogs.enabled must be a boolean';
39
+ }
40
+ if (Object.prototype.hasOwnProperty.call(value, 'intervalSeconds')
41
+ && (!Number.isInteger(value.intervalSeconds) || value.intervalSeconds < 1 || value.intervalSeconds > 60)) {
42
+ return 'nativeCliLogs.intervalSeconds must be an integer between 1-60';
43
+ }
44
+ return null;
45
+ }
46
+
47
+
64
48
  function uniqueModels(models = []) {
65
49
  const seen = new Set();
66
50
  const result = [];
@@ -108,10 +92,31 @@ function parseBooleanQuery(value, defaultValue = false) {
108
92
  const normalized = String(value).trim().toLowerCase();
109
93
  return ['1', 'true', 'yes', 'on'].includes(normalized);
110
94
  }
95
+ function readChannelList(platform) {
96
+ const driver = getPlatformCatalog().driver(platform, 'channels');
97
+ const result = typeof driver?.list === 'function' ? driver.list() : null;
98
+ if (result && typeof result.then === 'function') {
99
+ return result.then(value => {
100
+ const data = value?.status === 'ok' ? value.data : value;
101
+ return Array.isArray(data) ? data : data?.channels || [];
102
+ });
103
+ }
104
+ const data = result?.status === 'ok' ? result.data : result;
105
+ return Array.isArray(data) ? data : data?.channels || [];
106
+ }
107
+
108
+ async function listModelsForChannel(channel, platform, options = {}) {
109
+ const driver = getPlatformCatalog().driver(platform, 'channels');
110
+ if (typeof driver?.listModels !== 'function') return [];
111
+ const result = await driver.listModels(channel, options);
112
+ if (result?.status !== 'ok') return [];
113
+ return Array.isArray(result.data?.models) ? result.data.models : [];
114
+ }
111
115
 
112
116
  async function probeModelsForSingleChannel(channel, channelType, options = {}) {
113
- const builtInPreferred = Array.isArray(DEFAULT_CONFIG.defaultModels?.[channelType])
114
- ? DEFAULT_CONFIG.defaultModels[channelType]
117
+ const catalogKey = getModelCatalogKey(channelType);
118
+ const builtInPreferred = Array.isArray(DEFAULT_CONFIG.defaultModels?.[catalogKey])
119
+ ? DEFAULT_CONFIG.defaultModels[catalogKey]
115
120
  : [];
116
121
  const preferredModels = uniqueModels([
117
122
  ...collectChannelPreferredModels(channel),
@@ -119,12 +124,11 @@ async function probeModelsForSingleChannel(channel, channelType, options = {}) {
119
124
  ]);
120
125
 
121
126
  try {
122
- if (channelType === 'codex') {
123
- const listResult = await fetchModelsFromProvider(channel, 'openai_compatible');
124
- const listedModels = Array.isArray(listResult?.models) ? listResult.models : [];
125
- if (listedModels.length > 0) {
126
- return uniqueModels(listedModels);
127
- }
127
+ const listedModels = await listModelsForChannel(channel, channelType, {
128
+ forceRefresh: !!options.forceRefresh
129
+ });
130
+ if (listedModels.length > 0) {
131
+ return uniqueModels(listedModels);
128
132
  }
129
133
 
130
134
  const probe = await probeModelAvailability(channel, channelType, {
@@ -160,8 +164,9 @@ async function probeModelsForChannels(channels = [], channelType, options = {})
160
164
  function mergeProbedAndConfiguredModels(probedModels, configuredModels, toolType) {
161
165
  const safeConfigured = Array.isArray(configuredModels) ? configuredModels : [];
162
166
  const safeProbed = Array.isArray(probedModels) ? probedModels : [];
163
- const builtInDefaults = Array.isArray(DEFAULT_CONFIG.defaultModels?.[toolType])
164
- ? DEFAULT_CONFIG.defaultModels[toolType]
167
+ const catalogKey = getModelCatalogKey(toolType);
168
+ const builtInDefaults = Array.isArray(DEFAULT_CONFIG.defaultModels?.[catalogKey])
169
+ ? DEFAULT_CONFIG.defaultModels[catalogKey]
165
170
  : [];
166
171
  if (safeProbed.length > 0) {
167
172
  return uniqueModels([...safeProbed, ...safeConfigured, ...builtInDefaults]);
@@ -218,6 +223,18 @@ function validateModelList(models, toolType) {
218
223
  return { valid: true, cleaned };
219
224
  }
220
225
 
226
+ function projectDefaultModelsByPlatform(models = {}) {
227
+ const projected = { ...(models || {}) };
228
+ const catalog = getPlatformCatalog();
229
+ for (const platform of catalog.keys({ capability: 'channels' })) {
230
+ const catalogKey = getModelCatalogKey(platform);
231
+ if (!Array.isArray(projected[platform]) && Array.isArray(projected[catalogKey])) {
232
+ projected[platform] = projected[catalogKey];
233
+ }
234
+ }
235
+ return projected;
236
+ }
237
+
221
238
  /**
222
239
  * GET /api/config/default-models
223
240
  * 获取默认模型列表
@@ -225,7 +242,7 @@ function validateModelList(models, toolType) {
225
242
  router.get('/default-models', async (req, res) => {
226
243
  try {
227
244
  const config = loadConfig();
228
- const configuredDefaultModels = config.defaultModels || DEFAULT_CONFIG.defaultModels;
245
+ const configuredDefaultModels = projectDefaultModelsByPlatform(config.defaultModels || DEFAULT_CONFIG.defaultModels);
229
246
  const probe = parseBooleanQuery(req.query.probe, false);
230
247
 
231
248
  if (!probe) {
@@ -235,33 +252,20 @@ router.get('/default-models', async (req, res) => {
235
252
  });
236
253
  }
237
254
 
238
- const forceRefresh = parseBooleanQuery(req.query.forceRefresh, true);
239
- const claudeChannels = getAllChannels();
240
- const codexData = getCodexChannels();
241
- const geminiData = getGeminiChannels();
242
-
243
- // 各工具类型也按串行探测,进一步降低并发压力
244
- const claudeProbed = await probeModelsForChannels(claudeChannels || [], 'claude', { forceRefresh });
245
- const codexProbed = await probeModelsForChannels(codexData?.channels || [], 'codex', { forceRefresh });
246
- const geminiProbed = await probeModelsForChannels(geminiData?.channels || [], 'gemini', { forceRefresh });
247
-
248
- const defaultModels = {
249
- claude: mergeProbedAndConfiguredModels(
250
- claudeProbed,
251
- configuredDefaultModels.claude,
252
- 'claude'
253
- ),
254
- codex: mergeProbedAndConfiguredModels(
255
- codexProbed,
256
- configuredDefaultModels.codex,
257
- 'codex'
258
- ),
259
- gemini: mergeProbedAndConfiguredModels(
260
- geminiProbed,
261
- configuredDefaultModels.gemini,
262
- 'gemini'
255
+ const forceRefresh = parseBooleanQuery(req.query.forceRefresh, false);
256
+ const platforms = getPlatformCatalog().keys({ capability: 'channels' });
257
+ const channelLists = await Promise.all(platforms.map(platform => readChannelList(platform)));
258
+ const probedModels = await Promise.all(platforms.map((platform, index) => (
259
+ probeModelsForChannels(channelLists[index], platform, { forceRefresh })
260
+ )));
261
+ const defaultModels = Object.fromEntries(platforms.map((platform, index) => [
262
+ platform,
263
+ mergeProbedAndConfiguredModels(
264
+ probedModels[index],
265
+ configuredDefaultModels[platform],
266
+ platform
263
267
  )
264
- };
268
+ ]));
265
269
 
266
270
  res.json({
267
271
  defaultModels,
@@ -288,10 +292,9 @@ router.post('/default-models', (req, res) => {
288
292
  });
289
293
  }
290
294
 
291
- const validToolTypes = ['claude', 'codex', 'gemini'];
295
+ const validToolTypes = getPlatformCatalog().keys({ capability: 'channels' });
292
296
  const providedTypes = Object.keys(defaultModels);
293
297
 
294
- // Validate that only valid tool types are provided
295
298
  for (const toolType of providedTypes) {
296
299
  if (!validToolTypes.includes(toolType)) {
297
300
  return res.status(400).json({
@@ -299,7 +302,6 @@ router.post('/default-models', (req, res) => {
299
302
  });
300
303
  }
301
304
  }
302
-
303
305
  // Validate each model list
304
306
  const validated = {};
305
307
  const errors = {};
@@ -354,11 +356,11 @@ router.post('/default-models/reset', (req, res) => {
354
356
  const { toolType } = req.body;
355
357
 
356
358
  const config = loadConfig();
359
+ const validToolTypes = getPlatformCatalog().keys({ capability: 'channels' });
360
+ const builtInDefaults = projectDefaultModelsByPlatform(DEFAULT_CONFIG.defaultModels);
357
361
  let newDefaultModels;
358
362
 
359
363
  if (toolType) {
360
- // Reset specific tool type
361
- const validToolTypes = ['claude', 'codex', 'gemini'];
362
364
  if (!validToolTypes.includes(toolType)) {
363
365
  return res.status(400).json({
364
366
  error: `Invalid tool type: ${toolType}. Valid types: ${validToolTypes.join(', ')}`
@@ -367,14 +369,12 @@ router.post('/default-models/reset', (req, res) => {
367
369
 
368
370
  newDefaultModels = {
369
371
  ...(config.defaultModels || DEFAULT_CONFIG.defaultModels),
370
- [toolType]: DEFAULT_CONFIG.defaultModels[toolType]
372
+ [toolType]: builtInDefaults[toolType] || builtInDefaults[getModelCatalogKey(toolType)] || []
371
373
  };
372
374
  } else {
373
- // Reset all tool types
374
- newDefaultModels = { ...DEFAULT_CONFIG.defaultModels };
375
+ newDefaultModels = builtInDefaults;
375
376
  }
376
377
 
377
- // Save config
378
378
  const newConfig = {
379
379
  ...config,
380
380
  defaultModels: newDefaultModels
@@ -400,20 +400,17 @@ router.get('/advanced', (req, res) => {
400
400
  try {
401
401
  const config = loadConfig();
402
402
  const modelDiscovery = normalizeModelDiscovery(config.modelDiscovery);
403
+ const ports = Object.fromEntries(getPlatformCatalog().ports().map(({ key, defaultPort }) => [
404
+ key,
405
+ config.ports?.[key] ?? defaultPort
406
+ ]));
403
407
  res.json({
404
- ports: {
405
- webUI: config.ports?.webUI || 19999,
406
- proxy: config.ports?.proxy || 20088,
407
- codexProxy: config.ports?.codexProxy || 20089,
408
- geminiProxy: config.ports?.geminiProxy || 20090,
409
- opencodeProxy: config.ports?.opencodeProxy || 20091,
410
- ompProxy: config.ports?.ompProxy || 20092
411
- },
408
+ ports,
412
409
  maxLogs: config.maxLogs || 100,
413
410
  statsInterval: config.statsInterval || 30,
414
411
  enableSessionBinding: config.enableSessionBinding !== false, // 默认开启
415
412
  modelDiscovery,
416
- pricing: config.pricing || DEFAULT_CONFIG.pricing
413
+ nativeCliLogs: normalizeNativeCliLogs(config.nativeCliLogs)
417
414
  });
418
415
  } catch (error) {
419
416
  console.error('[Config API] Failed to get advanced config:', error);
@@ -427,14 +424,16 @@ router.get('/advanced', (req, res) => {
427
424
  */
428
425
  router.post('/advanced', (req, res) => {
429
426
  try {
427
+ const body = req.body || {};
430
428
  const {
431
429
  ports,
432
430
  maxLogs,
433
431
  statsInterval,
434
- pricing,
435
432
  enableSessionBinding,
436
- modelDiscovery
437
- } = req.body;
433
+ modelDiscovery,
434
+ nativeCliLogs
435
+ } = body;
436
+ const hasNativeCliLogs = Object.prototype.hasOwnProperty.call(body, 'nativeCliLogs');
438
437
 
439
438
  // 验证端口
440
439
  if (ports) {
@@ -468,9 +467,19 @@ router.post('/advanced', (req, res) => {
468
467
  }
469
468
  }
470
469
 
471
- // 加载当前配置
470
+ if (hasNativeCliLogs) {
471
+ const nativeCliLogsError = validateNativeCliLogs(nativeCliLogs);
472
+ if (nativeCliLogsError) {
473
+ return res.status(400).json({ error: nativeCliLogsError });
474
+ }
475
+ }
476
+
472
477
  const config = loadConfig();
473
- const sanitizedPricing = sanitizePricing(pricing, config.pricing);
478
+ const currentNativeCliLogs = normalizeNativeCliLogs(config.nativeCliLogs);
479
+ const normalizedNativeCliLogs = hasNativeCliLogs
480
+ ? normalizeNativeCliLogs(nativeCliLogs, currentNativeCliLogs)
481
+ : currentNativeCliLogs;
482
+
474
483
  const normalizedModelDiscovery = normalizeModelDiscovery(
475
484
  modelDiscovery,
476
485
  config.modelDiscovery || DEFAULT_CONFIG.modelDiscovery
@@ -493,7 +502,7 @@ router.post('/advanced', (req, res) => {
493
502
  statsInterval: statsInterval !== undefined ? parseInt(statsInterval) : config.statsInterval,
494
503
  enableSessionBinding: enableSessionBinding !== undefined ? enableSessionBinding : (config.enableSessionBinding !== false),
495
504
  modelDiscovery: normalizedModelDiscovery,
496
- pricing: sanitizedPricing
505
+ nativeCliLogs: normalizedNativeCliLogs
497
506
  };
498
507
 
499
508
  // 保存配置
@@ -507,7 +516,7 @@ router.post('/advanced', (req, res) => {
507
516
  statsInterval: newConfig.statsInterval,
508
517
  enableSessionBinding: newConfig.enableSessionBinding,
509
518
  modelDiscovery: newConfig.modelDiscovery,
510
- pricing: newConfig.pricing
519
+ nativeCliLogs: newConfig.nativeCliLogs
511
520
  }
512
521
  });
513
522
  } catch (error) {