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,506 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const crypto = require('crypto');
4
+ const { PATHS } = require('../config/paths');
5
+ const {
6
+ inspectTool,
7
+ SUPPORTED_TOOLS,
8
+ fingerprintFor,
9
+ readAllNativeOAuth
10
+ } = require('./native-oauth-adapters');
11
+ const { maskToken } = require('../server/services/oauth-utils');
12
+
13
+ function createEmptyStore() {
14
+ return {
15
+ version: 1,
16
+ tools: Object.fromEntries(SUPPORTED_TOOLS.map((tool) => [tool, {
17
+ defaultCredentialId: null,
18
+ credentials: []
19
+ }]))
20
+ };
21
+ }
22
+
23
+ function ensureStoreDir() {
24
+ fs.mkdirSync(path.dirname(PATHS.oauthCredentials), { recursive: true });
25
+ }
26
+
27
+ function readStore() {
28
+ ensureStoreDir();
29
+ if (!fs.existsSync(PATHS.oauthCredentials)) {
30
+ return createEmptyStore();
31
+ }
32
+
33
+ try {
34
+ const payload = JSON.parse(fs.readFileSync(PATHS.oauthCredentials, 'utf8'));
35
+ const next = createEmptyStore();
36
+ if (payload && typeof payload === 'object' && payload.tools && typeof payload.tools === 'object') {
37
+ SUPPORTED_TOOLS.forEach((tool) => {
38
+ const rawToolData = payload.tools[tool];
39
+ if (!rawToolData || typeof rawToolData !== 'object') {
40
+ return;
41
+ }
42
+ next.tools[tool] = {
43
+ defaultCredentialId: rawToolData.defaultCredentialId || null,
44
+ credentials: Array.isArray(rawToolData.credentials) ? rawToolData.credentials : []
45
+ };
46
+ });
47
+ }
48
+ return next;
49
+ } catch {
50
+ return createEmptyStore();
51
+ }
52
+ }
53
+
54
+ function writeStore(store) {
55
+ ensureStoreDir();
56
+ fs.writeFileSync(PATHS.oauthCredentials, JSON.stringify(store, null, 2), 'utf8');
57
+ if (process.platform !== 'win32') {
58
+ try {
59
+ fs.chmodSync(PATHS.oauthCredentials, 0o600);
60
+ } catch {
61
+ // ignore chmod failures
62
+ }
63
+ }
64
+ }
65
+
66
+ function assertSupportedTool(tool) {
67
+ if (!SUPPORTED_TOOLS.includes(tool)) {
68
+ throw new Error(`Unsupported OAuth tool: ${tool}`);
69
+ }
70
+ }
71
+
72
+ function safeString(value) {
73
+ return String(value || '').trim();
74
+ }
75
+
76
+
77
+ function buildCredentialName(tool, metadata, providedName = '') {
78
+ const explicit = safeString(providedName);
79
+ if (explicit) {
80
+ return explicit;
81
+ }
82
+
83
+ if (tool === 'omp' && safeString(metadata.providerId)) {
84
+ const accountLabel = safeString(metadata.accountId || metadata.accountEmail);
85
+ return accountLabel
86
+ ? `${tool} - ${metadata.providerId} - ${accountLabel}`
87
+ : `${tool} - ${metadata.providerId}`;
88
+ }
89
+
90
+ const accountLabel = safeString(metadata.accountId || metadata.accountEmail);
91
+ if (accountLabel) {
92
+ return `${tool} - ${accountLabel}`;
93
+ }
94
+
95
+ return `${tool} - ${new Date().toISOString().slice(0, 10)}`;
96
+ }
97
+
98
+ function sanitizeCredential(entry, defaultCredentialId) {
99
+ const primaryToken = entry?.secrets?.primaryToken
100
+ || entry?.secrets?.accessToken
101
+ || entry?.secrets?.token
102
+ || '';
103
+
104
+ return {
105
+ id: entry.id,
106
+ tool: entry.tool,
107
+ name: entry.name,
108
+ source: entry.source,
109
+ storage: entry.storage || '',
110
+ providerId: entry.providerId || '',
111
+ accountId: entry.accountId || '',
112
+ accountEmail: entry.accountEmail || '',
113
+ expiresAt: entry.expiresAt || null,
114
+ lastRefresh: entry.lastRefresh || null,
115
+ lastUsedAt: entry.lastUsedAt || null,
116
+ createdAt: entry.createdAt,
117
+ updatedAt: entry.updatedAt,
118
+ tokenPreview: maskToken(primaryToken),
119
+ isDefault: defaultCredentialId === entry.id
120
+ };
121
+ }
122
+
123
+ function sanitizeNativeCredential(entry = {}) {
124
+ const primaryToken = entry.primaryToken
125
+ || entry.accessToken
126
+ || entry.token
127
+ || '';
128
+
129
+ return {
130
+ providerId: entry.providerId || '',
131
+ accountId: entry.accountId || '',
132
+ accountEmail: entry.accountEmail || '',
133
+ expiresAt: entry.expiresAt || null,
134
+ lastRefresh: entry.lastRefresh || null,
135
+ storage: entry.storage || '',
136
+ tokenPreview: maskToken(primaryToken)
137
+ };
138
+ }
139
+
140
+ function sanitizeToolSummary(tool, toolStore) {
141
+ const credentials = (toolStore.credentials || [])
142
+ .map((entry) => sanitizeCredential(entry, toolStore.defaultCredentialId))
143
+ .sort((a, b) => {
144
+ const aTime = a.lastUsedAt || 0;
145
+ const bTime = b.lastUsedAt || 0;
146
+ if (aTime !== bTime) return bTime - aTime;
147
+ return (b.createdAt || 0) - (a.createdAt || 0);
148
+ });
149
+ const nativeState = inspectTool(tool);
150
+ const nativeCredentials = readAllNativeOAuth(tool).map((entry) => sanitizeNativeCredential(entry));
151
+ return {
152
+ tool,
153
+ defaultCredentialId: toolStore.defaultCredentialId || null,
154
+ credentials,
155
+ nativeState: {
156
+ ...nativeState,
157
+ nativeCredentials
158
+ }
159
+ };
160
+ }
161
+
162
+ function getToolStore(store, tool) {
163
+ assertSupportedTool(tool);
164
+ if (!store.tools[tool]) {
165
+ store.tools[tool] = { defaultCredentialId: null, credentials: [] };
166
+ }
167
+ return store.tools[tool];
168
+ }
169
+
170
+ function extractSecrets(tool, metadata) {
171
+ // 只保留真正的 secret 字段,不污染非敏感数据
172
+ switch (tool) {
173
+ case 'claude':
174
+ return {
175
+ accessToken: metadata.accessToken || '',
176
+ refreshToken: metadata.refreshToken || '',
177
+ expiresAt: metadata.expiresAt || null,
178
+ primaryToken: metadata.primaryToken || metadata.accessToken || ''
179
+ };
180
+ case 'codex':
181
+ return {
182
+ authMode: metadata.authMode || 'chatgpt',
183
+ accessToken: metadata.accessToken || '',
184
+ refreshToken: metadata.refreshToken || '',
185
+ idToken: metadata.idToken || '',
186
+ accountId: metadata.accountId || '',
187
+ lastRefresh: metadata.lastRefresh || null,
188
+ primaryToken: metadata.primaryToken || metadata.accessToken || ''
189
+ };
190
+ case 'gemini':
191
+ return {
192
+ accessToken: metadata.accessToken || '',
193
+ refreshToken: metadata.refreshToken || '',
194
+ tokenType: metadata.tokenType || 'Bearer',
195
+ scope: metadata.scope || '',
196
+ expiresAt: metadata.expiresAt || null,
197
+ primaryToken: metadata.primaryToken || metadata.accessToken || ''
198
+ };
199
+ case 'omp':
200
+ return {
201
+ providerId: metadata.providerId || '',
202
+ credentialType: metadata.credentialType || 'oauth',
203
+ accessToken: metadata.accessToken || '',
204
+ refreshToken: metadata.refreshToken || '',
205
+ expiresAt: metadata.expiresAt || null,
206
+ accountId: metadata.accountId || '',
207
+ accountEmail: metadata.accountEmail || '',
208
+ identityKey: metadata.identityKey || '',
209
+ importPayload: metadata.importPayload || null,
210
+ primaryToken: metadata.primaryToken || metadata.accessToken || ''
211
+ };
212
+ default:
213
+ return { primaryToken: metadata.primaryToken || metadata.accessToken || '' };
214
+ }
215
+ }
216
+
217
+ function stableFingerprintValue(tool, metadata) {
218
+ // 优先使用稳定标识符,避免 access token 轮换导致重复记录
219
+ const stableId = metadata.accountEmail
220
+ || metadata.accountId
221
+ || (tool === 'omp' ? metadata.providerId : '')
222
+ || metadata.refreshToken
223
+ || metadata.primaryToken
224
+ || metadata.accessToken
225
+ || '';
226
+ return stableId;
227
+ }
228
+
229
+ function resolveFingerprintValue(tool, metadata, options = {}) {
230
+ if (options.fingerprintMode === 'primary-token') {
231
+ return metadata.primaryToken
232
+ || metadata.accessToken
233
+ || stableFingerprintValue(tool, metadata);
234
+ }
235
+ return stableFingerprintValue(tool, metadata);
236
+ }
237
+
238
+ function upsertCredential(tool, metadata, options = {}) {
239
+ const store = readStore();
240
+ const toolStore = getToolStore(store, tool);
241
+ const now = Date.now();
242
+ const primaryToken = metadata.primaryToken || metadata.accessToken || '';
243
+ const fingerprint = fingerprintFor(tool, resolveFingerprintValue(tool, metadata, options));
244
+ const existingIndex = toolStore.credentials.findIndex((item) => item.fingerprint === fingerprint);
245
+ const existing = existingIndex >= 0 ? toolStore.credentials[existingIndex] : null;
246
+
247
+ const entry = {
248
+ id: existing?.id || crypto.randomUUID(),
249
+ tool,
250
+ name: buildCredentialName(tool, metadata, options.name),
251
+ source: options.source || existing?.source || 'manual',
252
+ storage: metadata.storage || existing?.storage || '',
253
+ providerId: metadata.providerId || existing?.providerId || '',
254
+ accountId: metadata.accountId || existing?.accountId || '',
255
+ accountEmail: metadata.accountEmail || existing?.accountEmail || '',
256
+ expiresAt: metadata.expiresAt || existing?.expiresAt || null,
257
+ lastRefresh: metadata.lastRefresh || existing?.lastRefresh || null,
258
+ createdAt: existing?.createdAt || now,
259
+ updatedAt: now,
260
+ fingerprint,
261
+ secrets: extractSecrets(tool, { ...existing?.secrets, ...metadata, primaryToken })
262
+ };
263
+
264
+ if (existingIndex >= 0) {
265
+ toolStore.credentials.splice(existingIndex, 1, entry);
266
+ } else {
267
+ toolStore.credentials.unshift(entry);
268
+ }
269
+
270
+ if (!toolStore.defaultCredentialId) {
271
+ toolStore.defaultCredentialId = entry.id;
272
+ }
273
+
274
+ writeStore(store);
275
+ return sanitizeCredential(entry, toolStore.defaultCredentialId);
276
+ }
277
+
278
+
279
+ function getToolSummary(tool) {
280
+ const store = readStore();
281
+ const toolStore = getToolStore(store, tool);
282
+ return sanitizeToolSummary(tool, toolStore);
283
+ }
284
+
285
+
286
+ function syncLocalCredential(tool) {
287
+ assertSupportedTool(tool);
288
+ const nativeCredentials = readAllNativeOAuth(tool);
289
+ if (!nativeCredentials.length) {
290
+ throw new Error('当前本地未检测到可同步的 OAuth 凭证。');
291
+ }
292
+
293
+ const credentials = nativeCredentials.map((metadata) => upsertCredential(tool, metadata, {
294
+ source: 'synced-local',
295
+ fingerprintMode: 'primary-token'
296
+ }));
297
+
298
+ return {
299
+ credential: credentials[0] || null,
300
+ credentials,
301
+ summary: getToolSummary(tool)
302
+ };
303
+ }
304
+
305
+
306
+ function findStoredCredential(tool, credentialId) {
307
+ const store = readStore();
308
+ const toolStore = getToolStore(store, tool);
309
+ const entry = toolStore.credentials.find((item) => item.id === credentialId);
310
+ if (!entry) {
311
+ throw new Error('OAuth 凭证不存在。');
312
+ }
313
+ return entry;
314
+ }
315
+
316
+
317
+ function httpGet(url, headers = {}) {
318
+ return new Promise((resolve, reject) => {
319
+ const https = require('https');
320
+ const urlObj = new URL(url);
321
+ const options = {
322
+ hostname: urlObj.hostname,
323
+ path: urlObj.pathname + urlObj.search,
324
+ method: 'GET',
325
+ headers,
326
+ timeout: 15000
327
+ };
328
+ const req = https.request(options, (res) => {
329
+ let body = '';
330
+ res.on('data', (chunk) => { body += chunk; });
331
+ res.on('end', () => resolve({ statusCode: res.statusCode, body }));
332
+ });
333
+ req.on('error', reject);
334
+ req.on('timeout', () => { req.destroy(); reject(new Error('请求超时')); });
335
+ req.end();
336
+ });
337
+ }
338
+
339
+ function httpPost(url, body, headers = {}) {
340
+ return new Promise((resolve, reject) => {
341
+ const https = require('https');
342
+ const urlObj = new URL(url);
343
+ const options = {
344
+ hostname: urlObj.hostname,
345
+ path: urlObj.pathname + urlObj.search,
346
+ method: 'POST',
347
+ headers: { ...headers, 'Content-Length': Buffer.byteLength(body) },
348
+ timeout: 15000
349
+ };
350
+ const req = https.request(options, (res) => {
351
+ let data = '';
352
+ res.on('data', (chunk) => { data += chunk; });
353
+ res.on('end', () => resolve({ statusCode: res.statusCode, body: data }));
354
+ });
355
+ req.on('error', reject);
356
+ req.on('timeout', () => { req.destroy(); reject(new Error('请求超时')); });
357
+ req.write(body);
358
+ req.end();
359
+ });
360
+ }
361
+
362
+ async function fetchClaudeUsage(accessToken) {
363
+ try {
364
+ const result = await httpGet('https://api.anthropic.com/api/oauth/usage', {
365
+ 'Authorization': `Bearer ${accessToken}`,
366
+ 'anthropic-beta': 'oauth-2025-04-20',
367
+ 'anthropic-version': '2023-06-01',
368
+ 'User-Agent': 'claude-cli/1.0'
369
+ });
370
+ const data = JSON.parse(result.body);
371
+ return { raw: data, provider: 'claude', statusCode: result.statusCode };
372
+ } catch (err) {
373
+ return { error: err.message, provider: 'claude' };
374
+ }
375
+ }
376
+
377
+ async function fetchCodexUsage(accessToken) {
378
+ // Codex uses JWT id_token; decode it to extract user info directly
379
+ try {
380
+ const { decodeJwtPayload } = require('../server/services/oauth-utils');
381
+ const payload = decodeJwtPayload(accessToken);
382
+ if (payload && (payload.email || payload.sub)) {
383
+ return {
384
+ raw: {
385
+ email: payload.email || '',
386
+ accountId: payload.sub || '',
387
+ name: payload.name || ''
388
+ },
389
+ provider: 'codex',
390
+ statusCode: 200
391
+ };
392
+ }
393
+ } catch (_) {
394
+ // fall through to API call
395
+ }
396
+ try {
397
+ const result = await httpGet('https://api.openai.com/v1/me', {
398
+ 'Authorization': `Bearer ${accessToken}`,
399
+ 'User-Agent': 'openai-node/4.0.0'
400
+ });
401
+ const data = JSON.parse(result.body);
402
+ return { raw: data, provider: 'codex', statusCode: result.statusCode };
403
+ } catch (err) {
404
+ return { error: err.message, provider: 'codex' };
405
+ }
406
+ }
407
+
408
+ async function fetchGeminiUsage(accessToken) {
409
+ try {
410
+ const body = JSON.stringify({
411
+ metadata: {
412
+ ideType: 'ANTIGRAVITY',
413
+ platform: 'PLATFORM_UNSPECIFIED',
414
+ pluginType: 'GEMINI'
415
+ }
416
+ });
417
+ const result = await httpPost('https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist', body, {
418
+ 'Authorization': `Bearer ${accessToken}`,
419
+ 'Content-Type': 'application/json',
420
+ 'User-Agent': 'google-api-nodejs-client/9.15.1',
421
+ 'X-Goog-Api-Client': 'google-cloud-sdk vscode_cloudshelleditor/0.1',
422
+ 'Client-Metadata': '{"ideType":"IDE_UNSPECIFIED","platform":"PLATFORM_UNSPECIFIED","pluginType":"GEMINI"}'
423
+ });
424
+ const data = JSON.parse(result.body);
425
+ return { raw: data, provider: 'gemini', statusCode: result.statusCode };
426
+ } catch (err) {
427
+ return { error: err.message, provider: 'gemini' };
428
+ }
429
+ }
430
+
431
+ function clampPercent(value) {
432
+ const number = Number(value);
433
+ if (!Number.isFinite(number)) return null;
434
+ const percent = number >= 0 && number <= 1 ? number * 100 : number;
435
+ return Math.max(0, Math.min(100, percent));
436
+ }
437
+
438
+ function normalizeWindow(window, label) {
439
+ if (!window || typeof window !== 'object') return null;
440
+ const usedPercent = clampPercent(window.used_percent ?? window.utilization);
441
+ if (usedPercent === null) return null;
442
+ return {
443
+ label,
444
+ remainingPercent: Math.max(0, Math.min(100, 100 - usedPercent)),
445
+ usedPercent,
446
+ resetsAt: window.reset_at || window.resetAt || null
447
+ };
448
+ }
449
+
450
+ function normalizeOAuthQuota(tool, raw) {
451
+ const value = raw && typeof raw === 'object' ? raw : {};
452
+ let primary = normalizeWindow(value.five_hour || value.fiveHour, '5h');
453
+ let secondary = normalizeWindow(value.seven_day || value.sevenDay, '7d');
454
+ const rateLimit = value.rate_limit || value.rateLimit;
455
+ if (rateLimit) {
456
+ primary = primary || normalizeWindow(rateLimit.primary_window || rateLimit.primaryWindow, '5h');
457
+ secondary = secondary || normalizeWindow(rateLimit.secondary_window || rateLimit.secondaryWindow, '7d');
458
+ }
459
+ if (!primary && !secondary) {
460
+ return { quota: null, status: 'unsupported', warning: `${tool}: provider did not return 5h/7d quota windows` };
461
+ }
462
+ return { quota: { status: 'available', primary, secondary }, status: 'available' };
463
+ }
464
+
465
+ async function fetchCredentialUsage(tool, credentialId) {
466
+ const entry = findStoredCredential(tool, credentialId);
467
+ const secrets = entry.secrets || {};
468
+ const accessToken = secrets.accessToken || secrets.primaryToken || '';
469
+ if (!accessToken) return { error: '无有效 token' };
470
+
471
+ let response;
472
+ switch (tool) {
473
+ case 'claude':
474
+ response = await fetchClaudeUsage(accessToken);
475
+ break;
476
+ case 'codex':
477
+ response = await fetchCodexUsage(secrets.idToken || accessToken);
478
+ break;
479
+ case 'gemini':
480
+ response = await fetchGeminiUsage(accessToken);
481
+ break;
482
+ case 'omp': {
483
+ const providerId = entry.providerId || secrets.providerId || '';
484
+ response = providerId.includes('claude') || providerId.includes('anthropic')
485
+ ? await fetchClaudeUsage(accessToken)
486
+ : providerId.includes('gemini') || providerId.includes('google')
487
+ ? await fetchGeminiUsage(accessToken)
488
+ : await fetchCodexUsage(accessToken);
489
+ break;
490
+ }
491
+ default:
492
+ return { quota: null, status: 'unsupported', error: `不支持的工具: ${tool}` };
493
+ }
494
+ if (response?.error) return { quota: null, status: 'unavailable', error: response.error };
495
+ if (response?.statusCode === 401 || response?.statusCode === 403) {
496
+ return { quota: null, status: 'unauthorized', error: '上游 OAuth 授权已失效' };
497
+ }
498
+ return normalizeOAuthQuota(tool, response?.raw);
499
+ }
500
+
501
+ module.exports = {
502
+ SUPPORTED_TOOLS,
503
+ syncLocalCredential,
504
+ normalizeOAuthQuota,
505
+ fetchCredentialUsage
506
+ };
@@ -0,0 +1,179 @@
1
+ 'use strict';
2
+
3
+ const os = require('os');
4
+ const path = require('path');
5
+ const { execFileSync } = require('child_process');
6
+
7
+ function resolveTemplate(value, resolved) {
8
+ return String(value)
9
+ .replace(/\$([A-Z][A-Z0-9_]*)/g, (_, name) => resolved.env[name] || '')
10
+ .replace(/\{home\}/g, resolved.home);
11
+ }
12
+
13
+ function isBareEnvReference(value) {
14
+ return /^\$[A-Z][A-Z0-9_]*$/.test(String(value));
15
+ }
16
+
17
+ function loadNativePathResolvers() {
18
+ return require('../config/paths');
19
+ }
20
+
21
+ function resolveDefaultHomeDir() {
22
+ try {
23
+ const configured = loadNativePathResolvers().HOME_DIR;
24
+ if (typeof configured === 'string' && configured.trim()) return configured;
25
+ } catch {
26
+ // Fall through to the shared home-directory resolver.
27
+ }
28
+ try {
29
+ const { resolvePreferredHomeDir } = require('../utils/home-dir');
30
+ if (typeof resolvePreferredHomeDir === 'function') {
31
+ return resolvePreferredHomeDir(process.platform, process.env, os.homedir());
32
+ }
33
+ } catch {
34
+ // Fall through to the operating-system home directory.
35
+ }
36
+ return os.homedir();
37
+ }
38
+
39
+ function resolveExistingEnvPath(envValue) {
40
+ if (typeof envValue !== 'string') return '';
41
+ return envValue.trim() || '';
42
+ }
43
+
44
+ function expandUserHome(value, homeDir) {
45
+ if (value === '~') return homeDir;
46
+ if (value.startsWith('~/') || value.startsWith('~\\')) return path.join(homeDir, value.slice(2));
47
+ return value;
48
+ }
49
+
50
+ function normalizeOmpProfileName(profile = '') {
51
+ const value = String(profile || '').trim();
52
+ return value && value !== 'default' ? value : '';
53
+ }
54
+
55
+ function resolveInjectedOmpHome(env, commandRunner, homeDir, hasInjectedHomeDir, hasInjectedCommandRunner) {
56
+ if (hasInjectedCommandRunner) {
57
+ const command = String(env.OMP_COMMAND || 'omp').trim() || 'omp';
58
+ try {
59
+ const output = commandRunner(command, ['config', 'path'], {
60
+ encoding: 'utf8',
61
+ env: { ...process.env, ...env },
62
+ stdio: ['ignore', 'pipe', 'pipe'],
63
+ timeout: 3000,
64
+ windowsHide: true
65
+ });
66
+ const configuredByCli = String(output || '').trim().split(/\r?\n/).find(Boolean);
67
+ if (configuredByCli) return path.resolve(expandUserHome(configuredByCli, homeDir));
68
+ } catch {
69
+ // Fall through to injected environment/profile paths.
70
+ }
71
+ }
72
+
73
+ const configuredDir = resolveExistingEnvPath(env.PI_CODING_AGENT_DIR || env.OMP_CODING_AGENT_DIR);
74
+ if (configuredDir) return path.resolve(expandUserHome(configuredDir, homeDir));
75
+
76
+ const hasInjectedOmpEnv = Boolean(env.OMP_CONFIG_DIR || env.PI_CODING_AGENT_DIR || env.OMP_CODING_AGENT_DIR || env.OMP_PROFILE);
77
+ if (!hasInjectedHomeDir && !hasInjectedOmpEnv && !hasInjectedCommandRunner) return undefined;
78
+ const profile = normalizeOmpProfileName(env.OMP_PROFILE);
79
+ const configRoot = expandUserHome(resolveExistingEnvPath(env.OMP_CONFIG_DIR) || path.join(homeDir, '.omp'), homeDir);
80
+ return path.resolve(profile ? path.join(configRoot, 'profiles', profile, 'agent') : path.join(configRoot, 'agent'));
81
+ }
82
+
83
+ function resolveNativeHome(pathResolverId, env, commandRunner, homeDir, hasInjectedHomeDir, hasInjectedCommandRunner) {
84
+ if (pathResolverId === 'declarative') return undefined;
85
+ if (pathResolverId === 'omp') {
86
+ const injectedOmpHome = resolveInjectedOmpHome(env, commandRunner, homeDir, hasInjectedHomeDir, hasInjectedCommandRunner);
87
+ if (injectedOmpHome) return injectedOmpHome;
88
+ }
89
+ if (hasInjectedHomeDir && pathResolverId !== 'omp') {
90
+ switch (pathResolverId) {
91
+ case 'claude': return env.CLAUDE_CONFIG_DIR || path.join(homeDir, '.claude');
92
+ case 'codex': return env.CODEX_HOME || path.join(homeDir, '.codex');
93
+ case 'gemini': return path.join(homeDir, '.gemini');
94
+ case 'opencode': return path.join(homeDir, '.config', 'opencode');
95
+ default: return undefined;
96
+ }
97
+ }
98
+ const resolvers = loadNativePathResolvers();
99
+ const configuredNativePaths = resolvers.NATIVE_PATHS || {};
100
+ const getClaudeConfigDir = typeof resolvers.getClaudeConfigDir === 'function'
101
+ ? resolvers.getClaudeConfigDir
102
+ : () => configuredNativePaths.claude?.dir
103
+ || path.join(homeDir, '.claude');
104
+ const getCodexDir = typeof resolvers.getCodexDir === 'function'
105
+ ? resolvers.getCodexDir
106
+ : () => configuredNativePaths.codex?.dir
107
+ || path.join(homeDir, '.codex');
108
+ const getGeminiDir = typeof resolvers.getGeminiDir === 'function'
109
+ ? resolvers.getGeminiDir
110
+ : () => configuredNativePaths.gemini?.dir
111
+ || path.join(homeDir, '.gemini');
112
+ const getOpenCodeConfigDir = typeof resolvers.getOpenCodeConfigDir === 'function'
113
+ ? resolvers.getOpenCodeConfigDir
114
+ : () => configuredNativePaths.opencode?.config
115
+ || path.join(homeDir, '.config', 'opencode');
116
+ const getOpenCodeDataDir = typeof resolvers.getOpenCodeDataDir === 'function'
117
+ ? resolvers.getOpenCodeDataDir
118
+ : () => configuredNativePaths.opencode?.data
119
+ || path.join(homeDir, '.local', 'share', 'opencode');
120
+ const getOmpAgentDir = typeof resolvers.getOmpAgentDir === 'function'
121
+ ? resolvers.getOmpAgentDir
122
+ : () => configuredNativePaths.omp?.dir
123
+ || path.join(homeDir, '.omp', 'agent');
124
+ switch (pathResolverId) {
125
+ case 'claude': return env.CLAUDE_CONFIG_DIR || getClaudeConfigDir();
126
+ case 'codex': return env.CODEX_HOME || getCodexDir();
127
+ case 'gemini': return getGeminiDir();
128
+ case 'opencode': return getOpenCodeConfigDir() || getOpenCodeDataDir();
129
+ case 'omp': return getOmpAgentDir(env, { commandRunner });
130
+ default: return undefined;
131
+ }
132
+ }
133
+
134
+ function assertInsideHome(root, candidate, manifestKey, pathName) {
135
+ const relative = path.relative(root, candidate);
136
+ if (relative === '..' || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
137
+ throw new Error(`Manifest ${manifestKey || 'platform'} path ${pathName} escapes home`);
138
+ }
139
+ }
140
+
141
+ function resolveManifestPaths(manifest, options = {}) {
142
+ const env = { ...process.env, ...(options.env || {}) };
143
+ const hasInjectedHomeDir = Object.prototype.hasOwnProperty.call(options, 'homeDir');
144
+ const homeDir = options.homeDir || resolveDefaultHomeDir();
145
+ const commandRunner = options.commandRunner || execFileSync;
146
+ const nativeHome = resolveNativeHome(manifest.pathResolverId || 'declarative', env, commandRunner, homeDir, hasInjectedHomeDir, Object.prototype.hasOwnProperty.call(options, 'commandRunner'));
147
+ const declared = manifest.paths || {};
148
+ const homeValue = declared.home || nativeHome || homeDir;
149
+ const resolved = { env, home: '' };
150
+ const expand = (value, { allowRelativeHomeFallback = true } = {}) => {
151
+ let result = resolveTemplate(value, resolved);
152
+ if (!result) return '';
153
+ if (result === '~') result = homeDir;
154
+ else if (result.startsWith('~/') || result.startsWith('~\\')) result = path.join(homeDir, result.slice(2));
155
+ else if (!path.isAbsolute(result) && allowRelativeHomeFallback) result = path.join(resolved.home || homeDir, result);
156
+ return path.normalize(result);
157
+ };
158
+ const homeSource = String(homeValue);
159
+ const rawHome = resolveTemplate(homeValue, resolved);
160
+ const explicitHomeRoot = path.isAbsolute(homeSource) || (isBareEnvReference(homeSource) && path.isAbsolute(rawHome));
161
+ resolved.home = expand(homeValue);
162
+ if (!resolved.home) throw new Error(`Manifest ${manifest.key || 'platform'} requires a non-empty home path`);
163
+ if (!explicitHomeRoot) assertInsideHome(homeDir, resolved.home, manifest.key, 'home');
164
+ const paths = {};
165
+ for (const [name, value] of Object.entries(declared)) {
166
+ const explicitAbsolute = path.isAbsolute(String(value));
167
+ const raw = resolveTemplate(value, resolved);
168
+ const isUrl = /^[a-z][a-z0-9+.-]*:\/\//i.test(raw);
169
+ const candidate = isUrl ? raw : expand(raw);
170
+ if (name !== 'home' && !explicitAbsolute && !isUrl) {
171
+ assertInsideHome(resolved.home, candidate, manifest.key, name);
172
+ }
173
+ paths[name] = candidate;
174
+ }
175
+ if (!Object.prototype.hasOwnProperty.call(paths, 'home')) paths.home = resolved.home;
176
+ return paths;
177
+ }
178
+
179
+ module.exports = { resolveManifestPaths, resolveTemplate };