chainlesschain 0.165.2 → 0.165.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 +151 -29
- package/package.json +2 -2
- package/src/assets/web-panel/assets/{AIOps-lS1R0Cza.js → AIOps-C__nnraW.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BmlgBPsj.js → ActionButton-CsKWHEZ-.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CNKczv1S.js → Analytics-BhIjfjWO.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BuZGJARQ.js → AppLayout-BjuXFzWZ.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-Dm73Sl-O.js → Artifacts-k6whDkZJ.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BGMW7A5e.js → Audit-C4FBMYRh.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BQ6M54JR.js → BackgroundAgents-C_vRrSXk.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DBzGP0bR.js → Backup-CngFZeVp.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-D1mLCoOV.js → BaseInput-B_H9EBRm.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BUfcN7p8.js → Chat-DLEC5kt7.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-xijcWkJe.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-Du0Yg5Pi.js → Checkbox-m3ClR4xh.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B2RXziHW.js → Codegen-CmLSFrgp.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DWhekOrR.js → Col-DFGQteHN.js} +1 -1
- package/src/assets/web-panel/assets/{Community-HQhrkon4.js → Community-EUUVORHE.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-izHNb4uz.js → Compact-2PSg0Yr7.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BDwLy41-.js → Compliance-CcKur7gB.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DFJhLa7K.js → Cowork-DK_Fezfa.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DYY9RG7-.js → Cron-Dbw89xl7.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-rr7tJTtv.js → Crosschain-CH66h_Ec.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D2sfHRLi.js → DID-D1igRb17.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-q_eGdhha.js → Dashboard-DVAsrobk.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Cufrh2Bz.js → Dropdown-Dl7W8AQs.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-B-kdv10f.js → EmailListRenderer-D5tpaEQC.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-D21XjgfG.js → FamilyGuardDashboard-O_VQf8gq.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CAwRTLZH.js → Federation-BTVcgS9n.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-vx3daNDF.js → FormItemContext-BRnkJAIz.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CRWY2wU4.js → GenericCardRenderer-8OWSCkDj.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Q6SwauyD.js → Git-WXLYTQj2.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BJ1q4IQZ.js → Governance-BezaUhtc.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CSWjROgD.js → Inference-CuRay3Gu.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-fzuQsWuY.js → KnowledgeGraph-DfWLDW1m.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DVF8Mnns.js → Logs-C55y2pPY.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-hDpWdiBc.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-BQP7LOA4.js → Marketplace-Dk08Uycg.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BNlJCmNc.js → McpTools-C11fSB5V.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-DLLg5WQ4.js → Memory-mr0eZc97.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CR2skNAF.js → MobileBridge-C0iCSRbb.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BxVavObl.js → MobileProjects-CY-xMG8Z.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-B17pgqMI.js → Mtc-Bplqc_Wc.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-4UmV5cIL.js → MtcAudit-BlzwsoSM.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DoMEXEcU.js → Multisig-BBLmTty6.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-h9DMXFX4.js → NLProgramming-DtT1uf1W.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cihn-xX8.js → Notes-DcqQAxTK.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BE6ZGa3R.js → NotificationSettings-cb0kWoZe.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CnwojoSI.js → OrderTableRenderer-kw9HZQNN.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-B2vpwmjb.js → Organization-DlTlbkUN.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-C4z28R0-.js → Overflow-pp1qs-oY.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BVlFkwhW.js → P2P-BESLnyYz.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BXbEdL5B.js → PdhVaultBrowser-B-J1mGuf.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-C28xs4lp.js → Permissions-B36PeT1_.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Dgl_rBjM.js → PersonalDataHub-CTK2ad-3.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-3QUIhrKI.js → Pipeline-zJNGXsac.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-8Gh33OZ5.js → Privacy-b9fz0Qf0.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BNmg4tZi.js → ProjectInit-DjZbZgiB.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-vgMfeCf9.js → ProjectSettings-C-hHJXlD.js} +2 -2
- package/src/assets/web-panel/assets/Projects-BC9KSDM6.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CXoOa8eX.js → Providers-Dz-CAYYU.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BhfTF0oS.js → QrScannerModal-A0yoQ3-3.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-C746HEAj.js → QuickAsk-DrFgFJNC.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BSej8Eo0.js → Recommend-KC8hF1g4.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-f3gmnlG3.js → RemoteSession-DGTPIk6u.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-CyvybpkN.js → Reputation-QmbwM7Yk.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DwV2PeYn.js → Row-BxjJylia.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-11GrzjZy.js → RssFeed-B7Wda1J6.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BjKXkrAY.js → Search-_plQ_YSA.js} +1 -1
- package/src/assets/web-panel/assets/{Security-eWiFb9Yk.js → Security-CD2YJZfx.js} +2 -2
- package/src/assets/web-panel/assets/{Services-CdCsMAtt.js → Services-qQE7NmwE.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-4Q2UTKQ5.js → Skeleton-DgQqkFf7.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-v4rtYrRj.js → Skills-C4C0oFFt.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CRhsFvd_.js → Sla-Px2N2B5c.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-DN6C3lQd.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-D16zonl7.js → SyncSettings-jm5aH_m7.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Xxozz0i_.js → Tasks-DlkJcv67.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CXJpPtCT.js → Templates-DyrTHUBs.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-XRV0L1ZF.js → Tenant-mC434PtL.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CYuO1i_w.js → Terminal-o0_s3NgK.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BXqitWsu.js → TimelineRenderer-DAGlAXOw.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BvPrDHIy.js → Tokens-BnulS_bs.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DhCrSTf5.js → Trigger-suQbVXYM.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DmsuZD6K.js → Trust-DbIJAPo5.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-D_yrts5C.js → UkeySign-CQNpbIHi.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-B01ihPrm.js → VideoEditing-D8aWCERk.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DpUjKa-N.js → Wallet-CuLpYfZc.js} +2 -2
- package/src/assets/web-panel/assets/{WebAuthn-CL07yON6.js → WebAuthn-CsfG8ZMc.js} +2 -2
- package/src/assets/web-panel/assets/{WorkflowEditor-CLMflnRr.js → WorkflowEditor-BYsEAZbd.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DtUqe8h_.js → chat-FT4Um3-I.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DPKrgVfy.js → colors-CKbS_Wlt.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BTt2GtOm.js → compact-item-CFJtzuJM.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-D_VeUc1J.js → createContext-B9kSRW6K.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DJZ0gAMu.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-1kndiylj.js → hasIn-DR-x0Xpi.js} +1 -1
- package/src/assets/web-panel/assets/{index-dVc-CXY4.js → index-7jHr_A_k.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFIZ_1Sf.js → index-B3ZX81mK.js} +1 -1
- package/src/assets/web-panel/assets/{index-fk2Rjacw.js → index-B7osrXqy.js} +3 -3
- package/src/assets/web-panel/assets/{index-CHG-KcS4.js → index-BGbPnC5x.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dbbymxpj.js → index-BI5hP_qy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaZAbw9A.js → index-BK3TiKVq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzjkKUmR.js → index-BVPU43b1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAXfRKfG.js → index-BW-t9n-q.js} +1 -1
- package/src/assets/web-panel/assets/{index-8nz_fmlj.js → index-BfFCQHL3.js} +1 -1
- package/src/assets/web-panel/assets/index-Bizb4hkw.js +1 -0
- package/src/assets/web-panel/assets/{index-DdkplL9R.js → index-Bt4fS2eL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DG2MZQ3f.js → index-BwR7yc2h.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfKBRdSS.js → index-Bzz0C1BZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-GsoUQ2M7.js → index-C2JvmYRc.js} +1 -1
- package/src/assets/web-panel/assets/{index-l1BETrDb.js → index-CGaXUsIs.js} +1 -1
- package/src/assets/web-panel/assets/{index-4bna2_SR.js → index-CJmIQ9XR.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfGl8CqG.js → index-C_enk9I_.js} +1 -1
- package/src/assets/web-panel/assets/{index-D95OFht7.js → index-Cr2FLUsD.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsJCDUJG.js → index-CvrCCqJt.js} +1 -1
- package/src/assets/web-panel/assets/{index-sDoMHTNA.js → index-D4LfPvWA.js} +1 -1
- package/src/assets/web-panel/assets/{index-By5n8up9.js → index-DMGmg497.js} +1 -1
- package/src/assets/web-panel/assets/{index-ocf06EVQ.js → index-DShSkww-.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bhudc_Ez.js → index-DTxNy0ZU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CX81qSM4.js → index-DW4BWjTk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BlDNVgBt.js → index-DWdqx7zI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CcO04eDn.js → index-Dap9c3eD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dwqmtk65.js → index-DcfxhKXR.js} +1 -1
- package/src/assets/web-panel/assets/{index-2eyAXE3d.js → index-DdkIhfi-.js} +1 -1
- package/src/assets/web-panel/assets/{index-brCInrzq.js → index-DeSgw-WV.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJ8vXGOa.js → index-DiNUEpSQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHpBMWCh.js → index-DjEP7WkH.js} +1 -1
- package/src/assets/web-panel/assets/{index-m31Ka8hZ.js → index-DtkFqPVA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CtF7EN49.js → index-KqDaCApw.js} +1 -1
- package/src/assets/web-panel/assets/index-OHSl-xCh.js +1 -0
- package/src/assets/web-panel/assets/{index-B9KvcS7R.js → index-OSzjTzGM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CauoBQkH.js → index-QBSeNVO3.js} +1 -1
- package/src/assets/web-panel/assets/{index-FzdwcSy2.js → index-WE08gMJP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxdTdBix.js → index-r2VI1Ikk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BepLZwgB.js → index-tqSEHPRT.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CvyYJd7z.js → initDefaultProps-Dd7n7VgI.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DYZkhUdz.js → motion-BwxouRw1.js} +1 -1
- package/src/assets/web-panel/assets/{move-slnJRVT1.js → move-DObN0PG9.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DVc0CKmy.js → mtc-parser-B3nOUQc7.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BCXAtHCq.js → omit-o9WU2Nbl.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DBsemz_K.js → pickAttrs-CL_vvfQ_.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BRtkJ-nv.js → placementArrow-CYrM2tyK.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Cebq7EZn.js → responsiveObserve-k_06cQ96.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DT7qvId2.js → slide-CPKG0pxS.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-pQiITLkG.js → statusUtils-BDDEeLTw.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-c-19BVKQ.js → styleChecker-Cmb7RTh7.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DsS5-0bE.js → useFlexGapSupport-e2IedC4N.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CxGiMe5n.js → useFs-CE_gxVnm.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D9btVID5.js → usePersonalDataHub-BkMIIKMz.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CUYFsFEN.js → vnode-DW886XV1.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CXmn_35j.js → zoom-Dwo_adaf.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/commands/agent.js +105 -35
- package/src/commands/artifacts.js +363 -33
- package/src/commands/cowork.js +202 -36
- package/src/commands/session-budget.js +155 -0
- package/src/commands/session-location.js +948 -0
- package/src/commands/session.js +72 -46
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/artifact-protocol.js +77 -13
- package/src/gateways/ws/session-protocol.js +391 -24
- package/src/gateways/ws/ws-agent-handler.js +191 -14
- package/src/gateways/ws/ws-server.js +14 -3
- package/src/gateways/ws/ws-session-gateway.js +101 -5
- package/src/harness/jsonl-session-store.js +1210 -0
- package/src/lib/agent-team/team-runner.js +43 -13
- package/src/lib/artifact-access-ledger.js +461 -0
- package/src/lib/artifact-cleanup-ledger.js +861 -0
- package/src/lib/artifact-deletion-ledger.js +677 -0
- package/src/lib/artifact-store.js +256 -51
- package/src/lib/background-agent-keeper-protocol.js +75 -4
- package/src/lib/background-agent-launch-barrier.js +74 -0
- package/src/lib/background-agent-supervisor.js +149 -5
- package/src/lib/background-turn-bootstrap-protocol.js +4 -0
- package/src/lib/command-lifecycle-report.js +8 -4
- package/src/lib/cowork-adapter.js +9 -5
- package/src/lib/cowork-task-runner.js +20 -0
- package/src/lib/cowork-workflow.js +178 -20
- package/src/lib/direct-model-usage.js +62 -22
- package/src/lib/dynamic-workflow-runtime.js +3184 -111
- package/src/lib/execution-location-result-apply.js +339 -0
- package/src/lib/execution-location-result-artifact.js +271 -0
- package/src/lib/execution-location-result-review.js +253 -0
- package/src/lib/execution-location-result-store.js +331 -0
- package/src/lib/execution-location-result.js +617 -0
- package/src/lib/execution-location-target.js +236 -1
- package/src/lib/managed-tool-checkpoint.js +47 -4
- package/src/lib/process-execution-broker/workspace-transaction.js +3 -0
- package/src/lib/session-budget-production-root.js +376 -0
- package/src/lib/session-budget-runtime.js +109 -18
- package/src/lib/session-budget-usage.js +63 -0
- package/src/lib/session-host-snapshot.js +19 -2
- package/src/lib/session-resource-budget.js +766 -105
- package/src/lib/sub-agent-context.js +69 -22
- package/src/lib/web-ui-server.js +12 -1
- package/src/lib/with-file-lock.js +175 -26
- package/src/repl/agent-repl.js +237 -16
- package/src/runtime/agent-core.js +123 -0
- package/src/runtime/headless-runner.js +135 -46
- package/src/runtime/headless-stream.js +133 -25
- package/src/runtime/policies/agent-policy.js +10 -0
- package/src/workers/background-agent-keeper.js +112 -19
- package/src/workers/background-agent-worker.js +383 -134
- package/src/workers/background-turn-bootstrap.js +13 -8
- package/src/assets/web-panel/assets/ChatBubbleRenderer-CY5m8ZHg.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-BLif4QSg.js +0 -1
- package/src/assets/web-panel/assets/Projects-BhtAVilc.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-DLjKsDVu.js +0 -1
- package/src/assets/web-panel/assets/devWarning-Bj5nUW2v.js +0 -1
- package/src/assets/web-panel/assets/index-CPcM-eqo.js +0 -1
- package/src/assets/web-panel/assets/index-xeSyVoRe.js +0 -1
|
@@ -19,6 +19,17 @@ import {
|
|
|
19
19
|
} from "../../lib/mcp-ledger-recovery-admission.js";
|
|
20
20
|
import { readSessionHostResumeState } from "../../lib/session-host-snapshot.js";
|
|
21
21
|
import { sanitizePersistedMessages } from "../../lib/session-message-provenance.js";
|
|
22
|
+
import {
|
|
23
|
+
deleteJsonlSession,
|
|
24
|
+
startSession as startJsonlSession,
|
|
25
|
+
} from "../../harness/jsonl-session-store.js";
|
|
26
|
+
import {
|
|
27
|
+
normalizeSessionBudgetRootConfig,
|
|
28
|
+
openProductionSessionBudgetRoot,
|
|
29
|
+
resolveSessionBudgetRootOptions,
|
|
30
|
+
sessionBudgetAdmissionError,
|
|
31
|
+
} from "../../lib/session-budget-production-root.js";
|
|
32
|
+
import { mergePricing } from "../../lib/llm-pricing.js";
|
|
22
33
|
|
|
23
34
|
const PAYLOAD_DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
24
35
|
const RAW_AUTHORITY_HASH = /^[0-9a-f]{64}$/;
|
|
@@ -467,6 +478,30 @@ function envelopeError(id, code, message, sessionId, details = {}) {
|
|
|
467
478
|
// Phase 5 envelope opt-in via beta flag `unified-envelope-2026-04-16`.
|
|
468
479
|
// Falls back to false if BetaFlags is unavailable so legacy behavior wins.
|
|
469
480
|
const PHASE5_ENVELOPE_FLAG = "unified-envelope-2026-04-16";
|
|
481
|
+
|
|
482
|
+
function wsBudgetDependency(server, name, fallback) {
|
|
483
|
+
const candidate = server?._sessionBudgetDependencies?.[name];
|
|
484
|
+
return typeof candidate === "function" ? candidate : fallback;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function resolveWsSessionBudget(message) {
|
|
488
|
+
return resolveSessionBudgetRootOptions({
|
|
489
|
+
sessionBudget: message.sessionBudget,
|
|
490
|
+
sessionMaxConcurrent: message.sessionMaxConcurrent,
|
|
491
|
+
sessionMaxSpawns: message.sessionMaxSpawns,
|
|
492
|
+
sessionMaxDepth: message.sessionMaxDepth,
|
|
493
|
+
sessionMaxTurns: message.sessionMaxTurns,
|
|
494
|
+
sessionMaxTokens: message.sessionMaxTokens,
|
|
495
|
+
sessionMaxCostUsd: message.sessionMaxCostUsd,
|
|
496
|
+
sessionMaxWallMs: message.sessionMaxWallMs,
|
|
497
|
+
sessionMaxToolMs: message.sessionMaxToolMs,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function sameSessionBudgetConfig(left, right) {
|
|
502
|
+
return JSON.stringify(left || null) === JSON.stringify(right || null);
|
|
503
|
+
}
|
|
504
|
+
|
|
470
505
|
async function _isPhase5EnvelopesEnabled() {
|
|
471
506
|
try {
|
|
472
507
|
const { getBetaFlags } =
|
|
@@ -478,9 +513,22 @@ async function _isPhase5EnvelopesEnabled() {
|
|
|
478
513
|
}
|
|
479
514
|
}
|
|
480
515
|
|
|
481
|
-
async function ensureSessionHandler(
|
|
482
|
-
|
|
483
|
-
|
|
516
|
+
async function ensureSessionHandler(
|
|
517
|
+
server,
|
|
518
|
+
ws,
|
|
519
|
+
session,
|
|
520
|
+
{ sessionHostLease: suppliedSessionHostLease = null } = {},
|
|
521
|
+
) {
|
|
522
|
+
const budgetConfig = session.sessionBudgetRoot
|
|
523
|
+
? normalizeSessionBudgetRootConfig(session.sessionBudgetRoot)
|
|
524
|
+
: resolveSessionBudgetRootOptions({});
|
|
525
|
+
if (budgetConfig.enabled && session.type === "chat") {
|
|
526
|
+
const error = new Error(
|
|
527
|
+
"Durable WebSocket session budgets require an agent session",
|
|
528
|
+
);
|
|
529
|
+
error.code = "CC_SESSION_BUDGET_WS_AGENT_REQUIRED";
|
|
530
|
+
suppliedSessionHostLease?.release?.();
|
|
531
|
+
throw error;
|
|
484
532
|
}
|
|
485
533
|
|
|
486
534
|
const { WebSocketInteractionAdapter } =
|
|
@@ -503,6 +551,17 @@ async function ensureSessionHandler(server, ws, session) {
|
|
|
503
551
|
},
|
|
504
552
|
});
|
|
505
553
|
|
|
554
|
+
const existingHandler = server.sessionHandlers.get(session.id);
|
|
555
|
+
if (existingHandler) {
|
|
556
|
+
suppliedSessionHostLease?.release?.();
|
|
557
|
+
existingHandler.assertSessionBudgetAdmission?.("WebSocket resume");
|
|
558
|
+
if (typeof existingHandler.attachInteraction === "function") {
|
|
559
|
+
existingHandler.attachInteraction(session.interaction);
|
|
560
|
+
} else {
|
|
561
|
+
existingHandler.interaction = session.interaction;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
506
565
|
// Route MCP elicitation through the authenticated WS question channel. The
|
|
507
566
|
// MCP client may be shared by the runtime, so this is deliberately only a
|
|
508
567
|
// transport hook; the MCP request/answer ids remain inside the pending
|
|
@@ -524,6 +583,8 @@ async function ensureSessionHandler(server, ws, session) {
|
|
|
524
583
|
);
|
|
525
584
|
}
|
|
526
585
|
|
|
586
|
+
if (existingHandler) return existingHandler;
|
|
587
|
+
|
|
527
588
|
let handler;
|
|
528
589
|
if (session.type === "chat") {
|
|
529
590
|
const { WSChatHandler } = await import("../../lib/ws-chat-handler.js");
|
|
@@ -533,18 +594,79 @@ async function ensureSessionHandler(server, ws, session) {
|
|
|
533
594
|
});
|
|
534
595
|
} else {
|
|
535
596
|
const { WSAgentHandler } = await import("./ws-agent-handler.js");
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
597
|
+
let sessionHostLease =
|
|
598
|
+
suppliedSessionHostLease ||
|
|
599
|
+
wsBudgetDependency(
|
|
600
|
+
server,
|
|
601
|
+
"acquireSessionHostLease",
|
|
602
|
+
acquireSessionHostLease,
|
|
603
|
+
)(session.id, { hostKind: "ws" });
|
|
604
|
+
let sessionBudgetRoot = null;
|
|
539
605
|
try {
|
|
606
|
+
if (budgetConfig.enabled) {
|
|
607
|
+
const priceTable =
|
|
608
|
+
budgetConfig.limits.maxUsd != null
|
|
609
|
+
? wsBudgetDependency(server, "mergePricing", mergePricing)(
|
|
610
|
+
server.sessionManager.config?.llm?.pricing,
|
|
611
|
+
)
|
|
612
|
+
: undefined;
|
|
613
|
+
sessionBudgetRoot = wsBudgetDependency(
|
|
614
|
+
server,
|
|
615
|
+
"openProductionSessionBudgetRoot",
|
|
616
|
+
openProductionSessionBudgetRoot,
|
|
617
|
+
)(session.id, budgetConfig, {
|
|
618
|
+
persist: true,
|
|
619
|
+
signal: sessionHostLease.signal || null,
|
|
620
|
+
table: priceTable,
|
|
621
|
+
});
|
|
622
|
+
if (
|
|
623
|
+
sessionBudgetRoot?.enabled !== true ||
|
|
624
|
+
!sessionBudgetRoot.budget ||
|
|
625
|
+
!sessionBudgetRoot.options ||
|
|
626
|
+
sessionBudgetRoot.options.sessionBudget !==
|
|
627
|
+
sessionBudgetRoot.budget ||
|
|
628
|
+
typeof sessionBudgetRoot.close !== "function"
|
|
629
|
+
) {
|
|
630
|
+
const error = new Error(
|
|
631
|
+
"WebSocket session budget root is invalid",
|
|
632
|
+
);
|
|
633
|
+
error.code = "CC_SESSION_BUDGET_ROOT_INVALID";
|
|
634
|
+
throw error;
|
|
635
|
+
}
|
|
636
|
+
if (sessionBudgetRoot.budget.signal?.aborted === true) {
|
|
637
|
+
throw sessionBudgetAdmissionError(
|
|
638
|
+
sessionBudgetRoot.budget.reason?.(),
|
|
639
|
+
"WebSocket startup",
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
540
643
|
handler = new WSAgentHandler({
|
|
541
644
|
session,
|
|
542
645
|
interaction: session.interaction,
|
|
543
646
|
db: server.sessionManager.db,
|
|
544
647
|
sessionHostLease,
|
|
648
|
+
sessionBudgetRoot,
|
|
545
649
|
});
|
|
650
|
+
sessionHostLease = null;
|
|
651
|
+
sessionBudgetRoot = null;
|
|
546
652
|
} catch (error) {
|
|
547
|
-
|
|
653
|
+
const cleanupErrors = [];
|
|
654
|
+
try {
|
|
655
|
+
sessionBudgetRoot?.close?.();
|
|
656
|
+
} catch (cleanupError) {
|
|
657
|
+
cleanupErrors.push(cleanupError);
|
|
658
|
+
}
|
|
659
|
+
try {
|
|
660
|
+
sessionHostLease?.release?.();
|
|
661
|
+
} catch (cleanupError) {
|
|
662
|
+
cleanupErrors.push(cleanupError);
|
|
663
|
+
}
|
|
664
|
+
if (cleanupErrors.length > 0) {
|
|
665
|
+
throw new AggregateError(
|
|
666
|
+
[error, ...cleanupErrors],
|
|
667
|
+
"WebSocket handler bootstrap and authority cleanup both failed",
|
|
668
|
+
);
|
|
669
|
+
}
|
|
548
670
|
throw error;
|
|
549
671
|
}
|
|
550
672
|
}
|
|
@@ -578,9 +700,40 @@ export async function handleSessionCreate(server, id, ws, message) {
|
|
|
578
700
|
worktreeIsolation,
|
|
579
701
|
systemPromptExtension,
|
|
580
702
|
shellPolicyOverrides,
|
|
703
|
+
sessionBudget,
|
|
704
|
+
sessionMaxConcurrent,
|
|
705
|
+
sessionMaxSpawns,
|
|
706
|
+
sessionMaxDepth,
|
|
707
|
+
sessionMaxTurns,
|
|
708
|
+
sessionMaxTokens,
|
|
709
|
+
sessionMaxCostUsd,
|
|
710
|
+
sessionMaxWallMs,
|
|
711
|
+
sessionMaxToolMs,
|
|
581
712
|
} = message;
|
|
582
713
|
|
|
714
|
+
let createdSessionId = null;
|
|
715
|
+
let canonicalSessionCreated = false;
|
|
716
|
+
let bootstrapLease = null;
|
|
717
|
+
let delegatedBootstrapLease = null;
|
|
583
718
|
try {
|
|
719
|
+
const sessionBudgetRoot = resolveWsSessionBudget({
|
|
720
|
+
sessionBudget,
|
|
721
|
+
sessionMaxConcurrent,
|
|
722
|
+
sessionMaxSpawns,
|
|
723
|
+
sessionMaxDepth,
|
|
724
|
+
sessionMaxTurns,
|
|
725
|
+
sessionMaxTokens,
|
|
726
|
+
sessionMaxCostUsd,
|
|
727
|
+
sessionMaxWallMs,
|
|
728
|
+
sessionMaxToolMs,
|
|
729
|
+
});
|
|
730
|
+
if (sessionBudgetRoot.enabled && (sessionType || "agent") !== "agent") {
|
|
731
|
+
const error = new Error(
|
|
732
|
+
"Durable WebSocket session budgets require sessionType=agent",
|
|
733
|
+
);
|
|
734
|
+
error.code = "CC_SESSION_BUDGET_WS_AGENT_REQUIRED";
|
|
735
|
+
throw error;
|
|
736
|
+
}
|
|
584
737
|
const { sessionId } = server.sessionManager.createSession({
|
|
585
738
|
type: sessionType || "agent",
|
|
586
739
|
provider,
|
|
@@ -593,9 +746,76 @@ export async function handleSessionCreate(server, id, ws, message) {
|
|
|
593
746
|
worktreeIsolation,
|
|
594
747
|
systemPromptExtension,
|
|
595
748
|
shellPolicyOverrides,
|
|
749
|
+
sessionBudgetRoot: sessionBudgetRoot.enabled
|
|
750
|
+
? sessionBudgetRoot
|
|
751
|
+
: null,
|
|
752
|
+
requireDurable: sessionBudgetRoot.enabled,
|
|
596
753
|
});
|
|
754
|
+
createdSessionId = sessionId;
|
|
597
755
|
|
|
598
756
|
const session = server.sessionManager.getSession(sessionId);
|
|
757
|
+
if (sessionBudgetRoot.enabled) {
|
|
758
|
+
bootstrapLease = wsBudgetDependency(
|
|
759
|
+
server,
|
|
760
|
+
"acquireSessionHostLease",
|
|
761
|
+
acquireSessionHostLease,
|
|
762
|
+
)(sessionId, { hostKind: "ws" });
|
|
763
|
+
let startedSessionId;
|
|
764
|
+
try {
|
|
765
|
+
startedSessionId = wsBudgetDependency(
|
|
766
|
+
server,
|
|
767
|
+
"startJsonlSession",
|
|
768
|
+
startJsonlSession,
|
|
769
|
+
)(sessionId, {
|
|
770
|
+
title: `WS agent ${new Date().toISOString().slice(0, 10)}`,
|
|
771
|
+
provider: session.provider,
|
|
772
|
+
model: session.model || "",
|
|
773
|
+
sessionBudgetRoot,
|
|
774
|
+
});
|
|
775
|
+
canonicalSessionCreated = true;
|
|
776
|
+
} catch (cause) {
|
|
777
|
+
const error = new Error(
|
|
778
|
+
"Budgeted WebSocket JSONL session could not be durably created",
|
|
779
|
+
{ cause },
|
|
780
|
+
);
|
|
781
|
+
error.code = "CC_SESSION_BUDGET_SESSION_START_FAILED";
|
|
782
|
+
throw error;
|
|
783
|
+
}
|
|
784
|
+
if (startedSessionId !== sessionId) {
|
|
785
|
+
const error = new Error(
|
|
786
|
+
"Budgeted WebSocket JSONL session returned a different session id",
|
|
787
|
+
);
|
|
788
|
+
error.code = "CC_SESSION_BUDGET_SESSION_START_FAILED";
|
|
789
|
+
throw error;
|
|
790
|
+
}
|
|
791
|
+
const canonicalStart = wsBudgetDependency(
|
|
792
|
+
server,
|
|
793
|
+
"readSessionHostResumeState",
|
|
794
|
+
readSessionHostResumeState,
|
|
795
|
+
)(sessionId);
|
|
796
|
+
if (!canonicalStart?.snapshot?.verified) {
|
|
797
|
+
const error = new Error(
|
|
798
|
+
"Budgeted WebSocket JSONL session could not be verified",
|
|
799
|
+
);
|
|
800
|
+
error.code = "CC_SESSION_BUDGET_SESSION_START_FAILED";
|
|
801
|
+
throw error;
|
|
802
|
+
}
|
|
803
|
+
if (
|
|
804
|
+
!canonicalStart.sessionBudgetRoot ||
|
|
805
|
+
!sameSessionBudgetConfig(
|
|
806
|
+
canonicalStart.sessionBudgetRoot,
|
|
807
|
+
sessionBudgetRoot,
|
|
808
|
+
)
|
|
809
|
+
) {
|
|
810
|
+
const error = new Error(
|
|
811
|
+
"Budgeted WebSocket JSONL declaration does not match the requested root",
|
|
812
|
+
);
|
|
813
|
+
error.code = "CC_SESSION_BUDGET_CONFIG_MISMATCH";
|
|
814
|
+
throw error;
|
|
815
|
+
}
|
|
816
|
+
session.canonicalJsonlSession = true;
|
|
817
|
+
session.sessionHostSnapshot = canonicalStart.snapshot;
|
|
818
|
+
}
|
|
599
819
|
const record = createSessionRecord(session, {
|
|
600
820
|
sessionId,
|
|
601
821
|
sessionType: sessionType || "agent",
|
|
@@ -608,11 +828,12 @@ export async function handleSessionCreate(server, id, ws, message) {
|
|
|
608
828
|
status: "created",
|
|
609
829
|
});
|
|
610
830
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
}
|
|
831
|
+
delegatedBootstrapLease = bootstrapLease;
|
|
832
|
+
bootstrapLease = null;
|
|
833
|
+
await ensureSessionHandler(server, ws, session, {
|
|
834
|
+
sessionHostLease: delegatedBootstrapLease,
|
|
835
|
+
});
|
|
836
|
+
delegatedBootstrapLease = null;
|
|
616
837
|
|
|
617
838
|
server.emit("session:create", { sessionId, type: sessionType || "agent" });
|
|
618
839
|
|
|
@@ -659,7 +880,60 @@ export async function handleSessionCreate(server, id, ws, message) {
|
|
|
659
880
|
),
|
|
660
881
|
);
|
|
661
882
|
} catch (err) {
|
|
662
|
-
|
|
883
|
+
if (createdSessionId) {
|
|
884
|
+
const createdSession = server.sessionManager.getSession(createdSessionId);
|
|
885
|
+
createdSession?.mcpClient?.clearElicitationHandler?.(createdSessionId);
|
|
886
|
+
const handler = server.sessionHandlers.get(createdSessionId);
|
|
887
|
+
try {
|
|
888
|
+
handler?.destroy?.();
|
|
889
|
+
} catch {
|
|
890
|
+
// The creation failure remains authoritative; rollback below still
|
|
891
|
+
// removes the unpublished manager/database state.
|
|
892
|
+
}
|
|
893
|
+
server.sessionHandlers.delete(createdSessionId);
|
|
894
|
+
if (canonicalSessionCreated) {
|
|
895
|
+
try {
|
|
896
|
+
wsBudgetDependency(
|
|
897
|
+
server,
|
|
898
|
+
"deleteJsonlSession",
|
|
899
|
+
deleteJsonlSession,
|
|
900
|
+
)(createdSessionId);
|
|
901
|
+
} catch {
|
|
902
|
+
// The bootstrap failure remains authoritative. A durable tombstone
|
|
903
|
+
// or orphan cleanup incident must never become session.started.
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
try {
|
|
907
|
+
if (
|
|
908
|
+
typeof server.sessionManager.rollbackSessionCreation === "function"
|
|
909
|
+
) {
|
|
910
|
+
server.sessionManager.rollbackSessionCreation(createdSessionId);
|
|
911
|
+
} else {
|
|
912
|
+
server.sessionManager.closeSession(createdSessionId);
|
|
913
|
+
}
|
|
914
|
+
} catch {
|
|
915
|
+
// Do not turn a failed bootstrap into a successful protocol response.
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
try {
|
|
919
|
+
bootstrapLease?.release?.();
|
|
920
|
+
} catch {
|
|
921
|
+
// Preserve the bootstrap error sent below.
|
|
922
|
+
}
|
|
923
|
+
try {
|
|
924
|
+
delegatedBootstrapLease?.release?.();
|
|
925
|
+
} catch {
|
|
926
|
+
// ensureSessionHandler may already have attempted this release.
|
|
927
|
+
}
|
|
928
|
+
server._send(
|
|
929
|
+
ws,
|
|
930
|
+
envelopeError(
|
|
931
|
+
id,
|
|
932
|
+
err?.code || "SESSION_CREATE_FAILED",
|
|
933
|
+
err?.message || "WebSocket session creation failed",
|
|
934
|
+
createdSessionId,
|
|
935
|
+
),
|
|
936
|
+
);
|
|
663
937
|
}
|
|
664
938
|
}
|
|
665
939
|
|
|
@@ -673,7 +947,11 @@ export async function handleSessionResume(server, id, ws, message) {
|
|
|
673
947
|
}
|
|
674
948
|
|
|
675
949
|
const { sessionId } = message;
|
|
676
|
-
const canonicalResume =
|
|
950
|
+
const canonicalResume = wsBudgetDependency(
|
|
951
|
+
server,
|
|
952
|
+
"readSessionHostResumeState",
|
|
953
|
+
readSessionHostResumeState,
|
|
954
|
+
)(sessionId);
|
|
677
955
|
if (canonicalResume && !canonicalResume.snapshot.verified) {
|
|
678
956
|
server._send(
|
|
679
957
|
ws,
|
|
@@ -702,6 +980,66 @@ export async function handleSessionResume(server, id, ws, message) {
|
|
|
702
980
|
return;
|
|
703
981
|
}
|
|
704
982
|
|
|
983
|
+
let sessionBudgetRoot;
|
|
984
|
+
let canonicalSessionBudgetRoot = null;
|
|
985
|
+
try {
|
|
986
|
+
sessionBudgetRoot = session.sessionBudgetRoot
|
|
987
|
+
? normalizeSessionBudgetRootConfig(session.sessionBudgetRoot)
|
|
988
|
+
: resolveSessionBudgetRootOptions({});
|
|
989
|
+
canonicalSessionBudgetRoot = canonicalResume?.sessionBudgetRoot
|
|
990
|
+
? normalizeSessionBudgetRootConfig(canonicalResume.sessionBudgetRoot)
|
|
991
|
+
: null;
|
|
992
|
+
} catch (error) {
|
|
993
|
+
server._send(
|
|
994
|
+
ws,
|
|
995
|
+
envelopeError(
|
|
996
|
+
id,
|
|
997
|
+
error?.code || "CC_SESSION_BUDGET_CONFIG_INVALID",
|
|
998
|
+
error?.message || "Persisted WebSocket session budget is invalid",
|
|
999
|
+
sessionId,
|
|
1000
|
+
),
|
|
1001
|
+
);
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
if (
|
|
1005
|
+
sessionBudgetRoot.enabled &&
|
|
1006
|
+
(!canonicalResume || !canonicalSessionBudgetRoot)
|
|
1007
|
+
) {
|
|
1008
|
+
server._send(
|
|
1009
|
+
ws,
|
|
1010
|
+
envelopeError(
|
|
1011
|
+
id,
|
|
1012
|
+
"CC_SESSION_BUDGET_JSONL_REQUIRED",
|
|
1013
|
+
"Budgeted WebSocket session has no canonical JSONL budget authority",
|
|
1014
|
+
sessionId,
|
|
1015
|
+
),
|
|
1016
|
+
);
|
|
1017
|
+
return;
|
|
1018
|
+
}
|
|
1019
|
+
if (
|
|
1020
|
+
canonicalSessionBudgetRoot?.enabled === true &&
|
|
1021
|
+
sessionBudgetRoot.enabled !== true
|
|
1022
|
+
) {
|
|
1023
|
+
sessionBudgetRoot = canonicalSessionBudgetRoot;
|
|
1024
|
+
} else if (
|
|
1025
|
+
canonicalSessionBudgetRoot &&
|
|
1026
|
+
!sameSessionBudgetConfig(canonicalSessionBudgetRoot, sessionBudgetRoot)
|
|
1027
|
+
) {
|
|
1028
|
+
server._send(
|
|
1029
|
+
ws,
|
|
1030
|
+
envelopeError(
|
|
1031
|
+
id,
|
|
1032
|
+
"CC_SESSION_BUDGET_CONFIG_MISMATCH",
|
|
1033
|
+
"WebSocket DB and canonical JSONL budget declarations do not match",
|
|
1034
|
+
sessionId,
|
|
1035
|
+
),
|
|
1036
|
+
);
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
session.sessionBudgetRoot = sessionBudgetRoot.enabled
|
|
1040
|
+
? sessionBudgetRoot
|
|
1041
|
+
: null;
|
|
1042
|
+
|
|
705
1043
|
// A JSONL transcript is the cross-host fact source. A fully verified one
|
|
706
1044
|
// replaces a stale DB/WS copy. The damaged case returned above before the
|
|
707
1045
|
// manager or agent handler could be resumed; only a genuinely absent JSONL
|
|
@@ -760,13 +1098,24 @@ export async function handleSessionResume(server, id, ws, message) {
|
|
|
760
1098
|
// Recovery authority must be attached before a handler is created/refreshed
|
|
761
1099
|
// or history is exposed. Otherwise an existing clean controller can admit a
|
|
762
1100
|
// turn in the resume window before the unsafe projection reaches it.
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
1101
|
+
try {
|
|
1102
|
+
// Existing handlers retain the durable lease and budget root, but their
|
|
1103
|
+
// interaction adapter belongs to the previous WebSocket transport. Route
|
|
1104
|
+
// every resume through the common bootstrap so it can reattach the new
|
|
1105
|
+
// transport without reopening either authority.
|
|
1106
|
+
await ensureSessionHandler(server, ws, session);
|
|
1107
|
+
} catch (error) {
|
|
1108
|
+
server._send(
|
|
1109
|
+
ws,
|
|
1110
|
+
envelopeError(
|
|
1111
|
+
id,
|
|
1112
|
+
error?.code || "SESSION_RESUME_FAILED",
|
|
1113
|
+
error?.message || "WebSocket session handler could not be resumed",
|
|
1114
|
+
sessionId,
|
|
1115
|
+
{ ...(sessionSnapshot ? { sessionSnapshot } : {}) },
|
|
1116
|
+
),
|
|
1117
|
+
);
|
|
1118
|
+
return;
|
|
770
1119
|
}
|
|
771
1120
|
const handler = server.sessionHandlers.get(sessionId);
|
|
772
1121
|
if (typeof handler?.refreshMcpRecoveryRuntime === "function") {
|
|
@@ -986,6 +1335,7 @@ export function handleSessionList(server, id, ws) {
|
|
|
986
1335
|
|
|
987
1336
|
export function handleSessionClose(server, id, ws, message) {
|
|
988
1337
|
const { sessionId } = message;
|
|
1338
|
+
const cleanupErrors = [];
|
|
989
1339
|
|
|
990
1340
|
const closingSession = server.sessionManager?.getSession?.(sessionId);
|
|
991
1341
|
if (closingSession?.mcpClient?.clearElicitationHandler) {
|
|
@@ -994,18 +1344,35 @@ export function handleSessionClose(server, id, ws, message) {
|
|
|
994
1344
|
|
|
995
1345
|
const handler = server.sessionHandlers.get(sessionId);
|
|
996
1346
|
if (handler && handler.destroy) {
|
|
997
|
-
|
|
1347
|
+
try {
|
|
1348
|
+
handler.destroy();
|
|
1349
|
+
} catch (error) {
|
|
1350
|
+
cleanupErrors.push(error);
|
|
1351
|
+
}
|
|
998
1352
|
}
|
|
999
1353
|
server.sessionHandlers.delete(sessionId);
|
|
1000
1354
|
|
|
1001
1355
|
if (server.sessionManager) {
|
|
1002
1356
|
try {
|
|
1003
1357
|
server.sessionManager.closeSession(sessionId);
|
|
1004
|
-
} catch (
|
|
1005
|
-
|
|
1358
|
+
} catch (error) {
|
|
1359
|
+
cleanupErrors.push(error);
|
|
1006
1360
|
}
|
|
1007
1361
|
}
|
|
1008
1362
|
|
|
1363
|
+
if (cleanupErrors.length > 0) {
|
|
1364
|
+
server._send(
|
|
1365
|
+
ws,
|
|
1366
|
+
envelopeError(
|
|
1367
|
+
id,
|
|
1368
|
+
"CC_WS_SESSION_CLOSE_FAILED",
|
|
1369
|
+
"WebSocket session authority could not be durably closed",
|
|
1370
|
+
sessionId,
|
|
1371
|
+
),
|
|
1372
|
+
);
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1009
1376
|
server.emit("session:close", { sessionId });
|
|
1010
1377
|
|
|
1011
1378
|
// Phase 5: broadcast service envelope for unified subscribers.
|