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,2 +1,2 @@
|
|
|
1
|
-
// createGitModule: used by the server entrypoint to assemble Git routes with provider runtimes.
|
|
2
|
-
export { createGitModule } from './git.module.js';
|
|
1
|
+
// createGitModule: used by the server entrypoint to assemble Git routes with provider runtimes.
|
|
2
|
+
export { createGitModule } from './git.module.js';
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import test from 'node:test';
|
|
3
|
-
|
|
4
|
-
import { deleteLocalBranch } from '../git-branch.service.js';
|
|
5
|
-
|
|
6
|
-
test('deleteLocalBranch uses safe deletion by default', async () => {
|
|
7
|
-
const commands: string[][] = [];
|
|
8
|
-
const output = await deleteLocalBranch({
|
|
9
|
-
projectPath: '/workspace/repo',
|
|
10
|
-
branch: 'feature/safe-delete',
|
|
11
|
-
force: false,
|
|
12
|
-
runCommand: async (_command, args) => {
|
|
13
|
-
commands.push(args);
|
|
14
|
-
return {
|
|
15
|
-
stdout: args.includes('--show-current') ? 'main\n' : 'Deleted branch feature/safe-delete.\n',
|
|
16
|
-
stderr: '',
|
|
17
|
-
};
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
assert.equal(output, 'Deleted branch feature/safe-delete.\n');
|
|
22
|
-
assert.deepEqual(commands, [
|
|
23
|
-
['branch', '--show-current'],
|
|
24
|
-
['branch', '-d', '--', 'feature/safe-delete'],
|
|
25
|
-
]);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test('deleteLocalBranch uses force deletion only when requested', async () => {
|
|
29
|
-
const commands: string[][] = [];
|
|
30
|
-
await deleteLocalBranch({
|
|
31
|
-
projectPath: '/workspace/repo',
|
|
32
|
-
branch: 'feature/unmerged',
|
|
33
|
-
force: true,
|
|
34
|
-
runCommand: async (_command, args) => {
|
|
35
|
-
commands.push(args);
|
|
36
|
-
return { stdout: args.includes('--show-current') ? 'main\n' : '', stderr: '' };
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
assert.deepEqual(commands, [
|
|
41
|
-
['branch', '--show-current'],
|
|
42
|
-
['branch', '-D', '--', 'feature/unmerged'],
|
|
43
|
-
]);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test('deleteLocalBranch refuses to delete the current branch even when forced', async () => {
|
|
47
|
-
await assert.rejects(
|
|
48
|
-
deleteLocalBranch({
|
|
49
|
-
projectPath: '/workspace/repo',
|
|
50
|
-
branch: 'feature/current',
|
|
51
|
-
force: true,
|
|
52
|
-
runCommand: async () => ({ stdout: 'feature/current\n', stderr: '' }),
|
|
53
|
-
}),
|
|
54
|
-
(error: unknown) => {
|
|
55
|
-
assert.equal((error as { code?: string }).code, 'GIT_CURRENT_BRANCH_DELETE');
|
|
56
|
-
assert.equal((error as { statusCode?: number }).statusCode, 400);
|
|
57
|
-
return true;
|
|
58
|
-
},
|
|
59
|
-
);
|
|
60
|
-
});
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
|
|
4
|
+
import { deleteLocalBranch } from '../git-branch.service.js';
|
|
5
|
+
|
|
6
|
+
test('deleteLocalBranch uses safe deletion by default', async () => {
|
|
7
|
+
const commands: string[][] = [];
|
|
8
|
+
const output = await deleteLocalBranch({
|
|
9
|
+
projectPath: '/workspace/repo',
|
|
10
|
+
branch: 'feature/safe-delete',
|
|
11
|
+
force: false,
|
|
12
|
+
runCommand: async (_command, args) => {
|
|
13
|
+
commands.push(args);
|
|
14
|
+
return {
|
|
15
|
+
stdout: args.includes('--show-current') ? 'main\n' : 'Deleted branch feature/safe-delete.\n',
|
|
16
|
+
stderr: '',
|
|
17
|
+
};
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
assert.equal(output, 'Deleted branch feature/safe-delete.\n');
|
|
22
|
+
assert.deepEqual(commands, [
|
|
23
|
+
['branch', '--show-current'],
|
|
24
|
+
['branch', '-d', '--', 'feature/safe-delete'],
|
|
25
|
+
]);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('deleteLocalBranch uses force deletion only when requested', async () => {
|
|
29
|
+
const commands: string[][] = [];
|
|
30
|
+
await deleteLocalBranch({
|
|
31
|
+
projectPath: '/workspace/repo',
|
|
32
|
+
branch: 'feature/unmerged',
|
|
33
|
+
force: true,
|
|
34
|
+
runCommand: async (_command, args) => {
|
|
35
|
+
commands.push(args);
|
|
36
|
+
return { stdout: args.includes('--show-current') ? 'main\n' : '', stderr: '' };
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
assert.deepEqual(commands, [
|
|
41
|
+
['branch', '--show-current'],
|
|
42
|
+
['branch', '-D', '--', 'feature/unmerged'],
|
|
43
|
+
]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('deleteLocalBranch refuses to delete the current branch even when forced', async () => {
|
|
47
|
+
await assert.rejects(
|
|
48
|
+
deleteLocalBranch({
|
|
49
|
+
projectPath: '/workspace/repo',
|
|
50
|
+
branch: 'feature/current',
|
|
51
|
+
force: true,
|
|
52
|
+
runCommand: async () => ({ stdout: 'feature/current\n', stderr: '' }),
|
|
53
|
+
}),
|
|
54
|
+
(error: unknown) => {
|
|
55
|
+
assert.equal((error as { code?: string }).code, 'GIT_CURRENT_BRANCH_DELETE');
|
|
56
|
+
assert.equal((error as { statusCode?: number }).statusCode, 400);
|
|
57
|
+
return true;
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { EventEmitter, once } from 'node:events';
|
|
3
|
-
import type { AddressInfo } from 'node:net';
|
|
4
|
-
import { PassThrough } from 'node:stream';
|
|
5
|
-
import test from 'node:test';
|
|
6
|
-
|
|
7
|
-
import express from 'express';
|
|
8
|
-
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { EventEmitter, once } from 'node:events';
|
|
3
|
+
import type { AddressInfo } from 'node:net';
|
|
4
|
+
import { PassThrough } from 'node:stream';
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
|
|
7
|
+
import express from 'express';
|
|
8
|
+
|
|
9
9
|
import { createGitRouter } from '@/modules/git/git.routes.js';
|
|
10
10
|
|
|
11
11
|
test('git status hides every spawned Git console window', async () => {
|
|
@@ -53,127 +53,127 @@ test('git status hides every spawned Git console window', async () => {
|
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
test('git init does not run when repository validation fails for an execution error', async () => {
|
|
56
|
-
const commands: string[][] = [];
|
|
57
|
-
const spawnProcess = ((_command: string, args: string[]) => {
|
|
58
|
-
commands.push(args);
|
|
59
|
-
const child = new EventEmitter() as EventEmitter & { stdout: PassThrough; stderr: PassThrough };
|
|
60
|
-
child.stdout = new PassThrough();
|
|
61
|
-
child.stderr = new PassThrough();
|
|
62
|
-
process.nextTick(() => child.emit('error', Object.assign(new Error('permission denied'), {
|
|
63
|
-
code: 'EACCES',
|
|
64
|
-
})));
|
|
65
|
-
return child;
|
|
66
|
-
}) as Parameters<typeof createGitRouter>[0]['spawnProcess'];
|
|
67
|
-
const unexpectedProvider = async (): Promise<never> => { throw new Error('unexpected provider call'); };
|
|
68
|
-
const router = createGitRouter({
|
|
69
|
-
fileSystem: { access: async () => undefined } as unknown as Parameters<typeof createGitRouter>[0]['fileSystem'],
|
|
70
|
-
spawnProcess,
|
|
71
|
-
resolveProjectPathById: () => '/workspace/repo',
|
|
72
|
-
queryClaude: unexpectedProvider,
|
|
73
|
-
queryCursor: unexpectedProvider,
|
|
74
|
-
});
|
|
75
|
-
const app = express();
|
|
76
|
-
app.use(express.json());
|
|
77
|
-
app.use('/api/git', router);
|
|
78
|
-
const server = app.listen(0, '127.0.0.1');
|
|
79
|
-
await once(server, 'listening');
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
const address = server.address() as AddressInfo;
|
|
83
|
-
const response = await fetch(`http://127.0.0.1:${address.port}/api/git/init`, {
|
|
84
|
-
method: 'POST',
|
|
85
|
-
headers: { 'content-type': 'application/json' },
|
|
86
|
-
body: JSON.stringify({ project: 'project-1' }),
|
|
87
|
-
});
|
|
88
|
-
const body = await response.json() as { success: boolean; error: string };
|
|
89
|
-
assert.equal(body.success, false);
|
|
90
|
-
assert.match(body.error, /permission denied/);
|
|
91
|
-
} finally {
|
|
92
|
-
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
assert.deepEqual(commands, [['rev-parse', '--is-inside-work-tree']]);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
test('delete branch parses force and uses Git force deletion', async () => {
|
|
99
|
-
const commands: string[][] = [];
|
|
100
|
-
const spawnProcess = ((_command: string, args: string[]) => {
|
|
101
|
-
commands.push(args);
|
|
102
|
-
const child = new EventEmitter() as EventEmitter & { stdout: PassThrough; stderr: PassThrough };
|
|
103
|
-
child.stdout = new PassThrough();
|
|
104
|
-
child.stderr = new PassThrough();
|
|
105
|
-
process.nextTick(() => {
|
|
106
|
-
if (args.includes('--is-inside-work-tree')) child.stdout.write('true\n');
|
|
107
|
-
if (args.includes('--show-toplevel')) child.stdout.write('/workspace/repo\n');
|
|
108
|
-
if (args.includes('--show-current')) child.stdout.write('main\n');
|
|
109
|
-
if (args.includes('-D')) child.stdout.write('Deleted branch feature/unmerged.\n');
|
|
110
|
-
child.stdout.end();
|
|
111
|
-
child.stderr.end();
|
|
112
|
-
child.emit('close', 0);
|
|
113
|
-
});
|
|
114
|
-
return child;
|
|
115
|
-
}) as Parameters<typeof createGitRouter>[0]['spawnProcess'];
|
|
116
|
-
const unexpectedProvider = async (): Promise<never> => { throw new Error('unexpected provider call'); };
|
|
117
|
-
const router = createGitRouter({
|
|
118
|
-
fileSystem: { access: async () => undefined } as unknown as Parameters<typeof createGitRouter>[0]['fileSystem'],
|
|
119
|
-
spawnProcess,
|
|
120
|
-
resolveProjectPathById: () => '/workspace/repo',
|
|
121
|
-
queryClaude: unexpectedProvider,
|
|
122
|
-
queryCursor: unexpectedProvider,
|
|
123
|
-
});
|
|
124
|
-
const app = express();
|
|
125
|
-
app.use(express.json());
|
|
126
|
-
app.use('/api/git', router);
|
|
127
|
-
const server = app.listen(0, '127.0.0.1');
|
|
128
|
-
await once(server, 'listening');
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
const address = server.address() as AddressInfo;
|
|
132
|
-
const response = await fetch(`http://127.0.0.1:${address.port}/api/git/delete-branch`, {
|
|
133
|
-
method: 'POST',
|
|
134
|
-
headers: { 'content-type': 'application/json' },
|
|
135
|
-
body: JSON.stringify({ project: 'project-1', branch: 'feature/unmerged', force: true }),
|
|
136
|
-
});
|
|
137
|
-
const body = await response.json() as { success: boolean; output: string };
|
|
138
|
-
assert.equal(response.status, 200);
|
|
139
|
-
assert.equal(body.success, true);
|
|
140
|
-
assert.match(body.output, /Deleted branch/);
|
|
141
|
-
} finally {
|
|
142
|
-
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
assert.deepEqual(commands.at(-1), ['branch', '-D', '--', 'feature/unmerged']);
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
test('delete branch rejects a non-boolean force value before running Git', async () => {
|
|
149
|
-
const spawnProcess = (() => {
|
|
150
|
-
throw new Error('Git must not run for invalid input');
|
|
151
|
-
}) as Parameters<typeof createGitRouter>[0]['spawnProcess'];
|
|
152
|
-
const unexpectedProvider = async (): Promise<never> => { throw new Error('unexpected provider call'); };
|
|
153
|
-
const router = createGitRouter({
|
|
154
|
-
fileSystem: { access: async () => undefined } as unknown as Parameters<typeof createGitRouter>[0]['fileSystem'],
|
|
155
|
-
spawnProcess,
|
|
156
|
-
resolveProjectPathById: () => '/workspace/repo',
|
|
157
|
-
queryClaude: unexpectedProvider,
|
|
158
|
-
queryCursor: unexpectedProvider,
|
|
159
|
-
});
|
|
160
|
-
const app = express();
|
|
161
|
-
app.use(express.json());
|
|
162
|
-
app.use('/api/git', router);
|
|
163
|
-
const server = app.listen(0, '127.0.0.1');
|
|
164
|
-
await once(server, 'listening');
|
|
165
|
-
|
|
166
|
-
try {
|
|
167
|
-
const address = server.address() as AddressInfo;
|
|
168
|
-
const response = await fetch(`http://127.0.0.1:${address.port}/api/git/delete-branch`, {
|
|
169
|
-
method: 'POST',
|
|
170
|
-
headers: { 'content-type': 'application/json' },
|
|
171
|
-
body: JSON.stringify({ project: 'project-1', branch: 'feature/unmerged', force: 'yes' }),
|
|
172
|
-
});
|
|
173
|
-
const body = await response.json() as { error: string };
|
|
174
|
-
assert.equal(response.status, 400);
|
|
175
|
-
assert.equal(body.error, 'force must be a boolean');
|
|
176
|
-
} finally {
|
|
177
|
-
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
178
|
-
}
|
|
179
|
-
});
|
|
56
|
+
const commands: string[][] = [];
|
|
57
|
+
const spawnProcess = ((_command: string, args: string[]) => {
|
|
58
|
+
commands.push(args);
|
|
59
|
+
const child = new EventEmitter() as EventEmitter & { stdout: PassThrough; stderr: PassThrough };
|
|
60
|
+
child.stdout = new PassThrough();
|
|
61
|
+
child.stderr = new PassThrough();
|
|
62
|
+
process.nextTick(() => child.emit('error', Object.assign(new Error('permission denied'), {
|
|
63
|
+
code: 'EACCES',
|
|
64
|
+
})));
|
|
65
|
+
return child;
|
|
66
|
+
}) as Parameters<typeof createGitRouter>[0]['spawnProcess'];
|
|
67
|
+
const unexpectedProvider = async (): Promise<never> => { throw new Error('unexpected provider call'); };
|
|
68
|
+
const router = createGitRouter({
|
|
69
|
+
fileSystem: { access: async () => undefined } as unknown as Parameters<typeof createGitRouter>[0]['fileSystem'],
|
|
70
|
+
spawnProcess,
|
|
71
|
+
resolveProjectPathById: () => '/workspace/repo',
|
|
72
|
+
queryClaude: unexpectedProvider,
|
|
73
|
+
queryCursor: unexpectedProvider,
|
|
74
|
+
});
|
|
75
|
+
const app = express();
|
|
76
|
+
app.use(express.json());
|
|
77
|
+
app.use('/api/git', router);
|
|
78
|
+
const server = app.listen(0, '127.0.0.1');
|
|
79
|
+
await once(server, 'listening');
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
const address = server.address() as AddressInfo;
|
|
83
|
+
const response = await fetch(`http://127.0.0.1:${address.port}/api/git/init`, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
headers: { 'content-type': 'application/json' },
|
|
86
|
+
body: JSON.stringify({ project: 'project-1' }),
|
|
87
|
+
});
|
|
88
|
+
const body = await response.json() as { success: boolean; error: string };
|
|
89
|
+
assert.equal(body.success, false);
|
|
90
|
+
assert.match(body.error, /permission denied/);
|
|
91
|
+
} finally {
|
|
92
|
+
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
assert.deepEqual(commands, [['rev-parse', '--is-inside-work-tree']]);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test('delete branch parses force and uses Git force deletion', async () => {
|
|
99
|
+
const commands: string[][] = [];
|
|
100
|
+
const spawnProcess = ((_command: string, args: string[]) => {
|
|
101
|
+
commands.push(args);
|
|
102
|
+
const child = new EventEmitter() as EventEmitter & { stdout: PassThrough; stderr: PassThrough };
|
|
103
|
+
child.stdout = new PassThrough();
|
|
104
|
+
child.stderr = new PassThrough();
|
|
105
|
+
process.nextTick(() => {
|
|
106
|
+
if (args.includes('--is-inside-work-tree')) child.stdout.write('true\n');
|
|
107
|
+
if (args.includes('--show-toplevel')) child.stdout.write('/workspace/repo\n');
|
|
108
|
+
if (args.includes('--show-current')) child.stdout.write('main\n');
|
|
109
|
+
if (args.includes('-D')) child.stdout.write('Deleted branch feature/unmerged.\n');
|
|
110
|
+
child.stdout.end();
|
|
111
|
+
child.stderr.end();
|
|
112
|
+
child.emit('close', 0);
|
|
113
|
+
});
|
|
114
|
+
return child;
|
|
115
|
+
}) as Parameters<typeof createGitRouter>[0]['spawnProcess'];
|
|
116
|
+
const unexpectedProvider = async (): Promise<never> => { throw new Error('unexpected provider call'); };
|
|
117
|
+
const router = createGitRouter({
|
|
118
|
+
fileSystem: { access: async () => undefined } as unknown as Parameters<typeof createGitRouter>[0]['fileSystem'],
|
|
119
|
+
spawnProcess,
|
|
120
|
+
resolveProjectPathById: () => '/workspace/repo',
|
|
121
|
+
queryClaude: unexpectedProvider,
|
|
122
|
+
queryCursor: unexpectedProvider,
|
|
123
|
+
});
|
|
124
|
+
const app = express();
|
|
125
|
+
app.use(express.json());
|
|
126
|
+
app.use('/api/git', router);
|
|
127
|
+
const server = app.listen(0, '127.0.0.1');
|
|
128
|
+
await once(server, 'listening');
|
|
129
|
+
|
|
130
|
+
try {
|
|
131
|
+
const address = server.address() as AddressInfo;
|
|
132
|
+
const response = await fetch(`http://127.0.0.1:${address.port}/api/git/delete-branch`, {
|
|
133
|
+
method: 'POST',
|
|
134
|
+
headers: { 'content-type': 'application/json' },
|
|
135
|
+
body: JSON.stringify({ project: 'project-1', branch: 'feature/unmerged', force: true }),
|
|
136
|
+
});
|
|
137
|
+
const body = await response.json() as { success: boolean; output: string };
|
|
138
|
+
assert.equal(response.status, 200);
|
|
139
|
+
assert.equal(body.success, true);
|
|
140
|
+
assert.match(body.output, /Deleted branch/);
|
|
141
|
+
} finally {
|
|
142
|
+
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
assert.deepEqual(commands.at(-1), ['branch', '-D', '--', 'feature/unmerged']);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('delete branch rejects a non-boolean force value before running Git', async () => {
|
|
149
|
+
const spawnProcess = (() => {
|
|
150
|
+
throw new Error('Git must not run for invalid input');
|
|
151
|
+
}) as Parameters<typeof createGitRouter>[0]['spawnProcess'];
|
|
152
|
+
const unexpectedProvider = async (): Promise<never> => { throw new Error('unexpected provider call'); };
|
|
153
|
+
const router = createGitRouter({
|
|
154
|
+
fileSystem: { access: async () => undefined } as unknown as Parameters<typeof createGitRouter>[0]['fileSystem'],
|
|
155
|
+
spawnProcess,
|
|
156
|
+
resolveProjectPathById: () => '/workspace/repo',
|
|
157
|
+
queryClaude: unexpectedProvider,
|
|
158
|
+
queryCursor: unexpectedProvider,
|
|
159
|
+
});
|
|
160
|
+
const app = express();
|
|
161
|
+
app.use(express.json());
|
|
162
|
+
app.use('/api/git', router);
|
|
163
|
+
const server = app.listen(0, '127.0.0.1');
|
|
164
|
+
await once(server, 'listening');
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const address = server.address() as AddressInfo;
|
|
168
|
+
const response = await fetch(`http://127.0.0.1:${address.port}/api/git/delete-branch`, {
|
|
169
|
+
method: 'POST',
|
|
170
|
+
headers: { 'content-type': 'application/json' },
|
|
171
|
+
body: JSON.stringify({ project: 'project-1', branch: 'feature/unmerged', force: 'yes' }),
|
|
172
|
+
});
|
|
173
|
+
const body = await response.json() as { error: string };
|
|
174
|
+
assert.equal(response.status, 400);
|
|
175
|
+
assert.equal(body.error, 'force must be a boolean');
|
|
176
|
+
} finally {
|
|
177
|
+
await new Promise<void>((resolve) => server.close(() => resolve()));
|
|
178
|
+
}
|
|
179
|
+
});
|
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import test from 'node:test';
|
|
3
|
-
|
|
4
|
-
import { parseGitLogWithStats, parseGitStatusOutput } from '../git-parsing.service.js';
|
|
5
|
-
|
|
6
|
-
// Builds `git status --porcelain=v1 -z` output: NUL-separated entries with a
|
|
7
|
-
// trailing NUL, exactly as git emits it.
|
|
8
|
-
const porcelain = (...entries: string[]) => entries.join('\0') + '\0';
|
|
9
|
-
|
|
10
|
-
test('parseGitStatusOutput buckets files and reports index-side staging', () => {
|
|
11
|
-
const output = porcelain(
|
|
12
|
-
'M staged-modified.ts',
|
|
13
|
-
' M unstaged-modified.ts',
|
|
14
|
-
'MM staged-and-unstaged.ts',
|
|
15
|
-
'A staged-new.ts',
|
|
16
|
-
'D staged-deleted.ts',
|
|
17
|
-
' D unstaged-deleted.ts',
|
|
18
|
-
'?? untracked.ts',
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
const result = parseGitStatusOutput(output);
|
|
22
|
-
|
|
23
|
-
assert.deepEqual(result.modified, ['staged-modified.ts', 'unstaged-modified.ts', 'staged-and-unstaged.ts']);
|
|
24
|
-
assert.deepEqual(result.added, ['staged-new.ts']);
|
|
25
|
-
assert.deepEqual(result.deleted, ['staged-deleted.ts', 'unstaged-deleted.ts']);
|
|
26
|
-
assert.deepEqual(result.untracked, ['untracked.ts']);
|
|
27
|
-
// Only index-side (X) changes count as staged.
|
|
28
|
-
assert.deepEqual(result.staged, [
|
|
29
|
-
'staged-modified.ts',
|
|
30
|
-
'staged-and-unstaged.ts',
|
|
31
|
-
'staged-new.ts',
|
|
32
|
-
'staged-deleted.ts',
|
|
33
|
-
]);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test('parseGitStatusOutput keeps paths with spaces intact (-z output has no quoting)', () => {
|
|
37
|
-
const result = parseGitStatusOutput(porcelain('M src/my folder/some file.ts'));
|
|
38
|
-
assert.deepEqual(result.modified, ['src/my folder/some file.ts']);
|
|
39
|
-
assert.deepEqual(result.staged, ['src/my folder/some file.ts']);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('parseGitStatusOutput tracks the post-rename path and skips the original', () => {
|
|
43
|
-
const output = porcelain('R renamed-to.ts', 'renamed-from.ts', ' M other.ts');
|
|
44
|
-
const result = parseGitStatusOutput(output);
|
|
45
|
-
|
|
46
|
-
assert.deepEqual(result.modified, ['renamed-to.ts', 'other.ts']);
|
|
47
|
-
assert.deepEqual(result.staged, ['renamed-to.ts']);
|
|
48
|
-
// The pre-rename path is metadata, not a change entry.
|
|
49
|
-
assert.equal(JSON.stringify(result).includes('renamed-from.ts'), false);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('parseGitStatusOutput never reports merge conflicts as staged', () => {
|
|
53
|
-
const output = porcelain('UU conflicted.ts', 'AA both-added.ts', 'DD both-deleted.ts');
|
|
54
|
-
const result = parseGitStatusOutput(output);
|
|
55
|
-
|
|
56
|
-
assert.deepEqual(result.modified, ['conflicted.ts', 'both-added.ts', 'both-deleted.ts']);
|
|
57
|
-
assert.deepEqual(result.staged, []);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
test('parseGitStatusOutput handles empty output', () => {
|
|
61
|
-
assert.deepEqual(parseGitStatusOutput(''), {
|
|
62
|
-
modified: [],
|
|
63
|
-
added: [],
|
|
64
|
-
deleted: [],
|
|
65
|
-
untracked: [],
|
|
66
|
-
staged: [],
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
// Builds one `git log --pretty=format:%H%x1f%P%x1f%D%x1f%an%x1f%ae%x1f%ad%x1f%s` line.
|
|
71
|
-
const US = '';
|
|
72
|
-
const logLine = (hash: string, parents: string, refs: string, subject: string) =>
|
|
73
|
-
[hash, parents, refs, 'Alice', 'a@x.com', '2026-07-06T10:00:00+03:00', subject].join(US);
|
|
74
|
-
|
|
75
|
-
test('parseGitLogWithStats parses commits with parents, refs, and shortstat lines', () => {
|
|
76
|
-
const output = [
|
|
77
|
-
logLine('c3', 'c2', 'HEAD -> main, origin/main, tag: v1.0', 'feat: add | pipes | to subject'),
|
|
78
|
-
' 3 files changed, 10 insertions(+), 2 deletions(-)',
|
|
79
|
-
'',
|
|
80
|
-
logLine('c2', 'c1 c0', '', 'Merge branch feature'),
|
|
81
|
-
'',
|
|
82
|
-
logLine('c0', '', '', 'initial commit'),
|
|
83
|
-
' 1 file changed, 1 insertion(+)',
|
|
84
|
-
].join('\n');
|
|
85
|
-
|
|
86
|
-
const commits = parseGitLogWithStats(output);
|
|
87
|
-
|
|
88
|
-
assert.equal(commits.length, 3);
|
|
89
|
-
assert.deepEqual(commits[0].parents, ['c2']);
|
|
90
|
-
assert.deepEqual(commits[0].refs, ['HEAD -> main', 'origin/main', 'tag: v1.0']);
|
|
91
|
-
// Pipes in the subject survive because fields are joined with .
|
|
92
|
-
assert.equal(commits[0].message, 'feat: add | pipes | to subject');
|
|
93
|
-
assert.equal(commits[0].stats, '3 files changed, 10 insertions(+), 2 deletions(-)');
|
|
94
|
-
|
|
95
|
-
// Merge commit: two parents, no shortstat line.
|
|
96
|
-
assert.deepEqual(commits[1].parents, ['c1', 'c0']);
|
|
97
|
-
assert.equal(commits[1].stats, '');
|
|
98
|
-
|
|
99
|
-
// Root commit: no parents.
|
|
100
|
-
assert.deepEqual(commits[2].parents, []);
|
|
101
|
-
assert.equal(commits[2].stats, '1 file changed, 1 insertion(+)');
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test('parseGitLogWithStats handles empty output', () => {
|
|
105
|
-
assert.deepEqual(parseGitLogWithStats(''), []);
|
|
106
|
-
});
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
|
|
4
|
+
import { parseGitLogWithStats, parseGitStatusOutput } from '../git-parsing.service.js';
|
|
5
|
+
|
|
6
|
+
// Builds `git status --porcelain=v1 -z` output: NUL-separated entries with a
|
|
7
|
+
// trailing NUL, exactly as git emits it.
|
|
8
|
+
const porcelain = (...entries: string[]) => entries.join('\0') + '\0';
|
|
9
|
+
|
|
10
|
+
test('parseGitStatusOutput buckets files and reports index-side staging', () => {
|
|
11
|
+
const output = porcelain(
|
|
12
|
+
'M staged-modified.ts',
|
|
13
|
+
' M unstaged-modified.ts',
|
|
14
|
+
'MM staged-and-unstaged.ts',
|
|
15
|
+
'A staged-new.ts',
|
|
16
|
+
'D staged-deleted.ts',
|
|
17
|
+
' D unstaged-deleted.ts',
|
|
18
|
+
'?? untracked.ts',
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const result = parseGitStatusOutput(output);
|
|
22
|
+
|
|
23
|
+
assert.deepEqual(result.modified, ['staged-modified.ts', 'unstaged-modified.ts', 'staged-and-unstaged.ts']);
|
|
24
|
+
assert.deepEqual(result.added, ['staged-new.ts']);
|
|
25
|
+
assert.deepEqual(result.deleted, ['staged-deleted.ts', 'unstaged-deleted.ts']);
|
|
26
|
+
assert.deepEqual(result.untracked, ['untracked.ts']);
|
|
27
|
+
// Only index-side (X) changes count as staged.
|
|
28
|
+
assert.deepEqual(result.staged, [
|
|
29
|
+
'staged-modified.ts',
|
|
30
|
+
'staged-and-unstaged.ts',
|
|
31
|
+
'staged-new.ts',
|
|
32
|
+
'staged-deleted.ts',
|
|
33
|
+
]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('parseGitStatusOutput keeps paths with spaces intact (-z output has no quoting)', () => {
|
|
37
|
+
const result = parseGitStatusOutput(porcelain('M src/my folder/some file.ts'));
|
|
38
|
+
assert.deepEqual(result.modified, ['src/my folder/some file.ts']);
|
|
39
|
+
assert.deepEqual(result.staged, ['src/my folder/some file.ts']);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('parseGitStatusOutput tracks the post-rename path and skips the original', () => {
|
|
43
|
+
const output = porcelain('R renamed-to.ts', 'renamed-from.ts', ' M other.ts');
|
|
44
|
+
const result = parseGitStatusOutput(output);
|
|
45
|
+
|
|
46
|
+
assert.deepEqual(result.modified, ['renamed-to.ts', 'other.ts']);
|
|
47
|
+
assert.deepEqual(result.staged, ['renamed-to.ts']);
|
|
48
|
+
// The pre-rename path is metadata, not a change entry.
|
|
49
|
+
assert.equal(JSON.stringify(result).includes('renamed-from.ts'), false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test('parseGitStatusOutput never reports merge conflicts as staged', () => {
|
|
53
|
+
const output = porcelain('UU conflicted.ts', 'AA both-added.ts', 'DD both-deleted.ts');
|
|
54
|
+
const result = parseGitStatusOutput(output);
|
|
55
|
+
|
|
56
|
+
assert.deepEqual(result.modified, ['conflicted.ts', 'both-added.ts', 'both-deleted.ts']);
|
|
57
|
+
assert.deepEqual(result.staged, []);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('parseGitStatusOutput handles empty output', () => {
|
|
61
|
+
assert.deepEqual(parseGitStatusOutput(''), {
|
|
62
|
+
modified: [],
|
|
63
|
+
added: [],
|
|
64
|
+
deleted: [],
|
|
65
|
+
untracked: [],
|
|
66
|
+
staged: [],
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Builds one `git log --pretty=format:%H%x1f%P%x1f%D%x1f%an%x1f%ae%x1f%ad%x1f%s` line.
|
|
71
|
+
const US = '';
|
|
72
|
+
const logLine = (hash: string, parents: string, refs: string, subject: string) =>
|
|
73
|
+
[hash, parents, refs, 'Alice', 'a@x.com', '2026-07-06T10:00:00+03:00', subject].join(US);
|
|
74
|
+
|
|
75
|
+
test('parseGitLogWithStats parses commits with parents, refs, and shortstat lines', () => {
|
|
76
|
+
const output = [
|
|
77
|
+
logLine('c3', 'c2', 'HEAD -> main, origin/main, tag: v1.0', 'feat: add | pipes | to subject'),
|
|
78
|
+
' 3 files changed, 10 insertions(+), 2 deletions(-)',
|
|
79
|
+
'',
|
|
80
|
+
logLine('c2', 'c1 c0', '', 'Merge branch feature'),
|
|
81
|
+
'',
|
|
82
|
+
logLine('c0', '', '', 'initial commit'),
|
|
83
|
+
' 1 file changed, 1 insertion(+)',
|
|
84
|
+
].join('\n');
|
|
85
|
+
|
|
86
|
+
const commits = parseGitLogWithStats(output);
|
|
87
|
+
|
|
88
|
+
assert.equal(commits.length, 3);
|
|
89
|
+
assert.deepEqual(commits[0].parents, ['c2']);
|
|
90
|
+
assert.deepEqual(commits[0].refs, ['HEAD -> main', 'origin/main', 'tag: v1.0']);
|
|
91
|
+
// Pipes in the subject survive because fields are joined with .
|
|
92
|
+
assert.equal(commits[0].message, 'feat: add | pipes | to subject');
|
|
93
|
+
assert.equal(commits[0].stats, '3 files changed, 10 insertions(+), 2 deletions(-)');
|
|
94
|
+
|
|
95
|
+
// Merge commit: two parents, no shortstat line.
|
|
96
|
+
assert.deepEqual(commits[1].parents, ['c1', 'c0']);
|
|
97
|
+
assert.equal(commits[1].stats, '');
|
|
98
|
+
|
|
99
|
+
// Root commit: no parents.
|
|
100
|
+
assert.deepEqual(commits[2].parents, []);
|
|
101
|
+
assert.equal(commits[2].stats, '1 file changed, 1 insertion(+)');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('parseGitLogWithStats handles empty output', () => {
|
|
105
|
+
assert.deepEqual(parseGitLogWithStats(''), []);
|
|
106
|
+
});
|