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,90 +1,90 @@
|
|
|
1
|
-
import { promises as fs } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
import { projectsDb, sessionsDb } from '@/modules/database/index.js';
|
|
5
|
-
import { AppError } from '@/shared/utils.js';
|
|
6
|
-
|
|
7
|
-
function uniqueJsonlPathsFromSessions(
|
|
8
|
-
sessions: Array<{ jsonl_path: string | null }>,
|
|
9
|
-
): string[] {
|
|
10
|
-
const seen = new Set<string>();
|
|
11
|
-
const result: string[] = [];
|
|
12
|
-
|
|
13
|
-
for (const row of sessions) {
|
|
14
|
-
const raw = row.jsonl_path?.trim();
|
|
15
|
-
if (!raw) {
|
|
16
|
-
continue;
|
|
17
|
-
}
|
|
18
|
-
const absolute = path.isAbsolute(raw) ? path.normalize(raw) : path.resolve(raw);
|
|
19
|
-
if (seen.has(absolute)) {
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
seen.add(absolute);
|
|
23
|
-
result.push(absolute);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return result;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function unlinkJsonlIfExists(filePath: string): Promise<void> {
|
|
30
|
-
try {
|
|
31
|
-
await fs.unlink(filePath);
|
|
32
|
-
} catch (error) {
|
|
33
|
-
const code = (error as NodeJS.ErrnoException).code;
|
|
34
|
-
if (code === 'ENOENT') {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
console.warn(`[project-delete] Failed to remove ${filePath}:`, (error as Error).message);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Loads all session rows for the project path and removes each distinct `jsonl_path` file on disk.
|
|
43
|
-
*/
|
|
44
|
-
export async function deleteSessionJsonlFilesForProjectPath(projectPath: string): Promise<void> {
|
|
45
|
-
const sessions = sessionsDb.getSessionsByProjectPathIncludingArchived(projectPath);
|
|
46
|
-
const paths = uniqueJsonlPathsFromSessions(sessions);
|
|
47
|
-
|
|
48
|
-
for (const filePath of paths) {
|
|
49
|
-
await unlinkJsonlIfExists(filePath);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* - **Soft delete** (`force` false): set `isArchived` on the `projects` row (hide from the active list; DB only).
|
|
55
|
-
* - **Force** (`force` true): for each session row for that `project_path`, delete the file at `jsonl_path`
|
|
56
|
-
* (when set), then remove session rows and the `projects` row.
|
|
57
|
-
*/
|
|
58
|
-
export async function deleteOrArchiveProject(projectId: string, force: boolean): Promise<void> {
|
|
59
|
-
const row = projectsDb.getProjectById(projectId);
|
|
60
|
-
if (!row) {
|
|
61
|
-
throw new AppError(`Unknown projectId: ${projectId}`, {
|
|
62
|
-
code: 'PROJECT_NOT_FOUND',
|
|
63
|
-
statusCode: 404,
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (!force) {
|
|
68
|
-
projectsDb.updateProjectIsArchivedById(projectId, true);
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
await deleteSessionJsonlFilesForProjectPath(row.project_path);
|
|
73
|
-
sessionsDb.deleteSessionsByProjectPath(row.project_path);
|
|
74
|
-
projectsDb.deleteProjectById(projectId);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Restores one archived project row back into the active project list.
|
|
79
|
-
*/
|
|
80
|
-
export function restoreArchivedProject(projectId: string): void {
|
|
81
|
-
const row = projectsDb.getProjectById(projectId);
|
|
82
|
-
if (!row) {
|
|
83
|
-
throw new AppError(`Unknown projectId: ${projectId}`, {
|
|
84
|
-
code: 'PROJECT_NOT_FOUND',
|
|
85
|
-
statusCode: 404,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
projectsDb.updateProjectIsArchivedById(projectId, false);
|
|
90
|
-
}
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { projectsDb, sessionsDb } from '@/modules/database/index.js';
|
|
5
|
+
import { AppError } from '@/shared/utils.js';
|
|
6
|
+
|
|
7
|
+
function uniqueJsonlPathsFromSessions(
|
|
8
|
+
sessions: Array<{ jsonl_path: string | null }>,
|
|
9
|
+
): string[] {
|
|
10
|
+
const seen = new Set<string>();
|
|
11
|
+
const result: string[] = [];
|
|
12
|
+
|
|
13
|
+
for (const row of sessions) {
|
|
14
|
+
const raw = row.jsonl_path?.trim();
|
|
15
|
+
if (!raw) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
const absolute = path.isAbsolute(raw) ? path.normalize(raw) : path.resolve(raw);
|
|
19
|
+
if (seen.has(absolute)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
seen.add(absolute);
|
|
23
|
+
result.push(absolute);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function unlinkJsonlIfExists(filePath: string): Promise<void> {
|
|
30
|
+
try {
|
|
31
|
+
await fs.unlink(filePath);
|
|
32
|
+
} catch (error) {
|
|
33
|
+
const code = (error as NodeJS.ErrnoException).code;
|
|
34
|
+
if (code === 'ENOENT') {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
console.warn(`[project-delete] Failed to remove ${filePath}:`, (error as Error).message);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Loads all session rows for the project path and removes each distinct `jsonl_path` file on disk.
|
|
43
|
+
*/
|
|
44
|
+
export async function deleteSessionJsonlFilesForProjectPath(projectPath: string): Promise<void> {
|
|
45
|
+
const sessions = sessionsDb.getSessionsByProjectPathIncludingArchived(projectPath);
|
|
46
|
+
const paths = uniqueJsonlPathsFromSessions(sessions);
|
|
47
|
+
|
|
48
|
+
for (const filePath of paths) {
|
|
49
|
+
await unlinkJsonlIfExists(filePath);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* - **Soft delete** (`force` false): set `isArchived` on the `projects` row (hide from the active list; DB only).
|
|
55
|
+
* - **Force** (`force` true): for each session row for that `project_path`, delete the file at `jsonl_path`
|
|
56
|
+
* (when set), then remove session rows and the `projects` row.
|
|
57
|
+
*/
|
|
58
|
+
export async function deleteOrArchiveProject(projectId: string, force: boolean): Promise<void> {
|
|
59
|
+
const row = projectsDb.getProjectById(projectId);
|
|
60
|
+
if (!row) {
|
|
61
|
+
throw new AppError(`Unknown projectId: ${projectId}`, {
|
|
62
|
+
code: 'PROJECT_NOT_FOUND',
|
|
63
|
+
statusCode: 404,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!force) {
|
|
68
|
+
projectsDb.updateProjectIsArchivedById(projectId, true);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
await deleteSessionJsonlFilesForProjectPath(row.project_path);
|
|
73
|
+
sessionsDb.deleteSessionsByProjectPath(row.project_path);
|
|
74
|
+
projectsDb.deleteProjectById(projectId);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Restores one archived project row back into the active project list.
|
|
79
|
+
*/
|
|
80
|
+
export function restoreArchivedProject(projectId: string): void {
|
|
81
|
+
const row = projectsDb.getProjectById(projectId);
|
|
82
|
+
if (!row) {
|
|
83
|
+
throw new AppError(`Unknown projectId: ${projectId}`, {
|
|
84
|
+
code: 'PROJECT_NOT_FOUND',
|
|
85
|
+
statusCode: 404,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
projectsDb.updateProjectIsArchivedById(projectId, false);
|
|
90
|
+
}
|
|
@@ -1,144 +1,144 @@
|
|
|
1
|
-
import fs from 'node:fs/promises';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
|
|
4
|
-
import { projectsDb } from '@/modules/database/index.js';
|
|
5
|
-
import type {
|
|
6
|
-
CreateProjectPathResult,
|
|
7
|
-
ProjectRepositoryRow,
|
|
8
|
-
WorkspacePathValidationResult,
|
|
9
|
-
} from '@/shared/types.js';
|
|
10
|
-
import { AppError, normalizeProjectPath, validateWorkspacePath } from '@/shared/utils.js';
|
|
11
|
-
|
|
12
|
-
type CreateProjectInput = {
|
|
13
|
-
projectPath: string;
|
|
14
|
-
customName?: string | null;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type CreateProjectDependencies = {
|
|
18
|
-
validatePath: (projectPath: string) => Promise<WorkspacePathValidationResult>;
|
|
19
|
-
ensureWorkspaceDirectory: (projectPath: string) => Promise<void>;
|
|
20
|
-
persistProjectPath: (projectPath: string, customName: string | null) => CreateProjectPathResult;
|
|
21
|
-
getProjectByPath: (projectPath: string) => ProjectRepositoryRow | null;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
type ProjectApiView = {
|
|
25
|
-
projectId: string;
|
|
26
|
-
path: string;
|
|
27
|
-
fullPath: string;
|
|
28
|
-
displayName: string;
|
|
29
|
-
customName: string | null;
|
|
30
|
-
isArchived: boolean;
|
|
31
|
-
isStarred: boolean;
|
|
32
|
-
sessions: [];
|
|
33
|
-
sessionMeta: {
|
|
34
|
-
hasMore: false;
|
|
35
|
-
total: 0;
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
type CreateProjectServiceResult = {
|
|
40
|
-
outcome: 'created' | 'reactivated_archived';
|
|
41
|
-
project: ProjectApiView;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const defaultDependencies: CreateProjectDependencies = {
|
|
45
|
-
validatePath: validateWorkspacePath,
|
|
46
|
-
ensureWorkspaceDirectory: async (projectPath: string): Promise<void> => {
|
|
47
|
-
await fs.mkdir(projectPath, { recursive: true });
|
|
48
|
-
const directoryStats = await fs.stat(projectPath);
|
|
49
|
-
if (!directoryStats.isDirectory()) {
|
|
50
|
-
throw new AppError('Path exists but is not a directory', {
|
|
51
|
-
code: 'PROJECT_PATH_NOT_DIRECTORY',
|
|
52
|
-
statusCode: 400,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
persistProjectPath: (projectPath: string, customName: string | null): CreateProjectPathResult =>
|
|
57
|
-
projectsDb.createProjectPath(projectPath, customName),
|
|
58
|
-
getProjectByPath: (projectPath: string): ProjectRepositoryRow | null =>
|
|
59
|
-
projectsDb.getProjectPath(projectPath),
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
function resolveDisplayName(customName: string | null | undefined, projectPath: string): string {
|
|
63
|
-
const trimmedCustomName = typeof customName === 'string' ? customName.trim() : '';
|
|
64
|
-
if (trimmedCustomName.length > 0) {
|
|
65
|
-
return trimmedCustomName;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
return path.basename(projectPath) || projectPath;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function mapProjectRowToApiView(projectRow: ProjectRepositoryRow): ProjectApiView {
|
|
72
|
-
return {
|
|
73
|
-
projectId: projectRow.project_id,
|
|
74
|
-
path: projectRow.project_path,
|
|
75
|
-
fullPath: projectRow.project_path,
|
|
76
|
-
displayName: resolveDisplayName(projectRow.custom_project_name, projectRow.project_path),
|
|
77
|
-
customName: projectRow.custom_project_name,
|
|
78
|
-
isArchived: Boolean(projectRow.isArchived),
|
|
79
|
-
isStarred: Boolean(projectRow.isStarred),
|
|
80
|
-
sessions: [],
|
|
81
|
-
sessionMeta: {
|
|
82
|
-
hasMore: false,
|
|
83
|
-
total: 0,
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export async function createProject(
|
|
89
|
-
input: CreateProjectInput,
|
|
90
|
-
dependencies: CreateProjectDependencies = defaultDependencies,
|
|
91
|
-
): Promise<CreateProjectServiceResult> {
|
|
92
|
-
const normalizedPath = normalizeProjectPath(input.projectPath || '');
|
|
93
|
-
if (!normalizedPath) {
|
|
94
|
-
throw new AppError('path is required', {
|
|
95
|
-
code: 'PROJECT_PATH_REQUIRED',
|
|
96
|
-
statusCode: 400,
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const pathValidation = await dependencies.validatePath(normalizedPath);
|
|
101
|
-
if (!pathValidation.valid || !pathValidation.resolvedPath) {
|
|
102
|
-
throw new AppError('Invalid project path', {
|
|
103
|
-
code: 'INVALID_PROJECT_PATH',
|
|
104
|
-
statusCode: 400,
|
|
105
|
-
details: pathValidation.error ?? 'Path validation failed',
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const resolvedProjectPath = normalizeProjectPath(pathValidation.resolvedPath);
|
|
110
|
-
await dependencies.ensureWorkspaceDirectory(resolvedProjectPath);
|
|
111
|
-
|
|
112
|
-
const normalizedCustomName = resolveDisplayName(input.customName ?? null, resolvedProjectPath);
|
|
113
|
-
const persistedProject = dependencies.persistProjectPath(resolvedProjectPath, normalizedCustomName);
|
|
114
|
-
|
|
115
|
-
if (persistedProject.outcome === 'active_conflict') {
|
|
116
|
-
throw new AppError('Project path already exists and is active', {
|
|
117
|
-
code: 'PROJECT_ALREADY_EXISTS',
|
|
118
|
-
statusCode: 409,
|
|
119
|
-
details: `Project path already exists: ${resolvedProjectPath}`,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const projectRow = persistedProject.project ?? dependencies.getProjectByPath(resolvedProjectPath);
|
|
124
|
-
if (!projectRow) {
|
|
125
|
-
throw new AppError('Failed to resolve project after creation', {
|
|
126
|
-
code: 'PROJECT_CREATE_FAILED',
|
|
127
|
-
statusCode: 500,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Archived rows intentionally remain archived when reused, as requested.
|
|
132
|
-
return {
|
|
133
|
-
outcome: persistedProject.outcome,
|
|
134
|
-
project: mapProjectRowToApiView(projectRow),
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Sets `projects.custom_project_name` for the given `projectId` (or clears it when empty).
|
|
140
|
-
*/
|
|
141
|
-
export function updateProjectDisplayName(projectId: string, newDisplayName: unknown): void {
|
|
142
|
-
const trimmed = typeof newDisplayName === 'string' ? newDisplayName.trim() : '';
|
|
143
|
-
projectsDb.updateCustomProjectNameById(projectId, trimmed.length > 0 ? trimmed : null);
|
|
144
|
-
}
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { projectsDb } from '@/modules/database/index.js';
|
|
5
|
+
import type {
|
|
6
|
+
CreateProjectPathResult,
|
|
7
|
+
ProjectRepositoryRow,
|
|
8
|
+
WorkspacePathValidationResult,
|
|
9
|
+
} from '@/shared/types.js';
|
|
10
|
+
import { AppError, normalizeProjectPath, validateWorkspacePath } from '@/shared/utils.js';
|
|
11
|
+
|
|
12
|
+
type CreateProjectInput = {
|
|
13
|
+
projectPath: string;
|
|
14
|
+
customName?: string | null;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type CreateProjectDependencies = {
|
|
18
|
+
validatePath: (projectPath: string) => Promise<WorkspacePathValidationResult>;
|
|
19
|
+
ensureWorkspaceDirectory: (projectPath: string) => Promise<void>;
|
|
20
|
+
persistProjectPath: (projectPath: string, customName: string | null) => CreateProjectPathResult;
|
|
21
|
+
getProjectByPath: (projectPath: string) => ProjectRepositoryRow | null;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type ProjectApiView = {
|
|
25
|
+
projectId: string;
|
|
26
|
+
path: string;
|
|
27
|
+
fullPath: string;
|
|
28
|
+
displayName: string;
|
|
29
|
+
customName: string | null;
|
|
30
|
+
isArchived: boolean;
|
|
31
|
+
isStarred: boolean;
|
|
32
|
+
sessions: [];
|
|
33
|
+
sessionMeta: {
|
|
34
|
+
hasMore: false;
|
|
35
|
+
total: 0;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
type CreateProjectServiceResult = {
|
|
40
|
+
outcome: 'created' | 'reactivated_archived';
|
|
41
|
+
project: ProjectApiView;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const defaultDependencies: CreateProjectDependencies = {
|
|
45
|
+
validatePath: validateWorkspacePath,
|
|
46
|
+
ensureWorkspaceDirectory: async (projectPath: string): Promise<void> => {
|
|
47
|
+
await fs.mkdir(projectPath, { recursive: true });
|
|
48
|
+
const directoryStats = await fs.stat(projectPath);
|
|
49
|
+
if (!directoryStats.isDirectory()) {
|
|
50
|
+
throw new AppError('Path exists but is not a directory', {
|
|
51
|
+
code: 'PROJECT_PATH_NOT_DIRECTORY',
|
|
52
|
+
statusCode: 400,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
persistProjectPath: (projectPath: string, customName: string | null): CreateProjectPathResult =>
|
|
57
|
+
projectsDb.createProjectPath(projectPath, customName),
|
|
58
|
+
getProjectByPath: (projectPath: string): ProjectRepositoryRow | null =>
|
|
59
|
+
projectsDb.getProjectPath(projectPath),
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function resolveDisplayName(customName: string | null | undefined, projectPath: string): string {
|
|
63
|
+
const trimmedCustomName = typeof customName === 'string' ? customName.trim() : '';
|
|
64
|
+
if (trimmedCustomName.length > 0) {
|
|
65
|
+
return trimmedCustomName;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return path.basename(projectPath) || projectPath;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function mapProjectRowToApiView(projectRow: ProjectRepositoryRow): ProjectApiView {
|
|
72
|
+
return {
|
|
73
|
+
projectId: projectRow.project_id,
|
|
74
|
+
path: projectRow.project_path,
|
|
75
|
+
fullPath: projectRow.project_path,
|
|
76
|
+
displayName: resolveDisplayName(projectRow.custom_project_name, projectRow.project_path),
|
|
77
|
+
customName: projectRow.custom_project_name,
|
|
78
|
+
isArchived: Boolean(projectRow.isArchived),
|
|
79
|
+
isStarred: Boolean(projectRow.isStarred),
|
|
80
|
+
sessions: [],
|
|
81
|
+
sessionMeta: {
|
|
82
|
+
hasMore: false,
|
|
83
|
+
total: 0,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function createProject(
|
|
89
|
+
input: CreateProjectInput,
|
|
90
|
+
dependencies: CreateProjectDependencies = defaultDependencies,
|
|
91
|
+
): Promise<CreateProjectServiceResult> {
|
|
92
|
+
const normalizedPath = normalizeProjectPath(input.projectPath || '');
|
|
93
|
+
if (!normalizedPath) {
|
|
94
|
+
throw new AppError('path is required', {
|
|
95
|
+
code: 'PROJECT_PATH_REQUIRED',
|
|
96
|
+
statusCode: 400,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const pathValidation = await dependencies.validatePath(normalizedPath);
|
|
101
|
+
if (!pathValidation.valid || !pathValidation.resolvedPath) {
|
|
102
|
+
throw new AppError('Invalid project path', {
|
|
103
|
+
code: 'INVALID_PROJECT_PATH',
|
|
104
|
+
statusCode: 400,
|
|
105
|
+
details: pathValidation.error ?? 'Path validation failed',
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const resolvedProjectPath = normalizeProjectPath(pathValidation.resolvedPath);
|
|
110
|
+
await dependencies.ensureWorkspaceDirectory(resolvedProjectPath);
|
|
111
|
+
|
|
112
|
+
const normalizedCustomName = resolveDisplayName(input.customName ?? null, resolvedProjectPath);
|
|
113
|
+
const persistedProject = dependencies.persistProjectPath(resolvedProjectPath, normalizedCustomName);
|
|
114
|
+
|
|
115
|
+
if (persistedProject.outcome === 'active_conflict') {
|
|
116
|
+
throw new AppError('Project path already exists and is active', {
|
|
117
|
+
code: 'PROJECT_ALREADY_EXISTS',
|
|
118
|
+
statusCode: 409,
|
|
119
|
+
details: `Project path already exists: ${resolvedProjectPath}`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const projectRow = persistedProject.project ?? dependencies.getProjectByPath(resolvedProjectPath);
|
|
124
|
+
if (!projectRow) {
|
|
125
|
+
throw new AppError('Failed to resolve project after creation', {
|
|
126
|
+
code: 'PROJECT_CREATE_FAILED',
|
|
127
|
+
statusCode: 500,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Archived rows intentionally remain archived when reused, as requested.
|
|
132
|
+
return {
|
|
133
|
+
outcome: persistedProject.outcome,
|
|
134
|
+
project: mapProjectRowToApiView(projectRow),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Sets `projects.custom_project_name` for the given `projectId` (or clears it when empty).
|
|
140
|
+
*/
|
|
141
|
+
export function updateProjectDisplayName(projectId: string, newDisplayName: unknown): void {
|
|
142
|
+
const trimmed = typeof newDisplayName === 'string' ? newDisplayName.trim() : '';
|
|
143
|
+
projectsDb.updateCustomProjectNameById(projectId, trimmed.length > 0 ? trimmed : null);
|
|
144
|
+
}
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
import { projectsDb } from '@/modules/database/index.js';
|
|
2
|
-
import { AppError } from '@/shared/utils.js';
|
|
3
|
-
|
|
4
|
-
type ToggleProjectStarResult = {
|
|
5
|
-
isStarred: boolean;
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
type ApplyLegacyStarredProjectIdsResult = {
|
|
9
|
-
updated: number;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
function normalizeProjectId(projectId: string): string {
|
|
13
|
-
return projectId.trim();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function uniqueProjectIds(projectIds: string[]): string[] {
|
|
17
|
-
const uniqueIds = new Set<string>();
|
|
18
|
-
for (const projectId of projectIds) {
|
|
19
|
-
const normalizedProjectId = normalizeProjectId(projectId);
|
|
20
|
-
if (!normalizedProjectId) {
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
uniqueIds.add(normalizedProjectId);
|
|
24
|
-
}
|
|
25
|
-
return [...uniqueIds];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Applies legacy `localStorage` stars keyed by DB `projectId` onto `projects.isStarred`.
|
|
30
|
-
*
|
|
31
|
-
* The operation is idempotent: already-starred projects are ignored, unknown ids are skipped.
|
|
32
|
-
*/
|
|
33
|
-
export function applyLegacyStarredProjectIds(projectIds: string[]): ApplyLegacyStarredProjectIdsResult {
|
|
34
|
-
const normalizedProjectIds = uniqueProjectIds(projectIds);
|
|
35
|
-
let updated = 0;
|
|
36
|
-
|
|
37
|
-
for (const projectId of normalizedProjectIds) {
|
|
38
|
-
const project = projectsDb.getProjectById(projectId);
|
|
39
|
-
if (!project) {
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (Boolean(project.isStarred)) {
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
projectsDb.updateProjectIsStarredById(projectId, true);
|
|
48
|
-
updated += 1;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return { updated };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Flips `projects.isStarred` for one project and returns the new state.
|
|
56
|
-
*/
|
|
57
|
-
export function toggleProjectStar(projectId: string): ToggleProjectStarResult {
|
|
58
|
-
const normalizedProjectId = normalizeProjectId(projectId);
|
|
59
|
-
if (!normalizedProjectId) {
|
|
60
|
-
throw new AppError('projectId is required', {
|
|
61
|
-
code: 'PROJECT_ID_REQUIRED',
|
|
62
|
-
statusCode: 400,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const project = projectsDb.getProjectById(normalizedProjectId);
|
|
67
|
-
if (!project) {
|
|
68
|
-
throw new AppError('Project not found', {
|
|
69
|
-
code: 'PROJECT_NOT_FOUND',
|
|
70
|
-
statusCode: 404,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const nextStarredState = !Boolean(project.isStarred);
|
|
75
|
-
projectsDb.updateProjectIsStarredById(normalizedProjectId, nextStarredState);
|
|
76
|
-
|
|
77
|
-
return { isStarred: nextStarredState };
|
|
78
|
-
}
|
|
1
|
+
import { projectsDb } from '@/modules/database/index.js';
|
|
2
|
+
import { AppError } from '@/shared/utils.js';
|
|
3
|
+
|
|
4
|
+
type ToggleProjectStarResult = {
|
|
5
|
+
isStarred: boolean;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
type ApplyLegacyStarredProjectIdsResult = {
|
|
9
|
+
updated: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
function normalizeProjectId(projectId: string): string {
|
|
13
|
+
return projectId.trim();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function uniqueProjectIds(projectIds: string[]): string[] {
|
|
17
|
+
const uniqueIds = new Set<string>();
|
|
18
|
+
for (const projectId of projectIds) {
|
|
19
|
+
const normalizedProjectId = normalizeProjectId(projectId);
|
|
20
|
+
if (!normalizedProjectId) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
uniqueIds.add(normalizedProjectId);
|
|
24
|
+
}
|
|
25
|
+
return [...uniqueIds];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Applies legacy `localStorage` stars keyed by DB `projectId` onto `projects.isStarred`.
|
|
30
|
+
*
|
|
31
|
+
* The operation is idempotent: already-starred projects are ignored, unknown ids are skipped.
|
|
32
|
+
*/
|
|
33
|
+
export function applyLegacyStarredProjectIds(projectIds: string[]): ApplyLegacyStarredProjectIdsResult {
|
|
34
|
+
const normalizedProjectIds = uniqueProjectIds(projectIds);
|
|
35
|
+
let updated = 0;
|
|
36
|
+
|
|
37
|
+
for (const projectId of normalizedProjectIds) {
|
|
38
|
+
const project = projectsDb.getProjectById(projectId);
|
|
39
|
+
if (!project) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (Boolean(project.isStarred)) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
projectsDb.updateProjectIsStarredById(projectId, true);
|
|
48
|
+
updated += 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { updated };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Flips `projects.isStarred` for one project and returns the new state.
|
|
56
|
+
*/
|
|
57
|
+
export function toggleProjectStar(projectId: string): ToggleProjectStarResult {
|
|
58
|
+
const normalizedProjectId = normalizeProjectId(projectId);
|
|
59
|
+
if (!normalizedProjectId) {
|
|
60
|
+
throw new AppError('projectId is required', {
|
|
61
|
+
code: 'PROJECT_ID_REQUIRED',
|
|
62
|
+
statusCode: 400,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const project = projectsDb.getProjectById(normalizedProjectId);
|
|
67
|
+
if (!project) {
|
|
68
|
+
throw new AppError('Project not found', {
|
|
69
|
+
code: 'PROJECT_NOT_FOUND',
|
|
70
|
+
statusCode: 404,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const nextStarredState = !Boolean(project.isStarred);
|
|
75
|
+
projectsDb.updateProjectIsStarredById(normalizedProjectId, nextStarredState);
|
|
76
|
+
|
|
77
|
+
return { isStarred: nextStarredState };
|
|
78
|
+
}
|