coding-tool-x 3.8.3 → 3.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +86 -15
  3. package/dist/web/assets/AgentsDrawer-BG6P3DX-.js +1 -0
  4. package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
  5. package/dist/web/assets/Analytics--z_FmL5P.js +1 -0
  6. package/dist/web/assets/Analytics-CyHhR126.css +1 -0
  7. package/dist/web/assets/AssetPathField-CrJtRKHy.js +1 -0
  8. package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
  9. package/dist/web/assets/ChatHistoryDrawer-BiuEryJj.js +1 -0
  10. package/dist/web/assets/CollapseItem-BAYEsL_Q.js +1 -0
  11. package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
  12. package/dist/web/assets/CommandsDrawer-YJ-U7BXN.js +1 -0
  13. package/dist/web/assets/ConfigExportDrawer-Ce_hAknW.js +1 -0
  14. package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
  15. package/dist/web/assets/ConfigTemplates-Bvr1NN6K.js +1 -0
  16. package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
  17. package/dist/web/assets/ConfigTemplatesDrawer-BjIeHfF-.js +1 -0
  18. package/dist/web/assets/ConfigTemplatesPanel-AV00tm_D.js +1 -0
  19. package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +1 -0
  20. package/dist/web/assets/Divider-D28g1gwj.js +1 -0
  21. package/dist/web/assets/DrawerContent-ChXgZ1Xm.js +1 -0
  22. package/dist/web/assets/FavoritesDrawer-CG9eI9Ay.css +1 -0
  23. package/dist/web/assets/FavoritesDrawer-Cz95o4CD.js +1 -0
  24. package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
  25. package/dist/web/assets/GatewayConvertDrawer-DLlbMz27.js +1 -0
  26. package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
  27. package/dist/web/assets/Home-D7CCOFQC.js +1 -0
  28. package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
  29. package/dist/web/assets/MarkdownEditor-rEZ-c72L.js +1 -0
  30. package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
  31. package/dist/web/assets/McpDrawer-DfoCyxU2.js +1 -0
  32. package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
  33. package/dist/web/assets/McpFormDrawer-SKu8HNUR.js +1 -0
  34. package/dist/web/assets/PluginManager-BbeK-3rV.js +1 -0
  35. package/dist/web/assets/PluginsDrawer-CWVJ7yjS.js +1 -0
  36. package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
  37. package/dist/web/assets/PluginsPanel-Cm2N3StG.js +1 -0
  38. package/dist/web/assets/PluginsPanel-D6ZqITcR.css +1 -0
  39. package/dist/web/assets/ProjectList-677RLZ8O.css +1 -0
  40. package/dist/web/assets/ProjectList-CsjnsNPv.js +1 -0
  41. package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
  42. package/dist/web/assets/PromptsDrawer-EGd3djFa.js +1 -0
  43. package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
  44. package/dist/web/assets/RecentSessionsDrawer-D1vtoLAs.js +1 -0
  45. package/dist/web/assets/SessionCard-BgLg49U3.js +1 -0
  46. package/dist/web/assets/SessionCard-aM2NHu6i.css +1 -0
  47. package/dist/web/assets/SessionList-BpYRz1cX.css +1 -0
  48. package/dist/web/assets/SessionList-TRiTklWk.js +1 -0
  49. package/dist/web/assets/SettingsDrawer-d5liXjHq.css +1 -0
  50. package/dist/web/assets/SettingsDrawer-rz2WejGY.js +1 -0
  51. package/dist/web/assets/SkillManager-BTjTUbHq.js +1 -0
  52. package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
  53. package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
  54. package/dist/web/assets/SkillsDrawer-pN0hbkK3.js +1 -0
  55. package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
  56. package/dist/web/assets/SkillsPanel-gmBWEoiF.js +1 -0
  57. package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
  58. package/dist/web/assets/SpeedTestDrawer-DcNzuVJk.js +1 -0
  59. package/dist/web/assets/Upload-v5rV0qTT.js +1 -0
  60. package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
  61. package/dist/web/assets/WorkspaceDrawer-DxmicM4U.js +1 -0
  62. package/dist/web/assets/WorkspaceManager-CJHCjARN.js +1 -0
  63. package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
  64. package/dist/web/assets/WorkspacePanel-D8_Zq-du.js +1 -0
  65. package/dist/web/assets/_plugin-vue_export-helper-BeLZJZij.js +1 -0
  66. package/dist/web/assets/client-UDwXBP9i.js +1 -0
  67. package/dist/web/assets/clipboard-B46yyoz_.js +1 -0
  68. package/dist/web/assets/headers-cf-QapUq.js +1 -0
  69. package/dist/web/assets/icons-B2Vg-IOC.js +1 -0
  70. package/dist/web/assets/index-C0EHRym0.css +1 -0
  71. package/dist/web/assets/index-DnEocV0M.js +2 -0
  72. package/dist/web/assets/light-Cp0t7v32.js +1 -0
  73. package/dist/web/assets/markdown-u082bbtj.js +1 -0
  74. package/dist/web/assets/platforms-CBkB45JP.js +1 -0
  75. package/dist/web/assets/platforms-FTpjxAT6.js +1 -0
  76. package/dist/web/assets/project-config-B2baPzYL.js +1 -0
  77. package/dist/web/assets/sessions-Cmy31slD.js +1 -0
  78. package/dist/web/assets/sessions-yC_oVVh8.js +1 -0
  79. package/dist/web/assets/skill-repo-input-B_fkGlUK.js +1 -0
  80. package/dist/web/assets/use-lock-html-scroll-DXIqmUW4.js +1 -0
  81. package/dist/web/assets/use-message-DoLM8C1C.js +1 -0
  82. package/dist/web/assets/useResponsiveDrawer-B3uojyvV.js +1 -0
  83. package/dist/web/assets/vendors-D0c_0KLP.js +1 -0
  84. package/dist/web/assets/vue-vendor-BqZbbXHA.js +1 -0
  85. package/dist/web/assets/workspaces-mjyPVGS8.js +1 -0
  86. package/dist/web/assets/xml-CgY3RMlX.js +1 -0
  87. package/dist/web/index.html +12 -8
  88. package/docs/native-log-memory-2026-09-16.md +43 -0
  89. package/docs/superpowers/plans/2026-08-26-configuration-driven-cli-platform.md +1578 -0
  90. package/docs/superpowers/plans/2026-08-30-project-scoped-config-control.md +1260 -0
  91. package/docs/superpowers/plans/2026-09-01-omp-skill-refresh-boundary.md +213 -0
  92. package/docs/superpowers/plans/2026-09-01-realtime-logs-panel.md +125 -0
  93. package/docs/superpowers/plans/2026-09-02-config-driven-platform-boundary.md +86 -0
  94. package/docs/superpowers/plans/2026-09-02-platform-implementation-drivers.md +508 -0
  95. package/docs/superpowers/plans/2026-09-03-cli-platform-correctness-boundary.md +760 -0
  96. package/docs/superpowers/plans/2026-09-03-dependency-security-remediation.md +133 -0
  97. package/docs/superpowers/plans/2026-09-04-model-catalog-pricing-sync.md +1078 -0
  98. package/docs/superpowers/plans/2026-09-05-codex-project-scan-500.md +128 -0
  99. package/docs/superpowers/plans/2026-09-06-project-skill-path-fix.md +97 -0
  100. package/docs/superpowers/specs/2026-08-26-configuration-driven-cli-platform-design.md +408 -0
  101. package/docs/superpowers/specs/2026-08-30-project-scoped-config-control-design.md +467 -0
  102. package/docs/superpowers/specs/2026-09-01-claude-session-content-repair-design.md +111 -0
  103. package/docs/superpowers/specs/2026-09-01-omp-skill-refresh-boundary-design.md +83 -0
  104. package/docs/superpowers/specs/2026-09-01-realtime-logs-panel-design.md +27 -0
  105. package/docs/superpowers/specs/2026-09-02-config-driven-platform-boundary-design.md +64 -0
  106. package/docs/superpowers/specs/2026-09-02-platform-implementation-driver-boundary-design.md +123 -0
  107. package/docs/superpowers/specs/2026-09-03-cli-platform-correctness-boundary-design.md +249 -0
  108. package/docs/superpowers/specs/2026-09-03-dependency-security-remediation-design.md +87 -0
  109. package/docs/superpowers/specs/2026-09-04-model-catalog-pricing-sync-design.md +301 -0
  110. package/docs/superpowers/specs/2026-09-05-codex-project-scan-500-design.md +24 -0
  111. package/package.json +13 -8
  112. package/src/commands/channels.js +88 -191
  113. package/src/commands/cli-type.js +19 -11
  114. package/src/commands/daemon.js +94 -32
  115. package/src/commands/doctor.js +16 -9
  116. package/src/commands/export-config.js +23 -5
  117. package/src/commands/list.js +130 -52
  118. package/src/commands/logs.js +44 -27
  119. package/src/commands/platform-command-registry.js +78 -0
  120. package/src/commands/plugin.js +11 -5
  121. package/src/commands/port-config.js +34 -52
  122. package/src/commands/proxy-control.js +207 -145
  123. package/src/commands/proxy.js +2 -2
  124. package/src/commands/resume.js +87 -91
  125. package/src/commands/search.js +137 -67
  126. package/src/commands/stats.js +30 -22
  127. package/src/commands/switch.js +1 -1
  128. package/src/commands/toggle-proxy.js +94 -111
  129. package/src/commands/ui.js +67 -6
  130. package/src/commands/workspace.js +90 -8
  131. package/src/config/default.js +6 -53
  132. package/src/config/loader.js +61 -24
  133. package/src/config/model-metadata.js +49 -59
  134. package/src/config/model-metadata.json +4095 -99
  135. package/src/config/paths.js +181 -8
  136. package/src/index.js +134 -71
  137. package/src/platforms/access.js +196 -0
  138. package/src/{server/services → platforms}/agents-service.js +354 -197
  139. package/src/platforms/channel-auth-registry.js +162 -0
  140. package/src/platforms/channel-auth-service.js +82 -0
  141. package/src/{server/services → platforms}/commands-service.js +195 -115
  142. package/src/platforms/driver-registry.js +59 -0
  143. package/src/platforms/drivers/claude/api-operations.js +62 -0
  144. package/src/{server/services/channels.js → platforms/drivers/claude/channels-implementation.js} +131 -33
  145. package/src/platforms/drivers/claude/channels.js +39 -0
  146. package/src/{server/services/config-sync-service.js → platforms/drivers/claude/config-sync.js} +29 -5
  147. package/src/{server/services → platforms/drivers/claude}/health-check.js +4 -4
  148. package/src/platforms/drivers/claude/health.js +22 -0
  149. package/src/platforms/drivers/claude/mcp.js +9 -0
  150. package/src/{server/services/settings-manager.js → platforms/drivers/claude/native-config-implementation.js} +13 -4
  151. package/src/platforms/drivers/claude/native-config.js +46 -0
  152. package/src/platforms/drivers/claude/native-logs.js +72 -0
  153. package/src/{server/services/claude-openai-gateway.js → platforms/drivers/claude/openai-gateway.js} +8 -65
  154. package/src/platforms/drivers/claude/project-config.js +21 -0
  155. package/src/platforms/drivers/claude/projects.js +62 -0
  156. package/src/platforms/drivers/claude/prompts.js +9 -0
  157. package/src/{server/proxy-server.js → platforms/drivers/claude/proxy-implementation.js} +41 -278
  158. package/src/platforms/drivers/claude/proxy.js +16 -0
  159. package/src/platforms/drivers/claude/resource-sync.js +9 -0
  160. package/src/platforms/drivers/claude/session-history-adapter.js +313 -0
  161. package/src/{server/services/sessions.js → platforms/drivers/claude/sessions-implementation.js} +145 -35
  162. package/src/platforms/drivers/claude/sessions.js +76 -0
  163. package/src/{server/services/claude-statistics-service.js → platforms/drivers/claude/statistics-implementation.js} +2 -2
  164. package/src/platforms/drivers/claude/statistics.js +16 -0
  165. package/src/{server/services/claude-wire.js → platforms/drivers/claude/wire.js} +1 -1
  166. package/src/platforms/drivers/codex/api-operations.js +9 -0
  167. package/src/{server/services/codex-channels.js → platforms/drivers/codex/channels-implementation.js} +149 -14
  168. package/src/platforms/drivers/codex/channels.js +45 -0
  169. package/src/{server/services/codex-config.js → platforms/drivers/codex/config.js} +12 -2
  170. package/src/{server/services/codex-env-manager.js → platforms/drivers/codex/env-manager.js} +1 -1
  171. package/src/platforms/drivers/codex/mcp.js +9 -0
  172. package/src/{server/services/codex-settings-manager.js → platforms/drivers/codex/native-config-implementation.js} +15 -6
  173. package/src/platforms/drivers/codex/native-config.js +47 -0
  174. package/src/platforms/drivers/codex/native-logs.js +166 -0
  175. package/src/platforms/drivers/codex/project-config.js +21 -0
  176. package/src/platforms/drivers/codex/projects.js +26 -0
  177. package/src/platforms/drivers/codex/prompts.js +9 -0
  178. package/src/{server/codex-proxy-server.js → platforms/drivers/codex/proxy-implementation.js} +30 -233
  179. package/src/platforms/drivers/codex/proxy.js +16 -0
  180. package/src/platforms/drivers/codex/resource-sync.js +9 -0
  181. package/src/{server/services/session-history-adapters/codex.js → platforms/drivers/codex/session-history-adapter.js} +37 -23
  182. package/src/{server/services/codex-sessions.js → platforms/drivers/codex/sessions-implementation.js} +81 -75
  183. package/src/platforms/drivers/codex/sessions.js +36 -0
  184. package/src/{server/services/codex-statistics-service.js → platforms/drivers/codex/statistics-implementation.js} +2 -2
  185. package/src/platforms/drivers/codex/statistics.js +16 -0
  186. package/src/platforms/drivers/gemini/api-operations.js +9 -0
  187. package/src/{server/services/gemini-channels.js → platforms/drivers/gemini/channels-implementation.js} +202 -37
  188. package/src/platforms/drivers/gemini/channels.js +39 -0
  189. package/src/{server/services/gemini-config.js → platforms/drivers/gemini/config.js} +12 -2
  190. package/src/platforms/drivers/gemini/mcp.js +9 -0
  191. package/src/{server/services/gemini-settings-manager.js → platforms/drivers/gemini/native-config-implementation.js} +14 -5
  192. package/src/platforms/drivers/gemini/native-config.js +39 -0
  193. package/src/platforms/drivers/gemini/native-logs.js +180 -0
  194. package/src/platforms/drivers/gemini/project-config.js +21 -0
  195. package/src/platforms/drivers/gemini/projects.js +26 -0
  196. package/src/platforms/drivers/gemini/prompts.js +9 -0
  197. package/src/{server/gemini-proxy-server.js → platforms/drivers/gemini/proxy-implementation.js} +36 -267
  198. package/src/platforms/drivers/gemini/proxy.js +16 -0
  199. package/src/platforms/drivers/gemini/resource-sync.js +9 -0
  200. package/src/{server/services/session-history-adapters/gemini.js → platforms/drivers/gemini/session-history-adapter.js} +70 -18
  201. package/src/{server/services/gemini-sessions.js → platforms/drivers/gemini/sessions-implementation.js} +53 -37
  202. package/src/platforms/drivers/gemini/sessions.js +47 -0
  203. package/src/{server/services/gemini-statistics-service.js → platforms/drivers/gemini/statistics-implementation.js} +2 -2
  204. package/src/platforms/drivers/gemini/statistics.js +16 -0
  205. package/src/{server/services/gemini-wire.js → platforms/drivers/gemini/wire.js} +1 -1
  206. package/src/platforms/drivers/generic-filesystem.js +166 -0
  207. package/src/platforms/drivers/generic-jsonl.js +141 -0
  208. package/src/platforms/drivers/generic-mcp.js +44 -0
  209. package/src/platforms/drivers/generic-openai-compatible.js +45 -0
  210. package/src/platforms/drivers/generic-prompt.js +41 -0
  211. package/src/platforms/drivers/legacy.js +677 -0
  212. package/src/platforms/drivers/native-config-snapshot.js +125 -0
  213. package/src/platforms/drivers/native-log-utils.js +1292 -0
  214. package/src/platforms/drivers/notification-hooks.js +578 -0
  215. package/src/{server/api/omp-config.js → platforms/drivers/omp/api-operations.js} +52 -64
  216. package/src/{server/services/omp-auth-provider-worker.js → platforms/drivers/omp/auth-provider-worker.js} +1 -1
  217. package/src/{server/services/omp-auth-providers.js → platforms/drivers/omp/auth-providers.js} +1 -1
  218. package/src/{server/services/omp-channels.js → platforms/drivers/omp/channels-implementation.js} +166 -39
  219. package/src/platforms/drivers/omp/channels.js +58 -0
  220. package/src/{server/services/omp-config.js → platforms/drivers/omp/config.js} +53 -13
  221. package/src/{server/services/omp-gateway-routing.js → platforms/drivers/omp/gateway-routing.js} +14 -7
  222. package/src/{server/services/omp-gateway.js → platforms/drivers/omp/gateway.js} +4 -262
  223. package/src/platforms/drivers/omp/mcp.js +9 -0
  224. package/src/{server/services/omp-settings-manager.js → platforms/drivers/omp/native-config-implementation.js} +75 -10
  225. package/src/platforms/drivers/omp/native-config.js +46 -0
  226. package/src/platforms/drivers/omp/native-logs.js +52 -0
  227. package/src/{server/services/omp-native-plugin-adapter.js → platforms/drivers/omp/native-plugin-adapter.js} +91 -4
  228. package/src/platforms/drivers/omp/project-config.js +29 -0
  229. package/src/platforms/drivers/omp/projects.js +20 -0
  230. package/src/platforms/drivers/omp/prompts.js +9 -0
  231. package/src/{server/omp-proxy-server.js → platforms/drivers/omp/proxy-implementation.js} +6 -15
  232. package/src/platforms/drivers/omp/proxy.js +16 -0
  233. package/src/platforms/drivers/omp/resource-sync.js +9 -0
  234. package/src/{server/services/session-history-adapters/omp.js → platforms/drivers/omp/session-history-adapter.js} +42 -18
  235. package/src/{server/services/omp-sessions.js → platforms/drivers/omp/sessions-implementation.js} +130 -94
  236. package/src/platforms/drivers/omp/sessions.js +36 -0
  237. package/src/{server/services/omp-skill-discovery.js → platforms/drivers/omp/skill-discovery.js} +159 -32
  238. package/src/{server/services/omp-skill-settings-service.js → platforms/drivers/omp/skill-settings.js} +1 -1
  239. package/src/{server/services/omp-statistics-service.js → platforms/drivers/omp/statistics-implementation.js} +3 -3
  240. package/src/platforms/drivers/omp/statistics.js +16 -0
  241. package/src/platforms/drivers/opencode/api-operations.js +9 -0
  242. package/src/{server/services/opencode-channels.js → platforms/drivers/opencode/channels-implementation.js} +28 -9
  243. package/src/platforms/drivers/opencode/channels.js +40 -0
  244. package/src/platforms/drivers/opencode/conversion.js +41 -0
  245. package/src/{server/services/opencode-gateway-converter.js → platforms/drivers/opencode/gateway-converter.js} +1 -1
  246. package/src/platforms/drivers/opencode/mcp.js +9 -0
  247. package/src/{server/services/opencode-settings-manager.js → platforms/drivers/opencode/native-config-implementation.js} +17 -6
  248. package/src/platforms/drivers/opencode/native-config.js +26 -0
  249. package/src/platforms/drivers/opencode/native-logs.js +133 -0
  250. package/src/platforms/drivers/opencode/project-config.js +98 -0
  251. package/src/platforms/drivers/opencode/projects.js +20 -0
  252. package/src/platforms/drivers/opencode/prompts.js +9 -0
  253. package/src/{server/opencode-proxy-server.js → platforms/drivers/opencode/proxy-implementation.js} +27 -362
  254. package/src/platforms/drivers/opencode/proxy.js +16 -0
  255. package/src/platforms/drivers/opencode/resource-sync.js +9 -0
  256. package/src/{server/services/opencode-sessions.js → platforms/drivers/opencode/sessions-implementation.js} +211 -64
  257. package/src/platforms/drivers/opencode/sessions.js +48 -0
  258. package/src/{server/services/opencode-statistics-service.js → platforms/drivers/opencode/statistics-implementation.js} +2 -2
  259. package/src/platforms/drivers/opencode/statistics.js +16 -0
  260. package/src/platforms/drivers/secure-file-driver.js +272 -0
  261. package/src/platforms/drivers/unsupported.js +7 -0
  262. package/src/platforms/manifest-schema.js +398 -0
  263. package/src/platforms/manifests/claude.json +489 -0
  264. package/src/platforms/manifests/codex.json +448 -0
  265. package/src/platforms/manifests/gemini.json +447 -0
  266. package/src/platforms/manifests/omp.json +496 -0
  267. package/src/platforms/manifests/opencode.json +422 -0
  268. package/src/{server/services → platforms}/native-oauth-adapters.js +87 -417
  269. package/src/{server/services → platforms}/notification-hooks.js +140 -1023
  270. package/src/platforms/oauth-credentials-service.js +506 -0
  271. package/src/platforms/path-resolver.js +179 -0
  272. package/src/platforms/platform-path-context.js +305 -0
  273. package/src/platforms/registry.js +248 -0
  274. package/src/platforms/remote-notification-providers.js +678 -0
  275. package/src/platforms/runtime.js +259 -0
  276. package/src/{server/services/session-history-adapters/index.js → platforms/session-history-adapters.js} +8 -1
  277. package/src/plugins/plugin-loader.js +2 -2
  278. package/src/plugins/plugin-manager.js +2 -2
  279. package/src/plugins/registry.js +27 -10
  280. package/src/reset-config.js +21 -5
  281. package/src/server/api/agents.js +46 -72
  282. package/src/server/api/commands.js +16 -6
  283. package/src/server/api/config-registry.js +206 -59
  284. package/src/server/api/config-sync.js +3 -2
  285. package/src/server/api/config-templates.js +20 -4
  286. package/src/server/api/config.js +111 -102
  287. package/src/server/api/convert.js +54 -178
  288. package/src/server/api/dashboard.js +168 -102
  289. package/src/server/api/hooks.js +1 -1
  290. package/src/server/api/mcp.js +224 -84
  291. package/src/server/api/platform-api-config.js +102 -0
  292. package/src/server/api/platform-route-factory.js +215 -0
  293. package/src/server/api/platform-routes.js +26 -0
  294. package/src/server/api/platforms.js +110 -0
  295. package/src/server/api/plugins.js +57 -57
  296. package/src/server/api/project-config.js +168 -0
  297. package/src/server/api/prompts.js +58 -45
  298. package/src/server/api/settings.js +55 -8
  299. package/src/server/api/skills.js +262 -133
  300. package/src/server/api/ui-config.js +2 -2
  301. package/src/server/api/validation-errors.js +18 -4
  302. package/src/server/api/workspaces.js +47 -12
  303. package/src/server/index.js +164 -213
  304. package/src/server/platform-context.js +81 -0
  305. package/src/server/services/channel-balance.js +11 -20
  306. package/src/server/services/channel-health.js +21 -6
  307. package/src/server/services/channel-scheduler.js +29 -39
  308. package/src/server/services/channel-sync-utils.js +23 -13
  309. package/src/server/services/config-export-service.js +350 -319
  310. package/src/server/services/config-registry-service.js +280 -54
  311. package/src/server/services/config-sync-manager.js +172 -944
  312. package/src/server/services/config-templates-service.js +419 -353
  313. package/src/server/services/control-manifest-store.js +206 -0
  314. package/src/server/services/dashboard-snapshot-worker.js +656 -100
  315. package/src/server/services/effective-control-service.js +557 -0
  316. package/src/server/services/local-resource-index.js +314 -0
  317. package/src/server/services/mcp-service.js +607 -977
  318. package/src/server/services/model-detector.js +15 -10
  319. package/src/server/services/native-log-channel-resolver.js +214 -0
  320. package/src/server/services/native-log-observer.js +291 -0
  321. package/src/server/services/network-access.js +1 -1
  322. package/src/server/services/platform-catalog.js +82 -0
  323. package/src/server/services/platform-resolution.js +32 -29
  324. package/src/server/services/plugins-service.js +376 -122
  325. package/src/server/services/project-config-service.js +550 -0
  326. package/src/server/services/project-path-validation.js +31 -0
  327. package/src/server/services/prompts-service.js +267 -233
  328. package/src/server/services/proxy-runtime.js +7 -4
  329. package/src/server/services/remote-credential-cache.js +43 -0
  330. package/src/server/services/repo-scanner-base.js +182 -75
  331. package/src/server/services/request-logger.js +7 -4
  332. package/src/server/services/session-history-index.js +780 -213
  333. package/src/server/services/session-history-worker.js +228 -33
  334. package/src/server/services/session-snapshot-worker.js +124 -34
  335. package/src/server/services/session-snapshots.js +4 -2
  336. package/src/server/services/skill-artifact-store.js +355 -0
  337. package/src/server/services/skill-format-adapters.js +65 -0
  338. package/src/server/services/skill-projection-service.js +323 -0
  339. package/src/server/services/skill-refresh-task-service.js +275 -0
  340. package/src/server/services/skill-service.js +2020 -677
  341. package/src/server/services/snapshot-cache.js +30 -8
  342. package/src/server/services/speed-test.js +8 -8
  343. package/src/server/services/sqlite-connection.js +19 -3
  344. package/src/server/services/statistics-service.js +240 -57
  345. package/src/server/services/ui-config.js +107 -76
  346. package/src/server/services/usage-log-utils.js +98 -0
  347. package/src/server/services/web-build.js +1 -1
  348. package/src/server/services/workspace-service.js +59 -29
  349. package/src/server/utils/pricing.js +10 -19
  350. package/src/server/websocket-server.js +153 -28
  351. package/src/{server/services/base → shared}/base-channel-service.js +156 -28
  352. package/src/shared/capability-driver.js +104 -0
  353. package/src/shared/channel-auth-policy.js +27 -0
  354. package/src/shared/channel-driver.js +161 -0
  355. package/src/shared/driver-factories/api.js +180 -0
  356. package/src/shared/driver-factories/mcp.js +244 -0
  357. package/src/shared/driver-factories/projects.js +121 -0
  358. package/src/shared/driver-factories/prompts.js +58 -0
  359. package/src/shared/driver-factories/resource-sync.js +375 -0
  360. package/src/shared/driver-result.js +78 -0
  361. package/src/shared/mcp-format.js +189 -0
  362. package/src/shared/platforms.js +104 -167
  363. package/src/shared/project-config.js +512 -0
  364. package/src/shared/proxy-driver.js +57 -0
  365. package/src/{server/services/base → shared}/response-usage-parser.js +8 -4
  366. package/src/ui/menu.js +91 -67
  367. package/src/utils/port-helper.js +35 -19
  368. package/src/utils/session.js +1 -1
  369. package/dist/web/assets/Analytics-COEUXmd4.js +0 -25
  370. package/dist/web/assets/Analytics-RNn1BUbG.css +0 -1
  371. package/dist/web/assets/ConfigTemplates-DLLkS53H.js +0 -1
  372. package/dist/web/assets/Home-DCEyLzwX.js +0 -1
  373. package/dist/web/assets/Home-DYVy4cGZ.css +0 -1
  374. package/dist/web/assets/PluginManager-Oe1ZHoMO.js +0 -1
  375. package/dist/web/assets/ProjectList-CWjuAFof.js +0 -1
  376. package/dist/web/assets/ProjectList-VeMNXfgO.css +0 -1
  377. package/dist/web/assets/SessionList-C4chCPxK.css +0 -1
  378. package/dist/web/assets/SessionList-v3ehGg9U.js +0 -1
  379. package/dist/web/assets/SkillManager-BsX8Qpj0.css +0 -1
  380. package/dist/web/assets/SkillManager-DUF_qP5S.js +0 -1
  381. package/dist/web/assets/WorkspaceManager-CjAWBosO.js +0 -1
  382. package/dist/web/assets/icons-nGdSKQn2.js +0 -1
  383. package/dist/web/assets/index-D5hyHPj7.js +0 -2
  384. package/dist/web/assets/index-bJRG3RXH.css +0 -1
  385. package/dist/web/assets/markdown-BNJfEgCA.js +0 -1
  386. package/dist/web/assets/markdown-BfC0goYb.css +0 -10
  387. package/dist/web/assets/naive-ui-BALVpMgd.js +0 -1
  388. package/dist/web/assets/vendors-DQA4Hw9v.js +0 -7
  389. package/dist/web/assets/vue-vendor-B5RqjEjQ.js +0 -45
  390. package/src/config/model-pricing.js +0 -35
  391. package/src/server/api/channels.js +0 -439
  392. package/src/server/api/claude-hooks.js +0 -56
  393. package/src/server/api/claude-statistics.js +0 -57
  394. package/src/server/api/codex-channels.js +0 -491
  395. package/src/server/api/codex-projects.js +0 -117
  396. package/src/server/api/codex-proxy.js +0 -293
  397. package/src/server/api/codex-sessions.js +0 -652
  398. package/src/server/api/codex-statistics.js +0 -57
  399. package/src/server/api/gemini-channels.js +0 -392
  400. package/src/server/api/gemini-projects.js +0 -103
  401. package/src/server/api/gemini-proxy.js +0 -231
  402. package/src/server/api/gemini-sessions.js +0 -550
  403. package/src/server/api/gemini-statistics.js +0 -57
  404. package/src/server/api/health-check.js +0 -31
  405. package/src/server/api/oauth-credentials.js +0 -198
  406. package/src/server/api/omp-channels.js +0 -575
  407. package/src/server/api/omp-projects.js +0 -88
  408. package/src/server/api/omp-proxy.js +0 -125
  409. package/src/server/api/omp-sessions.js +0 -386
  410. package/src/server/api/omp-statistics.js +0 -40
  411. package/src/server/api/opencode-channels.js +0 -471
  412. package/src/server/api/opencode-projects.js +0 -110
  413. package/src/server/api/opencode-proxy.js +0 -354
  414. package/src/server/api/opencode-sessions.js +0 -466
  415. package/src/server/api/opencode-statistics.js +0 -57
  416. package/src/server/api/projects.js +0 -120
  417. package/src/server/api/proxy.js +0 -330
  418. package/src/server/api/sessions.js +0 -810
  419. package/src/server/services/oauth-credentials-service.js +0 -945
  420. package/src/server/services/omp-session-log-observer.js +0 -138
  421. package/src/server/services/opencode-gateway-adapters.js +0 -43
  422. package/src/server/services/project-snapshots.js +0 -59
  423. package/src/server/services/proxy-log-helper.js +0 -298
  424. package/src/server/services/session-cache.js +0 -127
  425. package/src/server/services/session-converter.js +0 -582
  426. package/src/server/services/session-history-adapters/claude.js +0 -235
  427. /package/src/{server/services/claude-token-recovery.js → platforms/drivers/claude/token-recovery.js} +0 -0
  428. /package/src/{server/services/codex-parser.js → platforms/drivers/codex/parser.js} +0 -0
  429. /package/src/{server/services/codex-speed-test-template.json → platforms/drivers/codex/speed-test-template.json} +0 -0
  430. /package/src/{server/services/codex-wire.js → platforms/drivers/codex/wire.js} +0 -0
  431. /package/src/{server/services/omp-auth-gateway-client.js → platforms/drivers/omp/auth-gateway-client.js} +0 -0
  432. /package/src/{server/services/opencode-normalization.js → platforms/drivers/opencode/normalization.js} +0 -0
  433. /package/src/{server/services → shared}/config-artifact-paths.js +0 -0
  434. /package/src/{server/services/base → shared}/proxy-utils.js +0 -0
@@ -0,0 +1,313 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const readline = require('readline');
6
+ const { NATIVE_PATHS } = require('../../../config/paths');
7
+
8
+ const DEFAULT_CLAUDE_PROJECTS_DIR = NATIVE_PATHS?.claude?.projects || '';
9
+ let claudeProjectsDir = DEFAULT_CLAUDE_PROJECTS_DIR;
10
+
11
+ function configure({ pathContext } = {}) {
12
+ claudeProjectsDir = pathContext?.customized
13
+ ? (pathContext.native?.projects || DEFAULT_CLAUDE_PROJECTS_DIR)
14
+ : DEFAULT_CLAUDE_PROJECTS_DIR;
15
+ }
16
+
17
+ function _asContentBlocks(content) {
18
+ if (Array.isArray(content)) return content;
19
+ return content && typeof content === 'object' ? [content] : [];
20
+ }
21
+
22
+ function _formatJsonBlock(value, fallback = '') {
23
+ if (typeof value === 'string') return value;
24
+ try {
25
+ const serialized = JSON.stringify(value, null, 2);
26
+ return serialized === undefined ? fallback : serialized;
27
+ } catch (_) {
28
+ return fallback;
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Get Claude user-visible text from a message content block.
34
+ * Shared with sessions.js API for display consistency.
35
+ */
36
+ function getClaudeUserText(content) {
37
+ if (typeof content === 'string') {
38
+ return content === 'Warmup' ? '' : content;
39
+ }
40
+
41
+ const parts = [];
42
+ for (const item of _asContentBlocks(content)) {
43
+ if (item?.type === 'text' && item.text) {
44
+ parts.push(item.text);
45
+ } else if (item?.type === 'image') {
46
+ parts.push('[图片]');
47
+ }
48
+ }
49
+
50
+ return parts.join('\n\n').trim();
51
+ }
52
+
53
+ function getClaudeToolResultText(content) {
54
+ const parts = [];
55
+ for (const item of _asContentBlocks(content)) {
56
+ if (item?.type !== 'tool_result') continue;
57
+ const resultContent = _formatJsonBlock(item.content, '');
58
+ if (resultContent) {
59
+ parts.push(`**[工具结果]**\n\`\`\`\n${resultContent}\n\`\`\``);
60
+ }
61
+ }
62
+ return parts.join('\n\n').trim();
63
+ }
64
+
65
+ function getClaudeAssistantText(content) {
66
+ if (typeof content === 'string') {
67
+ return content === 'Warmup' ? '' : content;
68
+ }
69
+
70
+ const parts = [];
71
+ let subtype = null;
72
+ for (const item of _asContentBlocks(content)) {
73
+ if (item?.type === 'text' && item.text) {
74
+ parts.push(item.text);
75
+ } else if (item?.type === 'image') {
76
+ parts.push('[图片]');
77
+ } else if (item?.type === 'tool_use') {
78
+ subtype = 'tool_use';
79
+ const input = _formatJsonBlock(item.input, '{}');
80
+ parts.push(`**[调用工具: ${item.name || 'unknown'}]**\n\`\`\`json\n${input}\n\`\`\``);
81
+ } else if (item?.type === 'tool_result') {
82
+ subtype = subtype || 'tool_result';
83
+ const resultContent = _formatJsonBlock(item.content, '');
84
+ if (resultContent) {
85
+ parts.push(`**[工具结果]**\n\`\`\`\n${resultContent}\n\`\`\``);
86
+ }
87
+ } else if (item?.type === 'thinking') {
88
+ subtype = subtype || 'thinking';
89
+ if (item.thinking) parts.push(`**[思考]**\n${item.thinking}`);
90
+ }
91
+ }
92
+
93
+ return { content: parts.join('\n\n').trim(), subtype };
94
+ }
95
+
96
+ /**
97
+ * Parse real project path from encoded name.
98
+ */
99
+ function parseRealProjectPath(encodedName, config = {}) {
100
+ const { parseRealProjectPath: fn } = require('./sessions-implementation');
101
+ return fn(encodedName, config);
102
+ }
103
+
104
+ /**
105
+ * Inventory all Claude session files.
106
+ * @returns {Promise<Array<{filePath: string, size: number, mtimeMs: number, sessionId: string, projectHint: string}>>}
107
+ */
108
+ async function inventory({ projectsDir } = {}) {
109
+ const descriptors = [];
110
+ const rootDir = projectsDir || claudeProjectsDir;
111
+
112
+ try {
113
+ await fs.promises.stat(rootDir);
114
+ } catch (_) {
115
+ return descriptors;
116
+ }
117
+
118
+ const projects = await fs.promises.readdir(rootDir, { withFileTypes: true });
119
+ for (const entry of projects) {
120
+ if (!entry.isDirectory()) continue;
121
+ const projectName = entry.name;
122
+ const projectPath = path.join(rootDir, projectName);
123
+
124
+ let files;
125
+ try {
126
+ files = await fs.promises.readdir(projectPath);
127
+ } catch (_) {
128
+ continue;
129
+ }
130
+
131
+ for (const f of files) {
132
+ if (!f.endsWith('.jsonl') || f.startsWith('agent-')) continue;
133
+ const filePath = path.join(projectPath, f);
134
+ let stat;
135
+ try {
136
+ stat = await fs.promises.stat(filePath);
137
+ } catch (_) {
138
+ continue;
139
+ }
140
+ descriptors.push({
141
+ filePath,
142
+ size: stat.size,
143
+ mtimeMs: stat.mtimeMs,
144
+ sessionId: f.replace(/\.jsonl$/, ''),
145
+ projectHint: projectName
146
+ });
147
+ }
148
+ }
149
+
150
+ return descriptors;
151
+ }
152
+
153
+ /**
154
+ * Parse a Claude session file into normalized session + messages.
155
+ * @param {{filePath: string, size: number, mtimeMs: number, sessionId: string, projectHint: string}} descriptor
156
+ * @returns {Promise<{session: object, messages: Array}>}
157
+ */
158
+ async function parse(descriptor) {
159
+ const { filePath, size, mtimeMs, sessionId, projectHint } = descriptor;
160
+ const { fullPath, projectName: displayName } = parseRealProjectPath(projectHint, { projectsDir: descriptor.projectsDir });
161
+
162
+ const messages = [];
163
+ let firstMessage = null;
164
+ let gitBranch = null;
165
+ let provider = null;
166
+ let model = null;
167
+ let startedAt = null;
168
+ let updatedAt = null;
169
+ let usageJson = null;
170
+ const extra = {};
171
+ let userMessageNumber = 0;
172
+
173
+ const stream = fs.createReadStream(filePath, { encoding: 'utf8' });
174
+ const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
175
+
176
+ for await (const line of rl) {
177
+ if (!line.trim()) continue;
178
+
179
+ let json;
180
+ try {
181
+ json = JSON.parse(line);
182
+ } catch (_) {
183
+ continue;
184
+ }
185
+
186
+ const messagePayload = json.message && typeof json.message === 'object' && !Array.isArray(json.message)
187
+ ? json.message
188
+ : {};
189
+ const recordTimestamp = json.timestamp || messagePayload.timestamp || null;
190
+ const timestampValue = recordTimestamp ? new Date(recordTimestamp).getTime() : null;
191
+ const timestamp = Number.isFinite(timestampValue) ? timestampValue : null;
192
+ const recordModel = json.model || messagePayload.model || null;
193
+ const recordProvider = json.provider || messagePayload.provider || null;
194
+ const recordUsage = json.usage || messagePayload.usage || null;
195
+
196
+ if (json.type === 'metadata' || json.type === 'summary') {
197
+ if (json.cwd || messagePayload.cwd) extra.cwd = json.cwd || messagePayload.cwd;
198
+ if (json.gitBranch || messagePayload.gitBranch) {
199
+ gitBranch = json.gitBranch || messagePayload.gitBranch;
200
+ }
201
+ if (json.summary) extra.summary = json.summary;
202
+ if (timestamp !== null && startedAt === null) startedAt = timestamp;
203
+ if (recordModel) model = recordModel;
204
+ if (recordProvider) provider = recordProvider;
205
+ if (recordUsage) usageJson = JSON.stringify(recordUsage);
206
+ continue;
207
+ }
208
+
209
+ const role = json.role
210
+ || messagePayload.role
211
+ || (json.type === 'user' || json.type === 'human'
212
+ ? 'user'
213
+ : json.type === 'assistant' || json.type === 'ai'
214
+ ? 'assistant'
215
+ : null);
216
+ if (role !== 'user' && role !== 'assistant') continue;
217
+
218
+ const rawContent = json.content !== undefined && json.content !== null && json.content !== ''
219
+ ? json.content
220
+ : messagePayload.content !== undefined
221
+ ? messagePayload.content
222
+ : typeof json.message === 'string' ? json.message : '';
223
+ const messageId = messagePayload.id || json.uuid || json.id || null;
224
+
225
+ if (timestamp !== null) {
226
+ if (startedAt === null) startedAt = timestamp;
227
+ updatedAt = timestamp;
228
+ }
229
+ if (recordModel) model = recordModel;
230
+ if (recordProvider) provider = recordProvider;
231
+ if (recordUsage) usageJson = JSON.stringify(recordUsage);
232
+
233
+ if (role === 'user') {
234
+ const content = getClaudeUserText(rawContent);
235
+ if (content) {
236
+ userMessageNumber++;
237
+ if (!firstMessage) firstMessage = content;
238
+ messages.push({
239
+ messageId,
240
+ role,
241
+ type: json.type || role,
242
+ subtype: null,
243
+ content,
244
+ timestamp,
245
+ model: recordModel || model || null,
246
+ provider: recordProvider || provider || null,
247
+ userMessageNumber,
248
+ extraJson: null
249
+ });
250
+ }
251
+
252
+ const toolResultContent = getClaudeToolResultText(rawContent);
253
+ if (toolResultContent) {
254
+ messages.push({
255
+ messageId: messageId ? `${messageId}-tool-result` : null,
256
+ role: 'assistant',
257
+ type: 'assistant',
258
+ subtype: 'tool_result',
259
+ content: toolResultContent,
260
+ timestamp,
261
+ model: recordModel || model || null,
262
+ provider: recordProvider || provider || null,
263
+ userMessageNumber: null,
264
+ extraJson: null
265
+ });
266
+ }
267
+ continue;
268
+ }
269
+
270
+ const assistant = getClaudeAssistantText(rawContent);
271
+ if (!assistant.content) continue;
272
+ messages.push({
273
+ messageId,
274
+ role,
275
+ type: json.type || role,
276
+ subtype: assistant.subtype,
277
+ content: assistant.content,
278
+ timestamp,
279
+ model: recordModel || model || null,
280
+ provider: recordProvider || provider || null,
281
+ userMessageNumber: null,
282
+ extraJson: null
283
+ });
284
+ }
285
+
286
+ rl.close();
287
+ stream.destroy();
288
+
289
+ const session = {
290
+ sessionId,
291
+ projectName: projectHint,
292
+ projectDisplayName: displayName,
293
+ projectFullPath: fullPath,
294
+ firstMessage: firstMessage || null,
295
+ gitBranch,
296
+ provider,
297
+ model,
298
+ startedAt,
299
+ updatedAt: updatedAt || mtimeMs,
300
+ usageJson,
301
+ extraJson: JSON.stringify(extra)
302
+ };
303
+
304
+ return {
305
+ session,
306
+ messages: messages.map((message) => ({
307
+ ...message,
308
+ extraJson: message.extraJson ? JSON.stringify(message.extraJson) : null
309
+ }))
310
+ };
311
+ }
312
+
313
+ module.exports = { configure, inventory, parse, getClaudeUserText };
@@ -1,18 +1,41 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
3
  const crypto = require('crypto');
4
- const { getAllSessions, parseSessionInfoFast } = require('../../utils/session');
5
- const { loadAliases, setAlias } = require('./alias');
6
- const { globalCache, CacheKeys } = require('./enhanced-cache');
7
- const { listProjects: idxListProjects, listSessions: idxListSessions, getRecentSessions: idxGetRecent, searchSessions: idxSearch } = require('./session-history-index');
8
- const { PATHS, NATIVE_PATHS } = require('../../config/paths');
4
+ const { spawnSync } = require('child_process');
5
+ const { getAllSessions, parseSessionInfoFast } = require('../../../utils/session');
6
+ const { loadAliases, setAlias } = require('../../../server/services/alias');
7
+ const { globalCache, CacheKeys } = require('../../../server/services/enhanced-cache');
8
+ let sessionHistoryIndex = null;
9
+
10
+ function getSessionHistoryIndex(config = {}) {
11
+ if (!sessionHistoryIndex) {
12
+ const { getDefaultDependencies } = require('../../../platforms/runtime');
13
+ sessionHistoryIndex = getDefaultDependencies().sessionHistoryIndex;
14
+ if (!sessionHistoryIndex) {
15
+ const indexModule = require('../../../server/services/session-history-index');
16
+ sessionHistoryIndex = Object.keys(config).length > 0
17
+ ? indexModule.createSessionHistoryIndex({ config })
18
+ : indexModule;
19
+ }
20
+ }
21
+ return sessionHistoryIndex;
22
+ }
23
+ const { PATHS, NATIVE_PATHS } = require('../../../config/paths');
9
24
 
10
- const CLAUDE_PROJECTS_DIR = NATIVE_PATHS.claude.projects;
25
+ const DEFAULT_CLAUDE_PROJECTS_DIR = NATIVE_PATHS.claude.projects;
11
26
  const CODEX_PROJECTS_DIR = path.join(path.dirname(NATIVE_PATHS.codex.config), 'projects');
12
27
  const GEMINI_PROJECTS_DIR = path.join(path.dirname(NATIVE_PATHS.gemini.env), 'projects');
28
+ let claudeProjectsDir = DEFAULT_CLAUDE_PROJECTS_DIR;
29
+
30
+ function configure({ sessionHistoryIndex: index, pathContext } = {}) {
31
+ sessionHistoryIndex = index || null;
32
+ claudeProjectsDir = pathContext?.customized
33
+ ? (pathContext.native?.projects || DEFAULT_CLAUDE_PROJECTS_DIR)
34
+ : DEFAULT_CLAUDE_PROJECTS_DIR;
35
+ }
13
36
 
14
37
  function resolveProjectsDir(config = {}) {
15
- return config.projectsDir || CLAUDE_PROJECTS_DIR;
38
+ return config.projectsDir || claudeProjectsDir;
16
39
  }
17
40
 
18
41
  function withResolvedProjectsDir(config = {}) {
@@ -24,6 +47,81 @@ function getOrderFilePath() { return PATHS.projectOrder; }
24
47
  function getForkRelationsFilePath() { return PATHS.forkRelations; }
25
48
  function getSessionOrderFilePath() { return PATHS.sessionOrder; }
26
49
 
50
+ function readSessionCwd(config = {}, sessionId) {
51
+ const sessionFile = path.join(
52
+ resolveProjectsDir(config),
53
+ config.currentProject || '',
54
+ `${sessionId}.jsonl`
55
+ );
56
+ let fd;
57
+ try {
58
+ fd = fs.openSync(sessionFile, 'r');
59
+ const buffer = Buffer.alloc(2048);
60
+ const bytesRead = fs.readSync(fd, buffer, 0, buffer.length, 0);
61
+ const lines = buffer.subarray(0, bytesRead).toString('utf8').split('\n').slice(0, 5);
62
+ for (const line of lines) {
63
+ try {
64
+ const value = JSON.parse(line);
65
+ if (typeof value.cwd === 'string' && value.cwd.trim()) return value.cwd;
66
+ } catch (_) {
67
+ // 忽略无效的会话元数据
68
+ }
69
+ }
70
+ } catch (_) {
71
+ return null;
72
+ } finally {
73
+ if (fd !== undefined) {
74
+ try {
75
+ fs.closeSync(fd);
76
+ } catch (_) {
77
+ // 忽略文件关闭错误
78
+ }
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+
84
+ function resolveLaunchCwd(config, sessionId, cwd) {
85
+ const candidate = typeof cwd === 'string' && cwd.trim()
86
+ ? cwd
87
+ : readSessionCwd(config, sessionId);
88
+ if (candidate) {
89
+ try {
90
+ if (fs.statSync(candidate).isDirectory()) return candidate;
91
+ } catch (_) {
92
+ // 使用当前目录
93
+ }
94
+ }
95
+ return process.cwd();
96
+ }
97
+
98
+ function launch(sessionId, {
99
+ fork = false,
100
+ config = {},
101
+ cwd,
102
+ processRunner = spawnSync
103
+ } = {}) {
104
+ const normalizedSessionId = String(sessionId || '');
105
+ const args = ['-r', normalizedSessionId];
106
+ if (fork) args.push('--fork-session');
107
+ const launchCwd = resolveLaunchCwd(config, normalizedSessionId, cwd);
108
+ const result = processRunner('claude', args, {
109
+ cwd: launchCwd,
110
+ stdio: 'inherit',
111
+ windowsHide: true
112
+ });
113
+ if (result?.error) {
114
+ throw result.error instanceof Error ? result.error : new Error(String(result.error));
115
+ }
116
+ return {
117
+ ...(result && typeof result === 'object' ? result : {}),
118
+ status: result?.status ?? 0,
119
+ signal: result?.signal || null,
120
+ cwd: launchCwd,
121
+ args
122
+ };
123
+ }
124
+
27
125
  function getProjectOrder(config) {
28
126
  const orderFile = getOrderFilePath();
29
127
  try { if (fs.existsSync(orderFile)) return JSON.parse(fs.readFileSync(orderFile, 'utf8')); } catch (_) {}
@@ -101,20 +199,20 @@ function sliceClaudeSessionContentByUserMessage(content, afterUserMessageNumber)
101
199
 
102
200
  // ===== Read-side: all project/list/session/recent/search delegate to session-history-index =====
103
201
 
104
- async function getProjects(config) {
105
- const indexed = await idxListProjects('claude');
202
+ async function getProjects(config = {}, options = {}) {
203
+ const indexed = await getSessionHistoryIndex(config).listProjects('claude', { ...options, config });
106
204
  return indexed.map(p => p.name);
107
205
  }
108
206
 
109
- async function getProjectsWithStats(config, options = {}) {
110
- return idxListProjects('claude');
207
+ async function getProjectsWithStats(config = {}, options = {}) {
208
+ return getSessionHistoryIndex(config).listProjects('claude', { ...options, config });
111
209
  }
112
210
 
113
211
  // ===== Path resolution helpers (kept for mutation/conversion paths) =====
114
212
 
115
- function parseRealProjectPath(encodedName) {
213
+ function parseRealProjectPath(encodedName, config = {}) {
116
214
  const isWindows = process.platform === 'win32';
117
- const fallbackFromSessions = tryResolvePathFromSessions(encodedName);
215
+ const fallbackFromSessions = tryResolvePathFromSessions(encodedName, config);
118
216
  const windowsDriveMatch = encodedName.match(/^([A-Z])--(.+)$/);
119
217
 
120
218
  if (isWindows && windowsDriveMatch) {
@@ -197,9 +295,9 @@ function validateProjectPath(candidatePath) {
197
295
  return (candidatePath && fs.existsSync(candidatePath)) ? candidatePath : null;
198
296
  }
199
297
 
200
- function tryResolvePathFromSessions(encodedName) {
298
+ function tryResolvePathFromSessions(encodedName, config = {}) {
201
299
  try {
202
- const projectDir = path.join(CLAUDE_PROJECTS_DIR, encodedName);
300
+ const projectDir = path.join(resolveProjectsDir(config), encodedName);
203
301
  if (!fs.existsSync(projectDir)) return null;
204
302
  const files = fs.readdirSync(projectDir).filter(f => f.endsWith('.jsonl'));
205
303
  for (const file of files) {
@@ -228,24 +326,19 @@ function extractCwdFromSessionHeader(sessionFile) {
228
326
 
229
327
  // ===== Counts: delegates to index =====
230
328
 
231
- async function getProjectAndSessionCounts(config) {
232
- try {
233
- const projects = await idxListProjects('claude');
234
- let sessionCount = 0;
235
- for (const p of projects) sessionCount += p.sessionCount || 0;
236
- return { projectCount: projects.length, sessionCount };
237
- } catch (_) {
238
- return { projectCount: 0, sessionCount: 0 };
239
- }
329
+ async function getProjectAndSessionCounts(config = {}, options = {}) {
330
+ const projects = await getSessionHistoryIndex().listProjects('claude', { ...options, config });
331
+ let sessionCount = 0;
332
+ for (const project of projects) sessionCount += project.sessionCount || 0;
333
+ return { projectCount: projects.length, sessionCount };
240
334
  }
241
335
 
242
336
  // ===== Sessions for project: index + saved order + fork relations =====
243
337
 
244
338
  async function getSessionsForProject(config, projectName, options = {}) {
245
- const indexed = await idxListSessions('claude', projectName);
339
+ const indexed = await getSessionHistoryIndex().listSessions('claude', projectName, { ...options, config });
246
340
  const forkRelations = getForkRelations();
247
341
  const savedOrder = getSessionOrder(projectName);
248
-
249
342
  let sessions = indexed.map(s => ({
250
343
  sessionId: s.sessionId,
251
344
  mtime: s.mtime,
@@ -269,7 +362,6 @@ async function getSessionsForProject(config, projectName, options = {}) {
269
362
  const totalSize = sessions.reduce((sum, s) => sum + (s.size || 0), 0);
270
363
  return { sessions, totalSize };
271
364
  }
272
-
273
365
  // ===== Mutations (sync) =====
274
366
 
275
367
  function deleteSession(config, projectName, sessionId) {
@@ -343,8 +435,8 @@ function deleteProject(config, projectName) {
343
435
 
344
436
  // ===== Search: delegates to index =====
345
437
 
346
- async function searchSessions(config, projectName, keyword, contextLength = 15) {
347
- const results = await idxSearch('claude', keyword, { projectName, contextLength });
438
+ async function searchSessions(config, projectName, keyword, contextLength = 15, options = {}) {
439
+ const results = await getSessionHistoryIndex().searchSessions('claude', keyword, { projectName, contextLength, ...options, config });
348
440
  const aliases = loadAliases();
349
441
  return results.map(r => ({
350
442
  sessionId: r.sessionId,
@@ -354,10 +446,10 @@ async function searchSessions(config, projectName, keyword, contextLength = 15)
354
446
  }));
355
447
  }
356
448
 
357
- async function getRecentSessions(config, limit = 5) {
358
- const indexed = await idxGetRecent('claude', limit);
359
- const aliases = loadAliases();
449
+ async function getRecentSessions(config, limit = 5, options = {}) {
450
+ const indexed = await getSessionHistoryIndex().getRecentSessions('claude', limit, { ...options, config });
360
451
  const forkRelations = getForkRelations();
452
+ const aliases = loadAliases();
361
453
  return indexed.map(s => ({
362
454
  sessionId: s.sessionId,
363
455
  projectName: s.projectName,
@@ -377,13 +469,13 @@ async function searchSessionsAcrossProjects(config, keyword, contextLength = 35)
377
469
  const allResults = [];
378
470
 
379
471
  try {
380
- const claudeResults = await idxSearch('claude', keyword, { contextLength });
472
+ const claudeResults = await getSessionHistoryIndex().searchSessions('claude', keyword, { contextLength });
381
473
  for (const r of claudeResults) allResults.push({ ...r, channel: 'claude' });
382
474
  } catch (_) {}
383
475
 
384
476
  try {
385
477
  if (fs.existsSync(CODEX_PROJECTS_DIR)) {
386
- const { searchSessions: codexSearch } = require('./codex-sessions');
478
+ const { searchSessions: codexSearch } = require('../codex/sessions-implementation');
387
479
  const codexResults = await codexSearch(keyword);
388
480
  for (const r of codexResults) allResults.push({ ...r, channel: 'codex' });
389
481
  }
@@ -391,7 +483,7 @@ async function searchSessionsAcrossProjects(config, keyword, contextLength = 35)
391
483
 
392
484
  try {
393
485
  if (fs.existsSync(GEMINI_PROJECTS_DIR)) {
394
- const { searchSessions: geminiSearch } = require('./gemini-sessions');
486
+ const { searchSessions: geminiSearch } = require('../gemini/sessions-implementation');
395
487
  const geminiResults = await geminiSearch(keyword, contextLength);
396
488
  for (const r of geminiResults) allResults.push({ ...r, channel: 'gemini' });
397
489
  }
@@ -400,13 +492,31 @@ async function searchSessionsAcrossProjects(config, keyword, contextLength = 35)
400
492
  allResults.sort((a, b) => (b.matchCount || 0) - (a.matchCount || 0));
401
493
  return allResults;
402
494
  }
495
+ function hasActualMessages(sessionFile) {
496
+ if (!sessionFile || !fs.existsSync(sessionFile)) return false;
497
+ return fs.readFileSync(sessionFile, 'utf8')
498
+ .split(/\r?\n/)
499
+ .some(line => {
500
+ if (!line.trim()) return false;
501
+ try {
502
+ const entry = JSON.parse(line);
503
+ return entry.type === 'user' || entry.type === 'assistant'
504
+ || entry.message?.role === 'user' || entry.message?.role === 'assistant';
505
+ } catch (_) {
506
+ return false;
507
+ }
508
+ });
509
+ }
510
+
403
511
 
404
512
  module.exports = {
513
+ configure,
405
514
  getProjects,
406
515
  getProjectsWithStats,
407
516
  getSessionsForProject,
408
517
  deleteSession,
409
518
  forkSession,
519
+ launch,
410
520
  getRecentSessions,
411
521
  getProjectOrder,
412
522
  saveProjectOrder,
@@ -0,0 +1,76 @@
1
+ 'use strict';
2
+
3
+ const { createCapabilityDriver } = require('../../../shared/capability-driver');
4
+
5
+ function createDriver(context = {}) {
6
+ return createCapabilityDriver({
7
+ ...context,
8
+ platform: 'claude',
9
+ capability: 'sessions',
10
+ parserVersion: 2,
11
+ servicePath: './claude/sessions-implementation',
12
+ localServicePath: '../platforms/drivers/claude/sessions-implementation',
13
+ adapterLocalPath: '../platforms/drivers/claude/session-history-adapter',
14
+ adapterMethods: { inventory: 'inventory', parse: 'parse' },
15
+ methods: {
16
+ launch: 'launch',
17
+ saveSessionOrder: 'saveSessionOrder',
18
+ getSessionOrder: 'getSessionOrder',
19
+ parseRealProjectPath: 'parseRealProjectPath',
20
+ hasActualMessages: 'hasActualMessages',
21
+ status: 'getSessionStatus',
22
+ messages: 'getSessionMessages'
23
+ },
24
+ customMethods: {
25
+ delete: (service, projectName, sessionId, options = {}) => {
26
+ const result = service.deleteSession(options.config || {}, projectName, sessionId);
27
+ context.sessionHistoryIndex?.invalidateSource('claude');
28
+ return result;
29
+ },
30
+ fork: (service, projectName, sessionId, options = {}) => {
31
+ const result = service.forkSession(options.config || {}, projectName, sessionId, options);
32
+ context.sessionHistoryIndex?.invalidateSource('claude');
33
+ return result;
34
+ },
35
+ listSessions: (service, projectNameOrRequest, options = {}) => {
36
+ const descriptorRequest = projectNameOrRequest && typeof projectNameOrRequest === 'object';
37
+ const request = descriptorRequest ? projectNameOrRequest : options;
38
+ const projectName = descriptorRequest
39
+ ? request.params?.projectName
40
+ : projectNameOrRequest;
41
+ return service.getSessionsForProject(
42
+ request.config || {},
43
+ projectName,
44
+ request
45
+ );
46
+ },
47
+ recent: (service, limitOrRequest, options = {}) => {
48
+ const descriptorRequest = limitOrRequest && typeof limitOrRequest === 'object';
49
+ const request = descriptorRequest ? limitOrRequest : options;
50
+ const limit = descriptorRequest
51
+ ? Number.parseInt(request.query?.limit, 10) || 5
52
+ : limitOrRequest;
53
+ return service.getRecentSessions(request.config || {}, limit, request);
54
+ },
55
+ search: (service, projectName, keyword, contextLength, options = {}) => service.searchSessions(
56
+ options.config || {},
57
+ projectName,
58
+ keyword,
59
+ contextLength,
60
+ options
61
+ ),
62
+ searchAcrossProjects: (service, keyword, limit, options = {}) => service.searchSessionsAcrossProjects(
63
+ options.config || {},
64
+ keyword,
65
+ limit
66
+ )
67
+ },
68
+ onSuccess: operation => {
69
+ if (['delete', 'fork', 'saveSessionOrder'].includes(operation)) {
70
+ context.sessionHistoryIndex?.invalidateSource('claude');
71
+ }
72
+ }
73
+ });
74
+ }
75
+
76
+ 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 = 'claude-code';
10
10
  const USAGE_SOURCE = 'claude';