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
@@ -6,35 +6,110 @@
6
6
 
7
7
  const fs = require('fs');
8
8
  const path = require('path');
9
- const os = require('os');
10
- const { NATIVE_PATHS, PATHS } = require('../../config/paths');
11
- const { resolvePreferredHomeDir } = require('../../utils/home-dir');
12
-
13
- const HOME_DIR = resolvePreferredHomeDir(process.platform, process.env, os.homedir());
9
+ const { PATHS } = require('../../config/paths');
14
10
 
15
11
  // Prompts 配置文件路径
16
12
  const PROMPTS_FILE = PATHS.prompts;
17
13
 
18
- // 各平台提示词文件路径
19
- const CLAUDE_CONFIG_DIR = NATIVE_PATHS.claude.dir || path.dirname(NATIVE_PATHS.claude.settings);
20
- const CLAUDE_PROMPT_PATH = NATIVE_PATHS.claude.prompt || path.join(CLAUDE_CONFIG_DIR, 'CLAUDE.md');
21
- const CODEX_PROMPT_PATH = path.join(HOME_DIR, '.codex', 'AGENTS.md');
22
- const GEMINI_PROMPT_PATH = path.join(HOME_DIR, '.gemini', 'GEMINI.md');
23
- const OPENCODE_PROMPT_PATH = path.join(NATIVE_PATHS.opencode.config, 'AGENTS.md');
24
- const OMP_PROMPTS_DIR = NATIVE_PATHS.omp?.prompts
25
- || path.join(NATIVE_PATHS.omp?.dir || path.join(HOME_DIR, '.omp', 'agent'), 'prompts');
26
- const MANAGED_OMP_PROMPTS_DIR = path.join(OMP_PROMPTS_DIR, 'coding-tool-x');
27
-
28
- function normalizeApps(apps = {}, defaults = { claude: true, codex: true, gemini: true, opencode: false, omp: false }) {
14
+
15
+ function normalizePlatformKey(platform) {
16
+ return String(platform || '').trim().toLowerCase();
17
+ }
18
+
19
+ function getPlatformServices() {
20
+ const { registry, runtime } = require('../platform-context').getPlatformContext();
29
21
  return {
30
- claude: apps.claude !== undefined ? !!apps.claude : defaults.claude,
31
- codex: apps.codex !== undefined ? !!apps.codex : defaults.codex,
32
- gemini: apps.gemini !== undefined ? !!apps.gemini : defaults.gemini,
33
- opencode: apps.opencode !== undefined ? !!apps.opencode : defaults.opencode,
34
- omp: apps.omp !== undefined ? !!apps.omp: defaults.omp
22
+ registry,
23
+ runtime
35
24
  };
36
25
  }
37
26
 
27
+ function getPromptPlatformKeys() {
28
+ const { registry } = getPlatformServices();
29
+ const keys = [];
30
+ const seen = new Set();
31
+
32
+ for (const platform of registry.list()) {
33
+ const key = normalizePlatformKey(platform.key);
34
+ if (!key || seen.has(key)) continue;
35
+ const driverId = registry.getCapability(key, 'prompts');
36
+ if (!driverId || driverId === 'unsupported') continue;
37
+ seen.add(key);
38
+ keys.push(key);
39
+ }
40
+
41
+ return keys;
42
+ }
43
+
44
+ function createPlatformCapabilityError(platform, capability, code) {
45
+ const key = normalizePlatformKey(platform);
46
+ const error = new Error(code === 'not_found'
47
+ ? `无效的平台: ${key}`
48
+ : `平台 ${key} 未声明 ${capability} capability`);
49
+ error.status = 404;
50
+ error.code = code;
51
+ error.platform = key;
52
+ error.capability = capability;
53
+ return error;
54
+ }
55
+
56
+ function requirePromptCapability(platform) {
57
+ const key = normalizePlatformKey(platform);
58
+ const { registry, runtime } = getPlatformServices();
59
+ if (!registry.resolve(key)) {
60
+ throw createPlatformCapabilityError(key, 'prompts', 'not_found');
61
+ }
62
+ const driverId = registry.getCapability(key, 'prompts');
63
+ if (!driverId || driverId === 'unsupported') {
64
+ throw createPlatformCapabilityError(key, 'prompts', 'unsupported');
65
+ }
66
+ const driver = runtime.getDriver(key, 'prompts');
67
+ if (!driver) {
68
+ throw createPlatformCapabilityError(key, 'prompts', 'unsupported');
69
+ }
70
+ return { platform: key, driver, driverId };
71
+ }
72
+
73
+ function getDriverFailure(result, platform, operation) {
74
+ if (!result || result.status !== 'failed' || result.capability !== 'prompts') return null;
75
+ if (result.cause instanceof Error) return result.cause;
76
+ return new Error(result.error || `Prompt ${operation} failed for ${platform}`);
77
+ }
78
+
79
+ function assertPromptReadResult(result, platform) {
80
+ const failure = getDriverFailure(result, platform, 'read');
81
+ if (failure) throw failure;
82
+ const content = result?.status === 'ok' ? result.data : result;
83
+ if (typeof content !== 'string') throw new Error(`平台 ${platform} 的提示词内容无效`);
84
+ return content;
85
+ }
86
+
87
+
88
+ function normalizeApps(apps = {}, defaults = {
89
+ claude: true,
90
+ codex: true,
91
+ gemini: true,
92
+ opencode: false,
93
+ omp: false
94
+ }) {
95
+ const source = apps && typeof apps === 'object' && !Array.isArray(apps) ? apps : {};
96
+ const fallback = defaults && typeof defaults === 'object' && !Array.isArray(defaults) ? defaults : {};
97
+ const platformKeys = new Set(getPromptPlatformKeys());
98
+ const normalized = {};
99
+
100
+ for (const platform of platformKeys) {
101
+ normalized[platform] = source[platform] !== undefined
102
+ ? !!source[platform]
103
+ : !!fallback[platform];
104
+ }
105
+
106
+ // Preserve historical flags for platforms absent from the current registry.
107
+ for (const [platform, enabled] of Object.entries(source)) {
108
+ if (!platformKeys.has(platform)) normalized[platform] = !!enabled;
109
+ }
110
+ return normalized;
111
+ }
112
+
38
113
  // 内置模板(不是"默认",只是可选模板)
39
114
  const BUILTIN_TEMPLATES = [
40
115
  {
@@ -142,44 +217,6 @@ function writeJsonFile(filePath, data) {
142
217
  fs.renameSync(tempPath, filePath);
143
218
  }
144
219
 
145
- /**
146
- * 安全读取文本文件
147
- */
148
- function readTextFile(filePath, defaultValue = '') {
149
- try {
150
- if (fs.existsSync(filePath)) {
151
- return fs.readFileSync(filePath, 'utf-8');
152
- }
153
- } catch (err) {
154
- console.error(`[Prompts] Failed to read ${filePath}:`, err.message);
155
- }
156
- return defaultValue;
157
- }
158
-
159
- /**
160
- * 安全写入文本文件(原子写入)
161
- */
162
- function writeTextFile(filePath, content) {
163
- ensureDir(path.dirname(filePath));
164
- const tempPath = filePath + '.tmp';
165
- fs.writeFileSync(tempPath, content, 'utf-8');
166
- fs.renameSync(tempPath, filePath);
167
- }
168
-
169
- /**
170
- * 删除文件(如果存在)
171
- */
172
- function deleteFile(filePath) {
173
- try {
174
- if (fs.existsSync(filePath)) {
175
- fs.unlinkSync(filePath);
176
- return true;
177
- }
178
- } catch (err) {
179
- console.error(`[Prompts] Failed to delete ${filePath}:`, err.message);
180
- }
181
- return false;
182
- }
183
220
 
184
221
  // ============================================================================
185
222
  // Prompts 数据管理
@@ -208,8 +245,9 @@ function initPromptsData() {
208
245
  };
209
246
  });
210
247
 
211
- // 检查用户是否已有提示词文件,如果有则导入为"当前使用"
212
- const existingContent = readTextFile(CLAUDE_PROMPT_PATH, '');
248
+ const existingContent = getPromptPlatformKeys().includes('claude')
249
+ ? readPlatformPrompt('claude')
250
+ : '';
213
251
  if (existingContent.trim()) {
214
252
  const currentPreset = {
215
253
  id: 'current',
@@ -233,14 +271,13 @@ function initPromptsData() {
233
271
  let updated = false;
234
272
  for (const preset of Object.values(data.presets || {})) {
235
273
  const normalizedApps = normalizeApps(preset.apps);
236
- if (
237
- !preset.apps ||
238
- preset.apps.claude !== normalizedApps.claude ||
239
- preset.apps.codex !== normalizedApps.codex ||
240
- preset.apps.gemini !== normalizedApps.gemini ||
241
- preset.apps.opencode !== normalizedApps.opencode
242
- || preset.apps.omp !== normalizedApps.omp
243
- ) {
274
+ const sourceApps = preset.apps && typeof preset.apps === 'object' && !Array.isArray(preset.apps)
275
+ ? preset.apps
276
+ : {};
277
+ const needsNormalization = Object.entries(normalizedApps).some(
278
+ ([platform, enabled]) => sourceApps[platform] !== enabled
279
+ );
280
+ if (needsNormalization) {
244
281
  preset.apps = normalizedApps;
245
282
  updated = true;
246
283
  }
@@ -333,10 +370,10 @@ function savePreset(preset) {
333
370
  writeJsonFile(PROMPTS_FILE, data);
334
371
 
335
372
  if (wasActive) {
336
- if (existing && normalizeApps(existing.apps).omp && !preset.apps.omp) {
337
- deleteOmpPromptTemplate(existing);
373
+ const syncResult = syncPresetToAllPlatforms(preset);
374
+ if (syncResult && typeof syncResult.then === 'function') {
375
+ return syncResult.then(() => preset);
338
376
  }
339
- syncPresetToAllPlatforms(preset);
340
377
  }
341
378
 
342
379
  return preset;
@@ -362,10 +399,6 @@ function deletePreset(id) {
362
399
  data.activePresetId = null;
363
400
  }
364
401
 
365
- if (normalizeApps(preset.apps).omp) {
366
- deleteOmpPromptTemplate(preset);
367
- }
368
-
369
402
  delete data.presets[id];
370
403
  writeJsonFile(PROMPTS_FILE, data);
371
404
 
@@ -378,7 +411,6 @@ function deletePreset(id) {
378
411
  async function activatePreset(id) {
379
412
  const data = initPromptsData();
380
413
  const preset = data.presets[id];
381
- const previousPreset = data.activePresetId ? data.presets[data.activePresetId] : null;
382
414
 
383
415
  if (!preset) {
384
416
  throw new Error(`预设 "${id}" 不存在`);
@@ -388,10 +420,6 @@ async function activatePreset(id) {
388
420
  data.activePresetId = id;
389
421
  writeJsonFile(PROMPTS_FILE, data);
390
422
 
391
- if (previousPreset && previousPreset.id !== id && normalizeApps(previousPreset.apps).omp) {
392
- deleteOmpPromptTemplate(previousPreset);
393
- }
394
-
395
423
  // 同步到各平台
396
424
  await syncPresetToAllPlatforms(preset);
397
425
 
@@ -403,25 +431,36 @@ async function activatePreset(id) {
403
431
  */
404
432
  async function deactivatePrompt() {
405
433
  const data = initPromptsData();
406
- const activePreset = data.activePresetId ? data.presets[data.activePresetId] : null;
407
434
 
408
- // 清空激活状态
435
+ // Clear active state.
409
436
  data.activePresetId = null;
410
437
  writeJsonFile(PROMPTS_FILE, data);
411
438
 
412
- // 删除各平台的提示词文件
413
- const results = {
414
- claude: deleteFile(CLAUDE_PROMPT_PATH),
415
- codex: deleteFile(CODEX_PROMPT_PATH),
416
- gemini: deleteFile(GEMINI_PROMPT_PATH),
417
- opencode: deleteFile(OPENCODE_PROMPT_PATH),
418
- omp: activePreset && normalizeApps(activePreset.apps).omp
419
- ? deleteOmpPromptTemplate(activePreset)
420
- : false
421
- };
439
+ const results = {};
440
+ const pending = [];
441
+ for (const platform of getPromptPlatformKeys()) {
442
+ const { driver } = requirePromptCapability(platform);
443
+ if (typeof driver.remove !== 'function') {
444
+ const error = createPlatformCapabilityError(platform, 'prompts', 'unsupported');
445
+ error.operation = 'remove';
446
+ throw error;
447
+ }
448
+ const result = driver.remove();
449
+ if (result && typeof result.then === 'function') {
450
+ pending.push(result.then(value => {
451
+ const failure = getDriverFailure(value, platform, 'remove');
452
+ if (failure) throw failure;
453
+ results[platform] = true;
454
+ }));
455
+ } else {
456
+ const failure = getDriverFailure(result, platform, 'remove');
457
+ if (failure) throw failure;
458
+ results[platform] = true;
459
+ }
460
+ }
422
461
 
462
+ await Promise.all(pending);
423
463
  console.log('[Prompts] Deactivated and removed prompt files:', results);
424
-
425
464
  return results;
426
465
  }
427
466
 
@@ -432,183 +471,176 @@ async function deactivatePrompt() {
432
471
  /**
433
472
  * 同步预设到所有已启用的平台
434
473
  */
435
- function syncPresetToAllPlatforms(preset) {
436
- const apps = normalizeApps(preset.apps);
437
- const { content } = preset;
438
-
439
- if (apps.claude) {
440
- writeTextFile(CLAUDE_PROMPT_PATH, content);
441
- console.log('[Prompts] Synced to Claude:', CLAUDE_PROMPT_PATH);
474
+ function syncPromptToPlatform(platform, content) {
475
+ const { driver } = requirePromptCapability(platform);
476
+ if (typeof driver.write !== 'function') {
477
+ const error = createPlatformCapabilityError(platform, 'prompts', 'unsupported');
478
+ error.operation = 'write';
479
+ throw error;
442
480
  }
443
481
 
444
- if (apps.codex) {
445
- writeTextFile(CODEX_PROMPT_PATH, content);
446
- console.log('[Prompts] Synced to Codex:', CODEX_PROMPT_PATH);
447
- }
448
-
449
- if (apps.gemini) {
450
- writeTextFile(GEMINI_PROMPT_PATH, content);
451
- console.log('[Prompts] Synced to Gemini:', GEMINI_PROMPT_PATH);
452
- }
453
-
454
- if (apps.opencode) {
455
- writeTextFile(OPENCODE_PROMPT_PATH, content);
456
- console.log('[Prompts] Synced to OpenCode:', OPENCODE_PROMPT_PATH);
457
- }
458
-
459
- if (apps.omp) {
460
- const targetPath = writeOmpPromptTemplate(preset);
461
- console.log('[Prompts] Synced to OMP:', targetPath);
482
+ const result = driver.write(content);
483
+ if (result && typeof result.then === 'function') {
484
+ return result.then(value => {
485
+ const failure = getDriverFailure(value, platform, 'write');
486
+ if (failure) throw failure;
487
+ return value;
488
+ });
462
489
  }
490
+ return result;
463
491
  }
464
492
 
465
- function buildOmpPromptFileName(preset) {
466
- const rawId = (preset?.id || 'preset').toString().trim();
467
- const safeId = rawId.replace(/[^a-zA-Z0-9_-]/g, '-').replace(/-+/g, '-').slice(0, 100) || 'preset';
468
- return `${safeId}.md`;
469
- }
470
-
471
- function getOmpPromptTemplatePath(preset) {
472
- return path.join(MANAGED_OMP_PROMPTS_DIR, buildOmpPromptFileName(preset));
473
- }
493
+ /**
494
+ * 同步预设到所有已启用的平台
495
+ */
496
+ function syncPresetToAllPlatforms(preset) {
497
+ const apps = normalizeApps(preset.apps);
498
+ const { content } = preset;
499
+ const pending = [];
500
+
501
+ for (const platform of getPromptPlatformKeys()) {
502
+ if (!apps[platform]) continue;
503
+ const result = syncPromptToPlatform(platform, content);
504
+ if (result && typeof result.then === 'function') {
505
+ pending.push(result.then(() => {
506
+ console.log(`[Prompts] Synced to ${platform}`);
507
+ }));
508
+ } else {
509
+ console.log(`[Prompts] Synced to ${platform}`);
510
+ }
511
+ }
474
512
 
475
- function escapeFrontmatterValue(value) {
476
- return String(value || '')
477
- .replace(/\\/g, '\\\\')
478
- .replace(/"/g, '\\"')
479
- .replace(/\r?\n/g, ' ');
480
- }
481
513
 
482
- function buildOmpPromptTemplateContent(preset) {
483
- const description = escapeFrontmatterValue(preset.description || preset.name || preset.id);
484
- return `---\ndescription: "${description}"\n---\n\n${preset.content || ''}`;
514
+ return pending.length ? Promise.all(pending) : undefined;
485
515
  }
486
516
 
487
- function writeOmpPromptTemplate(preset) {
488
- const filePath = getOmpPromptTemplatePath(preset);
489
- writeTextFile(filePath, buildOmpPromptTemplateContent(preset));
490
- return filePath;
491
- }
492
-
493
- function deleteOmpPromptTemplate(preset) {
494
- return deleteFile(getOmpPromptTemplatePath(preset));
495
- }
496
517
 
497
518
  /**
498
519
  * 从平台读取当前提示词
499
520
  */
500
521
  function readPlatformPrompt(platform) {
501
- switch (platform) {
502
- case 'claude':
503
- return readTextFile(CLAUDE_PROMPT_PATH, '');
504
- case 'codex':
505
- return readTextFile(CODEX_PROMPT_PATH, '');
506
- case 'gemini':
507
- return readTextFile(GEMINI_PROMPT_PATH, '');
508
- case 'opencode':
509
- return readTextFile(OPENCODE_PROMPT_PATH, '');
510
- case 'omp':
511
- throw new Error('OMP 使用 prompts/ 目录中的模板文件,请通过平台状态查看模板列表');
512
- default:
513
- throw new Error(`无效的平台: ${platform}`);
522
+ const { platform: normalizedPlatform, driver } = requirePromptCapability(platform);
523
+ if (typeof driver.read !== 'function') {
524
+ const error = createPlatformCapabilityError(normalizedPlatform, 'prompts', 'unsupported');
525
+ error.operation = 'read';
526
+ throw error;
527
+ }
528
+
529
+ const result = driver.read();
530
+ if (result && typeof result.then === 'function') {
531
+ return result.then(value => assertPromptReadResult(value, normalizedPlatform));
514
532
  }
533
+ return assertPromptReadResult(result, normalizedPlatform);
515
534
  }
516
535
 
517
- function listOmpPromptTemplates() {
518
- if (!fs.existsSync(OMP_PROMPTS_DIR)) {
519
- return [];
520
- }
521
-
522
- const results = [];
523
- const walk = (dir) => {
524
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
525
- if (entry.name.startsWith('.')) continue;
526
- const fullPath = path.join(dir, entry.name);
527
- if (entry.isDirectory()) {
528
- walk(fullPath);
529
- } else if (entry.isFile() && path.extname(entry.name).toLowerCase() === '.md') {
530
- const relativePath = path.relative(OMP_PROMPTS_DIR, fullPath);
531
- results.push({
532
- name: path.basename(entry.name, '.md'),
533
- path: fullPath,
534
- relativePath,
535
- managed: relativePath.split(path.sep)[0] === 'coding-tool-x'
536
- });
537
- }
538
- }
539
- };
536
+ function writePlatformPrompt(platform, content) {
537
+ if (typeof content !== 'string') {
538
+ throw new Error('提示词内容必须是字符串');
539
+ }
540
540
 
541
- try {
542
- walk(OMP_PROMPTS_DIR);
543
- } catch (err) {
544
- console.error(`[Prompts] Failed to list OMP prompt templates:`, err.message);
541
+ const { platform: normalizedPlatform, driver } = requirePromptCapability(platform);
542
+ if (typeof driver.write !== 'function') {
543
+ const error = createPlatformCapabilityError(normalizedPlatform, 'prompts', 'unsupported');
544
+ error.operation = 'write';
545
+ throw error;
546
+ }
547
+
548
+ const result = driver.write(content);
549
+ if (result && typeof result.then === 'function') {
550
+ return result.then(value => {
551
+ const failure = getDriverFailure(value, normalizedPlatform, 'write');
552
+ if (failure) throw failure;
553
+ return content;
554
+ });
555
+ }
556
+ return result;
557
+ }
558
+
559
+ function removePlatformPrompt(platform) {
560
+ const { platform: normalizedPlatform, driver } = requirePromptCapability(platform);
561
+ if (typeof driver.remove !== 'function') {
562
+ const error = createPlatformCapabilityError(normalizedPlatform, 'prompts', 'unsupported');
563
+ error.operation = 'remove';
564
+ throw error;
545
565
  }
546
566
 
547
- return results.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
567
+ const result = driver.remove();
568
+ if (result && typeof result.then === 'function') {
569
+ return result.then(value => {
570
+ const failure = getDriverFailure(value, normalizedPlatform, 'remove');
571
+ if (failure) throw failure;
572
+ return true;
573
+ });
574
+ }
575
+ return result;
548
576
  }
549
577
 
578
+
550
579
  /**
551
580
  * 获取各平台当前的提示词状态
552
581
  */
553
582
  function getPlatformStatus() {
554
- return {
555
- claude: {
556
- path: CLAUDE_PROMPT_PATH,
557
- exists: fs.existsSync(CLAUDE_PROMPT_PATH),
558
- content: readTextFile(CLAUDE_PROMPT_PATH, '')
559
- },
560
- codex: {
561
- path: CODEX_PROMPT_PATH,
562
- exists: fs.existsSync(CODEX_PROMPT_PATH),
563
- content: readTextFile(CODEX_PROMPT_PATH, '')
564
- },
565
- gemini: {
566
- path: GEMINI_PROMPT_PATH,
567
- exists: fs.existsSync(GEMINI_PROMPT_PATH),
568
- content: readTextFile(GEMINI_PROMPT_PATH, '')
569
- },
570
- opencode: {
571
- path: OPENCODE_PROMPT_PATH,
572
- exists: fs.existsSync(OPENCODE_PROMPT_PATH),
573
- content: readTextFile(OPENCODE_PROMPT_PATH, '')
574
- },
575
- omp: {
576
- path: OMP_PROMPTS_DIR,
577
- managedPath: MANAGED_OMP_PROMPTS_DIR,
578
- exists: fs.existsSync(OMP_PROMPTS_DIR),
579
- templates: listOmpPromptTemplates()
583
+ const statuses = {};
584
+ const pending = [];
585
+
586
+ for (const platform of getPromptPlatformKeys()) {
587
+ const { driver } = requirePromptCapability(platform);
588
+ if (typeof driver.read !== 'function') {
589
+ const error = createPlatformCapabilityError(platform, 'prompts', 'unsupported');
590
+ error.operation = 'read';
591
+ throw error;
580
592
  }
581
- };
593
+ const pathValue = typeof driver.path === 'string' ? driver.path : null;
594
+ const result = driver.read();
595
+ const apply = value => {
596
+ const failure = getDriverFailure(value, platform, 'read');
597
+ if (failure) throw failure;
598
+ const content = assertPromptReadResult(value, platform);
599
+ statuses[platform] = {
600
+ ...(pathValue ? { path: pathValue } : {}),
601
+ exists: pathValue ? fs.existsSync(pathValue) : Boolean(content),
602
+ content
603
+ };
604
+ };
605
+ if (result && typeof result.then === 'function') pending.push(result.then(apply));
606
+ else apply(result);
607
+ }
608
+
609
+ return pending.length ? Promise.all(pending).then(() => statuses) : statuses;
582
610
  }
583
611
 
584
612
  /**
585
613
  * 从平台导入提示词作为新预设
586
614
  */
587
615
  function importFromPlatform(platform, presetName) {
588
- const content = readPlatformPrompt(platform);
616
+ const normalizedPlatform = requirePromptCapability(platform).platform;
617
+ const contentResult = readPlatformPrompt(normalizedPlatform);
589
618
 
590
- if (!content.trim()) {
591
- throw new Error(`${platform} 的提示词文件为空`);
592
- }
619
+ const createPreset = content => {
620
+ if (!content.trim()) {
621
+ throw new Error(`${normalizedPlatform} 的提示词文件为空`);
622
+ }
593
623
 
594
- // 生成唯一 ID
595
- const id = `imported-${platform}-${Date.now()}`;
624
+ const id = `imported-${normalizedPlatform}-${Date.now()}`;
625
+ const emptyApps = Object.fromEntries(getPromptPlatformKeys().map(key => [key, false]));
626
+ const preset = {
627
+ id,
628
+ name: presetName || `从 ${normalizedPlatform} 导入`,
629
+ description: `从 ${normalizedPlatform} 导入的提示词`,
630
+ content,
631
+ apps: normalizeApps(emptyApps),
632
+ isBuiltin: false,
633
+ createdAt: Date.now(),
634
+ updatedAt: Date.now()
635
+ };
596
636
 
597
- const preset = {
598
- id,
599
- name: presetName || `从 ${platform} 导入`,
600
- description: `从 ${platform} 导入的提示词`,
601
- content,
602
- apps: normalizeApps({ claude: false, codex: false, gemini: false, opencode: false, omp: false }),
603
- isBuiltin: false,
604
- createdAt: Date.now(),
605
- updatedAt: Date.now()
637
+ preset.apps[normalizedPlatform] = true;
638
+ return savePreset(preset);
606
639
  };
607
640
 
608
- // 标记来源平台
609
- preset.apps[platform] = true;
610
-
611
- return savePreset(preset);
641
+ return contentResult && typeof contentResult.then === 'function'
642
+ ? contentResult.then(createPreset)
643
+ : createPreset(contentResult);
612
644
  }
613
645
 
614
646
  /**
@@ -635,6 +667,8 @@ module.exports = {
635
667
  activatePreset,
636
668
  deactivatePrompt,
637
669
  readPlatformPrompt,
670
+ writePlatformPrompt,
671
+ removePlatformPrompt,
638
672
  getPlatformStatus,
639
673
  importFromPlatform,
640
674
  getStats
@@ -1,6 +1,6 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const { PATHS } = require('../../config/paths');
3
+ const { PATHS, getPlatformStatePath } = require('../../config/paths');
4
4
 
5
5
  const LOG_RECOVERY_BYTES = 1024 * 1024;
6
6
  const LOG_FILE_PATH = path.join(PATHS.logs, 'cc-tool-out.log');
@@ -19,8 +19,8 @@ const PROXY_START_LOG_PATTERNS = {
19
19
  };
20
20
 
21
21
  function getRuntimeFilePath(proxyType) {
22
- const filePath = PATHS.proxyRuntime?.[proxyType]
23
- || path.join(path.dirname(PATHS.proxyRuntime.claude), `${proxyType}-proxy.json`);
22
+ const filePath = getPlatformStatePath('proxyRuntime', proxyType);
23
+ if (!filePath) return null;
24
24
  const dir = path.dirname(filePath);
25
25
  if (!fs.existsSync(dir)) {
26
26
  fs.mkdirSync(dir, { recursive: true });
@@ -31,6 +31,7 @@ function getRuntimeFilePath(proxyType) {
31
31
  function saveProxyStartTime(proxyType, preserveExisting = false) {
32
32
  try {
33
33
  const filePath = getRuntimeFilePath(proxyType);
34
+ if (!filePath) return null;
34
35
  if (preserveExisting && fs.existsSync(filePath)) {
35
36
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
36
37
  }
@@ -58,6 +59,7 @@ function persistRecoveredStartTime(proxyType, startTime, recoveredFrom) {
58
59
  }
59
60
 
60
61
  const runtimeFilePath = getRuntimeFilePath(proxyType);
62
+ if (!runtimeFilePath) return null;
61
63
  const data = {
62
64
  startTime: validStartTime,
63
65
  type: proxyType,
@@ -70,6 +72,7 @@ function persistRecoveredStartTime(proxyType, startTime, recoveredFrom) {
70
72
  function readStoredProxyStartTime(proxyType) {
71
73
  try {
72
74
  const filePath = getRuntimeFilePath(proxyType);
75
+ if (!filePath) return null;
73
76
  if (!fs.existsSync(filePath)) return null;
74
77
  const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
75
78
  return toValidStartTime(data.startTime);
@@ -136,7 +139,7 @@ function recoverProxyStartTime(proxyType) {
136
139
  return logRecoveredStartTime;
137
140
  }
138
141
 
139
- const activeChannelPath = PATHS.activeChannel?.[proxyType];
142
+ const activeChannelPath = getPlatformStatePath('activeChannel', proxyType);
140
143
  if (!activeChannelPath || !fs.existsSync(activeChannelPath)) {
141
144
  return null;
142
145
  }