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,244 +1,244 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { once } from 'node:events';
|
|
3
|
-
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
4
|
-
import type { AddressInfo } from 'node:net';
|
|
5
|
-
import os from 'node:os';
|
|
6
|
-
import path from 'node:path';
|
|
7
|
-
import test from 'node:test';
|
|
8
|
-
|
|
9
|
-
import express, { type NextFunction, type Request, type Response } from 'express';
|
|
10
|
-
|
|
11
|
-
import { closeConnection, initializeDatabase, sessionsDb } from '@/modules/database/index.js';
|
|
12
|
-
import providerRouter from '@/modules/providers/provider.routes.js';
|
|
13
|
-
import { AppError } from '@/shared/utils.js';
|
|
14
|
-
|
|
15
|
-
async function withProviderServer(
|
|
16
|
-
run: (baseUrl: string, workspacePath: string) => Promise<void>,
|
|
17
|
-
): Promise<void> {
|
|
18
|
-
const previousDatabasePath = process.env.DATABASE_PATH;
|
|
19
|
-
const tempDirectory = await mkdtemp(path.join(os.tmpdir(), 'provider-routes-'));
|
|
20
|
-
|
|
21
|
-
closeConnection();
|
|
22
|
-
process.env.DATABASE_PATH = path.join(tempDirectory, 'auth.db');
|
|
23
|
-
await writeFile(process.env.DATABASE_PATH, '');
|
|
24
|
-
await initializeDatabase();
|
|
25
|
-
|
|
26
|
-
const app = express().use(express.json()).use('/api/providers', providerRouter);
|
|
27
|
-
app.use((error: unknown, _req: Request, res: Response, _next: NextFunction) => {
|
|
28
|
-
if (error instanceof AppError) {
|
|
29
|
-
res.status(error.statusCode).json({
|
|
30
|
-
success: false,
|
|
31
|
-
error: { code: error.code, message: error.message },
|
|
32
|
-
});
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
res.status(500).json({ success: false, error: { code: 'INTERNAL_ERROR' } });
|
|
36
|
-
});
|
|
37
|
-
const server = app.listen(0, '127.0.0.1');
|
|
38
|
-
await once(server, 'listening');
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const address = server.address() as AddressInfo;
|
|
42
|
-
await run(`http://127.0.0.1:${address.port}`, path.join(tempDirectory, 'workspace'));
|
|
43
|
-
} finally {
|
|
44
|
-
await new Promise<void>((resolve, reject) => {
|
|
45
|
-
server.close((error) => error ? reject(error) : resolve());
|
|
46
|
-
});
|
|
47
|
-
closeConnection();
|
|
48
|
-
if (previousDatabasePath === undefined) {
|
|
49
|
-
delete process.env.DATABASE_PATH;
|
|
50
|
-
} else {
|
|
51
|
-
process.env.DATABASE_PATH = previousDatabasePath;
|
|
52
|
-
}
|
|
53
|
-
await rm(tempDirectory, { recursive: true, force: true });
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
test('session creation route names a CloudCLI session from the initial message', async () => {
|
|
58
|
-
await withProviderServer(async (baseUrl, workspacePath) => {
|
|
59
|
-
const response = await fetch(`${baseUrl}/api/providers/sessions`, {
|
|
60
|
-
method: 'POST',
|
|
61
|
-
headers: { 'content-type': 'application/json' },
|
|
62
|
-
body: JSON.stringify({
|
|
63
|
-
provider: 'codex',
|
|
64
|
-
projectPath: workspacePath,
|
|
65
|
-
initialMessage: 'abcd efg\nhij klm nop',
|
|
66
|
-
}),
|
|
67
|
-
});
|
|
68
|
-
const payload = await response.json() as {
|
|
69
|
-
data: { sessionId: string; sessionName: string };
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
assert.equal(response.status, 201);
|
|
73
|
-
assert.equal(payload.data.sessionName, 'abcd efg hij klm');
|
|
74
|
-
assert.equal(
|
|
75
|
-
sessionsDb.getSessionById(payload.data.sessionId)?.custom_name,
|
|
76
|
-
'abcd efg hij klm',
|
|
77
|
-
);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test('conversation search streams title matches before transcript results', async () => {
|
|
82
|
-
await withProviderServer(async (baseUrl, workspacePath) => {
|
|
83
|
-
sessionsDb.createAppSession(
|
|
84
|
-
'title-only-session',
|
|
85
|
-
'codex',
|
|
86
|
-
workspacePath,
|
|
87
|
-
'Release planning notes',
|
|
88
|
-
);
|
|
89
|
-
const transcriptPath = path.join(path.dirname(workspacePath), 'codex-search.jsonl');
|
|
90
|
-
await writeFile(transcriptPath, `${JSON.stringify({
|
|
91
|
-
type: 'event_msg',
|
|
92
|
-
timestamp: '2026-08-12T09:00:00.000Z',
|
|
93
|
-
payload: {
|
|
94
|
-
type: 'user_message',
|
|
95
|
-
kind: 'plain',
|
|
96
|
-
message: 'Release planning also appears in this conversation.',
|
|
97
|
-
},
|
|
98
|
-
})}\n`);
|
|
99
|
-
sessionsDb.createSession(
|
|
100
|
-
'transcript-session',
|
|
101
|
-
'codex',
|
|
102
|
-
workspacePath,
|
|
103
|
-
'Unrelated session',
|
|
104
|
-
undefined,
|
|
105
|
-
undefined,
|
|
106
|
-
transcriptPath,
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
const response = await fetch(
|
|
110
|
-
`${baseUrl}/api/providers/search/sessions?q=release%20planning&limit=50`,
|
|
111
|
-
);
|
|
112
|
-
const eventStream = await response.text();
|
|
113
|
-
const titleEventIndex = eventStream.indexOf('event: title-results');
|
|
114
|
-
const conversationEventIndex = eventStream.indexOf('event: result');
|
|
115
|
-
const doneEventIndex = eventStream.indexOf('event: done');
|
|
116
|
-
|
|
117
|
-
assert.equal(response.status, 200);
|
|
118
|
-
assert.ok(titleEventIndex >= 0);
|
|
119
|
-
assert.ok(conversationEventIndex > titleEventIndex);
|
|
120
|
-
assert.ok(doneEventIndex > titleEventIndex);
|
|
121
|
-
|
|
122
|
-
const titleDataLine = eventStream
|
|
123
|
-
.slice(titleEventIndex, conversationEventIndex)
|
|
124
|
-
.split('\n')
|
|
125
|
-
.find((line) => line.startsWith('data: '));
|
|
126
|
-
assert.ok(titleDataLine);
|
|
127
|
-
|
|
128
|
-
const titlePayload = JSON.parse(titleDataLine.slice('data: '.length)) as {
|
|
129
|
-
titleResults: Array<{
|
|
130
|
-
sessionId: string;
|
|
131
|
-
sessionTitle: string;
|
|
132
|
-
provider: string;
|
|
133
|
-
}>;
|
|
134
|
-
};
|
|
135
|
-
assert.equal(titlePayload.titleResults.length, 1);
|
|
136
|
-
assert.equal(titlePayload.titleResults[0]?.sessionId, 'title-only-session');
|
|
137
|
-
assert.equal(titlePayload.titleResults[0]?.sessionTitle, 'Release planning notes');
|
|
138
|
-
assert.equal(titlePayload.titleResults[0]?.provider, 'codex');
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
test('reasoning effort is persisted and returned with the active session model', async () => {
|
|
143
|
-
await withProviderServer(async (baseUrl, workspacePath) => {
|
|
144
|
-
sessionsDb.createAppSession('effort-session', 'codex', workspacePath);
|
|
145
|
-
|
|
146
|
-
const updateResponse = await fetch(
|
|
147
|
-
`${baseUrl}/api/providers/codex/sessions/effort-session/active-effort`,
|
|
148
|
-
{
|
|
149
|
-
method: 'POST',
|
|
150
|
-
headers: { 'content-type': 'application/json' },
|
|
151
|
-
body: JSON.stringify({ effort: 'ultra' }),
|
|
152
|
-
},
|
|
153
|
-
);
|
|
154
|
-
const updatePayload = await updateResponse.json() as {
|
|
155
|
-
data: { effort: string; sessionId: string };
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
assert.equal(updateResponse.status, 200);
|
|
159
|
-
assert.equal(updatePayload.data.effort, 'ultra');
|
|
160
|
-
assert.equal(sessionsDb.getSessionById('effort-session')?.effort, 'ultra');
|
|
161
|
-
|
|
162
|
-
const readResponse = await fetch(
|
|
163
|
-
`${baseUrl}/api/providers/codex/sessions/effort-session/active-model`,
|
|
164
|
-
);
|
|
165
|
-
const readPayload = await readResponse.json() as {
|
|
166
|
-
data: { effort: string | null; sessionId: string };
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
assert.equal(readResponse.status, 200);
|
|
170
|
-
assert.equal(readPayload.data.sessionId, 'effort-session');
|
|
171
|
-
assert.equal(readPayload.data.effort, 'ultra');
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
test('model routes expose immutable defaults and full custom model CRUD', async () => {
|
|
176
|
-
await withProviderServer(async (baseUrl) => {
|
|
177
|
-
const initialResponse = await fetch(`${baseUrl}/api/providers/codex/models`);
|
|
178
|
-
const initialPayload = await initialResponse.json() as {
|
|
179
|
-
data: {
|
|
180
|
-
cache?: unknown;
|
|
181
|
-
models: {
|
|
182
|
-
OPTIONS: Array<{ recordId?: number; value: string; isCustom: boolean }>;
|
|
183
|
-
};
|
|
184
|
-
};
|
|
185
|
-
};
|
|
186
|
-
assert.equal(initialResponse.status, 200);
|
|
187
|
-
assert.equal('cache' in initialPayload.data, false);
|
|
188
|
-
const predefined = initialPayload.data.models.OPTIONS[0];
|
|
189
|
-
assert.equal(predefined.isCustom, false);
|
|
190
|
-
assert.equal(predefined.recordId, undefined);
|
|
191
|
-
|
|
192
|
-
const createResponse = await fetch(`${baseUrl}/api/providers/codex/models`, {
|
|
193
|
-
method: 'POST',
|
|
194
|
-
headers: { 'content-type': 'application/json' },
|
|
195
|
-
body: JSON.stringify({ model: 'Gateway GPT', id: 'gateway/gpt' }),
|
|
196
|
-
});
|
|
197
|
-
const createPayload = await createResponse.json() as {
|
|
198
|
-
data: { model: { recordId: number; value: string; label: string; isCustom: boolean } };
|
|
199
|
-
};
|
|
200
|
-
assert.equal(createResponse.status, 201);
|
|
201
|
-
assert.equal(createPayload.data.model.isCustom, true);
|
|
202
|
-
const customRecordId = createPayload.data.model.recordId;
|
|
203
|
-
|
|
204
|
-
const updateResponse = await fetch(
|
|
205
|
-
`${baseUrl}/api/providers/codex/models/${customRecordId}`,
|
|
206
|
-
{
|
|
207
|
-
method: 'PATCH',
|
|
208
|
-
headers: { 'content-type': 'application/json' },
|
|
209
|
-
body: JSON.stringify({ model: 'Gateway GPT Updated', id: 'gateway/gpt-v2' }),
|
|
210
|
-
},
|
|
211
|
-
);
|
|
212
|
-
const updatePayload = await updateResponse.json() as {
|
|
213
|
-
data: { model: { value: string; label: string } };
|
|
214
|
-
};
|
|
215
|
-
assert.equal(updateResponse.status, 200);
|
|
216
|
-
assert.equal(updatePayload.data.model.value, 'gateway/gpt-v2');
|
|
217
|
-
assert.equal(updatePayload.data.model.label, 'Gateway GPT Updated');
|
|
218
|
-
|
|
219
|
-
const immutableResponse = await fetch(
|
|
220
|
-
`${baseUrl}/api/providers/codex/models/999999`,
|
|
221
|
-
{
|
|
222
|
-
method: 'PATCH',
|
|
223
|
-
headers: { 'content-type': 'application/json' },
|
|
224
|
-
body: JSON.stringify({ model: 'Changed', id: 'changed' }),
|
|
225
|
-
},
|
|
226
|
-
);
|
|
227
|
-
const immutablePayload = await immutableResponse.json() as { error: { code: string } };
|
|
228
|
-
assert.equal(immutableResponse.status, 404);
|
|
229
|
-
assert.equal(immutablePayload.error.code, 'MODEL_NOT_FOUND');
|
|
230
|
-
|
|
231
|
-
const deleteResponse = await fetch(
|
|
232
|
-
`${baseUrl}/api/providers/codex/models/${customRecordId}`,
|
|
233
|
-
{ method: 'DELETE' },
|
|
234
|
-
);
|
|
235
|
-
const deletePayload = await deleteResponse.json() as {
|
|
236
|
-
data: { models: { OPTIONS: Array<{ recordId: number }> } };
|
|
237
|
-
};
|
|
238
|
-
assert.equal(deleteResponse.status, 200);
|
|
239
|
-
assert.equal(
|
|
240
|
-
deletePayload.data.models.OPTIONS.some((option) => option.recordId === customRecordId),
|
|
241
|
-
false,
|
|
242
|
-
);
|
|
243
|
-
});
|
|
244
|
-
});
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { once } from 'node:events';
|
|
3
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import type { AddressInfo } from 'node:net';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import test from 'node:test';
|
|
8
|
+
|
|
9
|
+
import express, { type NextFunction, type Request, type Response } from 'express';
|
|
10
|
+
|
|
11
|
+
import { closeConnection, initializeDatabase, sessionsDb } from '@/modules/database/index.js';
|
|
12
|
+
import providerRouter from '@/modules/providers/provider.routes.js';
|
|
13
|
+
import { AppError } from '@/shared/utils.js';
|
|
14
|
+
|
|
15
|
+
async function withProviderServer(
|
|
16
|
+
run: (baseUrl: string, workspacePath: string) => Promise<void>,
|
|
17
|
+
): Promise<void> {
|
|
18
|
+
const previousDatabasePath = process.env.DATABASE_PATH;
|
|
19
|
+
const tempDirectory = await mkdtemp(path.join(os.tmpdir(), 'provider-routes-'));
|
|
20
|
+
|
|
21
|
+
closeConnection();
|
|
22
|
+
process.env.DATABASE_PATH = path.join(tempDirectory, 'auth.db');
|
|
23
|
+
await writeFile(process.env.DATABASE_PATH, '');
|
|
24
|
+
await initializeDatabase();
|
|
25
|
+
|
|
26
|
+
const app = express().use(express.json()).use('/api/providers', providerRouter);
|
|
27
|
+
app.use((error: unknown, _req: Request, res: Response, _next: NextFunction) => {
|
|
28
|
+
if (error instanceof AppError) {
|
|
29
|
+
res.status(error.statusCode).json({
|
|
30
|
+
success: false,
|
|
31
|
+
error: { code: error.code, message: error.message },
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
res.status(500).json({ success: false, error: { code: 'INTERNAL_ERROR' } });
|
|
36
|
+
});
|
|
37
|
+
const server = app.listen(0, '127.0.0.1');
|
|
38
|
+
await once(server, 'listening');
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const address = server.address() as AddressInfo;
|
|
42
|
+
await run(`http://127.0.0.1:${address.port}`, path.join(tempDirectory, 'workspace'));
|
|
43
|
+
} finally {
|
|
44
|
+
await new Promise<void>((resolve, reject) => {
|
|
45
|
+
server.close((error) => error ? reject(error) : resolve());
|
|
46
|
+
});
|
|
47
|
+
closeConnection();
|
|
48
|
+
if (previousDatabasePath === undefined) {
|
|
49
|
+
delete process.env.DATABASE_PATH;
|
|
50
|
+
} else {
|
|
51
|
+
process.env.DATABASE_PATH = previousDatabasePath;
|
|
52
|
+
}
|
|
53
|
+
await rm(tempDirectory, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
test('session creation route names a CloudCLI session from the initial message', async () => {
|
|
58
|
+
await withProviderServer(async (baseUrl, workspacePath) => {
|
|
59
|
+
const response = await fetch(`${baseUrl}/api/providers/sessions`, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: { 'content-type': 'application/json' },
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
provider: 'codex',
|
|
64
|
+
projectPath: workspacePath,
|
|
65
|
+
initialMessage: 'abcd efg\nhij klm nop',
|
|
66
|
+
}),
|
|
67
|
+
});
|
|
68
|
+
const payload = await response.json() as {
|
|
69
|
+
data: { sessionId: string; sessionName: string };
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
assert.equal(response.status, 201);
|
|
73
|
+
assert.equal(payload.data.sessionName, 'abcd efg hij klm');
|
|
74
|
+
assert.equal(
|
|
75
|
+
sessionsDb.getSessionById(payload.data.sessionId)?.custom_name,
|
|
76
|
+
'abcd efg hij klm',
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('conversation search streams title matches before transcript results', async () => {
|
|
82
|
+
await withProviderServer(async (baseUrl, workspacePath) => {
|
|
83
|
+
sessionsDb.createAppSession(
|
|
84
|
+
'title-only-session',
|
|
85
|
+
'codex',
|
|
86
|
+
workspacePath,
|
|
87
|
+
'Release planning notes',
|
|
88
|
+
);
|
|
89
|
+
const transcriptPath = path.join(path.dirname(workspacePath), 'codex-search.jsonl');
|
|
90
|
+
await writeFile(transcriptPath, `${JSON.stringify({
|
|
91
|
+
type: 'event_msg',
|
|
92
|
+
timestamp: '2026-08-12T09:00:00.000Z',
|
|
93
|
+
payload: {
|
|
94
|
+
type: 'user_message',
|
|
95
|
+
kind: 'plain',
|
|
96
|
+
message: 'Release planning also appears in this conversation.',
|
|
97
|
+
},
|
|
98
|
+
})}\n`);
|
|
99
|
+
sessionsDb.createSession(
|
|
100
|
+
'transcript-session',
|
|
101
|
+
'codex',
|
|
102
|
+
workspacePath,
|
|
103
|
+
'Unrelated session',
|
|
104
|
+
undefined,
|
|
105
|
+
undefined,
|
|
106
|
+
transcriptPath,
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const response = await fetch(
|
|
110
|
+
`${baseUrl}/api/providers/search/sessions?q=release%20planning&limit=50`,
|
|
111
|
+
);
|
|
112
|
+
const eventStream = await response.text();
|
|
113
|
+
const titleEventIndex = eventStream.indexOf('event: title-results');
|
|
114
|
+
const conversationEventIndex = eventStream.indexOf('event: result');
|
|
115
|
+
const doneEventIndex = eventStream.indexOf('event: done');
|
|
116
|
+
|
|
117
|
+
assert.equal(response.status, 200);
|
|
118
|
+
assert.ok(titleEventIndex >= 0);
|
|
119
|
+
assert.ok(conversationEventIndex > titleEventIndex);
|
|
120
|
+
assert.ok(doneEventIndex > titleEventIndex);
|
|
121
|
+
|
|
122
|
+
const titleDataLine = eventStream
|
|
123
|
+
.slice(titleEventIndex, conversationEventIndex)
|
|
124
|
+
.split('\n')
|
|
125
|
+
.find((line) => line.startsWith('data: '));
|
|
126
|
+
assert.ok(titleDataLine);
|
|
127
|
+
|
|
128
|
+
const titlePayload = JSON.parse(titleDataLine.slice('data: '.length)) as {
|
|
129
|
+
titleResults: Array<{
|
|
130
|
+
sessionId: string;
|
|
131
|
+
sessionTitle: string;
|
|
132
|
+
provider: string;
|
|
133
|
+
}>;
|
|
134
|
+
};
|
|
135
|
+
assert.equal(titlePayload.titleResults.length, 1);
|
|
136
|
+
assert.equal(titlePayload.titleResults[0]?.sessionId, 'title-only-session');
|
|
137
|
+
assert.equal(titlePayload.titleResults[0]?.sessionTitle, 'Release planning notes');
|
|
138
|
+
assert.equal(titlePayload.titleResults[0]?.provider, 'codex');
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('reasoning effort is persisted and returned with the active session model', async () => {
|
|
143
|
+
await withProviderServer(async (baseUrl, workspacePath) => {
|
|
144
|
+
sessionsDb.createAppSession('effort-session', 'codex', workspacePath);
|
|
145
|
+
|
|
146
|
+
const updateResponse = await fetch(
|
|
147
|
+
`${baseUrl}/api/providers/codex/sessions/effort-session/active-effort`,
|
|
148
|
+
{
|
|
149
|
+
method: 'POST',
|
|
150
|
+
headers: { 'content-type': 'application/json' },
|
|
151
|
+
body: JSON.stringify({ effort: 'ultra' }),
|
|
152
|
+
},
|
|
153
|
+
);
|
|
154
|
+
const updatePayload = await updateResponse.json() as {
|
|
155
|
+
data: { effort: string; sessionId: string };
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
assert.equal(updateResponse.status, 200);
|
|
159
|
+
assert.equal(updatePayload.data.effort, 'ultra');
|
|
160
|
+
assert.equal(sessionsDb.getSessionById('effort-session')?.effort, 'ultra');
|
|
161
|
+
|
|
162
|
+
const readResponse = await fetch(
|
|
163
|
+
`${baseUrl}/api/providers/codex/sessions/effort-session/active-model`,
|
|
164
|
+
);
|
|
165
|
+
const readPayload = await readResponse.json() as {
|
|
166
|
+
data: { effort: string | null; sessionId: string };
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
assert.equal(readResponse.status, 200);
|
|
170
|
+
assert.equal(readPayload.data.sessionId, 'effort-session');
|
|
171
|
+
assert.equal(readPayload.data.effort, 'ultra');
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
test('model routes expose immutable defaults and full custom model CRUD', async () => {
|
|
176
|
+
await withProviderServer(async (baseUrl) => {
|
|
177
|
+
const initialResponse = await fetch(`${baseUrl}/api/providers/codex/models`);
|
|
178
|
+
const initialPayload = await initialResponse.json() as {
|
|
179
|
+
data: {
|
|
180
|
+
cache?: unknown;
|
|
181
|
+
models: {
|
|
182
|
+
OPTIONS: Array<{ recordId?: number; value: string; isCustom: boolean }>;
|
|
183
|
+
};
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
assert.equal(initialResponse.status, 200);
|
|
187
|
+
assert.equal('cache' in initialPayload.data, false);
|
|
188
|
+
const predefined = initialPayload.data.models.OPTIONS[0];
|
|
189
|
+
assert.equal(predefined.isCustom, false);
|
|
190
|
+
assert.equal(predefined.recordId, undefined);
|
|
191
|
+
|
|
192
|
+
const createResponse = await fetch(`${baseUrl}/api/providers/codex/models`, {
|
|
193
|
+
method: 'POST',
|
|
194
|
+
headers: { 'content-type': 'application/json' },
|
|
195
|
+
body: JSON.stringify({ model: 'Gateway GPT', id: 'gateway/gpt' }),
|
|
196
|
+
});
|
|
197
|
+
const createPayload = await createResponse.json() as {
|
|
198
|
+
data: { model: { recordId: number; value: string; label: string; isCustom: boolean } };
|
|
199
|
+
};
|
|
200
|
+
assert.equal(createResponse.status, 201);
|
|
201
|
+
assert.equal(createPayload.data.model.isCustom, true);
|
|
202
|
+
const customRecordId = createPayload.data.model.recordId;
|
|
203
|
+
|
|
204
|
+
const updateResponse = await fetch(
|
|
205
|
+
`${baseUrl}/api/providers/codex/models/${customRecordId}`,
|
|
206
|
+
{
|
|
207
|
+
method: 'PATCH',
|
|
208
|
+
headers: { 'content-type': 'application/json' },
|
|
209
|
+
body: JSON.stringify({ model: 'Gateway GPT Updated', id: 'gateway/gpt-v2' }),
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
const updatePayload = await updateResponse.json() as {
|
|
213
|
+
data: { model: { value: string; label: string } };
|
|
214
|
+
};
|
|
215
|
+
assert.equal(updateResponse.status, 200);
|
|
216
|
+
assert.equal(updatePayload.data.model.value, 'gateway/gpt-v2');
|
|
217
|
+
assert.equal(updatePayload.data.model.label, 'Gateway GPT Updated');
|
|
218
|
+
|
|
219
|
+
const immutableResponse = await fetch(
|
|
220
|
+
`${baseUrl}/api/providers/codex/models/999999`,
|
|
221
|
+
{
|
|
222
|
+
method: 'PATCH',
|
|
223
|
+
headers: { 'content-type': 'application/json' },
|
|
224
|
+
body: JSON.stringify({ model: 'Changed', id: 'changed' }),
|
|
225
|
+
},
|
|
226
|
+
);
|
|
227
|
+
const immutablePayload = await immutableResponse.json() as { error: { code: string } };
|
|
228
|
+
assert.equal(immutableResponse.status, 404);
|
|
229
|
+
assert.equal(immutablePayload.error.code, 'MODEL_NOT_FOUND');
|
|
230
|
+
|
|
231
|
+
const deleteResponse = await fetch(
|
|
232
|
+
`${baseUrl}/api/providers/codex/models/${customRecordId}`,
|
|
233
|
+
{ method: 'DELETE' },
|
|
234
|
+
);
|
|
235
|
+
const deletePayload = await deleteResponse.json() as {
|
|
236
|
+
data: { models: { OPTIONS: Array<{ recordId: number }> } };
|
|
237
|
+
};
|
|
238
|
+
assert.equal(deleteResponse.status, 200);
|
|
239
|
+
assert.equal(
|
|
240
|
+
deletePayload.data.models.OPTIONS.some((option) => option.recordId === customRecordId),
|
|
241
|
+
false,
|
|
242
|
+
);
|
|
243
|
+
});
|
|
244
|
+
});
|
|
@@ -1,73 +1,73 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { mkdtemp, rm } from 'node:fs/promises';
|
|
3
|
-
import { tmpdir } from 'node:os';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import test from 'node:test';
|
|
6
|
-
|
|
7
|
-
import { closeConnection, initializeDatabase, projectsDb, sessionsDb } from '@/modules/database/index.js';
|
|
8
|
-
import { sessionsService } from '@/modules/providers/services/sessions.service.js';
|
|
9
|
-
import { AppError, normalizeProjectPath } from '@/shared/utils.js';
|
|
10
|
-
|
|
11
|
-
async function withIsolatedDatabase(runTest: () => void | Promise<void>): Promise<void> {
|
|
12
|
-
const previousDatabasePath = process.env.DATABASE_PATH;
|
|
13
|
-
const tempDirectory = await mkdtemp(path.join(tmpdir(), 'sessions-details-'));
|
|
14
|
-
const databasePath = path.join(tempDirectory, 'auth.db');
|
|
15
|
-
|
|
16
|
-
closeConnection();
|
|
17
|
-
process.env.DATABASE_PATH = databasePath;
|
|
18
|
-
await initializeDatabase();
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
await runTest();
|
|
22
|
-
} finally {
|
|
23
|
-
closeConnection();
|
|
24
|
-
if (previousDatabasePath === undefined) {
|
|
25
|
-
delete process.env.DATABASE_PATH;
|
|
26
|
-
} else {
|
|
27
|
-
process.env.DATABASE_PATH = previousDatabasePath;
|
|
28
|
-
}
|
|
29
|
-
await rm(tempDirectory, { recursive: true, force: true });
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
test('getSessionDetailsById resolves the owning project for a disk-indexed session', async () => {
|
|
34
|
-
await withIsolatedDatabase(() => {
|
|
35
|
-
const projectPath = '/home/user/example-project';
|
|
36
|
-
const sessionId = sessionsDb.createSession('provider-abc', 'claude', projectPath, 'My session');
|
|
37
|
-
const projectRow = projectsDb.getProjectPath(projectPath);
|
|
38
|
-
assert.ok(projectRow, 'project row should exist after createSession');
|
|
39
|
-
|
|
40
|
-
const details = sessionsService.getSessionDetailsById(sessionId);
|
|
41
|
-
|
|
42
|
-
assert.equal(details.sessionId, sessionId);
|
|
43
|
-
assert.equal(details.provider, 'claude');
|
|
44
|
-
assert.equal(details.summary, 'My session');
|
|
45
|
-
assert.equal(details.isArchived, false);
|
|
46
|
-
assert.ok(details.project, 'project should be resolved');
|
|
47
|
-
assert.equal(details.project?.projectId, projectRow?.project_id);
|
|
48
|
-
// Paths are normalized to platform separators when stored.
|
|
49
|
-
assert.equal(details.project?.fullPath, normalizeProjectPath(projectPath));
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('getSessionDetailsById falls back to the provider-native id and returns the canonical app id', async () => {
|
|
54
|
-
await withIsolatedDatabase(() => {
|
|
55
|
-
const projectPath = '/home/user/alias-project';
|
|
56
|
-
const appSessionId = sessionsDb.createAppSession('app-session-1', 'claude', projectPath);
|
|
57
|
-
sessionsDb.assignProviderSessionId(appSessionId, 'provider-native-1');
|
|
58
|
-
|
|
59
|
-
const details = sessionsService.getSessionDetailsById('provider-native-1');
|
|
60
|
-
|
|
61
|
-
assert.equal(details.sessionId, appSessionId);
|
|
62
|
-
assert.equal(details.project?.fullPath, normalizeProjectPath(projectPath));
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('getSessionDetailsById throws SESSION_NOT_FOUND for unknown ids', async () => {
|
|
67
|
-
await withIsolatedDatabase(() => {
|
|
68
|
-
assert.throws(
|
|
69
|
-
() => sessionsService.getSessionDetailsById('does-not-exist'),
|
|
70
|
-
(error: unknown) => error instanceof AppError && error.code === 'SESSION_NOT_FOUND',
|
|
71
|
-
);
|
|
72
|
-
});
|
|
73
|
-
});
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
|
|
7
|
+
import { closeConnection, initializeDatabase, projectsDb, sessionsDb } from '@/modules/database/index.js';
|
|
8
|
+
import { sessionsService } from '@/modules/providers/services/sessions.service.js';
|
|
9
|
+
import { AppError, normalizeProjectPath } from '@/shared/utils.js';
|
|
10
|
+
|
|
11
|
+
async function withIsolatedDatabase(runTest: () => void | Promise<void>): Promise<void> {
|
|
12
|
+
const previousDatabasePath = process.env.DATABASE_PATH;
|
|
13
|
+
const tempDirectory = await mkdtemp(path.join(tmpdir(), 'sessions-details-'));
|
|
14
|
+
const databasePath = path.join(tempDirectory, 'auth.db');
|
|
15
|
+
|
|
16
|
+
closeConnection();
|
|
17
|
+
process.env.DATABASE_PATH = databasePath;
|
|
18
|
+
await initializeDatabase();
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
await runTest();
|
|
22
|
+
} finally {
|
|
23
|
+
closeConnection();
|
|
24
|
+
if (previousDatabasePath === undefined) {
|
|
25
|
+
delete process.env.DATABASE_PATH;
|
|
26
|
+
} else {
|
|
27
|
+
process.env.DATABASE_PATH = previousDatabasePath;
|
|
28
|
+
}
|
|
29
|
+
await rm(tempDirectory, { recursive: true, force: true });
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
test('getSessionDetailsById resolves the owning project for a disk-indexed session', async () => {
|
|
34
|
+
await withIsolatedDatabase(() => {
|
|
35
|
+
const projectPath = '/home/user/example-project';
|
|
36
|
+
const sessionId = sessionsDb.createSession('provider-abc', 'claude', projectPath, 'My session');
|
|
37
|
+
const projectRow = projectsDb.getProjectPath(projectPath);
|
|
38
|
+
assert.ok(projectRow, 'project row should exist after createSession');
|
|
39
|
+
|
|
40
|
+
const details = sessionsService.getSessionDetailsById(sessionId);
|
|
41
|
+
|
|
42
|
+
assert.equal(details.sessionId, sessionId);
|
|
43
|
+
assert.equal(details.provider, 'claude');
|
|
44
|
+
assert.equal(details.summary, 'My session');
|
|
45
|
+
assert.equal(details.isArchived, false);
|
|
46
|
+
assert.ok(details.project, 'project should be resolved');
|
|
47
|
+
assert.equal(details.project?.projectId, projectRow?.project_id);
|
|
48
|
+
// Paths are normalized to platform separators when stored.
|
|
49
|
+
assert.equal(details.project?.fullPath, normalizeProjectPath(projectPath));
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test('getSessionDetailsById falls back to the provider-native id and returns the canonical app id', async () => {
|
|
54
|
+
await withIsolatedDatabase(() => {
|
|
55
|
+
const projectPath = '/home/user/alias-project';
|
|
56
|
+
const appSessionId = sessionsDb.createAppSession('app-session-1', 'claude', projectPath);
|
|
57
|
+
sessionsDb.assignProviderSessionId(appSessionId, 'provider-native-1');
|
|
58
|
+
|
|
59
|
+
const details = sessionsService.getSessionDetailsById('provider-native-1');
|
|
60
|
+
|
|
61
|
+
assert.equal(details.sessionId, appSessionId);
|
|
62
|
+
assert.equal(details.project?.fullPath, normalizeProjectPath(projectPath));
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('getSessionDetailsById throws SESSION_NOT_FOUND for unknown ids', async () => {
|
|
67
|
+
await withIsolatedDatabase(() => {
|
|
68
|
+
assert.throws(
|
|
69
|
+
() => sessionsService.getSessionDetailsById('does-not-exist'),
|
|
70
|
+
(error: unknown) => error instanceof AppError && error.code === 'SESSION_NOT_FOUND',
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
});
|