coding-tool-x 3.8.4 → 3.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +86 -15
  3. package/dist/web/assets/AgentsDrawer-BG6P3DX-.js +1 -0
  4. package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
  5. package/dist/web/assets/Analytics--z_FmL5P.js +1 -0
  6. package/dist/web/assets/Analytics-CyHhR126.css +1 -0
  7. package/dist/web/assets/AssetPathField-CrJtRKHy.js +1 -0
  8. package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
  9. package/dist/web/assets/ChatHistoryDrawer-BiuEryJj.js +1 -0
  10. package/dist/web/assets/CollapseItem-BAYEsL_Q.js +1 -0
  11. package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
  12. package/dist/web/assets/CommandsDrawer-YJ-U7BXN.js +1 -0
  13. package/dist/web/assets/ConfigExportDrawer-Ce_hAknW.js +1 -0
  14. package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
  15. package/dist/web/assets/ConfigTemplates-Bvr1NN6K.js +1 -0
  16. package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
  17. package/dist/web/assets/ConfigTemplatesDrawer-BjIeHfF-.js +1 -0
  18. package/dist/web/assets/ConfigTemplatesPanel-AV00tm_D.js +1 -0
  19. package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +1 -0
  20. package/dist/web/assets/Divider-D28g1gwj.js +1 -0
  21. package/dist/web/assets/DrawerContent-ChXgZ1Xm.js +1 -0
  22. package/dist/web/assets/FavoritesDrawer-CG9eI9Ay.css +1 -0
  23. package/dist/web/assets/FavoritesDrawer-Cz95o4CD.js +1 -0
  24. package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
  25. package/dist/web/assets/GatewayConvertDrawer-DLlbMz27.js +1 -0
  26. package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
  27. package/dist/web/assets/Home-D7CCOFQC.js +1 -0
  28. package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
  29. package/dist/web/assets/MarkdownEditor-rEZ-c72L.js +1 -0
  30. package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
  31. package/dist/web/assets/McpDrawer-DfoCyxU2.js +1 -0
  32. package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
  33. package/dist/web/assets/McpFormDrawer-SKu8HNUR.js +1 -0
  34. package/dist/web/assets/PluginManager-BbeK-3rV.js +1 -0
  35. package/dist/web/assets/PluginsDrawer-CWVJ7yjS.js +1 -0
  36. package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
  37. package/dist/web/assets/PluginsPanel-Cm2N3StG.js +1 -0
  38. package/dist/web/assets/PluginsPanel-D6ZqITcR.css +1 -0
  39. package/dist/web/assets/ProjectList-677RLZ8O.css +1 -0
  40. package/dist/web/assets/ProjectList-CsjnsNPv.js +1 -0
  41. package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
  42. package/dist/web/assets/PromptsDrawer-EGd3djFa.js +1 -0
  43. package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
  44. package/dist/web/assets/RecentSessionsDrawer-D1vtoLAs.js +1 -0
  45. package/dist/web/assets/SessionCard-BgLg49U3.js +1 -0
  46. package/dist/web/assets/SessionCard-aM2NHu6i.css +1 -0
  47. package/dist/web/assets/SessionList-BpYRz1cX.css +1 -0
  48. package/dist/web/assets/SessionList-TRiTklWk.js +1 -0
  49. package/dist/web/assets/SettingsDrawer-d5liXjHq.css +1 -0
  50. package/dist/web/assets/SettingsDrawer-rz2WejGY.js +1 -0
  51. package/dist/web/assets/SkillManager-BTjTUbHq.js +1 -0
  52. package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
  53. package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
  54. package/dist/web/assets/SkillsDrawer-pN0hbkK3.js +1 -0
  55. package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
  56. package/dist/web/assets/SkillsPanel-gmBWEoiF.js +1 -0
  57. package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
  58. package/dist/web/assets/SpeedTestDrawer-DcNzuVJk.js +1 -0
  59. package/dist/web/assets/Upload-v5rV0qTT.js +1 -0
  60. package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
  61. package/dist/web/assets/WorkspaceDrawer-DxmicM4U.js +1 -0
  62. package/dist/web/assets/WorkspaceManager-CJHCjARN.js +1 -0
  63. package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
  64. package/dist/web/assets/WorkspacePanel-D8_Zq-du.js +1 -0
  65. package/dist/web/assets/_plugin-vue_export-helper-BeLZJZij.js +1 -0
  66. package/dist/web/assets/client-UDwXBP9i.js +1 -0
  67. package/dist/web/assets/clipboard-B46yyoz_.js +1 -0
  68. package/dist/web/assets/headers-cf-QapUq.js +1 -0
  69. package/dist/web/assets/icons-B2Vg-IOC.js +1 -0
  70. package/dist/web/assets/index-C0EHRym0.css +1 -0
  71. package/dist/web/assets/index-DnEocV0M.js +2 -0
  72. package/dist/web/assets/light-Cp0t7v32.js +1 -0
  73. package/dist/web/assets/markdown-u082bbtj.js +1 -0
  74. package/dist/web/assets/platforms-CBkB45JP.js +1 -0
  75. package/dist/web/assets/platforms-FTpjxAT6.js +1 -0
  76. package/dist/web/assets/project-config-B2baPzYL.js +1 -0
  77. package/dist/web/assets/sessions-Cmy31slD.js +1 -0
  78. package/dist/web/assets/sessions-yC_oVVh8.js +1 -0
  79. package/dist/web/assets/skill-repo-input-B_fkGlUK.js +1 -0
  80. package/dist/web/assets/use-lock-html-scroll-DXIqmUW4.js +1 -0
  81. package/dist/web/assets/use-message-DoLM8C1C.js +1 -0
  82. package/dist/web/assets/useResponsiveDrawer-B3uojyvV.js +1 -0
  83. package/dist/web/assets/vendors-D0c_0KLP.js +1 -0
  84. package/dist/web/assets/vue-vendor-BqZbbXHA.js +1 -0
  85. package/dist/web/assets/workspaces-mjyPVGS8.js +1 -0
  86. package/dist/web/assets/xml-CgY3RMlX.js +1 -0
  87. package/dist/web/index.html +12 -8
  88. package/docs/native-log-memory-2026-09-16.md +43 -0
  89. package/docs/superpowers/plans/2026-08-26-configuration-driven-cli-platform.md +1578 -0
  90. package/docs/superpowers/plans/2026-08-30-project-scoped-config-control.md +1260 -0
  91. package/docs/superpowers/plans/2026-09-01-omp-skill-refresh-boundary.md +213 -0
  92. package/docs/superpowers/plans/2026-09-01-realtime-logs-panel.md +125 -0
  93. package/docs/superpowers/plans/2026-09-02-config-driven-platform-boundary.md +86 -0
  94. package/docs/superpowers/plans/2026-09-02-platform-implementation-drivers.md +508 -0
  95. package/docs/superpowers/plans/2026-09-03-cli-platform-correctness-boundary.md +760 -0
  96. package/docs/superpowers/plans/2026-09-03-dependency-security-remediation.md +133 -0
  97. package/docs/superpowers/plans/2026-09-04-model-catalog-pricing-sync.md +1078 -0
  98. package/docs/superpowers/plans/2026-09-05-codex-project-scan-500.md +128 -0
  99. package/docs/superpowers/plans/2026-09-06-project-skill-path-fix.md +97 -0
  100. package/docs/superpowers/specs/2026-08-26-configuration-driven-cli-platform-design.md +408 -0
  101. package/docs/superpowers/specs/2026-08-30-project-scoped-config-control-design.md +467 -0
  102. package/docs/superpowers/specs/2026-09-01-claude-session-content-repair-design.md +111 -0
  103. package/docs/superpowers/specs/2026-09-01-omp-skill-refresh-boundary-design.md +83 -0
  104. package/docs/superpowers/specs/2026-09-01-realtime-logs-panel-design.md +27 -0
  105. package/docs/superpowers/specs/2026-09-02-config-driven-platform-boundary-design.md +64 -0
  106. package/docs/superpowers/specs/2026-09-02-platform-implementation-driver-boundary-design.md +123 -0
  107. package/docs/superpowers/specs/2026-09-03-cli-platform-correctness-boundary-design.md +249 -0
  108. package/docs/superpowers/specs/2026-09-03-dependency-security-remediation-design.md +87 -0
  109. package/docs/superpowers/specs/2026-09-04-model-catalog-pricing-sync-design.md +301 -0
  110. package/docs/superpowers/specs/2026-09-05-codex-project-scan-500-design.md +24 -0
  111. package/package.json +8 -4
  112. package/src/commands/channels.js +88 -191
  113. package/src/commands/cli-type.js +19 -11
  114. package/src/commands/daemon.js +94 -32
  115. package/src/commands/doctor.js +16 -9
  116. package/src/commands/export-config.js +23 -5
  117. package/src/commands/list.js +130 -52
  118. package/src/commands/logs.js +44 -27
  119. package/src/commands/platform-command-registry.js +78 -0
  120. package/src/commands/plugin.js +11 -5
  121. package/src/commands/port-config.js +34 -52
  122. package/src/commands/proxy-control.js +207 -145
  123. package/src/commands/proxy.js +2 -2
  124. package/src/commands/resume.js +87 -91
  125. package/src/commands/search.js +137 -67
  126. package/src/commands/stats.js +30 -22
  127. package/src/commands/switch.js +1 -1
  128. package/src/commands/toggle-proxy.js +94 -111
  129. package/src/commands/ui.js +67 -6
  130. package/src/commands/workspace.js +90 -8
  131. package/src/config/default.js +6 -53
  132. package/src/config/loader.js +61 -24
  133. package/src/config/model-metadata.js +49 -59
  134. package/src/config/model-metadata.json +4095 -99
  135. package/src/config/paths.js +181 -8
  136. package/src/index.js +134 -71
  137. package/src/platforms/access.js +196 -0
  138. package/src/{server/services → platforms}/agents-service.js +354 -197
  139. package/src/platforms/channel-auth-registry.js +162 -0
  140. package/src/platforms/channel-auth-service.js +82 -0
  141. package/src/{server/services → platforms}/commands-service.js +195 -115
  142. package/src/platforms/driver-registry.js +59 -0
  143. package/src/platforms/drivers/claude/api-operations.js +62 -0
  144. package/src/{server/services/channels.js → platforms/drivers/claude/channels-implementation.js} +131 -33
  145. package/src/platforms/drivers/claude/channels.js +39 -0
  146. package/src/{server/services/config-sync-service.js → platforms/drivers/claude/config-sync.js} +29 -5
  147. package/src/{server/services → platforms/drivers/claude}/health-check.js +4 -4
  148. package/src/platforms/drivers/claude/health.js +22 -0
  149. package/src/platforms/drivers/claude/mcp.js +9 -0
  150. package/src/{server/services/settings-manager.js → platforms/drivers/claude/native-config-implementation.js} +13 -4
  151. package/src/platforms/drivers/claude/native-config.js +46 -0
  152. package/src/platforms/drivers/claude/native-logs.js +72 -0
  153. package/src/{server/services/claude-openai-gateway.js → platforms/drivers/claude/openai-gateway.js} +8 -65
  154. package/src/platforms/drivers/claude/project-config.js +21 -0
  155. package/src/platforms/drivers/claude/projects.js +62 -0
  156. package/src/platforms/drivers/claude/prompts.js +9 -0
  157. package/src/{server/proxy-server.js → platforms/drivers/claude/proxy-implementation.js} +41 -278
  158. package/src/platforms/drivers/claude/proxy.js +16 -0
  159. package/src/platforms/drivers/claude/resource-sync.js +9 -0
  160. package/src/platforms/drivers/claude/session-history-adapter.js +313 -0
  161. package/src/{server/services/sessions.js → platforms/drivers/claude/sessions-implementation.js} +145 -35
  162. package/src/platforms/drivers/claude/sessions.js +76 -0
  163. package/src/{server/services/claude-statistics-service.js → platforms/drivers/claude/statistics-implementation.js} +2 -2
  164. package/src/platforms/drivers/claude/statistics.js +16 -0
  165. package/src/{server/services/claude-wire.js → platforms/drivers/claude/wire.js} +1 -1
  166. package/src/platforms/drivers/codex/api-operations.js +9 -0
  167. package/src/{server/services/codex-channels.js → platforms/drivers/codex/channels-implementation.js} +149 -14
  168. package/src/platforms/drivers/codex/channels.js +45 -0
  169. package/src/{server/services/codex-config.js → platforms/drivers/codex/config.js} +12 -2
  170. package/src/{server/services/codex-env-manager.js → platforms/drivers/codex/env-manager.js} +1 -1
  171. package/src/platforms/drivers/codex/mcp.js +9 -0
  172. package/src/{server/services/codex-settings-manager.js → platforms/drivers/codex/native-config-implementation.js} +15 -6
  173. package/src/platforms/drivers/codex/native-config.js +47 -0
  174. package/src/platforms/drivers/codex/native-logs.js +166 -0
  175. package/src/platforms/drivers/codex/project-config.js +21 -0
  176. package/src/platforms/drivers/codex/projects.js +26 -0
  177. package/src/platforms/drivers/codex/prompts.js +9 -0
  178. package/src/{server/codex-proxy-server.js → platforms/drivers/codex/proxy-implementation.js} +30 -233
  179. package/src/platforms/drivers/codex/proxy.js +16 -0
  180. package/src/platforms/drivers/codex/resource-sync.js +9 -0
  181. package/src/{server/services/session-history-adapters/codex.js → platforms/drivers/codex/session-history-adapter.js} +37 -23
  182. package/src/{server/services/codex-sessions.js → platforms/drivers/codex/sessions-implementation.js} +81 -75
  183. package/src/platforms/drivers/codex/sessions.js +36 -0
  184. package/src/{server/services/codex-statistics-service.js → platforms/drivers/codex/statistics-implementation.js} +2 -2
  185. package/src/platforms/drivers/codex/statistics.js +16 -0
  186. package/src/platforms/drivers/gemini/api-operations.js +9 -0
  187. package/src/{server/services/gemini-channels.js → platforms/drivers/gemini/channels-implementation.js} +202 -37
  188. package/src/platforms/drivers/gemini/channels.js +39 -0
  189. package/src/{server/services/gemini-config.js → platforms/drivers/gemini/config.js} +12 -2
  190. package/src/platforms/drivers/gemini/mcp.js +9 -0
  191. package/src/{server/services/gemini-settings-manager.js → platforms/drivers/gemini/native-config-implementation.js} +14 -5
  192. package/src/platforms/drivers/gemini/native-config.js +39 -0
  193. package/src/platforms/drivers/gemini/native-logs.js +180 -0
  194. package/src/platforms/drivers/gemini/project-config.js +21 -0
  195. package/src/platforms/drivers/gemini/projects.js +26 -0
  196. package/src/platforms/drivers/gemini/prompts.js +9 -0
  197. package/src/{server/gemini-proxy-server.js → platforms/drivers/gemini/proxy-implementation.js} +36 -267
  198. package/src/platforms/drivers/gemini/proxy.js +16 -0
  199. package/src/platforms/drivers/gemini/resource-sync.js +9 -0
  200. package/src/{server/services/session-history-adapters/gemini.js → platforms/drivers/gemini/session-history-adapter.js} +70 -18
  201. package/src/{server/services/gemini-sessions.js → platforms/drivers/gemini/sessions-implementation.js} +53 -37
  202. package/src/platforms/drivers/gemini/sessions.js +47 -0
  203. package/src/{server/services/gemini-statistics-service.js → platforms/drivers/gemini/statistics-implementation.js} +2 -2
  204. package/src/platforms/drivers/gemini/statistics.js +16 -0
  205. package/src/{server/services/gemini-wire.js → platforms/drivers/gemini/wire.js} +1 -1
  206. package/src/platforms/drivers/generic-filesystem.js +166 -0
  207. package/src/platforms/drivers/generic-jsonl.js +141 -0
  208. package/src/platforms/drivers/generic-mcp.js +44 -0
  209. package/src/platforms/drivers/generic-openai-compatible.js +45 -0
  210. package/src/platforms/drivers/generic-prompt.js +41 -0
  211. package/src/platforms/drivers/legacy.js +677 -0
  212. package/src/platforms/drivers/native-config-snapshot.js +125 -0
  213. package/src/platforms/drivers/native-log-utils.js +1292 -0
  214. package/src/platforms/drivers/notification-hooks.js +578 -0
  215. package/src/{server/api/omp-config.js → platforms/drivers/omp/api-operations.js} +52 -64
  216. package/src/{server/services/omp-auth-provider-worker.js → platforms/drivers/omp/auth-provider-worker.js} +1 -1
  217. package/src/{server/services/omp-auth-providers.js → platforms/drivers/omp/auth-providers.js} +1 -1
  218. package/src/{server/services/omp-channels.js → platforms/drivers/omp/channels-implementation.js} +166 -39
  219. package/src/platforms/drivers/omp/channels.js +58 -0
  220. package/src/{server/services/omp-config.js → platforms/drivers/omp/config.js} +53 -13
  221. package/src/{server/services/omp-gateway-routing.js → platforms/drivers/omp/gateway-routing.js} +14 -7
  222. package/src/{server/services/omp-gateway.js → platforms/drivers/omp/gateway.js} +4 -262
  223. package/src/platforms/drivers/omp/mcp.js +9 -0
  224. package/src/{server/services/omp-settings-manager.js → platforms/drivers/omp/native-config-implementation.js} +75 -10
  225. package/src/platforms/drivers/omp/native-config.js +46 -0
  226. package/src/platforms/drivers/omp/native-logs.js +52 -0
  227. package/src/{server/services/omp-native-plugin-adapter.js → platforms/drivers/omp/native-plugin-adapter.js} +91 -4
  228. package/src/platforms/drivers/omp/project-config.js +29 -0
  229. package/src/platforms/drivers/omp/projects.js +20 -0
  230. package/src/platforms/drivers/omp/prompts.js +9 -0
  231. package/src/{server/omp-proxy-server.js → platforms/drivers/omp/proxy-implementation.js} +6 -15
  232. package/src/platforms/drivers/omp/proxy.js +16 -0
  233. package/src/platforms/drivers/omp/resource-sync.js +9 -0
  234. package/src/{server/services/session-history-adapters/omp.js → platforms/drivers/omp/session-history-adapter.js} +42 -18
  235. package/src/{server/services/omp-sessions.js → platforms/drivers/omp/sessions-implementation.js} +130 -94
  236. package/src/platforms/drivers/omp/sessions.js +36 -0
  237. package/src/{server/services/omp-skill-discovery.js → platforms/drivers/omp/skill-discovery.js} +159 -32
  238. package/src/{server/services/omp-skill-settings-service.js → platforms/drivers/omp/skill-settings.js} +1 -1
  239. package/src/{server/services/omp-statistics-service.js → platforms/drivers/omp/statistics-implementation.js} +3 -3
  240. package/src/platforms/drivers/omp/statistics.js +16 -0
  241. package/src/platforms/drivers/opencode/api-operations.js +9 -0
  242. package/src/{server/services/opencode-channels.js → platforms/drivers/opencode/channels-implementation.js} +28 -9
  243. package/src/platforms/drivers/opencode/channels.js +40 -0
  244. package/src/platforms/drivers/opencode/conversion.js +41 -0
  245. package/src/{server/services/opencode-gateway-converter.js → platforms/drivers/opencode/gateway-converter.js} +1 -1
  246. package/src/platforms/drivers/opencode/mcp.js +9 -0
  247. package/src/{server/services/opencode-settings-manager.js → platforms/drivers/opencode/native-config-implementation.js} +17 -6
  248. package/src/platforms/drivers/opencode/native-config.js +26 -0
  249. package/src/platforms/drivers/opencode/native-logs.js +133 -0
  250. package/src/platforms/drivers/opencode/project-config.js +98 -0
  251. package/src/platforms/drivers/opencode/projects.js +20 -0
  252. package/src/platforms/drivers/opencode/prompts.js +9 -0
  253. package/src/{server/opencode-proxy-server.js → platforms/drivers/opencode/proxy-implementation.js} +27 -362
  254. package/src/platforms/drivers/opencode/proxy.js +16 -0
  255. package/src/platforms/drivers/opencode/resource-sync.js +9 -0
  256. package/src/{server/services/opencode-sessions.js → platforms/drivers/opencode/sessions-implementation.js} +211 -64
  257. package/src/platforms/drivers/opencode/sessions.js +48 -0
  258. package/src/{server/services/opencode-statistics-service.js → platforms/drivers/opencode/statistics-implementation.js} +2 -2
  259. package/src/platforms/drivers/opencode/statistics.js +16 -0
  260. package/src/platforms/drivers/secure-file-driver.js +272 -0
  261. package/src/platforms/drivers/unsupported.js +7 -0
  262. package/src/platforms/manifest-schema.js +398 -0
  263. package/src/platforms/manifests/claude.json +489 -0
  264. package/src/platforms/manifests/codex.json +448 -0
  265. package/src/platforms/manifests/gemini.json +447 -0
  266. package/src/platforms/manifests/omp.json +496 -0
  267. package/src/platforms/manifests/opencode.json +422 -0
  268. package/src/{server/services → platforms}/native-oauth-adapters.js +87 -417
  269. package/src/{server/services → platforms}/notification-hooks.js +140 -1023
  270. package/src/platforms/oauth-credentials-service.js +506 -0
  271. package/src/platforms/path-resolver.js +179 -0
  272. package/src/platforms/platform-path-context.js +305 -0
  273. package/src/platforms/registry.js +248 -0
  274. package/src/platforms/remote-notification-providers.js +678 -0
  275. package/src/platforms/runtime.js +259 -0
  276. package/src/{server/services/session-history-adapters/index.js → platforms/session-history-adapters.js} +8 -1
  277. package/src/plugins/plugin-loader.js +2 -2
  278. package/src/plugins/plugin-manager.js +2 -2
  279. package/src/plugins/registry.js +27 -10
  280. package/src/reset-config.js +21 -5
  281. package/src/server/api/agents.js +46 -72
  282. package/src/server/api/commands.js +16 -6
  283. package/src/server/api/config-registry.js +206 -59
  284. package/src/server/api/config-sync.js +3 -2
  285. package/src/server/api/config-templates.js +20 -4
  286. package/src/server/api/config.js +111 -102
  287. package/src/server/api/convert.js +54 -178
  288. package/src/server/api/dashboard.js +168 -102
  289. package/src/server/api/hooks.js +1 -1
  290. package/src/server/api/mcp.js +224 -84
  291. package/src/server/api/platform-api-config.js +102 -0
  292. package/src/server/api/platform-route-factory.js +215 -0
  293. package/src/server/api/platform-routes.js +26 -0
  294. package/src/server/api/platforms.js +110 -0
  295. package/src/server/api/plugins.js +57 -57
  296. package/src/server/api/project-config.js +168 -0
  297. package/src/server/api/prompts.js +58 -45
  298. package/src/server/api/settings.js +55 -8
  299. package/src/server/api/skills.js +262 -133
  300. package/src/server/api/ui-config.js +2 -2
  301. package/src/server/api/validation-errors.js +18 -4
  302. package/src/server/api/workspaces.js +47 -12
  303. package/src/server/index.js +164 -213
  304. package/src/server/platform-context.js +81 -0
  305. package/src/server/services/channel-balance.js +11 -20
  306. package/src/server/services/channel-health.js +21 -6
  307. package/src/server/services/channel-scheduler.js +29 -39
  308. package/src/server/services/channel-sync-utils.js +23 -13
  309. package/src/server/services/config-export-service.js +350 -319
  310. package/src/server/services/config-registry-service.js +280 -54
  311. package/src/server/services/config-sync-manager.js +172 -944
  312. package/src/server/services/config-templates-service.js +419 -353
  313. package/src/server/services/control-manifest-store.js +206 -0
  314. package/src/server/services/dashboard-snapshot-worker.js +656 -100
  315. package/src/server/services/effective-control-service.js +557 -0
  316. package/src/server/services/local-resource-index.js +314 -0
  317. package/src/server/services/mcp-service.js +607 -977
  318. package/src/server/services/model-detector.js +15 -10
  319. package/src/server/services/native-log-channel-resolver.js +214 -0
  320. package/src/server/services/native-log-observer.js +291 -0
  321. package/src/server/services/network-access.js +1 -1
  322. package/src/server/services/platform-catalog.js +82 -0
  323. package/src/server/services/platform-resolution.js +32 -29
  324. package/src/server/services/plugins-service.js +376 -122
  325. package/src/server/services/project-config-service.js +550 -0
  326. package/src/server/services/project-path-validation.js +31 -0
  327. package/src/server/services/prompts-service.js +267 -233
  328. package/src/server/services/proxy-runtime.js +7 -4
  329. package/src/server/services/remote-credential-cache.js +43 -0
  330. package/src/server/services/repo-scanner-base.js +182 -75
  331. package/src/server/services/request-logger.js +7 -4
  332. package/src/server/services/session-history-index.js +780 -213
  333. package/src/server/services/session-history-worker.js +228 -33
  334. package/src/server/services/session-snapshot-worker.js +124 -34
  335. package/src/server/services/session-snapshots.js +4 -2
  336. package/src/server/services/skill-artifact-store.js +355 -0
  337. package/src/server/services/skill-format-adapters.js +65 -0
  338. package/src/server/services/skill-projection-service.js +323 -0
  339. package/src/server/services/skill-refresh-task-service.js +275 -0
  340. package/src/server/services/skill-service.js +2020 -677
  341. package/src/server/services/snapshot-cache.js +30 -8
  342. package/src/server/services/speed-test.js +8 -8
  343. package/src/server/services/sqlite-connection.js +19 -3
  344. package/src/server/services/statistics-service.js +240 -57
  345. package/src/server/services/ui-config.js +107 -76
  346. package/src/server/services/usage-log-utils.js +98 -0
  347. package/src/server/services/web-build.js +1 -1
  348. package/src/server/services/workspace-service.js +59 -29
  349. package/src/server/utils/pricing.js +10 -19
  350. package/src/server/websocket-server.js +153 -28
  351. package/src/{server/services/base → shared}/base-channel-service.js +156 -28
  352. package/src/shared/capability-driver.js +104 -0
  353. package/src/shared/channel-auth-policy.js +27 -0
  354. package/src/shared/channel-driver.js +161 -0
  355. package/src/shared/driver-factories/api.js +180 -0
  356. package/src/shared/driver-factories/mcp.js +244 -0
  357. package/src/shared/driver-factories/projects.js +121 -0
  358. package/src/shared/driver-factories/prompts.js +58 -0
  359. package/src/shared/driver-factories/resource-sync.js +375 -0
  360. package/src/shared/driver-result.js +78 -0
  361. package/src/shared/mcp-format.js +189 -0
  362. package/src/shared/platforms.js +104 -167
  363. package/src/shared/project-config.js +512 -0
  364. package/src/shared/proxy-driver.js +57 -0
  365. package/src/{server/services/base → shared}/response-usage-parser.js +8 -4
  366. package/src/ui/menu.js +91 -67
  367. package/src/utils/port-helper.js +35 -19
  368. package/src/utils/session.js +1 -1
  369. package/dist/web/assets/Analytics-COEUXmd4.js +0 -25
  370. package/dist/web/assets/Analytics-RNn1BUbG.css +0 -1
  371. package/dist/web/assets/ConfigTemplates-DLLkS53H.js +0 -1
  372. package/dist/web/assets/Home-DCEyLzwX.js +0 -1
  373. package/dist/web/assets/Home-DYVy4cGZ.css +0 -1
  374. package/dist/web/assets/PluginManager-Oe1ZHoMO.js +0 -1
  375. package/dist/web/assets/ProjectList-CWjuAFof.js +0 -1
  376. package/dist/web/assets/ProjectList-VeMNXfgO.css +0 -1
  377. package/dist/web/assets/SessionList-C4chCPxK.css +0 -1
  378. package/dist/web/assets/SessionList-v3ehGg9U.js +0 -1
  379. package/dist/web/assets/SkillManager-BsX8Qpj0.css +0 -1
  380. package/dist/web/assets/SkillManager-DUF_qP5S.js +0 -1
  381. package/dist/web/assets/WorkspaceManager-CjAWBosO.js +0 -1
  382. package/dist/web/assets/icons-nGdSKQn2.js +0 -1
  383. package/dist/web/assets/index-D5hyHPj7.js +0 -2
  384. package/dist/web/assets/index-bJRG3RXH.css +0 -1
  385. package/dist/web/assets/markdown-BNJfEgCA.js +0 -1
  386. package/dist/web/assets/markdown-BfC0goYb.css +0 -10
  387. package/dist/web/assets/naive-ui-BALVpMgd.js +0 -1
  388. package/dist/web/assets/vendors-DQA4Hw9v.js +0 -7
  389. package/dist/web/assets/vue-vendor-B5RqjEjQ.js +0 -45
  390. package/src/config/model-pricing.js +0 -35
  391. package/src/server/api/channels.js +0 -439
  392. package/src/server/api/claude-hooks.js +0 -56
  393. package/src/server/api/claude-statistics.js +0 -57
  394. package/src/server/api/codex-channels.js +0 -491
  395. package/src/server/api/codex-projects.js +0 -117
  396. package/src/server/api/codex-proxy.js +0 -293
  397. package/src/server/api/codex-sessions.js +0 -652
  398. package/src/server/api/codex-statistics.js +0 -57
  399. package/src/server/api/gemini-channels.js +0 -392
  400. package/src/server/api/gemini-projects.js +0 -103
  401. package/src/server/api/gemini-proxy.js +0 -231
  402. package/src/server/api/gemini-sessions.js +0 -550
  403. package/src/server/api/gemini-statistics.js +0 -57
  404. package/src/server/api/health-check.js +0 -31
  405. package/src/server/api/oauth-credentials.js +0 -198
  406. package/src/server/api/omp-channels.js +0 -575
  407. package/src/server/api/omp-projects.js +0 -88
  408. package/src/server/api/omp-proxy.js +0 -125
  409. package/src/server/api/omp-sessions.js +0 -386
  410. package/src/server/api/omp-statistics.js +0 -40
  411. package/src/server/api/opencode-channels.js +0 -471
  412. package/src/server/api/opencode-projects.js +0 -110
  413. package/src/server/api/opencode-proxy.js +0 -354
  414. package/src/server/api/opencode-sessions.js +0 -466
  415. package/src/server/api/opencode-statistics.js +0 -57
  416. package/src/server/api/projects.js +0 -120
  417. package/src/server/api/proxy.js +0 -330
  418. package/src/server/api/sessions.js +0 -810
  419. package/src/server/services/oauth-credentials-service.js +0 -945
  420. package/src/server/services/omp-session-log-observer.js +0 -138
  421. package/src/server/services/opencode-gateway-adapters.js +0 -43
  422. package/src/server/services/project-snapshots.js +0 -59
  423. package/src/server/services/proxy-log-helper.js +0 -298
  424. package/src/server/services/session-cache.js +0 -127
  425. package/src/server/services/session-converter.js +0 -582
  426. package/src/server/services/session-history-adapters/claude.js +0 -235
  427. /package/src/{server/services/claude-token-recovery.js → platforms/drivers/claude/token-recovery.js} +0 -0
  428. /package/src/{server/services/codex-parser.js → platforms/drivers/codex/parser.js} +0 -0
  429. /package/src/{server/services/codex-speed-test-template.json → platforms/drivers/codex/speed-test-template.json} +0 -0
  430. /package/src/{server/services/codex-wire.js → platforms/drivers/codex/wire.js} +0 -0
  431. /package/src/{server/services/omp-auth-gateway-client.js → platforms/drivers/omp/auth-gateway-client.js} +0 -0
  432. /package/src/{server/services/opencode-normalization.js → platforms/drivers/opencode/normalization.js} +0 -0
  433. /package/src/{server/services → shared}/config-artifact-paths.js +0 -0
  434. /package/src/{server/services/base → shared}/proxy-utils.js +0 -0
@@ -2,7 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const crypto = require('crypto');
4
4
  const { DatabaseSync } = require('node:sqlite');
5
- const { NATIVE_PATHS, PATHS } = require('../../config/paths');
5
+ const { NATIVE_PATHS, PATHS } = require('../../../config/paths');
6
6
 
7
7
  /**
8
8
  * OpenCode 会话服务
@@ -11,14 +11,35 @@ const { NATIVE_PATHS, PATHS } = require('../../config/paths');
11
11
 
12
12
  const PROJECT_ORDER_FILE = PATHS.opencodeProjectOrder;
13
13
  const SESSION_ORDER_FILE = PATHS.opencodeSessionOrder;
14
- const OPENCODE_DB_PATH = path.join(NATIVE_PATHS.opencode.data, 'opencode.db');
15
- const COUNTS_CACHE_TTL_MS = 30 * 1000;
16
- const EMPTY_COUNTS = Object.freeze({ projectCount: 0, sessionCount: 0 });
14
+ let opencodeDataDirOverride = null;
17
15
 
18
- let countsCache = {
19
- expiresAt: 0,
20
- value: EMPTY_COUNTS
21
- };
16
+ function configure({ pathContext } = {}) {
17
+ opencodeDataDirOverride = pathContext?.customized
18
+ ? (pathContext.native?.data || null)
19
+ : null;
20
+ }
21
+
22
+ function getOpenCodeDbPath(dataDir = opencodeDataDirOverride || NATIVE_PATHS.opencode.data) {
23
+ const configuredPath = typeof process.env.OPENCODE_DB_PATH === 'string'
24
+ ? process.env.OPENCODE_DB_PATH.trim()
25
+ : '';
26
+ if (configuredPath && fs.existsSync(configuredPath)) return configuredPath;
27
+
28
+ const defaultPath = path.join(dataDir, 'opencode.db');
29
+ if (fs.existsSync(defaultPath)) return defaultPath;
30
+
31
+ try {
32
+ return fs.readdirSync(dataDir, { withFileTypes: true })
33
+ .filter(entry => entry.isFile() && /^opencode-.*\.db$/.test(entry.name))
34
+ .map(entry => {
35
+ const filePath = path.join(dataDir, entry.name);
36
+ return { filePath, mtimeMs: fs.statSync(filePath).mtimeMs };
37
+ })
38
+ .sort((a, b) => b.mtimeMs - a.mtimeMs)[0]?.filePath || defaultPath;
39
+ } catch (_) {
40
+ return defaultPath;
41
+ }
42
+ }
22
43
 
23
44
  function ensureParentDir(filePath) {
24
45
  const dir = path.dirname(filePath);
@@ -71,6 +92,48 @@ function parseJsonMaybe(raw, fallback = null) {
71
92
  }
72
93
  }
73
94
 
95
+ function isAbsolutePath(value) {
96
+ return typeof value === 'string' && (
97
+ path.isAbsolute(value)
98
+ || /^[a-zA-Z]:[\\/]/.test(value)
99
+ || value.startsWith('\\\\')
100
+ );
101
+ }
102
+
103
+ function getEmbeddedProjectMetadata(directory) {
104
+ if (!isAbsolutePath(directory)) return null;
105
+
106
+ const projectDirectory = path.normalize(directory);
107
+ const projectsDirectory = path.dirname(projectDirectory);
108
+ if (path.basename(projectsDirectory) !== 'projects') return null;
109
+
110
+ const hostDataDirectory = path.dirname(projectsDirectory);
111
+ const hostDatabasePath = path.join(hostDataDirectory, 'app.sqlite');
112
+ if (!fs.existsSync(hostDatabasePath)) return null;
113
+
114
+ let hostDb;
115
+ try {
116
+ hostDb = new DatabaseSync(hostDatabasePath, { readOnly: true, timeout: 1000 });
117
+ const project = hostDb.prepare(
118
+ 'SELECT name, metadata_json FROM projects WHERE id = ? LIMIT 1'
119
+ ).get(path.basename(projectDirectory));
120
+ if (!project) return null;
121
+
122
+ const metadata = parseJsonMaybe(project.metadata_json, {});
123
+ const linkedDirs = Array.isArray(metadata?.linkedDirs) ? metadata.linkedDirs : [];
124
+ const fullPath = linkedDirs.find(isAbsolutePath) || '';
125
+ const displayName = typeof project.name === 'string' && project.name.trim()
126
+ ? project.name.trim()
127
+ : (fullPath ? path.basename(fullPath) : path.basename(projectDirectory));
128
+
129
+ return { displayName, fullPath };
130
+ } catch (_) {
131
+ return null;
132
+ } finally {
133
+ try { hostDb?.close(); } catch (_) {}
134
+ }
135
+ }
136
+
74
137
  function extractTextContent(content) {
75
138
  if (typeof content === 'string') {
76
139
  return content;
@@ -152,7 +215,7 @@ function toIsoTime(input) {
152
215
 
153
216
  function _openCodeDb() {
154
217
  if (!isOpenCodeInstalled()) return null;
155
- const db = new DatabaseSync(OPENCODE_DB_PATH, { readOnly: false, timeout: 5000 });
218
+ const db = new DatabaseSync(getOpenCodeDbPath(), { readOnly: false, timeout: 5000 });
156
219
  db.exec('PRAGMA foreign_keys = ON');
157
220
  return db;
158
221
  }
@@ -193,12 +256,9 @@ function buildContext(text, keyword, contextLength = 35) {
193
256
 
194
257
  // 检查 OpenCode 是否安装
195
258
  function isOpenCodeInstalled() {
196
- return fs.existsSync(OPENCODE_DB_PATH);
259
+ return fs.existsSync(getOpenCodeDbPath());
197
260
  }
198
261
 
199
- function invalidateProjectAndSessionCountsCache() {
200
- countsCache = { expiresAt: 0, value: EMPTY_COUNTS };
201
- }
202
262
 
203
263
  // ---------------------------------------------------------------------------
204
264
  // Project / session order (file-based)
@@ -239,6 +299,9 @@ function removeSessionFromOrder(projectId, sessionId) {
239
299
 
240
300
  function getProjectDisplayName(project) {
241
301
  if (!project) return 'Unknown';
302
+ if (typeof project.name === 'string' && project.name.trim()) {
303
+ return project.name.trim();
304
+ }
242
305
  const worktree = project.worktree || '';
243
306
  if (worktree) {
244
307
  const parsed = parseJsonMaybe(project.data);
@@ -250,6 +313,14 @@ function getProjectDisplayName(project) {
250
313
  return project.id || 'Unknown';
251
314
  }
252
315
 
316
+ function getDisplayNameForPath(projectPath, fallback) {
317
+ if (typeof projectPath === 'string' && projectPath.trim() && projectPath !== '/') {
318
+ const name = path.basename(projectPath);
319
+ if (name) return name;
320
+ }
321
+ return fallback;
322
+ }
323
+
253
324
  function getSessionLocation(sessionId) {
254
325
  const row = getSessionRowById(sessionId);
255
326
  if (!row) return null;
@@ -260,24 +331,15 @@ function getSessionLocation(sessionId) {
260
331
  // Database query functions (parameterized)
261
332
  // ---------------------------------------------------------------------------
262
333
 
263
- function queryProjectAndSessionCounts() {
264
- const rows = _query(`
265
- SELECT
266
- (SELECT COUNT(*) FROM project) AS project_count,
267
- (SELECT COUNT(*) FROM session WHERE time_archived IS NULL) AS session_count
268
- `);
269
- return rows.length > 0 ? rows[0] : { project_count: 0, session_count: 0 };
270
- }
271
334
 
272
335
  function getProjectRows() {
273
336
  return _query(`
274
337
  SELECT
275
- p.id,
276
- p.worktree,
277
- p.time_created,
278
- p.time_updated,
279
- p.time_archived,
280
- p.data
338
+ p.*,
339
+ (SELECT s.directory FROM session s
340
+ WHERE s.project_id = p.id AND s.time_archived IS NULL
341
+ ORDER BY s.time_updated DESC LIMIT 1) AS session_directory,
342
+ (SELECT COUNT(*) FROM session s WHERE s.project_id = p.id AND s.time_archived IS NULL) AS session_count
281
343
  FROM project p
282
344
  ORDER BY p.time_updated DESC
283
345
  `);
@@ -303,7 +365,22 @@ function getSessionRowsByProjectId(projectId) {
303
365
  s.time_created,
304
366
  s.time_updated,
305
367
  s.time_compacting,
306
- s.time_archived
368
+ s.time_archived,
369
+ (
370
+ COALESCE((
371
+ SELECT SUM(LENGTH(CAST(m.data AS BLOB)))
372
+ FROM message m
373
+ WHERE m.session_id = s.id
374
+ ), 0)
375
+ + COALESCE((
376
+ SELECT SUM(LENGTH(CAST(p.data AS BLOB)))
377
+ FROM part p
378
+ WHERE p.session_id = s.id
379
+ ), 0)
380
+ + COALESCE(LENGTH(CAST(s.title AS BLOB)), 0)
381
+ + COALESCE(LENGTH(CAST(s.slug AS BLOB)), 0)
382
+ + COALESCE(LENGTH(CAST(s.directory AS BLOB)), 0)
383
+ ) AS storage_size
307
384
  FROM session s
308
385
  WHERE s.project_id = ?
309
386
  AND s.time_archived IS NULL
@@ -331,7 +408,22 @@ function getSessionRowById(sessionId) {
331
408
  s.time_created,
332
409
  s.time_updated,
333
410
  s.time_compacting,
334
- s.time_archived
411
+ s.time_archived,
412
+ (
413
+ COALESCE((
414
+ SELECT SUM(LENGTH(CAST(m.data AS BLOB)))
415
+ FROM message m
416
+ WHERE m.session_id = s.id
417
+ ), 0)
418
+ + COALESCE((
419
+ SELECT SUM(LENGTH(CAST(p.data AS BLOB)))
420
+ FROM part p
421
+ WHERE p.session_id = s.id
422
+ ), 0)
423
+ + COALESCE(LENGTH(CAST(s.title AS BLOB)), 0)
424
+ + COALESCE(LENGTH(CAST(s.slug AS BLOB)), 0)
425
+ + COALESCE(LENGTH(CAST(s.directory AS BLOB)), 0)
426
+ ) AS storage_size
335
427
  FROM session s
336
428
  WHERE s.id = ?
337
429
  LIMIT 1
@@ -372,7 +464,8 @@ function normalizeSession(session, projectId) {
372
464
  return {
373
465
  sessionId: session.id,
374
466
  mtime: toIsoTime(session.time_updated) || new Date().toISOString(),
375
- size: 0, // SQLite doesn't track file size natively
467
+ // SQLite has no per-session file, so use the UTF-8 size of its stored payloads.
468
+ size: Number(session.storage_size) || 0,
376
469
  filePath: `opencode://${projectId}/${session.id}`,
377
470
  gitBranch: null,
378
471
  firstMessage: session.title || null,
@@ -392,15 +485,26 @@ function normalizeSession(session, projectId) {
392
485
  // ---------------------------------------------------------------------------
393
486
 
394
487
  function getProjects(_options = {}) {
395
- const projects = getProjectRows().map((project) => ({
396
- name: project.id,
397
- displayName: getProjectDisplayName(project),
398
- fullPath: project.worktree || '/',
399
- path: project.worktree || '/',
400
- sessionCount: 0,
401
- lastUsed: toIsoTime(project.time_updated),
402
- source: 'opencode'
403
- }));
488
+ const projects = getProjectRows().map((project) => {
489
+ const fallbackPath = project.worktree && project.worktree !== '/'
490
+ ? project.worktree
491
+ : project.session_directory || project.worktree || '/';
492
+ const embeddedProject = getEmbeddedProjectMetadata(fallbackPath);
493
+ const fullPath = embeddedProject?.fullPath || fallbackPath;
494
+ const fallbackDisplayName = embeddedProject?.displayName
495
+ || getProjectDisplayName({ ...project, worktree: fullPath });
496
+ return {
497
+ name: project.id,
498
+ displayName: embeddedProject?.fullPath
499
+ ? getDisplayNameForPath(fullPath, fallbackDisplayName)
500
+ : fallbackDisplayName,
501
+ fullPath,
502
+ path: fullPath,
503
+ sessionCount: Number(project.session_count) || 0,
504
+ lastUsed: toIsoTime(project.time_updated),
505
+ source: 'opencode'
506
+ };
507
+ });
404
508
 
405
509
  const order = getProjectOrder();
406
510
  return sortByOrder(projects, order, (a, b) => (b.lastUsed || '').localeCompare(a.lastUsed || ''));
@@ -446,7 +550,8 @@ function searchSessions(keyword) {
446
550
 
447
551
  if (data && data.role === 'user') {
448
552
  text = extractTextFromMessageData(data);
449
- } else {
553
+ }
554
+ if (!text) {
450
555
  const messageParts = partsByMessageId.get(message.id) || [];
451
556
  for (const part of messageParts) {
452
557
  const partData = parseJsonMaybe(part.data, null);
@@ -509,7 +614,7 @@ function getSessionById(sessionId) {
509
614
  return {
510
615
  sessionId,
511
616
  mtime: toIsoTime(location.sessionData.time_updated) || new Date().toISOString(),
512
- size: 0,
617
+ size: Number(location.sessionData.storage_size) || 0,
513
618
  filePath: `opencode://${location.projectId}/${sessionId}`,
514
619
  source: 'opencode',
515
620
  directory: location.directory || null,
@@ -518,6 +623,56 @@ function getSessionById(sessionId) {
518
623
  };
519
624
  }
520
625
 
626
+ function getSessionStatus(sessionId) {
627
+ const session = getSessionById(sessionId);
628
+ if (!session) return null;
629
+ return {
630
+ sessionId,
631
+ lastModified: Date.parse(session.mtime) || null,
632
+ size: session.size || 0,
633
+ filePath: session.filePath
634
+ };
635
+ }
636
+
637
+ function getSessionMessages(sessionId, options = {}) {
638
+ const session = getSessionById(sessionId);
639
+ if (!session) return null;
640
+ const page = Math.max(1, Number.parseInt(options.page, 10) || 1);
641
+ const limit = Math.max(1, Math.min(200, Number.parseInt(options.limit, 10) || 50));
642
+ const order = String(options.order || 'desc').toLowerCase() === 'asc' ? 'asc' : 'desc';
643
+ const ordered = order === 'asc' ? [...session.messages] : [...session.messages].reverse();
644
+ const offset = (page - 1) * limit;
645
+ return {
646
+ messages: ordered.slice(offset, offset + limit),
647
+ metadata: { sessionId, messageCount: session.messages.length },
648
+ pagination: {
649
+ page,
650
+ limit,
651
+ total: session.messages.length,
652
+ hasMore: offset + limit < session.messages.length
653
+ }
654
+ };
655
+ }
656
+
657
+ function getSessionOutline(sessionId) {
658
+ const session = getSessionById(sessionId);
659
+ if (!session) return null;
660
+ let userMessageNumber = 0;
661
+ return {
662
+ sessionId,
663
+ items: session.messages.flatMap(message => {
664
+ if (message.role !== 'user') return [];
665
+ userMessageNumber += 1;
666
+ const firstLine = String(message.content || '').trim().split(/\r?\n/, 1)[0] || '(空消息)';
667
+ return [{
668
+ userMessageNumber,
669
+ preview: firstLine.length > 42 ? `${firstLine.slice(0, 42)}...` : firstLine,
670
+ timestamp: message.timestamp
671
+ }];
672
+ })
673
+ };
674
+ }
675
+
521
676
  function buildSessionMessages(sessionId) {
522
677
  const messages = getMessageRowsBySessionId(sessionId);
523
678
  const parts = getPartRowsBySessionId(sessionId);
@@ -534,9 +689,8 @@ function buildSessionMessages(sessionId) {
534
689
  const messageParts = partsByMessageId.get(message.id) || [];
535
690
 
536
691
  let content = '';
537
- if (data && data.role === 'user') {
538
- content = extractTextFromMessageData(data);
539
- } else if (messageParts.length > 0) {
692
+ content = extractTextFromMessageData(data);
693
+ if (!content && messageParts.length > 0) {
540
694
  content = messageParts
541
695
  .map(part => {
542
696
  const partData = parseJsonMaybe(part.data, null);
@@ -574,7 +728,7 @@ function deleteSession(sessionId) {
574
728
  );
575
729
 
576
730
  try {
577
- const { deleteAlias } = require('./alias');
731
+ const { deleteAlias } = require('../../../server/services/alias');
578
732
  deleteAlias(sessionId);
579
733
  } catch (err) {
580
734
  // ignore alias cleanup errors
@@ -583,7 +737,7 @@ function deleteSession(sessionId) {
583
737
  removeSessionFromOrder(location.projectId, sessionId);
584
738
 
585
739
  try {
586
- const { getForkRelations, saveForkRelations } = require('./sessions');
740
+ const { getForkRelations, saveForkRelations } = require('../claude/sessions-implementation');
587
741
  const relations = getForkRelations();
588
742
  delete relations[sessionId];
589
743
  Object.keys(relations).forEach((key) => {
@@ -596,7 +750,6 @@ function deleteSession(sessionId) {
596
750
  // ignore fork relation cleanup errors
597
751
  }
598
752
 
599
- invalidateProjectAndSessionCountsCache();
600
753
  return { success: true, projectName: location.projectId, sessionId };
601
754
  }
602
755
 
@@ -700,7 +853,7 @@ function forkSession(sessionId) {
700
853
  }
701
854
 
702
855
  try {
703
- const { getForkRelations, saveForkRelations } = require('./sessions');
856
+ const { getForkRelations, saveForkRelations } = require('../claude/sessions-implementation');
704
857
  const relations = getForkRelations();
705
858
  relations[newSessionId] = sessionId;
706
859
  saveForkRelations(relations);
@@ -708,7 +861,6 @@ function forkSession(sessionId) {
708
861
  // ignore
709
862
  }
710
863
 
711
- invalidateProjectAndSessionCountsCache();
712
864
  return { success: true, sessionId: newSessionId, forkedFrom: sessionId };
713
865
  }
714
866
 
@@ -730,7 +882,7 @@ function deleteProject(projectId) {
730
882
  const deletedSessionIds = sessionRows.map(row => row.id);
731
883
 
732
884
  try {
733
- const { deleteAlias } = require('./alias');
885
+ const { deleteAlias } = require('../../../server/services/alias');
734
886
  deletedSessionIds.forEach(id => {
735
887
  try { deleteAlias(id); } catch (_) {}
736
888
  });
@@ -739,32 +891,27 @@ function deleteProject(projectId) {
739
891
  _exec(`DELETE FROM project WHERE id = ?`, projectId);
740
892
 
741
893
  removeProjectFromOrder(projectId);
742
- invalidateProjectAndSessionCountsCache();
743
894
  return { success: true, projectId, deletedSessions: deletedSessionIds.length };
744
895
  }
745
896
 
746
897
  function getProjectAndSessionCounts(options = {}) {
747
- if (options.force) {
748
- invalidateProjectAndSessionCountsCache();
749
- } else if (countsCache.expiresAt > Date.now()) {
750
- return countsCache.value;
751
- }
752
-
753
- const row = queryProjectAndSessionCounts();
754
- const result = {
755
- projectCount: Number(row.project_count) || 0,
756
- sessionCount: Number(row.session_count) || 0
898
+ const projects = getProjects(options);
899
+ return {
900
+ projectCount: projects.length,
901
+ sessionCount: projects.reduce((sum, project) => sum + project.sessionCount, 0)
757
902
  };
758
-
759
- countsCache = { expiresAt: Date.now() + COUNTS_CACHE_TTL_MS, value: result };
760
- return result;
761
903
  }
762
904
 
763
905
  module.exports = {
906
+ configure,
907
+ getOpenCodeDbPath,
764
908
  isOpenCodeInstalled,
765
909
  getProjects,
766
910
  getSessionsByProjectId,
767
911
  getSessionById,
912
+ getSessionStatus,
913
+ getSessionMessages,
914
+ getSessionOutline,
768
915
  searchSessions,
769
916
  getRecentSessions,
770
917
  deleteSession,
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ const { createCapabilityDriver } = require('../../../shared/capability-driver');
4
+
5
+ function createDriver(context = {}) {
6
+ return createCapabilityDriver({
7
+ ...context,
8
+ platform: 'opencode',
9
+ capability: 'sessions',
10
+ servicePath: './opencode/sessions-implementation',
11
+ localServicePath: '../platforms/drivers/opencode/sessions-implementation',
12
+ methods: {
13
+ getProjects: 'getProjects',
14
+ recent: 'getRecentSessions',
15
+ search: 'searchSessions',
16
+ getSessionById: 'getSessionById',
17
+ delete: 'deleteSession',
18
+ fork: 'forkSession',
19
+ saveSessionOrder: 'saveSessionOrder',
20
+ status: 'getSessionStatus',
21
+ outline: 'getSessionOutline',
22
+ isAvailable: 'isOpenCodeInstalled'
23
+ },
24
+ customMethods: {
25
+ listSessions: (service, ...args) => {
26
+ const method = service.getSessionsByProjectId || service.getSessionsByProject;
27
+ if (typeof method !== 'function') return undefined;
28
+ return method.apply(service, args);
29
+ },
30
+ messages: (service, sessionId, options) => {
31
+ if (typeof service.getSessionMessages === 'function') {
32
+ return service.getSessionMessages(sessionId, options);
33
+ }
34
+ const session = typeof service.getSessionById === 'function'
35
+ ? service.getSessionById(sessionId)
36
+ : null;
37
+ return session?.messages || [];
38
+ }
39
+ },
40
+ onSuccess: operation => {
41
+ if (['delete', 'fork', 'saveSessionOrder'].includes(operation)) {
42
+ context.sessionHistoryIndex?.invalidateSource('opencode');
43
+ }
44
+ }
45
+ });
46
+ }
47
+
48
+ module.exports = { createDriver };
@@ -3,8 +3,8 @@ const {
3
3
  getStatistics: getSharedStatistics,
4
4
  getDailyStatistics: getSharedDailyStatistics,
5
5
  getTodayStatistics: getSharedTodayStatistics
6
- } = require('./statistics-service');
7
- const { normalizeUsageTokens, toNumber } = require('./proxy-log-helper');
6
+ } = require('../../../server/services/statistics-service');
7
+ const { normalizeUsageTokens, toNumber } = require('../../../server/services/usage-log-utils');
8
8
 
9
9
  const TOOL_TYPE = 'opencode';
10
10
 
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+
3
+ const { createCapabilityDriver } = require('../../../shared/capability-driver');
4
+
5
+ function createDriver(context = {}) {
6
+ return createCapabilityDriver({
7
+ ...context,
8
+ platform: 'opencode',
9
+ capability: 'statistics',
10
+ servicePath: './opencode/statistics-implementation',
11
+ localServicePath: '../opencode/statistics-implementation',
12
+ methods: {"getStatistics":"getStatistics","getDailyStatistics":"getDailyStatistics","getTodayStatistics":"getTodayStatistics","recordRequest":"recordRequest","resetStatistics":"resetStatistics"}
13
+ });
14
+ }
15
+
16
+ module.exports = { createDriver };