coding-tool-x 3.8.4 → 3.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +86 -15
  3. package/dist/web/assets/AgentsDrawer-BG6P3DX-.js +1 -0
  4. package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
  5. package/dist/web/assets/Analytics--z_FmL5P.js +1 -0
  6. package/dist/web/assets/Analytics-CyHhR126.css +1 -0
  7. package/dist/web/assets/AssetPathField-CrJtRKHy.js +1 -0
  8. package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
  9. package/dist/web/assets/ChatHistoryDrawer-BiuEryJj.js +1 -0
  10. package/dist/web/assets/CollapseItem-BAYEsL_Q.js +1 -0
  11. package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
  12. package/dist/web/assets/CommandsDrawer-YJ-U7BXN.js +1 -0
  13. package/dist/web/assets/ConfigExportDrawer-Ce_hAknW.js +1 -0
  14. package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
  15. package/dist/web/assets/ConfigTemplates-Bvr1NN6K.js +1 -0
  16. package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
  17. package/dist/web/assets/ConfigTemplatesDrawer-BjIeHfF-.js +1 -0
  18. package/dist/web/assets/ConfigTemplatesPanel-AV00tm_D.js +1 -0
  19. package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +1 -0
  20. package/dist/web/assets/Divider-D28g1gwj.js +1 -0
  21. package/dist/web/assets/DrawerContent-ChXgZ1Xm.js +1 -0
  22. package/dist/web/assets/FavoritesDrawer-CG9eI9Ay.css +1 -0
  23. package/dist/web/assets/FavoritesDrawer-Cz95o4CD.js +1 -0
  24. package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
  25. package/dist/web/assets/GatewayConvertDrawer-DLlbMz27.js +1 -0
  26. package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
  27. package/dist/web/assets/Home-D7CCOFQC.js +1 -0
  28. package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
  29. package/dist/web/assets/MarkdownEditor-rEZ-c72L.js +1 -0
  30. package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
  31. package/dist/web/assets/McpDrawer-DfoCyxU2.js +1 -0
  32. package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
  33. package/dist/web/assets/McpFormDrawer-SKu8HNUR.js +1 -0
  34. package/dist/web/assets/PluginManager-BbeK-3rV.js +1 -0
  35. package/dist/web/assets/PluginsDrawer-CWVJ7yjS.js +1 -0
  36. package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
  37. package/dist/web/assets/PluginsPanel-Cm2N3StG.js +1 -0
  38. package/dist/web/assets/PluginsPanel-D6ZqITcR.css +1 -0
  39. package/dist/web/assets/ProjectList-677RLZ8O.css +1 -0
  40. package/dist/web/assets/ProjectList-CsjnsNPv.js +1 -0
  41. package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
  42. package/dist/web/assets/PromptsDrawer-EGd3djFa.js +1 -0
  43. package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
  44. package/dist/web/assets/RecentSessionsDrawer-D1vtoLAs.js +1 -0
  45. package/dist/web/assets/SessionCard-BgLg49U3.js +1 -0
  46. package/dist/web/assets/SessionCard-aM2NHu6i.css +1 -0
  47. package/dist/web/assets/SessionList-BpYRz1cX.css +1 -0
  48. package/dist/web/assets/SessionList-TRiTklWk.js +1 -0
  49. package/dist/web/assets/SettingsDrawer-d5liXjHq.css +1 -0
  50. package/dist/web/assets/SettingsDrawer-rz2WejGY.js +1 -0
  51. package/dist/web/assets/SkillManager-BTjTUbHq.js +1 -0
  52. package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
  53. package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
  54. package/dist/web/assets/SkillsDrawer-pN0hbkK3.js +1 -0
  55. package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
  56. package/dist/web/assets/SkillsPanel-gmBWEoiF.js +1 -0
  57. package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
  58. package/dist/web/assets/SpeedTestDrawer-DcNzuVJk.js +1 -0
  59. package/dist/web/assets/Upload-v5rV0qTT.js +1 -0
  60. package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
  61. package/dist/web/assets/WorkspaceDrawer-DxmicM4U.js +1 -0
  62. package/dist/web/assets/WorkspaceManager-CJHCjARN.js +1 -0
  63. package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
  64. package/dist/web/assets/WorkspacePanel-D8_Zq-du.js +1 -0
  65. package/dist/web/assets/_plugin-vue_export-helper-BeLZJZij.js +1 -0
  66. package/dist/web/assets/client-UDwXBP9i.js +1 -0
  67. package/dist/web/assets/clipboard-B46yyoz_.js +1 -0
  68. package/dist/web/assets/headers-cf-QapUq.js +1 -0
  69. package/dist/web/assets/icons-B2Vg-IOC.js +1 -0
  70. package/dist/web/assets/index-C0EHRym0.css +1 -0
  71. package/dist/web/assets/index-DnEocV0M.js +2 -0
  72. package/dist/web/assets/light-Cp0t7v32.js +1 -0
  73. package/dist/web/assets/markdown-u082bbtj.js +1 -0
  74. package/dist/web/assets/platforms-CBkB45JP.js +1 -0
  75. package/dist/web/assets/platforms-FTpjxAT6.js +1 -0
  76. package/dist/web/assets/project-config-B2baPzYL.js +1 -0
  77. package/dist/web/assets/sessions-Cmy31slD.js +1 -0
  78. package/dist/web/assets/sessions-yC_oVVh8.js +1 -0
  79. package/dist/web/assets/skill-repo-input-B_fkGlUK.js +1 -0
  80. package/dist/web/assets/use-lock-html-scroll-DXIqmUW4.js +1 -0
  81. package/dist/web/assets/use-message-DoLM8C1C.js +1 -0
  82. package/dist/web/assets/useResponsiveDrawer-B3uojyvV.js +1 -0
  83. package/dist/web/assets/vendors-D0c_0KLP.js +1 -0
  84. package/dist/web/assets/vue-vendor-BqZbbXHA.js +1 -0
  85. package/dist/web/assets/workspaces-mjyPVGS8.js +1 -0
  86. package/dist/web/assets/xml-CgY3RMlX.js +1 -0
  87. package/dist/web/index.html +12 -8
  88. package/docs/native-log-memory-2026-09-16.md +43 -0
  89. package/docs/superpowers/plans/2026-08-26-configuration-driven-cli-platform.md +1578 -0
  90. package/docs/superpowers/plans/2026-08-30-project-scoped-config-control.md +1260 -0
  91. package/docs/superpowers/plans/2026-09-01-omp-skill-refresh-boundary.md +213 -0
  92. package/docs/superpowers/plans/2026-09-01-realtime-logs-panel.md +125 -0
  93. package/docs/superpowers/plans/2026-09-02-config-driven-platform-boundary.md +86 -0
  94. package/docs/superpowers/plans/2026-09-02-platform-implementation-drivers.md +508 -0
  95. package/docs/superpowers/plans/2026-09-03-cli-platform-correctness-boundary.md +760 -0
  96. package/docs/superpowers/plans/2026-09-03-dependency-security-remediation.md +133 -0
  97. package/docs/superpowers/plans/2026-09-04-model-catalog-pricing-sync.md +1078 -0
  98. package/docs/superpowers/plans/2026-09-05-codex-project-scan-500.md +128 -0
  99. package/docs/superpowers/plans/2026-09-06-project-skill-path-fix.md +97 -0
  100. package/docs/superpowers/specs/2026-08-26-configuration-driven-cli-platform-design.md +408 -0
  101. package/docs/superpowers/specs/2026-08-30-project-scoped-config-control-design.md +467 -0
  102. package/docs/superpowers/specs/2026-09-01-claude-session-content-repair-design.md +111 -0
  103. package/docs/superpowers/specs/2026-09-01-omp-skill-refresh-boundary-design.md +83 -0
  104. package/docs/superpowers/specs/2026-09-01-realtime-logs-panel-design.md +27 -0
  105. package/docs/superpowers/specs/2026-09-02-config-driven-platform-boundary-design.md +64 -0
  106. package/docs/superpowers/specs/2026-09-02-platform-implementation-driver-boundary-design.md +123 -0
  107. package/docs/superpowers/specs/2026-09-03-cli-platform-correctness-boundary-design.md +249 -0
  108. package/docs/superpowers/specs/2026-09-03-dependency-security-remediation-design.md +87 -0
  109. package/docs/superpowers/specs/2026-09-04-model-catalog-pricing-sync-design.md +301 -0
  110. package/docs/superpowers/specs/2026-09-05-codex-project-scan-500-design.md +24 -0
  111. package/package.json +8 -4
  112. package/src/commands/channels.js +88 -191
  113. package/src/commands/cli-type.js +19 -11
  114. package/src/commands/daemon.js +94 -32
  115. package/src/commands/doctor.js +16 -9
  116. package/src/commands/export-config.js +23 -5
  117. package/src/commands/list.js +130 -52
  118. package/src/commands/logs.js +44 -27
  119. package/src/commands/platform-command-registry.js +78 -0
  120. package/src/commands/plugin.js +11 -5
  121. package/src/commands/port-config.js +34 -52
  122. package/src/commands/proxy-control.js +207 -145
  123. package/src/commands/proxy.js +2 -2
  124. package/src/commands/resume.js +87 -91
  125. package/src/commands/search.js +137 -67
  126. package/src/commands/stats.js +30 -22
  127. package/src/commands/switch.js +1 -1
  128. package/src/commands/toggle-proxy.js +94 -111
  129. package/src/commands/ui.js +67 -6
  130. package/src/commands/workspace.js +90 -8
  131. package/src/config/default.js +6 -53
  132. package/src/config/loader.js +61 -24
  133. package/src/config/model-metadata.js +49 -59
  134. package/src/config/model-metadata.json +4095 -99
  135. package/src/config/paths.js +181 -8
  136. package/src/index.js +134 -71
  137. package/src/platforms/access.js +196 -0
  138. package/src/{server/services → platforms}/agents-service.js +354 -197
  139. package/src/platforms/channel-auth-registry.js +162 -0
  140. package/src/platforms/channel-auth-service.js +82 -0
  141. package/src/{server/services → platforms}/commands-service.js +195 -115
  142. package/src/platforms/driver-registry.js +59 -0
  143. package/src/platforms/drivers/claude/api-operations.js +62 -0
  144. package/src/{server/services/channels.js → platforms/drivers/claude/channels-implementation.js} +131 -33
  145. package/src/platforms/drivers/claude/channels.js +39 -0
  146. package/src/{server/services/config-sync-service.js → platforms/drivers/claude/config-sync.js} +29 -5
  147. package/src/{server/services → platforms/drivers/claude}/health-check.js +4 -4
  148. package/src/platforms/drivers/claude/health.js +22 -0
  149. package/src/platforms/drivers/claude/mcp.js +9 -0
  150. package/src/{server/services/settings-manager.js → platforms/drivers/claude/native-config-implementation.js} +13 -4
  151. package/src/platforms/drivers/claude/native-config.js +46 -0
  152. package/src/platforms/drivers/claude/native-logs.js +72 -0
  153. package/src/{server/services/claude-openai-gateway.js → platforms/drivers/claude/openai-gateway.js} +8 -65
  154. package/src/platforms/drivers/claude/project-config.js +21 -0
  155. package/src/platforms/drivers/claude/projects.js +62 -0
  156. package/src/platforms/drivers/claude/prompts.js +9 -0
  157. package/src/{server/proxy-server.js → platforms/drivers/claude/proxy-implementation.js} +41 -278
  158. package/src/platforms/drivers/claude/proxy.js +16 -0
  159. package/src/platforms/drivers/claude/resource-sync.js +9 -0
  160. package/src/platforms/drivers/claude/session-history-adapter.js +313 -0
  161. package/src/{server/services/sessions.js → platforms/drivers/claude/sessions-implementation.js} +145 -35
  162. package/src/platforms/drivers/claude/sessions.js +76 -0
  163. package/src/{server/services/claude-statistics-service.js → platforms/drivers/claude/statistics-implementation.js} +2 -2
  164. package/src/platforms/drivers/claude/statistics.js +16 -0
  165. package/src/{server/services/claude-wire.js → platforms/drivers/claude/wire.js} +1 -1
  166. package/src/platforms/drivers/codex/api-operations.js +9 -0
  167. package/src/{server/services/codex-channels.js → platforms/drivers/codex/channels-implementation.js} +149 -14
  168. package/src/platforms/drivers/codex/channels.js +45 -0
  169. package/src/{server/services/codex-config.js → platforms/drivers/codex/config.js} +12 -2
  170. package/src/{server/services/codex-env-manager.js → platforms/drivers/codex/env-manager.js} +1 -1
  171. package/src/platforms/drivers/codex/mcp.js +9 -0
  172. package/src/{server/services/codex-settings-manager.js → platforms/drivers/codex/native-config-implementation.js} +15 -6
  173. package/src/platforms/drivers/codex/native-config.js +47 -0
  174. package/src/platforms/drivers/codex/native-logs.js +166 -0
  175. package/src/platforms/drivers/codex/project-config.js +21 -0
  176. package/src/platforms/drivers/codex/projects.js +26 -0
  177. package/src/platforms/drivers/codex/prompts.js +9 -0
  178. package/src/{server/codex-proxy-server.js → platforms/drivers/codex/proxy-implementation.js} +30 -233
  179. package/src/platforms/drivers/codex/proxy.js +16 -0
  180. package/src/platforms/drivers/codex/resource-sync.js +9 -0
  181. package/src/{server/services/session-history-adapters/codex.js → platforms/drivers/codex/session-history-adapter.js} +37 -23
  182. package/src/{server/services/codex-sessions.js → platforms/drivers/codex/sessions-implementation.js} +81 -75
  183. package/src/platforms/drivers/codex/sessions.js +36 -0
  184. package/src/{server/services/codex-statistics-service.js → platforms/drivers/codex/statistics-implementation.js} +2 -2
  185. package/src/platforms/drivers/codex/statistics.js +16 -0
  186. package/src/platforms/drivers/gemini/api-operations.js +9 -0
  187. package/src/{server/services/gemini-channels.js → platforms/drivers/gemini/channels-implementation.js} +202 -37
  188. package/src/platforms/drivers/gemini/channels.js +39 -0
  189. package/src/{server/services/gemini-config.js → platforms/drivers/gemini/config.js} +12 -2
  190. package/src/platforms/drivers/gemini/mcp.js +9 -0
  191. package/src/{server/services/gemini-settings-manager.js → platforms/drivers/gemini/native-config-implementation.js} +14 -5
  192. package/src/platforms/drivers/gemini/native-config.js +39 -0
  193. package/src/platforms/drivers/gemini/native-logs.js +180 -0
  194. package/src/platforms/drivers/gemini/project-config.js +21 -0
  195. package/src/platforms/drivers/gemini/projects.js +26 -0
  196. package/src/platforms/drivers/gemini/prompts.js +9 -0
  197. package/src/{server/gemini-proxy-server.js → platforms/drivers/gemini/proxy-implementation.js} +36 -267
  198. package/src/platforms/drivers/gemini/proxy.js +16 -0
  199. package/src/platforms/drivers/gemini/resource-sync.js +9 -0
  200. package/src/{server/services/session-history-adapters/gemini.js → platforms/drivers/gemini/session-history-adapter.js} +70 -18
  201. package/src/{server/services/gemini-sessions.js → platforms/drivers/gemini/sessions-implementation.js} +53 -37
  202. package/src/platforms/drivers/gemini/sessions.js +47 -0
  203. package/src/{server/services/gemini-statistics-service.js → platforms/drivers/gemini/statistics-implementation.js} +2 -2
  204. package/src/platforms/drivers/gemini/statistics.js +16 -0
  205. package/src/{server/services/gemini-wire.js → platforms/drivers/gemini/wire.js} +1 -1
  206. package/src/platforms/drivers/generic-filesystem.js +166 -0
  207. package/src/platforms/drivers/generic-jsonl.js +141 -0
  208. package/src/platforms/drivers/generic-mcp.js +44 -0
  209. package/src/platforms/drivers/generic-openai-compatible.js +45 -0
  210. package/src/platforms/drivers/generic-prompt.js +41 -0
  211. package/src/platforms/drivers/legacy.js +677 -0
  212. package/src/platforms/drivers/native-config-snapshot.js +125 -0
  213. package/src/platforms/drivers/native-log-utils.js +1292 -0
  214. package/src/platforms/drivers/notification-hooks.js +578 -0
  215. package/src/{server/api/omp-config.js → platforms/drivers/omp/api-operations.js} +52 -64
  216. package/src/{server/services/omp-auth-provider-worker.js → platforms/drivers/omp/auth-provider-worker.js} +1 -1
  217. package/src/{server/services/omp-auth-providers.js → platforms/drivers/omp/auth-providers.js} +1 -1
  218. package/src/{server/services/omp-channels.js → platforms/drivers/omp/channels-implementation.js} +166 -39
  219. package/src/platforms/drivers/omp/channels.js +58 -0
  220. package/src/{server/services/omp-config.js → platforms/drivers/omp/config.js} +53 -13
  221. package/src/{server/services/omp-gateway-routing.js → platforms/drivers/omp/gateway-routing.js} +14 -7
  222. package/src/{server/services/omp-gateway.js → platforms/drivers/omp/gateway.js} +4 -262
  223. package/src/platforms/drivers/omp/mcp.js +9 -0
  224. package/src/{server/services/omp-settings-manager.js → platforms/drivers/omp/native-config-implementation.js} +75 -10
  225. package/src/platforms/drivers/omp/native-config.js +46 -0
  226. package/src/platforms/drivers/omp/native-logs.js +52 -0
  227. package/src/{server/services/omp-native-plugin-adapter.js → platforms/drivers/omp/native-plugin-adapter.js} +91 -4
  228. package/src/platforms/drivers/omp/project-config.js +29 -0
  229. package/src/platforms/drivers/omp/projects.js +20 -0
  230. package/src/platforms/drivers/omp/prompts.js +9 -0
  231. package/src/{server/omp-proxy-server.js → platforms/drivers/omp/proxy-implementation.js} +6 -15
  232. package/src/platforms/drivers/omp/proxy.js +16 -0
  233. package/src/platforms/drivers/omp/resource-sync.js +9 -0
  234. package/src/{server/services/session-history-adapters/omp.js → platforms/drivers/omp/session-history-adapter.js} +42 -18
  235. package/src/{server/services/omp-sessions.js → platforms/drivers/omp/sessions-implementation.js} +130 -94
  236. package/src/platforms/drivers/omp/sessions.js +36 -0
  237. package/src/{server/services/omp-skill-discovery.js → platforms/drivers/omp/skill-discovery.js} +159 -32
  238. package/src/{server/services/omp-skill-settings-service.js → platforms/drivers/omp/skill-settings.js} +1 -1
  239. package/src/{server/services/omp-statistics-service.js → platforms/drivers/omp/statistics-implementation.js} +3 -3
  240. package/src/platforms/drivers/omp/statistics.js +16 -0
  241. package/src/platforms/drivers/opencode/api-operations.js +9 -0
  242. package/src/{server/services/opencode-channels.js → platforms/drivers/opencode/channels-implementation.js} +28 -9
  243. package/src/platforms/drivers/opencode/channels.js +40 -0
  244. package/src/platforms/drivers/opencode/conversion.js +41 -0
  245. package/src/{server/services/opencode-gateway-converter.js → platforms/drivers/opencode/gateway-converter.js} +1 -1
  246. package/src/platforms/drivers/opencode/mcp.js +9 -0
  247. package/src/{server/services/opencode-settings-manager.js → platforms/drivers/opencode/native-config-implementation.js} +17 -6
  248. package/src/platforms/drivers/opencode/native-config.js +26 -0
  249. package/src/platforms/drivers/opencode/native-logs.js +133 -0
  250. package/src/platforms/drivers/opencode/project-config.js +98 -0
  251. package/src/platforms/drivers/opencode/projects.js +20 -0
  252. package/src/platforms/drivers/opencode/prompts.js +9 -0
  253. package/src/{server/opencode-proxy-server.js → platforms/drivers/opencode/proxy-implementation.js} +27 -362
  254. package/src/platforms/drivers/opencode/proxy.js +16 -0
  255. package/src/platforms/drivers/opencode/resource-sync.js +9 -0
  256. package/src/{server/services/opencode-sessions.js → platforms/drivers/opencode/sessions-implementation.js} +211 -64
  257. package/src/platforms/drivers/opencode/sessions.js +48 -0
  258. package/src/{server/services/opencode-statistics-service.js → platforms/drivers/opencode/statistics-implementation.js} +2 -2
  259. package/src/platforms/drivers/opencode/statistics.js +16 -0
  260. package/src/platforms/drivers/secure-file-driver.js +272 -0
  261. package/src/platforms/drivers/unsupported.js +7 -0
  262. package/src/platforms/manifest-schema.js +398 -0
  263. package/src/platforms/manifests/claude.json +489 -0
  264. package/src/platforms/manifests/codex.json +448 -0
  265. package/src/platforms/manifests/gemini.json +447 -0
  266. package/src/platforms/manifests/omp.json +496 -0
  267. package/src/platforms/manifests/opencode.json +422 -0
  268. package/src/{server/services → platforms}/native-oauth-adapters.js +87 -417
  269. package/src/{server/services → platforms}/notification-hooks.js +140 -1023
  270. package/src/platforms/oauth-credentials-service.js +506 -0
  271. package/src/platforms/path-resolver.js +179 -0
  272. package/src/platforms/platform-path-context.js +305 -0
  273. package/src/platforms/registry.js +248 -0
  274. package/src/platforms/remote-notification-providers.js +678 -0
  275. package/src/platforms/runtime.js +259 -0
  276. package/src/{server/services/session-history-adapters/index.js → platforms/session-history-adapters.js} +8 -1
  277. package/src/plugins/plugin-loader.js +2 -2
  278. package/src/plugins/plugin-manager.js +2 -2
  279. package/src/plugins/registry.js +27 -10
  280. package/src/reset-config.js +21 -5
  281. package/src/server/api/agents.js +46 -72
  282. package/src/server/api/commands.js +16 -6
  283. package/src/server/api/config-registry.js +206 -59
  284. package/src/server/api/config-sync.js +3 -2
  285. package/src/server/api/config-templates.js +20 -4
  286. package/src/server/api/config.js +111 -102
  287. package/src/server/api/convert.js +54 -178
  288. package/src/server/api/dashboard.js +168 -102
  289. package/src/server/api/hooks.js +1 -1
  290. package/src/server/api/mcp.js +224 -84
  291. package/src/server/api/platform-api-config.js +102 -0
  292. package/src/server/api/platform-route-factory.js +215 -0
  293. package/src/server/api/platform-routes.js +26 -0
  294. package/src/server/api/platforms.js +110 -0
  295. package/src/server/api/plugins.js +57 -57
  296. package/src/server/api/project-config.js +168 -0
  297. package/src/server/api/prompts.js +58 -45
  298. package/src/server/api/settings.js +55 -8
  299. package/src/server/api/skills.js +262 -133
  300. package/src/server/api/ui-config.js +2 -2
  301. package/src/server/api/validation-errors.js +18 -4
  302. package/src/server/api/workspaces.js +47 -12
  303. package/src/server/index.js +164 -213
  304. package/src/server/platform-context.js +81 -0
  305. package/src/server/services/channel-balance.js +11 -20
  306. package/src/server/services/channel-health.js +21 -6
  307. package/src/server/services/channel-scheduler.js +29 -39
  308. package/src/server/services/channel-sync-utils.js +23 -13
  309. package/src/server/services/config-export-service.js +350 -319
  310. package/src/server/services/config-registry-service.js +280 -54
  311. package/src/server/services/config-sync-manager.js +172 -944
  312. package/src/server/services/config-templates-service.js +419 -353
  313. package/src/server/services/control-manifest-store.js +206 -0
  314. package/src/server/services/dashboard-snapshot-worker.js +656 -100
  315. package/src/server/services/effective-control-service.js +557 -0
  316. package/src/server/services/local-resource-index.js +314 -0
  317. package/src/server/services/mcp-service.js +607 -977
  318. package/src/server/services/model-detector.js +15 -10
  319. package/src/server/services/native-log-channel-resolver.js +214 -0
  320. package/src/server/services/native-log-observer.js +291 -0
  321. package/src/server/services/network-access.js +1 -1
  322. package/src/server/services/platform-catalog.js +82 -0
  323. package/src/server/services/platform-resolution.js +32 -29
  324. package/src/server/services/plugins-service.js +376 -122
  325. package/src/server/services/project-config-service.js +550 -0
  326. package/src/server/services/project-path-validation.js +31 -0
  327. package/src/server/services/prompts-service.js +267 -233
  328. package/src/server/services/proxy-runtime.js +7 -4
  329. package/src/server/services/remote-credential-cache.js +43 -0
  330. package/src/server/services/repo-scanner-base.js +182 -75
  331. package/src/server/services/request-logger.js +7 -4
  332. package/src/server/services/session-history-index.js +780 -213
  333. package/src/server/services/session-history-worker.js +228 -33
  334. package/src/server/services/session-snapshot-worker.js +124 -34
  335. package/src/server/services/session-snapshots.js +4 -2
  336. package/src/server/services/skill-artifact-store.js +355 -0
  337. package/src/server/services/skill-format-adapters.js +65 -0
  338. package/src/server/services/skill-projection-service.js +323 -0
  339. package/src/server/services/skill-refresh-task-service.js +275 -0
  340. package/src/server/services/skill-service.js +2020 -677
  341. package/src/server/services/snapshot-cache.js +30 -8
  342. package/src/server/services/speed-test.js +8 -8
  343. package/src/server/services/sqlite-connection.js +19 -3
  344. package/src/server/services/statistics-service.js +240 -57
  345. package/src/server/services/ui-config.js +107 -76
  346. package/src/server/services/usage-log-utils.js +98 -0
  347. package/src/server/services/web-build.js +1 -1
  348. package/src/server/services/workspace-service.js +59 -29
  349. package/src/server/utils/pricing.js +10 -19
  350. package/src/server/websocket-server.js +153 -28
  351. package/src/{server/services/base → shared}/base-channel-service.js +156 -28
  352. package/src/shared/capability-driver.js +104 -0
  353. package/src/shared/channel-auth-policy.js +27 -0
  354. package/src/shared/channel-driver.js +161 -0
  355. package/src/shared/driver-factories/api.js +180 -0
  356. package/src/shared/driver-factories/mcp.js +244 -0
  357. package/src/shared/driver-factories/projects.js +121 -0
  358. package/src/shared/driver-factories/prompts.js +58 -0
  359. package/src/shared/driver-factories/resource-sync.js +375 -0
  360. package/src/shared/driver-result.js +78 -0
  361. package/src/shared/mcp-format.js +189 -0
  362. package/src/shared/platforms.js +104 -167
  363. package/src/shared/project-config.js +512 -0
  364. package/src/shared/proxy-driver.js +57 -0
  365. package/src/{server/services/base → shared}/response-usage-parser.js +8 -4
  366. package/src/ui/menu.js +91 -67
  367. package/src/utils/port-helper.js +35 -19
  368. package/src/utils/session.js +1 -1
  369. package/dist/web/assets/Analytics-COEUXmd4.js +0 -25
  370. package/dist/web/assets/Analytics-RNn1BUbG.css +0 -1
  371. package/dist/web/assets/ConfigTemplates-DLLkS53H.js +0 -1
  372. package/dist/web/assets/Home-DCEyLzwX.js +0 -1
  373. package/dist/web/assets/Home-DYVy4cGZ.css +0 -1
  374. package/dist/web/assets/PluginManager-Oe1ZHoMO.js +0 -1
  375. package/dist/web/assets/ProjectList-CWjuAFof.js +0 -1
  376. package/dist/web/assets/ProjectList-VeMNXfgO.css +0 -1
  377. package/dist/web/assets/SessionList-C4chCPxK.css +0 -1
  378. package/dist/web/assets/SessionList-v3ehGg9U.js +0 -1
  379. package/dist/web/assets/SkillManager-BsX8Qpj0.css +0 -1
  380. package/dist/web/assets/SkillManager-DUF_qP5S.js +0 -1
  381. package/dist/web/assets/WorkspaceManager-CjAWBosO.js +0 -1
  382. package/dist/web/assets/icons-nGdSKQn2.js +0 -1
  383. package/dist/web/assets/index-D5hyHPj7.js +0 -2
  384. package/dist/web/assets/index-bJRG3RXH.css +0 -1
  385. package/dist/web/assets/markdown-BNJfEgCA.js +0 -1
  386. package/dist/web/assets/markdown-BfC0goYb.css +0 -10
  387. package/dist/web/assets/naive-ui-BALVpMgd.js +0 -1
  388. package/dist/web/assets/vendors-DQA4Hw9v.js +0 -7
  389. package/dist/web/assets/vue-vendor-B5RqjEjQ.js +0 -45
  390. package/src/config/model-pricing.js +0 -35
  391. package/src/server/api/channels.js +0 -439
  392. package/src/server/api/claude-hooks.js +0 -56
  393. package/src/server/api/claude-statistics.js +0 -57
  394. package/src/server/api/codex-channels.js +0 -491
  395. package/src/server/api/codex-projects.js +0 -117
  396. package/src/server/api/codex-proxy.js +0 -293
  397. package/src/server/api/codex-sessions.js +0 -652
  398. package/src/server/api/codex-statistics.js +0 -57
  399. package/src/server/api/gemini-channels.js +0 -392
  400. package/src/server/api/gemini-projects.js +0 -103
  401. package/src/server/api/gemini-proxy.js +0 -231
  402. package/src/server/api/gemini-sessions.js +0 -550
  403. package/src/server/api/gemini-statistics.js +0 -57
  404. package/src/server/api/health-check.js +0 -31
  405. package/src/server/api/oauth-credentials.js +0 -198
  406. package/src/server/api/omp-channels.js +0 -575
  407. package/src/server/api/omp-projects.js +0 -88
  408. package/src/server/api/omp-proxy.js +0 -125
  409. package/src/server/api/omp-sessions.js +0 -386
  410. package/src/server/api/omp-statistics.js +0 -40
  411. package/src/server/api/opencode-channels.js +0 -471
  412. package/src/server/api/opencode-projects.js +0 -110
  413. package/src/server/api/opencode-proxy.js +0 -354
  414. package/src/server/api/opencode-sessions.js +0 -466
  415. package/src/server/api/opencode-statistics.js +0 -57
  416. package/src/server/api/projects.js +0 -120
  417. package/src/server/api/proxy.js +0 -330
  418. package/src/server/api/sessions.js +0 -810
  419. package/src/server/services/oauth-credentials-service.js +0 -945
  420. package/src/server/services/omp-session-log-observer.js +0 -138
  421. package/src/server/services/opencode-gateway-adapters.js +0 -43
  422. package/src/server/services/project-snapshots.js +0 -59
  423. package/src/server/services/proxy-log-helper.js +0 -298
  424. package/src/server/services/session-cache.js +0 -127
  425. package/src/server/services/session-converter.js +0 -582
  426. package/src/server/services/session-history-adapters/claude.js +0 -235
  427. /package/src/{server/services/claude-token-recovery.js → platforms/drivers/claude/token-recovery.js} +0 -0
  428. /package/src/{server/services/codex-parser.js → platforms/drivers/codex/parser.js} +0 -0
  429. /package/src/{server/services/codex-speed-test-template.json → platforms/drivers/codex/speed-test-template.json} +0 -0
  430. /package/src/{server/services/codex-wire.js → platforms/drivers/codex/wire.js} +0 -0
  431. /package/src/{server/services/omp-auth-gateway-client.js → platforms/drivers/omp/auth-gateway-client.js} +0 -0
  432. /package/src/{server/services/opencode-normalization.js → platforms/drivers/opencode/normalization.js} +0 -0
  433. /package/src/{server/services → shared}/config-artifact-paths.js +0 -0
  434. /package/src/{server/services/base → shared}/proxy-utils.js +0 -0
@@ -1,8 +1,30 @@
1
1
  'use strict';
2
2
 
3
- const { fork } = require('child_process');
3
+ const childProcess = require('child_process');
4
+ const { getPlatformContext } = require('../platform-context');
4
5
 
5
6
  const DASHBOARD_SNAPSHOT_WORKER_TIMEOUT_MS = 180 * 1000;
7
+ const MAX_SERIALIZED_ERROR_TEXT_LENGTH = 4096;
8
+
9
+ function _safeErrorText(value, fallback = '') {
10
+ const text = value == null || value === '' ? fallback : String(value);
11
+ return text.length > MAX_SERIALIZED_ERROR_TEXT_LENGTH
12
+ ? `${text.slice(0, MAX_SERIALIZED_ERROR_TEXT_LENGTH)}…`
13
+ : text;
14
+ }
15
+
16
+ function _safeCode(value) {
17
+ return typeof value === 'string' || (typeof value === 'number' && Number.isFinite(value))
18
+ ? value
19
+ : undefined;
20
+ }
21
+ function _safeRetryAfter(value) {
22
+ return typeof value === 'string' || (typeof value === 'number' && Number.isFinite(value))
23
+ ? value
24
+ : undefined;
25
+ }
26
+
27
+
6
28
 
7
29
  function sortClaudeProjects(projects, order = []) {
8
30
  if (!Array.isArray(order) || order.length === 0) {
@@ -19,116 +41,640 @@ function sortClaudeProjects(projects, order = []) {
19
41
  });
20
42
  }
21
43
 
22
- async function buildProjectsPayload(source, config = {}, options = {}) {
23
- switch (source) {
24
- case 'claude': {
25
- const { getProjectsWithStats, getProjectOrder } = require('./sessions');
26
- const projects = await getProjectsWithStats(config, { force: options.force === true });
27
- const sortedProjects = sortClaudeProjects(projects, getProjectOrder(config));
28
- return {
29
- projects: sortedProjects,
30
- currentProject: config.currentProject || (sortedProjects[0] ? sortedProjects[0].name : null)
31
- };
44
+ function _isTypedPayload(value) {
45
+ return !!value && typeof value === 'object' && (
46
+ (typeof value.status === 'string' && value.status !== 'ok') ||
47
+ typeof value.type === 'string'
48
+ );
49
+ }
50
+
51
+ function _isTypedFailurePayload(value) {
52
+ return !!value && typeof value === 'object'
53
+ && value.status === 'failed'
54
+ && typeof value.platform === 'string'
55
+ && typeof value.capability === 'string'
56
+ && typeof value.operation === 'string';
57
+ }
58
+
59
+ function _serializeCause(cause, depth = 0, seen = new Set()) {
60
+ if (!cause || depth > 3) {
61
+ return null;
62
+ }
63
+ if ((typeof cause === 'object' || typeof cause === 'function') && seen.has(cause)) {
64
+ return null;
65
+ }
66
+ if (typeof cause === 'object' || typeof cause === 'function') {
67
+ seen.add(cause);
68
+ }
69
+ const serialized = {
70
+ name: _safeErrorText(cause.name, 'Error'),
71
+ message: _safeErrorText(cause && cause.message ? cause.message : cause, 'Error')
72
+ };
73
+ if (typeof cause.retryable === 'boolean') {
74
+ serialized.retryable = cause.retryable;
75
+ }
76
+ const retryAfter = _safeRetryAfter(cause.retryAfter);
77
+ if (retryAfter !== undefined) {
78
+ serialized.retryAfter = retryAfter;
79
+ }
80
+ const code = _safeCode(cause.code);
81
+ if (code !== undefined) {
82
+ serialized.code = code;
83
+ }
84
+ if (cause.cause && cause.cause !== cause) {
85
+ const nestedCause = _serializeCause(cause.cause, depth + 1, seen);
86
+ if (nestedCause) {
87
+ serialized.cause = nestedCause;
32
88
  }
33
- case 'codex': {
34
- const { getProjects } = require('./codex-sessions');
35
- const projects = await getProjects({ force: options.force === true });
36
- return { projects, currentProject: projects[0] ? projects[0].name : null };
89
+ }
90
+ return serialized;
91
+ }
92
+ function _safeFailurePayload(value, fallback = {}) {
93
+ const source = value && typeof value === 'object' ? value : {};
94
+ const failure = {
95
+ status: typeof source.status === 'string' ? _safeErrorText(source.status) : _safeErrorText(fallback.status, 'failed'),
96
+ platform: typeof source.platform === 'string' ? _safeErrorText(source.platform) : _safeErrorText(fallback.platform),
97
+ capability: typeof source.capability === 'string' ? _safeErrorText(source.capability) : _safeErrorText(fallback.capability),
98
+ operation: typeof source.operation === 'string' ? _safeErrorText(source.operation) : _safeErrorText(fallback.operation),
99
+ error: source.error instanceof Error
100
+ ? _safeErrorText(source.error.message, 'dashboard capability failed')
101
+ : _safeErrorText(source.error !== undefined ? source.error : fallback.error, 'dashboard capability failed')
102
+ };
103
+ failure.retryable = failure.status === 'failed';
104
+ if (typeof source.retryable === 'boolean') {
105
+ failure.retryable = source.retryable;
106
+ }
107
+ const retryAfter = _safeRetryAfter(source.retryAfter);
108
+ if (retryAfter !== undefined) {
109
+ failure.retryAfter = retryAfter;
110
+ }
111
+ const code = _safeCode(source.code);
112
+ if (code !== undefined) {
113
+ failure.code = code;
114
+ }
115
+ const cause = source.cause || (source.error instanceof Error ? source.error : null);
116
+ const serializedCause = _serializeCause(cause);
117
+ if (serializedCause) {
118
+ failure.cause = serializedCause;
119
+ }
120
+ return failure;
121
+ }
122
+
123
+
124
+ function _serializeError(error) {
125
+ if (!error || typeof error !== 'object') {
126
+ return { message: _safeErrorText(error, 'Dashboard snapshot refresh failed') };
127
+ }
128
+ const serialized = {
129
+ message: _safeErrorText(error.message ? error.message : error, 'Dashboard snapshot refresh failed')
130
+ };
131
+ if (typeof error.status === 'string') serialized.status = _safeErrorText(error.status);
132
+ if (typeof error.platform === 'string') serialized.platform = _safeErrorText(error.platform);
133
+ if (typeof error.capability === 'string') serialized.capability = _safeErrorText(error.capability);
134
+ if (typeof error.operation === 'string') serialized.operation = _safeErrorText(error.operation);
135
+ if (typeof error.retryable === 'boolean') serialized.retryable = error.retryable;
136
+ const retryAfter = _safeRetryAfter(error.retryAfter);
137
+ if (retryAfter !== undefined) serialized.retryAfter = retryAfter;
138
+ const code = _safeCode(error.code);
139
+ if (code !== undefined) serialized.code = code;
140
+ const cause = _serializeCause(error.cause);
141
+ if (cause) {
142
+ serialized.cause = cause;
143
+ }
144
+ return serialized;
145
+ }
146
+
147
+ function _deserializeCause(cause, depth = 0, seen = new Set()) {
148
+ if (!cause || depth > 3) {
149
+ return null;
150
+ }
151
+ if (typeof cause === 'object' || typeof cause === 'function') {
152
+ if (seen.has(cause)) {
153
+ return null;
37
154
  }
38
- case 'gemini': {
39
- const { getProjects } = require('./gemini-sessions');
40
- const projects = await getProjects({ force: options.force === true });
41
- return { projects, currentProject: projects[0] ? projects[0].name : null };
155
+ seen.add(cause);
156
+ }
157
+ const error = cause instanceof Error
158
+ ? cause
159
+ : new Error(_safeErrorText(cause.message ? cause.message : cause, 'Error'));
160
+ if (!(cause instanceof Error) && cause.name) {
161
+ error.name = _safeErrorText(cause.name, 'Error');
162
+ }
163
+ if (typeof cause.retryable === 'boolean') {
164
+ error.retryable = cause.retryable;
165
+ }
166
+ const retryAfter = _safeRetryAfter(cause.retryAfter);
167
+ if (retryAfter !== undefined) {
168
+ error.retryAfter = retryAfter;
169
+ }
170
+ const code = _safeCode(cause.code);
171
+ if (code !== undefined) {
172
+ error.code = code;
173
+ }
174
+ if (cause.cause && cause.cause !== cause) {
175
+ const nestedCause = _deserializeCause(cause.cause, depth + 1, seen);
176
+ if (nestedCause) {
177
+ error.cause = nestedCause;
42
178
  }
43
- case 'opencode': {
44
- const { getProjects } = require('./opencode-sessions');
45
- const projects = getProjects({ force: options.force === true });
46
- return { projects, currentProject: projects[0] ? projects[0].name : null };
179
+ }
180
+ return error;
181
+ }
182
+
183
+ function _deserializeError(payload, fallbackMessage) {
184
+ if (payload instanceof Error) {
185
+ return payload;
186
+ }
187
+ if (!payload || typeof payload !== 'object') {
188
+ return new Error(_safeErrorText(payload, fallbackMessage));
189
+ }
190
+ const error = new Error(_safeErrorText(payload.message ? payload.message : fallbackMessage, fallbackMessage));
191
+ if (typeof payload.status === 'string') error.status = _safeErrorText(payload.status);
192
+ if (typeof payload.platform === 'string') error.platform = _safeErrorText(payload.platform);
193
+ if (typeof payload.capability === 'string') error.capability = _safeErrorText(payload.capability);
194
+ if (typeof payload.operation === 'string') error.operation = _safeErrorText(payload.operation);
195
+ if (typeof payload.retryable === 'boolean') error.retryable = payload.retryable;
196
+ const retryAfter = _safeRetryAfter(payload.retryAfter);
197
+ if (retryAfter !== undefined) error.retryAfter = retryAfter;
198
+ const code = _safeCode(payload.code);
199
+ if (code !== undefined) error.code = code;
200
+ const cause = _deserializeCause(payload.cause);
201
+ if (cause) {
202
+ error.cause = cause;
203
+ }
204
+ return error;
205
+ }
206
+
207
+ function _serializeWorkerValue(value) {
208
+ if (!_isTypedFailurePayload(value)) {
209
+ return value;
210
+ }
211
+ const serialized = {
212
+ status: value.status,
213
+ platform: _safeErrorText(value.platform),
214
+ capability: _safeErrorText(value.capability),
215
+ operation: _safeErrorText(value.operation),
216
+ error: value.error instanceof Error
217
+ ? _safeErrorText(value.error.message, 'dashboard snapshot failed')
218
+ : _safeErrorText(value.error, 'dashboard snapshot failed')
219
+ };
220
+ if (typeof value.retryable === 'boolean') {
221
+ serialized.retryable = value.retryable;
222
+ }
223
+ const retryAfter = _safeRetryAfter(value.retryAfter);
224
+ if (retryAfter !== undefined) serialized.retryAfter = retryAfter;
225
+ const code = _safeCode(value.code);
226
+ if (code !== undefined) serialized.code = code;
227
+ const cause = value.cause || (value.error instanceof Error ? value.error : null);
228
+ const serializedCause = _serializeCause(cause);
229
+ if (serializedCause) {
230
+ serialized.cause = serializedCause;
231
+ }
232
+ return serialized;
233
+ }
234
+
235
+ function _typedFailurePayloadToError(payload) {
236
+ const cause = payload.cause instanceof Error
237
+ ? payload.cause
238
+ : payload.cause && typeof payload.cause === 'object'
239
+ ? _deserializeCause(payload.cause)
240
+ : payload.cause != null
241
+ ? new Error(String(payload.cause))
242
+ : payload.error instanceof Error
243
+ ? payload.error
244
+ : new Error(String(payload.error || 'dashboard snapshot failed'));
245
+ const error = new Error(`Dashboard snapshot ${payload.capability} ${payload.operation} failed on ${payload.platform}: ${cause.message}`);
246
+ if (typeof payload.status === 'string') {
247
+ error.status = payload.status;
248
+ }
249
+ error.platform = payload.platform;
250
+ error.capability = payload.capability;
251
+ error.operation = payload.operation;
252
+ if (typeof payload.retryable === 'boolean') {
253
+ error.retryable = payload.retryable;
254
+ }
255
+ const retryAfter = _safeRetryAfter(payload.retryAfter);
256
+ if (retryAfter !== undefined) {
257
+ error.retryAfter = retryAfter;
258
+ }
259
+ const code = _safeCode(payload.code);
260
+ if (code !== undefined) {
261
+ error.code = code;
262
+ }
263
+ error.cause = cause;
264
+ error.failure = payload;
265
+ return error;
266
+ }
267
+
268
+ function _unsupportedPayload(source, capability) {
269
+ return { status: 'unsupported', platform: source, capability };
270
+ }
271
+
272
+ function _driverFailurePayload(source, capability, error) {
273
+ const result = {
274
+ status: 'failed',
275
+ platform: source,
276
+ capability,
277
+ operation: 'resolve-driver',
278
+ error: _safeErrorText(error && error.message ? error.message : error, 'dashboard snapshot failed'),
279
+ retryable: error?.retryable !== false
280
+ };
281
+ const retryAfter = _safeRetryAfter(error?.retryAfter);
282
+ if (retryAfter !== undefined) {
283
+ result.retryAfter = retryAfter;
284
+ }
285
+ const code = _safeCode(error?.code);
286
+ if (code !== undefined) {
287
+ result.code = code;
288
+ }
289
+ if (error) {
290
+ Object.defineProperty(result, 'cause', { value: error, enumerable: false });
291
+ }
292
+ return result;
293
+ }
294
+
295
+ function _capabilityInvocationError(source, capability, operation, error) {
296
+ const cause = error instanceof Error ? error : new Error(_safeErrorText(error, 'unknown error'));
297
+ const metadataSource = error && typeof error === 'object' ? error : cause;
298
+ const wrapped = new Error(cause.message);
299
+ if (typeof metadataSource.status === 'string') {
300
+ wrapped.status = _safeErrorText(metadataSource.status);
301
+ }
302
+ if (typeof metadataSource.retryable === 'boolean') {
303
+ wrapped.retryable = metadataSource.retryable;
304
+ }
305
+ const retryAfter = _safeRetryAfter(metadataSource.retryAfter);
306
+ if (retryAfter !== undefined) {
307
+ wrapped.retryAfter = retryAfter;
308
+ }
309
+ wrapped.platform = source;
310
+ wrapped.capability = capability;
311
+ wrapped.operation = operation;
312
+ wrapped.cause = error && typeof error === 'object' && error.cause ? error.cause : cause;
313
+ const code = _safeCode(metadataSource.code);
314
+ if (code !== undefined) {
315
+ wrapped.code = code;
316
+ }
317
+ return wrapped;
318
+ }
319
+
320
+ async function _invokeCapabilityGetter(source, capability, operation, getter, options) {
321
+ try {
322
+ const value = await getter(options);
323
+ return value && value.status === 'ok' ? value.data : value;
324
+ } catch (error) {
325
+ throw _capabilityInvocationError(source, capability, operation, error);
326
+ }
327
+ }
328
+
329
+ function _configProjectOrder(config = {}) {
330
+ if (Array.isArray(config.projectOrder)) {
331
+ return config.projectOrder;
332
+ }
333
+ if (Array.isArray(config.order)) {
334
+ return config.order;
335
+ }
336
+ return [];
337
+ }
338
+
339
+
340
+ function _getRuntimeDriver(runtime, source, capability) {
341
+ if (!runtime || typeof runtime.getDriver !== 'function') {
342
+ return null;
343
+ }
344
+ try {
345
+ return runtime.getDriver(source, capability);
346
+ } catch (error) {
347
+ return _driverFailurePayload(source, capability, error);
348
+ }
349
+ }
350
+
351
+ function _getProjectsGetter(driver) {
352
+ if (!driver) return null;
353
+ if (typeof driver.listProjects === 'function') return driver.listProjects.bind(driver);
354
+ if (typeof driver.getProjects === 'function') return driver.getProjects.bind(driver);
355
+ return null;
356
+ }
357
+
358
+ function _getProjectOrderGetter(driver) {
359
+ if (!driver || typeof driver.getProjectOrder !== 'function') return null;
360
+ return driver.getProjectOrder.bind(driver);
361
+ }
362
+
363
+ async function _getClaudeProjectOrder(driver, config, options) {
364
+ const getter = _getProjectOrderGetter(driver);
365
+ if (!getter) {
366
+ return _configProjectOrder(config);
367
+ }
368
+ const order = await _invokeCapabilityGetter(
369
+ 'claude',
370
+ 'project-order',
371
+ 'get',
372
+ getter,
373
+ { force: options.force === true, config }
374
+ );
375
+ if (_isTypedFailurePayload(order)) {
376
+ throw _typedFailurePayloadToError(order);
377
+ }
378
+ return Array.isArray(order) ? order : _configProjectOrder(config);
379
+ }
380
+
381
+ function _getCountsGetter(driver) {
382
+ if (!driver) return null;
383
+ if (typeof driver.getProjectAndSessionCounts === 'function') return driver.getProjectAndSessionCounts.bind(driver);
384
+ if (typeof driver.counts === 'function') return driver.counts.bind(driver);
385
+ return null;
386
+ }
387
+
388
+ function _getTodayStatsGetter(driver) {
389
+ if (!driver) return null;
390
+ if (typeof driver.getTodayStatistics === 'function') return driver.getTodayStatistics.bind(driver);
391
+ if (typeof driver.today === 'function') return driver.today.bind(driver);
392
+ return null;
393
+ }
394
+
395
+ function _getChannelsGetter(driver) {
396
+ if (!driver) return null;
397
+ if (typeof driver.list === 'function') return driver.list.bind(driver);
398
+ if (typeof driver.getChannels === 'function') return driver.getChannels.bind(driver);
399
+ return null;
400
+ }
401
+
402
+ function _isPlainSuccessProjectPayload(value) {
403
+ if (!value || typeof value !== 'object') {
404
+ return false;
405
+ }
406
+ return !('status' in value) && !('type' in value) && !('error' in value);
407
+ }
408
+
409
+ function _normalizeProjectPayload(source, projects, config = {}) {
410
+ if (Array.isArray(projects)) {
411
+ const ordered = source === 'claude'
412
+ ? sortClaudeProjects(projects, config.projectOrder || config.order || [])
413
+ : projects;
414
+
415
+ return {
416
+ projects: ordered,
417
+ currentProject: source === 'claude' ? (config.currentProject ?? (ordered[0] ? ordered[0].name : null)) : (ordered[0] ? ordered[0].name : null)
418
+ };
419
+ }
420
+
421
+ if (_isPlainSuccessProjectPayload(projects) && Array.isArray(projects.projects)) {
422
+ const ordered = source === 'claude'
423
+ ? sortClaudeProjects(projects.projects, config.projectOrder || config.order || [])
424
+ : projects.projects;
425
+
426
+ return {
427
+ ...projects,
428
+ projects: ordered,
429
+ currentProject: projects.currentProject ?? (source === 'claude' ? config.currentProject : undefined) ?? (ordered[0] ? ordered[0].name : null)
430
+ };
431
+ }
432
+
433
+ return projects;
434
+ }
435
+
436
+ function _normalizeChannelsPayload(driver, value) {
437
+ if (_isTypedPayload(value)) {
438
+ return value;
439
+ }
440
+ if (typeof driver?.normalizeDashboardChannels === 'function') {
441
+ return driver.normalizeDashboardChannels(value);
442
+ }
443
+ if (Array.isArray(value)) {
444
+ return { channels: value };
445
+ }
446
+ if (value && typeof value === 'object' && Array.isArray(value.channels)) {
447
+ return value;
448
+ }
449
+ if (value == null) {
450
+ return { channels: [] };
451
+ }
452
+ return value;
453
+ }
454
+
455
+ async function readProjectsPayload(source, config = {}, options = {}) {
456
+ const runtime = options.runtime || getPlatformContext().runtime;
457
+ const driver = _getRuntimeDriver(runtime, source, 'projects');
458
+ const getter = _getProjectsGetter(driver);
459
+ if (getter) {
460
+ const driverOptions = { force: options.force === true, config };
461
+ const projects = await _invokeCapabilityGetter(source, 'projects', 'list', getter, driverOptions);
462
+ if (_isTypedPayload(projects)) {
463
+ if (projects.status === 'failed' && projects.cause instanceof Error) {
464
+ throw projects.cause;
465
+ }
466
+ return projects;
47
467
  }
48
- case 'omp': {
49
- const { getProjects } = require('./omp-sessions');
50
- const projects = await getProjects({ force: options.force === true });
51
- return { projects, currentProject: projects[0] ? projects[0].name : null };
468
+ if (source === 'claude') {
469
+ const order = await _getClaudeProjectOrder(driver, config, options);
470
+ return _normalizeProjectPayload(source, projects, { projectOrder: order, currentProject: config.currentProject });
52
471
  }
53
- default:
54
- throw new Error(`Unsupported project snapshot source: ${source}`);
472
+ return _normalizeProjectPayload(source, projects, config);
55
473
  }
474
+
475
+ if (_isTypedPayload(driver)) {
476
+ return driver;
477
+ }
478
+
479
+ return _unsupportedPayload(source, 'projects');
56
480
  }
57
481
 
58
482
  async function buildCountsPayload(source, config = {}, options = {}) {
59
- switch (source) {
60
- case 'claude':
61
- return require('./sessions').getProjectAndSessionCounts(config);
62
- case 'codex':
63
- return require('./codex-sessions').getProjectAndSessionCounts({ force: options.force === true });
64
- case 'gemini':
65
- return require('./gemini-sessions').getProjectAndSessionCounts({ force: options.force === true });
66
- case 'opencode':
67
- return require('./opencode-sessions').getProjectAndSessionCounts({ force: options.force === true });
68
- case 'omp':
69
- return require('./omp-sessions').getProjectAndSessionCounts({ force: options.force === true });
70
- default:
71
- throw new Error(`Unsupported counts snapshot source: ${source}`);
72
- }
73
- }
74
-
75
- function buildTodayStatsPayload(source) {
76
- switch (source) {
77
- case 'claude':
78
- return require('./claude-statistics-service').getTodayStatistics();
79
- case 'codex':
80
- return require('./codex-statistics-service').getTodayStatistics();
81
- case 'gemini':
82
- return require('./gemini-statistics-service').getTodayStatistics();
83
- case 'opencode':
84
- return require('./opencode-statistics-service').getTodayStatistics();
85
- case 'omp':
86
- return require('./omp-statistics-service').getTodayStatistics();
87
- default:
88
- throw new Error(`Unsupported today stats snapshot source: ${source}`);
89
- }
90
- }
91
-
92
- function buildChannelsPayload(source) {
93
- switch (source) {
94
- case 'claude':
95
- return require('./channels').getAllChannels();
96
- case 'codex':
97
- return require('./codex-channels').getChannels();
98
- case 'gemini':
99
- return require('./gemini-channels').getChannels();
100
- case 'opencode':
101
- return require('./opencode-channels').getChannels();
102
- case 'omp':
103
- return require('./omp-channels').getChannels();
104
- default:
105
- throw new Error(`Unsupported channels snapshot source: ${source}`);
483
+ const runtime = options.runtime || getPlatformContext().runtime;
484
+ const countsDriver = _getRuntimeDriver(runtime, source, 'counts');
485
+ const countsGetter = _getCountsGetter(countsDriver);
486
+ if (countsGetter) {
487
+ return _invokeCapabilityGetter(source, 'counts', 'count', countsGetter, { force: options.force === true, config });
488
+ }
489
+ if (_isTypedPayload(countsDriver)) {
490
+ return countsDriver;
491
+ }
492
+
493
+ const projectsDriver = _getRuntimeDriver(runtime, source, 'projects');
494
+ const projectsGetter = _getCountsGetter(projectsDriver);
495
+ if (projectsGetter) {
496
+ return _invokeCapabilityGetter(source, 'counts', 'count', projectsGetter, { force: options.force === true, config });
497
+ }
498
+ if (_isTypedPayload(projectsDriver)) {
499
+ return projectsDriver;
500
+ }
501
+
502
+ return _unsupportedPayload(source, 'counts');
503
+ }
504
+
505
+ async function buildTodayStatsPayload(source, config = {}, options = {}) {
506
+ const runtime = options.runtime || getPlatformContext().runtime;
507
+ const driver = _getRuntimeDriver(runtime, source, 'statistics');
508
+ const getter = _getTodayStatsGetter(driver);
509
+ if (getter) {
510
+ return _invokeCapabilityGetter(source, 'statistics', 'get', getter, { force: options.force === true, config });
511
+ }
512
+
513
+ if (_isTypedPayload(driver)) {
514
+ return driver;
515
+ }
516
+
517
+ return _unsupportedPayload(source, 'statistics');
518
+ }
519
+
520
+ async function buildChannelsPayload(source, config = {}, options = {}) {
521
+ const runtime = options.runtime || getPlatformContext().runtime;
522
+ const driver = _getRuntimeDriver(runtime, source, 'channels');
523
+ const getter = _getChannelsGetter(driver);
524
+ if (getter) {
525
+ const value = await _invokeCapabilityGetter(source, 'channels', 'list', getter, { force: options.force === true, config });
526
+ return _normalizeChannelsPayload(driver, value);
527
+ }
528
+
529
+ if (_isTypedPayload(driver)) {
530
+ return driver;
531
+ }
532
+
533
+ return _unsupportedPayload(source, 'channels');
534
+ }
535
+
536
+ function _sourceCapabilityFallback(capability) {
537
+ if (capability === 'channels') {
538
+ return { channels: [] };
539
+ }
540
+ if (capability === 'counts') {
541
+ return { projectCount: 0, sessionCount: 0 };
542
+ }
543
+ return null;
544
+ }
545
+
546
+ function _sourceCapabilityFailure(source, capability, operation, error) {
547
+ const failure = _safeFailurePayload(error, {
548
+ status: 'failed',
549
+ platform: source,
550
+ capability,
551
+ operation,
552
+ error: error && error.message ? error.message : String(error)
553
+ });
554
+ if (error) {
555
+ const cause = error.cause || error;
556
+ Object.defineProperty(failure, 'cause', { value: cause, enumerable: false });
106
557
  }
558
+ return failure;
107
559
  }
108
560
 
109
- async function buildPayload({ kind, source, config, options }) {
110
- const snapshotOptions = options || {};
561
+ function _settledCapability(result, source, capability, operation, fallbackValue) {
562
+ const value = result.status === 'fulfilled'
563
+ ? result.value
564
+ : _sourceCapabilityFailure(source, capability, operation, result.reason);
565
+ if (_isTypedPayload(value)) {
566
+ const failure = _safeFailurePayload(value, {
567
+ platform: source,
568
+ capability,
569
+ operation,
570
+ error: 'dashboard capability failed'
571
+ });
572
+ return {
573
+ value: fallbackValue === undefined ? _sourceCapabilityFallback(capability) : fallbackValue,
574
+ failure
575
+ };
576
+ }
577
+ return { value, failure: null };
578
+ }
579
+
580
+ async function buildSourceDashboardPayload(source, config = {}, options = {}) {
581
+ const results = await Promise.allSettled([
582
+ buildChannelsPayload(source, config, options),
583
+ buildTodayStatsPayload(source, config, options),
584
+ buildCountsPayload(source, config, options)
585
+ ]);
586
+ const channels = _settledCapability(results[0], source, 'channels', 'list');
587
+ const todayStats = _settledCapability(results[1], source, 'statistics', 'get');
588
+ const counts = _settledCapability(results[2], source, 'counts', 'count');
589
+ const failures = [channels, todayStats, counts]
590
+ .filter(capability => capability.failure)
591
+ .map(capability => capability.failure);
592
+ const payload = {
593
+ channels: channels.value,
594
+ todayStats: todayStats.value,
595
+ counts: counts.value
596
+ };
597
+ if (failures.length > 0) {
598
+ Object.defineProperty(payload, '__errors', {
599
+ value: failures,
600
+ enumerable: true
601
+ });
602
+ }
603
+ return payload;
604
+ }
605
+
606
+ async function buildPayload({ kind, source, config, options, runtime } = {}) {
607
+ const isTest = process.env.NODE_ENV === 'test';
608
+ const snapshotOptions = isTest ? (options || {}) : _getSerializableWorkerOptions(options);
609
+ const effectiveRuntime = isTest ? (runtime || snapshotOptions.runtime) : undefined;
610
+ const effectiveOptions = effectiveRuntime ? { ...snapshotOptions, runtime: effectiveRuntime } : snapshotOptions;
111
611
  switch (kind) {
112
612
  case 'projects':
113
- return buildProjectsPayload(source, config || {}, snapshotOptions);
613
+ return readProjectsPayload(source, config || {}, effectiveOptions);
114
614
  case 'counts':
115
- return buildCountsPayload(source, config || {}, snapshotOptions);
615
+ return buildCountsPayload(source, config || {}, effectiveOptions);
116
616
  case 'todayStats':
117
- return buildTodayStatsPayload(source);
617
+ return buildTodayStatsPayload(source, config || {}, effectiveOptions);
118
618
  case 'channels':
119
- return buildChannelsPayload(source);
619
+ return buildChannelsPayload(source, config || {}, effectiveOptions);
620
+ case 'source':
621
+ return buildSourceDashboardPayload(source, config || {}, effectiveOptions);
120
622
  default:
121
623
  throw new Error(`Unsupported dashboard snapshot kind: ${kind}`);
122
624
  }
123
625
  }
124
626
 
627
+ function _sendWorkerMessage(message, exitCode, send, exit = process.exit) {
628
+ let exited = false;
629
+ const finish = (code) => {
630
+ if (exited) return;
631
+ exited = true;
632
+ exit(code);
633
+ };
634
+ const failureCode = exitCode && exitCode !== 0 ? exitCode : 1;
635
+ const sendImpl = send || (typeof process.send === 'function' ? process.send.bind(process) : null);
636
+
637
+ if (!sendImpl) {
638
+ finish(exitCode);
639
+ return;
640
+ }
641
+
642
+ try {
643
+ sendImpl(message, (callbackError) => {
644
+ if (callbackError) {
645
+ finish(failureCode);
646
+ return;
647
+ }
648
+ finish(exitCode);
649
+ });
650
+ } catch (_error) {
651
+ finish(failureCode);
652
+ }
653
+ }
654
+
655
+ function _getSerializableWorkerOptions(options = {}) {
656
+ if (!options || typeof options !== 'object') {
657
+ return {};
658
+ }
659
+ return typeof options.force === 'boolean' ? { force: options.force } : {};
660
+ }
661
+
125
662
  function runDashboardSnapshotWorker(kind, source, config = {}, options = {}) {
663
+ const workerOptions = _getSerializableWorkerOptions(options);
664
+ const runtime = options.runtime;
665
+
126
666
  if (process.env.NODE_ENV === 'test') {
127
- return Promise.resolve(buildPayload({ kind, source, config, options }));
667
+ return Promise.resolve(buildPayload({ kind, source, config, options: workerOptions, runtime }))
668
+ .then((value) => {
669
+ if (_isTypedFailurePayload(value)) {
670
+ throw _typedFailurePayloadToError(value);
671
+ }
672
+ return value;
673
+ });
128
674
  }
129
675
 
130
676
  return new Promise((resolve, reject) => {
131
- const child = fork(__filename, [], {
677
+ const child = childProcess.fork(__filename, [], {
132
678
  stdio: ['ignore', 'ignore', 'pipe', 'ipc'],
133
679
  windowsHide: true,
134
680
  env: {
@@ -144,9 +690,7 @@ function runDashboardSnapshotWorker(kind, source, config = {}, options = {}) {
144
690
  const finish = (error, value) => {
145
691
  if (settled) return;
146
692
  settled = true;
147
- if (timeout) {
148
- clearTimeout(timeout);
149
- }
693
+ clearTimeout(timeout);
150
694
  child.removeAllListeners();
151
695
  if (!child.killed) {
152
696
  child.kill();
@@ -172,9 +716,13 @@ function runDashboardSnapshotWorker(kind, source, config = {}, options = {}) {
172
716
  child.on('message', (message) => {
173
717
  if (!message || typeof message !== 'object') return;
174
718
  if (message.ok) {
719
+ if (_isTypedFailurePayload(message.value)) {
720
+ finish(_typedFailurePayloadToError(message.value));
721
+ return;
722
+ }
175
723
  finish(null, message.value);
176
724
  } else {
177
- finish(new Error(message.error || `Dashboard snapshot refresh failed for ${kind}/${source}`));
725
+ finish(_deserializeError(message.error, `Dashboard snapshot refresh failed for ${kind}/${source}`));
178
726
  }
179
727
  });
180
728
 
@@ -185,33 +733,41 @@ function runDashboardSnapshotWorker(kind, source, config = {}, options = {}) {
185
733
  finish(new Error(`Dashboard snapshot worker exited (${code || signal || 'unknown'})${suffix}`));
186
734
  });
187
735
 
188
- child.send({ kind, source, config, options });
736
+ try {
737
+ child.send({ kind, source, config, options: workerOptions });
738
+ } catch (error) {
739
+ finish(error);
740
+ }
189
741
  });
190
742
  }
191
743
 
744
+ function runDashboardSourceWorker(source, config = {}, options = {}) {
745
+ return runDashboardSnapshotWorker('source', source, config, options);
746
+ }
192
747
  function attachWorkerHandler() {
193
748
  process.on('message', async (message) => {
194
749
  try {
195
750
  const value = await buildPayload(message || {});
196
- if (process.send) {
197
- process.send({ ok: true, value }, () => process.exit(0));
198
- return;
199
- }
751
+ _sendWorkerMessage({ ok: true, value: _serializeWorkerValue(value) }, 0);
200
752
  } catch (error) {
201
- if (process.send) {
202
- process.send({ ok: false, error: error?.message || String(error) }, () => process.exit(1));
203
- return;
204
- }
753
+ _sendWorkerMessage({ ok: false, error: _serializeError(error) }, 1);
205
754
  }
206
- process.exit(0);
207
755
  });
208
756
  }
209
757
 
210
758
  if (process.env.CC_TOOL_DASHBOARD_SNAPSHOT_WORKER === '1' || require.main === module) {
211
759
  attachWorkerHandler();
212
760
  }
213
-
214
761
  module.exports = {
215
762
  buildPayload,
216
- runDashboardSnapshotWorker
763
+ buildSourceDashboardPayload,
764
+ runDashboardSnapshotWorker,
765
+ runDashboardSourceWorker,
766
+ _test: {
767
+ getSerializableWorkerOptions: _getSerializableWorkerOptions,
768
+ sendWorkerMessage: _sendWorkerMessage,
769
+ serializeError: _serializeError,
770
+ deserializeError: _deserializeError,
771
+ serializeWorkerValue: _serializeWorkerValue
772
+ }
217
773
  };