coding-tool-x 3.8.4 → 3.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +86 -15
  3. package/dist/web/assets/AgentsDrawer-BG6P3DX-.js +1 -0
  4. package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
  5. package/dist/web/assets/Analytics--z_FmL5P.js +1 -0
  6. package/dist/web/assets/Analytics-CyHhR126.css +1 -0
  7. package/dist/web/assets/AssetPathField-CrJtRKHy.js +1 -0
  8. package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
  9. package/dist/web/assets/ChatHistoryDrawer-BiuEryJj.js +1 -0
  10. package/dist/web/assets/CollapseItem-BAYEsL_Q.js +1 -0
  11. package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
  12. package/dist/web/assets/CommandsDrawer-YJ-U7BXN.js +1 -0
  13. package/dist/web/assets/ConfigExportDrawer-Ce_hAknW.js +1 -0
  14. package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
  15. package/dist/web/assets/ConfigTemplates-Bvr1NN6K.js +1 -0
  16. package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
  17. package/dist/web/assets/ConfigTemplatesDrawer-BjIeHfF-.js +1 -0
  18. package/dist/web/assets/ConfigTemplatesPanel-AV00tm_D.js +1 -0
  19. package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +1 -0
  20. package/dist/web/assets/Divider-D28g1gwj.js +1 -0
  21. package/dist/web/assets/DrawerContent-ChXgZ1Xm.js +1 -0
  22. package/dist/web/assets/FavoritesDrawer-CG9eI9Ay.css +1 -0
  23. package/dist/web/assets/FavoritesDrawer-Cz95o4CD.js +1 -0
  24. package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
  25. package/dist/web/assets/GatewayConvertDrawer-DLlbMz27.js +1 -0
  26. package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
  27. package/dist/web/assets/Home-D7CCOFQC.js +1 -0
  28. package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
  29. package/dist/web/assets/MarkdownEditor-rEZ-c72L.js +1 -0
  30. package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
  31. package/dist/web/assets/McpDrawer-DfoCyxU2.js +1 -0
  32. package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
  33. package/dist/web/assets/McpFormDrawer-SKu8HNUR.js +1 -0
  34. package/dist/web/assets/PluginManager-BbeK-3rV.js +1 -0
  35. package/dist/web/assets/PluginsDrawer-CWVJ7yjS.js +1 -0
  36. package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
  37. package/dist/web/assets/PluginsPanel-Cm2N3StG.js +1 -0
  38. package/dist/web/assets/PluginsPanel-D6ZqITcR.css +1 -0
  39. package/dist/web/assets/ProjectList-677RLZ8O.css +1 -0
  40. package/dist/web/assets/ProjectList-CsjnsNPv.js +1 -0
  41. package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
  42. package/dist/web/assets/PromptsDrawer-EGd3djFa.js +1 -0
  43. package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
  44. package/dist/web/assets/RecentSessionsDrawer-D1vtoLAs.js +1 -0
  45. package/dist/web/assets/SessionCard-BgLg49U3.js +1 -0
  46. package/dist/web/assets/SessionCard-aM2NHu6i.css +1 -0
  47. package/dist/web/assets/SessionList-BpYRz1cX.css +1 -0
  48. package/dist/web/assets/SessionList-TRiTklWk.js +1 -0
  49. package/dist/web/assets/SettingsDrawer-d5liXjHq.css +1 -0
  50. package/dist/web/assets/SettingsDrawer-rz2WejGY.js +1 -0
  51. package/dist/web/assets/SkillManager-BTjTUbHq.js +1 -0
  52. package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
  53. package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
  54. package/dist/web/assets/SkillsDrawer-pN0hbkK3.js +1 -0
  55. package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
  56. package/dist/web/assets/SkillsPanel-gmBWEoiF.js +1 -0
  57. package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
  58. package/dist/web/assets/SpeedTestDrawer-DcNzuVJk.js +1 -0
  59. package/dist/web/assets/Upload-v5rV0qTT.js +1 -0
  60. package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
  61. package/dist/web/assets/WorkspaceDrawer-DxmicM4U.js +1 -0
  62. package/dist/web/assets/WorkspaceManager-CJHCjARN.js +1 -0
  63. package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
  64. package/dist/web/assets/WorkspacePanel-D8_Zq-du.js +1 -0
  65. package/dist/web/assets/_plugin-vue_export-helper-BeLZJZij.js +1 -0
  66. package/dist/web/assets/client-UDwXBP9i.js +1 -0
  67. package/dist/web/assets/clipboard-B46yyoz_.js +1 -0
  68. package/dist/web/assets/headers-cf-QapUq.js +1 -0
  69. package/dist/web/assets/icons-B2Vg-IOC.js +1 -0
  70. package/dist/web/assets/index-C0EHRym0.css +1 -0
  71. package/dist/web/assets/index-DnEocV0M.js +2 -0
  72. package/dist/web/assets/light-Cp0t7v32.js +1 -0
  73. package/dist/web/assets/markdown-u082bbtj.js +1 -0
  74. package/dist/web/assets/platforms-CBkB45JP.js +1 -0
  75. package/dist/web/assets/platforms-FTpjxAT6.js +1 -0
  76. package/dist/web/assets/project-config-B2baPzYL.js +1 -0
  77. package/dist/web/assets/sessions-Cmy31slD.js +1 -0
  78. package/dist/web/assets/sessions-yC_oVVh8.js +1 -0
  79. package/dist/web/assets/skill-repo-input-B_fkGlUK.js +1 -0
  80. package/dist/web/assets/use-lock-html-scroll-DXIqmUW4.js +1 -0
  81. package/dist/web/assets/use-message-DoLM8C1C.js +1 -0
  82. package/dist/web/assets/useResponsiveDrawer-B3uojyvV.js +1 -0
  83. package/dist/web/assets/vendors-D0c_0KLP.js +1 -0
  84. package/dist/web/assets/vue-vendor-BqZbbXHA.js +1 -0
  85. package/dist/web/assets/workspaces-mjyPVGS8.js +1 -0
  86. package/dist/web/assets/xml-CgY3RMlX.js +1 -0
  87. package/dist/web/index.html +12 -8
  88. package/docs/native-log-memory-2026-09-16.md +43 -0
  89. package/docs/superpowers/plans/2026-08-26-configuration-driven-cli-platform.md +1578 -0
  90. package/docs/superpowers/plans/2026-08-30-project-scoped-config-control.md +1260 -0
  91. package/docs/superpowers/plans/2026-09-01-omp-skill-refresh-boundary.md +213 -0
  92. package/docs/superpowers/plans/2026-09-01-realtime-logs-panel.md +125 -0
  93. package/docs/superpowers/plans/2026-09-02-config-driven-platform-boundary.md +86 -0
  94. package/docs/superpowers/plans/2026-09-02-platform-implementation-drivers.md +508 -0
  95. package/docs/superpowers/plans/2026-09-03-cli-platform-correctness-boundary.md +760 -0
  96. package/docs/superpowers/plans/2026-09-03-dependency-security-remediation.md +133 -0
  97. package/docs/superpowers/plans/2026-09-04-model-catalog-pricing-sync.md +1078 -0
  98. package/docs/superpowers/plans/2026-09-05-codex-project-scan-500.md +128 -0
  99. package/docs/superpowers/plans/2026-09-06-project-skill-path-fix.md +97 -0
  100. package/docs/superpowers/specs/2026-08-26-configuration-driven-cli-platform-design.md +408 -0
  101. package/docs/superpowers/specs/2026-08-30-project-scoped-config-control-design.md +467 -0
  102. package/docs/superpowers/specs/2026-09-01-claude-session-content-repair-design.md +111 -0
  103. package/docs/superpowers/specs/2026-09-01-omp-skill-refresh-boundary-design.md +83 -0
  104. package/docs/superpowers/specs/2026-09-01-realtime-logs-panel-design.md +27 -0
  105. package/docs/superpowers/specs/2026-09-02-config-driven-platform-boundary-design.md +64 -0
  106. package/docs/superpowers/specs/2026-09-02-platform-implementation-driver-boundary-design.md +123 -0
  107. package/docs/superpowers/specs/2026-09-03-cli-platform-correctness-boundary-design.md +249 -0
  108. package/docs/superpowers/specs/2026-09-03-dependency-security-remediation-design.md +87 -0
  109. package/docs/superpowers/specs/2026-09-04-model-catalog-pricing-sync-design.md +301 -0
  110. package/docs/superpowers/specs/2026-09-05-codex-project-scan-500-design.md +24 -0
  111. package/package.json +8 -4
  112. package/src/commands/channels.js +88 -191
  113. package/src/commands/cli-type.js +19 -11
  114. package/src/commands/daemon.js +94 -32
  115. package/src/commands/doctor.js +16 -9
  116. package/src/commands/export-config.js +23 -5
  117. package/src/commands/list.js +130 -52
  118. package/src/commands/logs.js +44 -27
  119. package/src/commands/platform-command-registry.js +78 -0
  120. package/src/commands/plugin.js +11 -5
  121. package/src/commands/port-config.js +34 -52
  122. package/src/commands/proxy-control.js +207 -145
  123. package/src/commands/proxy.js +2 -2
  124. package/src/commands/resume.js +87 -91
  125. package/src/commands/search.js +137 -67
  126. package/src/commands/stats.js +30 -22
  127. package/src/commands/switch.js +1 -1
  128. package/src/commands/toggle-proxy.js +94 -111
  129. package/src/commands/ui.js +67 -6
  130. package/src/commands/workspace.js +90 -8
  131. package/src/config/default.js +6 -53
  132. package/src/config/loader.js +61 -24
  133. package/src/config/model-metadata.js +49 -59
  134. package/src/config/model-metadata.json +4095 -99
  135. package/src/config/paths.js +181 -8
  136. package/src/index.js +134 -71
  137. package/src/platforms/access.js +196 -0
  138. package/src/{server/services → platforms}/agents-service.js +354 -197
  139. package/src/platforms/channel-auth-registry.js +162 -0
  140. package/src/platforms/channel-auth-service.js +82 -0
  141. package/src/{server/services → platforms}/commands-service.js +195 -115
  142. package/src/platforms/driver-registry.js +59 -0
  143. package/src/platforms/drivers/claude/api-operations.js +62 -0
  144. package/src/{server/services/channels.js → platforms/drivers/claude/channels-implementation.js} +131 -33
  145. package/src/platforms/drivers/claude/channels.js +39 -0
  146. package/src/{server/services/config-sync-service.js → platforms/drivers/claude/config-sync.js} +29 -5
  147. package/src/{server/services → platforms/drivers/claude}/health-check.js +4 -4
  148. package/src/platforms/drivers/claude/health.js +22 -0
  149. package/src/platforms/drivers/claude/mcp.js +9 -0
  150. package/src/{server/services/settings-manager.js → platforms/drivers/claude/native-config-implementation.js} +13 -4
  151. package/src/platforms/drivers/claude/native-config.js +46 -0
  152. package/src/platforms/drivers/claude/native-logs.js +72 -0
  153. package/src/{server/services/claude-openai-gateway.js → platforms/drivers/claude/openai-gateway.js} +8 -65
  154. package/src/platforms/drivers/claude/project-config.js +21 -0
  155. package/src/platforms/drivers/claude/projects.js +62 -0
  156. package/src/platforms/drivers/claude/prompts.js +9 -0
  157. package/src/{server/proxy-server.js → platforms/drivers/claude/proxy-implementation.js} +41 -278
  158. package/src/platforms/drivers/claude/proxy.js +16 -0
  159. package/src/platforms/drivers/claude/resource-sync.js +9 -0
  160. package/src/platforms/drivers/claude/session-history-adapter.js +313 -0
  161. package/src/{server/services/sessions.js → platforms/drivers/claude/sessions-implementation.js} +145 -35
  162. package/src/platforms/drivers/claude/sessions.js +76 -0
  163. package/src/{server/services/claude-statistics-service.js → platforms/drivers/claude/statistics-implementation.js} +2 -2
  164. package/src/platforms/drivers/claude/statistics.js +16 -0
  165. package/src/{server/services/claude-wire.js → platforms/drivers/claude/wire.js} +1 -1
  166. package/src/platforms/drivers/codex/api-operations.js +9 -0
  167. package/src/{server/services/codex-channels.js → platforms/drivers/codex/channels-implementation.js} +149 -14
  168. package/src/platforms/drivers/codex/channels.js +45 -0
  169. package/src/{server/services/codex-config.js → platforms/drivers/codex/config.js} +12 -2
  170. package/src/{server/services/codex-env-manager.js → platforms/drivers/codex/env-manager.js} +1 -1
  171. package/src/platforms/drivers/codex/mcp.js +9 -0
  172. package/src/{server/services/codex-settings-manager.js → platforms/drivers/codex/native-config-implementation.js} +15 -6
  173. package/src/platforms/drivers/codex/native-config.js +47 -0
  174. package/src/platforms/drivers/codex/native-logs.js +166 -0
  175. package/src/platforms/drivers/codex/project-config.js +21 -0
  176. package/src/platforms/drivers/codex/projects.js +26 -0
  177. package/src/platforms/drivers/codex/prompts.js +9 -0
  178. package/src/{server/codex-proxy-server.js → platforms/drivers/codex/proxy-implementation.js} +30 -233
  179. package/src/platforms/drivers/codex/proxy.js +16 -0
  180. package/src/platforms/drivers/codex/resource-sync.js +9 -0
  181. package/src/{server/services/session-history-adapters/codex.js → platforms/drivers/codex/session-history-adapter.js} +37 -23
  182. package/src/{server/services/codex-sessions.js → platforms/drivers/codex/sessions-implementation.js} +81 -75
  183. package/src/platforms/drivers/codex/sessions.js +36 -0
  184. package/src/{server/services/codex-statistics-service.js → platforms/drivers/codex/statistics-implementation.js} +2 -2
  185. package/src/platforms/drivers/codex/statistics.js +16 -0
  186. package/src/platforms/drivers/gemini/api-operations.js +9 -0
  187. package/src/{server/services/gemini-channels.js → platforms/drivers/gemini/channels-implementation.js} +202 -37
  188. package/src/platforms/drivers/gemini/channels.js +39 -0
  189. package/src/{server/services/gemini-config.js → platforms/drivers/gemini/config.js} +12 -2
  190. package/src/platforms/drivers/gemini/mcp.js +9 -0
  191. package/src/{server/services/gemini-settings-manager.js → platforms/drivers/gemini/native-config-implementation.js} +14 -5
  192. package/src/platforms/drivers/gemini/native-config.js +39 -0
  193. package/src/platforms/drivers/gemini/native-logs.js +180 -0
  194. package/src/platforms/drivers/gemini/project-config.js +21 -0
  195. package/src/platforms/drivers/gemini/projects.js +26 -0
  196. package/src/platforms/drivers/gemini/prompts.js +9 -0
  197. package/src/{server/gemini-proxy-server.js → platforms/drivers/gemini/proxy-implementation.js} +36 -267
  198. package/src/platforms/drivers/gemini/proxy.js +16 -0
  199. package/src/platforms/drivers/gemini/resource-sync.js +9 -0
  200. package/src/{server/services/session-history-adapters/gemini.js → platforms/drivers/gemini/session-history-adapter.js} +70 -18
  201. package/src/{server/services/gemini-sessions.js → platforms/drivers/gemini/sessions-implementation.js} +53 -37
  202. package/src/platforms/drivers/gemini/sessions.js +47 -0
  203. package/src/{server/services/gemini-statistics-service.js → platforms/drivers/gemini/statistics-implementation.js} +2 -2
  204. package/src/platforms/drivers/gemini/statistics.js +16 -0
  205. package/src/{server/services/gemini-wire.js → platforms/drivers/gemini/wire.js} +1 -1
  206. package/src/platforms/drivers/generic-filesystem.js +166 -0
  207. package/src/platforms/drivers/generic-jsonl.js +141 -0
  208. package/src/platforms/drivers/generic-mcp.js +44 -0
  209. package/src/platforms/drivers/generic-openai-compatible.js +45 -0
  210. package/src/platforms/drivers/generic-prompt.js +41 -0
  211. package/src/platforms/drivers/legacy.js +677 -0
  212. package/src/platforms/drivers/native-config-snapshot.js +125 -0
  213. package/src/platforms/drivers/native-log-utils.js +1292 -0
  214. package/src/platforms/drivers/notification-hooks.js +578 -0
  215. package/src/{server/api/omp-config.js → platforms/drivers/omp/api-operations.js} +52 -64
  216. package/src/{server/services/omp-auth-provider-worker.js → platforms/drivers/omp/auth-provider-worker.js} +1 -1
  217. package/src/{server/services/omp-auth-providers.js → platforms/drivers/omp/auth-providers.js} +1 -1
  218. package/src/{server/services/omp-channels.js → platforms/drivers/omp/channels-implementation.js} +166 -39
  219. package/src/platforms/drivers/omp/channels.js +58 -0
  220. package/src/{server/services/omp-config.js → platforms/drivers/omp/config.js} +53 -13
  221. package/src/{server/services/omp-gateway-routing.js → platforms/drivers/omp/gateway-routing.js} +14 -7
  222. package/src/{server/services/omp-gateway.js → platforms/drivers/omp/gateway.js} +4 -262
  223. package/src/platforms/drivers/omp/mcp.js +9 -0
  224. package/src/{server/services/omp-settings-manager.js → platforms/drivers/omp/native-config-implementation.js} +75 -10
  225. package/src/platforms/drivers/omp/native-config.js +46 -0
  226. package/src/platforms/drivers/omp/native-logs.js +52 -0
  227. package/src/{server/services/omp-native-plugin-adapter.js → platforms/drivers/omp/native-plugin-adapter.js} +91 -4
  228. package/src/platforms/drivers/omp/project-config.js +29 -0
  229. package/src/platforms/drivers/omp/projects.js +20 -0
  230. package/src/platforms/drivers/omp/prompts.js +9 -0
  231. package/src/{server/omp-proxy-server.js → platforms/drivers/omp/proxy-implementation.js} +6 -15
  232. package/src/platforms/drivers/omp/proxy.js +16 -0
  233. package/src/platforms/drivers/omp/resource-sync.js +9 -0
  234. package/src/{server/services/session-history-adapters/omp.js → platforms/drivers/omp/session-history-adapter.js} +42 -18
  235. package/src/{server/services/omp-sessions.js → platforms/drivers/omp/sessions-implementation.js} +130 -94
  236. package/src/platforms/drivers/omp/sessions.js +36 -0
  237. package/src/{server/services/omp-skill-discovery.js → platforms/drivers/omp/skill-discovery.js} +159 -32
  238. package/src/{server/services/omp-skill-settings-service.js → platforms/drivers/omp/skill-settings.js} +1 -1
  239. package/src/{server/services/omp-statistics-service.js → platforms/drivers/omp/statistics-implementation.js} +3 -3
  240. package/src/platforms/drivers/omp/statistics.js +16 -0
  241. package/src/platforms/drivers/opencode/api-operations.js +9 -0
  242. package/src/{server/services/opencode-channels.js → platforms/drivers/opencode/channels-implementation.js} +28 -9
  243. package/src/platforms/drivers/opencode/channels.js +40 -0
  244. package/src/platforms/drivers/opencode/conversion.js +41 -0
  245. package/src/{server/services/opencode-gateway-converter.js → platforms/drivers/opencode/gateway-converter.js} +1 -1
  246. package/src/platforms/drivers/opencode/mcp.js +9 -0
  247. package/src/{server/services/opencode-settings-manager.js → platforms/drivers/opencode/native-config-implementation.js} +17 -6
  248. package/src/platforms/drivers/opencode/native-config.js +26 -0
  249. package/src/platforms/drivers/opencode/native-logs.js +133 -0
  250. package/src/platforms/drivers/opencode/project-config.js +98 -0
  251. package/src/platforms/drivers/opencode/projects.js +20 -0
  252. package/src/platforms/drivers/opencode/prompts.js +9 -0
  253. package/src/{server/opencode-proxy-server.js → platforms/drivers/opencode/proxy-implementation.js} +27 -362
  254. package/src/platforms/drivers/opencode/proxy.js +16 -0
  255. package/src/platforms/drivers/opencode/resource-sync.js +9 -0
  256. package/src/{server/services/opencode-sessions.js → platforms/drivers/opencode/sessions-implementation.js} +211 -64
  257. package/src/platforms/drivers/opencode/sessions.js +48 -0
  258. package/src/{server/services/opencode-statistics-service.js → platforms/drivers/opencode/statistics-implementation.js} +2 -2
  259. package/src/platforms/drivers/opencode/statistics.js +16 -0
  260. package/src/platforms/drivers/secure-file-driver.js +272 -0
  261. package/src/platforms/drivers/unsupported.js +7 -0
  262. package/src/platforms/manifest-schema.js +398 -0
  263. package/src/platforms/manifests/claude.json +489 -0
  264. package/src/platforms/manifests/codex.json +448 -0
  265. package/src/platforms/manifests/gemini.json +447 -0
  266. package/src/platforms/manifests/omp.json +496 -0
  267. package/src/platforms/manifests/opencode.json +422 -0
  268. package/src/{server/services → platforms}/native-oauth-adapters.js +87 -417
  269. package/src/{server/services → platforms}/notification-hooks.js +140 -1023
  270. package/src/platforms/oauth-credentials-service.js +506 -0
  271. package/src/platforms/path-resolver.js +179 -0
  272. package/src/platforms/platform-path-context.js +305 -0
  273. package/src/platforms/registry.js +248 -0
  274. package/src/platforms/remote-notification-providers.js +678 -0
  275. package/src/platforms/runtime.js +259 -0
  276. package/src/{server/services/session-history-adapters/index.js → platforms/session-history-adapters.js} +8 -1
  277. package/src/plugins/plugin-loader.js +2 -2
  278. package/src/plugins/plugin-manager.js +2 -2
  279. package/src/plugins/registry.js +27 -10
  280. package/src/reset-config.js +21 -5
  281. package/src/server/api/agents.js +46 -72
  282. package/src/server/api/commands.js +16 -6
  283. package/src/server/api/config-registry.js +206 -59
  284. package/src/server/api/config-sync.js +3 -2
  285. package/src/server/api/config-templates.js +20 -4
  286. package/src/server/api/config.js +111 -102
  287. package/src/server/api/convert.js +54 -178
  288. package/src/server/api/dashboard.js +168 -102
  289. package/src/server/api/hooks.js +1 -1
  290. package/src/server/api/mcp.js +224 -84
  291. package/src/server/api/platform-api-config.js +102 -0
  292. package/src/server/api/platform-route-factory.js +215 -0
  293. package/src/server/api/platform-routes.js +26 -0
  294. package/src/server/api/platforms.js +110 -0
  295. package/src/server/api/plugins.js +57 -57
  296. package/src/server/api/project-config.js +168 -0
  297. package/src/server/api/prompts.js +58 -45
  298. package/src/server/api/settings.js +55 -8
  299. package/src/server/api/skills.js +262 -133
  300. package/src/server/api/ui-config.js +2 -2
  301. package/src/server/api/validation-errors.js +18 -4
  302. package/src/server/api/workspaces.js +47 -12
  303. package/src/server/index.js +164 -213
  304. package/src/server/platform-context.js +81 -0
  305. package/src/server/services/channel-balance.js +11 -20
  306. package/src/server/services/channel-health.js +21 -6
  307. package/src/server/services/channel-scheduler.js +29 -39
  308. package/src/server/services/channel-sync-utils.js +23 -13
  309. package/src/server/services/config-export-service.js +350 -319
  310. package/src/server/services/config-registry-service.js +280 -54
  311. package/src/server/services/config-sync-manager.js +172 -944
  312. package/src/server/services/config-templates-service.js +419 -353
  313. package/src/server/services/control-manifest-store.js +206 -0
  314. package/src/server/services/dashboard-snapshot-worker.js +656 -100
  315. package/src/server/services/effective-control-service.js +557 -0
  316. package/src/server/services/local-resource-index.js +314 -0
  317. package/src/server/services/mcp-service.js +607 -977
  318. package/src/server/services/model-detector.js +15 -10
  319. package/src/server/services/native-log-channel-resolver.js +214 -0
  320. package/src/server/services/native-log-observer.js +291 -0
  321. package/src/server/services/network-access.js +1 -1
  322. package/src/server/services/platform-catalog.js +82 -0
  323. package/src/server/services/platform-resolution.js +32 -29
  324. package/src/server/services/plugins-service.js +376 -122
  325. package/src/server/services/project-config-service.js +550 -0
  326. package/src/server/services/project-path-validation.js +31 -0
  327. package/src/server/services/prompts-service.js +267 -233
  328. package/src/server/services/proxy-runtime.js +7 -4
  329. package/src/server/services/remote-credential-cache.js +43 -0
  330. package/src/server/services/repo-scanner-base.js +182 -75
  331. package/src/server/services/request-logger.js +7 -4
  332. package/src/server/services/session-history-index.js +780 -213
  333. package/src/server/services/session-history-worker.js +228 -33
  334. package/src/server/services/session-snapshot-worker.js +124 -34
  335. package/src/server/services/session-snapshots.js +4 -2
  336. package/src/server/services/skill-artifact-store.js +355 -0
  337. package/src/server/services/skill-format-adapters.js +65 -0
  338. package/src/server/services/skill-projection-service.js +323 -0
  339. package/src/server/services/skill-refresh-task-service.js +275 -0
  340. package/src/server/services/skill-service.js +2020 -677
  341. package/src/server/services/snapshot-cache.js +30 -8
  342. package/src/server/services/speed-test.js +8 -8
  343. package/src/server/services/sqlite-connection.js +19 -3
  344. package/src/server/services/statistics-service.js +240 -57
  345. package/src/server/services/ui-config.js +107 -76
  346. package/src/server/services/usage-log-utils.js +98 -0
  347. package/src/server/services/web-build.js +1 -1
  348. package/src/server/services/workspace-service.js +59 -29
  349. package/src/server/utils/pricing.js +10 -19
  350. package/src/server/websocket-server.js +153 -28
  351. package/src/{server/services/base → shared}/base-channel-service.js +156 -28
  352. package/src/shared/capability-driver.js +104 -0
  353. package/src/shared/channel-auth-policy.js +27 -0
  354. package/src/shared/channel-driver.js +161 -0
  355. package/src/shared/driver-factories/api.js +180 -0
  356. package/src/shared/driver-factories/mcp.js +244 -0
  357. package/src/shared/driver-factories/projects.js +121 -0
  358. package/src/shared/driver-factories/prompts.js +58 -0
  359. package/src/shared/driver-factories/resource-sync.js +375 -0
  360. package/src/shared/driver-result.js +78 -0
  361. package/src/shared/mcp-format.js +189 -0
  362. package/src/shared/platforms.js +104 -167
  363. package/src/shared/project-config.js +512 -0
  364. package/src/shared/proxy-driver.js +57 -0
  365. package/src/{server/services/base → shared}/response-usage-parser.js +8 -4
  366. package/src/ui/menu.js +91 -67
  367. package/src/utils/port-helper.js +35 -19
  368. package/src/utils/session.js +1 -1
  369. package/dist/web/assets/Analytics-COEUXmd4.js +0 -25
  370. package/dist/web/assets/Analytics-RNn1BUbG.css +0 -1
  371. package/dist/web/assets/ConfigTemplates-DLLkS53H.js +0 -1
  372. package/dist/web/assets/Home-DCEyLzwX.js +0 -1
  373. package/dist/web/assets/Home-DYVy4cGZ.css +0 -1
  374. package/dist/web/assets/PluginManager-Oe1ZHoMO.js +0 -1
  375. package/dist/web/assets/ProjectList-CWjuAFof.js +0 -1
  376. package/dist/web/assets/ProjectList-VeMNXfgO.css +0 -1
  377. package/dist/web/assets/SessionList-C4chCPxK.css +0 -1
  378. package/dist/web/assets/SessionList-v3ehGg9U.js +0 -1
  379. package/dist/web/assets/SkillManager-BsX8Qpj0.css +0 -1
  380. package/dist/web/assets/SkillManager-DUF_qP5S.js +0 -1
  381. package/dist/web/assets/WorkspaceManager-CjAWBosO.js +0 -1
  382. package/dist/web/assets/icons-nGdSKQn2.js +0 -1
  383. package/dist/web/assets/index-D5hyHPj7.js +0 -2
  384. package/dist/web/assets/index-bJRG3RXH.css +0 -1
  385. package/dist/web/assets/markdown-BNJfEgCA.js +0 -1
  386. package/dist/web/assets/markdown-BfC0goYb.css +0 -10
  387. package/dist/web/assets/naive-ui-BALVpMgd.js +0 -1
  388. package/dist/web/assets/vendors-DQA4Hw9v.js +0 -7
  389. package/dist/web/assets/vue-vendor-B5RqjEjQ.js +0 -45
  390. package/src/config/model-pricing.js +0 -35
  391. package/src/server/api/channels.js +0 -439
  392. package/src/server/api/claude-hooks.js +0 -56
  393. package/src/server/api/claude-statistics.js +0 -57
  394. package/src/server/api/codex-channels.js +0 -491
  395. package/src/server/api/codex-projects.js +0 -117
  396. package/src/server/api/codex-proxy.js +0 -293
  397. package/src/server/api/codex-sessions.js +0 -652
  398. package/src/server/api/codex-statistics.js +0 -57
  399. package/src/server/api/gemini-channels.js +0 -392
  400. package/src/server/api/gemini-projects.js +0 -103
  401. package/src/server/api/gemini-proxy.js +0 -231
  402. package/src/server/api/gemini-sessions.js +0 -550
  403. package/src/server/api/gemini-statistics.js +0 -57
  404. package/src/server/api/health-check.js +0 -31
  405. package/src/server/api/oauth-credentials.js +0 -198
  406. package/src/server/api/omp-channels.js +0 -575
  407. package/src/server/api/omp-projects.js +0 -88
  408. package/src/server/api/omp-proxy.js +0 -125
  409. package/src/server/api/omp-sessions.js +0 -386
  410. package/src/server/api/omp-statistics.js +0 -40
  411. package/src/server/api/opencode-channels.js +0 -471
  412. package/src/server/api/opencode-projects.js +0 -110
  413. package/src/server/api/opencode-proxy.js +0 -354
  414. package/src/server/api/opencode-sessions.js +0 -466
  415. package/src/server/api/opencode-statistics.js +0 -57
  416. package/src/server/api/projects.js +0 -120
  417. package/src/server/api/proxy.js +0 -330
  418. package/src/server/api/sessions.js +0 -810
  419. package/src/server/services/oauth-credentials-service.js +0 -945
  420. package/src/server/services/omp-session-log-observer.js +0 -138
  421. package/src/server/services/opencode-gateway-adapters.js +0 -43
  422. package/src/server/services/project-snapshots.js +0 -59
  423. package/src/server/services/proxy-log-helper.js +0 -298
  424. package/src/server/services/session-cache.js +0 -127
  425. package/src/server/services/session-converter.js +0 -582
  426. package/src/server/services/session-history-adapters/claude.js +0 -235
  427. /package/src/{server/services/claude-token-recovery.js → platforms/drivers/claude/token-recovery.js} +0 -0
  428. /package/src/{server/services/codex-parser.js → platforms/drivers/codex/parser.js} +0 -0
  429. /package/src/{server/services/codex-speed-test-template.json → platforms/drivers/codex/speed-test-template.json} +0 -0
  430. /package/src/{server/services/codex-wire.js → platforms/drivers/codex/wire.js} +0 -0
  431. /package/src/{server/services/omp-auth-gateway-client.js → platforms/drivers/omp/auth-gateway-client.js} +0 -0
  432. /package/src/{server/services/opencode-normalization.js → platforms/drivers/opencode/normalization.js} +0 -0
  433. /package/src/{server/services → shared}/config-artifact-paths.js +0 -0
  434. /package/src/{server/services/base → shared}/proxy-utils.js +0 -0
@@ -1,550 +0,0 @@
1
- const express = require('express');
2
- const router = express.Router();
3
- const {
4
- getProjectSessions,
5
- getSessionById,
6
- searchSessions,
7
- forkSession,
8
- deleteSession,
9
- getRecentSessions,
10
- saveSessionOrder,
11
- getProjectPath,
12
- getAllSessions
13
- } = require('../services/gemini-sessions');
14
- const { getSessionStatus, getSessionOutline, getMessagePage } = require('../services/session-history-index');
15
- const { isGeminiInstalled } = require('../services/gemini-config');
16
- const { loadAliases } = require('../services/alias');
17
- const {
18
- defaultProjectInfo,
19
- emptySessionList,
20
- getSessionListSnapshot,
21
- invalidateSessionSnapshots,
22
- runSessionSnapshotWorker
23
- } = require('../services/session-snapshots');
24
- const { invalidateProjectSnapshots } = require('../services/project-snapshots');
25
-
26
- function normalizeForkOptions(body = {}) {
27
- const alias = typeof body.alias === 'string' ? body.alias.trim() : '';
28
- const rawNumber = body.afterUserMessageNumber;
29
- const hasExplicitNumber = rawNumber !== undefined && rawNumber !== null && rawNumber !== '';
30
- const parsedNumber = hasExplicitNumber ? parseInt(rawNumber, 10) : null;
31
-
32
- if (hasExplicitNumber && (!Number.isInteger(parsedNumber) || parsedNumber <= 0)) {
33
- const error = new Error('afterUserMessageNumber must be a positive integer');
34
- error.statusCode = 400;
35
- throw error;
36
- }
37
-
38
- return {
39
- afterUserMessageNumber: parsedNumber,
40
- alias: alias || null
41
- };
42
- }
43
-
44
- module.exports = (config) => {
45
- /**
46
- * GET /api/gemini/sessions/search/global?keyword=xxx
47
- * 全局搜索
48
- */
49
- router.get('/search/global', async (req, res) => {
50
- try {
51
- if (!isGeminiInstalled()) {
52
- return res.status(404).json({ error: 'Gemini CLI not installed' });
53
- }
54
-
55
- const { keyword } = req.query;
56
-
57
- if (!keyword) {
58
- return res.status(400).json({ error: 'Keyword is required' });
59
- }
60
-
61
- const results = await searchSessions(keyword);
62
-
63
- res.json({
64
- keyword,
65
- totalMatches: results.reduce((sum, r) => sum + r.matchCount, 0),
66
- sessions: results,
67
- source: 'gemini'
68
- });
69
- } catch (err) {
70
- console.error('[Gemini API] Failed to search sessions:', err);
71
- res.status(500).json({ error: err.message });
72
- }
73
- });
74
-
75
- /**
76
- * GET /api/gemini/sessions/recent/list?limit=10
77
- * 获取最近会话
78
- */
79
- router.get('/recent/list', async (req, res) => {
80
- try {
81
- if (!isGeminiInstalled()) {
82
- return res.status(404).json({ error: 'Gemini CLI not installed' });
83
- }
84
-
85
- const limit = parseInt(req.query.limit) || 5;
86
- const sessions = await getRecentSessions(limit);
87
-
88
- res.json({
89
- sessions,
90
- source: 'gemini'
91
- });
92
- } catch (err) {
93
- console.error('[Gemini API] Failed to get recent sessions:', err);
94
- res.status(500).json({ error: err.message });
95
- }
96
- });
97
-
98
- /**
99
- * GET /api/gemini/sessions/:projectHash
100
- * 获取项目的所有会话
101
- */
102
- router.get('/:projectHash', async (req, res) => {
103
- try {
104
- if (!isGeminiInstalled()) {
105
- return res.status(404).json({ error: 'Gemini CLI not installed' });
106
- }
107
-
108
- const { projectHash } = req.params;
109
- const force = req.query?.fresh === '1';
110
- const snapshot = await getSessionListSnapshot('gemini', projectHash, {
111
- fallbackValue: emptySessionList(projectHash, {
112
- aliases: loadAliases(),
113
- projectInfo: defaultProjectInfo(projectHash)
114
- }),
115
- force,
116
- refresh: () => runSessionSnapshotWorker('gemini', projectHash, {}, { force })
117
- });
118
- res.json({ ...snapshot.value, meta: snapshot.meta });
119
- } catch (err) {
120
- console.error('[Gemini API] Failed to get sessions:', err);
121
- res.status(500).json({ error: err.message });
122
- }
123
- });
124
-
125
- /**
126
- * GET /api/gemini/sessions/:projectHash/search
127
- * 搜索项目内会话内容
128
- */
129
- router.get('/:projectHash/search', async (req, res) => {
130
- try {
131
- if (!isGeminiInstalled()) {
132
- return res.status(404).json({ error: 'Gemini CLI not installed' });
133
- }
134
-
135
- const { projectHash } = req.params;
136
- const { keyword, context } = req.query;
137
-
138
- if (!keyword) {
139
- return res.status(400).json({ error: 'Keyword is required' });
140
- }
141
-
142
- const contextLength = context ? parseInt(context) : 35;
143
-
144
- // 搜索所有会话,然后过滤该项目的会话
145
- const allResults = await searchSessions(keyword, contextLength);
146
- const results = allResults.filter(r => r.projectHash === projectHash);
147
-
148
- res.json({
149
- keyword,
150
- totalMatches: results.reduce((sum, r) => sum + r.matchCount, 0),
151
- sessions: results
152
- });
153
- } catch (err) {
154
- console.error('[Gemini API] Failed to search sessions:', err);
155
- res.status(500).json({ error: err.message });
156
- }
157
- });
158
-
159
- router.get('/:projectHash/:sessionId/status', async (req, res) => {
160
- // Try session-history-index first for fast lookup
161
- try {
162
- const idxStatus = await getSessionStatus('gemini', req.params.sessionId, { consistency: 'stale-ok' });
163
- if (idxStatus) {
164
- return res.json({
165
- sessionId: idxStatus.sessionId,
166
- lastModified: new Date(idxStatus.lastModified).toISOString(),
167
- size: idxStatus.size
168
- });
169
- }
170
- } catch (_) { /* fall through to direct lookup */ }
171
-
172
- try {
173
- if (!isGeminiInstalled()) {
174
- return res.status(404).json({ error: 'Gemini CLI not installed' });
175
- }
176
-
177
- const { sessionId } = req.params;
178
- const session = await getSessionById(sessionId);
179
- if (!session) {
180
- return res.status(404).json({ error: 'Session not found' });
181
- }
182
-
183
- res.json({
184
- sessionId,
185
- lastModified: session.lastUpdated || session.mtime || null,
186
- size: session.size || 0
187
- });
188
- } catch (err) {
189
- console.error('[Gemini API] Failed to get session status:', err);
190
- res.status(500).json({ error: err.message });
191
- }
192
- });
193
-
194
- router.get('/:projectHash/:sessionId/outline', async (req, res) => {
195
- // Try session-history-index first for fast lookup
196
- try {
197
- const idxOutline = await getSessionOutline('gemini', req.params.sessionId, { consistency: 'stale-ok' });
198
- if (idxOutline) {
199
- return res.json({
200
- sessionId: idxOutline.sessionId,
201
- items: idxOutline.items
202
- });
203
- }
204
- } catch (_) { /* fall through to direct read */ }
205
-
206
- try {
207
- if (!isGeminiInstalled()) {
208
- return res.status(404).json({ error: 'Gemini CLI not installed' });
209
- }
210
-
211
- const { sessionId } = req.params;
212
- const session = await getSessionById(sessionId);
213
- if (!session) {
214
- return res.status(404).json({ error: 'Session not found' });
215
- }
216
-
217
- let userMessageNumber = 0;
218
- const items = [];
219
- for (const msg of session.messages || []) {
220
- if (msg.type !== 'user') continue;
221
- const preview = typeof msg.content === 'string' ? msg.content.trim() : '';
222
- if (!preview) continue;
223
- userMessageNumber += 1;
224
- items.push({
225
- userMessageNumber,
226
- preview: preview.length > 42 ? `${preview.slice(0, 42)}...` : preview,
227
- timestamp: msg.timestamp || null
228
- });
229
- }
230
-
231
- res.json({
232
- sessionId,
233
- items
234
- });
235
- } catch (err) {
236
- console.error('[Gemini API] Failed to get session outline:', err);
237
- res.status(500).json({ error: err.message });
238
- }
239
- });
240
-
241
- /**
242
- * GET /api/gemini/sessions/:projectHash/:sessionId/messages
243
- * 获取会话的消息列表
244
- */
245
- router.get('/:projectHash/:sessionId/messages', async (req, res) => {
246
- const startMs = Date.now();
247
- // Try session-history-index first for fast lookup
248
- try {
249
- const { page = 1, limit = 20, order = 'desc' } = req.query;
250
- const pageNum = parseInt(page) || 1;
251
- const limitNum = parseInt(limit) || 20;
252
- const idxPage = await getMessagePage('gemini', req.params.sessionId, {
253
- page: pageNum, limit: limitNum, order
254
- });
255
- if (idxPage) {
256
- return res.json(idxPage);
257
- }
258
- } catch (_) { /* fall through to direct file read */ }
259
-
260
- try {
261
- if (!isGeminiInstalled()) {
262
- return res.status(404).json({ error: 'Gemini CLI not installed' });
263
- }
264
-
265
- const { sessionId } = req.params;
266
- const { page = 1, limit = 20, order = 'desc' } = req.query;
267
-
268
- const session = await getSessionById(sessionId);
269
-
270
- if (!session) {
271
- return res.status(404).json({ error: 'Session not found' });
272
- }
273
-
274
- // 转换消息格式为前端期望的格式
275
- const convertedMessages = [];
276
-
277
- let userMessageNumber = 0;
278
- for (const msg of session.messages || []) {
279
- // 用户消息
280
- if (msg.type === 'user') {
281
- userMessageNumber += 1;
282
- convertedMessages.push({
283
- type: 'user',
284
- content: msg.content || '[空消息]',
285
- timestamp: msg.timestamp,
286
- model: null,
287
- userMessageNumber
288
- });
289
- }
290
- // Gemini 助手消息(type 是 'gemini' 而不是 'assistant')
291
- else if (msg.type === 'gemini' || msg.type === 'assistant') {
292
- let content = msg.content || '[空消息]';
293
-
294
- // 如果有 thoughts(思考过程),添加到内容前面
295
- if (msg.thoughts && Array.isArray(msg.thoughts) && msg.thoughts.length > 0) {
296
- const thoughtsText = msg.thoughts.map(t =>
297
- `**[思考: ${t.subject}]**\n${t.description}`
298
- ).join('\n\n');
299
-
300
- content = `**[思考过程]**\n${thoughtsText}\n\n---\n\n${content}`;
301
- }
302
-
303
- convertedMessages.push({
304
- type: 'assistant',
305
- content,
306
- timestamp: msg.timestamp,
307
- model: msg.model || session.model || 'gemini'
308
- });
309
- }
310
- }
311
-
312
- // 分页处理
313
- const pageNum = parseInt(page);
314
- const limitNum = parseInt(limit);
315
-
316
- // 排序
317
- let messages = convertedMessages;
318
- if (order === 'desc') {
319
- messages = [...messages].reverse();
320
- }
321
-
322
- // 分页
323
- const totalMessages = messages.length;
324
- const start = (pageNum - 1) * limitNum;
325
- const end = start + limitNum;
326
- const paginatedMessages = messages.slice(start, end);
327
-
328
- res.json({
329
- messages: paginatedMessages,
330
- metadata: {
331
- gitBranch: null,
332
- gitRepository: null,
333
- cwd: null,
334
- model: session.model || 'gemini'
335
- },
336
- pagination: {
337
- page: pageNum,
338
- limit: limitNum,
339
- total: totalMessages,
340
- hasMore: end < totalMessages
341
- }
342
- });
343
- } catch (err) {
344
- console.error('[Gemini API] Failed to get session messages:', err);
345
- res.status(500).json({ error: err.message });
346
- }
347
- });
348
-
349
- /**
350
- * DELETE /api/gemini/sessions/:projectHash/:sessionId
351
- * 删除会话
352
- */
353
- router.delete('/:projectHash/:sessionId', (req, res) => {
354
- try {
355
- if (!isGeminiInstalled()) {
356
- return res.status(404).json({ error: 'Gemini CLI not installed' });
357
- }
358
-
359
- const { sessionId } = req.params;
360
- const result = deleteSession(sessionId);
361
- invalidateSessionSnapshots('gemini', req.params.projectHash);
362
- invalidateProjectSnapshots('gemini');
363
-
364
- res.json(result);
365
- } catch (err) {
366
- console.error('[Gemini API] Failed to delete session:', err);
367
- res.status(500).json({ error: err.message });
368
- }
369
- });
370
-
371
- /**
372
- * POST /api/gemini/sessions/:projectHash/batch-delete
373
- * 批量删除会话
374
- */
375
- router.post('/:projectHash/batch-delete', (req, res) => {
376
- try {
377
- if (!isGeminiInstalled()) {
378
- return res.status(404).json({ error: 'Gemini CLI not installed' });
379
- }
380
-
381
- const { sessionIds } = req.body || {};
382
- if (!Array.isArray(sessionIds) || sessionIds.length === 0) {
383
- return res.status(400).json({ error: 'sessionIds must be a non-empty array' });
384
- }
385
-
386
- const uniqueSessionIds = Array.from(new Set(
387
- sessionIds
388
- .filter(sessionId => typeof sessionId === 'string')
389
- .map(sessionId => sessionId.trim())
390
- .filter(Boolean)
391
- ));
392
-
393
- if (uniqueSessionIds.length === 0) {
394
- return res.status(400).json({ error: 'sessionIds must be a non-empty array' });
395
- }
396
-
397
- const deletedSessionIds = [];
398
- const failed = [];
399
-
400
- uniqueSessionIds.forEach((sessionId) => {
401
- try {
402
- deleteSession(sessionId);
403
- deletedSessionIds.push(sessionId);
404
- } catch (err) {
405
- failed.push({
406
- sessionId,
407
- error: err.message
408
- });
409
- }
410
- });
411
-
412
- if (deletedSessionIds.length > 0) {
413
- invalidateSessionSnapshots('gemini', req.params.projectHash);
414
- invalidateProjectSnapshots('gemini');
415
- }
416
-
417
- res.json({
418
- success: failed.length === 0,
419
- requestedCount: uniqueSessionIds.length,
420
- deletedCount: deletedSessionIds.length,
421
- deletedSessionIds,
422
- failed
423
- });
424
- } catch (err) {
425
- console.error('[Gemini API] Failed to batch delete sessions:', err);
426
- res.status(500).json({ error: err.message });
427
- }
428
- });
429
-
430
- /**
431
- * POST /api/gemini/sessions/:projectHash/:sessionId/fork
432
- * Fork 一个会话
433
- */
434
- router.post('/:projectHash/:sessionId/fork', (req, res) => {
435
- try {
436
- if (!isGeminiInstalled()) {
437
- return res.status(404).json({ error: 'Gemini CLI not installed' });
438
- }
439
-
440
- const { sessionId } = req.params;
441
- const result = forkSession(sessionId, normalizeForkOptions(req.body));
442
- invalidateSessionSnapshots('gemini', req.params.projectHash);
443
- invalidateProjectSnapshots('gemini');
444
-
445
- res.json(result);
446
- } catch (err) {
447
- console.error('[Gemini API] Failed to fork session:', err);
448
- res.status(err.statusCode || 500).json({ error: err.message });
449
- }
450
- });
451
-
452
- /**
453
- * POST /api/gemini/sessions/:projectHash/order
454
- * 保存会话排序
455
- */
456
- router.post('/:projectHash/order', (req, res) => {
457
- try {
458
- if (!isGeminiInstalled()) {
459
- return res.status(404).json({ error: 'Gemini CLI not installed' });
460
- }
461
-
462
- const { projectHash } = req.params;
463
- const { order } = req.body;
464
-
465
- if (!Array.isArray(order)) {
466
- return res.status(400).json({ error: 'order must be an array' });
467
- }
468
-
469
- saveSessionOrder(projectHash, order);
470
- invalidateSessionSnapshots('gemini', projectHash);
471
-
472
- res.json({ success: true });
473
- } catch (err) {
474
- console.error('[Gemini API] Failed to save session order:', err);
475
- res.status(500).json({ error: err.message });
476
- }
477
- });
478
-
479
- /**
480
- * POST /api/gemini/sessions/:projectHash/:sessionId/launch
481
- * 获取会话启动命令(用于复制)
482
- */
483
- router.post('/:projectHash/:sessionId/launch', async (req, res) => {
484
- try {
485
- if (!isGeminiInstalled()) {
486
- return res.status(404).json({ error: 'Gemini CLI not installed' });
487
- }
488
-
489
- const { projectHash, sessionId } = req.params;
490
-
491
- // 获取会话详情
492
- const session = await getSessionById(sessionId);
493
-
494
- if (!session) {
495
- return res.status(404).json({ error: 'Session not found' });
496
- }
497
-
498
- // 使用彩虹表方法获取项目路径
499
- const projectPath = getProjectPath(projectHash);
500
-
501
- if (!projectPath) {
502
- return res.status(400).json({
503
- error: 'Could not resolve project path. The original directory may have been moved or deleted.'
504
- });
505
- }
506
-
507
- // 获取该项目的所有会话文件,按 startTime 升序排列(与 gemini --list-sessions 一致)
508
- const allSessions = getAllSessions()
509
- .filter(s => s.projectHash === projectHash)
510
- .sort((a, b) => new Date(a.startTime) - new Date(b.startTime));
511
-
512
- // 找到该 sessionId 对应的最新文件的索引
513
- // 注意:同一个 sessionId 可能有多个文件(继续对话),我们要找最新的那个
514
- let sessionIndex = -1;
515
- for (let i = allSessions.length - 1; i >= 0; i--) {
516
- if (allSessions[i].sessionId === sessionId) {
517
- sessionIndex = i;
518
- break;
519
- }
520
- }
521
-
522
- if (sessionIndex === -1) {
523
- return res.status(404).json({ error: 'Session not found in project sessions list' });
524
- }
525
-
526
- // Gemini 的索引从 1 开始
527
- const resumeIndex = sessionIndex + 1;
528
-
529
- // 构建 Gemini CLI 命令(使用 --resume <index> 恢复特定会话)
530
- const command = `gemini --resume ${resumeIndex}`;
531
- const quotedCwd = `"${String(projectPath).replace(/"/g, '\\"')}"`;
532
- const copyCommand = `cd ${quotedCwd} && ${command}`;
533
-
534
- res.json({
535
- success: true,
536
- sessionId,
537
- projectPath,
538
- cwd: projectPath,
539
- tool: 'gemini',
540
- command,
541
- copyCommand
542
- });
543
- } catch (err) {
544
- console.error('[Gemini API] Failed to prepare launch command:', err);
545
- res.status(500).json({ error: err.message });
546
- }
547
- });
548
-
549
- return router;
550
- };
@@ -1,57 +0,0 @@
1
- const express = require('express');
2
- const router = express.Router();
3
- const {
4
- getStatistics,
5
- getDailyStatistics,
6
- getTodayStatistics
7
- } = require('../services/gemini-statistics-service');
8
-
9
- /**
10
- * 获取 Gemini 总体统计数据
11
- * GET /api/gemini/statistics/summary
12
- */
13
- router.get('/summary', (req, res) => {
14
- try {
15
- const stats = getStatistics();
16
- res.json(stats);
17
- } catch (error) {
18
- console.error('[Gemini] Failed to get statistics:', error);
19
- res.status(500).json({ error: 'Failed to get statistics' });
20
- }
21
- });
22
-
23
- /**
24
- * 获取 Gemini 今日统计数据
25
- * GET /api/gemini/statistics/today
26
- */
27
- router.get('/today', (req, res) => {
28
- try {
29
- const stats = getTodayStatistics();
30
- res.json(stats);
31
- } catch (error) {
32
- console.error('[Gemini] Failed to get today statistics:', error);
33
- res.status(500).json({ error: 'Failed to get today statistics' });
34
- }
35
- });
36
-
37
- /**
38
- * 获取 Gemini 指定日期的统计数据
39
- * GET /api/gemini/statistics/daily/:date
40
- */
41
- router.get('/daily/:date', (req, res) => {
42
- try {
43
- const { date } = req.params;
44
-
45
- if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
46
- return res.status(400).json({ error: 'Invalid date format. Expected YYYY-MM-DD' });
47
- }
48
-
49
- const stats = getDailyStatistics(date);
50
- res.json(stats);
51
- } catch (error) {
52
- console.error('[Gemini] Failed to get daily statistics:', error);
53
- res.status(500).json({ error: 'Failed to get daily statistics' });
54
- }
55
- });
56
-
57
- module.exports = router;
@@ -1,31 +0,0 @@
1
- const express = require('express');
2
- const router = express.Router();
3
- const { healthCheckAllProjects } = require('../services/health-check');
4
- const { getProjects } = require('../services/sessions');
5
-
6
- module.exports = (config) => {
7
- /**
8
- * GET /api/health-check - 健康检查所有项目
9
- */
10
- router.get('/', async (req, res) => {
11
- try {
12
- const projects = await getProjects(config);
13
- const projectList = Array.isArray(projects) ? projects : [];
14
- const result = healthCheckAllProjects(projectList);
15
-
16
- res.json({
17
- success: true,
18
- timestamp: new Date().toISOString(),
19
- ...result
20
- });
21
- } catch (error) {
22
- console.error('Health check failed:', error);
23
- res.status(500).json({
24
- success: false,
25
- error: error.message
26
- });
27
- }
28
- });
29
-
30
- return router;
31
- };