wind-agent-cli 1.37.2 → 1.37.3

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 (374) hide show
  1. package/LICENSE +718 -718
  2. package/README.md +1 -1
  3. package/dist/api-docs.html +901 -901
  4. package/dist/assets/{CodeEditor-B2Wf7Fg0.js → CodeEditor-BqmxpZ_D.js} +1 -1
  5. package/dist/assets/{FileTree-N2IkkHlv.js → FileTree-DLE7Ioai.js} +1 -1
  6. package/dist/assets/{GitPanel-DZCeuFZ2.js → GitPanel-f8RMRa8D.js} +1 -1
  7. package/dist/assets/{MarkdownPreview-C0tqYnVu.js → MarkdownPreview-93h_1tJa.js} +1 -1
  8. package/dist/assets/{PluginTabContent-Bnuf-fb8.js → PluginTabContent-DU1jjkXP.js} +1 -1
  9. package/dist/assets/{Shell-BfFnMZ-f.js → Shell-CN_2MRIM.js} +1 -1
  10. package/dist/assets/{StandaloneShell-QmyYwNAl.js → StandaloneShell-D0avS8UE.js} +1 -1
  11. package/dist/assets/{TaskMasterPanel-fMsmvN9L.js → TaskMasterPanel-Cpf1Q5Ph.js} +3 -3
  12. package/dist/assets/{abnfDiagram-N423BO3Z-DjPU7HLs.js → abnfDiagram-N423BO3Z-p3aJIm4T.js} +1 -1
  13. package/dist/assets/{arc-Pdq6Tvr3.js → arc-CTeud6Fl.js} +1 -1
  14. package/dist/assets/{architectureDiagram-T3A2C74G-D0JnT0Vh.js → architectureDiagram-T3A2C74G-CG7kRCJU.js} +1 -1
  15. package/dist/assets/{blockDiagram-VBNYF7ZC-DpaEf3mv.js → blockDiagram-VBNYF7ZC-oSjQ1SgE.js} +1 -1
  16. package/dist/assets/{c4Diagram-5PPSVZJV-MpqlPGFi.js → c4Diagram-5PPSVZJV-RkzF0DJV.js} +1 -1
  17. package/dist/assets/channel-BfQbarn9.js +1 -0
  18. package/dist/assets/{chunk-2GRJ4B5K-DoSdNo8u.js → chunk-2GRJ4B5K-B07uZ07O.js} +1 -1
  19. package/dist/assets/{chunk-2Q5K7J3B-CE7I3uMn.js → chunk-2Q5K7J3B-DNSfO7xS.js} +1 -1
  20. package/dist/assets/{chunk-5RXB4S5H-B4UQ8snD.js → chunk-5RXB4S5H-BTeYcgyb.js} +1 -1
  21. package/dist/assets/{chunk-5VM5RSS4-B55XgqHZ.js → chunk-5VM5RSS4-B7vZV0zC.js} +1 -1
  22. package/dist/assets/{chunk-6Q2QTUOP-BS1KpefW.js → chunk-6Q2QTUOP-DuS_xUGG.js} +1 -1
  23. package/dist/assets/{chunk-GF5L2VYU-DkEPedJP.js → chunk-GF5L2VYU-CKLZ3iVD.js} +1 -1
  24. package/dist/assets/{chunk-JWPE2WC7-DOtkNhMm.js → chunk-JWPE2WC7-DD2hcXvs.js} +1 -1
  25. package/dist/assets/{chunk-KBJHAD2P-BXLjviqM.js → chunk-KBJHAD2P-Cz-l38qp.js} +1 -1
  26. package/dist/assets/{chunk-RYQCIY6F-C50fjNNz.js → chunk-RYQCIY6F-DGFIU1YM.js} +1 -1
  27. package/dist/assets/{chunk-XXDRQBXY-QBYqCkb7.js → chunk-XXDRQBXY-CmfzoYFl.js} +1 -1
  28. package/dist/assets/classDiagram-JCYQIIEL-Bpfe3kq7.js +1 -0
  29. package/dist/assets/classDiagram-v2-OCEON4UE-Bpfe3kq7.js +1 -0
  30. package/dist/assets/{code-xml-VK1YfShP.js → code-xml-CLpHzEOP.js} +1 -1
  31. package/dist/assets/{cose-bilkent-JH36ORCC-DrVTo1Nh.js → cose-bilkent-JH36ORCC-DlFcLXCB.js} +1 -1
  32. package/dist/assets/{cynefin-VYW2F7L2-DnJa_OlQ.js → cynefin-VYW2F7L2-P1HecReO.js} +1 -1
  33. package/dist/assets/{cynefinDiagram-MW4NZA55-CCxBjw9E.js → cynefinDiagram-MW4NZA55-COgduz5P.js} +1 -1
  34. package/dist/assets/{dagre-VZM6K2ZE-C_GvE4lu.js → dagre-VZM6K2ZE-Bbb-siGp.js} +1 -1
  35. package/dist/assets/{diagram-7IWD3JNH-pFzs9HEu.js → diagram-7IWD3JNH-9CWGFMYR.js} +1 -1
  36. package/dist/assets/{diagram-B4RE2ZJO-CcehQC7x.js → diagram-B4RE2ZJO-TWK59T6V.js} +1 -1
  37. package/dist/assets/{diagram-LBJQPF4R-hfKcrrxe.js → diagram-LBJQPF4R-ErMC9yaa.js} +1 -1
  38. package/dist/assets/{diagram-Q27KOJAE-C1semJfK.js → diagram-Q27KOJAE-Dt_-C7hV.js} +1 -1
  39. package/dist/assets/{diagram-UB23O5K3-57hvXQXO.js → diagram-UB23O5K3-BJ1DnRAF.js} +1 -1
  40. package/dist/assets/{ebnfDiagram-BXEA7PRR-9KIAlAVw.js → ebnfDiagram-BXEA7PRR-CE1YaQ9s.js} +1 -1
  41. package/dist/assets/{erDiagram-JOGREHBK-B7OzJ767.js → erDiagram-JOGREHBK-Bqk7N9aY.js} +1 -1
  42. package/dist/assets/{flowDiagram-UKHOOZJN-CJV8fQPR.js → flowDiagram-UKHOOZJN-DEr2II5V.js} +1 -1
  43. package/dist/assets/{ganttDiagram-PKOTCBZU-CbMNWWQu.js → ganttDiagram-PKOTCBZU-CWYAUeYN.js} +1 -1
  44. package/dist/assets/{gitGraphDiagram-DS77QQ5N-I_vZ5waO.js → gitGraphDiagram-DS77QQ5N-tdEcEIM6.js} +1 -1
  45. package/dist/assets/{index-ZHwIojzi.js → index-B-sTfSZq.js} +1 -1
  46. package/dist/assets/{index-GFhXZyl2.js → index-BSe3UiFA.js} +1 -1
  47. package/dist/assets/{index-DFnVoqpx.js → index-B_FDMWar.js} +5 -5
  48. package/dist/assets/{index-DlSeAkw_.js → index-CWJtg2pR.js} +1 -1
  49. package/dist/assets/{infoDiagram-6WML65LV-Dh20Tsbq.js → infoDiagram-6WML65LV-A3IqRUnO.js} +1 -1
  50. package/dist/assets/{ishikawaDiagram-WSZJBQD7-DH2Sm3ko.js → ishikawaDiagram-WSZJBQD7-B2uL6bkK.js} +1 -1
  51. package/dist/assets/{journeyDiagram-NVQOT4AX-BNFQqlVu.js → journeyDiagram-NVQOT4AX-D9JB-hRW.js} +1 -1
  52. package/dist/assets/{kanban-definition-27J2QSJJ-B3iL0ztJ.js → kanban-definition-27J2QSJJ-DmlgiV7K.js} +1 -1
  53. package/dist/assets/{linear-Cwe9dEKA.js → linear-Ct_eoJQk.js} +1 -1
  54. package/dist/assets/{mermaid.core-BYRQSshi.js → mermaid.core-CQ698HNn.js} +5 -5
  55. package/dist/assets/{mindmap-definition-FAOFIHXS-BgfBYMzr.js → mindmap-definition-FAOFIHXS-DGtMgQhf.js} +1 -1
  56. package/dist/assets/{pegDiagram-VL7TDLO6-CNYpECr8.js → pegDiagram-VL7TDLO6-CO6vP4n9.js} +1 -1
  57. package/dist/assets/{pieDiagram-7S7Q4E2Y-DeSrxc4I.js → pieDiagram-7S7Q4E2Y-DMkt_Zfr.js} +1 -1
  58. package/dist/assets/{quadrantDiagram-CIZ2JOQS-BXVVQsa6.js → quadrantDiagram-CIZ2JOQS-DgNxRz6t.js} +1 -1
  59. package/dist/assets/{railroadDiagram-AXF67PYL-JTroIW8F.js → railroadDiagram-AXF67PYL-DKz9UqA9.js} +1 -1
  60. package/dist/assets/{requirementDiagram-LRYGKXZP-C1Z_inLz.js → requirementDiagram-LRYGKXZP-L84XyGgV.js} +1 -1
  61. package/dist/assets/{sankeyDiagram-W5VNT64P-DCJgKFUk.js → sankeyDiagram-W5VNT64P-CQqWbJ3j.js} +1 -1
  62. package/dist/assets/{sequenceDiagram-SI44F4Z6-D8Wrx5Vc.js → sequenceDiagram-SI44F4Z6--tnzS2tb.js} +1 -1
  63. package/dist/assets/{sizeCapture-X5ZJPWSS-CXqD68vD.js → sizeCapture-X5ZJPWSS-DujwEOtm.js} +1 -1
  64. package/dist/assets/{stateDiagram-OKZ733FA-CF0Ekqjo.js → stateDiagram-OKZ733FA-BK3TcZY2.js} +1 -1
  65. package/dist/assets/stateDiagram-v2-UEYNNEHI-_medyomK.js +1 -0
  66. package/dist/assets/{swimlanes-SLNWSIFB-DVIax_k4.js → swimlanes-SLNWSIFB-naX-Uv1B.js} +2 -2
  67. package/dist/assets/swimlanesDiagram-ULZ7WXOC-DstIv3TC.js +8 -0
  68. package/dist/assets/{timeline-definition-Z64GVDOM-DSqk3ApG.js → timeline-definition-Z64GVDOM-C-vP_ddU.js} +1 -1
  69. package/dist/assets/{vennDiagram-T6HMQDX7-DNbTqyG5.js → vennDiagram-T6HMQDX7-DN-I7o-7.js} +1 -1
  70. package/dist/assets/{wardleyDiagram-T6FBY63Y-BNCpsFZV.js → wardleyDiagram-T6FBY63Y-Db9dsaXv.js} +1 -1
  71. package/dist/assets/{xychartDiagram-ELKLHX3M-XsVZphHr.js → xychartDiagram-ELKLHX3M-DE6OxW_p.js} +1 -1
  72. package/dist/clear-cache.html +85 -85
  73. package/dist/convert-icons.md +52 -52
  74. package/dist/favicon.svg +8 -8
  75. package/dist/generate-icons.js +48 -48
  76. package/dist/icons/codex-white.svg +3 -3
  77. package/dist/icons/codex.svg +3 -3
  78. package/dist/icons/cursor-white.svg +11 -11
  79. package/dist/icons/icon-128x128.svg +11 -11
  80. package/dist/icons/icon-144x144.svg +11 -11
  81. package/dist/icons/icon-152x152.svg +11 -11
  82. package/dist/icons/icon-192x192.svg +11 -11
  83. package/dist/icons/icon-384x384.svg +11 -11
  84. package/dist/icons/icon-512x512.svg +11 -11
  85. package/dist/icons/icon-72x72.svg +11 -11
  86. package/dist/icons/icon-96x96.svg +11 -11
  87. package/dist/icons/icon-template.svg +11 -11
  88. package/dist/index.html +56 -56
  89. package/dist/logo.svg +17 -17
  90. package/dist/manifest.json +60 -60
  91. package/dist/sw.js +124 -124
  92. package/dist-server/server/modules/cli/cli.service.js +36 -36
  93. package/dist-server/server/modules/cli/sandbox.service.js +38 -38
  94. package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js +74 -74
  95. package/dist-server/server/modules/commands/commands.routes.js +24 -24
  96. package/dist-server/server/modules/database/migrations.js +190 -190
  97. package/dist-server/server/modules/database/repositories/api-keys.js +3 -3
  98. package/dist-server/server/modules/database/repositories/github-tokens.js +2 -2
  99. package/dist-server/server/modules/database/repositories/notification-channel-endpoints.js +28 -28
  100. package/dist-server/server/modules/database/repositories/notification-preferences.js +4 -4
  101. package/dist-server/server/modules/database/repositories/projects.db.js +61 -61
  102. package/dist-server/server/modules/database/repositories/provider-models.js +35 -35
  103. package/dist-server/server/modules/database/repositories/push-subscriptions.js +5 -5
  104. package/dist-server/server/modules/database/repositories/scan-state.db.js +5 -5
  105. package/dist-server/server/modules/database/repositories/sessions.db.js +92 -92
  106. package/dist-server/server/modules/database/schema.js +177 -177
  107. package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js +6 -6
  108. package/dist-server/server/modules/git/git.routes.js +17 -17
  109. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +12 -12
  110. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js +9 -9
  111. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.test.js +17 -17
  112. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +25 -25
  113. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +27 -27
  114. package/dist-server/server/modules/providers/services/provider-token-usage.service.js +9 -9
  115. package/dist-server/server/modules/providers/tests/mcp.test.js +3 -3
  116. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +96 -96
  117. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +18 -18
  118. package/dist-server/server/modules/taskmaster/taskmaster.routes.js +419 -419
  119. package/electron/cloud.js +260 -260
  120. package/electron/desktopNotifications.js +378 -378
  121. package/electron/desktopWindow.js +766 -766
  122. package/electron/launcher/index.html +14 -14
  123. package/electron/launcher/launcher.css +801 -801
  124. package/electron/launcher/launcher.js +687 -687
  125. package/electron/localServer.js +549 -549
  126. package/electron/main.js +944 -944
  127. package/electron/preload.cjs +60 -60
  128. package/electron/scripts/generate-macos-icon.js +62 -62
  129. package/electron/serverInstaller.js +277 -277
  130. package/electron/tabs.js +87 -87
  131. package/electron/viewHost.js +331 -331
  132. package/package.json +250 -247
  133. package/public/api-docs.html +901 -901
  134. package/scripts/fix-node-pty.js +67 -67
  135. package/scripts/promote-dist-server.mjs +50 -50
  136. package/scripts/release/build-server-bundle.js +176 -176
  137. package/scripts/release/prepare-desktop-app.js +152 -152
  138. package/server/index.ts +399 -399
  139. package/server/load-env.ts +47 -47
  140. package/server/modules/agent/agent.module.ts +52 -52
  141. package/server/modules/agent/agent.routes.ts +1287 -1287
  142. package/server/modules/agent/index.ts +2 -2
  143. package/server/modules/agent/tests/agent.routes.test.ts +205 -205
  144. package/server/modules/assets/assets.routes.ts +150 -150
  145. package/server/modules/assets/index.ts +3 -3
  146. package/server/modules/assets/services/image-assets.service.ts +127 -127
  147. package/server/modules/assets/tests/image-assets.service.test.ts +74 -74
  148. package/server/modules/auth/auth.middleware.ts +163 -163
  149. package/server/modules/auth/auth.module.ts +38 -38
  150. package/server/modules/auth/auth.routes.ts +57 -57
  151. package/server/modules/auth/auth.service.ts +155 -155
  152. package/server/modules/auth/index.ts +9 -9
  153. package/server/modules/auth/tests/auth.service.test.ts +95 -95
  154. package/server/modules/browser-use/browser-use-mcp.routes.ts +120 -120
  155. package/server/modules/browser-use/browser-use-mcp.ts +386 -386
  156. package/server/modules/browser-use/browser-use-runtime.ts +10 -10
  157. package/server/modules/browser-use/browser-use.routes.ts +96 -96
  158. package/server/modules/browser-use/browser-use.service.ts +836 -836
  159. package/server/modules/browser-use/index.ts +11 -11
  160. package/server/modules/browser-use/tests/browser-use.service.test.ts +10 -10
  161. package/server/modules/cli/cli.module.ts +93 -93
  162. package/server/modules/cli/cli.service.ts +248 -248
  163. package/server/modules/cli/cli.ts +19 -19
  164. package/server/modules/cli/index.ts +2 -2
  165. package/server/modules/cli/sandbox.service.ts +398 -398
  166. package/server/modules/cli/tests/cli-environment-bootstrap.test.ts +186 -186
  167. package/server/modules/cli/tests/cli.service.test.ts +86 -86
  168. package/server/modules/cli/tests/sandbox.service.test.ts +58 -58
  169. package/server/modules/commands/commands.module.ts +22 -22
  170. package/server/modules/commands/commands.routes.ts +586 -586
  171. package/server/modules/commands/index.ts +2 -2
  172. package/server/modules/commands/tests/commands.test.ts +109 -109
  173. package/server/modules/database/connection.ts +143 -143
  174. package/server/modules/database/index.ts +17 -17
  175. package/server/modules/database/init-db.ts +17 -17
  176. package/server/modules/database/migrations.ts +515 -515
  177. package/server/modules/database/repositories/api-keys.ts +119 -119
  178. package/server/modules/database/repositories/app-config.ts +53 -53
  179. package/server/modules/database/repositories/credentials.ts +106 -106
  180. package/server/modules/database/repositories/github-tokens.ts +100 -100
  181. package/server/modules/database/repositories/notification-channel-endpoints.ts +153 -153
  182. package/server/modules/database/repositories/notification-preferences.ts +117 -117
  183. package/server/modules/database/repositories/projects.db.ts +196 -196
  184. package/server/modules/database/repositories/provider-models.ts +168 -168
  185. package/server/modules/database/repositories/push-subscriptions.ts +80 -80
  186. package/server/modules/database/repositories/scan-state.db.ts +42 -42
  187. package/server/modules/database/repositories/sessions.db.ts +524 -524
  188. package/server/modules/database/repositories/users.ts +140 -140
  189. package/server/modules/database/repositories/vapid-keys.ts +57 -57
  190. package/server/modules/database/schema.ts +210 -210
  191. package/server/modules/database/tests/projects.db.integration.test.ts +72 -72
  192. package/server/modules/database/tests/provider-models.db.integration.test.ts +125 -125
  193. package/server/modules/database/tests/sessions-provider-mapping.test.ts +109 -109
  194. package/server/modules/database/tests/sessions.db.integration.test.ts +116 -116
  195. package/server/modules/file-tree/file-tree.module.ts +116 -116
  196. package/server/modules/file-tree/file-tree.routes.ts +258 -258
  197. package/server/modules/file-tree/file-tree.service.ts +675 -675
  198. package/server/modules/file-tree/index.ts +2 -2
  199. package/server/modules/file-tree/tests/file-tree.routes.test.ts +157 -157
  200. package/server/modules/file-tree/tests/file-tree.service.test.ts +371 -371
  201. package/server/modules/git/git-branch.service.ts +43 -43
  202. package/server/modules/git/git-parsing.service.ts +66 -66
  203. package/server/modules/git/git.module.ts +22 -22
  204. package/server/modules/git/git.routes.ts +1596 -1596
  205. package/server/modules/git/index.ts +2 -2
  206. package/server/modules/git/tests/git-branch.service.test.ts +60 -60
  207. package/server/modules/git/tests/git-init.routes.test.ts +132 -132
  208. package/server/modules/git/tests/git.test.ts +106 -106
  209. package/server/modules/notifications/index.ts +24 -24
  210. package/server/modules/notifications/notifications.routes.ts +127 -127
  211. package/server/modules/notifications/services/desktop-notification-clients.service.ts +124 -124
  212. package/server/modules/notifications/services/notification-orchestrator.service.js +310 -310
  213. package/server/modules/notifications/tests/notification-orchestrator.integration.test.ts +55 -55
  214. package/server/modules/notifications/vapid-keys.service.ts +38 -38
  215. package/server/modules/notifications/websocket/desktop-notifications-websocket.service.ts +109 -109
  216. package/server/modules/plugins/index.ts +9 -9
  217. package/server/modules/plugins/plugin-process.service.ts +217 -217
  218. package/server/modules/plugins/plugin-registry.service.ts +459 -459
  219. package/server/modules/plugins/plugins.module.ts +33 -33
  220. package/server/modules/plugins/plugins.routes.ts +66 -66
  221. package/server/modules/plugins/plugins.service.ts +147 -147
  222. package/server/modules/plugins/tests/plugins.service.test.ts +32 -32
  223. package/server/modules/projects/index.ts +11 -11
  224. package/server/modules/projects/projects.routes.ts +273 -273
  225. package/server/modules/projects/services/project-clone.service.ts +323 -323
  226. package/server/modules/projects/services/project-delete.service.ts +90 -90
  227. package/server/modules/projects/services/project-management.service.ts +144 -144
  228. package/server/modules/projects/services/project-star.service.ts +78 -78
  229. package/server/modules/projects/services/projects-has-taskmaster.service.ts +248 -248
  230. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +314 -314
  231. package/server/modules/projects/tests/project-clone.service.test.ts +183 -183
  232. package/server/modules/projects/tests/project-management.service.test.ts +117 -117
  233. package/server/modules/projects/tests/project-star.service.test.ts +123 -123
  234. package/server/modules/projects/tests/projects-has-taskmaster.service.test.ts +105 -105
  235. package/server/modules/providers/README.md +380 -380
  236. package/server/modules/providers/index.ts +10 -10
  237. package/server/modules/providers/list/claude/claude-auth.provider.ts +160 -160
  238. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -135
  239. package/server/modules/providers/list/claude/claude-models.provider.ts +294 -294
  240. package/server/modules/providers/list/claude/claude-runtime.provider.js +1068 -1068
  241. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +203 -203
  242. package/server/modules/providers/list/claude/claude-sessions.provider.ts +684 -684
  243. package/server/modules/providers/list/claude/claude-skills.provider.ts +265 -265
  244. package/server/modules/providers/list/claude/claude.provider.ts +30 -30
  245. package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -100
  246. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -135
  247. package/server/modules/providers/list/codex/codex-models.provider.ts +123 -123
  248. package/server/modules/providers/list/codex/codex-runtime.provider.js +533 -533
  249. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +203 -203
  250. package/server/modules/providers/list/codex/codex-sessions.provider.ts +938 -938
  251. package/server/modules/providers/list/codex/codex-skills.provider.ts +73 -73
  252. package/server/modules/providers/list/codex/codex.provider.ts +28 -28
  253. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -143
  254. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -108
  255. package/server/modules/providers/list/cursor/cursor-models.provider.ts +119 -119
  256. package/server/modules/providers/list/cursor/cursor-runtime.provider.js +385 -385
  257. package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +159 -159
  258. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +654 -654
  259. package/server/modules/providers/list/cursor/cursor-skills.provider.ts +39 -39
  260. package/server/modules/providers/list/cursor/cursor.provider.ts +30 -30
  261. package/server/modules/providers/list/opencode/opencode-auth.provider.ts +110 -110
  262. package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +228 -228
  263. package/server/modules/providers/list/opencode/opencode-models.provider.ts +203 -203
  264. package/server/modules/providers/list/opencode/opencode-runtime.provider.js +434 -434
  265. package/server/modules/providers/list/opencode/opencode-runtime.provider.test.js +261 -261
  266. package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +179 -179
  267. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +500 -500
  268. package/server/modules/providers/list/opencode/opencode-skills.provider.ts +78 -78
  269. package/server/modules/providers/list/opencode/opencode.provider.ts +30 -30
  270. package/server/modules/providers/provider.registry.ts +36 -36
  271. package/server/modules/providers/provider.routes.ts +877 -877
  272. package/server/modules/providers/services/mcp.service.ts +109 -109
  273. package/server/modules/providers/services/provider-auth.service.ts +26 -26
  274. package/server/modules/providers/services/provider-capabilities.service.ts +97 -97
  275. package/server/modules/providers/services/provider-models.service.ts +401 -401
  276. package/server/modules/providers/services/provider-runtime.service.ts +108 -108
  277. package/server/modules/providers/services/provider-token-usage.service.ts +357 -357
  278. package/server/modules/providers/services/session-conversations-search.service.ts +1321 -1321
  279. package/server/modules/providers/services/session-synchronizer.service.ts +74 -74
  280. package/server/modules/providers/services/sessions-watcher.service.ts +247 -247
  281. package/server/modules/providers/services/sessions.service.ts +471 -471
  282. package/server/modules/providers/services/skills.service.ts +39 -39
  283. package/server/modules/providers/shared/base/abstract.provider.ts +32 -32
  284. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -151
  285. package/server/modules/providers/shared/skills/skills.provider.ts +287 -287
  286. package/server/modules/providers/tests/claude-auth.test.ts +150 -150
  287. package/server/modules/providers/tests/claude-sessions.test.ts +61 -61
  288. package/server/modules/providers/tests/codex-sessions.test.ts +231 -231
  289. package/server/modules/providers/tests/mcp.test.ts +349 -349
  290. package/server/modules/providers/tests/opencode-models.test.ts +41 -41
  291. package/server/modules/providers/tests/opencode-sessions.test.ts +522 -522
  292. package/server/modules/providers/tests/provider-attachment-history.test.ts +247 -247
  293. package/server/modules/providers/tests/provider-models.service.test.ts +353 -353
  294. package/server/modules/providers/tests/provider-runtime.service.test.ts +138 -138
  295. package/server/modules/providers/tests/provider-token-usage.service.test.ts +186 -186
  296. package/server/modules/providers/tests/provider.routes.test.ts +244 -244
  297. package/server/modules/providers/tests/sessions-details.test.ts +73 -73
  298. package/server/modules/providers/tests/sessions.service.test.ts +127 -127
  299. package/server/modules/providers/tests/skills.test.ts +692 -692
  300. package/server/modules/settings/index.ts +2 -2
  301. package/server/modules/settings/settings.module.ts +50 -50
  302. package/server/modules/settings/settings.routes.ts +51 -51
  303. package/server/modules/settings/settings.service.ts +186 -186
  304. package/server/modules/settings/tests/settings.service.test.ts +54 -54
  305. package/server/modules/system/index.ts +2 -2
  306. package/server/modules/system/system.module.ts +62 -62
  307. package/server/modules/system/system.routes.ts +21 -21
  308. package/server/modules/system/system.service.ts +76 -76
  309. package/server/modules/system/tests/system.service.test.ts +118 -118
  310. package/server/modules/taskmaster/index.ts +2 -2
  311. package/server/modules/taskmaster/taskmaster.module.ts +24 -24
  312. package/server/modules/taskmaster/taskmaster.routes.ts +1482 -1482
  313. package/server/modules/taskmaster/taskmaster.service.ts +132 -132
  314. package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +144 -144
  315. package/server/modules/taskmaster/tests/taskmaster.service.test.ts +97 -97
  316. package/server/modules/user/index.ts +2 -2
  317. package/server/modules/user/tests/user.service.test.ts +61 -61
  318. package/server/modules/user/user.module.ts +58 -58
  319. package/server/modules/user/user.routes.ts +50 -50
  320. package/server/modules/user/user.service.ts +85 -85
  321. package/server/modules/voice/index.ts +2 -2
  322. package/server/modules/voice/tests/voice.service.test.ts +98 -98
  323. package/server/modules/voice/voice.module.ts +47 -47
  324. package/server/modules/voice/voice.routes.ts +113 -113
  325. package/server/modules/voice/voice.service.ts +192 -192
  326. package/server/modules/websocket/README.md +273 -273
  327. package/server/modules/websocket/index.ts +3 -3
  328. package/server/modules/websocket/services/chat-run-registry.service.ts +343 -343
  329. package/server/modules/websocket/services/chat-session-writer.service.ts +145 -145
  330. package/server/modules/websocket/services/chat-websocket.service.ts +425 -425
  331. package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +65 -65
  332. package/server/modules/websocket/services/shell-websocket.service.ts +502 -502
  333. package/server/modules/websocket/services/websocket-auth.service.ts +59 -59
  334. package/server/modules/websocket/services/websocket-server.service.ts +124 -124
  335. package/server/modules/websocket/services/websocket-state.service.ts +16 -16
  336. package/server/modules/websocket/services/websocket-writer.service.ts +38 -38
  337. package/server/modules/websocket/tests/chat-attachment-filter.test.ts +59 -59
  338. package/server/modules/websocket/tests/chat-run-registry.test.ts +282 -282
  339. package/server/modules/websocket/tests/shell-websocket.service.test.ts +100 -100
  340. package/server/modules/websocket/tests/websocket-heartbeat.service.test.ts +78 -78
  341. package/server/modules/worktrees/index.ts +2 -2
  342. package/server/modules/worktrees/services/worktree-create-and-open.service.ts +53 -53
  343. package/server/modules/worktrees/services/worktree-create.service.ts +104 -104
  344. package/server/modules/worktrees/services/worktree-git.service.ts +207 -207
  345. package/server/modules/worktrees/services/worktree-list.service.ts +143 -143
  346. package/server/modules/worktrees/services/worktree-merge.service.ts +157 -157
  347. package/server/modules/worktrees/services/worktree-open.service.ts +85 -85
  348. package/server/modules/worktrees/services/worktree-remove.service.ts +88 -88
  349. package/server/modules/worktrees/tests/worktree-create-and-open.service.test.ts +68 -68
  350. package/server/modules/worktrees/tests/worktree-create.service.test.ts +142 -142
  351. package/server/modules/worktrees/tests/worktree-git.service.test.ts +84 -84
  352. package/server/modules/worktrees/tests/worktree-list.service.test.ts +45 -45
  353. package/server/modules/worktrees/tests/worktree-merge.service.test.ts +213 -213
  354. package/server/modules/worktrees/tests/worktree-open.service.test.ts +122 -122
  355. package/server/modules/worktrees/tests/worktree-remove.service.test.ts +227 -227
  356. package/server/modules/worktrees/tests/worktrees.routes.test.ts +199 -199
  357. package/server/modules/worktrees/worktrees.module.ts +113 -113
  358. package/server/modules/worktrees/worktrees.routes.ts +116 -116
  359. package/server/shared/claude-cli-path.ts +139 -139
  360. package/server/shared/frontmatter.ts +18 -18
  361. package/server/shared/image-attachments.ts +435 -435
  362. package/server/shared/interfaces.ts +179 -179
  363. package/server/shared/tests/claude-cli-path.test.ts +61 -61
  364. package/server/shared/tests/image-attachments.test.ts +353 -353
  365. package/server/shared/tests/slice-tail-page.test.ts +42 -42
  366. package/server/shared/types.ts +1226 -1226
  367. package/server/shared/utils.ts +1161 -1161
  368. package/server/tsconfig.json +40 -40
  369. package/shared/networkHosts.js +22 -22
  370. package/dist/assets/channel-Bm0ZLE4z.js +0 -1
  371. package/dist/assets/classDiagram-JCYQIIEL-DqEOcNxw.js +0 -1
  372. package/dist/assets/classDiagram-v2-OCEON4UE-DqEOcNxw.js +0 -1
  373. package/dist/assets/stateDiagram-v2-UEYNNEHI-DARLpEFJ.js +0 -1
  374. package/dist/assets/swimlanesDiagram-ULZ7WXOC-CrgDgaY8.js +0 -8
@@ -1,209 +1,209 @@
1
- // @ts-nocheck -- temporary while command handlers are extracted into the injected service.
2
- import path from "path";
3
-
4
- import express from "express";
5
-
6
- import { parseFrontMatter } from "../../shared/frontmatter.js";
7
-
8
- type CommandsRouterDependencies = {
9
- fileSystem: typeof import('node:fs/promises');
10
- homeDirectory(): string;
11
- appRoot: string;
12
- models: typeof import('../providers/index.js').providerModelsService;
13
- runtime: {
14
- uptime(): number;
15
- memoryUsage(): NodeJS.MemoryUsage;
16
- version: string;
17
- platform: NodeJS.Platform;
18
- pid: number;
19
- };
20
- };
21
-
22
- /** Creates Commands routes around explicit filesystem, model-catalog, and runtime adapters. */
23
- export function createCommandsRouter(dependencies: CommandsRouterDependencies): express.Router {
24
- const fs = dependencies.fileSystem;
25
- const os = { homedir: dependencies.homeDirectory };
26
- const APP_ROOT = dependencies.appRoot;
27
- const providerModelsService = dependencies.models;
28
- const process = dependencies.runtime;
29
- const router = express.Router();
30
-
31
- const MODEL_PROVIDERS = ["claude", "cursor", "codex", "opencode"];
32
-
33
- const MODEL_PROVIDER_LABELS = {
34
- claude: "Claude",
35
- cursor: "Cursor",
36
- codex: "Codex",
37
- opencode: "OpenCode",
38
- };
39
-
40
- const readModelProvider = (value) => {
41
- if (typeof value !== "string") {
42
- return "claude";
43
- }
44
-
45
- const normalized = value.trim().toLowerCase();
46
- return MODEL_PROVIDERS.includes(normalized) ? normalized : "claude";
47
- };
48
-
49
- /**
50
- * Resolves the model a command should report.
51
- *
52
- * `context.model` is what the composer would send right now, so it stands in
53
- * for a chat that has no session row yet; the service prefers the session's own
54
- * recorded model whenever there is one.
55
- */
56
- const resolveCommandModel = async (modelsService, provider, context) => {
57
- const resolved = await modelsService.resolveSessionModel(provider, {
58
- sessionId: context?.sessionId,
59
- requestedModel: context?.model,
60
- });
61
- return resolved.model;
62
- };
63
-
64
- const executeModelsCommand = async (args, context, modelsService) => {
65
- const currentProvider = readModelProvider(context?.provider);
66
- const catalog = await modelsService.getProviderModels(currentProvider);
67
- const currentModel = await resolveCommandModel(modelsService, currentProvider, context);
68
- const availableModels = catalog.OPTIONS.map((option) => option.value);
69
- const availableOptions = catalog.OPTIONS.map((option) => ({
70
- value: option.value,
71
- label: option.label,
72
- description: option.description,
73
- recordId: option.recordId,
74
- isCustom: option.isCustom,
75
- }));
76
-
77
- return {
78
- type: "builtin",
79
- action: "models",
80
- data: {
81
- current: {
82
- provider: currentProvider,
83
- providerLabel: MODEL_PROVIDER_LABELS[currentProvider],
84
- model: currentModel,
85
- },
86
- available: {
87
- [currentProvider]: availableModels,
88
- },
89
- availableModels,
90
- availableOptions,
91
- defaultModel: catalog.DEFAULT,
92
- message: `Current model: ${currentModel}`,
93
- },
94
- };
95
- };
96
-
97
- /**
98
- * Recursively scan directory for command files (.md)
99
- * @param {string} dir - Directory to scan
100
- * @param {string} baseDir - Base directory for relative paths
101
- * @param {string} namespace - Namespace for commands (e.g., 'project', 'user')
102
- * @returns {Promise<Array>} Array of command objects
103
- */
104
- async function scanCommandsDirectory(dir, baseDir, namespace) {
105
- const commands = [];
106
-
107
- try {
108
- // Check if directory exists
109
- await fs.access(dir);
110
-
111
- const entries = await fs.readdir(dir, { withFileTypes: true });
112
-
113
- for (const entry of entries) {
114
- const fullPath = path.join(dir, entry.name);
115
-
116
- if (entry.isDirectory()) {
117
- // Recursively scan subdirectories
118
- const subCommands = await scanCommandsDirectory(
119
- fullPath,
120
- baseDir,
121
- namespace,
122
- );
123
- commands.push(...subCommands);
124
- } else if (entry.isFile() && entry.name.endsWith(".md")) {
125
- // Parse markdown file for metadata
126
- try {
127
- const content = await fs.readFile(fullPath, "utf8");
128
- const { data: frontmatter, content: commandContent } =
129
- parseFrontMatter(content);
130
-
131
- // Calculate relative path from baseDir for command name
132
- const relativePath = path.relative(baseDir, fullPath);
133
- // Remove .md extension and convert to command name
134
- const commandName =
135
- "/" + relativePath.replace(/\.md$/, "").replace(/\\/g, "/");
136
-
137
- // Extract description from frontmatter or first line of content
138
- let description = frontmatter.description || "";
139
- if (!description) {
140
- const firstLine = commandContent.trim().split("\n")[0];
141
- description = firstLine.replace(/^#+\s*/, "").trim();
142
- }
143
-
144
- commands.push({
145
- name: commandName,
146
- path: fullPath,
147
- relativePath,
148
- description,
149
- namespace,
150
- metadata: frontmatter,
151
- });
152
- } catch (err) {
153
- console.error(`Error parsing command file ${fullPath}:`, err.message);
154
- }
155
- }
156
- }
157
- } catch (err) {
158
- // Directory doesn't exist or can't be accessed - this is okay
159
- if (err.code !== "ENOENT" && err.code !== "EACCES") {
160
- console.error(`Error scanning directory ${dir}:`, err.message);
161
- }
162
- }
163
-
164
- return commands;
165
- }
166
-
167
- /**
168
- * Built-in commands that are always available
169
- */
1
+ // @ts-nocheck -- temporary while command handlers are extracted into the injected service.
2
+ import path from "path";
3
+
4
+ import express from "express";
5
+
6
+ import { parseFrontMatter } from "../../shared/frontmatter.js";
7
+
8
+ type CommandsRouterDependencies = {
9
+ fileSystem: typeof import('node:fs/promises');
10
+ homeDirectory(): string;
11
+ appRoot: string;
12
+ models: typeof import('../providers/index.js').providerModelsService;
13
+ runtime: {
14
+ uptime(): number;
15
+ memoryUsage(): NodeJS.MemoryUsage;
16
+ version: string;
17
+ platform: NodeJS.Platform;
18
+ pid: number;
19
+ };
20
+ };
21
+
22
+ /** Creates Commands routes around explicit filesystem, model-catalog, and runtime adapters. */
23
+ export function createCommandsRouter(dependencies: CommandsRouterDependencies): express.Router {
24
+ const fs = dependencies.fileSystem;
25
+ const os = { homedir: dependencies.homeDirectory };
26
+ const APP_ROOT = dependencies.appRoot;
27
+ const providerModelsService = dependencies.models;
28
+ const process = dependencies.runtime;
29
+ const router = express.Router();
30
+
31
+ const MODEL_PROVIDERS = ["claude", "cursor", "codex", "opencode"];
32
+
33
+ const MODEL_PROVIDER_LABELS = {
34
+ claude: "Claude",
35
+ cursor: "Cursor",
36
+ codex: "Codex",
37
+ opencode: "OpenCode",
38
+ };
39
+
40
+ const readModelProvider = (value) => {
41
+ if (typeof value !== "string") {
42
+ return "claude";
43
+ }
44
+
45
+ const normalized = value.trim().toLowerCase();
46
+ return MODEL_PROVIDERS.includes(normalized) ? normalized : "claude";
47
+ };
48
+
49
+ /**
50
+ * Resolves the model a command should report.
51
+ *
52
+ * `context.model` is what the composer would send right now, so it stands in
53
+ * for a chat that has no session row yet; the service prefers the session's own
54
+ * recorded model whenever there is one.
55
+ */
56
+ const resolveCommandModel = async (modelsService, provider, context) => {
57
+ const resolved = await modelsService.resolveSessionModel(provider, {
58
+ sessionId: context?.sessionId,
59
+ requestedModel: context?.model,
60
+ });
61
+ return resolved.model;
62
+ };
63
+
64
+ const executeModelsCommand = async (args, context, modelsService) => {
65
+ const currentProvider = readModelProvider(context?.provider);
66
+ const catalog = await modelsService.getProviderModels(currentProvider);
67
+ const currentModel = await resolveCommandModel(modelsService, currentProvider, context);
68
+ const availableModels = catalog.OPTIONS.map((option) => option.value);
69
+ const availableOptions = catalog.OPTIONS.map((option) => ({
70
+ value: option.value,
71
+ label: option.label,
72
+ description: option.description,
73
+ recordId: option.recordId,
74
+ isCustom: option.isCustom,
75
+ }));
76
+
77
+ return {
78
+ type: "builtin",
79
+ action: "models",
80
+ data: {
81
+ current: {
82
+ provider: currentProvider,
83
+ providerLabel: MODEL_PROVIDER_LABELS[currentProvider],
84
+ model: currentModel,
85
+ },
86
+ available: {
87
+ [currentProvider]: availableModels,
88
+ },
89
+ availableModels,
90
+ availableOptions,
91
+ defaultModel: catalog.DEFAULT,
92
+ message: `Current model: ${currentModel}`,
93
+ },
94
+ };
95
+ };
96
+
97
+ /**
98
+ * Recursively scan directory for command files (.md)
99
+ * @param {string} dir - Directory to scan
100
+ * @param {string} baseDir - Base directory for relative paths
101
+ * @param {string} namespace - Namespace for commands (e.g., 'project', 'user')
102
+ * @returns {Promise<Array>} Array of command objects
103
+ */
104
+ async function scanCommandsDirectory(dir, baseDir, namespace) {
105
+ const commands = [];
106
+
107
+ try {
108
+ // Check if directory exists
109
+ await fs.access(dir);
110
+
111
+ const entries = await fs.readdir(dir, { withFileTypes: true });
112
+
113
+ for (const entry of entries) {
114
+ const fullPath = path.join(dir, entry.name);
115
+
116
+ if (entry.isDirectory()) {
117
+ // Recursively scan subdirectories
118
+ const subCommands = await scanCommandsDirectory(
119
+ fullPath,
120
+ baseDir,
121
+ namespace,
122
+ );
123
+ commands.push(...subCommands);
124
+ } else if (entry.isFile() && entry.name.endsWith(".md")) {
125
+ // Parse markdown file for metadata
126
+ try {
127
+ const content = await fs.readFile(fullPath, "utf8");
128
+ const { data: frontmatter, content: commandContent } =
129
+ parseFrontMatter(content);
130
+
131
+ // Calculate relative path from baseDir for command name
132
+ const relativePath = path.relative(baseDir, fullPath);
133
+ // Remove .md extension and convert to command name
134
+ const commandName =
135
+ "/" + relativePath.replace(/\.md$/, "").replace(/\\/g, "/");
136
+
137
+ // Extract description from frontmatter or first line of content
138
+ let description = frontmatter.description || "";
139
+ if (!description) {
140
+ const firstLine = commandContent.trim().split("\n")[0];
141
+ description = firstLine.replace(/^#+\s*/, "").trim();
142
+ }
143
+
144
+ commands.push({
145
+ name: commandName,
146
+ path: fullPath,
147
+ relativePath,
148
+ description,
149
+ namespace,
150
+ metadata: frontmatter,
151
+ });
152
+ } catch (err) {
153
+ console.error(`Error parsing command file ${fullPath}:`, err.message);
154
+ }
155
+ }
156
+ }
157
+ } catch (err) {
158
+ // Directory doesn't exist or can't be accessed - this is okay
159
+ if (err.code !== "ENOENT" && err.code !== "EACCES") {
160
+ console.error(`Error scanning directory ${dir}:`, err.message);
161
+ }
162
+ }
163
+
164
+ return commands;
165
+ }
166
+
167
+ /**
168
+ * Built-in commands that are always available
169
+ */
170
170
  const builtInCommands = [
171
- {
172
- name: "/help",
173
- description: "Show help documentation for Claude Code",
174
- namespace: "builtin",
175
- metadata: { type: "builtin" },
176
- },
177
- {
178
- name: "/models",
179
- description: "View available models for the current provider",
180
- namespace: "builtin",
181
- metadata: { type: "builtin" },
182
- },
183
- {
184
- name: "/cost",
185
- description: "Display token usage information",
186
- namespace: "builtin",
187
- metadata: { type: "builtin" },
188
- },
189
- {
190
- name: "/memory",
191
- description: "Open CLAUDE.md memory file for editing",
192
- namespace: "builtin",
193
- metadata: { type: "builtin" },
194
- },
195
- {
196
- name: "/config",
197
- description: "Open settings and configuration",
198
- namespace: "builtin",
199
- metadata: { type: "builtin" },
200
- },
201
- {
202
- name: "/status",
203
- description: "Show system status and version information",
204
- namespace: "builtin",
205
- metadata: { type: "builtin" },
206
- },
171
+ {
172
+ name: "/help",
173
+ description: "Show help documentation for Claude Code",
174
+ namespace: "builtin",
175
+ metadata: { type: "builtin" },
176
+ },
177
+ {
178
+ name: "/models",
179
+ description: "View available models for the current provider",
180
+ namespace: "builtin",
181
+ metadata: { type: "builtin" },
182
+ },
183
+ {
184
+ name: "/cost",
185
+ description: "Display token usage information",
186
+ namespace: "builtin",
187
+ metadata: { type: "builtin" },
188
+ },
189
+ {
190
+ name: "/memory",
191
+ description: "Open CLAUDE.md memory file for editing",
192
+ namespace: "builtin",
193
+ metadata: { type: "builtin" },
194
+ },
195
+ {
196
+ name: "/config",
197
+ description: "Open settings and configuration",
198
+ namespace: "builtin",
199
+ metadata: { type: "builtin" },
200
+ },
201
+ {
202
+ name: "/status",
203
+ description: "Show system status and version information",
204
+ namespace: "builtin",
205
+ metadata: { type: "builtin" },
206
+ },
207
207
  ];
208
208
 
209
209
  const codexNativeCommands = [
@@ -238,242 +238,242 @@ const codexNativeCommands = [
238
238
  metadata: { type: "provider", provider: "codex" },
239
239
  },
240
240
  ];
241
-
242
- /**
243
- * Built-in command handlers
244
- * Each handler returns { type: 'builtin', action: string, data: any }
245
- */
246
- const builtInHandlers = {
241
+
242
+ /**
243
+ * Built-in command handlers
244
+ * Each handler returns { type: 'builtin', action: string, data: any }
245
+ */
246
+ const builtInHandlers = {
247
247
  "/help": async (args, context) => {
248
248
  const isCodex = readModelProvider(context?.provider) === "codex";
249
249
  const helpCommands = isCodex
250
250
  ? [...builtInCommands, ...codexNativeCommands]
251
251
  : builtInCommands;
252
252
  const helpText = `# ${isCodex ? "Codex and CloudCLI" : "CloudCLI"} Commands
253
-
254
- ## Built-in Commands
255
-
253
+
254
+ ## Built-in Commands
255
+
256
256
  ${helpCommands
257
- .map(
258
- (cmd) => `### ${cmd.name}
259
- ${cmd.description}
260
- `,
261
- )
262
- .join("\n")}
263
-
264
- ## Custom Commands
265
-
266
- Custom commands can be created in:
267
- - Project: \`.claude/commands/\` (project-specific)
268
- - User: \`~/.claude/commands/\` (available in all projects)
269
-
270
- ### Command Syntax
271
-
272
- - **Arguments**: Use \`$ARGUMENTS\` for all args or \`$1\`, \`$2\`, etc. for positional
273
- - **File Includes**: Use \`@filename\` to include file contents
274
- - **Bash Commands**: Use \`!command\` to execute bash commands
275
-
276
- ### Examples
277
-
278
- \`\`\`markdown
279
- /mycommand arg1 arg2
280
- \`\`\`
281
- `;
282
-
283
- return {
284
- type: "builtin",
285
- action: "help",
286
- data: {
287
- content: helpText,
288
- format: "markdown",
257
+ .map(
258
+ (cmd) => `### ${cmd.name}
259
+ ${cmd.description}
260
+ `,
261
+ )
262
+ .join("\n")}
263
+
264
+ ## Custom Commands
265
+
266
+ Custom commands can be created in:
267
+ - Project: \`.claude/commands/\` (project-specific)
268
+ - User: \`~/.claude/commands/\` (available in all projects)
269
+
270
+ ### Command Syntax
271
+
272
+ - **Arguments**: Use \`$ARGUMENTS\` for all args or \`$1\`, \`$2\`, etc. for positional
273
+ - **File Includes**: Use \`@filename\` to include file contents
274
+ - **Bash Commands**: Use \`!command\` to execute bash commands
275
+
276
+ ### Examples
277
+
278
+ \`\`\`markdown
279
+ /mycommand arg1 arg2
280
+ \`\`\`
281
+ `;
282
+
283
+ return {
284
+ type: "builtin",
285
+ action: "help",
286
+ data: {
287
+ content: helpText,
288
+ format: "markdown",
289
289
  commands: helpCommands.map((command) => ({
290
- name: command.name,
291
- description: command.description,
292
- namespace: command.namespace,
293
- })),
294
- },
295
- };
296
- },
297
-
290
+ name: command.name,
291
+ description: command.description,
292
+ namespace: command.namespace,
293
+ })),
294
+ },
295
+ };
296
+ },
297
+
298
298
  "/models": (args, context) => executeModelsCommand(args, context, providerModelsService),
299
299
  "/model": (args, context) => executeModelsCommand(args, context, providerModelsService),
300
-
301
- "/cost": async (args, context) => {
302
- const tokenUsage = context?.tokenUsage || {};
303
- const provider = readModelProvider(context?.provider);
304
- const model = await resolveCommandModel(providerModelsService, provider, context);
305
-
306
- const reportedUsed =
307
- Number(
308
- tokenUsage.used ?? tokenUsage.totalUsed ?? tokenUsage.total_tokens ?? 0,
309
- ) || 0;
310
- const total =
311
- Number(
312
- tokenUsage.total ??
313
- tokenUsage.contextWindow ??
314
- 0,
315
- ) || 0;
316
- const normalizedInputValue =
317
- tokenUsage.inputTokens ??
318
- tokenUsage.input ??
319
- tokenUsage.cumulativeInputTokens ??
320
- tokenUsage.breakdown?.input ??
321
- tokenUsage.promptTokens;
322
- const directInputTokens =
323
- Number(
324
- normalizedInputValue ??
325
- tokenUsage.input_tokens ??
326
- 0
327
- ) || 0;
328
- const cacheReadTokens =
329
- Number(
330
- tokenUsage.cacheReadTokens ??
331
- tokenUsage.cache_read_input_tokens ??
332
- tokenUsage.cacheReadInputTokens ??
333
- 0,
334
- ) || 0;
335
- const cacheCreationTokens =
336
- Number(
337
- tokenUsage.cacheCreationTokens ??
338
- tokenUsage.cache_creation_input_tokens ??
339
- tokenUsage.cacheCreationInputTokens ??
340
- 0,
341
- ) || 0;
342
- const inputTokens = normalizedInputValue == null
343
- ? directInputTokens + cacheReadTokens + cacheCreationTokens
344
- : directInputTokens;
345
- const outputTokens =
346
- Number(
347
- tokenUsage.outputTokens ??
348
- tokenUsage.output ??
349
- tokenUsage.output_tokens ??
350
- tokenUsage.cumulativeOutputTokens ??
351
- tokenUsage.breakdown?.output ??
352
- tokenUsage.completionTokens ??
353
- 0,
354
- ) || 0;
355
- const computedUsed = inputTokens + outputTokens;
356
- const hasTokenBreakdown = computedUsed > 0;
357
- const used = Math.max(reportedUsed, computedUsed);
358
-
359
- return {
360
- type: "builtin",
361
- action: "cost",
362
- data: {
363
- tokenUsage: {
364
- used,
365
- total,
366
- },
367
- ...(hasTokenBreakdown
368
- ? {
369
- tokenBreakdown: {
370
- input: inputTokens,
371
- output: outputTokens,
372
- },
373
- }
374
- : {}),
375
- provider,
376
- model,
377
- },
378
- };
379
- },
380
-
381
- "/status": async (args, context) => {
382
- // Read version from package.json
383
- const packageJsonPath = path.join(APP_ROOT, "package.json");
384
- let version = "unknown";
385
- let packageName = "claude-code-ui";
386
-
387
- try {
388
- const packageJson = JSON.parse(
389
- await fs.readFile(packageJsonPath, "utf8"),
390
- );
391
- version = packageJson.version;
392
- packageName = packageJson.name;
393
- } catch (err) {
394
- console.error("Error reading package.json:", err);
395
- }
396
-
397
- const uptime = process.uptime();
398
- const uptimeMinutes = Math.floor(uptime / 60);
399
- const uptimeHours = Math.floor(uptimeMinutes / 60);
400
- const uptimeFormatted =
401
- uptimeHours > 0
402
- ? `${uptimeHours}h ${uptimeMinutes % 60}m`
403
- : `${uptimeMinutes}m`;
404
-
405
- const statusProvider = readModelProvider(context?.provider);
406
- const model = await resolveCommandModel(providerModelsService, statusProvider, context);
407
- const memoryUsage = process.memoryUsage();
408
-
409
- return {
410
- type: "builtin",
411
- action: "status",
412
- data: {
413
- version,
414
- packageName,
415
- uptime: uptimeFormatted,
416
- uptimeSeconds: Math.floor(uptime),
417
- model,
418
- provider: statusProvider,
419
- nodeVersion: process.version,
420
- platform: process.platform,
421
- pid: process.pid,
422
- memoryUsage: {
423
- rssMb: Math.round(memoryUsage.rss / 1024 / 1024),
424
- heapUsedMb: Math.round(memoryUsage.heapUsed / 1024 / 1024),
425
- heapTotalMb: Math.round(memoryUsage.heapTotal / 1024 / 1024),
426
- },
427
- },
428
- };
429
- },
430
-
431
- "/memory": async (args, context) => {
432
- const projectPath = context?.projectPath;
433
-
434
- if (!projectPath) {
435
- return {
436
- type: "builtin",
437
- action: "memory",
438
- data: {
439
- error: "No project selected",
440
- message: "Please select a project to access its CLAUDE.md file",
441
- },
442
- };
443
- }
444
-
445
- const claudeMdPath = path.join(projectPath, "CLAUDE.md");
446
-
447
- // Check if CLAUDE.md exists
448
- let exists = false;
449
- try {
450
- await fs.access(claudeMdPath);
451
- exists = true;
452
- } catch (err) {
453
- // File doesn't exist
454
- }
455
-
456
- return {
457
- type: "builtin",
458
- action: "memory",
459
- data: {
460
- path: claudeMdPath,
461
- exists,
462
- message: exists
463
- ? `Opening CLAUDE.md at ${claudeMdPath}`
464
- : `CLAUDE.md not found at ${claudeMdPath}. Create it to store project-specific instructions.`,
465
- },
466
- };
467
- },
468
-
300
+
301
+ "/cost": async (args, context) => {
302
+ const tokenUsage = context?.tokenUsage || {};
303
+ const provider = readModelProvider(context?.provider);
304
+ const model = await resolveCommandModel(providerModelsService, provider, context);
305
+
306
+ const reportedUsed =
307
+ Number(
308
+ tokenUsage.used ?? tokenUsage.totalUsed ?? tokenUsage.total_tokens ?? 0,
309
+ ) || 0;
310
+ const total =
311
+ Number(
312
+ tokenUsage.total ??
313
+ tokenUsage.contextWindow ??
314
+ 0,
315
+ ) || 0;
316
+ const normalizedInputValue =
317
+ tokenUsage.inputTokens ??
318
+ tokenUsage.input ??
319
+ tokenUsage.cumulativeInputTokens ??
320
+ tokenUsage.breakdown?.input ??
321
+ tokenUsage.promptTokens;
322
+ const directInputTokens =
323
+ Number(
324
+ normalizedInputValue ??
325
+ tokenUsage.input_tokens ??
326
+ 0
327
+ ) || 0;
328
+ const cacheReadTokens =
329
+ Number(
330
+ tokenUsage.cacheReadTokens ??
331
+ tokenUsage.cache_read_input_tokens ??
332
+ tokenUsage.cacheReadInputTokens ??
333
+ 0,
334
+ ) || 0;
335
+ const cacheCreationTokens =
336
+ Number(
337
+ tokenUsage.cacheCreationTokens ??
338
+ tokenUsage.cache_creation_input_tokens ??
339
+ tokenUsage.cacheCreationInputTokens ??
340
+ 0,
341
+ ) || 0;
342
+ const inputTokens = normalizedInputValue == null
343
+ ? directInputTokens + cacheReadTokens + cacheCreationTokens
344
+ : directInputTokens;
345
+ const outputTokens =
346
+ Number(
347
+ tokenUsage.outputTokens ??
348
+ tokenUsage.output ??
349
+ tokenUsage.output_tokens ??
350
+ tokenUsage.cumulativeOutputTokens ??
351
+ tokenUsage.breakdown?.output ??
352
+ tokenUsage.completionTokens ??
353
+ 0,
354
+ ) || 0;
355
+ const computedUsed = inputTokens + outputTokens;
356
+ const hasTokenBreakdown = computedUsed > 0;
357
+ const used = Math.max(reportedUsed, computedUsed);
358
+
359
+ return {
360
+ type: "builtin",
361
+ action: "cost",
362
+ data: {
363
+ tokenUsage: {
364
+ used,
365
+ total,
366
+ },
367
+ ...(hasTokenBreakdown
368
+ ? {
369
+ tokenBreakdown: {
370
+ input: inputTokens,
371
+ output: outputTokens,
372
+ },
373
+ }
374
+ : {}),
375
+ provider,
376
+ model,
377
+ },
378
+ };
379
+ },
380
+
381
+ "/status": async (args, context) => {
382
+ // Read version from package.json
383
+ const packageJsonPath = path.join(APP_ROOT, "package.json");
384
+ let version = "unknown";
385
+ let packageName = "claude-code-ui";
386
+
387
+ try {
388
+ const packageJson = JSON.parse(
389
+ await fs.readFile(packageJsonPath, "utf8"),
390
+ );
391
+ version = packageJson.version;
392
+ packageName = packageJson.name;
393
+ } catch (err) {
394
+ console.error("Error reading package.json:", err);
395
+ }
396
+
397
+ const uptime = process.uptime();
398
+ const uptimeMinutes = Math.floor(uptime / 60);
399
+ const uptimeHours = Math.floor(uptimeMinutes / 60);
400
+ const uptimeFormatted =
401
+ uptimeHours > 0
402
+ ? `${uptimeHours}h ${uptimeMinutes % 60}m`
403
+ : `${uptimeMinutes}m`;
404
+
405
+ const statusProvider = readModelProvider(context?.provider);
406
+ const model = await resolveCommandModel(providerModelsService, statusProvider, context);
407
+ const memoryUsage = process.memoryUsage();
408
+
409
+ return {
410
+ type: "builtin",
411
+ action: "status",
412
+ data: {
413
+ version,
414
+ packageName,
415
+ uptime: uptimeFormatted,
416
+ uptimeSeconds: Math.floor(uptime),
417
+ model,
418
+ provider: statusProvider,
419
+ nodeVersion: process.version,
420
+ platform: process.platform,
421
+ pid: process.pid,
422
+ memoryUsage: {
423
+ rssMb: Math.round(memoryUsage.rss / 1024 / 1024),
424
+ heapUsedMb: Math.round(memoryUsage.heapUsed / 1024 / 1024),
425
+ heapTotalMb: Math.round(memoryUsage.heapTotal / 1024 / 1024),
426
+ },
427
+ },
428
+ };
429
+ },
430
+
431
+ "/memory": async (args, context) => {
432
+ const projectPath = context?.projectPath;
433
+
434
+ if (!projectPath) {
435
+ return {
436
+ type: "builtin",
437
+ action: "memory",
438
+ data: {
439
+ error: "No project selected",
440
+ message: "Please select a project to access its CLAUDE.md file",
441
+ },
442
+ };
443
+ }
444
+
445
+ const claudeMdPath = path.join(projectPath, "CLAUDE.md");
446
+
447
+ // Check if CLAUDE.md exists
448
+ let exists = false;
449
+ try {
450
+ await fs.access(claudeMdPath);
451
+ exists = true;
452
+ } catch (err) {
453
+ // File doesn't exist
454
+ }
455
+
456
+ return {
457
+ type: "builtin",
458
+ action: "memory",
459
+ data: {
460
+ path: claudeMdPath,
461
+ exists,
462
+ message: exists
463
+ ? `Opening CLAUDE.md at ${claudeMdPath}`
464
+ : `CLAUDE.md not found at ${claudeMdPath}. Create it to store project-specific instructions.`,
465
+ },
466
+ };
467
+ },
468
+
469
469
  "/config": async (args, context) => {
470
- return {
471
- type: "builtin",
472
- action: "config",
473
- data: {
474
- message: "Opening settings...",
475
- },
476
- };
470
+ return {
471
+ type: "builtin",
472
+ action: "config",
473
+ data: {
474
+ message: "Opening settings...",
475
+ },
476
+ };
477
477
  },
478
478
  "/mcp": async () => ({
479
479
  type: "builtin",
@@ -483,11 +483,11 @@ Custom commands can be created in:
483
483
  },
484
484
  }),
485
485
  };
486
-
487
- /**
488
- * POST /api/commands/list
489
- * List all available commands from project and user directories
490
- */
486
+
487
+ /**
488
+ * POST /api/commands/list
489
+ * List all available commands from project and user directories
490
+ */
491
491
  router.post("/list", async (req, res) => {
492
492
  try {
493
493
  const projectPath = typeof req.body?.projectPath === "string"
@@ -498,158 +498,158 @@ router.post("/list", async (req, res) => {
498
498
  ? [...builtInCommands, ...codexNativeCommands]
499
499
  : builtInCommands;
500
500
  const allCommands = [...providerBuiltInCommands];
501
-
502
- // Scan project-level commands (.claude/commands/)
503
- if (projectPath) {
504
- const projectCommandsDir = path.join(projectPath, ".claude", "commands");
505
- const projectCommands = await scanCommandsDirectory(
506
- projectCommandsDir,
507
- projectCommandsDir,
508
- "project",
509
- );
510
- allCommands.push(...projectCommands);
511
- }
512
-
513
- // Scan user-level commands (~/.claude/commands/)
514
- const homeDir = os.homedir();
515
- const userCommandsDir = path.join(homeDir, ".claude", "commands");
516
- const userCommands = await scanCommandsDirectory(
517
- userCommandsDir,
518
- userCommandsDir,
519
- "user",
520
- );
521
- allCommands.push(...userCommands);
522
-
523
- // Separate built-in and custom commands
524
- const customCommands = allCommands.filter(
525
- (cmd) => cmd.namespace !== "builtin",
526
- );
527
-
528
- // Sort commands alphabetically by name
529
- customCommands.sort((a, b) => a.name.localeCompare(b.name));
530
-
501
+
502
+ // Scan project-level commands (.claude/commands/)
503
+ if (projectPath) {
504
+ const projectCommandsDir = path.join(projectPath, ".claude", "commands");
505
+ const projectCommands = await scanCommandsDirectory(
506
+ projectCommandsDir,
507
+ projectCommandsDir,
508
+ "project",
509
+ );
510
+ allCommands.push(...projectCommands);
511
+ }
512
+
513
+ // Scan user-level commands (~/.claude/commands/)
514
+ const homeDir = os.homedir();
515
+ const userCommandsDir = path.join(homeDir, ".claude", "commands");
516
+ const userCommands = await scanCommandsDirectory(
517
+ userCommandsDir,
518
+ userCommandsDir,
519
+ "user",
520
+ );
521
+ allCommands.push(...userCommands);
522
+
523
+ // Separate built-in and custom commands
524
+ const customCommands = allCommands.filter(
525
+ (cmd) => cmd.namespace !== "builtin",
526
+ );
527
+
528
+ // Sort commands alphabetically by name
529
+ customCommands.sort((a, b) => a.name.localeCompare(b.name));
530
+
531
531
  res.json({
532
532
  builtIn: providerBuiltInCommands,
533
533
  custom: customCommands,
534
534
  count: allCommands.length,
535
- });
536
- } catch (error) {
537
- console.error("Error listing commands:", error);
538
- res.status(500).json({
539
- error: "Failed to list commands",
540
- message: error.message,
541
- });
542
- }
543
- });
544
-
545
- /**
546
- * POST /api/commands/execute
547
- * Execute a command with argument replacement
548
- * This endpoint prepares the command content but doesn't execute bash commands yet
549
- * (that will be handled in the command parser utility)
550
- */
551
- router.post("/execute", async (req, res) => {
552
- try {
553
- const { commandName, commandPath, args = [], context = {} } = req.body;
554
-
555
- if (!commandName) {
556
- return res.status(400).json({
557
- error: "Command name is required",
558
- });
559
- }
560
-
561
- // Handle built-in commands
562
- const handler = builtInHandlers[commandName];
563
- if (handler) {
564
- try {
565
- const result = await handler(args, context);
566
- return res.json({
567
- ...result,
568
- command: commandName,
569
- });
570
- } catch (error) {
571
- console.error(
572
- `Error executing built-in command ${commandName}:`,
573
- error,
574
- );
575
- return res.status(500).json({
576
- error: "Command execution failed",
577
- message: error.message,
578
- command: commandName,
579
- });
580
- }
581
- }
582
-
583
- // Handle custom commands
584
- if (!commandPath) {
585
- return res.status(400).json({
586
- error: "Command path is required for custom commands",
587
- });
588
- }
589
-
590
- // Load command content
591
- // Security: validate commandPath is within allowed directories
592
- {
593
- const resolvedPath = path.resolve(commandPath);
594
- const userBase = path.resolve(
595
- path.join(os.homedir(), ".claude", "commands"),
596
- );
597
- const projectBase = context?.projectPath
598
- ? path.resolve(path.join(context.projectPath, ".claude", "commands"))
599
- : null;
600
- const isUnder = (base) => {
601
- const rel = path.relative(base, resolvedPath);
602
- return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel);
603
- };
604
- if (!(isUnder(userBase) || (projectBase && isUnder(projectBase)))) {
605
- return res.status(403).json({
606
- error: "Access denied",
607
- message: "Command must be in .claude/commands directory",
608
- });
609
- }
610
- }
611
- const content = await fs.readFile(commandPath, "utf8");
612
- const { data: metadata, content: commandContent } =
613
- parseFrontMatter(content);
614
- // Basic argument replacement (will be enhanced in command parser utility)
615
- let processedContent = commandContent;
616
-
617
- // Replace $ARGUMENTS with all arguments joined
618
- const argsString = args.join(" ");
619
- processedContent = processedContent.replace(/\$ARGUMENTS/g, argsString);
620
-
621
- // Replace $1, $2, etc. with positional arguments
622
- args.forEach((arg, index) => {
623
- const placeholder = `$${index + 1}`;
624
- processedContent = processedContent.replace(
625
- new RegExp(`\\${placeholder}\\b`, "g"),
626
- arg,
627
- );
628
- });
629
-
630
- res.json({
631
- type: "custom",
632
- command: commandName,
633
- content: processedContent,
634
- metadata,
635
- hasFileIncludes: processedContent.includes("@"),
636
- hasBashCommands: processedContent.includes("!"),
637
- });
638
- } catch (error) {
639
- if (error.code === "ENOENT") {
640
- return res.status(404).json({
641
- error: "Command not found",
642
- message: `Command file not found: ${req.body.commandPath}`,
643
- });
644
- }
645
-
646
- console.error("Error executing command:", error);
647
- res.status(500).json({
648
- error: "Failed to execute command",
649
- message: error.message,
650
- });
651
- }
652
- });
653
-
654
- return router;
655
- }
535
+ });
536
+ } catch (error) {
537
+ console.error("Error listing commands:", error);
538
+ res.status(500).json({
539
+ error: "Failed to list commands",
540
+ message: error.message,
541
+ });
542
+ }
543
+ });
544
+
545
+ /**
546
+ * POST /api/commands/execute
547
+ * Execute a command with argument replacement
548
+ * This endpoint prepares the command content but doesn't execute bash commands yet
549
+ * (that will be handled in the command parser utility)
550
+ */
551
+ router.post("/execute", async (req, res) => {
552
+ try {
553
+ const { commandName, commandPath, args = [], context = {} } = req.body;
554
+
555
+ if (!commandName) {
556
+ return res.status(400).json({
557
+ error: "Command name is required",
558
+ });
559
+ }
560
+
561
+ // Handle built-in commands
562
+ const handler = builtInHandlers[commandName];
563
+ if (handler) {
564
+ try {
565
+ const result = await handler(args, context);
566
+ return res.json({
567
+ ...result,
568
+ command: commandName,
569
+ });
570
+ } catch (error) {
571
+ console.error(
572
+ `Error executing built-in command ${commandName}:`,
573
+ error,
574
+ );
575
+ return res.status(500).json({
576
+ error: "Command execution failed",
577
+ message: error.message,
578
+ command: commandName,
579
+ });
580
+ }
581
+ }
582
+
583
+ // Handle custom commands
584
+ if (!commandPath) {
585
+ return res.status(400).json({
586
+ error: "Command path is required for custom commands",
587
+ });
588
+ }
589
+
590
+ // Load command content
591
+ // Security: validate commandPath is within allowed directories
592
+ {
593
+ const resolvedPath = path.resolve(commandPath);
594
+ const userBase = path.resolve(
595
+ path.join(os.homedir(), ".claude", "commands"),
596
+ );
597
+ const projectBase = context?.projectPath
598
+ ? path.resolve(path.join(context.projectPath, ".claude", "commands"))
599
+ : null;
600
+ const isUnder = (base) => {
601
+ const rel = path.relative(base, resolvedPath);
602
+ return rel !== "" && !rel.startsWith("..") && !path.isAbsolute(rel);
603
+ };
604
+ if (!(isUnder(userBase) || (projectBase && isUnder(projectBase)))) {
605
+ return res.status(403).json({
606
+ error: "Access denied",
607
+ message: "Command must be in .claude/commands directory",
608
+ });
609
+ }
610
+ }
611
+ const content = await fs.readFile(commandPath, "utf8");
612
+ const { data: metadata, content: commandContent } =
613
+ parseFrontMatter(content);
614
+ // Basic argument replacement (will be enhanced in command parser utility)
615
+ let processedContent = commandContent;
616
+
617
+ // Replace $ARGUMENTS with all arguments joined
618
+ const argsString = args.join(" ");
619
+ processedContent = processedContent.replace(/\$ARGUMENTS/g, argsString);
620
+
621
+ // Replace $1, $2, etc. with positional arguments
622
+ args.forEach((arg, index) => {
623
+ const placeholder = `$${index + 1}`;
624
+ processedContent = processedContent.replace(
625
+ new RegExp(`\\${placeholder}\\b`, "g"),
626
+ arg,
627
+ );
628
+ });
629
+
630
+ res.json({
631
+ type: "custom",
632
+ command: commandName,
633
+ content: processedContent,
634
+ metadata,
635
+ hasFileIncludes: processedContent.includes("@"),
636
+ hasBashCommands: processedContent.includes("!"),
637
+ });
638
+ } catch (error) {
639
+ if (error.code === "ENOENT") {
640
+ return res.status(404).json({
641
+ error: "Command not found",
642
+ message: `Command file not found: ${req.body.commandPath}`,
643
+ });
644
+ }
645
+
646
+ console.error("Error executing command:", error);
647
+ res.status(500).json({
648
+ error: "Failed to execute command",
649
+ message: error.message,
650
+ });
651
+ }
652
+ });
653
+
654
+ return router;
655
+ }