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
@@ -1,15 +1,16 @@
1
+ 'use strict';
2
+
1
3
  const fs = require('fs');
2
4
  const path = require('path');
3
5
  const { PATHS } = require('../../config/paths');
4
6
  const {
5
- DEFAULT_HOME_CLI_COLUMNS,
6
- normalizeCustomCliPlatforms,
7
- normalizeHomeCliColumns
7
+ DEFAULT_ENABLED_CLI_PLATFORMS,
8
+ migrateLegacyCliConfig
8
9
  } = require('../../shared/platforms');
9
10
 
10
11
  const UI_CONFIG_FILE = PATHS.uiConfig;
12
+ const OPTIONAL_UI_CONFIG_FIELDS = ['remoteNotifications', 'claudeNotificationDisabledByUser'];
11
13
 
12
- // Default UI config
13
14
  const DEFAULT_UI_CONFIG = {
14
15
  theme: 'light',
15
16
  panelVisibility: {
@@ -40,128 +41,158 @@ const DEFAULT_UI_CONFIG = {
40
41
  opencode: [],
41
42
  omp: []
42
43
  },
43
- dashboardChannelOrder: DEFAULT_HOME_CLI_COLUMNS,
44
- homeCliColumns: DEFAULT_HOME_CLI_COLUMNS,
45
- customCliPlatforms: []
44
+ enabledCliPlatforms: DEFAULT_ENABLED_CLI_PLATFORMS
46
45
  };
47
46
 
48
- // 内存缓存
49
47
  let uiConfigCache = null;
50
48
  let cacheInitialized = false;
49
+ let watcherInitialized = false;
50
+
51
+ function clone(value) {
52
+ return JSON.parse(JSON.stringify(value));
53
+ }
51
54
 
52
- // Ensure UI config directory exists
53
55
  function ensureConfigDir() {
54
56
  const dir = path.dirname(UI_CONFIG_FILE);
55
- if (!fs.existsSync(dir)) {
56
- fs.mkdirSync(dir, { recursive: true });
57
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
58
+ }
59
+
60
+ function getAllowedPlatformKeys() {
61
+ // Keep this require lazy: runtime's registry construction reads configuration.
62
+ try {
63
+ const { registry } = require('../platform-context').getPlatformContext();
64
+ const platforms = registry && typeof registry.list === 'function' ? registry.list() : [];
65
+ const keys = platforms
66
+ .map(platform => String(platform && platform.key || '').trim().toLowerCase())
67
+ .filter(Boolean);
68
+ return keys.length ? keys : [...DEFAULT_ENABLED_CLI_PLATFORMS];
69
+ } catch (error) {
70
+ return [...DEFAULT_ENABLED_CLI_PLATFORMS];
71
+ }
72
+ }
73
+
74
+ function normalizeUIConfig(config = {}) {
75
+ const source = config && typeof config === 'object' && !Array.isArray(config) ? config : {};
76
+ const allowedKeys = getAllowedPlatformKeys();
77
+ const migrationInput = {
78
+ homeCliColumns: source.homeCliColumns,
79
+ dashboardChannelOrder: source.dashboardChannelOrder,
80
+ customCliPlatforms: source.customCliPlatforms,
81
+ allowedKeys,
82
+ fallback: DEFAULT_ENABLED_CLI_PLATFORMS
83
+ };
84
+ if (Object.prototype.hasOwnProperty.call(source, 'enabledCliPlatforms')) {
85
+ migrationInput.enabledCliPlatforms = source.enabledCliPlatforms;
86
+ }
87
+ const enabledCliPlatforms = migrateLegacyCliConfig(migrationInput);
88
+
89
+ const normalized = {
90
+ theme: source.theme || DEFAULT_UI_CONFIG.theme,
91
+ panelVisibility: { ...DEFAULT_UI_CONFIG.panelVisibility, ...(source.panelVisibility || {}) },
92
+ channelBalance: { ...DEFAULT_UI_CONFIG.channelBalance, ...(source.channelBalance || {}) },
93
+ channelLocks: { ...DEFAULT_UI_CONFIG.channelLocks, ...(source.channelLocks || {}) },
94
+ channelCollapse: { ...DEFAULT_UI_CONFIG.channelCollapse, ...(source.channelCollapse || {}) },
95
+ channelOrder: { ...DEFAULT_UI_CONFIG.channelOrder, ...(source.channelOrder || {}) },
96
+ enabledCliPlatforms
97
+ };
98
+ for (const field of OPTIONAL_UI_CONFIG_FIELDS) {
99
+ if (Object.prototype.hasOwnProperty.call(source, field)) normalized[field] = clone(source[field]);
100
+ }
101
+ return clone(normalized);
102
+ }
103
+
104
+ function writeCanonicalConfig(config) {
105
+ ensureConfigDir();
106
+ const temporaryFile = path.join(
107
+ path.dirname(UI_CONFIG_FILE),
108
+ `.${path.basename(UI_CONFIG_FILE)}.${process.pid}.${Date.now()}.tmp`
109
+ );
110
+ try {
111
+ fs.writeFileSync(temporaryFile, JSON.stringify(config, null, 2), 'utf8');
112
+ fs.renameSync(temporaryFile, UI_CONFIG_FILE);
113
+ } catch (error) {
114
+ try { fs.unlinkSync(temporaryFile); } catch { /* best effort cleanup */ }
115
+ throw error;
57
116
  }
58
117
  }
59
118
 
60
- // 从文件读取并缓存
61
119
  function readUIConfigFromFile() {
62
120
  ensureConfigDir();
63
121
 
64
- if (!fs.existsSync(UI_CONFIG_FILE)) {
65
- return { ...DEFAULT_UI_CONFIG };
66
- }
122
+ if (!fs.existsSync(UI_CONFIG_FILE)) return clone(DEFAULT_UI_CONFIG);
67
123
 
124
+ let data;
68
125
  try {
69
126
  const content = fs.readFileSync(UI_CONFIG_FILE, 'utf8');
70
- const data = JSON.parse(content);
71
- // Merge with defaults to ensure all keys exist
72
- return normalizeUIConfig({
73
- ...DEFAULT_UI_CONFIG,
74
- ...data,
75
- theme: data.theme || DEFAULT_UI_CONFIG.theme,
76
- panelVisibility: { ...DEFAULT_UI_CONFIG.panelVisibility, ...data.panelVisibility },
77
- channelBalance: { ...DEFAULT_UI_CONFIG.channelBalance, ...data.channelBalance },
78
- channelLocks: { ...DEFAULT_UI_CONFIG.channelLocks, ...data.channelLocks },
79
- channelCollapse: { ...DEFAULT_UI_CONFIG.channelCollapse, ...data.channelCollapse },
80
- channelOrder: { ...DEFAULT_UI_CONFIG.channelOrder, ...data.channelOrder }
81
- });
127
+ data = JSON.parse(content);
128
+ if (!data || typeof data !== 'object' || Array.isArray(data)) throw new Error('UI config must be an object');
82
129
  } catch (error) {
83
130
  console.error('Error loading UI config:', error);
84
- return normalizeUIConfig({ ...DEFAULT_UI_CONFIG });
131
+ return normalizeUIConfig({});
85
132
  }
86
- }
87
133
 
88
- function normalizeUIConfig(config = {}) {
89
- const customCliPlatforms = normalizeCustomCliPlatforms(config.customCliPlatforms);
90
- const legacyOrder = Array.isArray(config.homeCliColumns)
91
- ? config.homeCliColumns
92
- : config.dashboardChannelOrder;
93
- const homeCliColumns = normalizeHomeCliColumns(legacyOrder, customCliPlatforms);
94
-
95
- return {
96
- ...DEFAULT_UI_CONFIG,
97
- ...config,
98
- panelVisibility: { ...DEFAULT_UI_CONFIG.panelVisibility, ...(config.panelVisibility || {}) },
99
- channelBalance: { ...DEFAULT_UI_CONFIG.channelBalance, ...(config.channelBalance || {}) },
100
- channelLocks: { ...DEFAULT_UI_CONFIG.channelLocks, ...(config.channelLocks || {}) },
101
- channelCollapse: { ...DEFAULT_UI_CONFIG.channelCollapse, ...(config.channelCollapse || {}) },
102
- channelOrder: { ...DEFAULT_UI_CONFIG.channelOrder, ...(config.channelOrder || {}) },
103
- dashboardChannelOrder: homeCliColumns,
104
- homeCliColumns,
105
- customCliPlatforms
106
- };
134
+ const normalized = normalizeUIConfig(data);
135
+ if (JSON.stringify(data) !== JSON.stringify(normalized)) {
136
+ try {
137
+ writeCanonicalConfig(normalized);
138
+ } catch (error) {
139
+ console.error('Error rewriting UI config:', error);
140
+ }
141
+ }
142
+ return normalized;
107
143
  }
108
144
 
109
- // 初始化缓存(延迟初始化)
110
- function initializeCache() {
111
- if (cacheInitialized) return;
112
- uiConfigCache = readUIConfigFromFile();
113
- cacheInitialized = true;
114
-
115
- // 监听文件变化,更新缓存
145
+ function installConfigWatcher() {
146
+ if (watcherInitialized) return;
116
147
  try {
117
148
  fs.watchFile(UI_CONFIG_FILE, { persistent: false }, () => {
118
149
  uiConfigCache = readUIConfigFromFile();
119
150
  });
151
+ watcherInitialized = true;
120
152
  } catch (err) {
121
153
  console.error('Failed to watch UI config file:', err);
122
154
  }
123
155
  }
124
156
 
125
- // Load UI config(使用缓存)
157
+ function initializeCache() {
158
+ if (cacheInitialized) return;
159
+ uiConfigCache = readUIConfigFromFile();
160
+ cacheInitialized = true;
161
+ installConfigWatcher();
162
+ }
163
+
126
164
  function loadUIConfig() {
127
- if (!cacheInitialized) {
128
- initializeCache();
129
- }
130
- return JSON.parse(JSON.stringify(uiConfigCache)); // 深拷贝返回
165
+ if (!cacheInitialized) initializeCache();
166
+ return clone(uiConfigCache);
131
167
  }
132
168
 
133
- // Save UI config(同时更新缓存)
134
169
  function saveUIConfig(config) {
135
- ensureConfigDir();
136
-
137
170
  try {
138
- const normalizedConfig = normalizeUIConfig(config);
139
- fs.writeFileSync(UI_CONFIG_FILE, JSON.stringify(normalizedConfig, null, 2), 'utf8');
140
- // 同时更新缓存
141
- uiConfigCache = JSON.parse(JSON.stringify(normalizedConfig));
171
+ const currentConfig = loadUIConfig();
172
+ const source = config && typeof config === 'object' && !Array.isArray(config) ? config : {};
173
+ const normalizedConfig = normalizeUIConfig({ ...currentConfig, ...source });
174
+ writeCanonicalConfig(normalizedConfig);
175
+ uiConfigCache = clone(normalizedConfig);
176
+ cacheInitialized = true;
177
+ installConfigWatcher();
178
+ return clone(normalizedConfig);
142
179
  } catch (error) {
143
180
  console.error('Error saving UI config:', error);
144
181
  throw error;
145
182
  }
146
183
  }
147
184
 
148
- // Update specific config key
149
185
  function updateUIConfig(key, value) {
150
186
  const config = loadUIConfig();
151
187
  config[key] = value;
152
- saveUIConfig(config);
153
- return loadUIConfig();
188
+ return saveUIConfig(config);
154
189
  }
155
190
 
156
- // Update nested config
157
191
  function updateNestedUIConfig(parentKey, childKey, value) {
158
192
  const config = loadUIConfig();
159
- if (!config[parentKey]) {
160
- config[parentKey] = {};
161
- }
193
+ if (!config[parentKey] || typeof config[parentKey] !== 'object') config[parentKey] = {};
162
194
  config[parentKey][childKey] = value;
163
- saveUIConfig(config);
164
- return loadUIConfig();
195
+ return saveUIConfig(config);
165
196
  }
166
197
 
167
198
  module.exports = {
@@ -0,0 +1,98 @@
1
+ 'use strict';
2
+
3
+ const { normalizeUsage: normalizeNativeUsage } = require('../../platforms/drivers/native-log-utils');
4
+ const { resolveModelPricing, calculateTokenCost } = require('../utils/pricing');
5
+
6
+ function toNumber(value) {
7
+ const num = Number(value);
8
+ return Number.isFinite(num) ? num : 0;
9
+ }
10
+
11
+ function normalizeToolSource(source = '') {
12
+ const normalized = String(source || '').trim().toLowerCase();
13
+ if (normalized === 'claude' || normalized === 'claude-code') return 'claude';
14
+ if (normalized === 'codex') return 'codex';
15
+ if (normalized === 'gemini') return 'gemini';
16
+ if (normalized === 'opencode') return 'opencode';
17
+ if (normalized === 'omp' || normalized === 'omp-agent') return 'omp';
18
+ return 'claude';
19
+ }
20
+
21
+ function normalizeModelName(value = '') {
22
+ return typeof value === 'string' ? value.trim() : '';
23
+ }
24
+
25
+ function resolveActualModel(model = '', metadata = {}) {
26
+ const candidates = [model, metadata.redirectedModel, metadata.modelFromUrl, metadata.requestModel, metadata.model, metadata.originalModel];
27
+ for (const candidate of candidates) {
28
+ const normalized = normalizeModelName(candidate);
29
+ if (normalized) return normalized;
30
+ }
31
+ return '';
32
+ }
33
+
34
+ function normalizeUsageTokens(source, tokens = {}) {
35
+ const normalizedSource = normalizeToolSource(source);
36
+ const normalizedUsage = normalizeNativeUsage(tokens);
37
+ const input = toNumber(normalizedUsage.input);
38
+ const output = toNumber(normalizedUsage.output);
39
+ const cacheCreation = toNumber(normalizedUsage.cacheCreation);
40
+ const cacheRead = toNumber(normalizedUsage.cacheRead || normalizedUsage.cached);
41
+ const cached = toNumber(normalizedUsage.cached || cacheRead);
42
+ const reasoning = toNumber(normalizedUsage.reasoning);
43
+ const hasPositiveReportedTotal = ['total', 'total_tokens', 'totalTokens', 'totalTokenCount']
44
+ .some(key => toNumber(tokens?.[key]) > 0);
45
+ let total = toNumber(normalizedUsage.total);
46
+ if (!hasPositiveReportedTotal) {
47
+ if (normalizedSource === 'claude') {
48
+ total = input + output + cacheCreation + cacheRead;
49
+ } else if (normalizedSource === 'gemini') {
50
+ total = input + output + cacheCreation + cacheRead + reasoning;
51
+ }
52
+ }
53
+ return { input, output, cacheCreation, cacheRead, cached, reasoning, total };
54
+ }
55
+
56
+ function hasMeaningfulUsage(source, tokens = {}) {
57
+ const normalized = normalizeUsageTokens(source, tokens);
58
+ return normalized.total > 0 || normalized.input > 0 || normalized.output > 0
59
+ || normalized.cacheCreation > 0 || normalized.cacheRead > 0
60
+ || normalized.cached > 0 || normalized.reasoning > 0;
61
+ }
62
+
63
+ function calculateUsageCost(source, model, tokens = {}) {
64
+ const normalizedSource = normalizeToolSource(source);
65
+ const pricing = resolveModelPricing(normalizedSource, model);
66
+ return calculateTokenCost(pricing, normalizeUsageTokens(normalizedSource, tokens), {
67
+ reasoningBilledAsOutput: normalizedSource === 'gemini'
68
+ });
69
+ }
70
+
71
+ function formatRealtimeTime(timestamp = Date.now()) {
72
+ return new Date(timestamp).toLocaleTimeString('zh-CN', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
73
+ }
74
+
75
+ function buildSuccessLogPayload({ source, requestId, channel, model, originalModel, redirectedModel, tokens, cost = 0, timestamp = Date.now(), usageMissing = false }) {
76
+ const normalized = normalizeUsageTokens(source, tokens);
77
+ const payload = {
78
+ type: 'log', status: 'success', id: requestId, time: formatRealtimeTime(timestamp), channel,
79
+ model: model || '', inputTokens: normalized.input, outputTokens: normalized.output,
80
+ cacheCreation: normalized.cacheCreation, cacheRead: normalized.cacheRead, cachedTokens: normalized.cached,
81
+ reasoningTokens: normalized.reasoning, totalTokens: normalized.total, cost,
82
+ source: normalizeToolSource(source), timestamp, usageMissing: Boolean(usageMissing)
83
+ };
84
+ if (originalModel) payload.originalModel = originalModel;
85
+ if (redirectedModel) payload.redirectedModel = redirectedModel;
86
+ return payload;
87
+ }
88
+
89
+ module.exports = {
90
+ toNumber,
91
+ normalizeToolSource,
92
+ resolveActualModel,
93
+ normalizeUsageTokens,
94
+ hasMeaningfulUsage,
95
+ calculateUsageCost,
96
+ formatRealtimeTime,
97
+ buildSuccessLogPayload
98
+ };
@@ -6,7 +6,7 @@ const { spawn } = require('child_process');
6
6
 
7
7
  const DEFAULT_PROJECT_ROOT = path.resolve(__dirname, '../../..');
8
8
  const IGNORED_DIR_NAMES = new Set(['node_modules', '.git', 'dist']);
9
- const WATCHED_WEB_FILES = ['index.html', 'package.json', 'package-lock.json', 'pnpm-lock.yaml', 'vite.config.js'];
9
+ const WATCHED_WEB_FILES = ['index.html', 'package.json', 'package-lock.json', 'vite.config.js'];
10
10
  const WATCHED_WEB_DIRS = ['src', 'public'];
11
11
 
12
12
  function pathExists(targetPath) {
@@ -348,7 +348,7 @@ function getGitWorktrees(repoPath) {
348
348
  * @param {string} options.baseDir - 基础目录(可选)
349
349
  * @param {Array} options.projects - 项目列表 [{sourcePath, name, createWorktree, branch}]
350
350
  */
351
- function createWorkspace(options) {
351
+ async function createWorkspace(options) {
352
352
  const { name, description = '', baseDir, projects = [], configTemplateId } = options;
353
353
 
354
354
  if (!name || name.trim() === '') {
@@ -501,23 +501,6 @@ function createWorkspace(options) {
501
501
  });
502
502
  }
503
503
 
504
- // 应用配置模板(如果指定)
505
- let templateInfo = null;
506
- if (configTemplateId) {
507
- try {
508
- const result = configTemplatesService.applyTemplate(workspacePath, configTemplateId);
509
- templateInfo = {
510
- templateId: configTemplateId,
511
- templateName: result.template,
512
- appliedAt: new Date().toISOString()
513
- };
514
- } catch (templateError) {
515
- console.warn('应用配置模板失败:', templateError.message);
516
- // 不中断工作区创建流程
517
- }
518
- }
519
-
520
- // 保存工作区配置
521
504
  const workspaceId = generateWorkspaceId();
522
505
  const workspace = {
523
506
  id: workspaceId,
@@ -525,17 +508,64 @@ function createWorkspace(options) {
525
508
  description,
526
509
  path: workspacePath,
527
510
  projects: workspaceProjects,
528
- configTemplate: templateInfo,
511
+ configTemplate: null,
529
512
  createdAt: new Date().toISOString(),
530
513
  lastUsed: new Date().toISOString()
531
514
  };
532
515
 
533
516
  const data = loadWorkspaces();
534
517
  data.workspaces.push(workspace);
535
- saveWorkspaces(data);
518
+ if (!saveWorkspaces(data)) {
519
+ throw new Error('保存工作区配置失败');
520
+ }
521
+ let workspaceRegistered = true;
522
+
523
+ try {
524
+ // 应用配置模板(如果指定)
525
+ if (configTemplateId) {
526
+ try {
527
+ const result = await configTemplatesService.applyTemplate(workspacePath, configTemplateId);
528
+ workspace.configTemplate = {
529
+ templateId: configTemplateId,
530
+ templateName: result.template,
531
+ appliedAt: new Date().toISOString()
532
+ };
533
+ } catch (templateError) {
534
+ console.warn('应用配置模板失败:', templateError.message);
535
+ // 不中断工作区创建流程
536
+ }
537
+ }
536
538
 
537
- return workspace;
539
+ if (!saveWorkspaces(data)) {
540
+ throw new Error('保存工作区配置失败');
541
+ }
542
+ return workspace;
543
+ } catch (error) {
544
+ if (workspaceRegistered) {
545
+ const current = loadWorkspaces();
546
+ const index = current.workspaces.findIndex(item => item.id === workspaceId);
547
+ if (index !== -1 && !saveWorkspaces({
548
+ ...current,
549
+ workspaces: current.workspaces.filter(item => item.id !== workspaceId)
550
+ })) {
551
+ console.error('回滚工作区配置失败:', workspaceId);
552
+ }
553
+ workspaceRegistered = false;
554
+ }
555
+ throw error;
556
+ }
538
557
  } catch (error) {
558
+ for (const project of workspaceProjects) {
559
+ if (!project.useWorktree || !project.sourcePath || !project.targetPath) continue;
560
+ try {
561
+ runGitCommand(['worktree', 'remove', project.targetPath, '--force'], {
562
+ cwd: project.sourcePath
563
+ });
564
+ } catch (cleanupError) {
565
+ console.error(`注销 worktree 失败: ${project.targetPath}`, cleanupError.message);
566
+ }
567
+ }
568
+
539
569
  // 清理已创建的目录
540
570
  try {
541
571
  if (fs.existsSync(workspacePath)) {
@@ -732,14 +762,14 @@ function removeProjectFromWorkspace(workspaceId, projectName) {
732
762
  */
733
763
  async function getAllAvailableProjects() {
734
764
  const { loadConfig } = require('../../config/loader');
735
- const sessionsService = require('./sessions');
736
- const codexSessionsService = require('./codex-sessions');
737
- const geminiSessionsService = require('./gemini-sessions');
738
- const opencodeSessionsService = require('./opencode-sessions');
739
- const ompSessionsService = require('./omp-sessions');
740
- const { isCodexInstalled } = require('./codex-config');
741
- const { isGeminiInstalled } = require('./gemini-config');
742
- const { isOpenCodeInstalled } = require('./opencode-sessions');
765
+ const sessionsService = require('../../platforms/drivers/claude/sessions-implementation');
766
+ const codexSessionsService = require('../../platforms/drivers/codex/sessions-implementation');
767
+ const geminiSessionsService = require('../../platforms/drivers/gemini/sessions-implementation');
768
+ const opencodeSessionsService = require('../../platforms/drivers/opencode/sessions-implementation');
769
+ const ompSessionsService = require('../../platforms/drivers/omp/sessions-implementation');
770
+ const { isCodexInstalled } = require('../../platforms/drivers/codex/config');
771
+ const { isGeminiInstalled } = require('../../platforms/drivers/gemini/config');
772
+ const { isOpenCodeInstalled } = require('../../platforms/drivers/opencode/sessions-implementation');
743
773
 
744
774
  const allProjects = [];
745
775
  const seenKeys = new Set();
@@ -54,32 +54,24 @@ function resolveMetadataPricing(model) {
54
54
  }
55
55
  }
56
56
 
57
- function resolvePricing(_toolKey, modelPricing = {}, defaultPricing = {}) {
58
- return { ...defaultPricing, ...(modelPricing || {}) };
59
- }
60
-
61
- function resolveModelPricing(_toolKey, model, fallbackPricing = {}, defaultPricing = {}) {
57
+ function resolveModelPricing(_toolKey, model) {
62
58
  const pricingFromMetadata = resolveMetadataPricing(model);
63
- return {
64
- ...defaultPricing,
65
- ...(fallbackPricing || {}),
66
- ...(pricingFromMetadata || {})
67
- };
59
+ return pricingFromMetadata ? { ...pricingFromMetadata } : {};
68
60
  }
69
61
 
70
- function getRate(pricing, defaultPricing, key) {
62
+ function getRate(pricing, key) {
71
63
  if (typeof pricing?.[key] === 'number') return pricing[key];
72
- if (typeof defaultPricing?.[key] === 'number') return defaultPricing[key];
73
64
  return 0;
74
65
  }
75
66
 
76
- function calculateTokenCost(pricing = {}, tokens = {}, defaultPricing = {}) {
77
- const inputRate = getRate(pricing, defaultPricing, 'input');
78
- const outputRate = getRate(pricing, defaultPricing, 'output');
79
- const cacheCreationRate = getRate(pricing, defaultPricing, 'cacheCreation');
80
- const cacheReadRate = getRate(pricing, defaultPricing, 'cacheRead');
67
+ function calculateTokenCost(pricing = {}, tokens = {}, options = {}) {
68
+ const inputRate = getRate(pricing, 'input');
69
+ const outputRate = getRate(pricing, 'output');
70
+ const cacheCreationRate = getRate(pricing, 'cacheCreation');
71
+ const cacheReadRate = getRate(pricing, 'cacheRead');
81
72
  const inputTokens = Number(tokens.input || 0);
82
- const outputTokens = Number(tokens.output || 0);
73
+ const outputTokens = Number(tokens.output || 0)
74
+ + (options.reasoningBilledAsOutput ? Number(tokens.reasoning || 0) : 0);
83
75
  const cacheCreationTokens = Number(tokens.cacheCreation || 0);
84
76
  const cacheReadTokens = Number(tokens.cacheRead || tokens.cached || 0);
85
77
 
@@ -92,7 +84,6 @@ function calculateTokenCost(pricing = {}, tokens = {}, defaultPricing = {}) {
92
84
  }
93
85
 
94
86
  module.exports = {
95
- resolvePricing,
96
87
  resolveModelPricing,
97
88
  calculateTokenCost
98
89
  };