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.
- package/LICENSE +718 -718
- package/README.md +1 -1
- package/dist/api-docs.html +901 -901
- package/dist/assets/{CodeEditor-B2Wf7Fg0.js → CodeEditor-BqmxpZ_D.js} +1 -1
- package/dist/assets/{FileTree-N2IkkHlv.js → FileTree-DLE7Ioai.js} +1 -1
- package/dist/assets/{GitPanel-DZCeuFZ2.js → GitPanel-f8RMRa8D.js} +1 -1
- package/dist/assets/{MarkdownPreview-C0tqYnVu.js → MarkdownPreview-93h_1tJa.js} +1 -1
- package/dist/assets/{PluginTabContent-Bnuf-fb8.js → PluginTabContent-DU1jjkXP.js} +1 -1
- package/dist/assets/{Shell-BfFnMZ-f.js → Shell-CN_2MRIM.js} +1 -1
- package/dist/assets/{StandaloneShell-QmyYwNAl.js → StandaloneShell-D0avS8UE.js} +1 -1
- package/dist/assets/{TaskMasterPanel-fMsmvN9L.js → TaskMasterPanel-Cpf1Q5Ph.js} +3 -3
- package/dist/assets/{abnfDiagram-N423BO3Z-DjPU7HLs.js → abnfDiagram-N423BO3Z-p3aJIm4T.js} +1 -1
- package/dist/assets/{arc-Pdq6Tvr3.js → arc-CTeud6Fl.js} +1 -1
- package/dist/assets/{architectureDiagram-T3A2C74G-D0JnT0Vh.js → architectureDiagram-T3A2C74G-CG7kRCJU.js} +1 -1
- package/dist/assets/{blockDiagram-VBNYF7ZC-DpaEf3mv.js → blockDiagram-VBNYF7ZC-oSjQ1SgE.js} +1 -1
- package/dist/assets/{c4Diagram-5PPSVZJV-MpqlPGFi.js → c4Diagram-5PPSVZJV-RkzF0DJV.js} +1 -1
- package/dist/assets/channel-BfQbarn9.js +1 -0
- package/dist/assets/{chunk-2GRJ4B5K-DoSdNo8u.js → chunk-2GRJ4B5K-B07uZ07O.js} +1 -1
- package/dist/assets/{chunk-2Q5K7J3B-CE7I3uMn.js → chunk-2Q5K7J3B-DNSfO7xS.js} +1 -1
- package/dist/assets/{chunk-5RXB4S5H-B4UQ8snD.js → chunk-5RXB4S5H-BTeYcgyb.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-B55XgqHZ.js → chunk-5VM5RSS4-B7vZV0zC.js} +1 -1
- package/dist/assets/{chunk-6Q2QTUOP-BS1KpefW.js → chunk-6Q2QTUOP-DuS_xUGG.js} +1 -1
- package/dist/assets/{chunk-GF5L2VYU-DkEPedJP.js → chunk-GF5L2VYU-CKLZ3iVD.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-DOtkNhMm.js → chunk-JWPE2WC7-DD2hcXvs.js} +1 -1
- package/dist/assets/{chunk-KBJHAD2P-BXLjviqM.js → chunk-KBJHAD2P-Cz-l38qp.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-C50fjNNz.js → chunk-RYQCIY6F-DGFIU1YM.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-QBYqCkb7.js → chunk-XXDRQBXY-CmfzoYFl.js} +1 -1
- package/dist/assets/classDiagram-JCYQIIEL-Bpfe3kq7.js +1 -0
- package/dist/assets/classDiagram-v2-OCEON4UE-Bpfe3kq7.js +1 -0
- package/dist/assets/{code-xml-VK1YfShP.js → code-xml-CLpHzEOP.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-DrVTo1Nh.js → cose-bilkent-JH36ORCC-DlFcLXCB.js} +1 -1
- package/dist/assets/{cynefin-VYW2F7L2-DnJa_OlQ.js → cynefin-VYW2F7L2-P1HecReO.js} +1 -1
- package/dist/assets/{cynefinDiagram-MW4NZA55-CCxBjw9E.js → cynefinDiagram-MW4NZA55-COgduz5P.js} +1 -1
- package/dist/assets/{dagre-VZM6K2ZE-C_GvE4lu.js → dagre-VZM6K2ZE-Bbb-siGp.js} +1 -1
- package/dist/assets/{diagram-7IWD3JNH-pFzs9HEu.js → diagram-7IWD3JNH-9CWGFMYR.js} +1 -1
- package/dist/assets/{diagram-B4RE2ZJO-CcehQC7x.js → diagram-B4RE2ZJO-TWK59T6V.js} +1 -1
- package/dist/assets/{diagram-LBJQPF4R-hfKcrrxe.js → diagram-LBJQPF4R-ErMC9yaa.js} +1 -1
- package/dist/assets/{diagram-Q27KOJAE-C1semJfK.js → diagram-Q27KOJAE-Dt_-C7hV.js} +1 -1
- package/dist/assets/{diagram-UB23O5K3-57hvXQXO.js → diagram-UB23O5K3-BJ1DnRAF.js} +1 -1
- package/dist/assets/{ebnfDiagram-BXEA7PRR-9KIAlAVw.js → ebnfDiagram-BXEA7PRR-CE1YaQ9s.js} +1 -1
- package/dist/assets/{erDiagram-JOGREHBK-B7OzJ767.js → erDiagram-JOGREHBK-Bqk7N9aY.js} +1 -1
- package/dist/assets/{flowDiagram-UKHOOZJN-CJV8fQPR.js → flowDiagram-UKHOOZJN-DEr2II5V.js} +1 -1
- package/dist/assets/{ganttDiagram-PKOTCBZU-CbMNWWQu.js → ganttDiagram-PKOTCBZU-CWYAUeYN.js} +1 -1
- package/dist/assets/{gitGraphDiagram-DS77QQ5N-I_vZ5waO.js → gitGraphDiagram-DS77QQ5N-tdEcEIM6.js} +1 -1
- package/dist/assets/{index-ZHwIojzi.js → index-B-sTfSZq.js} +1 -1
- package/dist/assets/{index-GFhXZyl2.js → index-BSe3UiFA.js} +1 -1
- package/dist/assets/{index-DFnVoqpx.js → index-B_FDMWar.js} +5 -5
- package/dist/assets/{index-DlSeAkw_.js → index-CWJtg2pR.js} +1 -1
- package/dist/assets/{infoDiagram-6WML65LV-Dh20Tsbq.js → infoDiagram-6WML65LV-A3IqRUnO.js} +1 -1
- package/dist/assets/{ishikawaDiagram-WSZJBQD7-DH2Sm3ko.js → ishikawaDiagram-WSZJBQD7-B2uL6bkK.js} +1 -1
- package/dist/assets/{journeyDiagram-NVQOT4AX-BNFQqlVu.js → journeyDiagram-NVQOT4AX-D9JB-hRW.js} +1 -1
- package/dist/assets/{kanban-definition-27J2QSJJ-B3iL0ztJ.js → kanban-definition-27J2QSJJ-DmlgiV7K.js} +1 -1
- package/dist/assets/{linear-Cwe9dEKA.js → linear-Ct_eoJQk.js} +1 -1
- package/dist/assets/{mermaid.core-BYRQSshi.js → mermaid.core-CQ698HNn.js} +5 -5
- package/dist/assets/{mindmap-definition-FAOFIHXS-BgfBYMzr.js → mindmap-definition-FAOFIHXS-DGtMgQhf.js} +1 -1
- package/dist/assets/{pegDiagram-VL7TDLO6-CNYpECr8.js → pegDiagram-VL7TDLO6-CO6vP4n9.js} +1 -1
- package/dist/assets/{pieDiagram-7S7Q4E2Y-DeSrxc4I.js → pieDiagram-7S7Q4E2Y-DMkt_Zfr.js} +1 -1
- package/dist/assets/{quadrantDiagram-CIZ2JOQS-BXVVQsa6.js → quadrantDiagram-CIZ2JOQS-DgNxRz6t.js} +1 -1
- package/dist/assets/{railroadDiagram-AXF67PYL-JTroIW8F.js → railroadDiagram-AXF67PYL-DKz9UqA9.js} +1 -1
- package/dist/assets/{requirementDiagram-LRYGKXZP-C1Z_inLz.js → requirementDiagram-LRYGKXZP-L84XyGgV.js} +1 -1
- package/dist/assets/{sankeyDiagram-W5VNT64P-DCJgKFUk.js → sankeyDiagram-W5VNT64P-CQqWbJ3j.js} +1 -1
- package/dist/assets/{sequenceDiagram-SI44F4Z6-D8Wrx5Vc.js → sequenceDiagram-SI44F4Z6--tnzS2tb.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-CXqD68vD.js → sizeCapture-X5ZJPWSS-DujwEOtm.js} +1 -1
- package/dist/assets/{stateDiagram-OKZ733FA-CF0Ekqjo.js → stateDiagram-OKZ733FA-BK3TcZY2.js} +1 -1
- package/dist/assets/stateDiagram-v2-UEYNNEHI-_medyomK.js +1 -0
- package/dist/assets/{swimlanes-SLNWSIFB-DVIax_k4.js → swimlanes-SLNWSIFB-naX-Uv1B.js} +2 -2
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-DstIv3TC.js +8 -0
- package/dist/assets/{timeline-definition-Z64GVDOM-DSqk3ApG.js → timeline-definition-Z64GVDOM-C-vP_ddU.js} +1 -1
- package/dist/assets/{vennDiagram-T6HMQDX7-DNbTqyG5.js → vennDiagram-T6HMQDX7-DN-I7o-7.js} +1 -1
- package/dist/assets/{wardleyDiagram-T6FBY63Y-BNCpsFZV.js → wardleyDiagram-T6FBY63Y-Db9dsaXv.js} +1 -1
- package/dist/assets/{xychartDiagram-ELKLHX3M-XsVZphHr.js → xychartDiagram-ELKLHX3M-DE6OxW_p.js} +1 -1
- package/dist/clear-cache.html +85 -85
- package/dist/convert-icons.md +52 -52
- 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.svg +11 -11
- package/dist/icons/icon-144x144.svg +11 -11
- package/dist/icons/icon-152x152.svg +11 -11
- package/dist/icons/icon-192x192.svg +11 -11
- package/dist/icons/icon-384x384.svg +11 -11
- package/dist/icons/icon-512x512.svg +11 -11
- package/dist/icons/icon-72x72.svg +11 -11
- package/dist/icons/icon-96x96.svg +11 -11
- package/dist/icons/icon-template.svg +11 -11
- package/dist/index.html +56 -56
- package/dist/logo.svg +17 -17
- package/dist/manifest.json +60 -60
- package/dist/sw.js +124 -124
- package/dist-server/server/modules/cli/cli.service.js +36 -36
- package/dist-server/server/modules/cli/sandbox.service.js +38 -38
- package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js +74 -74
- package/dist-server/server/modules/commands/commands.routes.js +24 -24
- 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 +92 -92
- package/dist-server/server/modules/database/schema.js +177 -177
- package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js +6 -6
- package/dist-server/server/modules/git/git.routes.js +17 -17
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +12 -12
- 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/tests/mcp.test.js +3 -3
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +96 -96
- package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +18 -18
- package/dist-server/server/modules/taskmaster/taskmaster.routes.js +419 -419
- 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 +250 -247
- package/public/api-docs.html +901 -901
- package/scripts/fix-node-pty.js +67 -67
- 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/server/index.ts +399 -399
- package/server/load-env.ts +47 -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 +586 -586
- package/server/modules/commands/index.ts +2 -2
- package/server/modules/commands/tests/commands.test.ts +109 -109
- package/server/modules/database/connection.ts +143 -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 +72 -72
- package/server/modules/database/tests/provider-models.db.integration.test.ts +125 -125
- package/server/modules/database/tests/sessions-provider-mapping.test.ts +109 -109
- package/server/modules/database/tests/sessions.db.integration.test.ts +116 -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 +117 -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-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 +159 -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 +150 -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 +1482 -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 +502 -502
- 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 +1226 -1226
- package/server/shared/utils.ts +1161 -1161
- package/server/tsconfig.json +40 -40
- package/shared/networkHosts.js +22 -22
- package/dist/assets/channel-Bm0ZLE4z.js +0 -1
- package/dist/assets/classDiagram-JCYQIIEL-DqEOcNxw.js +0 -1
- package/dist/assets/classDiagram-v2-OCEON4UE-DqEOcNxw.js +0 -1
- package/dist/assets/stateDiagram-v2-UEYNNEHI-DARLpEFJ.js +0 -1
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-CrgDgaY8.js +0 -8
|
@@ -1,349 +1,349 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import fs from 'node:fs/promises';
|
|
3
|
-
import os from 'node:os';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import test from 'node:test';
|
|
6
|
-
|
|
7
|
-
import TOML from '@iarna/toml';
|
|
8
|
-
|
|
9
|
-
import { providerMcpService } from '@/modules/providers/services/mcp.service.js';
|
|
10
|
-
import { AppError } from '@/shared/utils.js';
|
|
11
|
-
|
|
12
|
-
const patchHomeDir = (nextHomeDir: string) => {
|
|
13
|
-
const original = os.homedir;
|
|
14
|
-
(os as any).homedir = () => nextHomeDir;
|
|
15
|
-
return () => {
|
|
16
|
-
(os as any).homedir = original;
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const readJson = async (filePath: string): Promise<Record<string, unknown>> => {
|
|
21
|
-
const content = await fs.readFile(filePath, 'utf8');
|
|
22
|
-
return JSON.parse(content) as Record<string, unknown>;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* This test covers Claude MCP support for all scopes (user/local/project) and all transports (stdio/http/sse),
|
|
27
|
-
* including add, update/list, and remove operations.
|
|
28
|
-
*/
|
|
29
|
-
test('providerMcpService handles claude MCP scopes/transports with file-backed persistence', { concurrency: false }, async () => {
|
|
30
|
-
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-claude-'));
|
|
31
|
-
const workspacePath = path.join(tempRoot, 'workspace');
|
|
32
|
-
await fs.mkdir(workspacePath, { recursive: true });
|
|
33
|
-
|
|
34
|
-
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
35
|
-
try {
|
|
36
|
-
await providerMcpService.upsertProviderMcpServer('claude', {
|
|
37
|
-
name: 'claude-user-stdio',
|
|
38
|
-
scope: 'user',
|
|
39
|
-
transport: 'stdio',
|
|
40
|
-
command: 'npx',
|
|
41
|
-
args: ['-y', 'my-server'],
|
|
42
|
-
env: { API_KEY: 'secret' },
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
await providerMcpService.upsertProviderMcpServer('claude', {
|
|
46
|
-
name: 'claude-local-http',
|
|
47
|
-
scope: 'local',
|
|
48
|
-
transport: 'http',
|
|
49
|
-
url: 'https://example.com/mcp',
|
|
50
|
-
headers: { Authorization: 'Bearer token' },
|
|
51
|
-
workspacePath,
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
await providerMcpService.upsertProviderMcpServer('claude', {
|
|
55
|
-
name: 'claude-project-sse',
|
|
56
|
-
scope: 'project',
|
|
57
|
-
transport: 'sse',
|
|
58
|
-
url: 'https://example.com/sse',
|
|
59
|
-
headers: { 'X-API-Key': 'abc' },
|
|
60
|
-
workspacePath,
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
const grouped = await providerMcpService.listProviderMcpServers('claude', { workspacePath });
|
|
64
|
-
assert.ok(grouped.user.some((server) => server.name === 'claude-user-stdio' && server.transport === 'stdio'));
|
|
65
|
-
assert.ok(grouped.local.some((server) => server.name === 'claude-local-http' && server.transport === 'http'));
|
|
66
|
-
assert.ok(grouped.project.some((server) => server.name === 'claude-project-sse' && server.transport === 'sse'));
|
|
67
|
-
|
|
68
|
-
// update behavior is the same upsert route with same name
|
|
69
|
-
await providerMcpService.upsertProviderMcpServer('claude', {
|
|
70
|
-
name: 'claude-project-sse',
|
|
71
|
-
scope: 'project',
|
|
72
|
-
transport: 'sse',
|
|
73
|
-
url: 'https://example.com/sse-updated',
|
|
74
|
-
headers: { 'X-API-Key': 'updated' },
|
|
75
|
-
workspacePath,
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
const projectConfig = await readJson(path.join(workspacePath, '.mcp.json'));
|
|
79
|
-
const projectServers = projectConfig.mcpServers as Record<string, unknown>;
|
|
80
|
-
const projectServer = projectServers['claude-project-sse'] as Record<string, unknown>;
|
|
81
|
-
assert.equal(projectServer.url, 'https://example.com/sse-updated');
|
|
82
|
-
|
|
83
|
-
const removeResult = await providerMcpService.removeProviderMcpServer('claude', {
|
|
84
|
-
name: 'claude-local-http',
|
|
85
|
-
scope: 'local',
|
|
86
|
-
workspacePath,
|
|
87
|
-
});
|
|
88
|
-
assert.equal(removeResult.removed, true);
|
|
89
|
-
} finally {
|
|
90
|
-
restoreHomeDir();
|
|
91
|
-
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* This test covers Codex MCP support for user/project scopes, stdio/http formats,
|
|
97
|
-
* and validation for unsupported scope/transport combinations.
|
|
98
|
-
*/
|
|
99
|
-
test('providerMcpService handles codex MCP TOML config and capability validation', { concurrency: false }, async () => {
|
|
100
|
-
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-codex-'));
|
|
101
|
-
const workspacePath = path.join(tempRoot, 'workspace');
|
|
102
|
-
await fs.mkdir(workspacePath, { recursive: true });
|
|
103
|
-
|
|
104
|
-
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
105
|
-
try {
|
|
106
|
-
await providerMcpService.upsertProviderMcpServer('codex', {
|
|
107
|
-
name: 'codex-user-stdio',
|
|
108
|
-
scope: 'user',
|
|
109
|
-
transport: 'stdio',
|
|
110
|
-
command: 'python',
|
|
111
|
-
args: ['server.py'],
|
|
112
|
-
env: { API_KEY: 'x' },
|
|
113
|
-
envVars: ['API_KEY'],
|
|
114
|
-
cwd: '/tmp',
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
await providerMcpService.upsertProviderMcpServer('codex', {
|
|
118
|
-
name: 'codex-project-http',
|
|
119
|
-
scope: 'project',
|
|
120
|
-
transport: 'http',
|
|
121
|
-
url: 'https://codex.example.com/mcp',
|
|
122
|
-
headers: { 'X-Custom-Header': 'value' },
|
|
123
|
-
envHttpHeaders: { 'X-API-Key': 'MY_API_KEY_ENV' },
|
|
124
|
-
bearerTokenEnvVar: 'MY_API_TOKEN',
|
|
125
|
-
workspacePath,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
const userTomlPath = path.join(tempRoot, '.codex', 'config.toml');
|
|
129
|
-
const userConfig = TOML.parse(await fs.readFile(userTomlPath, 'utf8')) as Record<string, unknown>;
|
|
130
|
-
const userServers = userConfig.mcp_servers as Record<string, unknown>;
|
|
131
|
-
const userStdio = userServers['codex-user-stdio'] as Record<string, unknown>;
|
|
132
|
-
assert.equal(userStdio.command, 'python');
|
|
133
|
-
|
|
134
|
-
const projectTomlPath = path.join(workspacePath, '.codex', 'config.toml');
|
|
135
|
-
const projectConfig = TOML.parse(await fs.readFile(projectTomlPath, 'utf8')) as Record<string, unknown>;
|
|
136
|
-
const projectServers = projectConfig.mcp_servers as Record<string, unknown>;
|
|
137
|
-
const projectHttp = projectServers['codex-project-http'] as Record<string, unknown>;
|
|
138
|
-
assert.equal(projectHttp.url, 'https://codex.example.com/mcp');
|
|
139
|
-
|
|
140
|
-
await assert.rejects(
|
|
141
|
-
providerMcpService.upsertProviderMcpServer('codex', {
|
|
142
|
-
name: 'codex-local',
|
|
143
|
-
scope: 'local',
|
|
144
|
-
transport: 'stdio',
|
|
145
|
-
command: 'node',
|
|
146
|
-
}),
|
|
147
|
-
(error: unknown) =>
|
|
148
|
-
error instanceof AppError &&
|
|
149
|
-
error.code === 'MCP_SCOPE_NOT_SUPPORTED' &&
|
|
150
|
-
error.statusCode === 400,
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
await assert.rejects(
|
|
154
|
-
providerMcpService.upsertProviderMcpServer('codex', {
|
|
155
|
-
name: 'codex-sse',
|
|
156
|
-
scope: 'project',
|
|
157
|
-
transport: 'sse',
|
|
158
|
-
url: 'https://example.com/sse',
|
|
159
|
-
workspacePath,
|
|
160
|
-
}),
|
|
161
|
-
(error: unknown) =>
|
|
162
|
-
error instanceof AppError &&
|
|
163
|
-
error.code === 'MCP_TRANSPORT_NOT_SUPPORTED' &&
|
|
164
|
-
error.statusCode === 400,
|
|
165
|
-
);
|
|
166
|
-
} finally {
|
|
167
|
-
restoreHomeDir();
|
|
168
|
-
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* This test covers OpenCode MCP support for user/project config files, JSONC-compatible
|
|
174
|
-
* reads, and validation for unsupported scope/transport combinations.
|
|
175
|
-
*/
|
|
176
|
-
test('providerMcpService handles opencode MCP config and capability validation', { concurrency: false }, async () => {
|
|
177
|
-
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-opencode-'));
|
|
178
|
-
const workspacePath = path.join(tempRoot, 'workspace');
|
|
179
|
-
await fs.mkdir(workspacePath, { recursive: true });
|
|
180
|
-
await fs.mkdir(path.join(tempRoot, '.config', 'opencode'), { recursive: true });
|
|
181
|
-
await fs.writeFile(
|
|
182
|
-
path.join(tempRoot, '.config', 'opencode', 'opencode.jsonc'),
|
|
183
|
-
`{
|
|
184
|
-
// Existing comments should not block OpenCode MCP reads.
|
|
185
|
-
"mcp": {}
|
|
186
|
-
}\n`,
|
|
187
|
-
'utf8',
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
191
|
-
try {
|
|
192
|
-
await providerMcpService.upsertProviderMcpServer('opencode', {
|
|
193
|
-
name: 'opencode-user-stdio',
|
|
194
|
-
scope: 'user',
|
|
195
|
-
transport: 'stdio',
|
|
196
|
-
command: 'node',
|
|
197
|
-
args: ['server.js'],
|
|
198
|
-
env: { API_KEY: 'x' },
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
await providerMcpService.upsertProviderMcpServer('opencode', {
|
|
202
|
-
name: 'opencode-project-http',
|
|
203
|
-
scope: 'project',
|
|
204
|
-
transport: 'http',
|
|
205
|
-
url: 'https://opencode.example.com/mcp',
|
|
206
|
-
headers: { Authorization: 'Bearer token' },
|
|
207
|
-
workspacePath,
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
const userConfig = await readJson(path.join(tempRoot, '.config', 'opencode', 'opencode.jsonc'));
|
|
211
|
-
const userServers = userConfig.mcp as Record<string, unknown>;
|
|
212
|
-
const userStdio = userServers['opencode-user-stdio'] as Record<string, unknown>;
|
|
213
|
-
assert.equal(userStdio.type, 'local');
|
|
214
|
-
assert.deepEqual(userStdio.command, ['node', 'server.js']);
|
|
215
|
-
assert.deepEqual(userStdio.environment, { API_KEY: 'x' });
|
|
216
|
-
|
|
217
|
-
const projectConfig = await readJson(path.join(workspacePath, 'opencode.json'));
|
|
218
|
-
const projectServers = projectConfig.mcp as Record<string, unknown>;
|
|
219
|
-
const projectHttp = projectServers['opencode-project-http'] as Record<string, unknown>;
|
|
220
|
-
assert.equal(projectHttp.type, 'remote');
|
|
221
|
-
assert.equal(projectHttp.url, 'https://opencode.example.com/mcp');
|
|
222
|
-
|
|
223
|
-
const grouped = await providerMcpService.listProviderMcpServers('opencode', { workspacePath });
|
|
224
|
-
assert.ok(grouped.user.some((server) => server.name === 'opencode-user-stdio' && server.transport === 'stdio'));
|
|
225
|
-
assert.ok(grouped.project.some((server) => server.name === 'opencode-project-http' && server.transport === 'http'));
|
|
226
|
-
|
|
227
|
-
await assert.rejects(
|
|
228
|
-
providerMcpService.upsertProviderMcpServer('opencode', {
|
|
229
|
-
name: 'opencode-local',
|
|
230
|
-
scope: 'local',
|
|
231
|
-
transport: 'stdio',
|
|
232
|
-
command: 'node',
|
|
233
|
-
}),
|
|
234
|
-
(error: unknown) =>
|
|
235
|
-
error instanceof AppError &&
|
|
236
|
-
error.code === 'MCP_SCOPE_NOT_SUPPORTED' &&
|
|
237
|
-
error.statusCode === 400,
|
|
238
|
-
);
|
|
239
|
-
|
|
240
|
-
await assert.rejects(
|
|
241
|
-
providerMcpService.upsertProviderMcpServer('opencode', {
|
|
242
|
-
name: 'opencode-sse',
|
|
243
|
-
scope: 'project',
|
|
244
|
-
transport: 'sse',
|
|
245
|
-
url: 'https://example.com/sse',
|
|
246
|
-
workspacePath,
|
|
247
|
-
}),
|
|
248
|
-
(error: unknown) =>
|
|
249
|
-
error instanceof AppError &&
|
|
250
|
-
error.code === 'MCP_TRANSPORT_NOT_SUPPORTED' &&
|
|
251
|
-
error.statusCode === 400,
|
|
252
|
-
);
|
|
253
|
-
} finally {
|
|
254
|
-
restoreHomeDir();
|
|
255
|
-
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* This test covers Cursor MCP JSON format and user/project scope persistence.
|
|
261
|
-
*/
|
|
262
|
-
test('providerMcpService handles cursor MCP JSON config formats', { concurrency: false }, async () => {
|
|
263
|
-
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-gc-'));
|
|
264
|
-
const workspacePath = path.join(tempRoot, 'workspace');
|
|
265
|
-
await fs.mkdir(workspacePath, { recursive: true });
|
|
266
|
-
|
|
267
|
-
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
268
|
-
try {
|
|
269
|
-
await providerMcpService.upsertProviderMcpServer('cursor', {
|
|
270
|
-
name: 'cursor-stdio',
|
|
271
|
-
scope: 'project',
|
|
272
|
-
transport: 'stdio',
|
|
273
|
-
command: 'npx',
|
|
274
|
-
args: ['-y', 'mcp-server'],
|
|
275
|
-
env: { API_KEY: 'value' },
|
|
276
|
-
workspacePath,
|
|
277
|
-
});
|
|
278
|
-
|
|
279
|
-
await providerMcpService.upsertProviderMcpServer('cursor', {
|
|
280
|
-
name: 'cursor-http',
|
|
281
|
-
scope: 'user',
|
|
282
|
-
transport: 'http',
|
|
283
|
-
url: 'http://localhost:3333/mcp',
|
|
284
|
-
headers: { API_KEY: 'value' },
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
const cursorUserConfig = await readJson(path.join(tempRoot, '.cursor', 'mcp.json'));
|
|
288
|
-
const cursorHttpServer = (cursorUserConfig.mcpServers as Record<string, unknown>)['cursor-http'] as Record<string, unknown>;
|
|
289
|
-
assert.equal(cursorHttpServer.url, 'http://localhost:3333/mcp');
|
|
290
|
-
assert.equal(cursorHttpServer.type, undefined);
|
|
291
|
-
} finally {
|
|
292
|
-
restoreHomeDir();
|
|
293
|
-
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
294
|
-
}
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* This test covers the global MCP adder requirement: only http/stdio are allowed and
|
|
299
|
-
* one payload is written to all providers.
|
|
300
|
-
*/
|
|
301
|
-
test('providerMcpService global adder writes to all providers and rejects unsupported transports', { concurrency: false }, async () => {
|
|
302
|
-
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-global-'));
|
|
303
|
-
const workspacePath = path.join(tempRoot, 'workspace');
|
|
304
|
-
await fs.mkdir(workspacePath, { recursive: true });
|
|
305
|
-
|
|
306
|
-
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
307
|
-
try {
|
|
308
|
-
const globalResult = await providerMcpService.addMcpServerToAllProviders({
|
|
309
|
-
name: 'global-http',
|
|
310
|
-
scope: 'project',
|
|
311
|
-
transport: 'http',
|
|
312
|
-
url: 'https://global.example.com/mcp',
|
|
313
|
-
workspacePath,
|
|
314
|
-
});
|
|
315
|
-
|
|
316
|
-
assert.equal(globalResult.length, 4);
|
|
317
|
-
assert.ok(globalResult.every((entry) => entry.created === true));
|
|
318
|
-
|
|
319
|
-
const claudeProject = await readJson(path.join(workspacePath, '.mcp.json'));
|
|
320
|
-
assert.ok((claudeProject.mcpServers as Record<string, unknown>)['global-http']);
|
|
321
|
-
|
|
322
|
-
const codexProject = TOML.parse(await fs.readFile(path.join(workspacePath, '.codex', 'config.toml'), 'utf8')) as Record<string, unknown>;
|
|
323
|
-
assert.ok((codexProject.mcp_servers as Record<string, unknown>)['global-http']);
|
|
324
|
-
|
|
325
|
-
const opencodeProject = await readJson(path.join(workspacePath, 'opencode.json'));
|
|
326
|
-
assert.ok((opencodeProject.mcp as Record<string, unknown>)['global-http']);
|
|
327
|
-
|
|
328
|
-
const cursorProject = await readJson(path.join(workspacePath, '.cursor', 'mcp.json'));
|
|
329
|
-
assert.ok((cursorProject.mcpServers as Record<string, unknown>)['global-http']);
|
|
330
|
-
|
|
331
|
-
await assert.rejects(
|
|
332
|
-
providerMcpService.addMcpServerToAllProviders({
|
|
333
|
-
name: 'global-sse',
|
|
334
|
-
scope: 'project',
|
|
335
|
-
transport: 'sse',
|
|
336
|
-
url: 'https://example.com/sse',
|
|
337
|
-
workspacePath,
|
|
338
|
-
}),
|
|
339
|
-
(error: unknown) =>
|
|
340
|
-
error instanceof AppError &&
|
|
341
|
-
error.code === 'INVALID_GLOBAL_MCP_TRANSPORT' &&
|
|
342
|
-
error.statusCode === 400,
|
|
343
|
-
);
|
|
344
|
-
} finally {
|
|
345
|
-
restoreHomeDir();
|
|
346
|
-
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
|
|
7
|
+
import TOML from '@iarna/toml';
|
|
8
|
+
|
|
9
|
+
import { providerMcpService } from '@/modules/providers/services/mcp.service.js';
|
|
10
|
+
import { AppError } from '@/shared/utils.js';
|
|
11
|
+
|
|
12
|
+
const patchHomeDir = (nextHomeDir: string) => {
|
|
13
|
+
const original = os.homedir;
|
|
14
|
+
(os as any).homedir = () => nextHomeDir;
|
|
15
|
+
return () => {
|
|
16
|
+
(os as any).homedir = original;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const readJson = async (filePath: string): Promise<Record<string, unknown>> => {
|
|
21
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
22
|
+
return JSON.parse(content) as Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* This test covers Claude MCP support for all scopes (user/local/project) and all transports (stdio/http/sse),
|
|
27
|
+
* including add, update/list, and remove operations.
|
|
28
|
+
*/
|
|
29
|
+
test('providerMcpService handles claude MCP scopes/transports with file-backed persistence', { concurrency: false }, async () => {
|
|
30
|
+
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-claude-'));
|
|
31
|
+
const workspacePath = path.join(tempRoot, 'workspace');
|
|
32
|
+
await fs.mkdir(workspacePath, { recursive: true });
|
|
33
|
+
|
|
34
|
+
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
35
|
+
try {
|
|
36
|
+
await providerMcpService.upsertProviderMcpServer('claude', {
|
|
37
|
+
name: 'claude-user-stdio',
|
|
38
|
+
scope: 'user',
|
|
39
|
+
transport: 'stdio',
|
|
40
|
+
command: 'npx',
|
|
41
|
+
args: ['-y', 'my-server'],
|
|
42
|
+
env: { API_KEY: 'secret' },
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
await providerMcpService.upsertProviderMcpServer('claude', {
|
|
46
|
+
name: 'claude-local-http',
|
|
47
|
+
scope: 'local',
|
|
48
|
+
transport: 'http',
|
|
49
|
+
url: 'https://example.com/mcp',
|
|
50
|
+
headers: { Authorization: 'Bearer token' },
|
|
51
|
+
workspacePath,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await providerMcpService.upsertProviderMcpServer('claude', {
|
|
55
|
+
name: 'claude-project-sse',
|
|
56
|
+
scope: 'project',
|
|
57
|
+
transport: 'sse',
|
|
58
|
+
url: 'https://example.com/sse',
|
|
59
|
+
headers: { 'X-API-Key': 'abc' },
|
|
60
|
+
workspacePath,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const grouped = await providerMcpService.listProviderMcpServers('claude', { workspacePath });
|
|
64
|
+
assert.ok(grouped.user.some((server) => server.name === 'claude-user-stdio' && server.transport === 'stdio'));
|
|
65
|
+
assert.ok(grouped.local.some((server) => server.name === 'claude-local-http' && server.transport === 'http'));
|
|
66
|
+
assert.ok(grouped.project.some((server) => server.name === 'claude-project-sse' && server.transport === 'sse'));
|
|
67
|
+
|
|
68
|
+
// update behavior is the same upsert route with same name
|
|
69
|
+
await providerMcpService.upsertProviderMcpServer('claude', {
|
|
70
|
+
name: 'claude-project-sse',
|
|
71
|
+
scope: 'project',
|
|
72
|
+
transport: 'sse',
|
|
73
|
+
url: 'https://example.com/sse-updated',
|
|
74
|
+
headers: { 'X-API-Key': 'updated' },
|
|
75
|
+
workspacePath,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const projectConfig = await readJson(path.join(workspacePath, '.mcp.json'));
|
|
79
|
+
const projectServers = projectConfig.mcpServers as Record<string, unknown>;
|
|
80
|
+
const projectServer = projectServers['claude-project-sse'] as Record<string, unknown>;
|
|
81
|
+
assert.equal(projectServer.url, 'https://example.com/sse-updated');
|
|
82
|
+
|
|
83
|
+
const removeResult = await providerMcpService.removeProviderMcpServer('claude', {
|
|
84
|
+
name: 'claude-local-http',
|
|
85
|
+
scope: 'local',
|
|
86
|
+
workspacePath,
|
|
87
|
+
});
|
|
88
|
+
assert.equal(removeResult.removed, true);
|
|
89
|
+
} finally {
|
|
90
|
+
restoreHomeDir();
|
|
91
|
+
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* This test covers Codex MCP support for user/project scopes, stdio/http formats,
|
|
97
|
+
* and validation for unsupported scope/transport combinations.
|
|
98
|
+
*/
|
|
99
|
+
test('providerMcpService handles codex MCP TOML config and capability validation', { concurrency: false }, async () => {
|
|
100
|
+
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-codex-'));
|
|
101
|
+
const workspacePath = path.join(tempRoot, 'workspace');
|
|
102
|
+
await fs.mkdir(workspacePath, { recursive: true });
|
|
103
|
+
|
|
104
|
+
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
105
|
+
try {
|
|
106
|
+
await providerMcpService.upsertProviderMcpServer('codex', {
|
|
107
|
+
name: 'codex-user-stdio',
|
|
108
|
+
scope: 'user',
|
|
109
|
+
transport: 'stdio',
|
|
110
|
+
command: 'python',
|
|
111
|
+
args: ['server.py'],
|
|
112
|
+
env: { API_KEY: 'x' },
|
|
113
|
+
envVars: ['API_KEY'],
|
|
114
|
+
cwd: '/tmp',
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
await providerMcpService.upsertProviderMcpServer('codex', {
|
|
118
|
+
name: 'codex-project-http',
|
|
119
|
+
scope: 'project',
|
|
120
|
+
transport: 'http',
|
|
121
|
+
url: 'https://codex.example.com/mcp',
|
|
122
|
+
headers: { 'X-Custom-Header': 'value' },
|
|
123
|
+
envHttpHeaders: { 'X-API-Key': 'MY_API_KEY_ENV' },
|
|
124
|
+
bearerTokenEnvVar: 'MY_API_TOKEN',
|
|
125
|
+
workspacePath,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const userTomlPath = path.join(tempRoot, '.codex', 'config.toml');
|
|
129
|
+
const userConfig = TOML.parse(await fs.readFile(userTomlPath, 'utf8')) as Record<string, unknown>;
|
|
130
|
+
const userServers = userConfig.mcp_servers as Record<string, unknown>;
|
|
131
|
+
const userStdio = userServers['codex-user-stdio'] as Record<string, unknown>;
|
|
132
|
+
assert.equal(userStdio.command, 'python');
|
|
133
|
+
|
|
134
|
+
const projectTomlPath = path.join(workspacePath, '.codex', 'config.toml');
|
|
135
|
+
const projectConfig = TOML.parse(await fs.readFile(projectTomlPath, 'utf8')) as Record<string, unknown>;
|
|
136
|
+
const projectServers = projectConfig.mcp_servers as Record<string, unknown>;
|
|
137
|
+
const projectHttp = projectServers['codex-project-http'] as Record<string, unknown>;
|
|
138
|
+
assert.equal(projectHttp.url, 'https://codex.example.com/mcp');
|
|
139
|
+
|
|
140
|
+
await assert.rejects(
|
|
141
|
+
providerMcpService.upsertProviderMcpServer('codex', {
|
|
142
|
+
name: 'codex-local',
|
|
143
|
+
scope: 'local',
|
|
144
|
+
transport: 'stdio',
|
|
145
|
+
command: 'node',
|
|
146
|
+
}),
|
|
147
|
+
(error: unknown) =>
|
|
148
|
+
error instanceof AppError &&
|
|
149
|
+
error.code === 'MCP_SCOPE_NOT_SUPPORTED' &&
|
|
150
|
+
error.statusCode === 400,
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
await assert.rejects(
|
|
154
|
+
providerMcpService.upsertProviderMcpServer('codex', {
|
|
155
|
+
name: 'codex-sse',
|
|
156
|
+
scope: 'project',
|
|
157
|
+
transport: 'sse',
|
|
158
|
+
url: 'https://example.com/sse',
|
|
159
|
+
workspacePath,
|
|
160
|
+
}),
|
|
161
|
+
(error: unknown) =>
|
|
162
|
+
error instanceof AppError &&
|
|
163
|
+
error.code === 'MCP_TRANSPORT_NOT_SUPPORTED' &&
|
|
164
|
+
error.statusCode === 400,
|
|
165
|
+
);
|
|
166
|
+
} finally {
|
|
167
|
+
restoreHomeDir();
|
|
168
|
+
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* This test covers OpenCode MCP support for user/project config files, JSONC-compatible
|
|
174
|
+
* reads, and validation for unsupported scope/transport combinations.
|
|
175
|
+
*/
|
|
176
|
+
test('providerMcpService handles opencode MCP config and capability validation', { concurrency: false }, async () => {
|
|
177
|
+
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-opencode-'));
|
|
178
|
+
const workspacePath = path.join(tempRoot, 'workspace');
|
|
179
|
+
await fs.mkdir(workspacePath, { recursive: true });
|
|
180
|
+
await fs.mkdir(path.join(tempRoot, '.config', 'opencode'), { recursive: true });
|
|
181
|
+
await fs.writeFile(
|
|
182
|
+
path.join(tempRoot, '.config', 'opencode', 'opencode.jsonc'),
|
|
183
|
+
`{
|
|
184
|
+
// Existing comments should not block OpenCode MCP reads.
|
|
185
|
+
"mcp": {}
|
|
186
|
+
}\n`,
|
|
187
|
+
'utf8',
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
191
|
+
try {
|
|
192
|
+
await providerMcpService.upsertProviderMcpServer('opencode', {
|
|
193
|
+
name: 'opencode-user-stdio',
|
|
194
|
+
scope: 'user',
|
|
195
|
+
transport: 'stdio',
|
|
196
|
+
command: 'node',
|
|
197
|
+
args: ['server.js'],
|
|
198
|
+
env: { API_KEY: 'x' },
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
await providerMcpService.upsertProviderMcpServer('opencode', {
|
|
202
|
+
name: 'opencode-project-http',
|
|
203
|
+
scope: 'project',
|
|
204
|
+
transport: 'http',
|
|
205
|
+
url: 'https://opencode.example.com/mcp',
|
|
206
|
+
headers: { Authorization: 'Bearer token' },
|
|
207
|
+
workspacePath,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const userConfig = await readJson(path.join(tempRoot, '.config', 'opencode', 'opencode.jsonc'));
|
|
211
|
+
const userServers = userConfig.mcp as Record<string, unknown>;
|
|
212
|
+
const userStdio = userServers['opencode-user-stdio'] as Record<string, unknown>;
|
|
213
|
+
assert.equal(userStdio.type, 'local');
|
|
214
|
+
assert.deepEqual(userStdio.command, ['node', 'server.js']);
|
|
215
|
+
assert.deepEqual(userStdio.environment, { API_KEY: 'x' });
|
|
216
|
+
|
|
217
|
+
const projectConfig = await readJson(path.join(workspacePath, 'opencode.json'));
|
|
218
|
+
const projectServers = projectConfig.mcp as Record<string, unknown>;
|
|
219
|
+
const projectHttp = projectServers['opencode-project-http'] as Record<string, unknown>;
|
|
220
|
+
assert.equal(projectHttp.type, 'remote');
|
|
221
|
+
assert.equal(projectHttp.url, 'https://opencode.example.com/mcp');
|
|
222
|
+
|
|
223
|
+
const grouped = await providerMcpService.listProviderMcpServers('opencode', { workspacePath });
|
|
224
|
+
assert.ok(grouped.user.some((server) => server.name === 'opencode-user-stdio' && server.transport === 'stdio'));
|
|
225
|
+
assert.ok(grouped.project.some((server) => server.name === 'opencode-project-http' && server.transport === 'http'));
|
|
226
|
+
|
|
227
|
+
await assert.rejects(
|
|
228
|
+
providerMcpService.upsertProviderMcpServer('opencode', {
|
|
229
|
+
name: 'opencode-local',
|
|
230
|
+
scope: 'local',
|
|
231
|
+
transport: 'stdio',
|
|
232
|
+
command: 'node',
|
|
233
|
+
}),
|
|
234
|
+
(error: unknown) =>
|
|
235
|
+
error instanceof AppError &&
|
|
236
|
+
error.code === 'MCP_SCOPE_NOT_SUPPORTED' &&
|
|
237
|
+
error.statusCode === 400,
|
|
238
|
+
);
|
|
239
|
+
|
|
240
|
+
await assert.rejects(
|
|
241
|
+
providerMcpService.upsertProviderMcpServer('opencode', {
|
|
242
|
+
name: 'opencode-sse',
|
|
243
|
+
scope: 'project',
|
|
244
|
+
transport: 'sse',
|
|
245
|
+
url: 'https://example.com/sse',
|
|
246
|
+
workspacePath,
|
|
247
|
+
}),
|
|
248
|
+
(error: unknown) =>
|
|
249
|
+
error instanceof AppError &&
|
|
250
|
+
error.code === 'MCP_TRANSPORT_NOT_SUPPORTED' &&
|
|
251
|
+
error.statusCode === 400,
|
|
252
|
+
);
|
|
253
|
+
} finally {
|
|
254
|
+
restoreHomeDir();
|
|
255
|
+
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* This test covers Cursor MCP JSON format and user/project scope persistence.
|
|
261
|
+
*/
|
|
262
|
+
test('providerMcpService handles cursor MCP JSON config formats', { concurrency: false }, async () => {
|
|
263
|
+
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-gc-'));
|
|
264
|
+
const workspacePath = path.join(tempRoot, 'workspace');
|
|
265
|
+
await fs.mkdir(workspacePath, { recursive: true });
|
|
266
|
+
|
|
267
|
+
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
268
|
+
try {
|
|
269
|
+
await providerMcpService.upsertProviderMcpServer('cursor', {
|
|
270
|
+
name: 'cursor-stdio',
|
|
271
|
+
scope: 'project',
|
|
272
|
+
transport: 'stdio',
|
|
273
|
+
command: 'npx',
|
|
274
|
+
args: ['-y', 'mcp-server'],
|
|
275
|
+
env: { API_KEY: 'value' },
|
|
276
|
+
workspacePath,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
await providerMcpService.upsertProviderMcpServer('cursor', {
|
|
280
|
+
name: 'cursor-http',
|
|
281
|
+
scope: 'user',
|
|
282
|
+
transport: 'http',
|
|
283
|
+
url: 'http://localhost:3333/mcp',
|
|
284
|
+
headers: { API_KEY: 'value' },
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
const cursorUserConfig = await readJson(path.join(tempRoot, '.cursor', 'mcp.json'));
|
|
288
|
+
const cursorHttpServer = (cursorUserConfig.mcpServers as Record<string, unknown>)['cursor-http'] as Record<string, unknown>;
|
|
289
|
+
assert.equal(cursorHttpServer.url, 'http://localhost:3333/mcp');
|
|
290
|
+
assert.equal(cursorHttpServer.type, undefined);
|
|
291
|
+
} finally {
|
|
292
|
+
restoreHomeDir();
|
|
293
|
+
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* This test covers the global MCP adder requirement: only http/stdio are allowed and
|
|
299
|
+
* one payload is written to all providers.
|
|
300
|
+
*/
|
|
301
|
+
test('providerMcpService global adder writes to all providers and rejects unsupported transports', { concurrency: false }, async () => {
|
|
302
|
+
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'llm-mcp-global-'));
|
|
303
|
+
const workspacePath = path.join(tempRoot, 'workspace');
|
|
304
|
+
await fs.mkdir(workspacePath, { recursive: true });
|
|
305
|
+
|
|
306
|
+
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
307
|
+
try {
|
|
308
|
+
const globalResult = await providerMcpService.addMcpServerToAllProviders({
|
|
309
|
+
name: 'global-http',
|
|
310
|
+
scope: 'project',
|
|
311
|
+
transport: 'http',
|
|
312
|
+
url: 'https://global.example.com/mcp',
|
|
313
|
+
workspacePath,
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
assert.equal(globalResult.length, 4);
|
|
317
|
+
assert.ok(globalResult.every((entry) => entry.created === true));
|
|
318
|
+
|
|
319
|
+
const claudeProject = await readJson(path.join(workspacePath, '.mcp.json'));
|
|
320
|
+
assert.ok((claudeProject.mcpServers as Record<string, unknown>)['global-http']);
|
|
321
|
+
|
|
322
|
+
const codexProject = TOML.parse(await fs.readFile(path.join(workspacePath, '.codex', 'config.toml'), 'utf8')) as Record<string, unknown>;
|
|
323
|
+
assert.ok((codexProject.mcp_servers as Record<string, unknown>)['global-http']);
|
|
324
|
+
|
|
325
|
+
const opencodeProject = await readJson(path.join(workspacePath, 'opencode.json'));
|
|
326
|
+
assert.ok((opencodeProject.mcp as Record<string, unknown>)['global-http']);
|
|
327
|
+
|
|
328
|
+
const cursorProject = await readJson(path.join(workspacePath, '.cursor', 'mcp.json'));
|
|
329
|
+
assert.ok((cursorProject.mcpServers as Record<string, unknown>)['global-http']);
|
|
330
|
+
|
|
331
|
+
await assert.rejects(
|
|
332
|
+
providerMcpService.addMcpServerToAllProviders({
|
|
333
|
+
name: 'global-sse',
|
|
334
|
+
scope: 'project',
|
|
335
|
+
transport: 'sse',
|
|
336
|
+
url: 'https://example.com/sse',
|
|
337
|
+
workspacePath,
|
|
338
|
+
}),
|
|
339
|
+
(error: unknown) =>
|
|
340
|
+
error instanceof AppError &&
|
|
341
|
+
error.code === 'INVALID_GLOBAL_MCP_TRANSPORT' &&
|
|
342
|
+
error.statusCode === 400,
|
|
343
|
+
);
|
|
344
|
+
} finally {
|
|
345
|
+
restoreHomeDir();
|
|
346
|
+
await fs.rm(tempRoot, { recursive: true, force: true });
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
|