coding-tool-x 3.8.4 → 3.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (434) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +86 -15
  3. package/dist/web/assets/AgentsDrawer-BG6P3DX-.js +1 -0
  4. package/dist/web/assets/AgentsDrawer-Pw2k-ZAa.css +1 -0
  5. package/dist/web/assets/Analytics--z_FmL5P.js +1 -0
  6. package/dist/web/assets/Analytics-CyHhR126.css +1 -0
  7. package/dist/web/assets/AssetPathField-CrJtRKHy.js +1 -0
  8. package/dist/web/assets/ChatHistoryDrawer-B2qBQs9L.css +1 -0
  9. package/dist/web/assets/ChatHistoryDrawer-BiuEryJj.js +1 -0
  10. package/dist/web/assets/CollapseItem-BAYEsL_Q.js +1 -0
  11. package/dist/web/assets/CommandsDrawer-BZJxlPvV.css +1 -0
  12. package/dist/web/assets/CommandsDrawer-YJ-U7BXN.js +1 -0
  13. package/dist/web/assets/ConfigExportDrawer-Ce_hAknW.js +1 -0
  14. package/dist/web/assets/ConfigExportDrawer-dwruRKWr.css +1 -0
  15. package/dist/web/assets/ConfigTemplates-Bvr1NN6K.js +1 -0
  16. package/dist/web/assets/ConfigTemplatesDrawer-BfDi8yO3.css +1 -0
  17. package/dist/web/assets/ConfigTemplatesDrawer-BjIeHfF-.js +1 -0
  18. package/dist/web/assets/ConfigTemplatesPanel-AV00tm_D.js +1 -0
  19. package/dist/web/assets/ConfigTemplatesPanel-CWyPtk67.css +1 -0
  20. package/dist/web/assets/Divider-D28g1gwj.js +1 -0
  21. package/dist/web/assets/DrawerContent-ChXgZ1Xm.js +1 -0
  22. package/dist/web/assets/FavoritesDrawer-CG9eI9Ay.css +1 -0
  23. package/dist/web/assets/FavoritesDrawer-Cz95o4CD.js +1 -0
  24. package/dist/web/assets/GatewayConvertDrawer-CuNlf7AC.css +1 -0
  25. package/dist/web/assets/GatewayConvertDrawer-DLlbMz27.js +1 -0
  26. package/dist/web/assets/Home-CSuFuJ9Y.css +1 -0
  27. package/dist/web/assets/Home-D7CCOFQC.js +1 -0
  28. package/dist/web/assets/MarkdownEditor-qfVgSre_.css +1 -0
  29. package/dist/web/assets/MarkdownEditor-rEZ-c72L.js +1 -0
  30. package/dist/web/assets/McpDrawer-C0dnsZhQ.css +1 -0
  31. package/dist/web/assets/McpDrawer-DfoCyxU2.js +1 -0
  32. package/dist/web/assets/McpFormDrawer-BRbDcawn.css +1 -0
  33. package/dist/web/assets/McpFormDrawer-SKu8HNUR.js +1 -0
  34. package/dist/web/assets/PluginManager-BbeK-3rV.js +1 -0
  35. package/dist/web/assets/PluginsDrawer-CWVJ7yjS.js +1 -0
  36. package/dist/web/assets/PluginsDrawer-DM3QjprE.css +1 -0
  37. package/dist/web/assets/PluginsPanel-Cm2N3StG.js +1 -0
  38. package/dist/web/assets/PluginsPanel-D6ZqITcR.css +1 -0
  39. package/dist/web/assets/ProjectList-677RLZ8O.css +1 -0
  40. package/dist/web/assets/ProjectList-CsjnsNPv.js +1 -0
  41. package/dist/web/assets/PromptsDrawer-BIgiYCEQ.css +1 -0
  42. package/dist/web/assets/PromptsDrawer-EGd3djFa.js +1 -0
  43. package/dist/web/assets/RecentSessionsDrawer-CKFsOYDM.css +1 -0
  44. package/dist/web/assets/RecentSessionsDrawer-D1vtoLAs.js +1 -0
  45. package/dist/web/assets/SessionCard-BgLg49U3.js +1 -0
  46. package/dist/web/assets/SessionCard-aM2NHu6i.css +1 -0
  47. package/dist/web/assets/SessionList-BpYRz1cX.css +1 -0
  48. package/dist/web/assets/SessionList-TRiTklWk.js +1 -0
  49. package/dist/web/assets/SettingsDrawer-d5liXjHq.css +1 -0
  50. package/dist/web/assets/SettingsDrawer-rz2WejGY.js +1 -0
  51. package/dist/web/assets/SkillManager-BTjTUbHq.js +1 -0
  52. package/dist/web/assets/SkillManager-C0GCT2Kb.css +1 -0
  53. package/dist/web/assets/SkillsDrawer-BCNme-aJ.css +1 -0
  54. package/dist/web/assets/SkillsDrawer-pN0hbkK3.js +1 -0
  55. package/dist/web/assets/SkillsPanel-B3Nm5j32.css +1 -0
  56. package/dist/web/assets/SkillsPanel-gmBWEoiF.js +1 -0
  57. package/dist/web/assets/SpeedTestDrawer-Dc0WToJ_.css +1 -0
  58. package/dist/web/assets/SpeedTestDrawer-DcNzuVJk.js +1 -0
  59. package/dist/web/assets/Upload-v5rV0qTT.js +1 -0
  60. package/dist/web/assets/WorkspaceDrawer-CGnMu9p1.css +1 -0
  61. package/dist/web/assets/WorkspaceDrawer-DxmicM4U.js +1 -0
  62. package/dist/web/assets/WorkspaceManager-CJHCjARN.js +1 -0
  63. package/dist/web/assets/WorkspacePanel-D0-zHTHP.css +1 -0
  64. package/dist/web/assets/WorkspacePanel-D8_Zq-du.js +1 -0
  65. package/dist/web/assets/_plugin-vue_export-helper-BeLZJZij.js +1 -0
  66. package/dist/web/assets/client-UDwXBP9i.js +1 -0
  67. package/dist/web/assets/clipboard-B46yyoz_.js +1 -0
  68. package/dist/web/assets/headers-cf-QapUq.js +1 -0
  69. package/dist/web/assets/icons-B2Vg-IOC.js +1 -0
  70. package/dist/web/assets/index-C0EHRym0.css +1 -0
  71. package/dist/web/assets/index-DnEocV0M.js +2 -0
  72. package/dist/web/assets/light-Cp0t7v32.js +1 -0
  73. package/dist/web/assets/markdown-u082bbtj.js +1 -0
  74. package/dist/web/assets/platforms-CBkB45JP.js +1 -0
  75. package/dist/web/assets/platforms-FTpjxAT6.js +1 -0
  76. package/dist/web/assets/project-config-B2baPzYL.js +1 -0
  77. package/dist/web/assets/sessions-Cmy31slD.js +1 -0
  78. package/dist/web/assets/sessions-yC_oVVh8.js +1 -0
  79. package/dist/web/assets/skill-repo-input-B_fkGlUK.js +1 -0
  80. package/dist/web/assets/use-lock-html-scroll-DXIqmUW4.js +1 -0
  81. package/dist/web/assets/use-message-DoLM8C1C.js +1 -0
  82. package/dist/web/assets/useResponsiveDrawer-B3uojyvV.js +1 -0
  83. package/dist/web/assets/vendors-D0c_0KLP.js +1 -0
  84. package/dist/web/assets/vue-vendor-BqZbbXHA.js +1 -0
  85. package/dist/web/assets/workspaces-mjyPVGS8.js +1 -0
  86. package/dist/web/assets/xml-CgY3RMlX.js +1 -0
  87. package/dist/web/index.html +12 -8
  88. package/docs/native-log-memory-2026-09-16.md +43 -0
  89. package/docs/superpowers/plans/2026-08-26-configuration-driven-cli-platform.md +1578 -0
  90. package/docs/superpowers/plans/2026-08-30-project-scoped-config-control.md +1260 -0
  91. package/docs/superpowers/plans/2026-09-01-omp-skill-refresh-boundary.md +213 -0
  92. package/docs/superpowers/plans/2026-09-01-realtime-logs-panel.md +125 -0
  93. package/docs/superpowers/plans/2026-09-02-config-driven-platform-boundary.md +86 -0
  94. package/docs/superpowers/plans/2026-09-02-platform-implementation-drivers.md +508 -0
  95. package/docs/superpowers/plans/2026-09-03-cli-platform-correctness-boundary.md +760 -0
  96. package/docs/superpowers/plans/2026-09-03-dependency-security-remediation.md +133 -0
  97. package/docs/superpowers/plans/2026-09-04-model-catalog-pricing-sync.md +1078 -0
  98. package/docs/superpowers/plans/2026-09-05-codex-project-scan-500.md +128 -0
  99. package/docs/superpowers/plans/2026-09-06-project-skill-path-fix.md +97 -0
  100. package/docs/superpowers/specs/2026-08-26-configuration-driven-cli-platform-design.md +408 -0
  101. package/docs/superpowers/specs/2026-08-30-project-scoped-config-control-design.md +467 -0
  102. package/docs/superpowers/specs/2026-09-01-claude-session-content-repair-design.md +111 -0
  103. package/docs/superpowers/specs/2026-09-01-omp-skill-refresh-boundary-design.md +83 -0
  104. package/docs/superpowers/specs/2026-09-01-realtime-logs-panel-design.md +27 -0
  105. package/docs/superpowers/specs/2026-09-02-config-driven-platform-boundary-design.md +64 -0
  106. package/docs/superpowers/specs/2026-09-02-platform-implementation-driver-boundary-design.md +123 -0
  107. package/docs/superpowers/specs/2026-09-03-cli-platform-correctness-boundary-design.md +249 -0
  108. package/docs/superpowers/specs/2026-09-03-dependency-security-remediation-design.md +87 -0
  109. package/docs/superpowers/specs/2026-09-04-model-catalog-pricing-sync-design.md +301 -0
  110. package/docs/superpowers/specs/2026-09-05-codex-project-scan-500-design.md +24 -0
  111. package/package.json +8 -4
  112. package/src/commands/channels.js +88 -191
  113. package/src/commands/cli-type.js +19 -11
  114. package/src/commands/daemon.js +94 -32
  115. package/src/commands/doctor.js +16 -9
  116. package/src/commands/export-config.js +23 -5
  117. package/src/commands/list.js +130 -52
  118. package/src/commands/logs.js +44 -27
  119. package/src/commands/platform-command-registry.js +78 -0
  120. package/src/commands/plugin.js +11 -5
  121. package/src/commands/port-config.js +34 -52
  122. package/src/commands/proxy-control.js +207 -145
  123. package/src/commands/proxy.js +2 -2
  124. package/src/commands/resume.js +87 -91
  125. package/src/commands/search.js +137 -67
  126. package/src/commands/stats.js +30 -22
  127. package/src/commands/switch.js +1 -1
  128. package/src/commands/toggle-proxy.js +94 -111
  129. package/src/commands/ui.js +67 -6
  130. package/src/commands/workspace.js +90 -8
  131. package/src/config/default.js +6 -53
  132. package/src/config/loader.js +61 -24
  133. package/src/config/model-metadata.js +49 -59
  134. package/src/config/model-metadata.json +4095 -99
  135. package/src/config/paths.js +181 -8
  136. package/src/index.js +134 -71
  137. package/src/platforms/access.js +196 -0
  138. package/src/{server/services → platforms}/agents-service.js +354 -197
  139. package/src/platforms/channel-auth-registry.js +162 -0
  140. package/src/platforms/channel-auth-service.js +82 -0
  141. package/src/{server/services → platforms}/commands-service.js +195 -115
  142. package/src/platforms/driver-registry.js +59 -0
  143. package/src/platforms/drivers/claude/api-operations.js +62 -0
  144. package/src/{server/services/channels.js → platforms/drivers/claude/channels-implementation.js} +131 -33
  145. package/src/platforms/drivers/claude/channels.js +39 -0
  146. package/src/{server/services/config-sync-service.js → platforms/drivers/claude/config-sync.js} +29 -5
  147. package/src/{server/services → platforms/drivers/claude}/health-check.js +4 -4
  148. package/src/platforms/drivers/claude/health.js +22 -0
  149. package/src/platforms/drivers/claude/mcp.js +9 -0
  150. package/src/{server/services/settings-manager.js → platforms/drivers/claude/native-config-implementation.js} +13 -4
  151. package/src/platforms/drivers/claude/native-config.js +46 -0
  152. package/src/platforms/drivers/claude/native-logs.js +72 -0
  153. package/src/{server/services/claude-openai-gateway.js → platforms/drivers/claude/openai-gateway.js} +8 -65
  154. package/src/platforms/drivers/claude/project-config.js +21 -0
  155. package/src/platforms/drivers/claude/projects.js +62 -0
  156. package/src/platforms/drivers/claude/prompts.js +9 -0
  157. package/src/{server/proxy-server.js → platforms/drivers/claude/proxy-implementation.js} +41 -278
  158. package/src/platforms/drivers/claude/proxy.js +16 -0
  159. package/src/platforms/drivers/claude/resource-sync.js +9 -0
  160. package/src/platforms/drivers/claude/session-history-adapter.js +313 -0
  161. package/src/{server/services/sessions.js → platforms/drivers/claude/sessions-implementation.js} +145 -35
  162. package/src/platforms/drivers/claude/sessions.js +76 -0
  163. package/src/{server/services/claude-statistics-service.js → platforms/drivers/claude/statistics-implementation.js} +2 -2
  164. package/src/platforms/drivers/claude/statistics.js +16 -0
  165. package/src/{server/services/claude-wire.js → platforms/drivers/claude/wire.js} +1 -1
  166. package/src/platforms/drivers/codex/api-operations.js +9 -0
  167. package/src/{server/services/codex-channels.js → platforms/drivers/codex/channels-implementation.js} +149 -14
  168. package/src/platforms/drivers/codex/channels.js +45 -0
  169. package/src/{server/services/codex-config.js → platforms/drivers/codex/config.js} +12 -2
  170. package/src/{server/services/codex-env-manager.js → platforms/drivers/codex/env-manager.js} +1 -1
  171. package/src/platforms/drivers/codex/mcp.js +9 -0
  172. package/src/{server/services/codex-settings-manager.js → platforms/drivers/codex/native-config-implementation.js} +15 -6
  173. package/src/platforms/drivers/codex/native-config.js +47 -0
  174. package/src/platforms/drivers/codex/native-logs.js +166 -0
  175. package/src/platforms/drivers/codex/project-config.js +21 -0
  176. package/src/platforms/drivers/codex/projects.js +26 -0
  177. package/src/platforms/drivers/codex/prompts.js +9 -0
  178. package/src/{server/codex-proxy-server.js → platforms/drivers/codex/proxy-implementation.js} +30 -233
  179. package/src/platforms/drivers/codex/proxy.js +16 -0
  180. package/src/platforms/drivers/codex/resource-sync.js +9 -0
  181. package/src/{server/services/session-history-adapters/codex.js → platforms/drivers/codex/session-history-adapter.js} +37 -23
  182. package/src/{server/services/codex-sessions.js → platforms/drivers/codex/sessions-implementation.js} +81 -75
  183. package/src/platforms/drivers/codex/sessions.js +36 -0
  184. package/src/{server/services/codex-statistics-service.js → platforms/drivers/codex/statistics-implementation.js} +2 -2
  185. package/src/platforms/drivers/codex/statistics.js +16 -0
  186. package/src/platforms/drivers/gemini/api-operations.js +9 -0
  187. package/src/{server/services/gemini-channels.js → platforms/drivers/gemini/channels-implementation.js} +202 -37
  188. package/src/platforms/drivers/gemini/channels.js +39 -0
  189. package/src/{server/services/gemini-config.js → platforms/drivers/gemini/config.js} +12 -2
  190. package/src/platforms/drivers/gemini/mcp.js +9 -0
  191. package/src/{server/services/gemini-settings-manager.js → platforms/drivers/gemini/native-config-implementation.js} +14 -5
  192. package/src/platforms/drivers/gemini/native-config.js +39 -0
  193. package/src/platforms/drivers/gemini/native-logs.js +180 -0
  194. package/src/platforms/drivers/gemini/project-config.js +21 -0
  195. package/src/platforms/drivers/gemini/projects.js +26 -0
  196. package/src/platforms/drivers/gemini/prompts.js +9 -0
  197. package/src/{server/gemini-proxy-server.js → platforms/drivers/gemini/proxy-implementation.js} +36 -267
  198. package/src/platforms/drivers/gemini/proxy.js +16 -0
  199. package/src/platforms/drivers/gemini/resource-sync.js +9 -0
  200. package/src/{server/services/session-history-adapters/gemini.js → platforms/drivers/gemini/session-history-adapter.js} +70 -18
  201. package/src/{server/services/gemini-sessions.js → platforms/drivers/gemini/sessions-implementation.js} +53 -37
  202. package/src/platforms/drivers/gemini/sessions.js +47 -0
  203. package/src/{server/services/gemini-statistics-service.js → platforms/drivers/gemini/statistics-implementation.js} +2 -2
  204. package/src/platforms/drivers/gemini/statistics.js +16 -0
  205. package/src/{server/services/gemini-wire.js → platforms/drivers/gemini/wire.js} +1 -1
  206. package/src/platforms/drivers/generic-filesystem.js +166 -0
  207. package/src/platforms/drivers/generic-jsonl.js +141 -0
  208. package/src/platforms/drivers/generic-mcp.js +44 -0
  209. package/src/platforms/drivers/generic-openai-compatible.js +45 -0
  210. package/src/platforms/drivers/generic-prompt.js +41 -0
  211. package/src/platforms/drivers/legacy.js +677 -0
  212. package/src/platforms/drivers/native-config-snapshot.js +125 -0
  213. package/src/platforms/drivers/native-log-utils.js +1292 -0
  214. package/src/platforms/drivers/notification-hooks.js +578 -0
  215. package/src/{server/api/omp-config.js → platforms/drivers/omp/api-operations.js} +52 -64
  216. package/src/{server/services/omp-auth-provider-worker.js → platforms/drivers/omp/auth-provider-worker.js} +1 -1
  217. package/src/{server/services/omp-auth-providers.js → platforms/drivers/omp/auth-providers.js} +1 -1
  218. package/src/{server/services/omp-channels.js → platforms/drivers/omp/channels-implementation.js} +166 -39
  219. package/src/platforms/drivers/omp/channels.js +58 -0
  220. package/src/{server/services/omp-config.js → platforms/drivers/omp/config.js} +53 -13
  221. package/src/{server/services/omp-gateway-routing.js → platforms/drivers/omp/gateway-routing.js} +14 -7
  222. package/src/{server/services/omp-gateway.js → platforms/drivers/omp/gateway.js} +4 -262
  223. package/src/platforms/drivers/omp/mcp.js +9 -0
  224. package/src/{server/services/omp-settings-manager.js → platforms/drivers/omp/native-config-implementation.js} +75 -10
  225. package/src/platforms/drivers/omp/native-config.js +46 -0
  226. package/src/platforms/drivers/omp/native-logs.js +52 -0
  227. package/src/{server/services/omp-native-plugin-adapter.js → platforms/drivers/omp/native-plugin-adapter.js} +91 -4
  228. package/src/platforms/drivers/omp/project-config.js +29 -0
  229. package/src/platforms/drivers/omp/projects.js +20 -0
  230. package/src/platforms/drivers/omp/prompts.js +9 -0
  231. package/src/{server/omp-proxy-server.js → platforms/drivers/omp/proxy-implementation.js} +6 -15
  232. package/src/platforms/drivers/omp/proxy.js +16 -0
  233. package/src/platforms/drivers/omp/resource-sync.js +9 -0
  234. package/src/{server/services/session-history-adapters/omp.js → platforms/drivers/omp/session-history-adapter.js} +42 -18
  235. package/src/{server/services/omp-sessions.js → platforms/drivers/omp/sessions-implementation.js} +130 -94
  236. package/src/platforms/drivers/omp/sessions.js +36 -0
  237. package/src/{server/services/omp-skill-discovery.js → platforms/drivers/omp/skill-discovery.js} +159 -32
  238. package/src/{server/services/omp-skill-settings-service.js → platforms/drivers/omp/skill-settings.js} +1 -1
  239. package/src/{server/services/omp-statistics-service.js → platforms/drivers/omp/statistics-implementation.js} +3 -3
  240. package/src/platforms/drivers/omp/statistics.js +16 -0
  241. package/src/platforms/drivers/opencode/api-operations.js +9 -0
  242. package/src/{server/services/opencode-channels.js → platforms/drivers/opencode/channels-implementation.js} +28 -9
  243. package/src/platforms/drivers/opencode/channels.js +40 -0
  244. package/src/platforms/drivers/opencode/conversion.js +41 -0
  245. package/src/{server/services/opencode-gateway-converter.js → platforms/drivers/opencode/gateway-converter.js} +1 -1
  246. package/src/platforms/drivers/opencode/mcp.js +9 -0
  247. package/src/{server/services/opencode-settings-manager.js → platforms/drivers/opencode/native-config-implementation.js} +17 -6
  248. package/src/platforms/drivers/opencode/native-config.js +26 -0
  249. package/src/platforms/drivers/opencode/native-logs.js +133 -0
  250. package/src/platforms/drivers/opencode/project-config.js +98 -0
  251. package/src/platforms/drivers/opencode/projects.js +20 -0
  252. package/src/platforms/drivers/opencode/prompts.js +9 -0
  253. package/src/{server/opencode-proxy-server.js → platforms/drivers/opencode/proxy-implementation.js} +27 -362
  254. package/src/platforms/drivers/opencode/proxy.js +16 -0
  255. package/src/platforms/drivers/opencode/resource-sync.js +9 -0
  256. package/src/{server/services/opencode-sessions.js → platforms/drivers/opencode/sessions-implementation.js} +211 -64
  257. package/src/platforms/drivers/opencode/sessions.js +48 -0
  258. package/src/{server/services/opencode-statistics-service.js → platforms/drivers/opencode/statistics-implementation.js} +2 -2
  259. package/src/platforms/drivers/opencode/statistics.js +16 -0
  260. package/src/platforms/drivers/secure-file-driver.js +272 -0
  261. package/src/platforms/drivers/unsupported.js +7 -0
  262. package/src/platforms/manifest-schema.js +398 -0
  263. package/src/platforms/manifests/claude.json +489 -0
  264. package/src/platforms/manifests/codex.json +448 -0
  265. package/src/platforms/manifests/gemini.json +447 -0
  266. package/src/platforms/manifests/omp.json +496 -0
  267. package/src/platforms/manifests/opencode.json +422 -0
  268. package/src/{server/services → platforms}/native-oauth-adapters.js +87 -417
  269. package/src/{server/services → platforms}/notification-hooks.js +140 -1023
  270. package/src/platforms/oauth-credentials-service.js +506 -0
  271. package/src/platforms/path-resolver.js +179 -0
  272. package/src/platforms/platform-path-context.js +305 -0
  273. package/src/platforms/registry.js +248 -0
  274. package/src/platforms/remote-notification-providers.js +678 -0
  275. package/src/platforms/runtime.js +259 -0
  276. package/src/{server/services/session-history-adapters/index.js → platforms/session-history-adapters.js} +8 -1
  277. package/src/plugins/plugin-loader.js +2 -2
  278. package/src/plugins/plugin-manager.js +2 -2
  279. package/src/plugins/registry.js +27 -10
  280. package/src/reset-config.js +21 -5
  281. package/src/server/api/agents.js +46 -72
  282. package/src/server/api/commands.js +16 -6
  283. package/src/server/api/config-registry.js +206 -59
  284. package/src/server/api/config-sync.js +3 -2
  285. package/src/server/api/config-templates.js +20 -4
  286. package/src/server/api/config.js +111 -102
  287. package/src/server/api/convert.js +54 -178
  288. package/src/server/api/dashboard.js +168 -102
  289. package/src/server/api/hooks.js +1 -1
  290. package/src/server/api/mcp.js +224 -84
  291. package/src/server/api/platform-api-config.js +102 -0
  292. package/src/server/api/platform-route-factory.js +215 -0
  293. package/src/server/api/platform-routes.js +26 -0
  294. package/src/server/api/platforms.js +110 -0
  295. package/src/server/api/plugins.js +57 -57
  296. package/src/server/api/project-config.js +168 -0
  297. package/src/server/api/prompts.js +58 -45
  298. package/src/server/api/settings.js +55 -8
  299. package/src/server/api/skills.js +262 -133
  300. package/src/server/api/ui-config.js +2 -2
  301. package/src/server/api/validation-errors.js +18 -4
  302. package/src/server/api/workspaces.js +47 -12
  303. package/src/server/index.js +164 -213
  304. package/src/server/platform-context.js +81 -0
  305. package/src/server/services/channel-balance.js +11 -20
  306. package/src/server/services/channel-health.js +21 -6
  307. package/src/server/services/channel-scheduler.js +29 -39
  308. package/src/server/services/channel-sync-utils.js +23 -13
  309. package/src/server/services/config-export-service.js +350 -319
  310. package/src/server/services/config-registry-service.js +280 -54
  311. package/src/server/services/config-sync-manager.js +172 -944
  312. package/src/server/services/config-templates-service.js +419 -353
  313. package/src/server/services/control-manifest-store.js +206 -0
  314. package/src/server/services/dashboard-snapshot-worker.js +656 -100
  315. package/src/server/services/effective-control-service.js +557 -0
  316. package/src/server/services/local-resource-index.js +314 -0
  317. package/src/server/services/mcp-service.js +607 -977
  318. package/src/server/services/model-detector.js +15 -10
  319. package/src/server/services/native-log-channel-resolver.js +214 -0
  320. package/src/server/services/native-log-observer.js +291 -0
  321. package/src/server/services/network-access.js +1 -1
  322. package/src/server/services/platform-catalog.js +82 -0
  323. package/src/server/services/platform-resolution.js +32 -29
  324. package/src/server/services/plugins-service.js +376 -122
  325. package/src/server/services/project-config-service.js +550 -0
  326. package/src/server/services/project-path-validation.js +31 -0
  327. package/src/server/services/prompts-service.js +267 -233
  328. package/src/server/services/proxy-runtime.js +7 -4
  329. package/src/server/services/remote-credential-cache.js +43 -0
  330. package/src/server/services/repo-scanner-base.js +182 -75
  331. package/src/server/services/request-logger.js +7 -4
  332. package/src/server/services/session-history-index.js +780 -213
  333. package/src/server/services/session-history-worker.js +228 -33
  334. package/src/server/services/session-snapshot-worker.js +124 -34
  335. package/src/server/services/session-snapshots.js +4 -2
  336. package/src/server/services/skill-artifact-store.js +355 -0
  337. package/src/server/services/skill-format-adapters.js +65 -0
  338. package/src/server/services/skill-projection-service.js +323 -0
  339. package/src/server/services/skill-refresh-task-service.js +275 -0
  340. package/src/server/services/skill-service.js +2020 -677
  341. package/src/server/services/snapshot-cache.js +30 -8
  342. package/src/server/services/speed-test.js +8 -8
  343. package/src/server/services/sqlite-connection.js +19 -3
  344. package/src/server/services/statistics-service.js +240 -57
  345. package/src/server/services/ui-config.js +107 -76
  346. package/src/server/services/usage-log-utils.js +98 -0
  347. package/src/server/services/web-build.js +1 -1
  348. package/src/server/services/workspace-service.js +59 -29
  349. package/src/server/utils/pricing.js +10 -19
  350. package/src/server/websocket-server.js +153 -28
  351. package/src/{server/services/base → shared}/base-channel-service.js +156 -28
  352. package/src/shared/capability-driver.js +104 -0
  353. package/src/shared/channel-auth-policy.js +27 -0
  354. package/src/shared/channel-driver.js +161 -0
  355. package/src/shared/driver-factories/api.js +180 -0
  356. package/src/shared/driver-factories/mcp.js +244 -0
  357. package/src/shared/driver-factories/projects.js +121 -0
  358. package/src/shared/driver-factories/prompts.js +58 -0
  359. package/src/shared/driver-factories/resource-sync.js +375 -0
  360. package/src/shared/driver-result.js +78 -0
  361. package/src/shared/mcp-format.js +189 -0
  362. package/src/shared/platforms.js +104 -167
  363. package/src/shared/project-config.js +512 -0
  364. package/src/shared/proxy-driver.js +57 -0
  365. package/src/{server/services/base → shared}/response-usage-parser.js +8 -4
  366. package/src/ui/menu.js +91 -67
  367. package/src/utils/port-helper.js +35 -19
  368. package/src/utils/session.js +1 -1
  369. package/dist/web/assets/Analytics-COEUXmd4.js +0 -25
  370. package/dist/web/assets/Analytics-RNn1BUbG.css +0 -1
  371. package/dist/web/assets/ConfigTemplates-DLLkS53H.js +0 -1
  372. package/dist/web/assets/Home-DCEyLzwX.js +0 -1
  373. package/dist/web/assets/Home-DYVy4cGZ.css +0 -1
  374. package/dist/web/assets/PluginManager-Oe1ZHoMO.js +0 -1
  375. package/dist/web/assets/ProjectList-CWjuAFof.js +0 -1
  376. package/dist/web/assets/ProjectList-VeMNXfgO.css +0 -1
  377. package/dist/web/assets/SessionList-C4chCPxK.css +0 -1
  378. package/dist/web/assets/SessionList-v3ehGg9U.js +0 -1
  379. package/dist/web/assets/SkillManager-BsX8Qpj0.css +0 -1
  380. package/dist/web/assets/SkillManager-DUF_qP5S.js +0 -1
  381. package/dist/web/assets/WorkspaceManager-CjAWBosO.js +0 -1
  382. package/dist/web/assets/icons-nGdSKQn2.js +0 -1
  383. package/dist/web/assets/index-D5hyHPj7.js +0 -2
  384. package/dist/web/assets/index-bJRG3RXH.css +0 -1
  385. package/dist/web/assets/markdown-BNJfEgCA.js +0 -1
  386. package/dist/web/assets/markdown-BfC0goYb.css +0 -10
  387. package/dist/web/assets/naive-ui-BALVpMgd.js +0 -1
  388. package/dist/web/assets/vendors-DQA4Hw9v.js +0 -7
  389. package/dist/web/assets/vue-vendor-B5RqjEjQ.js +0 -45
  390. package/src/config/model-pricing.js +0 -35
  391. package/src/server/api/channels.js +0 -439
  392. package/src/server/api/claude-hooks.js +0 -56
  393. package/src/server/api/claude-statistics.js +0 -57
  394. package/src/server/api/codex-channels.js +0 -491
  395. package/src/server/api/codex-projects.js +0 -117
  396. package/src/server/api/codex-proxy.js +0 -293
  397. package/src/server/api/codex-sessions.js +0 -652
  398. package/src/server/api/codex-statistics.js +0 -57
  399. package/src/server/api/gemini-channels.js +0 -392
  400. package/src/server/api/gemini-projects.js +0 -103
  401. package/src/server/api/gemini-proxy.js +0 -231
  402. package/src/server/api/gemini-sessions.js +0 -550
  403. package/src/server/api/gemini-statistics.js +0 -57
  404. package/src/server/api/health-check.js +0 -31
  405. package/src/server/api/oauth-credentials.js +0 -198
  406. package/src/server/api/omp-channels.js +0 -575
  407. package/src/server/api/omp-projects.js +0 -88
  408. package/src/server/api/omp-proxy.js +0 -125
  409. package/src/server/api/omp-sessions.js +0 -386
  410. package/src/server/api/omp-statistics.js +0 -40
  411. package/src/server/api/opencode-channels.js +0 -471
  412. package/src/server/api/opencode-projects.js +0 -110
  413. package/src/server/api/opencode-proxy.js +0 -354
  414. package/src/server/api/opencode-sessions.js +0 -466
  415. package/src/server/api/opencode-statistics.js +0 -57
  416. package/src/server/api/projects.js +0 -120
  417. package/src/server/api/proxy.js +0 -330
  418. package/src/server/api/sessions.js +0 -810
  419. package/src/server/services/oauth-credentials-service.js +0 -945
  420. package/src/server/services/omp-session-log-observer.js +0 -138
  421. package/src/server/services/opencode-gateway-adapters.js +0 -43
  422. package/src/server/services/project-snapshots.js +0 -59
  423. package/src/server/services/proxy-log-helper.js +0 -298
  424. package/src/server/services/session-cache.js +0 -127
  425. package/src/server/services/session-converter.js +0 -582
  426. package/src/server/services/session-history-adapters/claude.js +0 -235
  427. /package/src/{server/services/claude-token-recovery.js → platforms/drivers/claude/token-recovery.js} +0 -0
  428. /package/src/{server/services/codex-parser.js → platforms/drivers/codex/parser.js} +0 -0
  429. /package/src/{server/services/codex-speed-test-template.json → platforms/drivers/codex/speed-test-template.json} +0 -0
  430. /package/src/{server/services/codex-wire.js → platforms/drivers/codex/wire.js} +0 -0
  431. /package/src/{server/services/omp-auth-gateway-client.js → platforms/drivers/omp/auth-gateway-client.js} +0 -0
  432. /package/src/{server/services/opencode-normalization.js → platforms/drivers/opencode/normalization.js} +0 -0
  433. /package/src/{server/services → shared}/config-artifact-paths.js +0 -0
  434. /package/src/{server/services/base → shared}/proxy-utils.js +0 -0
@@ -0,0 +1,578 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const pathsModule = require('../../config/paths');
6
+ const { PATHS: DEFAULT_PATHS, NATIVE_PATHS: DEFAULT_NATIVE_PATHS } = pathsModule;
7
+ const codexSettingsManager = require('./codex/native-config-implementation');
8
+ const geminiSettingsManager = require('./gemini/native-config-implementation');
9
+
10
+ let PATHS = DEFAULT_PATHS;
11
+ let NATIVE_PATHS = DEFAULT_NATIVE_PATHS;
12
+
13
+ function configure({ pathContext } = {}) {
14
+ PATHS = DEFAULT_PATHS;
15
+ NATIVE_PATHS = DEFAULT_NATIVE_PATHS;
16
+ if (!pathContext?.customized) return;
17
+
18
+ const platform = pathContext.platform;
19
+ const native = pathContext.native || {};
20
+ const platformNative = DEFAULT_NATIVE_PATHS[platform] || {};
21
+ const state = pathContext.state || {};
22
+ NATIVE_PATHS = {
23
+ ...DEFAULT_NATIVE_PATHS,
24
+ [platform]: { ...platformNative, ...native }
25
+ };
26
+ PATHS = {
27
+ ...DEFAULT_PATHS,
28
+ ...(pathContext.paths?.notifyHook ? { notifyHook: pathContext.paths.notifyHook } : {}),
29
+ ...(state.channels ? { channels: { ...DEFAULT_PATHS.channels, [platform]: state.channels } } : {})
30
+ };
31
+ }
32
+
33
+ const MANAGED_HOOK_NAME = 'coding-tool-notify';
34
+ const MANAGED_OPENCODE_PLUGIN_FILE = 'coding-tool-notify.js';
35
+ const MANAGED_OMP_EXTENSION_FILE = 'coding-tool-notify.ts';
36
+ const HOOK_TYPES = Object.freeze(['notification', 'browser', 'dialog']);
37
+
38
+ const HOOK_DEFINITIONS = Object.freeze({
39
+ claude: Object.freeze({
40
+ key: 'claude',
41
+ label: 'Claude Code',
42
+ description: '当 Claude Code 任务完成或等待交互时发送系统通知',
43
+ implementation: '通过 Claude Code 的 Stop Hook 在任务完成时发送通知',
44
+ externalMessage: '检测到已有非 Coding Tool 的 Stop Hook。本界面只管理 Coding Tool 写入的通知配置。',
45
+ hints: Object.freeze(['仅管理 Coding Tool 写入的通知配置。'])
46
+ }),
47
+ codex: Object.freeze({
48
+ key: 'codex',
49
+ label: 'Codex CLI',
50
+ description: '当 Codex CLI 当前回合完成并等待下一步交互时发送系统通知',
51
+ implementation: '通过 Codex CLI 的 notify 命令在回合完成后发送通知',
52
+ externalMessage: '检测到现有 notify 配置。启用 Coding Tool 托管通知会替换当前 notify 命令;关闭时只会移除 Coding Tool 写入的 notify。',
53
+ hints: Object.freeze(['启用时会写入 Codex 的 notify 配置。'])
54
+ }),
55
+ gemini: Object.freeze({
56
+ key: 'gemini',
57
+ label: 'Gemini CLI',
58
+ description: '当 Gemini CLI 回合完成或等待下一步交互时发送系统通知',
59
+ implementation: '通过 Gemini CLI 的 AfterAgent Hook 在任务完成时发送通知',
60
+ externalMessage: '检测到已有非 Coding Tool 的 Gemini Hook。本界面只管理 Coding Tool 写入的通知配置。',
61
+ hints: Object.freeze(['仅移除 Coding Tool 标记的 AfterAgent Hook。'])
62
+ }),
63
+ opencode: Object.freeze({
64
+ key: 'opencode',
65
+ label: 'OpenCode',
66
+ description: '当 OpenCode 会话空闲或发生错误时发送系统通知',
67
+ implementation: '通过 OpenCode 插件事件(session.idle / session.error)发送通知',
68
+ externalMessage: '检测到其他 OpenCode 通知配置时,本界面只管理 Coding Tool 生成的插件文件。',
69
+ hints: Object.freeze(['通知插件由 Coding Tool 写入 OpenCode 配置目录。'])
70
+ }),
71
+ omp: Object.freeze({
72
+ key: 'omp',
73
+ label: 'OMP',
74
+ description: '当 OMP 回合完成或等待下一步交互时发送系统通知',
75
+ implementation: '通过 OMP 托管 Extension 事件发送通知',
76
+ externalMessage: '检测到其他 OMP 通知扩展时,本界面只管理 Coding Tool 生成的扩展文件。',
77
+ hints: Object.freeze(['通知扩展由 Coding Tool 写入 OMP extensions 目录。'])
78
+ })
79
+ });
80
+
81
+ function normalizeType(type) {
82
+ return type === 'dialog' || type === 'browser' ? type : 'notification';
83
+ }
84
+
85
+ function parseManagedType(input) {
86
+ const value = String(input || '');
87
+ const matches = [
88
+ value.match(/--cc-notify-type=(dialog|notification|browser)/i),
89
+ value.match(/--mode=(dialog|notification|browser)/i),
90
+ value.match(/MODE\s*=\s*["'](dialog|notification|browser)["']/i)
91
+ ];
92
+
93
+ for (const match of matches) {
94
+ if (match?.[1]) return normalizeType(match[1].toLowerCase());
95
+ }
96
+ return null;
97
+ }
98
+
99
+ function isManagedNotifyPath(input) {
100
+ const normalizedInput = String(input || '').replace(/\\/g, '/');
101
+ const normalizedPath = String(PATHS.notifyHook || '').replace(/\\/g, '/');
102
+ return normalizedInput.includes('notify-hook.js')
103
+ || (normalizedPath && normalizedInput.includes(normalizedPath));
104
+ }
105
+
106
+ function ensureParentDir(filePath) {
107
+ const dir = path.dirname(filePath);
108
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
109
+ }
110
+
111
+ function readJsonFile(filePath) {
112
+ if (!fs.existsSync(filePath)) return {};
113
+ const content = fs.readFileSync(filePath, 'utf8');
114
+ return content.trim() ? JSON.parse(content) : {};
115
+ }
116
+
117
+ function writeJsonFile(filePath, value) {
118
+ ensureParentDir(filePath);
119
+ fs.writeFileSync(filePath, JSON.stringify(value, null, 2), 'utf8');
120
+ }
121
+
122
+ function quoteShellArg(value) {
123
+ const stringValue = String(value || '');
124
+ if (/^[A-Za-z0-9_./:=+-]+$/.test(stringValue)) return stringValue;
125
+ return `"${stringValue.replace(/"/g, '\\"')}"`;
126
+ }
127
+
128
+ function buildClaudeCommand(type) {
129
+ const mode = normalizeType(type);
130
+ const args = ['node', PATHS.notifyHook, `--source=claude`, `--mode=${mode}`, `--cc-notify-type=${mode}`];
131
+ return `${quoteShellArg(args[0])} ${quoteShellArg(args[1])} ${args.slice(2).map(quoteShellArg).join(' ')}`;
132
+ }
133
+
134
+ function buildCodexNotifyCommand(type) {
135
+ const mode = normalizeType(type);
136
+ return ['node', PATHS.notifyHook, `--source=codex`, `--mode=${mode}`, `--cc-notify-type=${mode}`];
137
+ }
138
+
139
+ function buildGeminiCommand(type) {
140
+ const mode = normalizeType(type);
141
+ const args = ['node', PATHS.notifyHook, `--source=gemini`, `--mode=${mode}`, `--cc-notify-type=${mode}`];
142
+ return `${quoteShellArg(args[0])} ${quoteShellArg(args[1])} ${args.slice(2).map(quoteShellArg).join(' ')}`;
143
+ }
144
+
145
+ function getOpenCodeManagedPluginPath() {
146
+ return path.join(NATIVE_PATHS.opencode.config, 'plugins', MANAGED_OPENCODE_PLUGIN_FILE);
147
+ }
148
+
149
+ function getOmpManagedExtensionPath() {
150
+ const ompPaths = NATIVE_PATHS.omp || {};
151
+ const extensionsDir = ompPaths.extensions
152
+ || path.join(ompPaths.dir || path.dirname(ompPaths.settings || PATHS.notifyHook), 'extensions');
153
+ return path.join(extensionsDir, MANAGED_OMP_EXTENSION_FILE);
154
+ }
155
+
156
+ function buildOpenCodePluginContent(type) {
157
+ const mode = normalizeType(type);
158
+ return `// Managed by Coding Tool. Do not edit manually.
159
+ // mode:${mode}
160
+ import { spawn } from 'node:child_process'
161
+
162
+ const SCRIPT_PATH = ${JSON.stringify(PATHS.notifyHook)}
163
+ const MODE = ${JSON.stringify(mode)}
164
+
165
+ function fire(eventType) {
166
+ try {
167
+ const child = spawn('node', [
168
+ SCRIPT_PATH,
169
+ '--source=opencode',
170
+ \`--mode=\${MODE}\`,
171
+ \`--cc-notify-type=\${MODE}\`,
172
+ \`--event-type=\${eventType}\`
173
+ ], {
174
+ detached: true,
175
+ stdio: 'ignore',
176
+ windowsHide: true
177
+ })
178
+ child.unref()
179
+ } catch (error) {
180
+ // Ignore notification failures.
181
+ }
182
+ }
183
+
184
+ export const CodingToolNotifyPlugin = async () => ({
185
+ event: async ({ event }) => {
186
+ const eventType = event?.type
187
+ if (eventType === 'session.idle' || eventType === 'session.error') {
188
+ fire(eventType)
189
+ }
190
+ }
191
+ })
192
+ `;
193
+ }
194
+
195
+ function buildOmpExtensionContent(type) {
196
+ const mode = normalizeType(type);
197
+ return `// Managed by Coding Tool. Do not edit manually.
198
+ // mode:${mode}
199
+ import { spawn } from 'node:child_process'
200
+
201
+ const SCRIPT_PATH = ${JSON.stringify(PATHS.notifyHook)}
202
+ const MODE = ${JSON.stringify(mode)}
203
+ let lastFireAt = 0
204
+
205
+ function shouldFire() {
206
+ const now = Date.now()
207
+ if (now - lastFireAt < 1000) {
208
+ return false
209
+ }
210
+ lastFireAt = now
211
+ return true
212
+ }
213
+
214
+ function fire(eventType) {
215
+ if (!shouldFire()) {
216
+ return
217
+ }
218
+
219
+ try {
220
+ const child = spawn('node', [
221
+ SCRIPT_PATH,
222
+ '--source=omp',
223
+ \`--mode=\${MODE}\`,
224
+ \`--cc-notify-type=\${MODE}\`,
225
+ \`--event-type=\${eventType}\`
226
+ ], {
227
+ detached: true,
228
+ stdio: 'ignore',
229
+ windowsHide: true
230
+ })
231
+ child.unref()
232
+ } catch (error) {
233
+ // Ignore notification failures.
234
+ }
235
+ }
236
+
237
+ export default async function CodingToolNotifyExtension(omp) {
238
+ const register = (eventName) => {
239
+ if (typeof omp?.on !== 'function') {
240
+ return
241
+ }
242
+ omp.on(eventName, async () => {
243
+ fire(eventName)
244
+ })
245
+ }
246
+
247
+ register('agent_settled')
248
+ register('turn_end')
249
+ }
250
+ `;
251
+ }
252
+
253
+ function getClaudeHookStatus() {
254
+ const settings = readJsonFile(NATIVE_PATHS.claude.settings);
255
+ const stopHooks = Array.isArray(settings?.hooks?.Stop) ? settings.hooks.Stop : [];
256
+ let enabled = false;
257
+ let external = false;
258
+ let type = 'notification';
259
+
260
+ for (const group of stopHooks) {
261
+ const hooks = Array.isArray(group?.hooks) ? group.hooks : [];
262
+ for (const hook of hooks) {
263
+ const command = String(hook?.command || '');
264
+ if (!command) continue;
265
+ if (isManagedNotifyPath(command)) {
266
+ enabled = true;
267
+ type = parseManagedType(command) || type;
268
+ } else {
269
+ external = true;
270
+ }
271
+ }
272
+ }
273
+
274
+ return { enabled, external, type, method: 'Stop Hook' };
275
+ }
276
+
277
+ function saveClaudeHook({ enabled, type } = {}) {
278
+ const settings = readJsonFile(NATIVE_PATHS.claude.settings);
279
+ const hooks = settings.hooks && typeof settings.hooks === 'object' ? { ...settings.hooks } : {};
280
+ const currentGroups = Array.isArray(hooks.Stop) ? hooks.Stop : [];
281
+ const filteredGroups = currentGroups.map((group) => {
282
+ const groupHooks = Array.isArray(group?.hooks) ? group.hooks : [];
283
+ const nextHooks = groupHooks.filter(hook => !isManagedNotifyPath(hook?.command));
284
+ if (nextHooks.length === 0) return null;
285
+ return { ...group, hooks: nextHooks };
286
+ }).filter(Boolean);
287
+
288
+ if (enabled === true) {
289
+ filteredGroups.push({
290
+ hooks: [{
291
+ name: MANAGED_HOOK_NAME,
292
+ type: 'command',
293
+ command: buildClaudeCommand(type)
294
+ }]
295
+ });
296
+ }
297
+
298
+ if (filteredGroups.length > 0) hooks.Stop = filteredGroups;
299
+ else delete hooks.Stop;
300
+ if (Object.keys(hooks).length > 0) settings.hooks = hooks;
301
+ else delete settings.hooks;
302
+
303
+ writeJsonFile(NATIVE_PATHS.claude.settings, settings);
304
+ return getClaudeHookStatus();
305
+ }
306
+
307
+ function readCodexConfig() {
308
+ if (typeof codexSettingsManager.configExists === 'function' && !codexSettingsManager.configExists()) {
309
+ return {};
310
+ }
311
+ return codexSettingsManager.readConfig();
312
+ }
313
+
314
+ function isManagedCodexNotify(notify) {
315
+ return Array.isArray(notify) && notify.some(part => isManagedNotifyPath(part));
316
+ }
317
+
318
+ function parseCodexNotificationStatus(config = {}) {
319
+ const notify = Array.isArray(config?.notify) ? config.notify : [];
320
+ if (notify.length === 0) {
321
+ return { enabled: false, external: false, type: 'notification', method: 'notify' };
322
+ }
323
+ const joined = notify.join(' ');
324
+ const managed = isManagedCodexNotify(notify);
325
+ return {
326
+ enabled: managed,
327
+ external: !managed,
328
+ type: parseManagedType(joined) || 'notification',
329
+ method: 'notify'
330
+ };
331
+ }
332
+
333
+ function getCodexHookStatus() {
334
+ return parseCodexNotificationStatus(readCodexConfig());
335
+ }
336
+
337
+ function saveCodexHook({ enabled, type } = {}) {
338
+ const config = readCodexConfig();
339
+ const nextConfig = config && typeof config === 'object' ? { ...config } : {};
340
+ if (enabled === true) {
341
+ nextConfig.notify = buildCodexNotifyCommand(type);
342
+ } else if (isManagedCodexNotify(nextConfig.notify)) {
343
+ delete nextConfig.notify;
344
+ }
345
+ ensureParentDir(NATIVE_PATHS.codex.config);
346
+ codexSettingsManager.writeConfig(nextConfig);
347
+ return getCodexHookStatus();
348
+ }
349
+
350
+ function readGeminiSettings() {
351
+ if (typeof geminiSettingsManager.settingsExists === 'function' && !geminiSettingsManager.settingsExists()) {
352
+ return {};
353
+ }
354
+ return geminiSettingsManager.readSettings();
355
+ }
356
+
357
+ function isManagedGeminiHook(hook) {
358
+ const command = String(hook?.command || '');
359
+ const name = String(hook?.name || '');
360
+ return name === MANAGED_HOOK_NAME || isManagedNotifyPath(command);
361
+ }
362
+
363
+ function parseGeminiNotificationStatus(settings = {}) {
364
+ const afterAgentGroups = Array.isArray(settings?.hooks?.AfterAgent) ? settings.hooks.AfterAgent : [];
365
+ let enabled = false;
366
+ let external = false;
367
+ let type = 'notification';
368
+
369
+ for (const group of afterAgentGroups) {
370
+ const hooks = Array.isArray(group?.hooks) ? group.hooks : [];
371
+ for (const hook of hooks) {
372
+ if (isManagedGeminiHook(hook)) {
373
+ enabled = true;
374
+ type = parseManagedType(hook.command) || type;
375
+ } else {
376
+ external = true;
377
+ }
378
+ }
379
+ }
380
+
381
+ return { enabled, external, type, method: 'AfterAgent Hook' };
382
+ }
383
+
384
+ function getGeminiHookStatus() {
385
+ return parseGeminiNotificationStatus(readGeminiSettings());
386
+ }
387
+
388
+ function saveGeminiHook({ enabled, type } = {}) {
389
+ const settings = readGeminiSettings();
390
+ const nextSettings = settings && typeof settings === 'object' ? { ...settings } : {};
391
+ const hooks = nextSettings.hooks && typeof nextSettings.hooks === 'object' ? { ...nextSettings.hooks } : {};
392
+ const currentGroups = Array.isArray(hooks.AfterAgent) ? hooks.AfterAgent : [];
393
+ const filteredGroups = currentGroups.map((group) => {
394
+ const groupHooks = Array.isArray(group?.hooks) ? group.hooks : [];
395
+ const nextHooks = groupHooks.filter(hook => !isManagedGeminiHook(hook));
396
+ if (nextHooks.length === 0) return null;
397
+ return { ...group, hooks: nextHooks };
398
+ }).filter(Boolean);
399
+
400
+ if (enabled === true) {
401
+ filteredGroups.push({
402
+ matcher: '*',
403
+ hooks: [{
404
+ name: MANAGED_HOOK_NAME,
405
+ type: 'command',
406
+ command: buildGeminiCommand(type)
407
+ }]
408
+ });
409
+ }
410
+
411
+ if (filteredGroups.length > 0) hooks.AfterAgent = filteredGroups;
412
+ else delete hooks.AfterAgent;
413
+ if (Object.keys(hooks).length > 0) nextSettings.hooks = hooks;
414
+ else delete nextSettings.hooks;
415
+
416
+ ensureParentDir(geminiSettingsManager.getSettingsPath());
417
+ geminiSettingsManager.writeSettings(nextSettings);
418
+ return getGeminiHookStatus();
419
+ }
420
+
421
+ function parseOpenCodeNotificationStatus(content = '') {
422
+ if (!content) {
423
+ return { enabled: false, external: false, type: 'notification', method: 'Plugin Events' };
424
+ }
425
+ return {
426
+ enabled: true,
427
+ external: false,
428
+ type: parseManagedType(content) || 'notification',
429
+ method: 'Plugin Events'
430
+ };
431
+ }
432
+
433
+ function getOpenCodeHookStatus() {
434
+ const pluginPath = getOpenCodeManagedPluginPath();
435
+ return parseOpenCodeNotificationStatus(fs.existsSync(pluginPath) ? fs.readFileSync(pluginPath, 'utf8') : '');
436
+ }
437
+
438
+ function saveOpenCodeHook({ enabled, type } = {}) {
439
+ const pluginPath = getOpenCodeManagedPluginPath();
440
+ const opencodeSettingsManager = require('./opencode/native-config-implementation');
441
+ const configPath = opencodeSettingsManager.selectConfigPath();
442
+
443
+ if (enabled !== true) {
444
+ if (fs.existsSync(pluginPath)) fs.unlinkSync(pluginPath);
445
+ if (fs.existsSync(configPath)) {
446
+ const config = opencodeSettingsManager.readConfig(configPath);
447
+ if (Array.isArray(config.plugins)) {
448
+ config.plugins = config.plugins.filter(item => item !== './plugins/coding-tool-notify.js');
449
+ if (config.plugins.length === 0) delete config.plugins;
450
+ opencodeSettingsManager.writeConfig(configPath, config);
451
+ }
452
+ }
453
+ return getOpenCodeHookStatus();
454
+ }
455
+
456
+ ensureParentDir(pluginPath);
457
+ fs.writeFileSync(pluginPath, buildOpenCodePluginContent(type), 'utf8');
458
+ const config = fs.existsSync(configPath) ? opencodeSettingsManager.readConfig(configPath) : {};
459
+ if (!Array.isArray(config.plugins)) config.plugins = [];
460
+ const pluginRef = './plugins/coding-tool-notify.js';
461
+ if (!config.plugins.includes(pluginRef)) config.plugins.push(pluginRef);
462
+ opencodeSettingsManager.writeConfig(configPath, config);
463
+ return getOpenCodeHookStatus();
464
+ }
465
+
466
+ function parseOmpNotificationStatus(content = '') {
467
+ if (!content) {
468
+ return { enabled: false, external: false, type: 'notification', method: 'Extension Events' };
469
+ }
470
+ return {
471
+ enabled: true,
472
+ external: false,
473
+ type: parseManagedType(content) || 'notification',
474
+ method: 'Extension Events'
475
+ };
476
+ }
477
+
478
+ function getOmpHookStatus() {
479
+ const extensionPath = getOmpManagedExtensionPath();
480
+ return parseOmpNotificationStatus(fs.existsSync(extensionPath) ? fs.readFileSync(extensionPath, 'utf8') : '');
481
+ }
482
+
483
+ function saveOmpHook({ enabled, type } = {}) {
484
+ const extensionPath = getOmpManagedExtensionPath();
485
+ if (enabled !== true) {
486
+ if (fs.existsSync(extensionPath)) fs.unlinkSync(extensionPath);
487
+ return getOmpHookStatus();
488
+ }
489
+ ensureParentDir(extensionPath);
490
+ fs.writeFileSync(extensionPath, buildOmpExtensionContent(type), 'utf8');
491
+ return getOmpHookStatus();
492
+ }
493
+
494
+ const IMPLEMENTATIONS = Object.freeze({
495
+ claude: Object.freeze({ getHooks: getClaudeHookStatus, saveHooks: saveClaudeHook }),
496
+ codex: Object.freeze({ getHooks: getCodexHookStatus, saveHooks: saveCodexHook }),
497
+ gemini: Object.freeze({ getHooks: getGeminiHookStatus, saveHooks: saveGeminiHook }),
498
+ opencode: Object.freeze({ getHooks: getOpenCodeHookStatus, saveHooks: saveOpenCodeHook }),
499
+ omp: Object.freeze({ getHooks: getOmpHookStatus, saveHooks: saveOmpHook })
500
+ });
501
+
502
+ function cloneDefinition(definition) {
503
+ return {
504
+ ...definition,
505
+ hints: Array.isArray(definition.hints) ? [...definition.hints] : []
506
+ };
507
+ }
508
+
509
+ function defaultTestHooks({ type, platform }) {
510
+ const notificationHooks = require('../notification-hooks');
511
+ return notificationHooks.testNotification({ type, source: platform });
512
+ }
513
+
514
+ function createNotificationHooksDriver({ platform, capability = 'hooks', testNotification, pathContext } = {}) {
515
+ const implementation = IMPLEMENTATIONS[platform];
516
+ const definition = HOOK_DEFINITIONS[platform];
517
+ if (!implementation || !definition) {
518
+ return { status: 'unsupported', platform, capability };
519
+ }
520
+
521
+ configure({ pathContext });
522
+ const runTest = typeof testNotification === 'function' ? testNotification : defaultTestHooks;
523
+ return {
524
+ platform,
525
+ capability,
526
+ getHooks: () => {
527
+ configure({ pathContext });
528
+ return implementation.getHooks();
529
+ },
530
+ saveHooks: (input = {}) => {
531
+ configure({ pathContext });
532
+ return implementation.saveHooks({
533
+ enabled: input.enabled === true,
534
+ type: normalizeType(input.type)
535
+ });
536
+ },
537
+ testHooks: (input = {}) => {
538
+ configure({ pathContext });
539
+ return runTest({
540
+ type: normalizeType(input.type),
541
+ platform
542
+ });
543
+ },
544
+ getDefinition: () => cloneDefinition(definition)
545
+ };
546
+ }
547
+
548
+ module.exports = {
549
+ HOOK_TYPES,
550
+ HOOK_DEFINITIONS,
551
+ MANAGED_HOOK_NAME,
552
+ configure,
553
+ createNotificationHooksDriver,
554
+ normalizeType,
555
+ parseManagedType,
556
+ isManagedNotifyPath,
557
+ getClaudeHookStatus,
558
+ getCodexHookStatus,
559
+ getGeminiHookStatus,
560
+ getOpenCodeHookStatus,
561
+ getOmpHookStatus,
562
+ parseCodexNotificationStatus,
563
+ parseGeminiNotificationStatus,
564
+ parseOpenCodeNotificationStatus,
565
+ parseOmpNotificationStatus,
566
+ buildClaudeCommand,
567
+ buildCodexNotifyCommand,
568
+ buildGeminiCommand,
569
+ buildOpenCodePluginContent,
570
+ buildOmpExtensionContent,
571
+ getOpenCodeManagedPluginPath,
572
+ getOmpManagedExtensionPath,
573
+ saveClaudeHook,
574
+ saveCodexHook,
575
+ saveGeminiHook,
576
+ saveOpenCodeHook,
577
+ saveOmpHook
578
+ };