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
@@ -2,9 +2,29 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { execFileSync } = require('child_process');
4
4
  const yaml = require('js-yaml');
5
- const { HOME_DIR, PATHS = {} } = require('../../config/paths');
5
+ const {
6
+ HOME_DIR,
7
+ PATHS = {},
8
+ getOmpAgentDir: resolveSharedOmpAgentDir
9
+ } = require('../../../config/paths');
6
10
 
7
11
  const DEFAULT_OMP_COMMAND = 'omp';
12
+ const OMP_RUNTIME_ENV_KEYS = [
13
+ 'PATH',
14
+ 'OMP_COMMAND',
15
+ 'OMP_CONFIG_DIR',
16
+ 'OMP_PROFILE',
17
+ 'PI_CODING_AGENT_DIR',
18
+ 'OMP_CODING_AGENT_DIR'
19
+ ];
20
+ let nativePathsOverride = null;
21
+ let cachedRuntimeResolution = null;
22
+
23
+ function configure({ pathContext } = {}) {
24
+ nativePathsOverride = pathContext?.customized && pathContext.native?.dir
25
+ ? { ...pathContext.native, agentDir: pathContext.native.dir }
26
+ : null;
27
+ }
8
28
  const YAML_DUMP_OPTIONS = Object.freeze({
9
29
  lineWidth: 120,
10
30
  noRefs: true,
@@ -88,6 +108,10 @@ function readOmpAgentDirFromCommand(command, env = process.env, options = {}) {
88
108
  function getOmpAgentDir(env = process.env, options = {}) {
89
109
  const runtime = options.runtime || (options.resolveRuntime === false ? null : resolveOmpRuntime(env, options));
90
110
  if (runtime?.runtime === 'omp' && runtime.installed) {
111
+ if (!options.commandRunner && typeof resolveSharedOmpAgentDir === 'function') {
112
+ const configuredAgentDir = resolveSharedOmpAgentDir(env);
113
+ if (configuredAgentDir) return configuredAgentDir;
114
+ }
91
115
  const commandAgentDir = readOmpAgentDirFromCommand(runtime.command, env, options);
92
116
  if (commandAgentDir) {
93
117
  return commandAgentDir;
@@ -97,6 +121,9 @@ function getOmpAgentDir(env = process.env, options = {}) {
97
121
  }
98
122
 
99
123
  function getOmpPaths(env = process.env, options = {}) {
124
+ if (nativePathsOverride && options.usePathContext !== false) {
125
+ return { ...nativePathsOverride };
126
+ }
100
127
  const runtime = options.runtime || (options.resolveRuntime === false ? null : resolveOmpRuntime(env, options));
101
128
  const agentDir = getOmpAgentDir(env, { ...options, runtime });
102
129
  return {
@@ -233,6 +260,11 @@ function getOmpCommand(env = process.env) {
233
260
  return String(env.OMP_COMMAND || DEFAULT_OMP_COMMAND).trim() || DEFAULT_OMP_COMMAND;
234
261
  }
235
262
 
263
+ function getRuntimeCacheKey(env = process.env, options = {}) {
264
+ if (typeof options.commandRunner === 'function') return '';
265
+ return JSON.stringify(OMP_RUNTIME_ENV_KEYS.map(key => [key, String(env[key] || '')]));
266
+ }
267
+
236
268
  function commandExists(command, env = process.env, options = {}) {
237
269
  try {
238
270
  runOmpCommand(command, ['--version'], env, options, 'ignore');
@@ -243,35 +275,42 @@ function commandExists(command, env = process.env, options = {}) {
243
275
  }
244
276
 
245
277
  function resolveOmpRuntime(env = process.env, options = {}) {
278
+ const cacheKey = getRuntimeCacheKey(env, options);
279
+ if (cacheKey && cachedRuntimeResolution?.key === cacheKey) {
280
+ return cachedRuntimeResolution.value;
281
+ }
282
+
246
283
  const configured = env.OMP_COMMAND;
284
+ let result;
247
285
  if (configured) {
248
286
  const command = getOmpCommand(env);
249
- return {
287
+ result = {
250
288
  command,
251
289
  runtime: 'omp',
252
290
  installed: commandExists(command, env, options),
253
291
  configured: true,
254
292
  commandSource: 'OMP_COMMAND'
255
293
  };
256
- }
257
-
258
- if (commandExists(DEFAULT_OMP_COMMAND, env, options)) {
259
- return {
294
+ } else if (commandExists(DEFAULT_OMP_COMMAND, env, options)) {
295
+ result = {
260
296
  command: DEFAULT_OMP_COMMAND,
261
297
  runtime: 'omp',
262
298
  installed: true,
263
299
  configured: false,
264
300
  commandSource: 'path'
265
301
  };
302
+ } else {
303
+ result = {
304
+ command: DEFAULT_OMP_COMMAND,
305
+ runtime: 'omp',
306
+ installed: false,
307
+ configured: false,
308
+ commandSource: 'fallback'
309
+ };
266
310
  }
267
311
 
268
- return {
269
- command: DEFAULT_OMP_COMMAND,
270
- runtime: 'omp',
271
- installed: false,
272
- configured: false,
273
- commandSource: 'fallback'
274
- };
312
+ if (cacheKey) cachedRuntimeResolution = { key: cacheKey, value: result };
313
+ return result;
275
314
  }
276
315
 
277
316
  function isOmpInstalled(env = process.env, options = {}) {
@@ -338,6 +377,7 @@ function getOmpStatus(env = process.env, options = {}) {
338
377
  }
339
378
 
340
379
  module.exports = {
380
+ configure,
341
381
  expandHome,
342
382
  getOmpAgentDir,
343
383
  getOmpPaths,
@@ -180,7 +180,11 @@ function prepareManagedOmpChannels(channels = [], gateway = {}) {
180
180
  throw new Error('OMP gateway secret is required before managed providers can be generated');
181
181
  }
182
182
 
183
- const enabled = channels.filter(channel => channel && channel.enabled !== false && channel.baseUrl);
183
+ const enabled = channels.filter(channel => (
184
+ channel
185
+ && channel.enabled !== false
186
+ && (channel.baseUrl || normalizeText(channel.authMode) === 'oauth')
187
+ ));
184
188
  const groups = new Map();
185
189
  enabled.forEach((channel) => {
186
190
  const key = getGroupKey(channel);
@@ -211,13 +215,16 @@ function prepareManagedOmpChannels(channels = [], gateway = {}) {
211
215
  }
212
216
  const authMode = normalizeText(template.authMode) || 'api_key';
213
217
  const transport = normalizeText(template.transport || template.providerConfig?.transport);
214
- const supportedOAuthIds = Array.isArray(gateway.supportedOAuthChannelIds)
215
- ? new Set(gateway.supportedOAuthChannelIds)
216
- : null;
218
+ const supportedOAuthIds = new Set(
219
+ Array.isArray(gateway.supportedOAuthChannelIds) ? gateway.supportedOAuthChannelIds : []
220
+ );
217
221
  const oauthGatewayUnavailable = authMode === 'oauth' && (
218
- !normalizeText(template.apiKey)
219
- || transport !== 'pi-native'
220
- || (supportedOAuthIds && groupChannels.some(channel => !supportedOAuthIds.has(channel.id)))
222
+ groupChannels.some(channel => (
223
+ !normalizeText(channel.baseUrl)
224
+ || !normalizeText(channel.apiKey)
225
+ || normalizeText(channel.transport || channel.providerConfig?.transport) !== 'pi-native'
226
+ || !supportedOAuthIds.has(channel.id)
227
+ ))
221
228
  );
222
229
  if (oauthGatewayUnavailable) {
223
230
  groupChannels.forEach(channel => unsupportedChannels.push({
@@ -5,24 +5,10 @@ const http = require('http');
5
5
  const https = require('https');
6
6
  const httpProxy = require('http-proxy');
7
7
  const { URL } = require('url');
8
- const { allocateChannel, releaseChannel } = require('./channel-scheduler');
9
- const { recordSuccess, recordFailure } = require('./channel-health');
10
- const { recordRequest: recordOmpRequest } = require('./omp-statistics-service');
11
- const {
12
- createTokenData,
13
- mergeUsageIntoTokenData,
14
- parseNonStreamingUsage,
15
- parseSSEEventText,
16
- parseSSEUsage,
17
- splitSSEEvents
18
- } = require('./base/response-usage-parser');
19
- const {
20
- publishFailureLog: publishSharedFailureLog,
21
- publishUsageLog: publishSharedUsageLog
22
- } = require('./proxy-log-helper');
23
- const { attachServerShutdownHandling, expediteServerShutdown } = require('./server-shutdown');
24
- const { resolveOmpGatewayRoute } = require('./omp-gateway-routing');
25
- const { broadcastLog } = require('../websocket-server');
8
+ const { allocateChannel, releaseChannel } = require('../../../server/services/channel-scheduler');
9
+ const { recordSuccess, recordFailure } = require('../../../server/services/channel-health');
10
+ const { attachServerShutdownHandling, expediteServerShutdown } = require('../../../server/services/server-shutdown');
11
+ const { resolveOmpGatewayRoute } = require('./gateway-routing');
26
12
 
27
13
  const RETRYABLE_STATUS = new Set([401, 403, 429, 502, 503, 504]);
28
14
  const MAX_REQUEST_BYTES = 100 * 1024 * 1024;
@@ -221,96 +207,6 @@ function hasValidCapability(req, parsedUrl, route) {
221
207
  return candidates.some(candidate => constantTimeEqual(candidate, route.capability));
222
208
  }
223
209
 
224
- function mergeParsedUsage(tokenData, value, eventType = '') {
225
- if (Array.isArray(value)) {
226
- value.forEach(item => mergeParsedUsage(tokenData, item, eventType));
227
- return;
228
- }
229
- mergeUsageIntoTokenData(
230
- tokenData,
231
- eventType ? parseSSEUsage(value, eventType) : parseNonStreamingUsage(value)
232
- );
233
- }
234
-
235
- function createResponseUsageMonitor(contentType = '') {
236
- const tokenData = createTokenData();
237
- const streaming = String(contentType).toLowerCase().includes('text/event-stream');
238
- const chunks = [];
239
- let bufferedBytes = 0;
240
- let sseBuffer = '';
241
- let observationDisabled = false;
242
-
243
- const parseEvent = (eventText) => {
244
- const event = parseSSEEventText(eventText);
245
- if (!event) return;
246
- try {
247
- mergeParsedUsage(tokenData, JSON.parse(event.data), event.eventType);
248
- } catch {
249
- // Usage observation must never alter or reject the transparent response.
250
- }
251
- };
252
-
253
- return {
254
- observe(chunk) {
255
- if (observationDisabled) return;
256
- if (streaming) {
257
- if (Buffer.byteLength(sseBuffer) + chunk.length > MAX_REQUEST_BYTES) {
258
- observationDisabled = true;
259
- sseBuffer = '';
260
- return;
261
- }
262
- sseBuffer += chunk.toString('utf8');
263
- const split = splitSSEEvents(sseBuffer);
264
- split.events.forEach(parseEvent);
265
- sseBuffer = split.remainder;
266
- } else if (bufferedBytes + chunk.length <= MAX_REQUEST_BYTES) {
267
- chunks.push(Buffer.from(chunk));
268
- bufferedBytes += chunk.length;
269
- } else {
270
- observationDisabled = true;
271
- chunks.length = 0;
272
- }
273
- },
274
- finish() {
275
- if (observationDisabled) {
276
- return {
277
- model: tokenData.model,
278
- tokens: {
279
- input: tokenData.inputTokens,
280
- output: tokenData.outputTokens,
281
- cacheCreation: tokenData.cacheCreation,
282
- cacheRead: tokenData.cacheRead,
283
- cached: tokenData.cachedTokens,
284
- reasoning: tokenData.reasoningTokens,
285
- total: tokenData.totalTokens
286
- }
287
- };
288
- }
289
- if (streaming) {
290
- parseEvent(sseBuffer);
291
- } else if (chunks.length > 0) {
292
- try {
293
- mergeParsedUsage(tokenData, JSON.parse(Buffer.concat(chunks).toString('utf8')));
294
- } catch {
295
- // Non-JSON responses are valid passthrough responses without usage.
296
- }
297
- }
298
- return {
299
- model: tokenData.model,
300
- tokens: {
301
- input: tokenData.inputTokens,
302
- output: tokenData.outputTokens,
303
- cacheCreation: tokenData.cacheCreation,
304
- cacheRead: tokenData.cacheRead,
305
- cached: tokenData.cachedTokens,
306
- reasoning: tokenData.reasoningTokens,
307
- total: tokenData.totalTokens
308
- }
309
- };
310
- }
311
- };
312
- }
313
-
314
210
  function closeServer(server, forceAfterMs = 1000) {
315
211
  if (!server) return Promise.resolve();
316
212
  return new Promise((resolve, reject) => {
@@ -332,59 +228,6 @@ function createOmpGateway(options = {}) {
332
228
  const release = options.releaseChannel || releaseChannel;
333
229
  const onSuccess = options.recordSuccess || recordSuccess;
334
230
  const onFailure = options.recordFailure || recordFailure;
335
- const publishUsage = options.publishUsageLog || ((data) => {
336
- const enrich = (payload) => broadcastLog({
337
- ...payload,
338
- originalProvider: data.originalProvider,
339
- providerApi: data.providerApi,
340
- routingGroup: data.routingGroup,
341
- actualChannelId: data.channelId,
342
- upstreamModel: data.model,
343
- switchReason: data.switchReason || undefined,
344
- attemptedChannels: data.attemptedChannels
345
- });
346
- return publishSharedUsageLog({
347
- source: 'omp',
348
- metadata: {
349
- id: data.requestId,
350
- channel: data.channel,
351
- channelId: data.channelId,
352
- originalModel: data.originalModel,
353
- startTime: data.startTime
354
- },
355
- model: data.model || data.originalModel,
356
- tokens: data.tokens,
357
- broadcastLog: enrich,
358
- recordRequest: recordOmpRequest,
359
- recordSuccess: null
360
- });
361
- });
362
- const publishFailure = options.publishFailureLog || ((data) => {
363
- const enrich = (payload) => broadcastLog({
364
- ...payload,
365
- originalProvider: data.originalProvider,
366
- providerApi: data.providerApi,
367
- routingGroup: data.routingGroup,
368
- actualChannelId: data.channelId,
369
- switchReason: data.switchReason || undefined,
370
- attemptedChannels: data.attemptedChannels
371
- });
372
- return publishSharedFailureLog({
373
- source: 'omp',
374
- metadata: {
375
- id: data.requestId,
376
- channel: data.channel,
377
- model: data.model
378
- },
379
- channel: data.channel,
380
- model: data.model,
381
- message: data.message,
382
- error: data.error,
383
- statusCode: data.statusCode,
384
- stage: data.stage,
385
- broadcastLog: enrich
386
- });
387
- });
388
231
  const websocketProxy = httpProxy.createProxyServer({
389
232
  ws: true,
390
233
  changeOrigin: true,
@@ -512,11 +355,7 @@ function createOmpGateway(options = {}) {
512
355
  if (signal?.aborted) throw createAbortError();
513
356
  const modelId = extractModelId(body, req.headers['content-type']);
514
357
  const attemptedIds = [];
515
- const attemptedChannels = [];
516
- const requestId = `omp-${crypto.randomUUID()}`;
517
- const startTime = Date.now();
518
358
  let lastError = null;
519
- let switchReason = '';
520
359
 
521
360
  for (let attempt = 0; attempt < 2; attempt++) {
522
361
  let channel;
@@ -532,7 +371,6 @@ function createOmpGateway(options = {}) {
532
371
  break;
533
372
  }
534
373
  attemptedIds.push(channel.id);
535
- attemptedChannels.push(channel.name || channel.id);
536
374
 
537
375
  try {
538
376
  const result = await forwardAttempt(req, route, channel, body, signal);
@@ -541,22 +379,6 @@ function createOmpGateway(options = {}) {
541
379
  result.response.resume();
542
380
  result.release();
543
381
  onFailure(channel.id, 'omp');
544
- switchReason = `http-${result.statusCode}`;
545
- publishFailure({
546
- source: 'omp',
547
- requestId,
548
- channel: channel.name || channel.id,
549
- channelId: channel.id,
550
- originalProvider: route.providerKey,
551
- providerApi: route.providerApi,
552
- routingGroup: route.routingGroup,
553
- model: modelId,
554
- statusCode: result.statusCode,
555
- stage: 'dynamic-switch',
556
- switchReason,
557
- attemptedChannels: [...attemptedChannels],
558
- message: `OMP upstream returned HTTP ${result.statusCode}`
559
- });
560
382
  lastError = Object.assign(new Error(`OMP upstream returned HTTP ${result.statusCode}`), {
561
383
  statusCode: result.statusCode
562
384
  });
@@ -564,7 +386,6 @@ function createOmpGateway(options = {}) {
564
386
  }
565
387
 
566
388
  res.writeHead(result.statusCode, result.response.headers);
567
- const usageMonitor = createResponseUsageMonitor(result.response.headers['content-type']);
568
389
  await new Promise((resolve) => {
569
390
  let completed = false;
570
391
  const finish = (error) => {
@@ -573,45 +394,12 @@ function createOmpGateway(options = {}) {
573
394
  activeUpstreams.delete(result.response);
574
395
  result.release();
575
396
  if (result.statusCode < 400 && !error) {
576
- const usage = usageMonitor.finish();
577
397
  onSuccess(channel.id, 'omp');
578
- publishUsage({
579
- source: 'omp',
580
- requestId,
581
- startTime,
582
- channel: channel.name || channel.id,
583
- channelId: channel.id,
584
- originalProvider: route.providerKey,
585
- providerApi: route.providerApi,
586
- routingGroup: route.routingGroup,
587
- originalModel: modelId,
588
- model: usage.model || modelId,
589
- tokens: usage.tokens,
590
- switchReason,
591
- attemptedChannels: [...attemptedChannels]
592
- });
593
398
  } else {
594
399
  onFailure(channel.id, 'omp');
595
- publishFailure({
596
- source: 'omp',
597
- requestId,
598
- channel: channel.name || channel.id,
599
- channelId: channel.id,
600
- originalProvider: route.providerKey,
601
- providerApi: route.providerApi,
602
- routingGroup: route.routingGroup,
603
- model: modelId,
604
- error,
605
- statusCode: result.statusCode,
606
- stage: error ? 'response-stream' : 'upstream-response',
607
- switchReason,
608
- attemptedChannels: [...attemptedChannels],
609
- message: error?.message || `OMP upstream returned HTTP ${result.statusCode}`
610
- });
611
400
  }
612
401
  resolve();
613
402
  };
614
- result.response.on('data', chunk => usageMonitor.observe(chunk));
615
403
  result.response.once('end', () => finish());
616
404
  result.response.once('close', () => finish(new Error('OMP upstream response closed early')));
617
405
  result.response.once('error', (error) => {
@@ -632,22 +420,6 @@ function createOmpGateway(options = {}) {
632
420
  break;
633
421
  }
634
422
  onFailure(channel.id, 'omp');
635
- switchReason = error.code || error.message || 'connection-error';
636
- publishFailure({
637
- source: 'omp',
638
- requestId,
639
- channel: channel.name || channel.id,
640
- channelId: channel.id,
641
- originalProvider: route.providerKey,
642
- providerApi: route.providerApi,
643
- routingGroup: route.routingGroup,
644
- model: modelId,
645
- error,
646
- statusCode: error.statusCode,
647
- stage: attempt === 0 ? 'dynamic-switch' : 'upstream-connect',
648
- switchReason,
649
- attemptedChannels: [...attemptedChannels]
650
- });
651
423
  }
652
424
  }
653
425
 
@@ -770,9 +542,6 @@ function createOmpGateway(options = {}) {
770
542
  }
771
543
 
772
544
  inflightRequests++;
773
- const requestId = `omp-${crypto.randomUUID()}`;
774
- const startTime = Date.now();
775
- const websocketModel = normalizeModelId(channel.model || '');
776
545
  let released = false;
777
546
  let failed = false;
778
547
  let failureRecorded = false;
@@ -781,19 +550,6 @@ function createOmpGateway(options = {}) {
781
550
  if (failureRecorded) return;
782
551
  failureRecorded = true;
783
552
  onFailure(channel.id, 'omp');
784
- publishFailure({
785
- source: 'omp',
786
- requestId,
787
- channel: channel.name || channel.id,
788
- channelId: channel.id,
789
- originalProvider: route.providerKey,
790
- providerApi: route.providerApi,
791
- routingGroup: route.routingGroup,
792
- model: websocketModel,
793
- error,
794
- stage: 'websocket',
795
- attemptedChannels: [channel.name || channel.id]
796
- });
797
553
  };
798
554
  const releaseOnce = () => {
799
555
  if (released) return;
@@ -801,20 +557,6 @@ function createOmpGateway(options = {}) {
801
557
  inflightRequests = Math.max(0, inflightRequests - 1);
802
558
  if (!failed) {
803
559
  onSuccess(channel.id, 'omp');
804
- publishUsage({
805
- source: 'omp',
806
- requestId,
807
- startTime,
808
- channel: channel.name || channel.id,
809
- channelId: channel.id,
810
- originalProvider: route.providerKey,
811
- providerApi: route.providerApi,
812
- routingGroup: route.routingGroup,
813
- originalModel: websocketModel,
814
- model: websocketModel,
815
- tokens: {},
816
- attemptedChannels: [channel.name || channel.id]
817
- });
818
560
  }
819
561
  release(channel.id, 'omp');
820
562
  };
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const { createMcpDriver } = require('../../../shared/driver-factories/mcp');
4
+
5
+ function createDriver(context = {}) {
6
+ return createMcpDriver({ ...context, platform: 'omp' });
7
+ }
8
+
9
+ module.exports = { createDriver };
@@ -2,9 +2,9 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const { spawnSync } = require('child_process');
4
4
  const yaml = require('js-yaml');
5
- const ompConfig = require('./omp-config');
6
- const { prepareManagedOmpChannels } = require('./omp-gateway-routing');
7
- const { MODEL_METADATA, MODEL_ALIASES } = require('../../config/model-metadata');
5
+ const ompConfig = require('./config');
6
+ const { prepareManagedOmpChannels } = require('./gateway-routing');
7
+ const { MODEL_METADATA, MODEL_ALIASES } = require('../../../config/model-metadata');
8
8
  const {
9
9
  MODEL_METADATA_MODES,
10
10
  isPlainObject,
@@ -12,7 +12,7 @@ const {
12
12
  resolveModelDefinition,
13
13
  serializeModelSelector,
14
14
  splitModelSelector
15
- } = require('./model-definition-schema');
15
+ } = require('../../../server/services/model-definition-schema');
16
16
 
17
17
  const MANAGED_PROVIDER_PREFIX = 'ctx-';
18
18
  const MODELS_BACKUP_MARKER = '.ctx-backup-';
@@ -695,6 +695,57 @@ function buildManagedModelsConfig(channels = [], baseConfig = readModelsConfig()
695
695
  return next;
696
696
  }
697
697
 
698
+ function isNativeOmpOAuthChannel(channel = {}) {
699
+ return channel
700
+ && channel.enabled !== false
701
+ && channel.authMode === 'oauth'
702
+ && !String(channel.baseUrl || '').trim();
703
+ }
704
+
705
+ function collectNativeOmpOAuthVisibility(channels = []) {
706
+ const enabledModels = [];
707
+ let defaultModel = null;
708
+
709
+ (channels || []).filter(isNativeOmpOAuthChannel).forEach((channel) => {
710
+ const rawProviderId = String(
711
+ channel.oauthProviderId || channel.authRef?.providerId || ''
712
+ ).trim();
713
+ if (!rawProviderId) return;
714
+ const providerId = normalizeProviderId(rawProviderId);
715
+
716
+ const allowedModels = Array.isArray(channel.allowedModels) ? channel.allowedModels : [];
717
+ const candidates = allowedModels.length > 0
718
+ ? allowedModels
719
+ : [
720
+ ...(Array.isArray(channel.models) ? channel.models : []),
721
+ channel.model
722
+ ];
723
+ const modelIds = [];
724
+ candidates.forEach((value) => {
725
+ const rawId = typeof value === 'object' && value !== null
726
+ ? value.id || value.name
727
+ : value;
728
+ const selector = splitModelSelector(rawId || '');
729
+ if (selector.modelId && !modelIds.some(id => id.toLowerCase() === selector.modelId.toLowerCase())) {
730
+ modelIds.push(selector.modelId);
731
+ }
732
+ });
733
+
734
+ modelIds.forEach((modelId) => {
735
+ pushUnique(enabledModels, `${providerId}/${modelId}`);
736
+ });
737
+
738
+ if (!defaultModel) {
739
+ const selected = splitModelSelector(channel.model || '');
740
+ if (selected.modelId && modelIds.some(id => id.toLowerCase() === selected.modelId.toLowerCase())) {
741
+ defaultModel = `${providerId}/${serializeModelSelector(selected.modelId, selected.thinkingLevel)}`;
742
+ }
743
+ }
744
+ });
745
+
746
+ return { enabledModels, defaultModel };
747
+ }
748
+
698
749
  function getOriginalProviderId(channel = {}) {
699
750
  if (channel.originalProviderId) {
700
751
  return normalizeProviderId(channel.originalProviderId);
@@ -711,6 +762,10 @@ function collectManagedVisibility(channels = [], modelsConfig = { providers: {}
711
762
  const warnings = [];
712
763
  const providers = modelsConfig.providers || {};
713
764
  let managedDefaultModel = null;
765
+ const nativeOAuthVisibility = collectNativeOmpOAuthVisibility([
766
+ ...(Array.isArray(channels) ? channels : []),
767
+ ...(Array.isArray(options.nativeOAuthChannels) ? options.nativeOAuthChannels : [])
768
+ ]);
714
769
 
715
770
  (channels || [])
716
771
  .filter(channel => channel && channel.enabled !== false && channel.baseUrl)
@@ -761,13 +816,21 @@ function collectManagedVisibility(channels = [], modelsConfig = { providers: {}
761
816
  }
762
817
  }
763
818
 
819
+ const visibleModels = uniqueStrings([
820
+ ...managedEnabledModels,
821
+ ...nativeOAuthVisibility.enabledModels
822
+ ]);
823
+
764
824
  return {
765
- managedEnabledModels,
766
- managedEnabledModelsForSettings: managedEnabledModels.length > 0
767
- ? managedEnabledModels
825
+ managedEnabledModels: visibleModels,
826
+ managedEnabledModelsForSettings: visibleModels.length > 0
827
+ ? visibleModels
768
828
  : [NO_MANAGED_MODELS_SELECTOR],
769
829
  managedDisabledProviders,
770
- managedDefaultModel: managedDefaultModel || managedEnabledModels[0] || null,
830
+ managedDefaultModel: managedDefaultModel
831
+ || nativeOAuthVisibility.defaultModel
832
+ || visibleModels[0]
833
+ || null,
771
834
  warnings
772
835
  };
773
836
  }
@@ -898,7 +961,6 @@ function syncManagedOmpVisibility(channels = [], modelsConfig = { providers: {}
898
961
  : captureOriginalVisibility(settings);
899
962
  const before = JSON.stringify(settings);
900
963
  const settingsBackupPath = createModelsBackupIfNeeded(settingsPath, options);
901
-
902
964
  settings.enabledModels = visibility.managedEnabledModelsForSettings;
903
965
  settings.disabledProviders = uniqueStrings([
904
966
  ...collectUserDisabledProviders(settings, previousState),
@@ -1134,7 +1196,10 @@ function writeManagedOmpProviders(channels = [], options = {}) {
1134
1196
  });
1135
1197
  const backupPath = createModelsBackupIfNeeded(paths.modelsYml, options);
1136
1198
  writeModelsConfig(config, paths.modelsYml);
1137
- const visibility = syncManagedOmpVisibility(effectiveChannels, config, options);
1199
+ const visibility = syncManagedOmpVisibility(effectiveChannels, config, {
1200
+ ...options,
1201
+ nativeOAuthChannels: channels.filter(isNativeOmpOAuthChannel)
1202
+ });
1138
1203
  const validation = options.validateWithCli === true
1139
1204
  ? validateOmpModelsConfig(options)
1140
1205
  : { skipped: true, reason: 'cli-validation-disabled', warnings: [] };