wind-agent-cli 1.37.2 → 1.38.0
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.
- package/LICENSE +718 -718
- package/README.md +17 -2
- package/dist/api-docs.html +901 -901
- package/dist/assets/{CodeEditor-B2Wf7Fg0.js → CodeEditor-FvgsnJ7J.js} +6 -6
- package/dist/assets/FileTree-NLULrBDi.js +1 -0
- package/dist/assets/GitPanel-51KUBbEW.js +4 -0
- package/dist/assets/{MarkdownPreview-C0tqYnVu.js → MarkdownPreview-PEEWVWeS.js} +17 -27
- package/dist/assets/Shell-BEx66cW_.js +76 -0
- package/dist/assets/Shell-DrlLKa8f.css +1 -0
- package/dist/assets/StandaloneShell-BkuUCPZP.js +1 -0
- package/dist/assets/TaskMasterPanel-DfQG80SF.js +2 -0
- package/dist/assets/abnfDiagram-N423BO3Z-Cc0ul87U.js +1 -0
- package/dist/assets/arc-BAuugHw_.js +1 -0
- package/dist/assets/architectureDiagram-T3A2C74G-DA3G7QZD.js +36 -0
- package/dist/assets/{blockDiagram-VBNYF7ZC-DpaEf3mv.js → blockDiagram-VBNYF7ZC-tJ12IJs3.js} +4 -4
- package/dist/assets/c4Diagram-5PPSVZJV-5BTMCXL4.js +10 -0
- package/dist/assets/channel-BGDgNNQz.js +1 -0
- package/dist/assets/{chunk-2GRJ4B5K-DoSdNo8u.js → chunk-2GRJ4B5K-BPaI06Ou.js} +1 -1
- package/dist/assets/{chunk-2Q5K7J3B-CE7I3uMn.js → chunk-2Q5K7J3B-HV4zmsEe.js} +1 -1
- package/dist/assets/chunk-5RXB4S5H-BAwutJoU.js +231 -0
- package/dist/assets/{chunk-5VM5RSS4-B55XgqHZ.js → chunk-5VM5RSS4-B9QAJPrv.js} +1 -1
- package/dist/assets/{chunk-6Q2QTUOP-BS1KpefW.js → chunk-6Q2QTUOP-BOIW8bzI.js} +1 -1
- package/dist/assets/chunk-GF5L2VYU-DD13o00-.js +206 -0
- package/dist/assets/{chunk-JWPE2WC7-DOtkNhMm.js → chunk-JWPE2WC7-CFBm23VK.js} +1 -1
- package/dist/assets/{chunk-KBJHAD2P-BXLjviqM.js → chunk-KBJHAD2P-C0i0v8Op.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-C50fjNNz.js → chunk-RYQCIY6F-DfeK0taV.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-QBYqCkb7.js → chunk-XXDRQBXY-BKWvf-QE.js} +1 -1
- package/dist/assets/classDiagram-JCYQIIEL-C2SNM4oy.js +1 -0
- package/dist/assets/classDiagram-v2-OCEON4UE-C2SNM4oy.js +1 -0
- package/dist/assets/cose-bilkent-JH36ORCC-CBE8oM7L.js +1 -0
- package/dist/assets/{cynefin-VYW2F7L2-DnJa_OlQ.js → cynefin-VYW2F7L2-DziGp35A.js} +11 -23
- package/dist/assets/cynefinDiagram-MW4NZA55-CNvtHl39.js +62 -0
- package/dist/assets/cytoscape.esm-yzknjiTM.js +321 -0
- package/dist/assets/dagre-VZM6K2ZE-Bz9lsU7m.js +4 -0
- package/dist/assets/{diagram-7IWD3JNH-pFzs9HEu.js → diagram-7IWD3JNH-CV7D3VSd.js} +5 -5
- package/dist/assets/{diagram-B4RE2ZJO-CcehQC7x.js → diagram-B4RE2ZJO-Dj4EjDNC.js} +2 -2
- package/dist/assets/diagram-LBJQPF4R-wJ6FHvf-.js +24 -0
- package/dist/assets/diagram-Q27KOJAE-DMFYMhOB.js +24 -0
- package/dist/assets/diagram-UB23O5K3-DeBSbWAI.js +41 -0
- package/dist/assets/ebnfDiagram-BXEA7PRR-2NnJSGhT.js +1 -0
- package/dist/assets/erDiagram-JOGREHBK-DrSlg8hr.js +85 -0
- package/dist/assets/feature-chat-CvOCyaLe.js +88 -0
- package/dist/assets/feature-workspace-CAB6bgPy.js +39 -0
- package/dist/assets/{flowDiagram-UKHOOZJN-CJV8fQPR.js → flowDiagram-UKHOOZJN-C0pejU6W.js} +4 -4
- package/dist/assets/ganttDiagram-PKOTCBZU-BM0VCUUz.js +292 -0
- package/dist/assets/gitGraphDiagram-DS77QQ5N-SbLG0c5_.js +106 -0
- package/dist/assets/graph-DOmOIIwC.js +1 -0
- package/dist/assets/{index-GFhXZyl2.js → index-BflGfU1C.js} +3 -3
- package/dist/assets/index-Btkf0_rU.js +1 -0
- package/dist/assets/index-Cr5MbHuj.css +1 -0
- package/dist/assets/index-Gqazqfs3.js +1 -0
- package/dist/assets/index-nyrkoQK6.js +35 -0
- package/dist/assets/infoDiagram-6WML65LV-Cf5DSa66.js +2 -0
- package/dist/assets/ishikawaDiagram-WSZJBQD7-DwyFutKy.js +70 -0
- package/dist/assets/journeyDiagram-NVQOT4AX-Df0FRhLo.js +139 -0
- package/dist/assets/{kanban-definition-27J2QSJJ-B3iL0ztJ.js → kanban-definition-27J2QSJJ-HmpbjrZz.js} +6 -6
- package/dist/assets/{layout-D6BstSzF.js → layout-D-LzfAck.js} +1 -1
- package/dist/assets/{linear-Cwe9dEKA.js → linear-DOM01LBe.js} +1 -1
- package/dist/assets/map-DxJ2ADlA.js +1 -0
- package/dist/assets/mermaid.core-C2Ma-_S6.js +306 -0
- package/dist/assets/{mindmap-definition-FAOFIHXS-BgfBYMzr.js → mindmap-definition-FAOFIHXS-B4GOIn76.js} +4 -4
- package/dist/assets/pegDiagram-VL7TDLO6-BHur7aH2.js +1 -0
- package/dist/assets/{pieDiagram-7S7Q4E2Y-DeSrxc4I.js → pieDiagram-7S7Q4E2Y-Cw0UELLV.js} +2 -2
- package/dist/assets/quadrantDiagram-CIZ2JOQS-CB2BrX3g.js +7 -0
- package/dist/assets/railroadDiagram-AXF67PYL-DPYZYmLX.js +1 -0
- package/dist/assets/requirementDiagram-LRYGKXZP-DSX4IJ1n.js +84 -0
- package/dist/assets/sankeyDiagram-W5VNT64P-TenC3ZQo.js +40 -0
- package/dist/assets/sequenceDiagram-SI44F4Z6-DltGsf3F.js +162 -0
- package/dist/assets/sizeCapture-X5ZJPWSS-D7llwbJZ.js +1 -0
- package/dist/assets/stateDiagram-OKZ733FA-C-hAvbnY.js +1 -0
- package/dist/assets/stateDiagram-v2-UEYNNEHI-DaYSFcRQ.js +1 -0
- package/dist/assets/swimlanes-SLNWSIFB-DWD30fv6.js +2 -0
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-LTkF2T6t.js +8 -0
- package/dist/assets/timeline-definition-Z64GVDOM-quWmimSE.js +120 -0
- package/dist/assets/vendor-data-DsEZeNPr.js +4 -0
- package/dist/assets/vendor-i18n-B6HjLCnN.js +1 -0
- package/dist/assets/vendor-markdown-DkITEES2.js +298 -0
- package/dist/assets/vendor-react-C2GTiUCy.js +10 -0
- package/dist/assets/vendor-ui-CAUHSABu.js +49 -0
- package/dist/assets/vennDiagram-T6HMQDX7-aUQcm8h5.js +34 -0
- package/dist/assets/{wardleyDiagram-T6FBY63Y-BNCpsFZV.js → wardleyDiagram-T6FBY63Y-BZ0bwsFQ.js} +2 -2
- package/dist/assets/workbox-window.prod.es5-BBnX5xw4.js +2 -0
- package/dist/assets/xychartDiagram-ELKLHX3M-DOVzAq63.js +7 -0
- package/dist/clear-cache.html +85 -85
- package/dist/convert-icons.md +52 -52
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +8 -8
- package/dist/generate-icons.js +48 -48
- package/dist/icons/codex-white.svg +3 -3
- package/dist/icons/codex.svg +3 -3
- package/dist/icons/cursor-white.svg +11 -11
- package/dist/icons/icon-128x128.png +0 -0
- package/dist/icons/icon-128x128.svg +11 -11
- package/dist/icons/icon-144x144.png +0 -0
- package/dist/icons/icon-144x144.svg +11 -11
- package/dist/icons/icon-152x152.png +0 -0
- package/dist/icons/icon-152x152.svg +11 -11
- package/dist/icons/icon-180x180.png +0 -0
- package/dist/icons/icon-192x192.png +0 -0
- package/dist/icons/icon-192x192.svg +11 -11
- package/dist/icons/icon-384x384.png +0 -0
- package/dist/icons/icon-384x384.svg +11 -11
- package/dist/icons/icon-512x512.png +0 -0
- package/dist/icons/icon-512x512.svg +11 -11
- package/dist/icons/icon-72x72.png +0 -0
- package/dist/icons/icon-72x72.svg +11 -11
- package/dist/icons/icon-96x96.png +0 -0
- package/dist/icons/icon-96x96.svg +11 -11
- package/dist/icons/icon-maskable-192x192.png +0 -0
- package/dist/icons/icon-maskable-512x512.png +0 -0
- package/dist/icons/icon-template.svg +11 -11
- package/dist/icons/new-icon.png +0 -0
- package/dist/index.html +48 -58
- package/dist/logo-128.png +0 -0
- package/dist/logo-256.png +0 -0
- package/dist/logo.svg +17 -17
- package/dist/manifest.webmanifest +1 -0
- package/dist/push-sw.js +48 -0
- package/dist/screenshots/setup-screen-mobile.png +0 -0
- package/dist/screenshots/setup-screen.png +0 -0
- package/dist/sw.js +1 -124
- package/dist/workbox-ae5c0bb2.js +1 -0
- package/dist-server/server/index.js +1 -1
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/load-env.js +4 -2
- package/dist-server/server/load-env.js.map +1 -1
- package/dist-server/server/modules/agent/agent.routes.js +1 -1
- package/dist-server/server/modules/agent/agent.routes.js.map +1 -1
- package/dist-server/server/modules/browser-use/browser-use.service.js +1 -1
- package/dist-server/server/modules/browser-use/browser-use.service.js.map +1 -1
- package/dist-server/server/modules/cli/cli.service.js +37 -37
- package/dist-server/server/modules/cli/cli.service.js.map +1 -1
- package/dist-server/server/modules/cli/sandbox.service.js +43 -43
- package/dist-server/server/modules/cli/sandbox.service.js.map +1 -1
- package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js +74 -74
- package/dist-server/server/modules/commands/commands.routes.js +25 -25
- package/dist-server/server/modules/commands/commands.routes.js.map +1 -1
- package/dist-server/server/modules/commands/tests/commands.test.js +1 -1
- package/dist-server/server/modules/commands/tests/commands.test.js.map +1 -1
- package/dist-server/server/modules/database/connection.js +1 -1
- package/dist-server/server/modules/database/connection.js.map +1 -1
- package/dist-server/server/modules/database/migrations.js +190 -190
- package/dist-server/server/modules/database/repositories/api-keys.js +3 -3
- package/dist-server/server/modules/database/repositories/github-tokens.js +2 -2
- package/dist-server/server/modules/database/repositories/notification-channel-endpoints.js +28 -28
- package/dist-server/server/modules/database/repositories/notification-preferences.js +4 -4
- package/dist-server/server/modules/database/repositories/projects.db.js +61 -61
- package/dist-server/server/modules/database/repositories/provider-models.js +35 -35
- package/dist-server/server/modules/database/repositories/push-subscriptions.js +5 -5
- package/dist-server/server/modules/database/repositories/scan-state.db.js +5 -5
- package/dist-server/server/modules/database/repositories/sessions.db.js +93 -93
- package/dist-server/server/modules/database/schema.js +177 -177
- package/dist-server/server/modules/database/tests/projects.db.integration.test.js +3 -2
- package/dist-server/server/modules/database/tests/projects.db.integration.test.js.map +1 -1
- package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js +6 -6
- package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js +4 -3
- package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js.map +1 -1
- package/dist-server/server/modules/database/tests/sessions.db.integration.test.js +2 -1
- package/dist-server/server/modules/database/tests/sessions.db.integration.test.js.map +1 -1
- package/dist-server/server/modules/git/git.routes.js +17 -17
- package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js +1 -1
- package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js.map +1 -1
- package/dist-server/server/modules/notifications/vapid-keys.service.js +1 -1
- package/dist-server/server/modules/notifications/vapid-keys.service.js.map +1 -1
- package/dist-server/server/modules/projects/tests/project-management.service.test.js +2 -1
- package/dist-server/server/modules/projects/tests/project-management.service.test.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js +2 -2
- package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +13 -13
- package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js +9 -9
- package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.test.js +17 -17
- package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +25 -25
- package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +27 -27
- package/dist-server/server/modules/providers/services/provider-token-usage.service.js +9 -9
- package/dist-server/server/modules/providers/services/sessions.service.js +1 -1
- package/dist-server/server/modules/providers/tests/claude-auth.test.js +8 -0
- package/dist-server/server/modules/providers/tests/claude-auth.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js +1 -1
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/mcp.test.js +3 -3
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +98 -98
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +18 -18
- package/dist-server/server/modules/providers/tests/provider.routes.test.js +1 -1
- package/dist-server/server/modules/providers/tests/provider.routes.test.js.map +1 -1
- package/dist-server/server/modules/system/system.service.js +1 -1
- package/dist-server/server/modules/system/system.service.js.map +1 -1
- package/dist-server/server/modules/system/tests/system.service.test.js +1 -1
- package/dist-server/server/modules/system/tests/system.service.test.js.map +1 -1
- package/dist-server/server/modules/taskmaster/taskmaster.routes.js +423 -422
- package/dist-server/server/modules/taskmaster/taskmaster.routes.js.map +1 -1
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js +1 -1
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
- package/dist-server/server/modules/worktrees/services/worktree-list.service.js +1 -1
- package/dist-server/server/modules/worktrees/services/worktree-open.service.js +1 -1
- package/dist-server/server/modules/worktrees/services/worktree-remove.service.js +1 -1
- package/electron/cloud.js +260 -260
- package/electron/desktopNotifications.js +378 -378
- package/electron/desktopWindow.js +766 -766
- package/electron/launcher/index.html +14 -14
- package/electron/launcher/launcher.css +801 -801
- package/electron/launcher/launcher.js +687 -687
- package/electron/localServer.js +549 -549
- package/electron/main.js +944 -944
- package/electron/preload.cjs +60 -60
- package/electron/scripts/generate-macos-icon.js +62 -62
- package/electron/serverInstaller.js +277 -277
- package/electron/tabs.js +87 -87
- package/electron/viewHost.js +331 -331
- package/package.json +262 -247
- package/public/api-docs.html +901 -901
- package/scripts/build-client.mjs +30 -0
- package/scripts/fix-node-pty.js +67 -67
- package/scripts/generate-pwa-icons.ps1 +33 -0
- package/scripts/promote-dist-server.mjs +50 -50
- package/scripts/release/build-server-bundle.js +176 -176
- package/scripts/release/prepare-desktop-app.js +152 -152
- package/scripts/verify-pwa-build.mjs +37 -0
- package/server/index.ts +399 -399
- package/server/load-env.ts +49 -47
- package/server/modules/agent/agent.module.ts +52 -52
- package/server/modules/agent/agent.routes.ts +1287 -1287
- package/server/modules/agent/index.ts +2 -2
- package/server/modules/agent/tests/agent.routes.test.ts +205 -205
- package/server/modules/assets/assets.routes.ts +150 -150
- package/server/modules/assets/index.ts +3 -3
- package/server/modules/assets/services/image-assets.service.ts +127 -127
- package/server/modules/assets/tests/image-assets.service.test.ts +74 -74
- package/server/modules/auth/auth.middleware.ts +163 -163
- package/server/modules/auth/auth.module.ts +38 -38
- package/server/modules/auth/auth.routes.ts +57 -57
- package/server/modules/auth/auth.service.ts +155 -155
- package/server/modules/auth/index.ts +9 -9
- package/server/modules/auth/tests/auth.service.test.ts +95 -95
- package/server/modules/browser-use/browser-use-mcp.routes.ts +120 -120
- package/server/modules/browser-use/browser-use-mcp.ts +386 -386
- package/server/modules/browser-use/browser-use-runtime.ts +10 -10
- package/server/modules/browser-use/browser-use.routes.ts +96 -96
- package/server/modules/browser-use/browser-use.service.ts +836 -836
- package/server/modules/browser-use/index.ts +11 -11
- package/server/modules/browser-use/tests/browser-use.service.test.ts +10 -10
- package/server/modules/cli/cli.module.ts +93 -93
- package/server/modules/cli/cli.service.ts +248 -248
- package/server/modules/cli/cli.ts +19 -19
- package/server/modules/cli/index.ts +2 -2
- package/server/modules/cli/sandbox.service.ts +398 -398
- package/server/modules/cli/tests/cli-environment-bootstrap.test.ts +186 -186
- package/server/modules/cli/tests/cli.service.test.ts +86 -86
- package/server/modules/cli/tests/sandbox.service.test.ts +58 -58
- package/server/modules/commands/commands.module.ts +22 -22
- package/server/modules/commands/commands.routes.ts +587 -587
- package/server/modules/commands/index.ts +2 -2
- package/server/modules/commands/tests/commands.test.ts +110 -110
- package/server/modules/database/connection.ts +144 -143
- package/server/modules/database/index.ts +17 -17
- package/server/modules/database/init-db.ts +17 -17
- package/server/modules/database/migrations.ts +515 -515
- package/server/modules/database/repositories/api-keys.ts +119 -119
- package/server/modules/database/repositories/app-config.ts +53 -53
- package/server/modules/database/repositories/credentials.ts +106 -106
- package/server/modules/database/repositories/github-tokens.ts +100 -100
- package/server/modules/database/repositories/notification-channel-endpoints.ts +153 -153
- package/server/modules/database/repositories/notification-preferences.ts +117 -117
- package/server/modules/database/repositories/projects.db.ts +196 -196
- package/server/modules/database/repositories/provider-models.ts +168 -168
- package/server/modules/database/repositories/push-subscriptions.ts +80 -80
- package/server/modules/database/repositories/scan-state.db.ts +42 -42
- package/server/modules/database/repositories/sessions.db.ts +524 -524
- package/server/modules/database/repositories/users.ts +140 -140
- package/server/modules/database/repositories/vapid-keys.ts +57 -57
- package/server/modules/database/schema.ts +210 -210
- package/server/modules/database/tests/projects.db.integration.test.ts +73 -72
- package/server/modules/database/tests/provider-models.db.integration.test.ts +125 -125
- package/server/modules/database/tests/sessions-provider-mapping.test.ts +110 -109
- package/server/modules/database/tests/sessions.db.integration.test.ts +117 -116
- package/server/modules/file-tree/file-tree.module.ts +116 -116
- package/server/modules/file-tree/file-tree.routes.ts +258 -258
- package/server/modules/file-tree/file-tree.service.ts +675 -675
- package/server/modules/file-tree/index.ts +2 -2
- package/server/modules/file-tree/tests/file-tree.routes.test.ts +157 -157
- package/server/modules/file-tree/tests/file-tree.service.test.ts +371 -371
- package/server/modules/git/git-branch.service.ts +43 -43
- package/server/modules/git/git-parsing.service.ts +66 -66
- package/server/modules/git/git.module.ts +22 -22
- package/server/modules/git/git.routes.ts +1596 -1596
- package/server/modules/git/index.ts +2 -2
- package/server/modules/git/tests/git-branch.service.test.ts +60 -60
- package/server/modules/git/tests/git-init.routes.test.ts +132 -132
- package/server/modules/git/tests/git.test.ts +106 -106
- package/server/modules/notifications/index.ts +24 -24
- package/server/modules/notifications/notifications.routes.ts +127 -127
- package/server/modules/notifications/services/desktop-notification-clients.service.ts +124 -124
- package/server/modules/notifications/services/notification-orchestrator.service.js +310 -310
- package/server/modules/notifications/tests/notification-orchestrator.integration.test.ts +55 -55
- package/server/modules/notifications/vapid-keys.service.ts +38 -38
- package/server/modules/notifications/websocket/desktop-notifications-websocket.service.ts +109 -109
- package/server/modules/plugins/index.ts +9 -9
- package/server/modules/plugins/plugin-process.service.ts +217 -217
- package/server/modules/plugins/plugin-registry.service.ts +459 -459
- package/server/modules/plugins/plugins.module.ts +33 -33
- package/server/modules/plugins/plugins.routes.ts +66 -66
- package/server/modules/plugins/plugins.service.ts +147 -147
- package/server/modules/plugins/tests/plugins.service.test.ts +32 -32
- package/server/modules/projects/index.ts +11 -11
- package/server/modules/projects/projects.routes.ts +273 -273
- package/server/modules/projects/services/project-clone.service.ts +323 -323
- package/server/modules/projects/services/project-delete.service.ts +90 -90
- package/server/modules/projects/services/project-management.service.ts +144 -144
- package/server/modules/projects/services/project-star.service.ts +78 -78
- package/server/modules/projects/services/projects-has-taskmaster.service.ts +248 -248
- package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +314 -314
- package/server/modules/projects/tests/project-clone.service.test.ts +183 -183
- package/server/modules/projects/tests/project-management.service.test.ts +118 -117
- package/server/modules/projects/tests/project-star.service.test.ts +123 -123
- package/server/modules/projects/tests/projects-has-taskmaster.service.test.ts +105 -105
- package/server/modules/providers/README.md +380 -380
- package/server/modules/providers/index.ts +10 -10
- package/server/modules/providers/list/claude/claude-auth.provider.ts +160 -160
- package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -135
- package/server/modules/providers/list/claude/claude-models.provider.ts +294 -294
- package/server/modules/providers/list/claude/claude-runtime.provider.js +1068 -1068
- package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +203 -203
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +684 -684
- package/server/modules/providers/list/claude/claude-skills.provider.ts +265 -265
- package/server/modules/providers/list/claude/claude.provider.ts +30 -30
- package/server/modules/providers/list/codex/codex-app-server.client.ts +2 -2
- package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -100
- package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -135
- package/server/modules/providers/list/codex/codex-models.provider.ts +123 -123
- package/server/modules/providers/list/codex/codex-runtime.provider.js +533 -533
- package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +203 -203
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +938 -938
- package/server/modules/providers/list/codex/codex-skills.provider.ts +73 -73
- package/server/modules/providers/list/codex/codex.provider.ts +28 -28
- package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -143
- package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -108
- package/server/modules/providers/list/cursor/cursor-models.provider.ts +119 -119
- package/server/modules/providers/list/cursor/cursor-runtime.provider.js +385 -385
- package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +158 -159
- package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +654 -654
- package/server/modules/providers/list/cursor/cursor-skills.provider.ts +39 -39
- package/server/modules/providers/list/cursor/cursor.provider.ts +30 -30
- package/server/modules/providers/list/opencode/opencode-auth.provider.ts +110 -110
- package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +228 -228
- package/server/modules/providers/list/opencode/opencode-models.provider.ts +203 -203
- package/server/modules/providers/list/opencode/opencode-runtime.provider.js +434 -434
- package/server/modules/providers/list/opencode/opencode-runtime.provider.test.js +261 -261
- package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +179 -179
- package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +500 -500
- package/server/modules/providers/list/opencode/opencode-skills.provider.ts +78 -78
- package/server/modules/providers/list/opencode/opencode.provider.ts +30 -30
- package/server/modules/providers/provider.registry.ts +36 -36
- package/server/modules/providers/provider.routes.ts +877 -877
- package/server/modules/providers/services/mcp.service.ts +109 -109
- package/server/modules/providers/services/provider-auth.service.ts +26 -26
- package/server/modules/providers/services/provider-capabilities.service.ts +97 -97
- package/server/modules/providers/services/provider-models.service.ts +401 -401
- package/server/modules/providers/services/provider-runtime.service.ts +108 -108
- package/server/modules/providers/services/provider-token-usage.service.ts +357 -357
- package/server/modules/providers/services/session-conversations-search.service.ts +1321 -1321
- package/server/modules/providers/services/session-synchronizer.service.ts +74 -74
- package/server/modules/providers/services/sessions-watcher.service.ts +247 -247
- package/server/modules/providers/services/sessions.service.ts +471 -471
- package/server/modules/providers/services/skills.service.ts +39 -39
- package/server/modules/providers/shared/base/abstract.provider.ts +32 -32
- package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -151
- package/server/modules/providers/shared/skills/skills.provider.ts +287 -287
- package/server/modules/providers/tests/claude-auth.test.ts +157 -150
- package/server/modules/providers/tests/claude-sessions.test.ts +61 -61
- package/server/modules/providers/tests/codex-sessions.test.ts +231 -231
- package/server/modules/providers/tests/mcp.test.ts +349 -349
- package/server/modules/providers/tests/opencode-models.test.ts +41 -41
- package/server/modules/providers/tests/opencode-sessions.test.ts +522 -522
- package/server/modules/providers/tests/provider-attachment-history.test.ts +247 -247
- package/server/modules/providers/tests/provider-models.service.test.ts +353 -353
- package/server/modules/providers/tests/provider-runtime.service.test.ts +138 -138
- package/server/modules/providers/tests/provider-token-usage.service.test.ts +186 -186
- package/server/modules/providers/tests/provider.routes.test.ts +244 -244
- package/server/modules/providers/tests/sessions-details.test.ts +73 -73
- package/server/modules/providers/tests/sessions.service.test.ts +127 -127
- package/server/modules/providers/tests/skills.test.ts +692 -692
- package/server/modules/settings/index.ts +2 -2
- package/server/modules/settings/settings.module.ts +50 -50
- package/server/modules/settings/settings.routes.ts +51 -51
- package/server/modules/settings/settings.service.ts +186 -186
- package/server/modules/settings/tests/settings.service.test.ts +54 -54
- package/server/modules/system/index.ts +2 -2
- package/server/modules/system/system.module.ts +62 -62
- package/server/modules/system/system.routes.ts +21 -21
- package/server/modules/system/system.service.ts +76 -76
- package/server/modules/system/tests/system.service.test.ts +118 -118
- package/server/modules/taskmaster/index.ts +2 -2
- package/server/modules/taskmaster/taskmaster.module.ts +24 -24
- package/server/modules/taskmaster/taskmaster.routes.ts +1483 -1482
- package/server/modules/taskmaster/taskmaster.service.ts +132 -132
- package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +144 -144
- package/server/modules/taskmaster/tests/taskmaster.service.test.ts +97 -97
- package/server/modules/user/index.ts +2 -2
- package/server/modules/user/tests/user.service.test.ts +61 -61
- package/server/modules/user/user.module.ts +58 -58
- package/server/modules/user/user.routes.ts +50 -50
- package/server/modules/user/user.service.ts +85 -85
- package/server/modules/voice/index.ts +2 -2
- package/server/modules/voice/tests/voice.service.test.ts +98 -98
- package/server/modules/voice/voice.module.ts +47 -47
- package/server/modules/voice/voice.routes.ts +113 -113
- package/server/modules/voice/voice.service.ts +192 -192
- package/server/modules/websocket/README.md +273 -273
- package/server/modules/websocket/index.ts +3 -3
- package/server/modules/websocket/services/chat-run-registry.service.ts +343 -343
- package/server/modules/websocket/services/chat-session-writer.service.ts +145 -145
- package/server/modules/websocket/services/chat-websocket.service.ts +425 -425
- package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +65 -65
- package/server/modules/websocket/services/shell-websocket.service.ts +503 -503
- package/server/modules/websocket/services/websocket-auth.service.ts +59 -59
- package/server/modules/websocket/services/websocket-server.service.ts +124 -124
- package/server/modules/websocket/services/websocket-state.service.ts +16 -16
- package/server/modules/websocket/services/websocket-writer.service.ts +38 -38
- package/server/modules/websocket/tests/chat-attachment-filter.test.ts +59 -59
- package/server/modules/websocket/tests/chat-run-registry.test.ts +282 -282
- package/server/modules/websocket/tests/shell-websocket.service.test.ts +100 -100
- package/server/modules/websocket/tests/websocket-heartbeat.service.test.ts +78 -78
- package/server/modules/worktrees/index.ts +2 -2
- package/server/modules/worktrees/services/worktree-create-and-open.service.ts +53 -53
- package/server/modules/worktrees/services/worktree-create.service.ts +104 -104
- package/server/modules/worktrees/services/worktree-git.service.ts +207 -207
- package/server/modules/worktrees/services/worktree-list.service.ts +143 -143
- package/server/modules/worktrees/services/worktree-merge.service.ts +157 -157
- package/server/modules/worktrees/services/worktree-open.service.ts +85 -85
- package/server/modules/worktrees/services/worktree-remove.service.ts +88 -88
- package/server/modules/worktrees/tests/worktree-create-and-open.service.test.ts +68 -68
- package/server/modules/worktrees/tests/worktree-create.service.test.ts +142 -142
- package/server/modules/worktrees/tests/worktree-git.service.test.ts +84 -84
- package/server/modules/worktrees/tests/worktree-list.service.test.ts +45 -45
- package/server/modules/worktrees/tests/worktree-merge.service.test.ts +213 -213
- package/server/modules/worktrees/tests/worktree-open.service.test.ts +122 -122
- package/server/modules/worktrees/tests/worktree-remove.service.test.ts +227 -227
- package/server/modules/worktrees/tests/worktrees.routes.test.ts +199 -199
- package/server/modules/worktrees/worktrees.module.ts +113 -113
- package/server/modules/worktrees/worktrees.routes.ts +116 -116
- package/server/shared/claude-cli-path.ts +139 -139
- package/server/shared/frontmatter.ts +18 -18
- package/server/shared/image-attachments.ts +435 -435
- package/server/shared/interfaces.ts +179 -179
- package/server/shared/tests/claude-cli-path.test.ts +61 -61
- package/server/shared/tests/image-attachments.test.ts +353 -353
- package/server/shared/tests/slice-tail-page.test.ts +42 -42
- package/server/shared/types.ts +1228 -1228
- package/server/shared/utils.ts +1161 -1161
- package/server/tsconfig.json +40 -40
- package/shared/networkHosts.js +22 -22
- package/dist/assets/FileTree-N2IkkHlv.js +0 -127
- package/dist/assets/GitPanel-DZCeuFZ2.js +0 -29
- package/dist/assets/PluginTabContent-Bnuf-fb8.js +0 -1
- package/dist/assets/Shell-BfFnMZ-f.js +0 -81
- package/dist/assets/Shell-qxJ8_QYu.css +0 -32
- package/dist/assets/StandaloneShell-QmyYwNAl.js +0 -1
- package/dist/assets/TaskMasterPanel-fMsmvN9L.js +0 -32
- package/dist/assets/abnfDiagram-N423BO3Z-DjPU7HLs.js +0 -1
- package/dist/assets/arc-Pdq6Tvr3.js +0 -1
- package/dist/assets/architectureDiagram-T3A2C74G-D0JnT0Vh.js +0 -36
- package/dist/assets/c4Diagram-5PPSVZJV-MpqlPGFi.js +0 -10
- package/dist/assets/channel-Bm0ZLE4z.js +0 -1
- package/dist/assets/chunk-5RXB4S5H-B4UQ8snD.js +0 -231
- package/dist/assets/chunk-GF5L2VYU-DkEPedJP.js +0 -206
- package/dist/assets/classDiagram-JCYQIIEL-DqEOcNxw.js +0 -1
- package/dist/assets/classDiagram-v2-OCEON4UE-DqEOcNxw.js +0 -1
- package/dist/assets/code-xml-VK1YfShP.js +0 -6
- package/dist/assets/cose-bilkent-JH36ORCC-DrVTo1Nh.js +0 -1
- package/dist/assets/cynefinDiagram-MW4NZA55-CCxBjw9E.js +0 -62
- package/dist/assets/cytoscape.esm-C10L9Icf.js +0 -331
- package/dist/assets/dagre-VZM6K2ZE-C_GvE4lu.js +0 -4
- package/dist/assets/diagram-LBJQPF4R-hfKcrrxe.js +0 -24
- package/dist/assets/diagram-Q27KOJAE-C1semJfK.js +0 -24
- package/dist/assets/diagram-UB23O5K3-57hvXQXO.js +0 -41
- package/dist/assets/ebnfDiagram-BXEA7PRR-9KIAlAVw.js +0 -1
- package/dist/assets/erDiagram-JOGREHBK-B7OzJ767.js +0 -85
- package/dist/assets/ganttDiagram-PKOTCBZU-CbMNWWQu.js +0 -292
- package/dist/assets/gitGraphDiagram-DS77QQ5N-I_vZ5waO.js +0 -106
- package/dist/assets/graph-Cx-EqisW.js +0 -1
- package/dist/assets/index-DFnVoqpx.js +0 -1174
- package/dist/assets/index-DlSeAkw_.js +0 -11
- package/dist/assets/index-ZHwIojzi.js +0 -1
- package/dist/assets/index-t1w8KNxn.css +0 -1
- package/dist/assets/infoDiagram-6WML65LV-Dh20Tsbq.js +0 -2
- package/dist/assets/ishikawaDiagram-WSZJBQD7-DH2Sm3ko.js +0 -70
- package/dist/assets/journeyDiagram-NVQOT4AX-BNFQqlVu.js +0 -139
- package/dist/assets/map-CV9uif0g.js +0 -1
- package/dist/assets/mermaid.core-BYRQSshi.js +0 -312
- package/dist/assets/pegDiagram-VL7TDLO6-CNYpECr8.js +0 -1
- package/dist/assets/quadrantDiagram-CIZ2JOQS-BXVVQsa6.js +0 -7
- package/dist/assets/railroadDiagram-AXF67PYL-JTroIW8F.js +0 -1
- package/dist/assets/requirementDiagram-LRYGKXZP-C1Z_inLz.js +0 -84
- package/dist/assets/sankeyDiagram-W5VNT64P-DCJgKFUk.js +0 -40
- package/dist/assets/sequenceDiagram-SI44F4Z6-D8Wrx5Vc.js +0 -162
- package/dist/assets/sizeCapture-X5ZJPWSS-CXqD68vD.js +0 -1
- package/dist/assets/stateDiagram-OKZ733FA-CF0Ekqjo.js +0 -1
- package/dist/assets/stateDiagram-v2-UEYNNEHI-DARLpEFJ.js +0 -1
- package/dist/assets/swimlanes-SLNWSIFB-DVIax_k4.js +0 -2
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-CrgDgaY8.js +0 -8
- package/dist/assets/timeline-definition-Z64GVDOM-DSqk3ApG.js +0 -120
- package/dist/assets/vendor-react-whEHfigN.js +0 -59
- package/dist/assets/vennDiagram-T6HMQDX7-DNbTqyG5.js +0 -34
- package/dist/assets/xychartDiagram-ELKLHX3M-XsVZphHr.js +0 -7
- package/dist/manifest.json +0 -61
|
@@ -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
|
-
const helpText = `# ${isCodex ? "Codex and
|
|
253
|
-
|
|
254
|
-
## Built-in Commands
|
|
255
|
-
|
|
252
|
+
const helpText = `# ${isCodex ? "Codex and WindCli" : "WindCli"} Commands
|
|
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
|
+
}
|