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,287 +1,287 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { mkdir, rm, stat, writeFile } from 'node:fs/promises';
|
|
3
|
-
|
|
4
|
-
import type { IProviderSkills } from '@/shared/interfaces.js';
|
|
5
|
-
import type {
|
|
6
|
-
LLMProvider,
|
|
7
|
-
ProviderSkillCreateInput,
|
|
8
|
-
ProviderSkillRemoveInput,
|
|
9
|
-
ProviderSkill,
|
|
10
|
-
ProviderSkillListOptions,
|
|
11
|
-
ProviderSkillSource,
|
|
12
|
-
} from '@/shared/types.js';
|
|
13
|
-
import {
|
|
14
|
-
findProviderSkillMarkdownFiles,
|
|
15
|
-
readOptionalString,
|
|
16
|
-
readProviderSkillMarkdownDefinitionFromContent,
|
|
17
|
-
readProviderSkillMarkdownDefinition,
|
|
18
|
-
AppError,
|
|
19
|
-
} from '@/shared/utils.js';
|
|
20
|
-
|
|
21
|
-
const resolveWorkspacePath = (workspacePath?: string): string =>
|
|
22
|
-
path.resolve(workspacePath ?? process.cwd());
|
|
23
|
-
|
|
24
|
-
const stripMarkdownExtension = (value: string): string => value.replace(/\.md$/i, '');
|
|
25
|
-
|
|
26
|
-
const normalizeSkillDirectoryName = (value: string): string => (
|
|
27
|
-
value
|
|
28
|
-
.trim()
|
|
29
|
-
.replace(/[\\/]+/g, '-')
|
|
30
|
-
.replace(/[<>:"|?*\x00-\x1F]/g, '-')
|
|
31
|
-
.replace(/\s+/g, '-')
|
|
32
|
-
.replace(/-+/g, '-')
|
|
33
|
-
.replace(/^\.+|\.+$/g, '')
|
|
34
|
-
.replace(/^-+|-+$/g, '')
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
type PendingSkillInstall = {
|
|
38
|
-
skillDirectoryPath: string;
|
|
39
|
-
skillPath: string;
|
|
40
|
-
content: string;
|
|
41
|
-
supportingFiles: Array<{
|
|
42
|
-
targetPath: string;
|
|
43
|
-
content: string | Buffer;
|
|
44
|
-
}>;
|
|
45
|
-
skill: ProviderSkill;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
const resolveSkillSupportingFilePath = (
|
|
49
|
-
skillDirectoryPath: string,
|
|
50
|
-
relativePath: string,
|
|
51
|
-
entryIndex: number,
|
|
52
|
-
): string => {
|
|
53
|
-
const normalizedRelativePath = relativePath.trim().replace(/\\/g, '/');
|
|
54
|
-
const pathSegments = normalizedRelativePath.split('/');
|
|
55
|
-
if (
|
|
56
|
-
!normalizedRelativePath
|
|
57
|
-
|| path.isAbsolute(normalizedRelativePath)
|
|
58
|
-
|| pathSegments.some((segment) => !segment || segment === '.' || segment === '..')
|
|
59
|
-
|| normalizedRelativePath.toLowerCase() === 'skill.md'
|
|
60
|
-
) {
|
|
61
|
-
throw new AppError(
|
|
62
|
-
`Skill entry ${entryIndex + 1} includes an invalid supporting file path "${relativePath}".`,
|
|
63
|
-
{
|
|
64
|
-
code: 'PROVIDER_SKILL_FILE_PATH_INVALID',
|
|
65
|
-
statusCode: 400,
|
|
66
|
-
},
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const resolvedSkillDirectoryPath = path.resolve(skillDirectoryPath);
|
|
71
|
-
const resolvedFilePath = path.resolve(resolvedSkillDirectoryPath, ...pathSegments);
|
|
72
|
-
if (!resolvedFilePath.startsWith(`${resolvedSkillDirectoryPath}${path.sep}`)) {
|
|
73
|
-
throw new AppError(
|
|
74
|
-
`Skill entry ${entryIndex + 1} supporting files must stay inside the skill directory.`,
|
|
75
|
-
{
|
|
76
|
-
code: 'PROVIDER_SKILL_FILE_PATH_INVALID',
|
|
77
|
-
statusCode: 400,
|
|
78
|
-
},
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return resolvedFilePath;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Shared skills provider for provider-specific skill source discovery.
|
|
87
|
-
*/
|
|
88
|
-
export abstract class SkillsProvider implements IProviderSkills {
|
|
89
|
-
protected readonly provider: LLMProvider;
|
|
90
|
-
|
|
91
|
-
protected constructor(provider: LLMProvider) {
|
|
92
|
-
this.provider = provider;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async listSkills(options?: ProviderSkillListOptions): Promise<ProviderSkill[]> {
|
|
96
|
-
const workspacePath = resolveWorkspacePath(options?.workspacePath);
|
|
97
|
-
const sources = await this.getSkillSources(workspacePath);
|
|
98
|
-
const skills: ProviderSkill[] = [];
|
|
99
|
-
|
|
100
|
-
for (const source of sources) {
|
|
101
|
-
const skillFiles = await findProviderSkillMarkdownFiles(source.rootDir, {
|
|
102
|
-
recursive: source.recursive,
|
|
103
|
-
});
|
|
104
|
-
for (const skillPath of skillFiles) {
|
|
105
|
-
try {
|
|
106
|
-
const definition = await readProviderSkillMarkdownDefinition(skillPath);
|
|
107
|
-
const command = source.commandForSkill
|
|
108
|
-
? source.commandForSkill(definition.name)
|
|
109
|
-
: `${source.commandPrefix ?? '/'}${definition.name}`;
|
|
110
|
-
|
|
111
|
-
skills.push({
|
|
112
|
-
provider: this.provider,
|
|
113
|
-
name: definition.name,
|
|
114
|
-
description: definition.description,
|
|
115
|
-
command,
|
|
116
|
-
scope: source.scope,
|
|
117
|
-
sourcePath: skillPath,
|
|
118
|
-
pluginName: source.pluginName,
|
|
119
|
-
pluginId: source.pluginId,
|
|
120
|
-
});
|
|
121
|
-
} catch {
|
|
122
|
-
// A malformed or unreadable skill markdown file should not hide other valid skills.
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return skills;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async addSkills(input: ProviderSkillCreateInput): Promise<ProviderSkill[]> {
|
|
131
|
-
const globalSkillSource = await this.getGlobalSkillSource();
|
|
132
|
-
if (!globalSkillSource) {
|
|
133
|
-
throw new AppError(`${this.provider} does not support managed global skills.`, {
|
|
134
|
-
code: 'PROVIDER_SKILLS_WRITE_UNSUPPORTED',
|
|
135
|
-
statusCode: 400,
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (!Array.isArray(input.entries) || input.entries.length === 0) {
|
|
140
|
-
throw new AppError('At least one skill entry is required.', {
|
|
141
|
-
code: 'PROVIDER_SKILLS_REQUIRED',
|
|
142
|
-
statusCode: 400,
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const seenSkillPaths = new Set<string>();
|
|
147
|
-
const pendingInstalls: PendingSkillInstall[] = [];
|
|
148
|
-
|
|
149
|
-
for (const [index, entry] of input.entries.entries()) {
|
|
150
|
-
const content = typeof entry.content === 'string' ? entry.content.trim() : '';
|
|
151
|
-
if (!content) {
|
|
152
|
-
throw new AppError(`Skill entry ${index + 1} must include markdown content.`, {
|
|
153
|
-
code: 'PROVIDER_SKILL_CONTENT_REQUIRED',
|
|
154
|
-
statusCode: 400,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const fileNameFallback = readOptionalString(entry.fileName);
|
|
159
|
-
const requestedDirectoryName = readOptionalString(entry.directoryName);
|
|
160
|
-
const fallbackSkillName = normalizeSkillDirectoryName(
|
|
161
|
-
requestedDirectoryName
|
|
162
|
-
?? (fileNameFallback ? stripMarkdownExtension(fileNameFallback) : `skill-${index + 1}`),
|
|
163
|
-
);
|
|
164
|
-
const definition = readProviderSkillMarkdownDefinitionFromContent(content, fallbackSkillName);
|
|
165
|
-
const resolvedDirectoryName = normalizeSkillDirectoryName(
|
|
166
|
-
requestedDirectoryName ?? definition.name,
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
if (!resolvedDirectoryName) {
|
|
170
|
-
throw new AppError(`Skill entry ${index + 1} must include a valid skill name.`, {
|
|
171
|
-
code: 'PROVIDER_SKILL_NAME_REQUIRED',
|
|
172
|
-
statusCode: 400,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const skillDirectoryPath = path.join(globalSkillSource.rootDir, resolvedDirectoryName);
|
|
177
|
-
const skillPath = path.join(skillDirectoryPath, 'SKILL.md');
|
|
178
|
-
const normalizedSkillPath = path.resolve(skillPath);
|
|
179
|
-
if (seenSkillPaths.has(normalizedSkillPath)) {
|
|
180
|
-
throw new AppError(`Duplicate skill target "${resolvedDirectoryName}" in one request.`, {
|
|
181
|
-
code: 'PROVIDER_SKILL_DUPLICATE_TARGET',
|
|
182
|
-
statusCode: 400,
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
seenSkillPaths.add(normalizedSkillPath);
|
|
187
|
-
const supportingFiles = (entry.files ?? []).map((file) => ({
|
|
188
|
-
targetPath: resolveSkillSupportingFilePath(skillDirectoryPath, file.relativePath, index),
|
|
189
|
-
content: file.encoding === 'base64'
|
|
190
|
-
? Buffer.from(file.content, 'base64')
|
|
191
|
-
: file.content,
|
|
192
|
-
}));
|
|
193
|
-
const seenSupportingPaths = new Set<string>();
|
|
194
|
-
for (const file of supportingFiles) {
|
|
195
|
-
if (seenSupportingPaths.has(file.targetPath)) {
|
|
196
|
-
throw new AppError(`Skill entry ${index + 1} includes a duplicate supporting file path.`, {
|
|
197
|
-
code: 'PROVIDER_SKILL_DUPLICATE_FILE',
|
|
198
|
-
statusCode: 400,
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
seenSupportingPaths.add(file.targetPath);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const command = globalSkillSource.commandForSkill
|
|
205
|
-
? globalSkillSource.commandForSkill(definition.name)
|
|
206
|
-
: `${globalSkillSource.commandPrefix ?? '/'}${definition.name}`;
|
|
207
|
-
|
|
208
|
-
pendingInstalls.push({
|
|
209
|
-
skillDirectoryPath,
|
|
210
|
-
skillPath,
|
|
211
|
-
content,
|
|
212
|
-
supportingFiles,
|
|
213
|
-
skill: {
|
|
214
|
-
provider: this.provider,
|
|
215
|
-
name: definition.name,
|
|
216
|
-
description: definition.description,
|
|
217
|
-
command,
|
|
218
|
-
scope: globalSkillSource.scope,
|
|
219
|
-
sourcePath: skillPath,
|
|
220
|
-
pluginName: globalSkillSource.pluginName,
|
|
221
|
-
pluginId: globalSkillSource.pluginId,
|
|
222
|
-
},
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
for (const install of pendingInstalls) {
|
|
227
|
-
// Replace the complete skill directory so removed scripts or assets do not remain stale.
|
|
228
|
-
await rm(install.skillDirectoryPath, { recursive: true, force: true });
|
|
229
|
-
await mkdir(install.skillDirectoryPath, { recursive: true });
|
|
230
|
-
await writeFile(install.skillPath, `${install.content}\n`, 'utf8');
|
|
231
|
-
for (const file of install.supportingFiles) {
|
|
232
|
-
await mkdir(path.dirname(file.targetPath), { recursive: true });
|
|
233
|
-
await writeFile(file.targetPath, file.content);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return pendingInstalls.map((install) => install.skill);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
async removeSkill(
|
|
241
|
-
input: ProviderSkillRemoveInput,
|
|
242
|
-
): Promise<{ removed: boolean; provider: LLMProvider; directoryName: string }> {
|
|
243
|
-
const globalSkillSource = await this.getGlobalSkillSource();
|
|
244
|
-
if (!globalSkillSource) {
|
|
245
|
-
throw new AppError(`${this.provider} does not support managed global skills.`, {
|
|
246
|
-
code: 'PROVIDER_SKILLS_WRITE_UNSUPPORTED',
|
|
247
|
-
statusCode: 400,
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
const directoryName = normalizeSkillDirectoryName(input.directoryName);
|
|
252
|
-
if (!directoryName) {
|
|
253
|
-
throw new AppError('Skill directoryName is required.', {
|
|
254
|
-
code: 'PROVIDER_SKILL_DIRECTORY_REQUIRED',
|
|
255
|
-
statusCode: 400,
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
const skillDirectoryPath = path.join(globalSkillSource.rootDir, directoryName);
|
|
260
|
-
const resolvedRoot = path.resolve(globalSkillSource.rootDir);
|
|
261
|
-
const resolvedSkillDirectoryPath = path.resolve(skillDirectoryPath);
|
|
262
|
-
if (
|
|
263
|
-
resolvedSkillDirectoryPath !== resolvedRoot
|
|
264
|
-
&& !resolvedSkillDirectoryPath.startsWith(`${resolvedRoot}${path.sep}`)
|
|
265
|
-
) {
|
|
266
|
-
throw new AppError('Skill directory must stay inside the managed skill root.', {
|
|
267
|
-
code: 'PROVIDER_SKILL_DIRECTORY_INVALID',
|
|
268
|
-
statusCode: 400,
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const removed = await stat(resolvedSkillDirectoryPath)
|
|
273
|
-
.then((stats) => stats.isDirectory())
|
|
274
|
-
.catch(() => false);
|
|
275
|
-
if (removed) {
|
|
276
|
-
await rm(resolvedSkillDirectoryPath, { recursive: true, force: true });
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
return { removed, provider: this.provider, directoryName };
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
protected abstract getSkillSources(workspacePath: string): Promise<ProviderSkillSource[]>;
|
|
283
|
-
|
|
284
|
-
protected async getGlobalSkillSource(): Promise<ProviderSkillSource | null> {
|
|
285
|
-
return null;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { mkdir, rm, stat, writeFile } from 'node:fs/promises';
|
|
3
|
+
|
|
4
|
+
import type { IProviderSkills } from '@/shared/interfaces.js';
|
|
5
|
+
import type {
|
|
6
|
+
LLMProvider,
|
|
7
|
+
ProviderSkillCreateInput,
|
|
8
|
+
ProviderSkillRemoveInput,
|
|
9
|
+
ProviderSkill,
|
|
10
|
+
ProviderSkillListOptions,
|
|
11
|
+
ProviderSkillSource,
|
|
12
|
+
} from '@/shared/types.js';
|
|
13
|
+
import {
|
|
14
|
+
findProviderSkillMarkdownFiles,
|
|
15
|
+
readOptionalString,
|
|
16
|
+
readProviderSkillMarkdownDefinitionFromContent,
|
|
17
|
+
readProviderSkillMarkdownDefinition,
|
|
18
|
+
AppError,
|
|
19
|
+
} from '@/shared/utils.js';
|
|
20
|
+
|
|
21
|
+
const resolveWorkspacePath = (workspacePath?: string): string =>
|
|
22
|
+
path.resolve(workspacePath ?? process.cwd());
|
|
23
|
+
|
|
24
|
+
const stripMarkdownExtension = (value: string): string => value.replace(/\.md$/i, '');
|
|
25
|
+
|
|
26
|
+
const normalizeSkillDirectoryName = (value: string): string => (
|
|
27
|
+
value
|
|
28
|
+
.trim()
|
|
29
|
+
.replace(/[\\/]+/g, '-')
|
|
30
|
+
.replace(/[<>:"|?*\x00-\x1F]/g, '-')
|
|
31
|
+
.replace(/\s+/g, '-')
|
|
32
|
+
.replace(/-+/g, '-')
|
|
33
|
+
.replace(/^\.+|\.+$/g, '')
|
|
34
|
+
.replace(/^-+|-+$/g, '')
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
type PendingSkillInstall = {
|
|
38
|
+
skillDirectoryPath: string;
|
|
39
|
+
skillPath: string;
|
|
40
|
+
content: string;
|
|
41
|
+
supportingFiles: Array<{
|
|
42
|
+
targetPath: string;
|
|
43
|
+
content: string | Buffer;
|
|
44
|
+
}>;
|
|
45
|
+
skill: ProviderSkill;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const resolveSkillSupportingFilePath = (
|
|
49
|
+
skillDirectoryPath: string,
|
|
50
|
+
relativePath: string,
|
|
51
|
+
entryIndex: number,
|
|
52
|
+
): string => {
|
|
53
|
+
const normalizedRelativePath = relativePath.trim().replace(/\\/g, '/');
|
|
54
|
+
const pathSegments = normalizedRelativePath.split('/');
|
|
55
|
+
if (
|
|
56
|
+
!normalizedRelativePath
|
|
57
|
+
|| path.isAbsolute(normalizedRelativePath)
|
|
58
|
+
|| pathSegments.some((segment) => !segment || segment === '.' || segment === '..')
|
|
59
|
+
|| normalizedRelativePath.toLowerCase() === 'skill.md'
|
|
60
|
+
) {
|
|
61
|
+
throw new AppError(
|
|
62
|
+
`Skill entry ${entryIndex + 1} includes an invalid supporting file path "${relativePath}".`,
|
|
63
|
+
{
|
|
64
|
+
code: 'PROVIDER_SKILL_FILE_PATH_INVALID',
|
|
65
|
+
statusCode: 400,
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const resolvedSkillDirectoryPath = path.resolve(skillDirectoryPath);
|
|
71
|
+
const resolvedFilePath = path.resolve(resolvedSkillDirectoryPath, ...pathSegments);
|
|
72
|
+
if (!resolvedFilePath.startsWith(`${resolvedSkillDirectoryPath}${path.sep}`)) {
|
|
73
|
+
throw new AppError(
|
|
74
|
+
`Skill entry ${entryIndex + 1} supporting files must stay inside the skill directory.`,
|
|
75
|
+
{
|
|
76
|
+
code: 'PROVIDER_SKILL_FILE_PATH_INVALID',
|
|
77
|
+
statusCode: 400,
|
|
78
|
+
},
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return resolvedFilePath;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Shared skills provider for provider-specific skill source discovery.
|
|
87
|
+
*/
|
|
88
|
+
export abstract class SkillsProvider implements IProviderSkills {
|
|
89
|
+
protected readonly provider: LLMProvider;
|
|
90
|
+
|
|
91
|
+
protected constructor(provider: LLMProvider) {
|
|
92
|
+
this.provider = provider;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async listSkills(options?: ProviderSkillListOptions): Promise<ProviderSkill[]> {
|
|
96
|
+
const workspacePath = resolveWorkspacePath(options?.workspacePath);
|
|
97
|
+
const sources = await this.getSkillSources(workspacePath);
|
|
98
|
+
const skills: ProviderSkill[] = [];
|
|
99
|
+
|
|
100
|
+
for (const source of sources) {
|
|
101
|
+
const skillFiles = await findProviderSkillMarkdownFiles(source.rootDir, {
|
|
102
|
+
recursive: source.recursive,
|
|
103
|
+
});
|
|
104
|
+
for (const skillPath of skillFiles) {
|
|
105
|
+
try {
|
|
106
|
+
const definition = await readProviderSkillMarkdownDefinition(skillPath);
|
|
107
|
+
const command = source.commandForSkill
|
|
108
|
+
? source.commandForSkill(definition.name)
|
|
109
|
+
: `${source.commandPrefix ?? '/'}${definition.name}`;
|
|
110
|
+
|
|
111
|
+
skills.push({
|
|
112
|
+
provider: this.provider,
|
|
113
|
+
name: definition.name,
|
|
114
|
+
description: definition.description,
|
|
115
|
+
command,
|
|
116
|
+
scope: source.scope,
|
|
117
|
+
sourcePath: skillPath,
|
|
118
|
+
pluginName: source.pluginName,
|
|
119
|
+
pluginId: source.pluginId,
|
|
120
|
+
});
|
|
121
|
+
} catch {
|
|
122
|
+
// A malformed or unreadable skill markdown file should not hide other valid skills.
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return skills;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async addSkills(input: ProviderSkillCreateInput): Promise<ProviderSkill[]> {
|
|
131
|
+
const globalSkillSource = await this.getGlobalSkillSource();
|
|
132
|
+
if (!globalSkillSource) {
|
|
133
|
+
throw new AppError(`${this.provider} does not support managed global skills.`, {
|
|
134
|
+
code: 'PROVIDER_SKILLS_WRITE_UNSUPPORTED',
|
|
135
|
+
statusCode: 400,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (!Array.isArray(input.entries) || input.entries.length === 0) {
|
|
140
|
+
throw new AppError('At least one skill entry is required.', {
|
|
141
|
+
code: 'PROVIDER_SKILLS_REQUIRED',
|
|
142
|
+
statusCode: 400,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const seenSkillPaths = new Set<string>();
|
|
147
|
+
const pendingInstalls: PendingSkillInstall[] = [];
|
|
148
|
+
|
|
149
|
+
for (const [index, entry] of input.entries.entries()) {
|
|
150
|
+
const content = typeof entry.content === 'string' ? entry.content.trim() : '';
|
|
151
|
+
if (!content) {
|
|
152
|
+
throw new AppError(`Skill entry ${index + 1} must include markdown content.`, {
|
|
153
|
+
code: 'PROVIDER_SKILL_CONTENT_REQUIRED',
|
|
154
|
+
statusCode: 400,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const fileNameFallback = readOptionalString(entry.fileName);
|
|
159
|
+
const requestedDirectoryName = readOptionalString(entry.directoryName);
|
|
160
|
+
const fallbackSkillName = normalizeSkillDirectoryName(
|
|
161
|
+
requestedDirectoryName
|
|
162
|
+
?? (fileNameFallback ? stripMarkdownExtension(fileNameFallback) : `skill-${index + 1}`),
|
|
163
|
+
);
|
|
164
|
+
const definition = readProviderSkillMarkdownDefinitionFromContent(content, fallbackSkillName);
|
|
165
|
+
const resolvedDirectoryName = normalizeSkillDirectoryName(
|
|
166
|
+
requestedDirectoryName ?? definition.name,
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
if (!resolvedDirectoryName) {
|
|
170
|
+
throw new AppError(`Skill entry ${index + 1} must include a valid skill name.`, {
|
|
171
|
+
code: 'PROVIDER_SKILL_NAME_REQUIRED',
|
|
172
|
+
statusCode: 400,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const skillDirectoryPath = path.join(globalSkillSource.rootDir, resolvedDirectoryName);
|
|
177
|
+
const skillPath = path.join(skillDirectoryPath, 'SKILL.md');
|
|
178
|
+
const normalizedSkillPath = path.resolve(skillPath);
|
|
179
|
+
if (seenSkillPaths.has(normalizedSkillPath)) {
|
|
180
|
+
throw new AppError(`Duplicate skill target "${resolvedDirectoryName}" in one request.`, {
|
|
181
|
+
code: 'PROVIDER_SKILL_DUPLICATE_TARGET',
|
|
182
|
+
statusCode: 400,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
seenSkillPaths.add(normalizedSkillPath);
|
|
187
|
+
const supportingFiles = (entry.files ?? []).map((file) => ({
|
|
188
|
+
targetPath: resolveSkillSupportingFilePath(skillDirectoryPath, file.relativePath, index),
|
|
189
|
+
content: file.encoding === 'base64'
|
|
190
|
+
? Buffer.from(file.content, 'base64')
|
|
191
|
+
: file.content,
|
|
192
|
+
}));
|
|
193
|
+
const seenSupportingPaths = new Set<string>();
|
|
194
|
+
for (const file of supportingFiles) {
|
|
195
|
+
if (seenSupportingPaths.has(file.targetPath)) {
|
|
196
|
+
throw new AppError(`Skill entry ${index + 1} includes a duplicate supporting file path.`, {
|
|
197
|
+
code: 'PROVIDER_SKILL_DUPLICATE_FILE',
|
|
198
|
+
statusCode: 400,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
seenSupportingPaths.add(file.targetPath);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const command = globalSkillSource.commandForSkill
|
|
205
|
+
? globalSkillSource.commandForSkill(definition.name)
|
|
206
|
+
: `${globalSkillSource.commandPrefix ?? '/'}${definition.name}`;
|
|
207
|
+
|
|
208
|
+
pendingInstalls.push({
|
|
209
|
+
skillDirectoryPath,
|
|
210
|
+
skillPath,
|
|
211
|
+
content,
|
|
212
|
+
supportingFiles,
|
|
213
|
+
skill: {
|
|
214
|
+
provider: this.provider,
|
|
215
|
+
name: definition.name,
|
|
216
|
+
description: definition.description,
|
|
217
|
+
command,
|
|
218
|
+
scope: globalSkillSource.scope,
|
|
219
|
+
sourcePath: skillPath,
|
|
220
|
+
pluginName: globalSkillSource.pluginName,
|
|
221
|
+
pluginId: globalSkillSource.pluginId,
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
for (const install of pendingInstalls) {
|
|
227
|
+
// Replace the complete skill directory so removed scripts or assets do not remain stale.
|
|
228
|
+
await rm(install.skillDirectoryPath, { recursive: true, force: true });
|
|
229
|
+
await mkdir(install.skillDirectoryPath, { recursive: true });
|
|
230
|
+
await writeFile(install.skillPath, `${install.content}\n`, 'utf8');
|
|
231
|
+
for (const file of install.supportingFiles) {
|
|
232
|
+
await mkdir(path.dirname(file.targetPath), { recursive: true });
|
|
233
|
+
await writeFile(file.targetPath, file.content);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return pendingInstalls.map((install) => install.skill);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async removeSkill(
|
|
241
|
+
input: ProviderSkillRemoveInput,
|
|
242
|
+
): Promise<{ removed: boolean; provider: LLMProvider; directoryName: string }> {
|
|
243
|
+
const globalSkillSource = await this.getGlobalSkillSource();
|
|
244
|
+
if (!globalSkillSource) {
|
|
245
|
+
throw new AppError(`${this.provider} does not support managed global skills.`, {
|
|
246
|
+
code: 'PROVIDER_SKILLS_WRITE_UNSUPPORTED',
|
|
247
|
+
statusCode: 400,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const directoryName = normalizeSkillDirectoryName(input.directoryName);
|
|
252
|
+
if (!directoryName) {
|
|
253
|
+
throw new AppError('Skill directoryName is required.', {
|
|
254
|
+
code: 'PROVIDER_SKILL_DIRECTORY_REQUIRED',
|
|
255
|
+
statusCode: 400,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const skillDirectoryPath = path.join(globalSkillSource.rootDir, directoryName);
|
|
260
|
+
const resolvedRoot = path.resolve(globalSkillSource.rootDir);
|
|
261
|
+
const resolvedSkillDirectoryPath = path.resolve(skillDirectoryPath);
|
|
262
|
+
if (
|
|
263
|
+
resolvedSkillDirectoryPath !== resolvedRoot
|
|
264
|
+
&& !resolvedSkillDirectoryPath.startsWith(`${resolvedRoot}${path.sep}`)
|
|
265
|
+
) {
|
|
266
|
+
throw new AppError('Skill directory must stay inside the managed skill root.', {
|
|
267
|
+
code: 'PROVIDER_SKILL_DIRECTORY_INVALID',
|
|
268
|
+
statusCode: 400,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const removed = await stat(resolvedSkillDirectoryPath)
|
|
273
|
+
.then((stats) => stats.isDirectory())
|
|
274
|
+
.catch(() => false);
|
|
275
|
+
if (removed) {
|
|
276
|
+
await rm(resolvedSkillDirectoryPath, { recursive: true, force: true });
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return { removed, provider: this.provider, directoryName };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
protected abstract getSkillSources(workspacePath: string): Promise<ProviderSkillSource[]>;
|
|
283
|
+
|
|
284
|
+
protected async getGlobalSkillSource(): Promise<ProviderSkillSource | null> {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
}
|