@cloudcli-ai/cloudcli 1.37.2 → 1.37.4
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/README.md +269 -0
- package/dist/assets/{abnfDiagram-N423BO3Z-C4UAoHJb.js → abnfDiagram-N423BO3Z-Dmkwx38H.js} +1 -1
- package/dist/assets/{arc-B8jF-ja9.js → arc-DLe9AYuO.js} +1 -1
- package/dist/assets/{architectureDiagram-T3A2C74G-C_Wur_CU.js → architectureDiagram-T3A2C74G-CBbbbNUW.js} +1 -1
- package/dist/assets/{blockDiagram-VBNYF7ZC-Cq4P1i8t.js → blockDiagram-VBNYF7ZC-CaMEaWu4.js} +1 -1
- package/dist/assets/{c4Diagram-5PPSVZJV-C1wG4eUj.js → c4Diagram-5PPSVZJV-DhjMgNnR.js} +1 -1
- package/dist/assets/channel-CWrmwsir.js +1 -0
- package/dist/assets/{chunk-2GRJ4B5K-B8fnBG6E.js → chunk-2GRJ4B5K-yjl3-F-i.js} +1 -1
- package/dist/assets/{chunk-2Q5K7J3B-WdfPooPJ.js → chunk-2Q5K7J3B-DsAYaWEP.js} +1 -1
- package/dist/assets/{chunk-5RXB4S5H-DhZJuG2E.js → chunk-5RXB4S5H-Bt5qmqOX.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-B0rjslal.js → chunk-5VM5RSS4-yWrWVvUt.js} +1 -1
- package/dist/assets/{chunk-6Q2QTUOP-CG2Oj4jL.js → chunk-6Q2QTUOP-Dt66K5xb.js} +1 -1
- package/dist/assets/{chunk-GF5L2VYU-rrl2lRxY.js → chunk-GF5L2VYU-DA0vzaj4.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-CjVbrVMA.js → chunk-JWPE2WC7-CUkbx96V.js} +1 -1
- package/dist/assets/{chunk-KBJHAD2P-CRzKgU8S.js → chunk-KBJHAD2P-DWKxx1WH.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-DBz4GTZF.js → chunk-RYQCIY6F-BqluplN0.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-wHxalsXk.js → chunk-XXDRQBXY-DelKg3Xf.js} +1 -1
- package/dist/assets/classDiagram-JCYQIIEL-COAGCC6w.js +1 -0
- package/dist/assets/classDiagram-v2-OCEON4UE-COAGCC6w.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-s1hygY8e.js → cose-bilkent-JH36ORCC-DHV93-Em.js} +1 -1
- package/dist/assets/{cynefin-VYW2F7L2-C4LGV15i.js → cynefin-VYW2F7L2-B9HZgoGX.js} +1 -1
- package/dist/assets/{cynefinDiagram-MW4NZA55-C5uhu7B3.js → cynefinDiagram-MW4NZA55-hFjjEQg8.js} +1 -1
- package/dist/assets/{dagre-VZM6K2ZE-B-OBTewm.js → dagre-VZM6K2ZE-CpeVOC7V.js} +1 -1
- package/dist/assets/{diagram-7IWD3JNH-BjGKQxih.js → diagram-7IWD3JNH-D0H1UoRA.js} +1 -1
- package/dist/assets/{diagram-B4RE2ZJO-BMKz1X2L.js → diagram-B4RE2ZJO-6Y7BQUup.js} +1 -1
- package/dist/assets/{diagram-LBJQPF4R-DNh-GhKC.js → diagram-LBJQPF4R-C0nNOwht.js} +1 -1
- package/dist/assets/{diagram-Q27KOJAE-BaTG9jPT.js → diagram-Q27KOJAE-En6QlOVX.js} +1 -1
- package/dist/assets/{diagram-UB23O5K3-BUwo2OvJ.js → diagram-UB23O5K3-CmPiNeGD.js} +1 -1
- package/dist/assets/{ebnfDiagram-BXEA7PRR-DAZgfzX2.js → ebnfDiagram-BXEA7PRR-Bygzp1Qt.js} +1 -1
- package/dist/assets/{erDiagram-JOGREHBK-1w1CcGEb.js → erDiagram-JOGREHBK-CwScRfzl.js} +1 -1
- package/dist/assets/{flowDiagram-UKHOOZJN-D4EII8Jj.js → flowDiagram-UKHOOZJN-bKX-0xP6.js} +1 -1
- package/dist/assets/{ganttDiagram-PKOTCBZU-ChvJZAgB.js → ganttDiagram-PKOTCBZU-DtZPKXGd.js} +1 -1
- package/dist/assets/{gitGraphDiagram-DS77QQ5N-DtOn41S8.js → gitGraphDiagram-DS77QQ5N-CUOtdL1o.js} +1 -1
- package/dist/assets/index-CdjIFxM2.js +5004 -0
- package/dist/assets/index-DgafhGTF.css +32 -0
- package/dist/assets/{infoDiagram-6WML65LV-DN_PVEJZ.js → infoDiagram-6WML65LV-ciRQTS0h.js} +1 -1
- package/dist/assets/{ishikawaDiagram-WSZJBQD7-DbkF1kXb.js → ishikawaDiagram-WSZJBQD7-CgjhQZ84.js} +1 -1
- package/dist/assets/{journeyDiagram-NVQOT4AX-pJwmhddE.js → journeyDiagram-NVQOT4AX-BsbQSeIW.js} +1 -1
- package/dist/assets/{kanban-definition-27J2QSJJ-PPAPgNp5.js → kanban-definition-27J2QSJJ-CrwzY9Jw.js} +1 -1
- package/dist/assets/{linear-iPR-J9f7.js → linear-BUaCDr6l.js} +1 -1
- package/dist/assets/{mermaid.core-BEUL86Z6.js → mermaid.core-ClgdUU0j.js} +5 -5
- package/dist/assets/{mindmap-definition-FAOFIHXS-BvZoBib7.js → mindmap-definition-FAOFIHXS-BictljY1.js} +1 -1
- package/dist/assets/{pegDiagram-VL7TDLO6-DhYreaUd.js → pegDiagram-VL7TDLO6-BXdByy_U.js} +1 -1
- package/dist/assets/{pieDiagram-7S7Q4E2Y-CrOHlyD0.js → pieDiagram-7S7Q4E2Y-uZsMfkRX.js} +1 -1
- package/dist/assets/{quadrantDiagram-CIZ2JOQS-D4g5yH3t.js → quadrantDiagram-CIZ2JOQS-7lCv4QIj.js} +1 -1
- package/dist/assets/{railroadDiagram-AXF67PYL-Dj39lHlf.js → railroadDiagram-AXF67PYL-07dxIWbi.js} +1 -1
- package/dist/assets/{requirementDiagram-LRYGKXZP-1AS4Zgm_.js → requirementDiagram-LRYGKXZP-Cb31Yv1_.js} +1 -1
- package/dist/assets/{sankeyDiagram-W5VNT64P-CKlMn19P.js → sankeyDiagram-W5VNT64P-X0YPSyF9.js} +1 -1
- package/dist/assets/{sequenceDiagram-SI44F4Z6-B_j3qyvo.js → sequenceDiagram-SI44F4Z6-BdBxSIlP.js} +1 -1
- package/dist/assets/server.browser-CtX3Hdl5.js +27 -0
- package/dist/assets/{sizeCapture-X5ZJPWSS-Bp2Op16v.js → sizeCapture-X5ZJPWSS-DQM5xAyD.js} +1 -1
- package/dist/assets/{stateDiagram-OKZ733FA-C0cN6DoY.js → stateDiagram-OKZ733FA-DJ3xkLUF.js} +1 -1
- package/dist/assets/stateDiagram-v2-UEYNNEHI-vAaE4zNo.js +1 -0
- package/dist/assets/{swimlanes-SLNWSIFB-BEvXOV9b.js → swimlanes-SLNWSIFB-rjfYdW0w.js} +2 -2
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-TV2IF4Nq.js +8 -0
- package/dist/assets/{timeline-definition-Z64GVDOM-zdJQinvZ.js → timeline-definition-Z64GVDOM-DZMra5do.js} +1 -1
- package/dist/assets/{vendor-codemirror-OwyKSvPE.js → vendor-codemirror-CYrSt7-U.js} +18 -18
- package/dist/assets/{vennDiagram-T6HMQDX7-DuF1uZMY.js → vennDiagram-T6HMQDX7-BevD8uu0.js} +1 -1
- package/dist/assets/{wardleyDiagram-T6FBY63Y-B9AlLQup.js → wardleyDiagram-T6FBY63Y-DsIyXB7z.js} +1 -1
- package/dist/assets/{xychartDiagram-ELKLHX3M-DTJX48Qg.js → xychartDiagram-ELKLHX3M-G3PlF3ko.js} +1 -1
- package/dist/index.html +3 -3
- package/dist-server/server/index.js +11 -4
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/agent/agent.module.js +9 -2
- package/dist-server/server/modules/agent/agent.module.js.map +1 -1
- package/dist-server/server/modules/agent/agent.routes.js +177 -130
- package/dist-server/server/modules/agent/agent.routes.js.map +1 -1
- package/dist-server/server/modules/agent/tests/agent-run-registration.test.js +306 -0
- package/dist-server/server/modules/agent/tests/agent-run-registration.test.js.map +1 -0
- package/dist-server/server/modules/agent/tests/agent.routes.test.js +48 -2
- package/dist-server/server/modules/agent/tests/agent.routes.test.js.map +1 -1
- package/dist-server/server/modules/browser-use/browser-use.routes.js +39 -33
- package/dist-server/server/modules/browser-use/browser-use.routes.js.map +1 -1
- package/dist-server/server/modules/database/connection.js +1 -1
- package/dist-server/server/modules/database/connection.js.map +1 -1
- package/dist-server/server/modules/database/index.js +5 -0
- package/dist-server/server/modules/database/index.js.map +1 -1
- package/dist-server/server/modules/database/migrations.js +45 -1
- package/dist-server/server/modules/database/migrations.js.map +1 -1
- package/dist-server/server/modules/database/repositories/provider-models.js +60 -6
- package/dist-server/server/modules/database/repositories/provider-models.js.map +1 -1
- package/dist-server/server/modules/database/repositories/scheduled-messages.db.js +71 -0
- package/dist-server/server/modules/database/repositories/scheduled-messages.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/session-drafts.db.js +105 -0
- package/dist-server/server/modules/database/repositories/session-drafts.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/sessions.db.js +144 -5
- package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
- package/dist-server/server/modules/database/repositories/user-preferences.db.js +65 -0
- package/dist-server/server/modules/database/repositories/user-preferences.db.js.map +1 -0
- package/dist-server/server/modules/database/schema.js +99 -0
- package/dist-server/server/modules/database/schema.js.map +1 -1
- package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js +99 -0
- package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js.map +1 -1
- package/dist-server/server/modules/database/tests/sessions.db.integration.test.js +39 -0
- package/dist-server/server/modules/database/tests/sessions.db.integration.test.js.map +1 -1
- package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js +105 -0
- package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js.map +1 -0
- package/dist-server/server/modules/file-tree/file-tree.module.js +2 -1
- package/dist-server/server/modules/file-tree/file-tree.module.js.map +1 -1
- package/dist-server/server/modules/file-tree/file-tree.service.js +44 -7
- package/dist-server/server/modules/file-tree/file-tree.service.js.map +1 -1
- package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js +126 -1
- package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js.map +1 -1
- package/dist-server/server/modules/git/git-branch-diff.service.js +142 -0
- package/dist-server/server/modules/git/git-branch-diff.service.js.map +1 -0
- package/dist-server/server/modules/git/git-branch.service.js.map +1 -1
- package/dist-server/server/modules/git/git.routes.js +92 -5
- package/dist-server/server/modules/git/git.routes.js.map +1 -1
- package/dist-server/server/modules/git/tests/git-branch-diff.service.test.js +160 -0
- package/dist-server/server/modules/git/tests/git-branch-diff.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/project-clone.routes.js +108 -0
- package/dist-server/server/modules/projects/project-clone.routes.js.map +1 -0
- package/dist-server/server/modules/projects/projects.routes.js +13 -66
- package/dist-server/server/modules/projects/projects.routes.js.map +1 -1
- package/dist-server/server/modules/projects/services/project-clone-request.service.js +36 -0
- package/dist-server/server/modules/projects/services/project-clone-request.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-clone.service.js +86 -32
- package/dist-server/server/modules/projects/services/project-clone.service.js.map +1 -1
- package/dist-server/server/modules/projects/services/project-delete.service.js +12 -1
- package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -1
- package/dist-server/server/modules/projects/services/project-star.service.js +2 -2
- package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -1
- package/dist-server/server/modules/projects/tests/project-clone.routes.test.js +191 -0
- package/dist-server/server/modules/projects/tests/project-clone.routes.test.js.map +1 -0
- package/dist-server/server/modules/projects/tests/project-clone.service.test.js +275 -0
- package/dist-server/server/modules/projects/tests/project-clone.service.test.js.map +1 -1
- package/dist-server/server/modules/providers/index.js +3 -0
- package/dist-server/server/modules/providers/index.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +62 -9
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js +46 -0
- package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +31 -12
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js +472 -53
- package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +38 -11
- package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +1007 -60
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +4 -1
- package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js +204 -0
- package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js +32 -0
- package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +47 -0
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js +71 -53
- package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +8 -0
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +1621 -431
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +9 -2
- package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js +16 -8
- package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +274 -9
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js +5 -2
- package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +19 -2
- package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/provider.routes.js +134 -2
- package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
- package/dist-server/server/modules/providers/services/claude-cli-liveness.service.js +100 -0
- package/dist-server/server/modules/providers/services/claude-cli-liveness.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/claude-settings-permissions.service.js +97 -0
- package/dist-server/server/modules/providers/services/claude-settings-permissions.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/provider-capabilities.service.js +23 -1
- package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-models.service.js +59 -5
- package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-runtime.service.js +8 -0
- package/dist-server/server/modules/providers/services/provider-runtime.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-token-usage.service.js +139 -35
- package/dist-server/server/modules/providers/services/provider-token-usage.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js +2 -4
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/session-history-cache.service.js +91 -0
- package/dist-server/server/modules/providers/services/session-history-cache.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js +105 -32
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js +3 -60
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/sessions.service.js +252 -12
- package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
- package/dist-server/server/modules/providers/tests/claude-auth.test.js +183 -0
- package/dist-server/server/modules/providers/tests/claude-auth.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/claude-background-work.test.js +172 -0
- package/dist-server/server/modules/providers/tests/claude-background-work.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-compaction.test.js +84 -0
- package/dist-server/server/modules/providers/tests/claude-compaction.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-message-model.test.js +123 -0
- package/dist-server/server/modules/providers/tests/claude-message-model.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-models.test.js +39 -0
- package/dist-server/server/modules/providers/tests/claude-models.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-runtime-hold.test.js +265 -0
- package/dist-server/server/modules/providers/tests/claude-runtime-hold.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-sessions.test.js +1815 -33
- package/dist-server/server/modules/providers/tests/claude-sessions.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/claude-settings-permissions.test.js +228 -0
- package/dist-server/server/modules/providers/tests/claude-settings-permissions.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js +16 -0
- package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-token-budget.test.js +85 -0
- package/dist-server/server/modules/providers/tests/claude-token-budget.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-message-editing.test.js +338 -0
- package/dist-server/server/modules/providers/tests/codex-message-editing.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-models.test.js +25 -0
- package/dist-server/server/modules/providers/tests/codex-models.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-runtime.test.js +83 -0
- package/dist-server/server/modules/providers/tests/codex-runtime.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-session-fork.test.js +54 -0
- package/dist-server/server/modules/providers/tests/codex-session-fork.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js +354 -15
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/cursor-auth.test.js +167 -0
- package/dist-server/server/modules/providers/tests/cursor-auth.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/opencode-models.test.js +196 -4
- package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +19 -1
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/provider-capabilities.service.test.js +30 -0
- package/dist-server/server/modules/providers/tests/provider-capabilities.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/provider-models.service.test.js +79 -1
- package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +164 -1
- package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/provider.routes.test.js +190 -1
- package/dist-server/server/modules/providers/tests/provider.routes.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/session-fork.test.js +113 -0
- package/dist-server/server/modules/providers/tests/session-fork.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js +139 -0
- package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js +90 -0
- package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js +122 -0
- package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/sessions.service.test.js +219 -1
- package/dist-server/server/modules/providers/tests/sessions.service.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/skills.test.js +15 -3
- package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
- package/dist-server/server/modules/scheduled-messages/index.js +5 -0
- package/dist-server/server/modules/scheduled-messages/index.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js +47 -0
- package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js +175 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js +95 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js +290 -0
- package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js.map +1 -0
- package/dist-server/server/modules/taskmaster/taskmaster.routes.js +23 -23
- package/dist-server/server/modules/taskmaster/taskmaster.routes.js.map +1 -1
- package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js +48 -0
- package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js.map +1 -1
- package/dist-server/server/modules/user/tests/user.service.test.js +70 -0
- package/dist-server/server/modules/user/tests/user.service.test.js.map +1 -1
- package/dist-server/server/modules/user/user.module.js +10 -1
- package/dist-server/server/modules/user/user.module.js.map +1 -1
- package/dist-server/server/modules/user/user.routes.js +44 -0
- package/dist-server/server/modules/user/user.routes.js.map +1 -1
- package/dist-server/server/modules/user/user.service.js +75 -0
- package/dist-server/server/modules/user/user.service.js.map +1 -1
- package/dist-server/server/modules/voice/tests/voice.service.test.js +3 -2
- package/dist-server/server/modules/voice/tests/voice.service.test.js.map +1 -1
- package/dist-server/server/modules/websocket/index.js +7 -0
- package/dist-server/server/modules/websocket/index.js.map +1 -1
- package/dist-server/server/modules/websocket/services/chat-run-registry.service.js +37 -49
- package/dist-server/server/modules/websocket/services/chat-run-registry.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +35 -5
- package/dist-server/server/modules/websocket/services/chat-session-writer.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js +204 -10
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js +94 -0
- package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js +236 -20
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
- package/dist-server/server/modules/websocket/tests/chat-background-subscribe.test.js +137 -0
- package/dist-server/server/modules/websocket/tests/chat-background-subscribe.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js +263 -0
- package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js +29 -3
- package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js.map +1 -1
- package/dist-server/server/modules/websocket/tests/chat-stop-task.test.js +96 -0
- package/dist-server/server/modules/websocket/tests/chat-stop-task.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js +106 -0
- package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js +500 -0
- package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js.map +1 -1
- package/dist-server/server/shared/claude-cli-path.js +22 -5
- package/dist-server/server/shared/claude-cli-path.js.map +1 -1
- package/dist-server/server/shared/index.js +3 -0
- package/dist-server/server/shared/index.js.map +1 -0
- package/dist-server/server/shared/message-unification.js +376 -0
- package/dist-server/server/shared/message-unification.js.map +1 -0
- package/dist-server/server/shared/tests/claude-cli-path.test.js +45 -1
- package/dist-server/server/shared/tests/claude-cli-path.test.js.map +1 -1
- package/dist-server/server/shared/tests/message-unification.test.js +174 -0
- package/dist-server/server/shared/tests/message-unification.test.js.map +1 -0
- package/dist-server/server/shared/tests/read-only-roots.test.js +124 -0
- package/dist-server/server/shared/tests/read-only-roots.test.js.map +1 -0
- package/dist-server/server/shared/tests/strip-ansi-sequences.test.js +31 -0
- package/dist-server/server/shared/tests/strip-ansi-sequences.test.js.map +1 -0
- package/dist-server/server/shared/utils.js +160 -0
- package/dist-server/server/shared/utils.js.map +1 -1
- package/electron/desktopWindow.js +6 -0
- package/electron/viewHost.js +25 -2
- package/package.json +20 -17
- package/server/index.ts +16 -5
- package/server/modules/agent/agent.module.ts +11 -1
- package/server/modules/agent/agent.routes.ts +200 -142
- package/server/modules/agent/tests/agent-run-registration.test.ts +348 -0
- package/server/modules/agent/tests/agent.routes.test.ts +51 -2
- package/server/modules/browser-use/browser-use.routes.ts +96 -33
- package/server/modules/database/connection.ts +2 -1
- package/server/modules/database/index.ts +10 -0
- package/server/modules/database/migrations.ts +51 -0
- package/server/modules/database/repositories/provider-models.ts +79 -6
- package/server/modules/database/repositories/scheduled-messages.db.ts +127 -0
- package/server/modules/database/repositories/session-drafts.db.ts +171 -0
- package/server/modules/database/repositories/sessions.db.ts +204 -3
- package/server/modules/database/repositories/user-preferences.db.ts +80 -0
- package/server/modules/database/schema.ts +103 -0
- package/server/modules/database/tests/provider-models.db.integration.test.ts +113 -0
- package/server/modules/database/tests/sessions.db.integration.test.ts +52 -0
- package/server/modules/database/tests/user-preferences.db.integration.test.ts +135 -0
- package/server/modules/file-tree/file-tree.module.ts +2 -1
- package/server/modules/file-tree/file-tree.service.ts +49 -7
- package/server/modules/file-tree/tests/file-tree.service.test.ts +163 -1
- package/server/modules/git/git-branch-diff.service.ts +204 -0
- package/server/modules/git/git-branch.service.ts +2 -12
- package/server/modules/git/git.routes.ts +100 -6
- package/server/modules/git/tests/git-branch-diff.service.test.ts +210 -0
- package/server/modules/projects/project-clone.routes.ts +142 -0
- package/server/modules/projects/projects.routes.ts +16 -81
- package/server/modules/projects/services/project-clone-request.service.ts +56 -0
- package/server/modules/projects/services/project-clone.service.ts +102 -34
- package/server/modules/projects/services/project-delete.service.ts +13 -1
- package/server/modules/projects/services/project-star.service.ts +2 -2
- package/server/modules/projects/tests/project-clone.routes.test.ts +246 -0
- package/server/modules/projects/tests/project-clone.service.test.ts +376 -0
- package/server/modules/providers/index.ts +4 -0
- package/server/modules/providers/list/claude/claude-auth.provider.ts +81 -11
- package/server/modules/providers/list/claude/claude-fork.provider.ts +57 -0
- package/server/modules/providers/list/claude/claude-models.provider.ts +37 -17
- package/server/modules/providers/list/claude/claude-runtime.provider.js +510 -54
- package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +40 -14
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +1195 -63
- package/server/modules/providers/list/claude/claude-skills.provider.ts +4 -1
- package/server/modules/providers/list/claude/claude.provider.ts +3 -0
- package/server/modules/providers/list/codex/codex-app-server.client.ts +243 -0
- package/server/modules/providers/list/codex/codex-fork.provider.ts +40 -0
- package/server/modules/providers/list/codex/codex-models.provider.ts +47 -0
- package/server/modules/providers/list/codex/{codex-runtime.provider.js → codex-runtime.provider.ts} +105 -70
- package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +9 -0
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +1847 -455
- package/server/modules/providers/list/codex/codex.provider.ts +3 -0
- package/server/modules/providers/list/cursor/cursor-auth.provider.ts +10 -2
- package/server/modules/providers/list/cursor/cursor-runtime.provider.js +17 -8
- package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +0 -1
- package/server/modules/providers/list/opencode/opencode-models.provider.ts +297 -9
- package/server/modules/providers/list/opencode/opencode-runtime.provider.js +5 -2
- package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +30 -2
- package/server/modules/providers/provider.routes.ts +162 -2
- package/server/modules/providers/services/claude-cli-liveness.service.ts +121 -0
- package/server/modules/providers/services/claude-settings-permissions.service.ts +127 -0
- package/server/modules/providers/services/provider-capabilities.service.ts +40 -1
- package/server/modules/providers/services/provider-models.service.ts +71 -4
- package/server/modules/providers/services/provider-runtime.service.ts +11 -0
- package/server/modules/providers/services/provider-token-usage.service.ts +166 -39
- package/server/modules/providers/services/session-conversations-search.service.ts +2 -5
- package/server/modules/providers/services/session-history-cache.service.ts +150 -0
- package/server/modules/providers/services/session-synchronizer.service.ts +125 -38
- package/server/modules/providers/services/sessions-watcher.service.ts +3 -64
- package/server/modules/providers/services/sessions.service.ts +309 -17
- package/server/modules/providers/tests/claude-auth.test.ts +208 -0
- package/server/modules/providers/tests/claude-background-work.test.ts +213 -0
- package/server/modules/providers/tests/claude-compaction.test.ts +101 -0
- package/server/modules/providers/tests/claude-message-model.test.ts +160 -0
- package/server/modules/providers/tests/claude-models.test.ts +87 -0
- package/server/modules/providers/tests/claude-runtime-hold.test.ts +309 -0
- package/server/modules/providers/tests/claude-sessions.test.ts +2167 -37
- package/server/modules/providers/tests/claude-settings-permissions.test.ts +271 -0
- package/server/modules/providers/tests/claude-subagent-echo.test.ts +25 -0
- package/server/modules/providers/tests/claude-token-budget.test.ts +104 -0
- package/server/modules/providers/tests/codex-message-editing.test.ts +419 -0
- package/server/modules/providers/tests/codex-models.test.ts +37 -0
- package/server/modules/providers/tests/codex-runtime.test.ts +94 -0
- package/server/modules/providers/tests/codex-session-fork.test.ts +59 -0
- package/server/modules/providers/tests/codex-sessions.test.ts +396 -15
- package/server/modules/providers/tests/cursor-auth.test.ts +187 -0
- package/server/modules/providers/tests/opencode-models.test.ts +266 -8
- package/server/modules/providers/tests/opencode-sessions.test.ts +40 -1
- package/server/modules/providers/tests/provider-capabilities.service.test.ts +37 -0
- package/server/modules/providers/tests/provider-models.service.test.ts +99 -1
- package/server/modules/providers/tests/provider-token-usage.service.test.ts +188 -1
- package/server/modules/providers/tests/provider.routes.test.ts +230 -1
- package/server/modules/providers/tests/session-fork.test.ts +173 -0
- package/server/modules/providers/tests/session-history-cache.service.test.ts +165 -0
- package/server/modules/providers/tests/session-orphan-prune.test.ts +107 -0
- package/server/modules/providers/tests/session-synchronizer-coalescing.test.ts +136 -0
- package/server/modules/providers/tests/sessions.service.test.ts +303 -1
- package/server/modules/providers/tests/skills.test.ts +21 -5
- package/server/modules/scheduled-messages/index.ts +8 -0
- package/server/modules/scheduled-messages/scheduled-messages.routes.ts +68 -0
- package/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.ts +216 -0
- package/server/modules/scheduled-messages/services/scheduled-messages.service.ts +121 -0
- package/server/modules/scheduled-messages/tests/scheduled-messages.test.ts +354 -0
- package/server/modules/taskmaster/taskmaster.routes.ts +23 -33
- package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +57 -0
- package/server/modules/user/tests/user.service.test.ts +90 -0
- package/server/modules/user/user.module.ts +10 -1
- package/server/modules/user/user.routes.ts +44 -0
- package/server/modules/user/user.service.ts +105 -0
- package/server/modules/voice/tests/voice.service.test.ts +3 -2
- package/server/modules/websocket/README.md +4 -2
- package/server/modules/websocket/index.ts +8 -0
- package/server/modules/websocket/services/chat-run-registry.service.ts +45 -54
- package/server/modules/websocket/services/chat-session-writer.service.ts +36 -6
- package/server/modules/websocket/services/chat-websocket.service.ts +302 -16
- package/server/modules/websocket/services/session-upsert-broadcast.service.ts +108 -0
- package/server/modules/websocket/services/shell-websocket.service.ts +276 -22
- package/server/modules/websocket/tests/chat-background-subscribe.test.ts +167 -0
- package/server/modules/websocket/tests/chat-edit-send.test.ts +309 -0
- package/server/modules/websocket/tests/chat-run-registry.test.ts +34 -3
- package/server/modules/websocket/tests/chat-stop-task.test.ts +127 -0
- package/server/modules/websocket/tests/session-upsert-broadcast.test.ts +138 -0
- package/server/modules/websocket/tests/shell-websocket.service.test.ts +629 -0
- package/server/shared/claude-cli-path.ts +24 -6
- package/server/shared/index.ts +3 -0
- package/server/shared/interfaces.ts +91 -0
- package/server/shared/message-unification.ts +449 -0
- package/server/shared/tests/claude-cli-path.test.ts +58 -1
- package/server/shared/tests/message-unification.test.ts +218 -0
- package/server/shared/tests/read-only-roots.test.ts +139 -0
- package/server/shared/tests/strip-ansi-sequences.test.ts +42 -0
- package/server/shared/types.ts +382 -7
- package/server/shared/utils.ts +176 -0
- package/dist/assets/channel-_falYbU1.js +0 -1
- package/dist/assets/classDiagram-JCYQIIEL-Dn-3CfpR.js +0 -1
- package/dist/assets/classDiagram-v2-OCEON4UE-Dn-3CfpR.js +0 -1
- package/dist/assets/index-CzPLBvXT.css +0 -32
- package/dist/assets/index-DFkBBuSA.js +0 -1549
- package/dist/assets/stateDiagram-v2-UEYNNEHI-BvBxUUrZ.js +0 -1
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-CsE-x4YK.js +0 -8
|
@@ -3,7 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import type { WebSocket } from 'ws';
|
|
4
4
|
|
|
5
5
|
import { sessionsDb } from '@/modules/database/index.js';
|
|
6
|
-
import { providerModelsService } from '@/modules/providers/index.js';
|
|
6
|
+
import { providerModelsService, sessionsService } from '@/modules/providers/index.js';
|
|
7
7
|
import { chatRunRegistry } from '@/modules/websocket/services/chat-run-registry.service.js';
|
|
8
8
|
import { connectedClients, WS_OPEN_STATE } from '@/modules/websocket/services/websocket-state.service.js';
|
|
9
9
|
import {
|
|
@@ -64,7 +64,7 @@ export function filterImagesToUploadStore(
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
/** Application boundary for dispatching provider runs and approvals. */
|
|
67
|
-
type ProviderRuntimeGateway = {
|
|
67
|
+
export type ProviderRuntimeGateway = {
|
|
68
68
|
hasRuntime(provider: string): boolean;
|
|
69
69
|
run(
|
|
70
70
|
provider: LLMProvider,
|
|
@@ -73,6 +73,9 @@ type ProviderRuntimeGateway = {
|
|
|
73
73
|
writer: ProviderRuntimeWriter,
|
|
74
74
|
): Promise<unknown>;
|
|
75
75
|
abort(provider: LLMProvider, sessionId: string): Promise<boolean>;
|
|
76
|
+
stopBackgroundTask(provider: LLMProvider, sessionId: string, taskId: string): Promise<boolean>;
|
|
77
|
+
/** Whether a provider runtime still holds background work for the session after its turn ended. */
|
|
78
|
+
hasBackgroundWork(sessionId: string): boolean;
|
|
76
79
|
resolveToolApproval(requestId: string, payload: ProviderPermissionDecision): void;
|
|
77
80
|
getPendingApprovalsForSession(sessionId: string): unknown[];
|
|
78
81
|
};
|
|
@@ -149,10 +152,34 @@ async function handleChatSend(
|
|
|
149
152
|
data: AnyRecord,
|
|
150
153
|
dependencies: ChatWebSocketDependencies
|
|
151
154
|
): Promise<void> {
|
|
155
|
+
const resolved = resolveSendTarget(ws, data, dependencies, 'chat.send');
|
|
156
|
+
if (!resolved) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
await dispatchRun(ws, userId, resolved.sessionId, resolved.session, data, dependencies);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
type ResolvedSendTarget = {
|
|
164
|
+
sessionId: string;
|
|
165
|
+
session: NonNullable<ReturnType<typeof sessionsDb.getSessionById>>;
|
|
166
|
+
provider: LLMProvider;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Shared front half of `chat.send` and `chat.edit-send`: the session row and
|
|
171
|
+
* provider come from the database, never from the client.
|
|
172
|
+
*/
|
|
173
|
+
function resolveSendTarget(
|
|
174
|
+
ws: WebSocket,
|
|
175
|
+
data: AnyRecord,
|
|
176
|
+
dependencies: ChatWebSocketDependencies,
|
|
177
|
+
frameName: string,
|
|
178
|
+
): ResolvedSendTarget | null {
|
|
152
179
|
const sessionId = readRequiredSessionId(data);
|
|
153
180
|
if (!sessionId) {
|
|
154
|
-
sendProtocolError(ws, 'SESSION_ID_REQUIRED',
|
|
155
|
-
return;
|
|
181
|
+
sendProtocolError(ws, 'SESSION_ID_REQUIRED', `${frameName} requires a sessionId.`);
|
|
182
|
+
return null;
|
|
156
183
|
}
|
|
157
184
|
|
|
158
185
|
const session = sessionsDb.getSessionById(sessionId);
|
|
@@ -163,15 +190,36 @@ async function handleChatSend(
|
|
|
163
190
|
`Session "${sessionId}" was not found. Create it via POST /api/providers/sessions first.`,
|
|
164
191
|
sessionId
|
|
165
192
|
);
|
|
166
|
-
return;
|
|
193
|
+
return null;
|
|
167
194
|
}
|
|
168
195
|
|
|
169
196
|
const provider = session.provider as LLMProvider;
|
|
170
197
|
if (!dependencies.runtime.hasRuntime(provider)) {
|
|
171
198
|
sendProtocolError(ws, 'UNSUPPORTED_PROVIDER', `Provider "${provider}" is not available.`, sessionId);
|
|
172
|
-
return;
|
|
199
|
+
return null;
|
|
173
200
|
}
|
|
174
201
|
|
|
202
|
+
return { sessionId, session, provider };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Registers the run and hands the turn to the provider runtime.
|
|
207
|
+
*
|
|
208
|
+
* `extraRuntimeOptions` is how an edited message asks the provider to resume
|
|
209
|
+
* partway instead of continuing from the tip; a normal send passes nothing.
|
|
210
|
+
*/
|
|
211
|
+
async function dispatchRun(
|
|
212
|
+
ws: WebSocket | null,
|
|
213
|
+
userId: string | number | null,
|
|
214
|
+
sessionId: string,
|
|
215
|
+
session: NonNullable<ReturnType<typeof sessionsDb.getSessionById>>,
|
|
216
|
+
data: AnyRecord,
|
|
217
|
+
dependencies: ChatWebSocketDependencies,
|
|
218
|
+
extraRuntimeOptions: AnyRecord = {},
|
|
219
|
+
beforeRun?: (run: NonNullable<ReturnType<typeof chatRunRegistry.startRun>>) => void | Promise<void>,
|
|
220
|
+
): Promise<{ started: boolean; error: string | null }> {
|
|
221
|
+
const provider = session.provider as LLMProvider;
|
|
222
|
+
|
|
175
223
|
const run = chatRunRegistry.startRun({
|
|
176
224
|
appSessionId: sessionId,
|
|
177
225
|
provider,
|
|
@@ -181,13 +229,15 @@ async function handleChatSend(
|
|
|
181
229
|
});
|
|
182
230
|
|
|
183
231
|
if (!run) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
232
|
+
if (ws) {
|
|
233
|
+
sendProtocolError(
|
|
234
|
+
ws,
|
|
235
|
+
'RUN_IN_PROGRESS',
|
|
236
|
+
`Session "${sessionId}" already has a run in progress.`,
|
|
237
|
+
sessionId
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
return { started: false, error: 'A run is already in progress for this session.' };
|
|
191
241
|
}
|
|
192
242
|
|
|
193
243
|
const clientOptions = (data.options ?? {}) as AnyRecord;
|
|
@@ -221,6 +271,7 @@ async function handleChatSend(
|
|
|
221
271
|
// app session id.
|
|
222
272
|
const runtimeOptions: AnyRecord = {
|
|
223
273
|
...clientOptions,
|
|
274
|
+
...extraRuntimeOptions,
|
|
224
275
|
// Attachments are re-validated server-side: only direct children of the
|
|
225
276
|
// global upload store may reach provider runtimes or their file tools.
|
|
226
277
|
attachments: uniqueAttachments,
|
|
@@ -231,11 +282,17 @@ async function handleChatSend(
|
|
|
231
282
|
projectPath: session.project_path ?? clientOptions.projectPath,
|
|
232
283
|
};
|
|
233
284
|
|
|
285
|
+
let failure: string | null = null;
|
|
234
286
|
try {
|
|
287
|
+
// Runs only now that the session is reserved, because an edit rewinds the
|
|
288
|
+
// conversation here and a rewind for a run that was never admitted cannot
|
|
289
|
+
// be taken back. Inside the try so a rewind that throws still releases the
|
|
290
|
+
// run instead of leaving the session processing forever.
|
|
291
|
+
await beforeRun?.(run);
|
|
235
292
|
await dependencies.runtime.run(provider, command, runtimeOptions, run.writer);
|
|
236
293
|
} catch (error) {
|
|
237
|
-
|
|
238
|
-
console.error(`[Chat] Provider runtime "${provider}" failed`, { sessionId, error:
|
|
294
|
+
failure = error instanceof Error ? error.message : String(error);
|
|
295
|
+
console.error(`[Chat] Provider runtime "${provider}" failed`, { sessionId, error: failure });
|
|
239
296
|
} finally {
|
|
240
297
|
// Safety net: a runtime that crashed (or resolved) without emitting its
|
|
241
298
|
// terminal `complete` would otherwise leave the session stuck in
|
|
@@ -244,6 +301,113 @@ async function handleChatSend(
|
|
|
244
301
|
// settles, and the session-keyed completeRun would kill that new run.
|
|
245
302
|
chatRunRegistry.completeRunIfCurrent(run, { exitCode: 1 });
|
|
246
303
|
}
|
|
304
|
+
|
|
305
|
+
return { started: true, error: failure };
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Handles `chat.edit-send`: replaces an already-sent message and everything
|
|
310
|
+
* after it with a new turn.
|
|
311
|
+
*
|
|
312
|
+
* Nothing is deleted. The provider resumes the conversation partway and
|
|
313
|
+
* appends the replacement, so the abandoned attempt stays in the transcript
|
|
314
|
+
* file and is simply no longer part of the live conversation — the same shape
|
|
315
|
+
* Claude Code's rewind and Codex's fork-with-cut-point produce.
|
|
316
|
+
*/
|
|
317
|
+
async function handleChatEditSend(
|
|
318
|
+
ws: WebSocket,
|
|
319
|
+
userId: string | number | null,
|
|
320
|
+
data: AnyRecord,
|
|
321
|
+
dependencies: ChatWebSocketDependencies
|
|
322
|
+
): Promise<void> {
|
|
323
|
+
const resolved = resolveSendTarget(ws, data, dependencies, 'chat.edit-send');
|
|
324
|
+
if (!resolved) {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const { sessionId, session, provider } = resolved;
|
|
329
|
+
const anchorId = typeof data.anchorId === 'string' ? data.anchorId.trim() : '';
|
|
330
|
+
if (!anchorId) {
|
|
331
|
+
sendProtocolError(ws, 'ANCHOR_REQUIRED', 'chat.edit-send requires the anchorId of the message being replaced.', sessionId);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
let resumeThroughId: string | null;
|
|
336
|
+
try {
|
|
337
|
+
const anchor = await sessionsService.resolveEditAnchor(sessionId, anchorId);
|
|
338
|
+
if (!anchor) {
|
|
339
|
+
sendProtocolError(
|
|
340
|
+
ws,
|
|
341
|
+
'EDIT_NOT_SUPPORTED',
|
|
342
|
+
`Provider "${provider}" cannot replace an already-sent message.`,
|
|
343
|
+
sessionId
|
|
344
|
+
);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (!anchor.found) {
|
|
348
|
+
sendProtocolError(ws, 'ANCHOR_NOT_FOUND', 'That message is no longer in the transcript.', sessionId);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
resumeThroughId = anchor.resumeThroughId;
|
|
352
|
+
} catch (error) {
|
|
353
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
354
|
+
sendProtocolError(ws, 'ANCHOR_LOOKUP_FAILED', `Could not read the transcript: ${message}`, sessionId);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Providers split here on what their runtime can do. Claude resumes its
|
|
359
|
+
// transcript partway, so the anchor rides along as a run option. Codex
|
|
360
|
+
// cannot — a thread only grows — so the conversation is rewound on disk and
|
|
361
|
+
// the run that follows is an ordinary resume of whatever the session then
|
|
362
|
+
// points at. Which of the two applies is decided here; the rewind itself
|
|
363
|
+
// waits until the run has actually been admitted.
|
|
364
|
+
const rewinds = sessionsService.providerRewindsForEdit(sessionId);
|
|
365
|
+
|
|
366
|
+
await dispatchRun(
|
|
367
|
+
ws,
|
|
368
|
+
userId,
|
|
369
|
+
sessionId,
|
|
370
|
+
session,
|
|
371
|
+
data,
|
|
372
|
+
dependencies,
|
|
373
|
+
// `null` is meaningful: the edited turn was the first prompt, so the
|
|
374
|
+
// conversation starts over instead of resuming.
|
|
375
|
+
rewinds
|
|
376
|
+
? {}
|
|
377
|
+
: { resumeAnchorId: resumeThroughId ?? undefined, resumeFromScratch: resumeThroughId === null },
|
|
378
|
+
async (run) => {
|
|
379
|
+
// Emitted through the run's writer so it is sequenced and replayed like
|
|
380
|
+
// any other event — a second tab watching this session has to truncate
|
|
381
|
+
// too.
|
|
382
|
+
//
|
|
383
|
+
// Before the rewind, not after it. A rewind that has to branch spawns a
|
|
384
|
+
// process and waits on a JSON-RPC round trip, and holding the frame
|
|
385
|
+
// until that came back left the message the user had just edited away
|
|
386
|
+
// sitting on screen for about a second — the very flicker this feature
|
|
387
|
+
// exists to avoid. Announcing first is safe because a rewind that fails
|
|
388
|
+
// still ends the run, and the terminal `complete` makes every client
|
|
389
|
+
// re-read the transcript, which puts back anything that turned out not
|
|
390
|
+
// to have been replaced after all.
|
|
391
|
+
run.writer.send({
|
|
392
|
+
kind: 'history_truncated',
|
|
393
|
+
provider,
|
|
394
|
+
sessionId,
|
|
395
|
+
anchorId,
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
if (rewinds) {
|
|
399
|
+
try {
|
|
400
|
+
await sessionsService.rewindSessionForEdit(sessionId, resumeThroughId);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
403
|
+
sendProtocolError(ws, 'EDIT_REWIND_FAILED', `Could not rewind the conversation: ${message}`, sessionId);
|
|
404
|
+
// Ends the run before the provider is asked to continue a
|
|
405
|
+
// conversation that was not rewound after all.
|
|
406
|
+
throw error;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
);
|
|
247
411
|
}
|
|
248
412
|
|
|
249
413
|
/**
|
|
@@ -276,6 +440,52 @@ async function handleChatAbort(
|
|
|
276
440
|
});
|
|
277
441
|
}
|
|
278
442
|
|
|
443
|
+
/**
|
|
444
|
+
* Handles `chat.stop-task`: stops one background task of a session — an
|
|
445
|
+
* agent, a workflow or a backgrounded command that is still going after its
|
|
446
|
+
* turn ended. Unlike `chat.abort` there is no run to consult: the task lives
|
|
447
|
+
* in the provider's held process, which is the only thing that can stop it.
|
|
448
|
+
* The provider then reports the task as stopped on the session's stream, so
|
|
449
|
+
* nothing is echoed back here on success.
|
|
450
|
+
*/
|
|
451
|
+
async function handleChatStopTask(
|
|
452
|
+
ws: WebSocket,
|
|
453
|
+
data: AnyRecord,
|
|
454
|
+
dependencies: ChatWebSocketDependencies
|
|
455
|
+
): Promise<void> {
|
|
456
|
+
const sessionId = readRequiredSessionId(data);
|
|
457
|
+
if (!sessionId) {
|
|
458
|
+
sendProtocolError(ws, 'SESSION_ID_REQUIRED', 'chat.stop-task requires a sessionId.');
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const taskId = typeof data.taskId === 'string' ? data.taskId.trim() : '';
|
|
463
|
+
if (!taskId) {
|
|
464
|
+
sendProtocolError(ws, 'TASK_ID_REQUIRED', 'chat.stop-task requires a taskId.', sessionId);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const session = sessionsDb.getSessionById(sessionId);
|
|
469
|
+
if (!session) {
|
|
470
|
+
sendProtocolError(ws, 'SESSION_NOT_FOUND', `Session "${sessionId}" was not found.`, sessionId);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const stopped = await dependencies.runtime.stopBackgroundTask(
|
|
475
|
+
session.provider as LLMProvider,
|
|
476
|
+
sessionId,
|
|
477
|
+
taskId,
|
|
478
|
+
);
|
|
479
|
+
if (!stopped) {
|
|
480
|
+
sendProtocolError(
|
|
481
|
+
ws,
|
|
482
|
+
'NO_SUCH_TASK',
|
|
483
|
+
`Session "${sessionId}" has no running background task "${taskId}".`,
|
|
484
|
+
sessionId,
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
279
489
|
/**
|
|
280
490
|
* Handles `chat.subscribe`: for each requested session, reports whether a run
|
|
281
491
|
* is processing, re-attaches the live stream to this socket, replays missed
|
|
@@ -313,7 +523,11 @@ function handleChatSubscribe(
|
|
|
313
523
|
|
|
314
524
|
// Future live events for this run should land on the socket that asked —
|
|
315
525
|
// this is what makes mid-stream page refreshes work for all providers.
|
|
316
|
-
|
|
526
|
+
// A session whose turn ended but whose background work is still going
|
|
527
|
+
// keeps producing events through the same writer (task progress, the
|
|
528
|
+
// turn the CLI pushes when a task reports), so a tab opened during that
|
|
529
|
+
// work attaches too; the registry keeps the run while the work lasts.
|
|
530
|
+
if (isProcessing || dependencies.runtime.hasBackgroundWork(sessionId)) {
|
|
317
531
|
chatRunRegistry.attachConnection(sessionId, ws);
|
|
318
532
|
}
|
|
319
533
|
|
|
@@ -366,6 +580,7 @@ function handlePermissionResponse(data: AnyRecord, dependencies: ChatWebSocketDe
|
|
|
366
580
|
* Inbound protocol (client to server):
|
|
367
581
|
* - `chat.send` { sessionId, content, options? }
|
|
368
582
|
* - `chat.abort` { sessionId }
|
|
583
|
+
* - `chat.stop-task` { sessionId, taskId }
|
|
369
584
|
* - `chat.subscribe` { sessions: [{ sessionId, lastSeq? }] }
|
|
370
585
|
* - `chat.permission-response` { requestId, allow, updatedInput?, message?, rememberEntry? }
|
|
371
586
|
*
|
|
@@ -374,6 +589,71 @@ function handlePermissionResponse(data: AnyRecord, dependencies: ChatWebSocketDe
|
|
|
374
589
|
* (`chat_subscribed`, `session_upserted`, `loading_progress`,
|
|
375
590
|
* `protocol_error`).
|
|
376
591
|
*/
|
|
592
|
+
/**
|
|
593
|
+
* Runs a turn for a session with no client attached.
|
|
594
|
+
*
|
|
595
|
+
* Used by scheduled messages, which fire from a timer: there is no socket to
|
|
596
|
+
* report errors to and no audience to stream to. The run is registered exactly
|
|
597
|
+
* like an interactive one, so anyone who opens the session while it is going
|
|
598
|
+
* subscribes and replays it from the start, and the session shows as busy
|
|
599
|
+
* everywhere in the meantime.
|
|
600
|
+
*
|
|
601
|
+
* Resolves when the provider run settles. Returns false when the session has
|
|
602
|
+
* gone away or is busy without `interruptActiveRun`, which the caller reports
|
|
603
|
+
* on the schedule.
|
|
604
|
+
*/
|
|
605
|
+
export async function runDetachedChatTurn(
|
|
606
|
+
input: {
|
|
607
|
+
sessionId: string;
|
|
608
|
+
userId: string | number | null;
|
|
609
|
+
content: string;
|
|
610
|
+
options?: AnyRecord;
|
|
611
|
+
/**
|
|
612
|
+
* Aborts a run already in progress instead of refusing to start. A
|
|
613
|
+
* scheduled message sets this: the user picked the time knowing it might
|
|
614
|
+
* land mid-run, so the timer outranks whatever is running.
|
|
615
|
+
*/
|
|
616
|
+
interruptActiveRun?: boolean;
|
|
617
|
+
},
|
|
618
|
+
dependencies: ChatWebSocketDependencies,
|
|
619
|
+
): Promise<{ started: boolean; error: string | null }> {
|
|
620
|
+
const session = sessionsDb.getSessionById(input.sessionId);
|
|
621
|
+
if (!session) {
|
|
622
|
+
return { started: false, error: 'The session no longer exists.' };
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
const provider = session.provider as LLMProvider;
|
|
626
|
+
if (!dependencies.runtime.hasRuntime(provider)) {
|
|
627
|
+
return { started: false, error: `Provider "${provider}" is not available.` };
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
const activeRun = chatRunRegistry.getRun(input.sessionId);
|
|
631
|
+
if (activeRun && activeRun.status === 'running') {
|
|
632
|
+
if (!input.interruptActiveRun) {
|
|
633
|
+
return { started: false, error: 'A run was already in progress for this session.' };
|
|
634
|
+
}
|
|
635
|
+
// Same shape as `chat.abort`: cancel the provider run and emit the
|
|
636
|
+
// terminal `complete` on its behalf, so every watching client sees the
|
|
637
|
+
// interrupted run end before this turn's stream begins. The interrupted
|
|
638
|
+
// run's own dispatch settles later through completeRunIfCurrent, which is
|
|
639
|
+
// scoped to that run and cannot touch the one started here.
|
|
640
|
+
const aborted = await dependencies.runtime.abort(activeRun.provider, input.sessionId);
|
|
641
|
+
chatRunRegistry.completeRun(input.sessionId, {
|
|
642
|
+
exitCode: aborted ? 0 : 1,
|
|
643
|
+
aborted: true,
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
return dispatchRun(
|
|
648
|
+
null,
|
|
649
|
+
input.userId,
|
|
650
|
+
input.sessionId,
|
|
651
|
+
session,
|
|
652
|
+
{ sessionId: input.sessionId, content: input.content, options: input.options ?? {} },
|
|
653
|
+
dependencies,
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
|
|
377
657
|
export function handleChatConnection(
|
|
378
658
|
ws: WebSocket,
|
|
379
659
|
request: AuthenticatedWebSocketRequest,
|
|
@@ -395,12 +675,18 @@ export function handleChatConnection(
|
|
|
395
675
|
const messageType = typeof data.type === 'string' ? data.type : '';
|
|
396
676
|
|
|
397
677
|
switch (messageType) {
|
|
678
|
+
case 'chat.edit-send':
|
|
679
|
+
await handleChatEditSend(ws, userId, data, dependencies);
|
|
680
|
+
return;
|
|
398
681
|
case 'chat.send':
|
|
399
682
|
await handleChatSend(ws, userId, data, dependencies);
|
|
400
683
|
return;
|
|
401
684
|
case 'chat.abort':
|
|
402
685
|
await handleChatAbort(ws, data, dependencies);
|
|
403
686
|
return;
|
|
687
|
+
case 'chat.stop-task':
|
|
688
|
+
await handleChatStopTask(ws, data, dependencies);
|
|
689
|
+
return;
|
|
404
690
|
case 'chat.subscribe':
|
|
405
691
|
handleChatSubscribe(ws, data, dependencies);
|
|
406
692
|
return;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
import { projectsDb, sessionsDb } from '@/modules/database/index.js';
|
|
4
|
+
import { generateDisplayName } from '@/modules/projects/index.js';
|
|
5
|
+
import { connectedClients, WS_OPEN_STATE } from '@/modules/websocket/services/websocket-state.service.js';
|
|
6
|
+
import type { SessionUpsertedEvent } from '@/shared/types.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The single producer of the `session_upserted` delta.
|
|
10
|
+
*
|
|
11
|
+
* The event carries everything a sidebar needs to upsert a session in place
|
|
12
|
+
* (its summary plus the owning project's metadata), so clients never refetch
|
|
13
|
+
* the whole project list because one transcript changed on disk.
|
|
14
|
+
*
|
|
15
|
+
* It used to be built in two places — the on-disk sessions watcher and the
|
|
16
|
+
* chat run registry — and only the registry's copy set `providerSessionId`.
|
|
17
|
+
* That field is how the client notices a row it is showing has been merged
|
|
18
|
+
* into its canonical app-session row, so a merge announced by any other path
|
|
19
|
+
* left a stale duplicate in the sidebar. One builder, one shape.
|
|
20
|
+
*/
|
|
21
|
+
async function buildSessionUpsertedEvent(
|
|
22
|
+
sessionIdOrProviderSessionId: string,
|
|
23
|
+
): Promise<SessionUpsertedEvent | null> {
|
|
24
|
+
// Resolving by provider id first covers the watcher, which only ever sees
|
|
25
|
+
// the id written in the transcript. For a row where the two ids are equal
|
|
26
|
+
// — legacy rows, and any session indexed from disk before its mapping
|
|
27
|
+
// existed — both lookups land on the same row anyway.
|
|
28
|
+
const row = sessionsDb.getSessionByProviderSessionId(sessionIdOrProviderSessionId)
|
|
29
|
+
?? sessionsDb.getSessionById(sessionIdOrProviderSessionId);
|
|
30
|
+
if (!row || row.isArchived) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const projectPath = row.project_path;
|
|
35
|
+
const project = projectPath ? projectsDb.getProjectPath(projectPath) : null;
|
|
36
|
+
const displayName = project?.custom_project_name?.trim()
|
|
37
|
+
? project.custom_project_name
|
|
38
|
+
: await generateDisplayName(path.basename(projectPath ?? '') || (projectPath ?? ''), projectPath);
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
kind: 'session_upserted',
|
|
42
|
+
sessionId: row.session_id,
|
|
43
|
+
providerSessionId: row.provider_session_id ?? null,
|
|
44
|
+
// The column is a plain TEXT and typed as `string` on the row, but only
|
|
45
|
+
// provider adapters ever write it.
|
|
46
|
+
provider: row.provider as SessionUpsertedEvent['provider'],
|
|
47
|
+
session: {
|
|
48
|
+
id: row.session_id,
|
|
49
|
+
summary: row.custom_name || '',
|
|
50
|
+
messageCount: 0,
|
|
51
|
+
lastActivity: row.updated_at ?? row.created_at ?? new Date().toISOString(),
|
|
52
|
+
},
|
|
53
|
+
project: project
|
|
54
|
+
? {
|
|
55
|
+
projectId: project.project_id,
|
|
56
|
+
path: project.project_path,
|
|
57
|
+
fullPath: project.project_path,
|
|
58
|
+
displayName,
|
|
59
|
+
isStarred: Boolean(project.isStarred),
|
|
60
|
+
}
|
|
61
|
+
: null,
|
|
62
|
+
timestamp: new Date().toISOString(),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function sendToConnectedClients(payloads: string[]): void {
|
|
67
|
+
if (payloads.length === 0) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
connectedClients.forEach((client) => {
|
|
72
|
+
if (client.readyState === WS_OPEN_STATE) {
|
|
73
|
+
for (const payload of payloads) {
|
|
74
|
+
client.send(payload);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Announces one session. Used by the chat run registry when a run reports its provider-native id. */
|
|
81
|
+
export async function broadcastSessionUpserted(sessionIdOrProviderSessionId: string): Promise<void> {
|
|
82
|
+
const event = await buildSessionUpsertedEvent(sessionIdOrProviderSessionId);
|
|
83
|
+
if (event) {
|
|
84
|
+
sendToConnectedClients([JSON.stringify(event)]);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Announces a batch of sessions. Used by the providers module's sessions
|
|
90
|
+
* watcher, whose debounced flush can carry dozens of ids at once — the client
|
|
91
|
+
* set is walked once for the whole batch rather than once per session.
|
|
92
|
+
*/
|
|
93
|
+
export async function broadcastSessionUpsertedBatch(
|
|
94
|
+
sessionIds: Iterable<string>,
|
|
95
|
+
): Promise<void> {
|
|
96
|
+
const payloads: string[] = [];
|
|
97
|
+
for (const sessionId of sessionIds) {
|
|
98
|
+
const event = await buildSessionUpsertedEvent(sessionId);
|
|
99
|
+
if (event) {
|
|
100
|
+
payloads.push(JSON.stringify(event));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
sendToConnectedClients(payloads);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** @internal Exported for the broadcast tests, which assert the payload shape directly. */
|
|
108
|
+
export { buildSessionUpsertedEvent };
|