coding-tool-x 3.8.3 → 3.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +86 -15
  3. package/dist/web/assets/AgentsDrawer-BG6P3DX-.js +1 -0
  4. package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
  5. package/dist/web/assets/Analytics--z_FmL5P.js +1 -0
  6. package/dist/web/assets/Analytics-CyHhR126.css +1 -0
  7. package/dist/web/assets/AssetPathField-CrJtRKHy.js +1 -0
  8. package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
  9. package/dist/web/assets/ChatHistoryDrawer-BiuEryJj.js +1 -0
  10. package/dist/web/assets/CollapseItem-BAYEsL_Q.js +1 -0
  11. package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
  12. package/dist/web/assets/CommandsDrawer-YJ-U7BXN.js +1 -0
  13. package/dist/web/assets/ConfigExportDrawer-Ce_hAknW.js +1 -0
  14. package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
  15. package/dist/web/assets/ConfigTemplates-Bvr1NN6K.js +1 -0
  16. package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
  17. package/dist/web/assets/ConfigTemplatesDrawer-BjIeHfF-.js +1 -0
  18. package/dist/web/assets/ConfigTemplatesPanel-AV00tm_D.js +1 -0
  19. package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +1 -0
  20. package/dist/web/assets/Divider-D28g1gwj.js +1 -0
  21. package/dist/web/assets/DrawerContent-ChXgZ1Xm.js +1 -0
  22. package/dist/web/assets/FavoritesDrawer-CG9eI9Ay.css +1 -0
  23. package/dist/web/assets/FavoritesDrawer-Cz95o4CD.js +1 -0
  24. package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
  25. package/dist/web/assets/GatewayConvertDrawer-DLlbMz27.js +1 -0
  26. package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
  27. package/dist/web/assets/Home-D7CCOFQC.js +1 -0
  28. package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
  29. package/dist/web/assets/MarkdownEditor-rEZ-c72L.js +1 -0
  30. package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
  31. package/dist/web/assets/McpDrawer-DfoCyxU2.js +1 -0
  32. package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
  33. package/dist/web/assets/McpFormDrawer-SKu8HNUR.js +1 -0
  34. package/dist/web/assets/PluginManager-BbeK-3rV.js +1 -0
  35. package/dist/web/assets/PluginsDrawer-CWVJ7yjS.js +1 -0
  36. package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
  37. package/dist/web/assets/PluginsPanel-Cm2N3StG.js +1 -0
  38. package/dist/web/assets/PluginsPanel-D6ZqITcR.css +1 -0
  39. package/dist/web/assets/ProjectList-677RLZ8O.css +1 -0
  40. package/dist/web/assets/ProjectList-CsjnsNPv.js +1 -0
  41. package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
  42. package/dist/web/assets/PromptsDrawer-EGd3djFa.js +1 -0
  43. package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
  44. package/dist/web/assets/RecentSessionsDrawer-D1vtoLAs.js +1 -0
  45. package/dist/web/assets/SessionCard-BgLg49U3.js +1 -0
  46. package/dist/web/assets/SessionCard-aM2NHu6i.css +1 -0
  47. package/dist/web/assets/SessionList-BpYRz1cX.css +1 -0
  48. package/dist/web/assets/SessionList-TRiTklWk.js +1 -0
  49. package/dist/web/assets/SettingsDrawer-d5liXjHq.css +1 -0
  50. package/dist/web/assets/SettingsDrawer-rz2WejGY.js +1 -0
  51. package/dist/web/assets/SkillManager-BTjTUbHq.js +1 -0
  52. package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
  53. package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
  54. package/dist/web/assets/SkillsDrawer-pN0hbkK3.js +1 -0
  55. package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
  56. package/dist/web/assets/SkillsPanel-gmBWEoiF.js +1 -0
  57. package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
  58. package/dist/web/assets/SpeedTestDrawer-DcNzuVJk.js +1 -0
  59. package/dist/web/assets/Upload-v5rV0qTT.js +1 -0
  60. package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
  61. package/dist/web/assets/WorkspaceDrawer-DxmicM4U.js +1 -0
  62. package/dist/web/assets/WorkspaceManager-CJHCjARN.js +1 -0
  63. package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
  64. package/dist/web/assets/WorkspacePanel-D8_Zq-du.js +1 -0
  65. package/dist/web/assets/_plugin-vue_export-helper-BeLZJZij.js +1 -0
  66. package/dist/web/assets/client-UDwXBP9i.js +1 -0
  67. package/dist/web/assets/clipboard-B46yyoz_.js +1 -0
  68. package/dist/web/assets/headers-cf-QapUq.js +1 -0
  69. package/dist/web/assets/icons-B2Vg-IOC.js +1 -0
  70. package/dist/web/assets/index-C0EHRym0.css +1 -0
  71. package/dist/web/assets/index-DnEocV0M.js +2 -0
  72. package/dist/web/assets/light-Cp0t7v32.js +1 -0
  73. package/dist/web/assets/markdown-u082bbtj.js +1 -0
  74. package/dist/web/assets/platforms-CBkB45JP.js +1 -0
  75. package/dist/web/assets/platforms-FTpjxAT6.js +1 -0
  76. package/dist/web/assets/project-config-B2baPzYL.js +1 -0
  77. package/dist/web/assets/sessions-Cmy31slD.js +1 -0
  78. package/dist/web/assets/sessions-yC_oVVh8.js +1 -0
  79. package/dist/web/assets/skill-repo-input-B_fkGlUK.js +1 -0
  80. package/dist/web/assets/use-lock-html-scroll-DXIqmUW4.js +1 -0
  81. package/dist/web/assets/use-message-DoLM8C1C.js +1 -0
  82. package/dist/web/assets/useResponsiveDrawer-B3uojyvV.js +1 -0
  83. package/dist/web/assets/vendors-D0c_0KLP.js +1 -0
  84. package/dist/web/assets/vue-vendor-BqZbbXHA.js +1 -0
  85. package/dist/web/assets/workspaces-mjyPVGS8.js +1 -0
  86. package/dist/web/assets/xml-CgY3RMlX.js +1 -0
  87. package/dist/web/index.html +12 -8
  88. package/docs/native-log-memory-2026-09-16.md +43 -0
  89. package/docs/superpowers/plans/2026-08-26-configuration-driven-cli-platform.md +1578 -0
  90. package/docs/superpowers/plans/2026-08-30-project-scoped-config-control.md +1260 -0
  91. package/docs/superpowers/plans/2026-09-01-omp-skill-refresh-boundary.md +213 -0
  92. package/docs/superpowers/plans/2026-09-01-realtime-logs-panel.md +125 -0
  93. package/docs/superpowers/plans/2026-09-02-config-driven-platform-boundary.md +86 -0
  94. package/docs/superpowers/plans/2026-09-02-platform-implementation-drivers.md +508 -0
  95. package/docs/superpowers/plans/2026-09-03-cli-platform-correctness-boundary.md +760 -0
  96. package/docs/superpowers/plans/2026-09-03-dependency-security-remediation.md +133 -0
  97. package/docs/superpowers/plans/2026-09-04-model-catalog-pricing-sync.md +1078 -0
  98. package/docs/superpowers/plans/2026-09-05-codex-project-scan-500.md +128 -0
  99. package/docs/superpowers/plans/2026-09-06-project-skill-path-fix.md +97 -0
  100. package/docs/superpowers/specs/2026-08-26-configuration-driven-cli-platform-design.md +408 -0
  101. package/docs/superpowers/specs/2026-08-30-project-scoped-config-control-design.md +467 -0
  102. package/docs/superpowers/specs/2026-09-01-claude-session-content-repair-design.md +111 -0
  103. package/docs/superpowers/specs/2026-09-01-omp-skill-refresh-boundary-design.md +83 -0
  104. package/docs/superpowers/specs/2026-09-01-realtime-logs-panel-design.md +27 -0
  105. package/docs/superpowers/specs/2026-09-02-config-driven-platform-boundary-design.md +64 -0
  106. package/docs/superpowers/specs/2026-09-02-platform-implementation-driver-boundary-design.md +123 -0
  107. package/docs/superpowers/specs/2026-09-03-cli-platform-correctness-boundary-design.md +249 -0
  108. package/docs/superpowers/specs/2026-09-03-dependency-security-remediation-design.md +87 -0
  109. package/docs/superpowers/specs/2026-09-04-model-catalog-pricing-sync-design.md +301 -0
  110. package/docs/superpowers/specs/2026-09-05-codex-project-scan-500-design.md +24 -0
  111. package/package.json +13 -8
  112. package/src/commands/channels.js +88 -191
  113. package/src/commands/cli-type.js +19 -11
  114. package/src/commands/daemon.js +94 -32
  115. package/src/commands/doctor.js +16 -9
  116. package/src/commands/export-config.js +23 -5
  117. package/src/commands/list.js +130 -52
  118. package/src/commands/logs.js +44 -27
  119. package/src/commands/platform-command-registry.js +78 -0
  120. package/src/commands/plugin.js +11 -5
  121. package/src/commands/port-config.js +34 -52
  122. package/src/commands/proxy-control.js +207 -145
  123. package/src/commands/proxy.js +2 -2
  124. package/src/commands/resume.js +87 -91
  125. package/src/commands/search.js +137 -67
  126. package/src/commands/stats.js +30 -22
  127. package/src/commands/switch.js +1 -1
  128. package/src/commands/toggle-proxy.js +94 -111
  129. package/src/commands/ui.js +67 -6
  130. package/src/commands/workspace.js +90 -8
  131. package/src/config/default.js +6 -53
  132. package/src/config/loader.js +61 -24
  133. package/src/config/model-metadata.js +49 -59
  134. package/src/config/model-metadata.json +4095 -99
  135. package/src/config/paths.js +181 -8
  136. package/src/index.js +134 -71
  137. package/src/platforms/access.js +196 -0
  138. package/src/{server/services → platforms}/agents-service.js +354 -197
  139. package/src/platforms/channel-auth-registry.js +162 -0
  140. package/src/platforms/channel-auth-service.js +82 -0
  141. package/src/{server/services → platforms}/commands-service.js +195 -115
  142. package/src/platforms/driver-registry.js +59 -0
  143. package/src/platforms/drivers/claude/api-operations.js +62 -0
  144. package/src/{server/services/channels.js → platforms/drivers/claude/channels-implementation.js} +131 -33
  145. package/src/platforms/drivers/claude/channels.js +39 -0
  146. package/src/{server/services/config-sync-service.js → platforms/drivers/claude/config-sync.js} +29 -5
  147. package/src/{server/services → platforms/drivers/claude}/health-check.js +4 -4
  148. package/src/platforms/drivers/claude/health.js +22 -0
  149. package/src/platforms/drivers/claude/mcp.js +9 -0
  150. package/src/{server/services/settings-manager.js → platforms/drivers/claude/native-config-implementation.js} +13 -4
  151. package/src/platforms/drivers/claude/native-config.js +46 -0
  152. package/src/platforms/drivers/claude/native-logs.js +72 -0
  153. package/src/{server/services/claude-openai-gateway.js → platforms/drivers/claude/openai-gateway.js} +8 -65
  154. package/src/platforms/drivers/claude/project-config.js +21 -0
  155. package/src/platforms/drivers/claude/projects.js +62 -0
  156. package/src/platforms/drivers/claude/prompts.js +9 -0
  157. package/src/{server/proxy-server.js → platforms/drivers/claude/proxy-implementation.js} +41 -278
  158. package/src/platforms/drivers/claude/proxy.js +16 -0
  159. package/src/platforms/drivers/claude/resource-sync.js +9 -0
  160. package/src/platforms/drivers/claude/session-history-adapter.js +313 -0
  161. package/src/{server/services/sessions.js → platforms/drivers/claude/sessions-implementation.js} +145 -35
  162. package/src/platforms/drivers/claude/sessions.js +76 -0
  163. package/src/{server/services/claude-statistics-service.js → platforms/drivers/claude/statistics-implementation.js} +2 -2
  164. package/src/platforms/drivers/claude/statistics.js +16 -0
  165. package/src/{server/services/claude-wire.js → platforms/drivers/claude/wire.js} +1 -1
  166. package/src/platforms/drivers/codex/api-operations.js +9 -0
  167. package/src/{server/services/codex-channels.js → platforms/drivers/codex/channels-implementation.js} +149 -14
  168. package/src/platforms/drivers/codex/channels.js +45 -0
  169. package/src/{server/services/codex-config.js → platforms/drivers/codex/config.js} +12 -2
  170. package/src/{server/services/codex-env-manager.js → platforms/drivers/codex/env-manager.js} +1 -1
  171. package/src/platforms/drivers/codex/mcp.js +9 -0
  172. package/src/{server/services/codex-settings-manager.js → platforms/drivers/codex/native-config-implementation.js} +15 -6
  173. package/src/platforms/drivers/codex/native-config.js +47 -0
  174. package/src/platforms/drivers/codex/native-logs.js +166 -0
  175. package/src/platforms/drivers/codex/project-config.js +21 -0
  176. package/src/platforms/drivers/codex/projects.js +26 -0
  177. package/src/platforms/drivers/codex/prompts.js +9 -0
  178. package/src/{server/codex-proxy-server.js → platforms/drivers/codex/proxy-implementation.js} +30 -233
  179. package/src/platforms/drivers/codex/proxy.js +16 -0
  180. package/src/platforms/drivers/codex/resource-sync.js +9 -0
  181. package/src/{server/services/session-history-adapters/codex.js → platforms/drivers/codex/session-history-adapter.js} +37 -23
  182. package/src/{server/services/codex-sessions.js → platforms/drivers/codex/sessions-implementation.js} +81 -75
  183. package/src/platforms/drivers/codex/sessions.js +36 -0
  184. package/src/{server/services/codex-statistics-service.js → platforms/drivers/codex/statistics-implementation.js} +2 -2
  185. package/src/platforms/drivers/codex/statistics.js +16 -0
  186. package/src/platforms/drivers/gemini/api-operations.js +9 -0
  187. package/src/{server/services/gemini-channels.js → platforms/drivers/gemini/channels-implementation.js} +202 -37
  188. package/src/platforms/drivers/gemini/channels.js +39 -0
  189. package/src/{server/services/gemini-config.js → platforms/drivers/gemini/config.js} +12 -2
  190. package/src/platforms/drivers/gemini/mcp.js +9 -0
  191. package/src/{server/services/gemini-settings-manager.js → platforms/drivers/gemini/native-config-implementation.js} +14 -5
  192. package/src/platforms/drivers/gemini/native-config.js +39 -0
  193. package/src/platforms/drivers/gemini/native-logs.js +180 -0
  194. package/src/platforms/drivers/gemini/project-config.js +21 -0
  195. package/src/platforms/drivers/gemini/projects.js +26 -0
  196. package/src/platforms/drivers/gemini/prompts.js +9 -0
  197. package/src/{server/gemini-proxy-server.js → platforms/drivers/gemini/proxy-implementation.js} +36 -267
  198. package/src/platforms/drivers/gemini/proxy.js +16 -0
  199. package/src/platforms/drivers/gemini/resource-sync.js +9 -0
  200. package/src/{server/services/session-history-adapters/gemini.js → platforms/drivers/gemini/session-history-adapter.js} +70 -18
  201. package/src/{server/services/gemini-sessions.js → platforms/drivers/gemini/sessions-implementation.js} +53 -37
  202. package/src/platforms/drivers/gemini/sessions.js +47 -0
  203. package/src/{server/services/gemini-statistics-service.js → platforms/drivers/gemini/statistics-implementation.js} +2 -2
  204. package/src/platforms/drivers/gemini/statistics.js +16 -0
  205. package/src/{server/services/gemini-wire.js → platforms/drivers/gemini/wire.js} +1 -1
  206. package/src/platforms/drivers/generic-filesystem.js +166 -0
  207. package/src/platforms/drivers/generic-jsonl.js +141 -0
  208. package/src/platforms/drivers/generic-mcp.js +44 -0
  209. package/src/platforms/drivers/generic-openai-compatible.js +45 -0
  210. package/src/platforms/drivers/generic-prompt.js +41 -0
  211. package/src/platforms/drivers/legacy.js +677 -0
  212. package/src/platforms/drivers/native-config-snapshot.js +125 -0
  213. package/src/platforms/drivers/native-log-utils.js +1292 -0
  214. package/src/platforms/drivers/notification-hooks.js +578 -0
  215. package/src/{server/api/omp-config.js → platforms/drivers/omp/api-operations.js} +52 -64
  216. package/src/{server/services/omp-auth-provider-worker.js → platforms/drivers/omp/auth-provider-worker.js} +1 -1
  217. package/src/{server/services/omp-auth-providers.js → platforms/drivers/omp/auth-providers.js} +1 -1
  218. package/src/{server/services/omp-channels.js → platforms/drivers/omp/channels-implementation.js} +166 -39
  219. package/src/platforms/drivers/omp/channels.js +58 -0
  220. package/src/{server/services/omp-config.js → platforms/drivers/omp/config.js} +53 -13
  221. package/src/{server/services/omp-gateway-routing.js → platforms/drivers/omp/gateway-routing.js} +14 -7
  222. package/src/{server/services/omp-gateway.js → platforms/drivers/omp/gateway.js} +4 -262
  223. package/src/platforms/drivers/omp/mcp.js +9 -0
  224. package/src/{server/services/omp-settings-manager.js → platforms/drivers/omp/native-config-implementation.js} +75 -10
  225. package/src/platforms/drivers/omp/native-config.js +46 -0
  226. package/src/platforms/drivers/omp/native-logs.js +52 -0
  227. package/src/{server/services/omp-native-plugin-adapter.js → platforms/drivers/omp/native-plugin-adapter.js} +91 -4
  228. package/src/platforms/drivers/omp/project-config.js +29 -0
  229. package/src/platforms/drivers/omp/projects.js +20 -0
  230. package/src/platforms/drivers/omp/prompts.js +9 -0
  231. package/src/{server/omp-proxy-server.js → platforms/drivers/omp/proxy-implementation.js} +6 -15
  232. package/src/platforms/drivers/omp/proxy.js +16 -0
  233. package/src/platforms/drivers/omp/resource-sync.js +9 -0
  234. package/src/{server/services/session-history-adapters/omp.js → platforms/drivers/omp/session-history-adapter.js} +42 -18
  235. package/src/{server/services/omp-sessions.js → platforms/drivers/omp/sessions-implementation.js} +130 -94
  236. package/src/platforms/drivers/omp/sessions.js +36 -0
  237. package/src/{server/services/omp-skill-discovery.js → platforms/drivers/omp/skill-discovery.js} +159 -32
  238. package/src/{server/services/omp-skill-settings-service.js → platforms/drivers/omp/skill-settings.js} +1 -1
  239. package/src/{server/services/omp-statistics-service.js → platforms/drivers/omp/statistics-implementation.js} +3 -3
  240. package/src/platforms/drivers/omp/statistics.js +16 -0
  241. package/src/platforms/drivers/opencode/api-operations.js +9 -0
  242. package/src/{server/services/opencode-channels.js → platforms/drivers/opencode/channels-implementation.js} +28 -9
  243. package/src/platforms/drivers/opencode/channels.js +40 -0
  244. package/src/platforms/drivers/opencode/conversion.js +41 -0
  245. package/src/{server/services/opencode-gateway-converter.js → platforms/drivers/opencode/gateway-converter.js} +1 -1
  246. package/src/platforms/drivers/opencode/mcp.js +9 -0
  247. package/src/{server/services/opencode-settings-manager.js → platforms/drivers/opencode/native-config-implementation.js} +17 -6
  248. package/src/platforms/drivers/opencode/native-config.js +26 -0
  249. package/src/platforms/drivers/opencode/native-logs.js +133 -0
  250. package/src/platforms/drivers/opencode/project-config.js +98 -0
  251. package/src/platforms/drivers/opencode/projects.js +20 -0
  252. package/src/platforms/drivers/opencode/prompts.js +9 -0
  253. package/src/{server/opencode-proxy-server.js → platforms/drivers/opencode/proxy-implementation.js} +27 -362
  254. package/src/platforms/drivers/opencode/proxy.js +16 -0
  255. package/src/platforms/drivers/opencode/resource-sync.js +9 -0
  256. package/src/{server/services/opencode-sessions.js → platforms/drivers/opencode/sessions-implementation.js} +211 -64
  257. package/src/platforms/drivers/opencode/sessions.js +48 -0
  258. package/src/{server/services/opencode-statistics-service.js → platforms/drivers/opencode/statistics-implementation.js} +2 -2
  259. package/src/platforms/drivers/opencode/statistics.js +16 -0
  260. package/src/platforms/drivers/secure-file-driver.js +272 -0
  261. package/src/platforms/drivers/unsupported.js +7 -0
  262. package/src/platforms/manifest-schema.js +398 -0
  263. package/src/platforms/manifests/claude.json +489 -0
  264. package/src/platforms/manifests/codex.json +448 -0
  265. package/src/platforms/manifests/gemini.json +447 -0
  266. package/src/platforms/manifests/omp.json +496 -0
  267. package/src/platforms/manifests/opencode.json +422 -0
  268. package/src/{server/services → platforms}/native-oauth-adapters.js +87 -417
  269. package/src/{server/services → platforms}/notification-hooks.js +140 -1023
  270. package/src/platforms/oauth-credentials-service.js +506 -0
  271. package/src/platforms/path-resolver.js +179 -0
  272. package/src/platforms/platform-path-context.js +305 -0
  273. package/src/platforms/registry.js +248 -0
  274. package/src/platforms/remote-notification-providers.js +678 -0
  275. package/src/platforms/runtime.js +259 -0
  276. package/src/{server/services/session-history-adapters/index.js → platforms/session-history-adapters.js} +8 -1
  277. package/src/plugins/plugin-loader.js +2 -2
  278. package/src/plugins/plugin-manager.js +2 -2
  279. package/src/plugins/registry.js +27 -10
  280. package/src/reset-config.js +21 -5
  281. package/src/server/api/agents.js +46 -72
  282. package/src/server/api/commands.js +16 -6
  283. package/src/server/api/config-registry.js +206 -59
  284. package/src/server/api/config-sync.js +3 -2
  285. package/src/server/api/config-templates.js +20 -4
  286. package/src/server/api/config.js +111 -102
  287. package/src/server/api/convert.js +54 -178
  288. package/src/server/api/dashboard.js +168 -102
  289. package/src/server/api/hooks.js +1 -1
  290. package/src/server/api/mcp.js +224 -84
  291. package/src/server/api/platform-api-config.js +102 -0
  292. package/src/server/api/platform-route-factory.js +215 -0
  293. package/src/server/api/platform-routes.js +26 -0
  294. package/src/server/api/platforms.js +110 -0
  295. package/src/server/api/plugins.js +57 -57
  296. package/src/server/api/project-config.js +168 -0
  297. package/src/server/api/prompts.js +58 -45
  298. package/src/server/api/settings.js +55 -8
  299. package/src/server/api/skills.js +262 -133
  300. package/src/server/api/ui-config.js +2 -2
  301. package/src/server/api/validation-errors.js +18 -4
  302. package/src/server/api/workspaces.js +47 -12
  303. package/src/server/index.js +164 -213
  304. package/src/server/platform-context.js +81 -0
  305. package/src/server/services/channel-balance.js +11 -20
  306. package/src/server/services/channel-health.js +21 -6
  307. package/src/server/services/channel-scheduler.js +29 -39
  308. package/src/server/services/channel-sync-utils.js +23 -13
  309. package/src/server/services/config-export-service.js +350 -319
  310. package/src/server/services/config-registry-service.js +280 -54
  311. package/src/server/services/config-sync-manager.js +172 -944
  312. package/src/server/services/config-templates-service.js +419 -353
  313. package/src/server/services/control-manifest-store.js +206 -0
  314. package/src/server/services/dashboard-snapshot-worker.js +656 -100
  315. package/src/server/services/effective-control-service.js +557 -0
  316. package/src/server/services/local-resource-index.js +314 -0
  317. package/src/server/services/mcp-service.js +607 -977
  318. package/src/server/services/model-detector.js +15 -10
  319. package/src/server/services/native-log-channel-resolver.js +214 -0
  320. package/src/server/services/native-log-observer.js +291 -0
  321. package/src/server/services/network-access.js +1 -1
  322. package/src/server/services/platform-catalog.js +82 -0
  323. package/src/server/services/platform-resolution.js +32 -29
  324. package/src/server/services/plugins-service.js +376 -122
  325. package/src/server/services/project-config-service.js +550 -0
  326. package/src/server/services/project-path-validation.js +31 -0
  327. package/src/server/services/prompts-service.js +267 -233
  328. package/src/server/services/proxy-runtime.js +7 -4
  329. package/src/server/services/remote-credential-cache.js +43 -0
  330. package/src/server/services/repo-scanner-base.js +182 -75
  331. package/src/server/services/request-logger.js +7 -4
  332. package/src/server/services/session-history-index.js +780 -213
  333. package/src/server/services/session-history-worker.js +228 -33
  334. package/src/server/services/session-snapshot-worker.js +124 -34
  335. package/src/server/services/session-snapshots.js +4 -2
  336. package/src/server/services/skill-artifact-store.js +355 -0
  337. package/src/server/services/skill-format-adapters.js +65 -0
  338. package/src/server/services/skill-projection-service.js +323 -0
  339. package/src/server/services/skill-refresh-task-service.js +275 -0
  340. package/src/server/services/skill-service.js +2020 -677
  341. package/src/server/services/snapshot-cache.js +30 -8
  342. package/src/server/services/speed-test.js +8 -8
  343. package/src/server/services/sqlite-connection.js +19 -3
  344. package/src/server/services/statistics-service.js +240 -57
  345. package/src/server/services/ui-config.js +107 -76
  346. package/src/server/services/usage-log-utils.js +98 -0
  347. package/src/server/services/web-build.js +1 -1
  348. package/src/server/services/workspace-service.js +59 -29
  349. package/src/server/utils/pricing.js +10 -19
  350. package/src/server/websocket-server.js +153 -28
  351. package/src/{server/services/base → shared}/base-channel-service.js +156 -28
  352. package/src/shared/capability-driver.js +104 -0
  353. package/src/shared/channel-auth-policy.js +27 -0
  354. package/src/shared/channel-driver.js +161 -0
  355. package/src/shared/driver-factories/api.js +180 -0
  356. package/src/shared/driver-factories/mcp.js +244 -0
  357. package/src/shared/driver-factories/projects.js +121 -0
  358. package/src/shared/driver-factories/prompts.js +58 -0
  359. package/src/shared/driver-factories/resource-sync.js +375 -0
  360. package/src/shared/driver-result.js +78 -0
  361. package/src/shared/mcp-format.js +189 -0
  362. package/src/shared/platforms.js +104 -167
  363. package/src/shared/project-config.js +512 -0
  364. package/src/shared/proxy-driver.js +57 -0
  365. package/src/{server/services/base → shared}/response-usage-parser.js +8 -4
  366. package/src/ui/menu.js +91 -67
  367. package/src/utils/port-helper.js +35 -19
  368. package/src/utils/session.js +1 -1
  369. package/dist/web/assets/Analytics-COEUXmd4.js +0 -25
  370. package/dist/web/assets/Analytics-RNn1BUbG.css +0 -1
  371. package/dist/web/assets/ConfigTemplates-DLLkS53H.js +0 -1
  372. package/dist/web/assets/Home-DCEyLzwX.js +0 -1
  373. package/dist/web/assets/Home-DYVy4cGZ.css +0 -1
  374. package/dist/web/assets/PluginManager-Oe1ZHoMO.js +0 -1
  375. package/dist/web/assets/ProjectList-CWjuAFof.js +0 -1
  376. package/dist/web/assets/ProjectList-VeMNXfgO.css +0 -1
  377. package/dist/web/assets/SessionList-C4chCPxK.css +0 -1
  378. package/dist/web/assets/SessionList-v3ehGg9U.js +0 -1
  379. package/dist/web/assets/SkillManager-BsX8Qpj0.css +0 -1
  380. package/dist/web/assets/SkillManager-DUF_qP5S.js +0 -1
  381. package/dist/web/assets/WorkspaceManager-CjAWBosO.js +0 -1
  382. package/dist/web/assets/icons-nGdSKQn2.js +0 -1
  383. package/dist/web/assets/index-D5hyHPj7.js +0 -2
  384. package/dist/web/assets/index-bJRG3RXH.css +0 -1
  385. package/dist/web/assets/markdown-BNJfEgCA.js +0 -1
  386. package/dist/web/assets/markdown-BfC0goYb.css +0 -10
  387. package/dist/web/assets/naive-ui-BALVpMgd.js +0 -1
  388. package/dist/web/assets/vendors-DQA4Hw9v.js +0 -7
  389. package/dist/web/assets/vue-vendor-B5RqjEjQ.js +0 -45
  390. package/src/config/model-pricing.js +0 -35
  391. package/src/server/api/channels.js +0 -439
  392. package/src/server/api/claude-hooks.js +0 -56
  393. package/src/server/api/claude-statistics.js +0 -57
  394. package/src/server/api/codex-channels.js +0 -491
  395. package/src/server/api/codex-projects.js +0 -117
  396. package/src/server/api/codex-proxy.js +0 -293
  397. package/src/server/api/codex-sessions.js +0 -652
  398. package/src/server/api/codex-statistics.js +0 -57
  399. package/src/server/api/gemini-channels.js +0 -392
  400. package/src/server/api/gemini-projects.js +0 -103
  401. package/src/server/api/gemini-proxy.js +0 -231
  402. package/src/server/api/gemini-sessions.js +0 -550
  403. package/src/server/api/gemini-statistics.js +0 -57
  404. package/src/server/api/health-check.js +0 -31
  405. package/src/server/api/oauth-credentials.js +0 -198
  406. package/src/server/api/omp-channels.js +0 -575
  407. package/src/server/api/omp-projects.js +0 -88
  408. package/src/server/api/omp-proxy.js +0 -125
  409. package/src/server/api/omp-sessions.js +0 -386
  410. package/src/server/api/omp-statistics.js +0 -40
  411. package/src/server/api/opencode-channels.js +0 -471
  412. package/src/server/api/opencode-projects.js +0 -110
  413. package/src/server/api/opencode-proxy.js +0 -354
  414. package/src/server/api/opencode-sessions.js +0 -466
  415. package/src/server/api/opencode-statistics.js +0 -57
  416. package/src/server/api/projects.js +0 -120
  417. package/src/server/api/proxy.js +0 -330
  418. package/src/server/api/sessions.js +0 -810
  419. package/src/server/services/oauth-credentials-service.js +0 -945
  420. package/src/server/services/omp-session-log-observer.js +0 -138
  421. package/src/server/services/opencode-gateway-adapters.js +0 -43
  422. package/src/server/services/project-snapshots.js +0 -59
  423. package/src/server/services/proxy-log-helper.js +0 -298
  424. package/src/server/services/session-cache.js +0 -127
  425. package/src/server/services/session-converter.js +0 -582
  426. package/src/server/services/session-history-adapters/claude.js +0 -235
  427. /package/src/{server/services/claude-token-recovery.js → platforms/drivers/claude/token-recovery.js} +0 -0
  428. /package/src/{server/services/codex-parser.js → platforms/drivers/codex/parser.js} +0 -0
  429. /package/src/{server/services/codex-speed-test-template.json → platforms/drivers/codex/speed-test-template.json} +0 -0
  430. /package/src/{server/services/codex-wire.js → platforms/drivers/codex/wire.js} +0 -0
  431. /package/src/{server/services/omp-auth-gateway-client.js → platforms/drivers/omp/auth-gateway-client.js} +0 -0
  432. /package/src/{server/services/opencode-normalization.js → platforms/drivers/opencode/normalization.js} +0 -0
  433. /package/src/{server/services → shared}/config-artifact-paths.js +0 -0
  434. /package/src/{server/services/base → shared}/proxy-utils.js +0 -0
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ const { createProjectsDriver } = require('../../../shared/driver-factories/projects');
4
+
5
+ function createDriver(context = {}) {
6
+ return createProjectsDriver({
7
+ ...context,
8
+ platform: 'codex',
9
+ servicePath: './codex/sessions-implementation',
10
+ localServicePath: '../../platforms/drivers/codex/sessions-implementation',
11
+ availabilityCheck: () => {
12
+ const config = context.requireImpl
13
+ ? context.requireImpl('./codex/config')
14
+ : require('./config');
15
+ config.configure?.({ pathContext: context.pathContext });
16
+ return config.isCodexInstalled();
17
+ },
18
+ onSuccess: operation => {
19
+ if (['saveProjectOrder', 'createProject', 'deleteProject'].includes(operation)) {
20
+ context.sessionHistoryIndex?.invalidateSource('codex');
21
+ }
22
+ }
23
+ });
24
+ }
25
+
26
+ module.exports = { createDriver };
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const { createPromptDriver } = require('../../../shared/driver-factories/prompts');
4
+
5
+ function createDriver(context = {}) {
6
+ return createPromptDriver({ ...context, platform: 'codex' });
7
+ }
8
+
9
+ module.exports = { createDriver };
@@ -2,26 +2,20 @@ const express = require('express');
2
2
  const httpProxy = require('http-proxy');
3
3
  const http = require('http');
4
4
  const chalk = require('chalk');
5
- const { broadcastLog, broadcastSchedulerState } = require('./websocket-server');
6
- const { allocateChannel, releaseChannel, getSchedulerState } = require('./services/channel-scheduler');
7
- const { recordSuccess, recordFailure } = require('./services/channel-health');
8
- const { loadConfig } = require('../config/loader');
9
- const DEFAULT_CONFIG = require('../config/default');
10
- const { resolveModelPricing, calculateTokenCost } = require('./utils/pricing');
11
- const { recordRequest: recordCodexRequest } = require('./services/codex-statistics-service');
12
- const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('./services/proxy-runtime');
13
- const { createDecodedStream } = require('./services/response-decoder');
14
- const { getEffectiveApiKey } = require('./services/codex-channels');
15
- const { persistProxyRequestSnapshot } = require('./services/request-logger');
16
- const { publishUsageLog, publishFailureLog } = require('./services/proxy-log-helper');
5
+ const { broadcastSchedulerState } = require('../../../server/websocket-server');
6
+ const { allocateChannel, releaseChannel, getSchedulerState } = require('../../../server/services/channel-scheduler');
7
+ const { recordSuccess, recordFailure } = require('../../../server/services/channel-health');
8
+ const { loadConfig } = require('../../../config/loader');
9
+ const { saveProxyStartTime, clearProxyStartTime, getProxyStartTime, getProxyRuntime } = require('../../../server/services/proxy-runtime');
10
+ const { getEffectiveApiKey, getCodexProxyExcludedChannelIds } = require('./channels-implementation');
11
+ const { persistProxyRequestSnapshot } = require('../../../server/services/request-logger');
17
12
  const {
18
13
  redirectModel,
19
14
  resolveTargetUrl,
20
15
  isChatCompletionsPath,
21
16
  ensureOpenAiStreamUsage
22
- } = require('./services/base/proxy-utils');
23
- const { parseSSEUsage, parseNonStreamingUsage, mergeUsageIntoTokenData, createTokenData } = require('./services/base/response-usage-parser');
24
- const { attachServerShutdownHandling, expediteServerShutdown } = require('./services/server-shutdown');
17
+ } = require('../../../shared/proxy-utils');
18
+ const { attachServerShutdownHandling, expediteServerShutdown } = require('../../../server/services/server-shutdown');
25
19
 
26
20
  let proxyServer = null;
27
21
  let proxyApp = null;
@@ -34,64 +28,12 @@ const requestMetadata = new Map();
34
28
  // 格式: { channelId: { "originalModel": "redirectedModel", ... } }
35
29
  const printedRedirectCache = new Map();
36
30
 
37
- // OpenAI 模型定价(每百万 tokens 的价格,单位:美元)
38
- // 作为 model-metadata 未覆盖时的兜底值
39
- const PRICING = {
40
- 'gpt-4o': { input: 2.5, output: 10 },
41
- 'gpt-4o-2024-11-20': { input: 2.5, output: 10 },
42
- 'gpt-4o-mini': { input: 0.15, output: 0.6 },
43
- 'gpt-4-turbo': { input: 10, output: 30 },
44
- 'gpt-4': { input: 30, output: 60 },
45
- 'gpt-3.5-turbo': { input: 0.5, output: 1.5 },
46
- 'o1': { input: 15, output: 60 },
47
- 'o1-mini': { input: 3, output: 12 },
48
- 'o1-pro': { input: 150, output: 600 },
49
- 'o3': { input: 10, output: 40 },
50
- 'o3-mini': { input: 1.1, output: 4.4 },
51
- 'o4-mini': { input: 1.1, output: 4.4 }
52
- };
53
-
54
- const CODEX_BASE_PRICING = DEFAULT_CONFIG.pricing.codex;
55
31
 
56
- // detectModelTier, redirectModel, resolveTargetUrl imported from services/base/proxy-utils
32
+ // detectModelTier, redirectModel, resolveTargetUrl imported from shared/proxy-utils
57
33
 
58
34
  // resolveCodexTarget replaced by resolveTargetUrl from proxy-utils
59
35
  const resolveCodexTarget = resolveTargetUrl;
60
36
 
61
- /**
62
- * 计算请求成本
63
- */
64
- function calculateCost(model, tokens) {
65
- let fallbackPricing = PRICING[model];
66
- if (!fallbackPricing) {
67
- const modelLower = String(model || '').toLowerCase();
68
- if (modelLower.includes('gpt-4o-mini')) {
69
- fallbackPricing = PRICING['gpt-4o-mini'];
70
- } else if (modelLower.includes('gpt-4o')) {
71
- fallbackPricing = PRICING['gpt-4o'];
72
- } else if (modelLower.includes('gpt-4')) {
73
- fallbackPricing = PRICING['gpt-4'];
74
- } else if (modelLower.includes('gpt-3.5')) {
75
- fallbackPricing = PRICING['gpt-3.5-turbo'];
76
- } else if (modelLower.includes('o1-mini')) {
77
- fallbackPricing = PRICING['o1-mini'];
78
- } else if (modelLower.includes('o1-pro')) {
79
- fallbackPricing = PRICING['o1-pro'];
80
- } else if (modelLower.includes('o1')) {
81
- fallbackPricing = PRICING['o1'];
82
- } else if (modelLower.includes('o3-mini')) {
83
- fallbackPricing = PRICING['o3-mini'];
84
- } else if (modelLower.includes('o3')) {
85
- fallbackPricing = PRICING['o3'];
86
- } else if (modelLower.includes('o4-mini')) {
87
- fallbackPricing = PRICING['o4-mini'];
88
- }
89
- }
90
-
91
- const pricing = resolveModelPricing('codex', model, fallbackPricing, CODEX_BASE_PRICING);
92
- return calculateTokenCost(pricing, tokens, CODEX_BASE_PRICING);
93
- }
94
-
95
37
  const jsonBodyParser = express.json({
96
38
  limit: '100mb',
97
39
  verify: (req, res, buf) => {
@@ -114,6 +56,11 @@ async function startCodexProxyServer(options = {}) {
114
56
  return { success: true, port: currentPort };
115
57
  }
116
58
 
59
+ const excludedChannelIds = getCodexProxyExcludedChannelIds();
60
+ if (excludedChannelIds.length > 0) {
61
+ throw new Error('Codex dynamic proxy supports API-key channels only; disable OAuth channels first');
62
+ }
63
+
117
64
  try {
118
65
  const config = loadConfig();
119
66
  const port = config.ports?.codexProxy || 20089;
@@ -163,7 +110,11 @@ async function startCodexProxyServer(options = {}) {
163
110
 
164
111
  proxyApp.use(async (req, res) => {
165
112
  try {
166
- const channel = await allocateChannel({ source: 'codex', enableSessionBinding: false });
113
+ const channel = await allocateChannel({
114
+ source: 'codex',
115
+ enableSessionBinding: false,
116
+ excludeChannelIds: getCodexProxyExcludedChannelIds()
117
+ });
167
118
  req.selectedChannel = channel;
168
119
 
169
120
  const release = (() => {
@@ -184,14 +135,6 @@ async function startCodexProxyServer(options = {}) {
184
135
  const effectiveKey = getEffectiveApiKey(channel);
185
136
  if (!effectiveKey) {
186
137
  release();
187
- publishFailureLog({
188
- source: 'codex',
189
- channel: channel.name,
190
- message: 'API key not configured or expired. Please update your channel key.',
191
- statusCode: 401,
192
- stage: 'preflight',
193
- broadcastLog
194
- });
195
138
  return res.status(401).json({
196
139
  error: {
197
140
  message: 'API key not configured or expired. Please update your channel key.',
@@ -263,20 +206,6 @@ async function startCodexProxyServer(options = {}) {
263
206
  release();
264
207
  if (err) {
265
208
  recordFailure(channel.id, 'codex', err);
266
- const metadata = requestMetadata.get(req) || {
267
- channel: channel.name,
268
- channelId: channel.id,
269
- startTime: Date.now()
270
- };
271
- publishFailureLog({
272
- source: 'codex',
273
- metadata,
274
- message: err.message,
275
- error: err,
276
- statusCode: 502,
277
- stage: 'proxy_web',
278
- broadcastLog
279
- });
280
209
  console.error('Codex proxy error:', err);
281
210
  if (res && !res.headersSent) {
282
211
  res.status(502).json({
@@ -290,13 +219,6 @@ async function startCodexProxyServer(options = {}) {
290
219
  });
291
220
  } catch (error) {
292
221
  console.error('Codex channel allocation error:', error);
293
- publishFailureLog({
294
- source: 'codex',
295
- message: error.message || 'No Codex channel available',
296
- statusCode: 503,
297
- stage: 'allocate_channel',
298
- broadcastLog
299
- });
300
222
  if (!res.headersSent) {
301
223
  res.status(503).json({
302
224
  error: {
@@ -308,155 +230,44 @@ async function startCodexProxyServer(options = {}) {
308
230
  }
309
231
  });
310
232
 
311
- // 监听代理响应 (OpenAI 格式)
233
+ // 代理响应只负责维护传输健康状态;实时日志和 usage 来自 CLI 原生日志。
312
234
  proxy.on('proxyRes', (proxyRes, req, res) => {
313
235
  const metadata = requestMetadata.get(req);
314
- if (!metadata) {
315
- return;
316
- }
236
+ if (!metadata) return;
317
237
 
318
- // 检查响应是否已关闭
319
238
  if (res.writableEnded || res.destroyed) {
320
239
  requestMetadata.delete(req);
321
240
  return;
322
241
  }
323
242
 
324
- // 标记响应是否已关闭
325
- let isResponseClosed = false;
326
-
327
243
  // 监听响应关闭事件
328
244
  res.on('close', () => {
329
- isResponseClosed = true;
330
245
  requestMetadata.delete(req);
331
246
  });
332
247
 
333
248
  // 监听响应错误事件
334
249
  res.on('error', (err) => {
335
- isResponseClosed = true;
336
- // 忽略客户端断开连接的常见错误
337
250
  if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') {
338
251
  console.error('Response error:', err);
339
252
  }
253
+ recordFailure(metadata.channelId, 'codex', err);
340
254
  requestMetadata.delete(req);
341
255
  });
342
256
 
343
- let buffer = '';
344
- let tokenData = createTokenData();
345
- let usageRecorded = false;
346
- const parsedStream = createDecodedStream(proxyRes);
347
-
348
- function recordUsageIfReady() {
349
- if (usageRecorded) {
350
- return false;
351
- }
352
-
353
- const result = publishUsageLog({
354
- source: 'codex',
355
- metadata,
356
- model: tokenData.model,
357
- tokens: {
358
- input: tokenData.inputTokens,
359
- output: tokenData.outputTokens,
360
- cacheCreation: tokenData.cacheCreation,
361
- cacheRead: tokenData.cacheRead,
362
- cached: tokenData.cachedTokens,
363
- reasoning: tokenData.reasoningTokens,
364
- total: tokenData.totalTokens
365
- },
366
- calculateCost,
367
- broadcastLog,
368
- recordRequest: recordCodexRequest,
369
- recordSuccess,
370
- allowBroadcast: true
371
- });
372
-
373
- if (!result) {
374
- return false;
375
- }
376
-
377
- usageRecorded = true;
378
- return true;
379
- }
380
-
381
- parsedStream.on('data', (chunk) => {
382
- if (isResponseClosed) {
383
- return;
384
- }
385
-
386
- buffer += chunk.toString('utf8');
387
-
388
- // 检查是否是 SSE 流
389
- if (proxyRes.headers['content-type']?.includes('text/event-stream')) {
390
- const events = buffer.split('\n\n');
391
- buffer = events.pop() || '';
392
-
393
- events.forEach((eventText) => {
394
- if (!eventText.trim()) return;
395
-
396
- try {
397
- const lines = eventText.split('\n');
398
- let eventType = '';
399
- let data = '';
400
-
401
- lines.forEach(line => {
402
- if (line.startsWith('event:')) {
403
- eventType = line.substring(6).trim();
404
- } else if (line.startsWith('data:')) {
405
- data = line.substring(5).trim();
406
- }
407
- });
408
-
409
- if (!data || data === '[DONE]') return;
410
-
411
- const parsed = JSON.parse(data);
412
- const usage = parseSSEUsage(parsed, eventType);
413
- mergeUsageIntoTokenData(tokenData, usage);
414
-
415
- if (usage.isDone) {
416
- recordUsageIfReady();
417
- }
418
- } catch (err) {
419
- // 忽略解析错误
420
- }
421
- });
422
- }
423
- });
424
-
425
- parsedStream.on('end', () => {
426
- // 如果不是流式响应,尝试从完整响应中解析
427
- if (!proxyRes.headers['content-type']?.includes('text/event-stream')) {
428
- try {
429
- const parsed = JSON.parse(buffer);
430
- const usage = parseNonStreamingUsage(parsed);
431
- mergeUsageIntoTokenData(tokenData, usage);
432
- } catch (err) {
433
- // 忽略解析错误
434
- }
435
- }
436
-
437
- recordUsageIfReady();
438
-
439
- if (!isResponseClosed) {
440
- requestMetadata.delete(req);
257
+ proxyRes.on('end', () => {
258
+ if (Number(proxyRes.statusCode) >= 400) {
259
+ recordFailure(metadata.channelId, 'codex', new Error(`Codex upstream HTTP ${proxyRes.statusCode}`));
260
+ } else {
261
+ recordSuccess(metadata.channelId, 'codex');
441
262
  }
263
+ requestMetadata.delete(req);
442
264
  });
443
265
 
444
- parsedStream.on('error', (err) => {
445
- // 忽略代理响应错误(可能是网络问题)
266
+ proxyRes.on('error', (err) => {
446
267
  if (err.code !== 'EPIPE' && err.code !== 'ECONNRESET') {
447
268
  console.error('Proxy response error:', err);
448
269
  }
449
- isResponseClosed = true;
450
270
  recordFailure(metadata.channelId, 'codex', err);
451
- publishFailureLog({
452
- source: 'codex',
453
- metadata,
454
- message: err.message,
455
- error: err,
456
- statusCode: proxyRes.statusCode,
457
- stage: 'response_stream',
458
- broadcastLog
459
- });
460
271
  requestMetadata.delete(req);
461
272
  });
462
273
  });
@@ -469,19 +280,6 @@ async function startCodexProxyServer(options = {}) {
469
280
  releaseChannel(req.selectedChannel.id, 'codex');
470
281
  broadcastSchedulerState('codex', getSchedulerState('codex'));
471
282
  }
472
- publishFailureLog({
473
- source: 'codex',
474
- metadata: (req && requestMetadata.get(req)) || {
475
- channel: req?.selectedChannel?.name,
476
- channelId: req?.selectedChannel?.id,
477
- model: req?.body?.model
478
- },
479
- message: err.message,
480
- error: err,
481
- statusCode: 502,
482
- stage: 'proxy',
483
- broadcastLog
484
- });
485
283
  if (res && !res.headersSent) {
486
284
  res.status(502).json({
487
285
  error: {
@@ -592,5 +390,4 @@ module.exports = {
592
390
  stopCodexProxyServer,
593
391
  getCodexProxyStatus,
594
392
  clearCodexRedirectCache,
595
- calculateCost
596
393
  };
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ const { createProxyDriver } = require('../../../shared/proxy-driver');
4
+
5
+ function createDriver(context = {}) {
6
+ return createProxyDriver({
7
+ ...context,
8
+ platform: 'codex',
9
+ servicePath: './codex/proxy-implementation',
10
+ localServicePath: '../platforms/drivers/codex/proxy-implementation',
11
+ exports: { status: 'getCodexProxyStatus', start: 'startCodexProxyServer', stop: 'stopCodexProxyServer' },
12
+ cliMetadata: { defaultPort: 20089 }
13
+ });
14
+ }
15
+
16
+ module.exports = { createDriver };
@@ -0,0 +1,9 @@
1
+ 'use strict';
2
+
3
+ const { createResourceSyncDriver } = require('../../../shared/driver-factories/resource-sync');
4
+
5
+ function createDriver(context = {}) {
6
+ return createResourceSyncDriver({ ...context, platform: 'codex' });
7
+ }
8
+
9
+ module.exports = { createDriver };
@@ -2,47 +2,59 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const { getCodexDir } = require('../codex-config');
6
- const { extractSessionMeta, extractMessages, extractTokenUsage, readJSONL } = require('../codex-parser');
5
+ const { getCodexDir } = require('./config');
6
+ const { parseSession } = require('./parser');
7
+
8
+ function configure({ pathContext } = {}) {
9
+ require('./config').configure?.({ pathContext });
10
+ }
11
+
12
+ function extractSessionIdFromRolloutFilename(filePath) {
13
+ const basename = path.basename(filePath, '.jsonl');
14
+ const match = basename.match(/([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/i);
15
+ return match ? match[1] : basename;
16
+ }
7
17
 
8
18
  /**
9
19
  * Scan all Codex session files recursively.
10
20
  * @returns {Array<{filePath: string, size: number, mtimeMs: number, sessionId: string}>}
11
21
  */
12
- function scanSessionFiles() {
22
+ async function scanSessionFiles(projectsDir = null) {
13
23
  const results = [];
14
- const sessionsDir = path.join(getCodexDir(), 'sessions');
24
+ const sessionsDir = projectsDir || path.join(getCodexDir(), 'sessions');
15
25
 
16
- if (!fs.existsSync(sessionsDir)) {
26
+ try {
27
+ await fs.promises.stat(sessionsDir);
28
+ } catch (_) {
17
29
  return results;
18
30
  }
19
31
 
20
- function scanDir(dir) {
32
+ async function scanDir(dir) {
21
33
  let entries;
22
34
  try {
23
- entries = fs.readdirSync(dir, { withFileTypes: true });
35
+ entries = await fs.promises.readdir(dir, { withFileTypes: true });
24
36
  } catch (_) {
25
37
  return;
26
38
  }
27
39
  for (const entry of entries) {
28
40
  const fullPath = path.join(dir, entry.name);
29
41
  if (entry.isDirectory()) {
30
- scanDir(fullPath);
42
+ await scanDir(fullPath);
31
43
  } else if (entry.isFile() && entry.name.match(/^rollout-.*\.jsonl$/)) {
32
44
  try {
33
- const stat = fs.statSync(fullPath);
45
+ const stat = await fs.promises.stat(fullPath);
34
46
  results.push({
35
47
  filePath: fullPath,
36
48
  size: stat.size,
37
49
  mtimeMs: stat.mtimeMs,
38
- sessionId: entry.name.replace(/\.jsonl$/, '')
50
+ sessionId: extractSessionIdFromRolloutFilename(fullPath)
39
51
  });
40
52
  } catch (_) {}
41
53
  }
42
54
  }
43
55
  }
44
56
 
45
- scanDir(sessionsDir);
57
+ await scanDir(sessionsDir);
46
58
  return results;
47
59
  }
48
60
 
@@ -67,8 +79,8 @@ function extractCodexProjectName(meta) {
67
79
  * Inventory all Codex session files.
68
80
  * @returns {Promise<Array>}
69
81
  */
70
- async function inventory() {
71
- const files = scanSessionFiles();
82
+ async function inventory({ projectsDir } = {}) {
83
+ const files = await scanSessionFiles(projectsDir);
72
84
  return files.map(f => ({
73
85
  filePath: f.filePath,
74
86
  size: f.size,
@@ -83,13 +95,15 @@ async function inventory() {
83
95
  */
84
96
  async function parse(descriptor) {
85
97
  const { filePath, size, mtimeMs, sessionId } = descriptor;
86
- const lines = readJSONL(filePath);
87
-
88
- const meta = extractSessionMeta(lines);
89
- const messages = extractMessages(lines);
90
- const tokenUsage = extractTokenUsage(lines);
91
-
98
+ const parsed = parseSession(filePath);
99
+ const meta = parsed?.meta;
100
+ const messages = parsed?.messages || [];
101
+ const tokenUsage = parsed?.tokens;
92
102
  const projectName = extractCodexProjectName(meta);
103
+ const descriptorIdIsNative = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(sessionId);
104
+ const nativeSessionId = descriptorIdIsNative
105
+ ? sessionId
106
+ : (typeof meta?.sessionId === 'string' && meta.sessionId.trim() ? meta.sessionId.trim() : sessionId);
93
107
  const usageJson = tokenUsage ? JSON.stringify(tokenUsage) : null;
94
108
 
95
109
  // Build normalized messages
@@ -119,7 +133,7 @@ async function parse(descriptor) {
119
133
 
120
134
  const isUser = msg.role === 'user' || msg.role === 'human';
121
135
  return {
122
- messageId: msg.id || `codex-${sessionId}-${idx}`,
136
+ messageId: msg.id || `codex-${nativeSessionId}-${idx}`,
123
137
  role: msg.role || 'unknown',
124
138
  type: msg.type || msg.role || 'unknown',
125
139
  subtype: msg.subtype || null,
@@ -136,10 +150,10 @@ async function parse(descriptor) {
136
150
  const lastMsg = normalizedMessages[normalizedMessages.length - 1];
137
151
 
138
152
  const session = {
139
- sessionId,
153
+ sessionId: nativeSessionId,
140
154
  projectName,
141
155
  projectDisplayName: projectName,
142
- projectFullPath: null,
156
+ projectFullPath: typeof meta?.cwd === 'string' && meta.cwd.trim() ? meta.cwd.trim() : null,
143
157
  firstMessage: firstUserMsg ? firstUserMsg.content : null,
144
158
  gitBranch: meta ? (meta.gitBranch || null) : null,
145
159
  provider: null,
@@ -155,4 +169,4 @@ async function parse(descriptor) {
155
169
  return { session, messages: normalizedMessages };
156
170
  }
157
171
 
158
- module.exports = { inventory, parse, extractCodexProjectName };
172
+ module.exports = { configure, inventory, parse, extractCodexProjectName };