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,24 +1,24 @@
|
|
|
1
|
-
export {
|
|
2
|
-
// Used by notification tests and delivery workflows to create channel payloads.
|
|
3
|
-
buildNotificationPayload,
|
|
4
|
-
// Used by provider runtimes and Settings to create normalized notification events.
|
|
5
|
-
createNotificationEvent,
|
|
6
|
-
// Used by provider runtimes and Settings to deliver events through enabled channels.
|
|
7
|
-
notifyUserIfEnabled,
|
|
8
|
-
// Used by provider runtimes to report failed agent runs.
|
|
9
|
-
notifyRunFailed,
|
|
10
|
-
// Used by provider runtimes to report stopped or completed agent runs.
|
|
11
|
-
notifyRunStopped,
|
|
12
|
-
// Used by provider runtimes to report background work that finished after its turn ended.
|
|
13
|
-
notifyBackgroundWorkCompleted,
|
|
14
|
-
} from '@/modules/notifications/services/notification-orchestrator.service.js';
|
|
15
|
-
export {
|
|
16
|
-
registerDesktopNotificationClient,
|
|
17
|
-
sendDesktopNotification,
|
|
18
|
-
unregisterDesktopNotificationClient,
|
|
19
|
-
} from '@/modules/notifications/services/desktop-notification-clients.service.js';
|
|
20
|
-
export { handleDesktopNotificationsConnection } from '@/modules/notifications/websocket/desktop-notifications-websocket.service.js';
|
|
21
|
-
// getPublicKey: used by Settings to expose the Web Push subscription key.
|
|
22
|
-
export { getPublicKey } from './vapid-keys.service.js';
|
|
23
|
-
// configureWebPush: used by the server entrypoint during notification startup.
|
|
24
|
-
export { configureWebPush } from './vapid-keys.service.js';
|
|
1
|
+
export {
|
|
2
|
+
// Used by notification tests and delivery workflows to create channel payloads.
|
|
3
|
+
buildNotificationPayload,
|
|
4
|
+
// Used by provider runtimes and Settings to create normalized notification events.
|
|
5
|
+
createNotificationEvent,
|
|
6
|
+
// Used by provider runtimes and Settings to deliver events through enabled channels.
|
|
7
|
+
notifyUserIfEnabled,
|
|
8
|
+
// Used by provider runtimes to report failed agent runs.
|
|
9
|
+
notifyRunFailed,
|
|
10
|
+
// Used by provider runtimes to report stopped or completed agent runs.
|
|
11
|
+
notifyRunStopped,
|
|
12
|
+
// Used by provider runtimes to report background work that finished after its turn ended.
|
|
13
|
+
notifyBackgroundWorkCompleted,
|
|
14
|
+
} from '@/modules/notifications/services/notification-orchestrator.service.js';
|
|
15
|
+
export {
|
|
16
|
+
registerDesktopNotificationClient,
|
|
17
|
+
sendDesktopNotification,
|
|
18
|
+
unregisterDesktopNotificationClient,
|
|
19
|
+
} from '@/modules/notifications/services/desktop-notification-clients.service.js';
|
|
20
|
+
export { handleDesktopNotificationsConnection } from '@/modules/notifications/websocket/desktop-notifications-websocket.service.js';
|
|
21
|
+
// getPublicKey: used by Settings to expose the Web Push subscription key.
|
|
22
|
+
export { getPublicKey } from './vapid-keys.service.js';
|
|
23
|
+
// configureWebPush: used by the server entrypoint during notification startup.
|
|
24
|
+
export { configureWebPush } from './vapid-keys.service.js';
|
|
@@ -1,127 +1,127 @@
|
|
|
1
|
-
import express from 'express';
|
|
2
|
-
|
|
3
|
-
import { notificationChannelEndpointsDb, notificationPreferencesDb } from '@/modules/database/index.js';
|
|
4
|
-
|
|
5
|
-
const router = express.Router();
|
|
6
|
-
|
|
7
|
-
function readText(value: unknown): string {
|
|
8
|
-
return typeof value === 'string' ? value.trim() : '';
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
function sanitizeEndpoint(endpoint: any) {
|
|
12
|
-
return {
|
|
13
|
-
id: endpoint.id,
|
|
14
|
-
channel: endpoint.channel,
|
|
15
|
-
endpointId: endpoint.endpoint_id,
|
|
16
|
-
label: endpoint.label,
|
|
17
|
-
metadata: notificationChannelEndpointsDb.parseMetadata(endpoint.metadata_json),
|
|
18
|
-
enabled: Boolean(endpoint.enabled),
|
|
19
|
-
lastSeenAt: endpoint.last_seen_at,
|
|
20
|
-
createdAt: endpoint.created_at,
|
|
21
|
-
updatedAt: endpoint.updated_at,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function readUserId(req: express.Request): number {
|
|
26
|
-
const userId = Number((req as any).user?.id);
|
|
27
|
-
if (!Number.isInteger(userId) || userId <= 0) {
|
|
28
|
-
throw new Error('Authenticated user is missing');
|
|
29
|
-
}
|
|
30
|
-
return userId;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function updateChannelPreference(userId: number, channel: string): unknown {
|
|
34
|
-
const currentPrefs = notificationPreferencesDb.getPreferences(userId);
|
|
35
|
-
const hasEnabledEndpoint = notificationChannelEndpointsDb.getEnabledEndpoints(userId, channel).length > 0;
|
|
36
|
-
return notificationPreferencesDb.updatePreferences(userId, {
|
|
37
|
-
...currentPrefs,
|
|
38
|
-
channels: { ...currentPrefs.channels, [channel]: hasEnabledEndpoint },
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
router.get('/endpoints', (req, res) => {
|
|
43
|
-
try {
|
|
44
|
-
const channel = readText(req.query.channel);
|
|
45
|
-
if (!channel) {
|
|
46
|
-
return res.status(400).json({ error: 'channel is required' });
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const userId = readUserId(req);
|
|
50
|
-
const endpoints = notificationChannelEndpointsDb
|
|
51
|
-
.getEndpoints(userId, channel)
|
|
52
|
-
.map(sanitizeEndpoint);
|
|
53
|
-
return res.json({ success: true, endpoints });
|
|
54
|
-
} catch (error) {
|
|
55
|
-
console.error('Error fetching notification endpoints:', error);
|
|
56
|
-
return res.status(500).json({ error: 'Failed to fetch notification endpoints' });
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
router.post('/endpoints/current', (req, res) => {
|
|
61
|
-
try {
|
|
62
|
-
const { channel, endpointId, label, metadata = {}, enabled = true } = req.body || {};
|
|
63
|
-
const normalizedChannel = readText(channel);
|
|
64
|
-
const normalizedEndpointId = readText(endpointId);
|
|
65
|
-
if (!normalizedChannel || !normalizedEndpointId) {
|
|
66
|
-
return res.status(400).json({ error: 'channel and endpointId are required' });
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const userId = readUserId(req);
|
|
70
|
-
const endpoint = notificationChannelEndpointsDb.upsertEndpoint({
|
|
71
|
-
userId,
|
|
72
|
-
channel: normalizedChannel,
|
|
73
|
-
endpointId: normalizedEndpointId,
|
|
74
|
-
label,
|
|
75
|
-
metadata: metadata && typeof metadata === 'object' ? metadata : {},
|
|
76
|
-
enabled: enabled !== false,
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
const preferences = updateChannelPreference(userId, normalizedChannel);
|
|
80
|
-
return res.json({ success: true, endpoint: sanitizeEndpoint(endpoint), preferences });
|
|
81
|
-
} catch (error) {
|
|
82
|
-
console.error('Error registering notification endpoint:', error);
|
|
83
|
-
return res.status(500).json({ error: 'Failed to register notification endpoint' });
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
router.patch('/endpoints/:channel/:endpointId', (req, res) => {
|
|
88
|
-
try {
|
|
89
|
-
const { channel, endpointId } = req.params;
|
|
90
|
-
const { enabled } = req.body || {};
|
|
91
|
-
if (typeof enabled !== 'boolean') {
|
|
92
|
-
return res.status(400).json({ error: 'enabled must be a boolean' });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const userId = readUserId(req);
|
|
96
|
-
const updated = notificationChannelEndpointsDb.setEndpointEnabled(userId, channel, endpointId, enabled);
|
|
97
|
-
if (!updated) {
|
|
98
|
-
return res.status(404).json({ error: 'Notification endpoint not found' });
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const endpoint = notificationChannelEndpointsDb.getEndpoint(userId, channel, endpointId);
|
|
102
|
-
const preferences = updateChannelPreference(userId, channel);
|
|
103
|
-
return res.json({ success: true, endpoint: endpoint ? sanitizeEndpoint(endpoint) : null, preferences });
|
|
104
|
-
} catch (error) {
|
|
105
|
-
console.error('Error updating notification endpoint:', error);
|
|
106
|
-
return res.status(500).json({ error: 'Failed to update notification endpoint' });
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
router.delete('/endpoints/:channel/:endpointId', (req, res) => {
|
|
111
|
-
try {
|
|
112
|
-
const { channel, endpointId } = req.params;
|
|
113
|
-
const userId = readUserId(req);
|
|
114
|
-
const removed = notificationChannelEndpointsDb.removeEndpoint(userId, channel, endpointId);
|
|
115
|
-
if (!removed) {
|
|
116
|
-
return res.status(404).json({ error: 'Notification endpoint not found' });
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const preferences = updateChannelPreference(userId, channel);
|
|
120
|
-
return res.json({ success: true, preferences });
|
|
121
|
-
} catch (error) {
|
|
122
|
-
console.error('Error removing notification endpoint:', error);
|
|
123
|
-
return res.status(500).json({ error: 'Failed to remove notification endpoint' });
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
export default router;
|
|
1
|
+
import express from 'express';
|
|
2
|
+
|
|
3
|
+
import { notificationChannelEndpointsDb, notificationPreferencesDb } from '@/modules/database/index.js';
|
|
4
|
+
|
|
5
|
+
const router = express.Router();
|
|
6
|
+
|
|
7
|
+
function readText(value: unknown): string {
|
|
8
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function sanitizeEndpoint(endpoint: any) {
|
|
12
|
+
return {
|
|
13
|
+
id: endpoint.id,
|
|
14
|
+
channel: endpoint.channel,
|
|
15
|
+
endpointId: endpoint.endpoint_id,
|
|
16
|
+
label: endpoint.label,
|
|
17
|
+
metadata: notificationChannelEndpointsDb.parseMetadata(endpoint.metadata_json),
|
|
18
|
+
enabled: Boolean(endpoint.enabled),
|
|
19
|
+
lastSeenAt: endpoint.last_seen_at,
|
|
20
|
+
createdAt: endpoint.created_at,
|
|
21
|
+
updatedAt: endpoint.updated_at,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function readUserId(req: express.Request): number {
|
|
26
|
+
const userId = Number((req as any).user?.id);
|
|
27
|
+
if (!Number.isInteger(userId) || userId <= 0) {
|
|
28
|
+
throw new Error('Authenticated user is missing');
|
|
29
|
+
}
|
|
30
|
+
return userId;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function updateChannelPreference(userId: number, channel: string): unknown {
|
|
34
|
+
const currentPrefs = notificationPreferencesDb.getPreferences(userId);
|
|
35
|
+
const hasEnabledEndpoint = notificationChannelEndpointsDb.getEnabledEndpoints(userId, channel).length > 0;
|
|
36
|
+
return notificationPreferencesDb.updatePreferences(userId, {
|
|
37
|
+
...currentPrefs,
|
|
38
|
+
channels: { ...currentPrefs.channels, [channel]: hasEnabledEndpoint },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
router.get('/endpoints', (req, res) => {
|
|
43
|
+
try {
|
|
44
|
+
const channel = readText(req.query.channel);
|
|
45
|
+
if (!channel) {
|
|
46
|
+
return res.status(400).json({ error: 'channel is required' });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const userId = readUserId(req);
|
|
50
|
+
const endpoints = notificationChannelEndpointsDb
|
|
51
|
+
.getEndpoints(userId, channel)
|
|
52
|
+
.map(sanitizeEndpoint);
|
|
53
|
+
return res.json({ success: true, endpoints });
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('Error fetching notification endpoints:', error);
|
|
56
|
+
return res.status(500).json({ error: 'Failed to fetch notification endpoints' });
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
router.post('/endpoints/current', (req, res) => {
|
|
61
|
+
try {
|
|
62
|
+
const { channel, endpointId, label, metadata = {}, enabled = true } = req.body || {};
|
|
63
|
+
const normalizedChannel = readText(channel);
|
|
64
|
+
const normalizedEndpointId = readText(endpointId);
|
|
65
|
+
if (!normalizedChannel || !normalizedEndpointId) {
|
|
66
|
+
return res.status(400).json({ error: 'channel and endpointId are required' });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const userId = readUserId(req);
|
|
70
|
+
const endpoint = notificationChannelEndpointsDb.upsertEndpoint({
|
|
71
|
+
userId,
|
|
72
|
+
channel: normalizedChannel,
|
|
73
|
+
endpointId: normalizedEndpointId,
|
|
74
|
+
label,
|
|
75
|
+
metadata: metadata && typeof metadata === 'object' ? metadata : {},
|
|
76
|
+
enabled: enabled !== false,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const preferences = updateChannelPreference(userId, normalizedChannel);
|
|
80
|
+
return res.json({ success: true, endpoint: sanitizeEndpoint(endpoint), preferences });
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error('Error registering notification endpoint:', error);
|
|
83
|
+
return res.status(500).json({ error: 'Failed to register notification endpoint' });
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
router.patch('/endpoints/:channel/:endpointId', (req, res) => {
|
|
88
|
+
try {
|
|
89
|
+
const { channel, endpointId } = req.params;
|
|
90
|
+
const { enabled } = req.body || {};
|
|
91
|
+
if (typeof enabled !== 'boolean') {
|
|
92
|
+
return res.status(400).json({ error: 'enabled must be a boolean' });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const userId = readUserId(req);
|
|
96
|
+
const updated = notificationChannelEndpointsDb.setEndpointEnabled(userId, channel, endpointId, enabled);
|
|
97
|
+
if (!updated) {
|
|
98
|
+
return res.status(404).json({ error: 'Notification endpoint not found' });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const endpoint = notificationChannelEndpointsDb.getEndpoint(userId, channel, endpointId);
|
|
102
|
+
const preferences = updateChannelPreference(userId, channel);
|
|
103
|
+
return res.json({ success: true, endpoint: endpoint ? sanitizeEndpoint(endpoint) : null, preferences });
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error('Error updating notification endpoint:', error);
|
|
106
|
+
return res.status(500).json({ error: 'Failed to update notification endpoint' });
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
router.delete('/endpoints/:channel/:endpointId', (req, res) => {
|
|
111
|
+
try {
|
|
112
|
+
const { channel, endpointId } = req.params;
|
|
113
|
+
const userId = readUserId(req);
|
|
114
|
+
const removed = notificationChannelEndpointsDb.removeEndpoint(userId, channel, endpointId);
|
|
115
|
+
if (!removed) {
|
|
116
|
+
return res.status(404).json({ error: 'Notification endpoint not found' });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const preferences = updateChannelPreference(userId, channel);
|
|
120
|
+
return res.json({ success: true, preferences });
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error('Error removing notification endpoint:', error);
|
|
123
|
+
return res.status(500).json({ error: 'Failed to remove notification endpoint' });
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
export default router;
|
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
import type { WebSocket } from 'ws';
|
|
2
|
-
|
|
3
|
-
import { notificationChannelEndpointsDb } from '@/modules/database/index.js';
|
|
4
|
-
|
|
5
|
-
const DESKTOP_CHANNEL = 'desktop';
|
|
6
|
-
|
|
7
|
-
const clientsByUserId = new Map<number, Map<string, WebSocket>>();
|
|
8
|
-
const clientBySocket = new WeakMap<WebSocket, { userId: number; endpointId: string }>();
|
|
9
|
-
|
|
10
|
-
function normalizeUserId(userId: unknown): number | null {
|
|
11
|
-
const numeric = Number(userId);
|
|
12
|
-
return Number.isInteger(numeric) && numeric > 0 ? numeric : null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function normalizeEndpointId(endpointId: unknown): string {
|
|
16
|
-
if (typeof endpointId !== 'string') return '';
|
|
17
|
-
return endpointId.trim();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function getUserClients(userId: unknown, create = false): Map<string, WebSocket> | null {
|
|
21
|
-
const normalizedUserId = normalizeUserId(userId);
|
|
22
|
-
if (!normalizedUserId) return null;
|
|
23
|
-
let clients = clientsByUserId.get(normalizedUserId);
|
|
24
|
-
if (!clients && create) {
|
|
25
|
-
clients = new Map();
|
|
26
|
-
clientsByUserId.set(normalizedUserId, clients);
|
|
27
|
-
}
|
|
28
|
-
return clients || null;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function registerDesktopNotificationClient({
|
|
32
|
-
userId,
|
|
33
|
-
deviceId,
|
|
34
|
-
label = null,
|
|
35
|
-
platform = null,
|
|
36
|
-
appVersion = null,
|
|
37
|
-
ws,
|
|
38
|
-
}: {
|
|
39
|
-
userId: number;
|
|
40
|
-
deviceId: string;
|
|
41
|
-
label?: string | null;
|
|
42
|
-
platform?: string | null;
|
|
43
|
-
appVersion?: string | null;
|
|
44
|
-
ws: WebSocket;
|
|
45
|
-
}) {
|
|
46
|
-
const normalizedUserId = normalizeUserId(userId);
|
|
47
|
-
const endpointId = normalizeEndpointId(deviceId);
|
|
48
|
-
if (!normalizedUserId || !endpointId) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const endpoint = notificationChannelEndpointsDb.upsertEndpoint({
|
|
53
|
-
userId: normalizedUserId,
|
|
54
|
-
channel: DESKTOP_CHANNEL,
|
|
55
|
-
endpointId,
|
|
56
|
-
label,
|
|
57
|
-
metadata: { platform, appVersion },
|
|
58
|
-
enabled: true,
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
const clients = getUserClients(normalizedUserId, true)!;
|
|
62
|
-
const previous = clients.get(endpointId);
|
|
63
|
-
if (previous && previous !== ws && previous.readyState === previous.OPEN) {
|
|
64
|
-
previous.close(4000, 'Device reconnected');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
clients.set(endpointId, ws);
|
|
68
|
-
clientBySocket.set(ws, { userId: normalizedUserId, endpointId });
|
|
69
|
-
return endpoint;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function unregisterDesktopNotificationClient(ws: WebSocket): void {
|
|
73
|
-
const registration = clientBySocket.get(ws);
|
|
74
|
-
if (!registration) return;
|
|
75
|
-
|
|
76
|
-
const clients = getUserClients(registration.userId);
|
|
77
|
-
if (clients?.get(registration.endpointId) === ws) {
|
|
78
|
-
clients.delete(registration.endpointId);
|
|
79
|
-
if (clients.size === 0) {
|
|
80
|
-
clientsByUserId.delete(registration.userId);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
clientBySocket.delete(ws);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export function sendDesktopNotification(userId: unknown, payload: unknown): { attempted: number; sent: number } {
|
|
87
|
-
const normalizedUserId = normalizeUserId(userId);
|
|
88
|
-
if (!normalizedUserId) return { attempted: 0, sent: 0 };
|
|
89
|
-
|
|
90
|
-
const clients = getUserClients(normalizedUserId);
|
|
91
|
-
if (!clients?.size) return { attempted: 0, sent: 0 };
|
|
92
|
-
|
|
93
|
-
const enabledEndpointIds = new Set(
|
|
94
|
-
notificationChannelEndpointsDb
|
|
95
|
-
.getEnabledEndpoints(normalizedUserId, DESKTOP_CHANNEL)
|
|
96
|
-
.map((endpoint) => endpoint.endpoint_id)
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
const message = JSON.stringify({
|
|
100
|
-
type: 'notification',
|
|
101
|
-
id: typeof (payload as any)?.data?.tag === 'string' ? (payload as any).data.tag : `${Date.now()}`,
|
|
102
|
-
payload,
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
let attempted = 0;
|
|
106
|
-
let sent = 0;
|
|
107
|
-
for (const [endpointId, ws] of clients.entries()) {
|
|
108
|
-
if (!enabledEndpointIds.has(endpointId)) continue;
|
|
109
|
-
attempted += 1;
|
|
110
|
-
if (ws.readyState !== ws.OPEN) {
|
|
111
|
-
unregisterDesktopNotificationClient(ws);
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
try {
|
|
115
|
-
ws.send(message);
|
|
116
|
-
notificationChannelEndpointsDb.touchEndpoint(normalizedUserId, DESKTOP_CHANNEL, endpointId);
|
|
117
|
-
sent += 1;
|
|
118
|
-
} catch {
|
|
119
|
-
unregisterDesktopNotificationClient(ws);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return { attempted, sent };
|
|
124
|
-
}
|
|
1
|
+
import type { WebSocket } from 'ws';
|
|
2
|
+
|
|
3
|
+
import { notificationChannelEndpointsDb } from '@/modules/database/index.js';
|
|
4
|
+
|
|
5
|
+
const DESKTOP_CHANNEL = 'desktop';
|
|
6
|
+
|
|
7
|
+
const clientsByUserId = new Map<number, Map<string, WebSocket>>();
|
|
8
|
+
const clientBySocket = new WeakMap<WebSocket, { userId: number; endpointId: string }>();
|
|
9
|
+
|
|
10
|
+
function normalizeUserId(userId: unknown): number | null {
|
|
11
|
+
const numeric = Number(userId);
|
|
12
|
+
return Number.isInteger(numeric) && numeric > 0 ? numeric : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function normalizeEndpointId(endpointId: unknown): string {
|
|
16
|
+
if (typeof endpointId !== 'string') return '';
|
|
17
|
+
return endpointId.trim();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getUserClients(userId: unknown, create = false): Map<string, WebSocket> | null {
|
|
21
|
+
const normalizedUserId = normalizeUserId(userId);
|
|
22
|
+
if (!normalizedUserId) return null;
|
|
23
|
+
let clients = clientsByUserId.get(normalizedUserId);
|
|
24
|
+
if (!clients && create) {
|
|
25
|
+
clients = new Map();
|
|
26
|
+
clientsByUserId.set(normalizedUserId, clients);
|
|
27
|
+
}
|
|
28
|
+
return clients || null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function registerDesktopNotificationClient({
|
|
32
|
+
userId,
|
|
33
|
+
deviceId,
|
|
34
|
+
label = null,
|
|
35
|
+
platform = null,
|
|
36
|
+
appVersion = null,
|
|
37
|
+
ws,
|
|
38
|
+
}: {
|
|
39
|
+
userId: number;
|
|
40
|
+
deviceId: string;
|
|
41
|
+
label?: string | null;
|
|
42
|
+
platform?: string | null;
|
|
43
|
+
appVersion?: string | null;
|
|
44
|
+
ws: WebSocket;
|
|
45
|
+
}) {
|
|
46
|
+
const normalizedUserId = normalizeUserId(userId);
|
|
47
|
+
const endpointId = normalizeEndpointId(deviceId);
|
|
48
|
+
if (!normalizedUserId || !endpointId) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const endpoint = notificationChannelEndpointsDb.upsertEndpoint({
|
|
53
|
+
userId: normalizedUserId,
|
|
54
|
+
channel: DESKTOP_CHANNEL,
|
|
55
|
+
endpointId,
|
|
56
|
+
label,
|
|
57
|
+
metadata: { platform, appVersion },
|
|
58
|
+
enabled: true,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const clients = getUserClients(normalizedUserId, true)!;
|
|
62
|
+
const previous = clients.get(endpointId);
|
|
63
|
+
if (previous && previous !== ws && previous.readyState === previous.OPEN) {
|
|
64
|
+
previous.close(4000, 'Device reconnected');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
clients.set(endpointId, ws);
|
|
68
|
+
clientBySocket.set(ws, { userId: normalizedUserId, endpointId });
|
|
69
|
+
return endpoint;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function unregisterDesktopNotificationClient(ws: WebSocket): void {
|
|
73
|
+
const registration = clientBySocket.get(ws);
|
|
74
|
+
if (!registration) return;
|
|
75
|
+
|
|
76
|
+
const clients = getUserClients(registration.userId);
|
|
77
|
+
if (clients?.get(registration.endpointId) === ws) {
|
|
78
|
+
clients.delete(registration.endpointId);
|
|
79
|
+
if (clients.size === 0) {
|
|
80
|
+
clientsByUserId.delete(registration.userId);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
clientBySocket.delete(ws);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function sendDesktopNotification(userId: unknown, payload: unknown): { attempted: number; sent: number } {
|
|
87
|
+
const normalizedUserId = normalizeUserId(userId);
|
|
88
|
+
if (!normalizedUserId) return { attempted: 0, sent: 0 };
|
|
89
|
+
|
|
90
|
+
const clients = getUserClients(normalizedUserId);
|
|
91
|
+
if (!clients?.size) return { attempted: 0, sent: 0 };
|
|
92
|
+
|
|
93
|
+
const enabledEndpointIds = new Set(
|
|
94
|
+
notificationChannelEndpointsDb
|
|
95
|
+
.getEnabledEndpoints(normalizedUserId, DESKTOP_CHANNEL)
|
|
96
|
+
.map((endpoint) => endpoint.endpoint_id)
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const message = JSON.stringify({
|
|
100
|
+
type: 'notification',
|
|
101
|
+
id: typeof (payload as any)?.data?.tag === 'string' ? (payload as any).data.tag : `${Date.now()}`,
|
|
102
|
+
payload,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
let attempted = 0;
|
|
106
|
+
let sent = 0;
|
|
107
|
+
for (const [endpointId, ws] of clients.entries()) {
|
|
108
|
+
if (!enabledEndpointIds.has(endpointId)) continue;
|
|
109
|
+
attempted += 1;
|
|
110
|
+
if (ws.readyState !== ws.OPEN) {
|
|
111
|
+
unregisterDesktopNotificationClient(ws);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
ws.send(message);
|
|
116
|
+
notificationChannelEndpointsDb.touchEndpoint(normalizedUserId, DESKTOP_CHANNEL, endpointId);
|
|
117
|
+
sent += 1;
|
|
118
|
+
} catch {
|
|
119
|
+
unregisterDesktopNotificationClient(ws);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return { attempted, sent };
|
|
124
|
+
}
|