@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
|
@@ -17,11 +17,16 @@ import os from 'os';
|
|
|
17
17
|
import path from 'path';
|
|
18
18
|
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
19
19
|
import { appendFilesInputTag, buildClaudeUserContent, normalizeImageDescriptors } from '../../../../shared/image-attachments.js';
|
|
20
|
-
import { CLAUDE_PREDEFINED_MODELS } from '../../../../modules/providers/list/claude/claude-models.provider.js';
|
|
20
|
+
import { CLAUDE_PREDEFINED_MODELS, CLAUDE_ULTRACODE_EFFORT } from '../../../../modules/providers/list/claude/claude-models.provider.js';
|
|
21
21
|
import { resolveClaudeCodeExecutablePath } from '../../../../shared/claude-cli-path.js';
|
|
22
22
|
import { createNotificationEvent, notifyBackgroundWorkCompleted, notifyRunFailed, notifyRunStopped, notifyUserIfEnabled } from '../../../../modules/notifications/index.js';
|
|
23
|
+
import { sessionHistoryCache } from '../../../../modules/providers/services/session-history-cache.service.js';
|
|
23
24
|
import { createCompleteMessage, createNormalizedMessage } from '../../../../shared/utils.js';
|
|
24
25
|
const activeSessions = new Map();
|
|
26
|
+
// Outstanding background tasks per live session, keyed like activeSessions. An
|
|
27
|
+
// entry lives exactly as long as the map entry it shadows: cleared when the
|
|
28
|
+
// session is removed, and reset when a newer run takes the key over.
|
|
29
|
+
const backgroundWork = createBackgroundWorkTracker();
|
|
25
30
|
const pendingToolApprovals = new Map();
|
|
26
31
|
// Sessions cancelled via abort-session. The abort handler already sent the
|
|
27
32
|
// terminal `complete` (aborted: true) to the client, so the run loop must not
|
|
@@ -51,6 +56,11 @@ const TOOL_APPROVAL_TIMEOUT_MS = parseInt(process.env.CLAUDE_TOOL_APPROVAL_TIMEO
|
|
|
51
56
|
// forever. The timer resets on every message, so it measures silence, not total time.
|
|
52
57
|
const BG_WAIT_CEILING_MS = 30 * 60 * 1000;
|
|
53
58
|
const TOOLS_REQUIRING_INTERACTION = new Set(['AskUserQuestion', 'ExitPlanMode']);
|
|
59
|
+
// Ultracode is a session-scoped setting rather than an SDK effort level: it pairs xhigh
|
|
60
|
+
// effort with standing dynamic-workflow orchestration, and the CLI only honours it when
|
|
61
|
+
// Workflows are enabled. The catalog offers it as an effort choice for the picker, so the
|
|
62
|
+
// selection is translated back into the two options the SDK actually understands here.
|
|
63
|
+
const ULTRACODE_SDK_EFFORT = 'xhigh';
|
|
54
64
|
function resolveClaudeEffort(model, effort, modelsDefinition = CLAUDE_PREDEFINED_MODELS) {
|
|
55
65
|
const selectedModel = modelsDefinition?.OPTIONS?.find((option) => option.value === model) || null;
|
|
56
66
|
const allowedEfforts = selectedModel?.effort?.values
|
|
@@ -59,6 +69,27 @@ function resolveClaudeEffort(model, effort, modelsDefinition = CLAUDE_PREDEFINED
|
|
|
59
69
|
? effort
|
|
60
70
|
: undefined;
|
|
61
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Writes the resolved effort choice onto the SDK options, expanding `ultracode` into the
|
|
74
|
+
* xhigh effort level plus the session-scoped settings it requires.
|
|
75
|
+
* @param {Object} sdkOptions - SDK options being built
|
|
76
|
+
* @param {string|undefined} resolvedEffort - Catalog-validated effort selection
|
|
77
|
+
*/
|
|
78
|
+
function applyClaudeEffort(sdkOptions, resolvedEffort) {
|
|
79
|
+
if (!resolvedEffort) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (resolvedEffort !== CLAUDE_ULTRACODE_EFFORT) {
|
|
83
|
+
sdkOptions.effort = resolvedEffort;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
sdkOptions.effort = ULTRACODE_SDK_EFFORT;
|
|
87
|
+
sdkOptions.settings = {
|
|
88
|
+
...(sdkOptions.settings || {}),
|
|
89
|
+
ultracode: true,
|
|
90
|
+
enableWorkflows: true
|
|
91
|
+
};
|
|
92
|
+
}
|
|
62
93
|
function createRequestId() {
|
|
63
94
|
if (typeof crypto.randomUUID === 'function') {
|
|
64
95
|
return crypto.randomUUID();
|
|
@@ -149,14 +180,19 @@ function matchesToolPermission(entry, toolName, input) {
|
|
|
149
180
|
return false;
|
|
150
181
|
}
|
|
151
182
|
function mapCliOptionsToSDK(options = {}) {
|
|
152
|
-
const { providerSessionId, cwd, toolsSettings, permissionMode, effort } = options;
|
|
183
|
+
const { providerSessionId, cwd, toolsSettings, permissionMode, effort, resumeAnchorId, resumeFromScratch } = options;
|
|
153
184
|
const sdkOptions = {};
|
|
154
185
|
// Forward all host env vars (e.g. ANTHROPIC_BASE_URL) to the subprocess.
|
|
155
186
|
// Since SDK 0.2.113, options.env replaces process.env instead of overlaying it.
|
|
156
187
|
sdkOptions.env = { ...process.env, CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS: String(BG_WAIT_CEILING_MS) };
|
|
157
188
|
// Resolve the executable eagerly on Windows because the SDK uses raw child_process.spawn,
|
|
158
189
|
// which does not reliably follow npm's shell wrappers like cross-spawn does.
|
|
159
|
-
|
|
190
|
+
// When nothing resolves the option stays unset on purpose: the SDK then falls back to the
|
|
191
|
+
// binary it ships, which beats handing it a bare `claude` that raw spawn can never launch.
|
|
192
|
+
const claudeExecutablePath = resolveClaudeCodeExecutablePath(process.env.CLAUDE_CLI_PATH);
|
|
193
|
+
if (claudeExecutablePath) {
|
|
194
|
+
sdkOptions.pathToClaudeCodeExecutable = claudeExecutablePath;
|
|
195
|
+
}
|
|
160
196
|
if (cwd) {
|
|
161
197
|
sdkOptions.cwd = cwd;
|
|
162
198
|
}
|
|
@@ -187,18 +223,25 @@ function mapCliOptionsToSDK(options = {}) {
|
|
|
187
223
|
sdkOptions.tools = { type: 'preset', preset: 'claude_code' };
|
|
188
224
|
sdkOptions.disallowedTools = settings.disallowedTools || [];
|
|
189
225
|
sdkOptions.model = options.model || CLAUDE_PREDEFINED_MODELS.DEFAULT;
|
|
190
|
-
|
|
191
|
-
if (resolvedEffort) {
|
|
192
|
-
sdkOptions.effort = resolvedEffort;
|
|
193
|
-
}
|
|
226
|
+
applyClaudeEffort(sdkOptions, resolveClaudeEffort(sdkOptions.model, effort, options.effortModels || CLAUDE_PREDEFINED_MODELS));
|
|
194
227
|
sdkOptions.systemPrompt = {
|
|
195
228
|
type: 'preset',
|
|
196
229
|
preset: 'claude_code'
|
|
197
230
|
};
|
|
198
231
|
sdkOptions.settingSources = ['project', 'user', 'local'];
|
|
199
232
|
// The SDK resumes with the provider-native session id, never the app id.
|
|
200
|
-
|
|
233
|
+
// `resumeFromScratch` is set when the very first prompt of a conversation was
|
|
234
|
+
// edited: there is nothing before it to resume through, so the turn has to
|
|
235
|
+
// start the conversation over instead.
|
|
236
|
+
if (providerSessionId && !resumeFromScratch) {
|
|
201
237
|
sdkOptions.resume = providerSessionId;
|
|
238
|
+
// Editing an already-sent message re-runs the conversation truncated just
|
|
239
|
+
// before it. `resumeSessionAt` is inclusive of the uuid it names, so the
|
|
240
|
+
// caller resolves the last row to KEEP and passes that — never the edited
|
|
241
|
+
// turn itself, which would leave the original prompt in context.
|
|
242
|
+
if (resumeAnchorId) {
|
|
243
|
+
sdkOptions.resumeSessionAt = resumeAnchorId;
|
|
244
|
+
}
|
|
202
245
|
}
|
|
203
246
|
return sdkOptions;
|
|
204
247
|
}
|
|
@@ -227,6 +270,9 @@ function addSession(sessionId, queryInstance, writer = null, releaseInput = null
|
|
|
227
270
|
console.error(`Error interrupting superseded run for session ${sessionId}:`, error?.message || error);
|
|
228
271
|
});
|
|
229
272
|
existing.releaseInput?.();
|
|
273
|
+
// Whatever the superseded process had outstanding dies with it and will
|
|
274
|
+
// never report, so the new run starts from an empty task set.
|
|
275
|
+
backgroundWork.clear(sessionId);
|
|
230
276
|
}
|
|
231
277
|
const carried = superseding ? null : existing;
|
|
232
278
|
activeSessions.set(sessionId, {
|
|
@@ -237,6 +283,44 @@ function addSession(sessionId, queryInstance, writer = null, releaseInput = null
|
|
|
237
283
|
// Re-registered mid-run once the provider session id lands; keep the closer.
|
|
238
284
|
releaseInput: releaseInput || carried?.releaseInput || null
|
|
239
285
|
});
|
|
286
|
+
// The history reader reports a background agent as running or stopped by
|
|
287
|
+
// whether this entry exists, and the cached history does not see this map.
|
|
288
|
+
sessionHistoryCache.invalidate(sessionId);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Lets go of the process an earlier run left holding a session open, so the
|
|
292
|
+
* next turn can take the session over.
|
|
293
|
+
*
|
|
294
|
+
* Closing stdin is not enough on its own: the CLI's wind-down waits for the
|
|
295
|
+
* background agents the process still has going — for up to the ceiling it
|
|
296
|
+
* was started with (BG_WAIT_CEILING_MS) — so an abandoned process with an
|
|
297
|
+
* agent outstanding would run next to the process that replaced it for as
|
|
298
|
+
* long as the agent does, both appending to the same session file. Stop the
|
|
299
|
+
* tasks first, while stdin is still open: the SDK drops control requests
|
|
300
|
+
* written after stdin has ended, which is also why the interrupt a later
|
|
301
|
+
* supersede sends to this process cannot do the job.
|
|
302
|
+
*
|
|
303
|
+
* The stops are not awaited — each request is written to the CLI before this
|
|
304
|
+
* returns, and a reply is only missing when the process has already gone.
|
|
305
|
+
* @param {string} sessionId - Session identifier
|
|
306
|
+
*/
|
|
307
|
+
function releaseHeldSession(sessionId) {
|
|
308
|
+
const held = getSession(sessionId);
|
|
309
|
+
if (!held) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
for (const task of backgroundWork.outstanding(sessionId)) {
|
|
313
|
+
// A stop that cannot be delivered changes nothing about what happens
|
|
314
|
+
// next: the process is on its way out either way. Guard the synchronous
|
|
315
|
+
// call too, so a failing stop can never skip the release below.
|
|
316
|
+
try {
|
|
317
|
+
Promise.resolve(held.instance?.stopTask?.(task.taskId)).catch(() => { });
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
// Same as a rejected stop.
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
held.releaseInput?.();
|
|
240
324
|
}
|
|
241
325
|
/**
|
|
242
326
|
* Removes a session from the active sessions map
|
|
@@ -244,6 +328,11 @@ function addSession(sessionId, queryInstance, writer = null, releaseInput = null
|
|
|
244
328
|
*/
|
|
245
329
|
function removeSession(sessionId) {
|
|
246
330
|
activeSessions.delete(sessionId);
|
|
331
|
+
// No process, no background work: anything still tracked was killed with it.
|
|
332
|
+
backgroundWork.clear(sessionId);
|
|
333
|
+
// See addSession: a page cached while the process was up still says
|
|
334
|
+
// `running` for any agent that never reported back.
|
|
335
|
+
sessionHistoryCache.invalidate(sessionId);
|
|
247
336
|
}
|
|
248
337
|
/**
|
|
249
338
|
* Gets a session from the active sessions map
|
|
@@ -275,44 +364,118 @@ function transformMessage(sdkMessage) {
|
|
|
275
364
|
}
|
|
276
365
|
return sdkMessage;
|
|
277
366
|
}
|
|
367
|
+
/**
|
|
368
|
+
* True for the user bubble the SDK echoes for a subagent's own prompt.
|
|
369
|
+
*
|
|
370
|
+
* Subagent traffic carries `parent_tool_use_id`, so this echo lands in the main
|
|
371
|
+
* thread and stacks a second copy of the prompt right below the Agent tool card
|
|
372
|
+
* that already displays it. It also disappears on reload, because the transcript
|
|
373
|
+
* keeps that turn in the subagent's sidechain rather than the session file.
|
|
374
|
+
* @param {Object} message - Normalized message about to be sent to the client
|
|
375
|
+
* @returns {boolean}
|
|
376
|
+
*/
|
|
377
|
+
export function isSubagentPromptEcho(message) {
|
|
378
|
+
return Boolean(message?.parentToolUseId) && message.role === 'user' && message.kind === 'text';
|
|
379
|
+
}
|
|
278
380
|
function readNumber(value) {
|
|
279
381
|
const parsed = Number(value);
|
|
280
382
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
281
383
|
}
|
|
282
384
|
/**
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
385
|
+
* @typedef {Object} TokenBudget
|
|
386
|
+
* @property {number} used
|
|
387
|
+
* @property {number} total
|
|
388
|
+
* @property {number} inputTokens
|
|
389
|
+
* @property {number} outputTokens
|
|
390
|
+
* @property {number} [cacheReadTokens]
|
|
391
|
+
* @property {number} [cacheCreationTokens]
|
|
392
|
+
* @property {number} [cacheTokens]
|
|
393
|
+
* @property {{ input: number, output: number }} breakdown
|
|
394
|
+
*/
|
|
395
|
+
/**
|
|
396
|
+
* Builds a context-window budget from an Anthropic-shaped usage payload.
|
|
397
|
+
*
|
|
398
|
+
* `input_tokens + cache_read + cache_creation` is one request's whole prompt,
|
|
399
|
+
* which is exactly what the context window holds at that moment.
|
|
400
|
+
* @param {Object} messageUsage - Anthropic usage payload
|
|
401
|
+
* @returns {TokenBudget} Token budget object
|
|
402
|
+
*/
|
|
403
|
+
function buildTokenBudget(messageUsage) {
|
|
404
|
+
const directInputTokens = readNumber(messageUsage.input_tokens ?? messageUsage.inputTokens);
|
|
405
|
+
const cacheCreationTokens = readNumber(messageUsage.cache_creation_input_tokens ?? messageUsage.cacheCreationInputTokens ?? messageUsage.cacheCreationTokens);
|
|
406
|
+
const cacheReadTokens = readNumber(messageUsage.cache_read_input_tokens ?? messageUsage.cacheReadInputTokens ?? messageUsage.cacheReadTokens);
|
|
407
|
+
const cacheTokens = cacheCreationTokens + cacheReadTokens;
|
|
408
|
+
const inputTokens = directInputTokens + cacheTokens;
|
|
409
|
+
const outputTokens = readNumber(messageUsage.output_tokens ?? messageUsage.outputTokens);
|
|
410
|
+
const contextWindow = parseInt(process.env.CONTEXT_WINDOW, 10) || 160000;
|
|
411
|
+
return {
|
|
412
|
+
used: inputTokens + outputTokens,
|
|
413
|
+
total: contextWindow,
|
|
414
|
+
inputTokens,
|
|
415
|
+
outputTokens,
|
|
416
|
+
cacheReadTokens,
|
|
417
|
+
cacheCreationTokens,
|
|
418
|
+
cacheTokens,
|
|
419
|
+
breakdown: {
|
|
420
|
+
input: inputTokens,
|
|
421
|
+
output: outputTokens,
|
|
422
|
+
},
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Extracts the session's context-window usage from an SDK stream message.
|
|
427
|
+
*
|
|
428
|
+
* Only assistant messages describe the context window: each one reports the
|
|
429
|
+
* prompt its own request carried. The turn-ending `result` is deliberately not
|
|
430
|
+
* a source here — see `extractCumulativeTokenBudget`.
|
|
286
431
|
* @param {Object} sdkMessage - SDK stream message
|
|
287
|
-
* @returns {
|
|
432
|
+
* @returns {TokenBudget|null} Token budget object or null
|
|
288
433
|
*/
|
|
289
434
|
function extractTokenBudget(sdkMessage) {
|
|
290
435
|
if (!sdkMessage || typeof sdkMessage !== 'object') {
|
|
291
436
|
return null;
|
|
292
437
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
438
|
+
// Subagent traffic (parent_tool_use_id set) reports the subagent's own
|
|
439
|
+
// context window, not this session's — surfacing it makes the counter drop
|
|
440
|
+
// to the subagent's number and bounce back on the next main-thread event.
|
|
441
|
+
if (sdkMessage.parent_tool_use_id) {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
// Only assistant messages carry Anthropic-shaped usage. System
|
|
445
|
+
// task_progress/task_notification events have a top-level `usage` too, but
|
|
446
|
+
// shaped {total_tokens, tool_uses, duration_ms} — reading Anthropic keys
|
|
447
|
+
// off it yields an all-zero budget that flashes "0" in the composer.
|
|
448
|
+
if (sdkMessage.type !== 'assistant') {
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
const messageUsage = sdkMessage.message?.usage;
|
|
452
|
+
if (!messageUsage || typeof messageUsage !== 'object') {
|
|
453
|
+
return null;
|
|
454
|
+
}
|
|
455
|
+
return buildTokenBudget(messageUsage);
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Last-resort budget read from a turn's `result` message.
|
|
459
|
+
*
|
|
460
|
+
* `result.usage` and `result.modelUsage` are the turn's *bill*: every request
|
|
461
|
+
* the turn made, summed, including each subagent's. A turn that made four
|
|
462
|
+
* requests therefore reports roughly four times the context the conversation
|
|
463
|
+
* actually holds, so publishing it made the counter leap at the end of a turn
|
|
464
|
+
* and fall back on the next assistant message — worst with subagents running,
|
|
465
|
+
* whose requests inflate the sum without ever entering this session's context.
|
|
466
|
+
*
|
|
467
|
+
* It is still the only usage an SDK build that reports none per assistant
|
|
468
|
+
* message ever emits, so it stays available for the caller to use when a turn
|
|
469
|
+
* produced no assistant budget at all.
|
|
470
|
+
* @param {Object} sdkMessage - SDK stream message
|
|
471
|
+
* @returns {TokenBudget|null} Token budget object or null
|
|
472
|
+
*/
|
|
473
|
+
function extractCumulativeTokenBudget(sdkMessage) {
|
|
474
|
+
if (!sdkMessage || typeof sdkMessage !== 'object' || sdkMessage.type !== 'result') {
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
if (sdkMessage.usage && typeof sdkMessage.usage === 'object') {
|
|
478
|
+
return buildTokenBudget(sdkMessage.usage);
|
|
316
479
|
}
|
|
317
480
|
if (!sdkMessage.modelUsage || typeof sdkMessage.modelUsage !== 'object') {
|
|
318
481
|
return null;
|
|
@@ -338,19 +501,26 @@ function extractTokenBudget(sdkMessage) {
|
|
|
338
501
|
},
|
|
339
502
|
};
|
|
340
503
|
}
|
|
341
|
-
// Tool calls that leave work running past the end of a turn. Bash only
|
|
342
|
-
// when
|
|
343
|
-
|
|
504
|
+
// Tool calls that leave work running past the end of a turn. Bash and Agent only
|
|
505
|
+
// count when they are backgrounded; the rest defer or watch work by nature.
|
|
506
|
+
// Workflow belongs here rather than in a branch of its own: its input schema has
|
|
507
|
+
// no foreground option at all, so every call returns a task id immediately and
|
|
508
|
+
// reports back in a later turn.
|
|
509
|
+
const DEFERRED_WORK_TOOLS = new Set(['Monitor', 'ScheduleWakeup', 'CronCreate', 'TaskCreate', 'Workflow']);
|
|
344
510
|
/**
|
|
345
511
|
* Detects tool calls that keep working after the turn's `result` arrives.
|
|
346
512
|
*
|
|
347
513
|
* Only turns that start background work need their CLI process held open; every
|
|
348
514
|
* other turn can let it exit immediately, as it did before the hold existed.
|
|
349
515
|
*
|
|
516
|
+
* Used by the providers module's tests, which pin the tool matching directly:
|
|
517
|
+
* the alternative is driving a whole SDK run to observe whether stdin was held,
|
|
518
|
+
* and the cost of getting this wrong is silently killed background work.
|
|
519
|
+
*
|
|
350
520
|
* @param {Object} sdkMessage - SDK stream message
|
|
351
521
|
* @returns {boolean} True when the message launches work that outlives the turn
|
|
352
522
|
*/
|
|
353
|
-
function startsBackgroundWork(sdkMessage) {
|
|
523
|
+
export function startsBackgroundWork(sdkMessage) {
|
|
354
524
|
const content = sdkMessage?.message?.content;
|
|
355
525
|
if (!Array.isArray(content)) {
|
|
356
526
|
return false;
|
|
@@ -362,9 +532,152 @@ function startsBackgroundWork(sdkMessage) {
|
|
|
362
532
|
if (block.name === 'Bash') {
|
|
363
533
|
return block.input?.run_in_background === true;
|
|
364
534
|
}
|
|
535
|
+
// A backgrounded subagent outlives the turn exactly like a backgrounded
|
|
536
|
+
// Bash does, so the process has to be held open for it to report back.
|
|
537
|
+
// Agents background by default — `run_in_background` is optional and only
|
|
538
|
+
// an explicit `false` opts out — hence `!== false` rather than `=== true`.
|
|
539
|
+
// A foreground agent must stay out of DEFERRED_WORK_TOOLS: it never pushes
|
|
540
|
+
// a follow-up turn, so it would pin the process for the full ceiling.
|
|
541
|
+
if (block.name === 'Agent') {
|
|
542
|
+
return block.input?.run_in_background !== false;
|
|
543
|
+
}
|
|
365
544
|
return DEFERRED_WORK_TOOLS.has(block.name);
|
|
366
545
|
});
|
|
367
546
|
}
|
|
547
|
+
// `task_updated` patch statuses after which a task is gone for good. `pending`,
|
|
548
|
+
// `running` and `paused` are still outstanding; `killed` is what the CLI
|
|
549
|
+
// writes when it stops a task itself (the task notification spells it
|
|
550
|
+
// `stopped`).
|
|
551
|
+
const TERMINAL_TASK_STATUSES = new Set(['completed', 'failed', 'killed']);
|
|
552
|
+
/**
|
|
553
|
+
* Tracks the background tasks each live session still has outstanding, folded
|
|
554
|
+
* from the `system` task events the SDK stream already carries.
|
|
555
|
+
*
|
|
556
|
+
* `startsBackgroundWork` above only knows that a turn *launched* something
|
|
557
|
+
* lasting; this knows what is still running and which task ids it answers to,
|
|
558
|
+
* which is what the running-sessions list and a stop request need once the
|
|
559
|
+
* turn's `result` has gone out and nothing else remembers the session is busy.
|
|
560
|
+
*
|
|
561
|
+
* Verified against a real query (SDK 0.3.165): `task_started` carries
|
|
562
|
+
* `task_id`, `tool_use_id`, `task_type` and `description` for every agent,
|
|
563
|
+
* workflow and backgrounded command (a foreground Bash emits nothing);
|
|
564
|
+
* `task_notification` settles a task with any status; `task_updated` carries
|
|
565
|
+
* only `task_id` and a patch, and is terminal when the patch's `status` is.
|
|
566
|
+
* Housekeeping tasks the CLI starts on its own have no `tool_use_id` and are
|
|
567
|
+
* not tracked — nothing in the transcript could show them.
|
|
568
|
+
*
|
|
569
|
+
* Exported so the folding can be driven with the four event shapes directly;
|
|
570
|
+
* the runtime keeps one instance keyed like `activeSessions`.
|
|
571
|
+
*
|
|
572
|
+
* @returns {{
|
|
573
|
+
* apply: (sessionKey: string, message: Object) => void,
|
|
574
|
+
* hasOutstanding: (sessionKey: string) => boolean,
|
|
575
|
+
* has: (sessionKey: string, taskId: string) => boolean,
|
|
576
|
+
* outstanding: (sessionKey: string) => Array<import('../../../../shared/types.js').BackgroundTaskSummary>,
|
|
577
|
+
* clear: (sessionKey: string) => void,
|
|
578
|
+
* list: () => Array<{ sessionId: string, tasks: Array<import('../../../../shared/types.js').BackgroundTaskSummary> }>
|
|
579
|
+
* }}
|
|
580
|
+
*/
|
|
581
|
+
export function createBackgroundWorkTracker() {
|
|
582
|
+
/** @type {Map<string, Map<string, import('../../../../shared/types.js').BackgroundTaskSummary>>} */
|
|
583
|
+
const sessions = new Map();
|
|
584
|
+
/**
|
|
585
|
+
* Tool-use ids the session's own turns issued. A task started for a call an
|
|
586
|
+
* agent made inside its own transcript — a workflow agent's backgrounded
|
|
587
|
+
* command, say — reaches this stream too, and nothing in the parent
|
|
588
|
+
* transcript could show it; it is kept for stopping but flagged `nested`.
|
|
589
|
+
* @type {Map<string, Set<string>>}
|
|
590
|
+
*/
|
|
591
|
+
const ownToolUseIds = new Map();
|
|
592
|
+
const remove = (sessionKey, taskId) => {
|
|
593
|
+
const tasks = sessions.get(sessionKey);
|
|
594
|
+
if (!tasks) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
tasks.delete(taskId);
|
|
598
|
+
if (tasks.size === 0) {
|
|
599
|
+
sessions.delete(sessionKey);
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
return {
|
|
603
|
+
apply(sessionKey, message) {
|
|
604
|
+
if (message?.type === 'assistant' && !message.parent_tool_use_id) {
|
|
605
|
+
const content = message.message?.content;
|
|
606
|
+
if (Array.isArray(content)) {
|
|
607
|
+
for (const block of content) {
|
|
608
|
+
if (block?.type === 'tool_use' && typeof block.id === 'string') {
|
|
609
|
+
let ids = ownToolUseIds.get(sessionKey);
|
|
610
|
+
if (!ids) {
|
|
611
|
+
ids = new Set();
|
|
612
|
+
ownToolUseIds.set(sessionKey, ids);
|
|
613
|
+
}
|
|
614
|
+
ids.add(block.id);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
if (message?.type !== 'system' || typeof message.task_id !== 'string') {
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
switch (message.subtype) {
|
|
624
|
+
case 'task_started': {
|
|
625
|
+
if (typeof message.tool_use_id !== 'string') {
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
const task = {
|
|
629
|
+
taskId: message.task_id,
|
|
630
|
+
toolUseId: message.tool_use_id,
|
|
631
|
+
taskType: message.task_type,
|
|
632
|
+
description: message.description,
|
|
633
|
+
startedAt: Date.now()
|
|
634
|
+
};
|
|
635
|
+
if (typeof message.workflow_name === 'string') {
|
|
636
|
+
task.workflowName = message.workflow_name;
|
|
637
|
+
}
|
|
638
|
+
if (!ownToolUseIds.get(sessionKey)?.has(message.tool_use_id)) {
|
|
639
|
+
task.nested = true;
|
|
640
|
+
}
|
|
641
|
+
let tasks = sessions.get(sessionKey);
|
|
642
|
+
if (!tasks) {
|
|
643
|
+
tasks = new Map();
|
|
644
|
+
sessions.set(sessionKey, tasks);
|
|
645
|
+
}
|
|
646
|
+
tasks.set(task.taskId, task);
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
case 'task_notification':
|
|
650
|
+
remove(sessionKey, message.task_id);
|
|
651
|
+
return;
|
|
652
|
+
case 'task_updated':
|
|
653
|
+
if (TERMINAL_TASK_STATUSES.has(message.patch?.status)) {
|
|
654
|
+
remove(sessionKey, message.task_id);
|
|
655
|
+
}
|
|
656
|
+
return;
|
|
657
|
+
default:
|
|
658
|
+
}
|
|
659
|
+
},
|
|
660
|
+
hasOutstanding(sessionKey) {
|
|
661
|
+
return sessions.has(sessionKey);
|
|
662
|
+
},
|
|
663
|
+
has(sessionKey, taskId) {
|
|
664
|
+
return Boolean(sessions.get(sessionKey)?.has(taskId));
|
|
665
|
+
},
|
|
666
|
+
outstanding(sessionKey) {
|
|
667
|
+
return Array.from(sessions.get(sessionKey)?.values() ?? []);
|
|
668
|
+
},
|
|
669
|
+
clear(sessionKey) {
|
|
670
|
+
sessions.delete(sessionKey);
|
|
671
|
+
ownToolUseIds.delete(sessionKey);
|
|
672
|
+
},
|
|
673
|
+
list() {
|
|
674
|
+
return Array.from(sessions, ([sessionId, tasks]) => ({
|
|
675
|
+
sessionId,
|
|
676
|
+
tasks: Array.from(tasks.values())
|
|
677
|
+
}));
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
}
|
|
368
681
|
/**
|
|
369
682
|
* Builds the SDK user messages for one turn.
|
|
370
683
|
*
|
|
@@ -509,13 +822,22 @@ async function queryClaudeSDK(command, options = {}, ws, context) {
|
|
|
509
822
|
// Set when a turn starts background work, cleared when the next `result`
|
|
510
823
|
// arrives — only turns with work still outstanding hold their process open.
|
|
511
824
|
let backgroundWorkPending = false;
|
|
825
|
+
// Set when the stream reports a task starting during this turn. Task events
|
|
826
|
+
// are the exact word on what is still running, so when the turn produced
|
|
827
|
+
// any, the tracker decides the hold; `startsBackgroundWork` is the fallback
|
|
828
|
+
// for tools that emit none (Monitor, ScheduleWakeup, CronCreate, TaskCreate)
|
|
829
|
+
// and for an SDK that does not report tasks at all.
|
|
830
|
+
let sawTaskEventThisTurn = false;
|
|
512
831
|
// True while the process is being held open for background work, so a later
|
|
513
832
|
// `result` can be recognised as that work reporting back.
|
|
514
833
|
let heldForBackgroundWork = false;
|
|
834
|
+
// Set once a turn publishes a budget read from an assistant message, so the
|
|
835
|
+
// turn-ending `result` is only mined for usage when nothing better arrived.
|
|
836
|
+
let assistantBudgetSent = false;
|
|
515
837
|
// A new turn supersedes any earlier one still holding this session's process
|
|
516
838
|
// open, so held runs cannot stack up across a conversation.
|
|
517
839
|
if (sessionKey()) {
|
|
518
|
-
|
|
840
|
+
releaseHeldSession(sessionKey());
|
|
519
841
|
}
|
|
520
842
|
// Arms (or re-arms) the idle countdown that eventually closes stdin.
|
|
521
843
|
const scheduleRelease = () => {
|
|
@@ -630,6 +952,12 @@ async function queryClaudeSDK(command, options = {}, ws, context) {
|
|
|
630
952
|
if (decision.cancelled) {
|
|
631
953
|
return { behavior: 'deny', message: 'Permission request cancelled' };
|
|
632
954
|
}
|
|
955
|
+
// A client answered. Announce it on the run stream so the replay buffer
|
|
956
|
+
// and every other attached tab drop the prompt — resolving happens over
|
|
957
|
+
// the inbound socket only, so without this a mid-run page refresh
|
|
958
|
+
// replays the `permission_request` with nothing to retract it and the
|
|
959
|
+
// already-answered prompt resurrects.
|
|
960
|
+
ws.send(createNormalizedMessage({ kind: 'permission_resolved', requestId, sessionId: capturedSessionId || sessionId || null, provider: 'claude' }));
|
|
633
961
|
if (decision.allow) {
|
|
634
962
|
if (decision.rememberEntry && typeof decision.rememberEntry === 'string') {
|
|
635
963
|
if (!sdkOptions.allowedTools.includes(decision.rememberEntry)) {
|
|
@@ -643,10 +971,13 @@ async function queryClaudeSDK(command, options = {}, ws, context) {
|
|
|
643
971
|
}
|
|
644
972
|
return { behavior: 'deny', message: decision.message ?? 'User denied tool use' };
|
|
645
973
|
};
|
|
974
|
+
// The SDK's own `query`, unless the caller supplies one (tests script the
|
|
975
|
+
// stream to drive the hold logic below without a CLI process).
|
|
976
|
+
const createQuery = context.createQuery ?? query;
|
|
646
977
|
let heldPrompt = createHeldPromptStream(promptMessages);
|
|
647
978
|
releasePromptStream = heldPrompt.release;
|
|
648
979
|
try {
|
|
649
|
-
queryInstance =
|
|
980
|
+
queryInstance = createQuery({
|
|
650
981
|
prompt: heldPrompt.stream,
|
|
651
982
|
options: sdkOptions
|
|
652
983
|
});
|
|
@@ -660,7 +991,7 @@ async function queryClaudeSDK(command, options = {}, ws, context) {
|
|
|
660
991
|
heldPrompt.release();
|
|
661
992
|
heldPrompt = createHeldPromptStream(promptMessages);
|
|
662
993
|
releasePromptStream = heldPrompt.release;
|
|
663
|
-
queryInstance =
|
|
994
|
+
queryInstance = createQuery({
|
|
664
995
|
prompt: heldPrompt.stream,
|
|
665
996
|
options: sdkOptions
|
|
666
997
|
});
|
|
@@ -699,19 +1030,47 @@ async function queryClaudeSDK(command, options = {}, ws, context) {
|
|
|
699
1030
|
if (transformedMessage.parentToolUseId && !msg.parentToolUseId) {
|
|
700
1031
|
msg.parentToolUseId = transformedMessage.parentToolUseId;
|
|
701
1032
|
}
|
|
1033
|
+
if (isSubagentPromptEcho(msg)) {
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
702
1036
|
ws.send(msg);
|
|
703
1037
|
}
|
|
704
|
-
// Extract and send token budget updates from assistant
|
|
705
|
-
|
|
1038
|
+
// Extract and send token budget updates from assistant usage payloads,
|
|
1039
|
+
// falling back to the turn's cumulative bill only for SDK builds that
|
|
1040
|
+
// report no per-assistant usage at all.
|
|
1041
|
+
const tokenBudgetData = extractTokenBudget(message)
|
|
1042
|
+
|| (assistantBudgetSent ? null : extractCumulativeTokenBudget(message));
|
|
706
1043
|
if (tokenBudgetData) {
|
|
1044
|
+
if (message.type === 'assistant') {
|
|
1045
|
+
assistantBudgetSent = true;
|
|
1046
|
+
}
|
|
707
1047
|
ws.send(createNormalizedMessage({ kind: 'status', text: 'token_budget', tokenBudget: tokenBudgetData, sessionId: capturedSessionId || sessionId || null, provider: 'claude' }));
|
|
708
1048
|
}
|
|
709
1049
|
if (startsBackgroundWork(message)) {
|
|
710
1050
|
backgroundWorkPending = true;
|
|
711
1051
|
}
|
|
1052
|
+
if (message.type === 'system' && message.subtype === 'task_started') {
|
|
1053
|
+
sawTaskEventThisTurn = true;
|
|
1054
|
+
}
|
|
1055
|
+
backgroundWork.apply(sessionKey(), message);
|
|
1056
|
+
// A task the user stopped gets no follow-up turn from the CLI — only its
|
|
1057
|
+
// `stopped` notification — so when that was the last outstanding task
|
|
1058
|
+
// nothing will ever push the `result` the release below waits for, and
|
|
1059
|
+
// the process would sit until the idle ceiling. Release it here. A
|
|
1060
|
+
// completed task is different: the CLI relays its result in a turn of
|
|
1061
|
+
// its own, which closing stdin now would cut short.
|
|
1062
|
+
if (heldForBackgroundWork
|
|
1063
|
+
&& message.type === 'system'
|
|
1064
|
+
&& message.subtype === 'task_notification'
|
|
1065
|
+
&& message.status === 'stopped'
|
|
1066
|
+
&& !backgroundWork.hasOutstanding(sessionKey())) {
|
|
1067
|
+
heldForBackgroundWork = false;
|
|
1068
|
+
releasePromptStream();
|
|
1069
|
+
}
|
|
712
1070
|
if (message.type === 'result') {
|
|
713
1071
|
// The turn is done as far as the client is concerned.
|
|
714
1072
|
const abortPending = sessionKey() ? abortedSessionIds.has(sessionKey()) : false;
|
|
1073
|
+
const stillOutstanding = backgroundWork.hasOutstanding(sessionKey());
|
|
715
1074
|
if (!turnCompleteSent && !abortPending) {
|
|
716
1075
|
turnCompleteSent = true;
|
|
717
1076
|
ws.send(createCompleteMessage({ provider: 'claude', sessionId: capturedSessionId || sessionId || null, exitCode: 0 }));
|
|
@@ -723,9 +1082,10 @@ async function queryClaudeSDK(command, options = {}, ws, context) {
|
|
|
723
1082
|
stopReason: 'completed'
|
|
724
1083
|
});
|
|
725
1084
|
}
|
|
726
|
-
else if (heldForBackgroundWork && !abortPending) {
|
|
1085
|
+
else if (heldForBackgroundWork && !abortPending && !stillOutstanding) {
|
|
727
1086
|
// A result after the turn already reported complete means the work we
|
|
728
|
-
// held the process open for has finished and pushed a follow-up turn
|
|
1087
|
+
// held the process open for has finished and pushed a follow-up turn
|
|
1088
|
+
// — the last of it, when nothing else is still running.
|
|
729
1089
|
notifyBackgroundWorkCompleted({
|
|
730
1090
|
userId: ws?.userId || null,
|
|
731
1091
|
provider: 'claude',
|
|
@@ -733,11 +1093,26 @@ async function queryClaudeSDK(command, options = {}, ws, context) {
|
|
|
733
1093
|
sessionName: sessionSummary
|
|
734
1094
|
});
|
|
735
1095
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
1096
|
+
// Work started during this turn, or work from an earlier turn that
|
|
1097
|
+
// has not settled yet (a follow-up turn reports one task in while
|
|
1098
|
+
// another is still going), is still running. Hold the process open
|
|
1099
|
+
// so it can finish and report back in a follow-up turn; the ceiling
|
|
1100
|
+
// is only a backstop for work that never reports.
|
|
1101
|
+
//
|
|
1102
|
+
// The release when the last task settles is this same branch on the
|
|
1103
|
+
// follow-up turn the CLI pushes for it, not the settling event
|
|
1104
|
+
// itself: closing stdin at that moment would cut the turn that
|
|
1105
|
+
// relays the task's result.
|
|
1106
|
+
//
|
|
1107
|
+
// When the turn reported its tasks, the tracker is the whole truth: an
|
|
1108
|
+
// Agent call without `run_in_background` is scored as background by
|
|
1109
|
+
// `startsBackgroundWork`, but the CLI runs it in the foreground and
|
|
1110
|
+
// it has settled before this `result` — holding for it kept a process
|
|
1111
|
+
// alive for the full ceiling with nothing outstanding.
|
|
1112
|
+
const holdForTurn = sawTaskEventThisTurn ? stillOutstanding : backgroundWorkPending || stillOutstanding;
|
|
1113
|
+
backgroundWorkPending = false;
|
|
1114
|
+
sawTaskEventThisTurn = false;
|
|
1115
|
+
if (holdForTurn) {
|
|
741
1116
|
heldForBackgroundWork = true;
|
|
742
1117
|
scheduleRelease();
|
|
743
1118
|
}
|
|
@@ -863,6 +1238,34 @@ async function abortClaudeSDKSession(sessionId) {
|
|
|
863
1238
|
return false;
|
|
864
1239
|
}
|
|
865
1240
|
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Sessions whose background tasks are still outstanding, with the tasks.
|
|
1243
|
+
*
|
|
1244
|
+
* A session stays here after its turn's `result` for as long as the process
|
|
1245
|
+
* is held open for the work — which is exactly the window in which nothing
|
|
1246
|
+
* else (the chat run registry marks the run completed at `result`) knows the
|
|
1247
|
+
* session is still busy.
|
|
1248
|
+
* @returns {Array<{ sessionId: string, tasks: Array<import('../../../../shared/types.js').BackgroundTaskSummary> }>}
|
|
1249
|
+
*/
|
|
1250
|
+
function listClaudeSDKBackgroundWork() {
|
|
1251
|
+
return backgroundWork.list();
|
|
1252
|
+
}
|
|
1253
|
+
/**
|
|
1254
|
+
* Stops one outstanding background task through the SDK, which then emits a
|
|
1255
|
+
* `task_notification` with status `stopped` — the same event that drops the
|
|
1256
|
+
* task from the tracker and settles its card.
|
|
1257
|
+
* @param {string} sessionId - Session identifier
|
|
1258
|
+
* @param {string} taskId - The task's `task_id` as reported on `task_started`
|
|
1259
|
+
* @returns {Promise<boolean>} False when no live process is tracking the task
|
|
1260
|
+
*/
|
|
1261
|
+
async function stopClaudeSDKTask(sessionId, taskId) {
|
|
1262
|
+
const session = getSession(sessionId);
|
|
1263
|
+
if (!session || !backgroundWork.has(sessionId, taskId)) {
|
|
1264
|
+
return false;
|
|
1265
|
+
}
|
|
1266
|
+
await session.instance.stopTask(taskId);
|
|
1267
|
+
return true;
|
|
1268
|
+
}
|
|
866
1269
|
/**
|
|
867
1270
|
* Checks if an SDK session is currently active
|
|
868
1271
|
* @param {string} sessionId - Session identifier
|
|
@@ -870,7 +1273,21 @@ async function abortClaudeSDKSession(sessionId) {
|
|
|
870
1273
|
*/
|
|
871
1274
|
function isClaudeSDKSessionActive(sessionId) {
|
|
872
1275
|
const session = getSession(sessionId);
|
|
873
|
-
return session && session.status === 'active';
|
|
1276
|
+
return Boolean(session && session.status === 'active');
|
|
1277
|
+
}
|
|
1278
|
+
/**
|
|
1279
|
+
* When the run behind a session started, or null when no run is up.
|
|
1280
|
+
*
|
|
1281
|
+
* The history reader uses this to tell a background agent launched by the
|
|
1282
|
+
* live process (still able to report back) from one launched by an earlier
|
|
1283
|
+
* process that has since exited (never will): a launch row older than the
|
|
1284
|
+
* live run cannot belong to it.
|
|
1285
|
+
* @param {string} sessionId - Session identifier
|
|
1286
|
+
* @returns {number|null} Epoch milliseconds the live run started, or null
|
|
1287
|
+
*/
|
|
1288
|
+
function getClaudeSDKSessionStartTime(sessionId) {
|
|
1289
|
+
const session = getSession(sessionId);
|
|
1290
|
+
return session && session.status === 'active' ? session.startTime : null;
|
|
874
1291
|
}
|
|
875
1292
|
/**
|
|
876
1293
|
* Gets all active SDK session IDs
|
|
@@ -922,7 +1339,9 @@ export const claudeRuntime = {
|
|
|
922
1339
|
resolve: resolveToolApproval,
|
|
923
1340
|
listPending: getPendingApprovalsForSession,
|
|
924
1341
|
},
|
|
1342
|
+
listBackgroundWork: listClaudeSDKBackgroundWork,
|
|
1343
|
+
stopBackgroundTask: stopClaudeSDKTask,
|
|
925
1344
|
};
|
|
926
1345
|
// Export public API
|
|
927
|
-
export { queryClaudeSDK, abortClaudeSDKSession, isClaudeSDKSessionActive, getActiveClaudeSDKSessions, resolveToolApproval, getPendingApprovalsForSession, reconnectSessionWriter };
|
|
1346
|
+
export { queryClaudeSDK, abortClaudeSDKSession, listClaudeSDKBackgroundWork, stopClaudeSDKTask, isClaudeSDKSessionActive, getClaudeSDKSessionStartTime, getActiveClaudeSDKSessions, resolveToolApproval, getPendingApprovalsForSession, reconnectSessionWriter, extractTokenBudget, extractCumulativeTokenBudget };
|
|
928
1347
|
//# sourceMappingURL=claude-runtime.provider.js.map
|