chainlesschain 0.162.188 → 0.162.193
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 +61 -11
- package/bin/chainlesschain.js +7 -52
- package/completions/_cc +209 -0
- package/completions/cc.bash +18 -0
- package/completions/cc.fish +13 -0
- package/completions/cc.ps1 +226 -0
- package/package.json +10 -2
- package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
- package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
- package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
- package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
- package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
- package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
- package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
- package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
- package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
- package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
- package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
- package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
- package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
- package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
- package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
- package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
- package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
- package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
- package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
- package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
- package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
- package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
- package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
- package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/cli-help.js +181 -0
- package/src/command-help-index.json +181 -0
- package/src/command-manifest.json +1107 -175
- package/src/command-surface-policy.js +197 -0
- package/src/commands/agent.js +98 -33
- package/src/commands/artifacts.js +400 -2
- package/src/commands/background-session.js +41 -3
- package/src/commands/checkpoint-managed.js +1059 -0
- package/src/commands/checkpoint-restore-recovery.js +1476 -0
- package/src/commands/checkpoint.js +950 -22
- package/src/commands/compact.js +101 -25
- package/src/commands/config.js +506 -20
- package/src/commands/doctor.js +4 -1
- package/src/commands/hub.js +1 -1
- package/src/commands/mcp.js +688 -24
- package/src/commands/pack.js +16 -2
- package/src/commands/plugin.js +20 -12
- package/src/commands/session-mcp-recovery.js +218 -0
- package/src/commands/session.js +470 -110
- package/src/commands/setup.js +36 -10
- package/src/commands/skill.js +181 -110
- package/src/commands/status.js +21 -5
- package/src/commands/team-distributed.js +3324 -0
- package/src/commands/team.js +1130 -74
- package/src/commands/update.js +68 -6
- package/src/constants.js +11 -0
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/action-protocol.js +10 -0
- package/src/gateways/ws/session-protocol.js +555 -27
- package/src/gateways/ws/ws-agent-handler.js +541 -14
- package/src/gateways/ws/ws-session-gateway.js +129 -22
- package/src/gateways/ws/ws-session-state.js +431 -0
- package/src/harness/background-task-manager.js +233 -36
- package/src/harness/jsonl-session-store.js +2551 -167
- package/src/harness/mcp-client.js +802 -61
- package/src/harness/prompt-compressor.js +227 -27
- package/src/harness/session-index.js +89 -38
- package/src/harness/session-list-index.js +254 -0
- package/src/harness/structured-handoff.js +410 -0
- package/src/lazy-dispatch.js +747 -84
- package/src/lib/__tests__/logger.test.js +50 -2
- package/src/lib/advisor-runtime.js +1047 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-sandbox.js +120 -26
- package/src/lib/agent-session-export.js +20 -0
- package/src/lib/agent-team/task-lease.js +271 -3
- package/src/lib/agent-team/team-adjudication.js +1501 -0
- package/src/lib/agent-team/team-budget.js +4 -1
- package/src/lib/agent-team/team-control-store.js +582 -0
- package/src/lib/agent-team/team-distributed-queue.js +5246 -0
- package/src/lib/agent-team/team-process-checkpoint.js +211 -0
- package/src/lib/agent-team/team-runner.js +543 -24
- package/src/lib/agent-team/team-worktree.js +1403 -95
- package/src/lib/artifact-store.js +131 -8
- package/src/lib/background-agent-supervisor.js +185 -13
- package/src/lib/background-interaction-journal.js +37 -9
- package/src/lib/background-launch-profile.js +1058 -0
- package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
- package/src/lib/checkpoint-restore-orchestrator.js +987 -0
- package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
- package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
- package/src/lib/checkpoint-restore-recovery.js +884 -0
- package/src/lib/checkpoint-restore-retention.js +126 -0
- package/src/lib/checkpoint-restore-saga.js +5079 -0
- package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
- package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
- package/src/lib/checkpoint-store.js +1688 -97
- package/src/lib/checkpoint-timeline-authority.js +522 -0
- package/src/lib/checkpoint-timeline.js +642 -0
- package/src/lib/config-keys.js +18 -119
- package/src/lib/config-manager.js +446 -27
- package/src/lib/config-redaction.js +57 -0
- package/src/lib/config-schema.js +853 -0
- package/src/lib/cowork-mcp-tools.js +5 -0
- package/src/lib/cowork-task-runner.js +458 -63
- package/src/lib/delivery-coordinator.js +1234 -0
- package/src/lib/delivery-evidence.js +450 -0
- package/src/lib/doctor-checkup.js +199 -14
- package/src/lib/executable-path.js +34 -0
- package/src/lib/fatal-handler.js +16 -0
- package/src/lib/file-checkpoint.js +4909 -186
- package/src/lib/file-lines.js +125 -0
- package/src/lib/headless-config-command.js +16 -5
- package/src/lib/hook-runner.cjs +139 -38
- package/src/lib/hooks-v2-workspace-context.js +10 -0
- package/src/lib/impacted-gate-selector.js +424 -0
- package/src/lib/interaction-adapter.js +62 -0
- package/src/lib/jsonl-session-store.js +1 -35
- package/src/lib/logger.js +66 -14
- package/src/lib/managed-checkpoint-render.js +60 -0
- package/src/lib/managed-tool-checkpoint.js +194 -0
- package/src/lib/mcp-call-ledger-store.js +1069 -0
- package/src/lib/mcp-call-ledger.js +747 -0
- package/src/lib/mcp-client.js +5 -0
- package/src/lib/mcp-conflict-scheduler.js +468 -0
- package/src/lib/mcp-effect-contract.js +102 -0
- package/src/lib/mcp-headers-helper-trust.js +145 -0
- package/src/lib/mcp-headers-helper.js +616 -0
- package/src/lib/mcp-host-recovery-runtime.js +131 -0
- package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
- package/src/lib/mcp-recovery-adjudication.js +443 -0
- package/src/lib/output-context.js +86 -0
- package/src/lib/packer/file-identity.js +170 -0
- package/src/lib/packer/index.js +3 -0
- package/src/lib/packer/native-update-state.js +277 -0
- package/src/lib/packer/pack-update-applier.js +1983 -136
- package/src/lib/packer/pack-update-checker.js +34 -0
- package/src/lib/packer/pack-update-downloader.js +875 -86
- package/src/lib/packer/pack-update-signature.js +86 -0
- package/src/lib/packer/pkg-config-generator.js +6 -0
- package/src/lib/paths.js +65 -10
- package/src/lib/plan-mode.js +831 -14
- package/src/lib/plan-persistence.js +540 -0
- package/src/lib/plugin-runtime/hooks.js +227 -69
- package/src/lib/plugin-runtime/plugin-options.js +189 -44
- package/src/lib/pr-automation-policy.js +146 -8
- package/src/lib/process-execution-broker/credential-agent.js +7 -0
- package/src/lib/process-execution-broker/index.js +491 -13
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
- package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +284 -19
- package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
- package/src/lib/project-instructions.js +165 -29
- package/src/lib/project-mcp-trust.js +67 -0
- package/src/lib/public-ide-capability-manifest.js +272 -0
- package/src/lib/public-ide-capability-validation.js +351 -0
- package/src/lib/secret-store.js +267 -43
- package/src/lib/secure-file-identity.js +433 -0
- package/src/lib/secure-fs.js +1089 -0
- package/src/lib/security-audit.js +58 -0
- package/src/lib/service-manager.js +34 -13
- package/src/lib/session-budget-runtime.js +1452 -0
- package/src/lib/session-host-snapshot.js +388 -0
- package/src/lib/session-message-provenance.js +429 -0
- package/src/lib/session-projection.js +804 -0
- package/src/lib/session-resource-budget.js +1495 -0
- package/src/lib/settings-hooks.cjs +138 -22
- package/src/lib/settings-loader.cjs +25 -2
- package/src/lib/side-effect-ledger-store.js +45 -23
- package/src/lib/skill-execution-identity.js +217 -0
- package/src/lib/skill-loader.js +299 -18
- package/src/lib/sub-agent-context.js +236 -28
- package/src/lib/sub-agent-registry.js +5 -0
- package/src/lib/subagent-contract.js +94 -0
- package/src/lib/todo-manager.js +185 -18
- package/src/lib/todo-persistence.js +417 -0
- package/src/lib/turn-binding-store.js +41 -23
- package/src/lib/turn-binding.js +160 -2
- package/src/lib/with-file-lock.js +165 -24
- package/src/lib/ws-chat-handler.js +21 -0
- package/src/program-base.js +18 -0
- package/src/repl/advisor-command.js +103 -0
- package/src/repl/agent-repl.js +2175 -146
- package/src/repl/btw-command.js +93 -10
- package/src/repl/clipboard-image.js +119 -0
- package/src/repl/config-summary.js +64 -108
- package/src/repl/prompt-editor.js +233 -0
- package/src/repl/prompt-interactions.js +344 -0
- package/src/repl/prompt-stash.js +354 -0
- package/src/repl/prompt-suggestions.js +312 -0
- package/src/repl/repl-keybindings.js +227 -0
- package/src/repl/session-recap.js +217 -0
- package/src/repl/slash-command-registry.js +22 -0
- package/src/repl/terminal-layout.js +88 -0
- package/src/runtime/agent-core.js +1630 -447
- package/src/runtime/coding-agent-contract-shared.cjs +13 -1
- package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
- package/src/runtime/diagnostics.js +32 -13
- package/src/runtime/headless-runner.js +310 -118
- package/src/runtime/headless-stream.js +356 -95
- package/src/runtime/mcp-config.js +148 -14
- package/src/runtime/policies/agent-policy.js +14 -0
- package/src/runtime/status-diagnostics-lite.js +137 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
- package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
- package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
- package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
|
@@ -7,6 +7,296 @@ import {
|
|
|
7
7
|
import { createSessionRecord } from "../../runtime/contracts/session-record.js";
|
|
8
8
|
import { loadSideEffectLedger } from "../../lib/side-effect-ledger-store.js";
|
|
9
9
|
import { reconcileSideEffects } from "../../lib/side-effect-ledger.js";
|
|
10
|
+
import {
|
|
11
|
+
formatMcpLedgerRecoveryNotice,
|
|
12
|
+
loadMcpLedgerRecovery,
|
|
13
|
+
} from "../../lib/mcp-call-ledger-store.js";
|
|
14
|
+
import { isProxy } from "node:util/types";
|
|
15
|
+
import {
|
|
16
|
+
MCP_RECOVERY_INVALID_CODE,
|
|
17
|
+
classifyMcpRecoveryAdmission,
|
|
18
|
+
} from "../../lib/mcp-ledger-recovery-admission.js";
|
|
19
|
+
import { readSessionHostResumeState } from "../../lib/session-host-snapshot.js";
|
|
20
|
+
import { sanitizePersistedMessages } from "../../lib/session-message-provenance.js";
|
|
21
|
+
|
|
22
|
+
const PAYLOAD_DIGEST = /^sha256:[0-9a-f]{64}$/;
|
|
23
|
+
const RAW_AUTHORITY_HASH = /^[0-9a-f]{64}$/;
|
|
24
|
+
const MCP_REPLAY_DENY_FIELDS = new Set([
|
|
25
|
+
"ledgerId",
|
|
26
|
+
"serverName",
|
|
27
|
+
"toolName",
|
|
28
|
+
"inputBytes",
|
|
29
|
+
"replayDigest",
|
|
30
|
+
]);
|
|
31
|
+
const MCP_RECOVERY_REMEDIATIONS = new Set([
|
|
32
|
+
"inspect_transcript",
|
|
33
|
+
"adjudicate_started_calls",
|
|
34
|
+
"exact_replay_denied",
|
|
35
|
+
]);
|
|
36
|
+
const RESUME_RECOVERY_NOTICE = Symbol("cc.resume-recovery-notice");
|
|
37
|
+
|
|
38
|
+
function captureCanonicalHostSystemPrefix(session) {
|
|
39
|
+
if (Array.isArray(session?._canonicalHostSystemPrefix)) {
|
|
40
|
+
const explicit = sanitizePersistedMessages(
|
|
41
|
+
session._canonicalHostSystemPrefix,
|
|
42
|
+
{ strict: true },
|
|
43
|
+
);
|
|
44
|
+
if (explicit.some((message) => message.role !== "system")) {
|
|
45
|
+
throw new TypeError("Canonical WS host prefix is invalid");
|
|
46
|
+
}
|
|
47
|
+
return Object.freeze(explicit.map((message) => Object.freeze(message)));
|
|
48
|
+
}
|
|
49
|
+
const persisted = sanitizePersistedMessages(session?.messages || [], {
|
|
50
|
+
strict: true,
|
|
51
|
+
});
|
|
52
|
+
const firstMessage = persisted[0] || null;
|
|
53
|
+
const prefix = [];
|
|
54
|
+
if (firstMessage?.role === "system") {
|
|
55
|
+
// A WS session is created with exactly one host-owned system prompt. Any
|
|
56
|
+
// later leading systems may be canonical summaries or recovery notices
|
|
57
|
+
// serialized by the DB compatibility mirror; they must not be promoted
|
|
58
|
+
// into the host prefix after a process restart.
|
|
59
|
+
prefix.push(Object.freeze(firstMessage));
|
|
60
|
+
}
|
|
61
|
+
const frozenPrefix = Object.freeze(prefix);
|
|
62
|
+
Object.defineProperty(session, "_canonicalHostSystemPrefix", {
|
|
63
|
+
configurable: true,
|
|
64
|
+
value: frozenPrefix,
|
|
65
|
+
});
|
|
66
|
+
return frozenPrefix;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function replaceResumeRecoveryNotice(session, notice) {
|
|
70
|
+
const previous = session?._resumeRecoveryNoticeMessage || null;
|
|
71
|
+
const messages = (
|
|
72
|
+
Array.isArray(session?.messages) ? session.messages : []
|
|
73
|
+
).filter(
|
|
74
|
+
(message) =>
|
|
75
|
+
message !== previous && message?.[RESUME_RECOVERY_NOTICE] !== true,
|
|
76
|
+
);
|
|
77
|
+
let insertionIndex = 0;
|
|
78
|
+
while (messages[insertionIndex]?.role === "system") insertionIndex += 1;
|
|
79
|
+
|
|
80
|
+
let recoveryMessage = null;
|
|
81
|
+
if (typeof notice === "string" && notice.trim()) {
|
|
82
|
+
recoveryMessage = { role: "system", content: notice };
|
|
83
|
+
Object.defineProperty(recoveryMessage, RESUME_RECOVERY_NOTICE, {
|
|
84
|
+
value: true,
|
|
85
|
+
});
|
|
86
|
+
messages.splice(insertionIndex, 0, recoveryMessage);
|
|
87
|
+
}
|
|
88
|
+
session.messages = messages;
|
|
89
|
+
Object.defineProperty(session, "_resumeRecoveryNoticeMessage", {
|
|
90
|
+
configurable: true,
|
|
91
|
+
writable: true,
|
|
92
|
+
value: recoveryMessage,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function recoveryErrorCode(error, fallbackCode) {
|
|
97
|
+
try {
|
|
98
|
+
return typeof error?.code === "string" && error.code
|
|
99
|
+
? error.code
|
|
100
|
+
: fallbackCode;
|
|
101
|
+
} catch {
|
|
102
|
+
return fallbackCode;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function ownDataValue(record, key, fallback = null) {
|
|
107
|
+
if (!record || typeof record !== "object" || isProxy(record)) {
|
|
108
|
+
const error = new TypeError(`MCP recovery ${key} record is not plain data`);
|
|
109
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
const descriptor = Object.getOwnPropertyDescriptor(record, key);
|
|
113
|
+
if (!descriptor) return fallback;
|
|
114
|
+
if (!("value" in descriptor)) {
|
|
115
|
+
const error = new TypeError(`MCP recovery ${key} must be a data property`);
|
|
116
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
117
|
+
throw error;
|
|
118
|
+
}
|
|
119
|
+
return descriptor.value;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function recoveryString(value, fallback) {
|
|
123
|
+
if (value == null) return fallback;
|
|
124
|
+
if (typeof value === "string") return value;
|
|
125
|
+
const error = new TypeError("MCP recovery scalar must be a string");
|
|
126
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function snapshotMcpRecord(record) {
|
|
131
|
+
const effectContract = ownDataValue(record, "effectContract", null);
|
|
132
|
+
let effect = "unknown";
|
|
133
|
+
if (effectContract != null) {
|
|
134
|
+
if (typeof effectContract !== "object" || isProxy(effectContract)) {
|
|
135
|
+
const error = new TypeError("MCP recovery effect contract is malformed");
|
|
136
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
137
|
+
throw error;
|
|
138
|
+
}
|
|
139
|
+
effect = recoveryString(
|
|
140
|
+
ownDataValue(effectContract, "effect", "unknown"),
|
|
141
|
+
"unknown",
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
return Object.freeze({
|
|
145
|
+
ledgerId: recoveryString(ownDataValue(record, "ledgerId", null), null),
|
|
146
|
+
serverName: recoveryString(
|
|
147
|
+
ownDataValue(record, "serverName", "unknown"),
|
|
148
|
+
"unknown",
|
|
149
|
+
),
|
|
150
|
+
toolName: recoveryString(
|
|
151
|
+
ownDataValue(record, "toolName", "unknown"),
|
|
152
|
+
"unknown",
|
|
153
|
+
),
|
|
154
|
+
effect,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function snapshotMcpIncident(incident) {
|
|
159
|
+
return Object.freeze({
|
|
160
|
+
code: recoveryString(
|
|
161
|
+
ownDataValue(incident, "code", MCP_RECOVERY_INVALID_CODE),
|
|
162
|
+
MCP_RECOVERY_INVALID_CODE,
|
|
163
|
+
),
|
|
164
|
+
ledgerId: recoveryString(ownDataValue(incident, "ledgerId", null), null),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function snapshotMcpReplayDeny(entry) {
|
|
169
|
+
if (!entry || typeof entry !== "object" || isProxy(entry)) {
|
|
170
|
+
const error = new TypeError("MCP replay deny entry is malformed");
|
|
171
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
const descriptors = Object.getOwnPropertyDescriptors(entry);
|
|
175
|
+
const fields = Object.keys(descriptors);
|
|
176
|
+
if (
|
|
177
|
+
fields.length !== MCP_REPLAY_DENY_FIELDS.size ||
|
|
178
|
+
fields.some((field) => !MCP_REPLAY_DENY_FIELDS.has(field)) ||
|
|
179
|
+
[...MCP_REPLAY_DENY_FIELDS].some(
|
|
180
|
+
(field) => !descriptors[field] || !("value" in descriptors[field]),
|
|
181
|
+
)
|
|
182
|
+
) {
|
|
183
|
+
const error = new TypeError("MCP replay deny entry schema is invalid");
|
|
184
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
185
|
+
throw error;
|
|
186
|
+
}
|
|
187
|
+
const snapshot = Object.freeze({
|
|
188
|
+
ledgerId: recoveryString(descriptors.ledgerId.value, null),
|
|
189
|
+
serverName: recoveryString(descriptors.serverName.value, null),
|
|
190
|
+
toolName: recoveryString(descriptors.toolName.value, null),
|
|
191
|
+
inputBytes: descriptors.inputBytes.value,
|
|
192
|
+
replayDigest: recoveryString(descriptors.replayDigest.value, null),
|
|
193
|
+
});
|
|
194
|
+
if (
|
|
195
|
+
!snapshot.ledgerId ||
|
|
196
|
+
!snapshot.serverName ||
|
|
197
|
+
!snapshot.toolName ||
|
|
198
|
+
!Number.isInteger(snapshot.inputBytes) ||
|
|
199
|
+
snapshot.inputBytes < 0 ||
|
|
200
|
+
!PAYLOAD_DIGEST.test(snapshot.replayDigest || "")
|
|
201
|
+
) {
|
|
202
|
+
const error = new TypeError("MCP replay deny identity is invalid");
|
|
203
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
204
|
+
throw error;
|
|
205
|
+
}
|
|
206
|
+
return snapshot;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function strictMcpRecoverySnapshot(recovery) {
|
|
210
|
+
if (recovery == null) {
|
|
211
|
+
const error = new TypeError("MCP recovery projection is missing");
|
|
212
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
213
|
+
throw error;
|
|
214
|
+
}
|
|
215
|
+
const admission = classifyMcpRecoveryAdmission(recovery);
|
|
216
|
+
if (admission.reasonCode) {
|
|
217
|
+
const error = new TypeError("MCP recovery projection is malformed");
|
|
218
|
+
error.code = admission.reasonCode;
|
|
219
|
+
throw error;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// classifyMcpRecoveryAdmission rejects proxies/accessors first. Capture the
|
|
223
|
+
// two authority arrays exactly once as own data descriptors so a formatter
|
|
224
|
+
// or time-varying getter can never turn an unsafe projection into clean state.
|
|
225
|
+
const descriptors = Object.getOwnPropertyDescriptors(recovery);
|
|
226
|
+
const unsettledSource = descriptors.unsettled?.value;
|
|
227
|
+
const incidentsSource = descriptors.incidents?.value;
|
|
228
|
+
const replayDeniedSource = descriptors.replayDenied?.value;
|
|
229
|
+
if (
|
|
230
|
+
!Array.isArray(unsettledSource) ||
|
|
231
|
+
!Array.isArray(incidentsSource) ||
|
|
232
|
+
!Array.isArray(replayDeniedSource)
|
|
233
|
+
) {
|
|
234
|
+
const error = new TypeError("MCP recovery arrays are unavailable");
|
|
235
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
const unsettled = Object.freeze(unsettledSource.map(snapshotMcpRecord));
|
|
239
|
+
const incidents = Object.freeze(incidentsSource.map(snapshotMcpIncident));
|
|
240
|
+
const replayDenied = Object.freeze(
|
|
241
|
+
replayDeniedSource.map(snapshotMcpReplayDeny),
|
|
242
|
+
);
|
|
243
|
+
const headHash = recoveryString(
|
|
244
|
+
ownDataValue(recovery, "headHash", null),
|
|
245
|
+
null,
|
|
246
|
+
);
|
|
247
|
+
const recoveryDigest = recoveryString(
|
|
248
|
+
ownDataValue(recovery, "recoveryDigest", null),
|
|
249
|
+
null,
|
|
250
|
+
);
|
|
251
|
+
if (
|
|
252
|
+
(headHash != null && !RAW_AUTHORITY_HASH.test(headHash)) ||
|
|
253
|
+
(recoveryDigest != null && !PAYLOAD_DIGEST.test(recoveryDigest))
|
|
254
|
+
) {
|
|
255
|
+
const error = new TypeError("MCP recovery authority digest is invalid");
|
|
256
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
257
|
+
throw error;
|
|
258
|
+
}
|
|
259
|
+
const remediation = recoveryString(
|
|
260
|
+
ownDataValue(recovery, "remediation", null),
|
|
261
|
+
null,
|
|
262
|
+
);
|
|
263
|
+
if (remediation !== null && !MCP_RECOVERY_REMEDIATIONS.has(remediation)) {
|
|
264
|
+
const error = new TypeError("MCP recovery remediation is invalid");
|
|
265
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
return Object.freeze({
|
|
269
|
+
admission,
|
|
270
|
+
unsettled,
|
|
271
|
+
incidents,
|
|
272
|
+
replayDenied,
|
|
273
|
+
headHash,
|
|
274
|
+
recoveryDigest,
|
|
275
|
+
remediation,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function failClosedMcpRecovery(
|
|
280
|
+
error,
|
|
281
|
+
fallbackCode = "CC_MCP_LEDGER_EVENT_READ_FAILED",
|
|
282
|
+
) {
|
|
283
|
+
const code = recoveryErrorCode(error, fallbackCode);
|
|
284
|
+
const incident = Object.freeze({ code, ledgerId: null });
|
|
285
|
+
return Object.freeze({
|
|
286
|
+
count: 1,
|
|
287
|
+
unsettled: Object.freeze([]),
|
|
288
|
+
incidents: Object.freeze([incident]),
|
|
289
|
+
replayDenied: Object.freeze([]),
|
|
290
|
+
blockMode: "all",
|
|
291
|
+
headHash: null,
|
|
292
|
+
recoveryDigest: null,
|
|
293
|
+
remediation: "inspect_transcript",
|
|
294
|
+
notice:
|
|
295
|
+
"MCP recovery notice — the durable MCP ledger could not be verified. " +
|
|
296
|
+
"Do NOT automatically retry prior MCP actions; inspect the session " +
|
|
297
|
+
`transcript first (${code}).`,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
10
300
|
|
|
11
301
|
/**
|
|
12
302
|
* P0-2: on a bridge/IDE resume, surface any irreversible tool that was in flight
|
|
@@ -14,9 +304,9 @@ import { reconcileSideEffects } from "../../lib/side-effect-ledger.js";
|
|
|
14
304
|
* + short key + reason, never argument values) plus a human-readable notice, or
|
|
15
305
|
* null when nothing needs verification. PURE apart from reading the ledger.
|
|
16
306
|
*/
|
|
17
|
-
function
|
|
307
|
+
function buildSideEffectResumeRecovery(sessionId, loadLedger) {
|
|
18
308
|
try {
|
|
19
|
-
const ledger =
|
|
309
|
+
const ledger = loadLedger(sessionId);
|
|
20
310
|
const plan = reconcileSideEffects(ledger);
|
|
21
311
|
if (!plan.inspect.length) return null;
|
|
22
312
|
const items = plan.plans
|
|
@@ -40,12 +330,116 @@ function buildResumeRecovery(sessionId) {
|
|
|
40
330
|
` • [${it.kind}]${it.key ? ` (${it.key})` : ""} — ${it.reason}`,
|
|
41
331
|
)
|
|
42
332
|
.join("\n");
|
|
43
|
-
return { count: items.length, items, notice };
|
|
44
|
-
} catch {
|
|
45
|
-
|
|
333
|
+
return { count: items.length, items, incidents: [], notice };
|
|
334
|
+
} catch (error) {
|
|
335
|
+
const code = recoveryErrorCode(
|
|
336
|
+
error,
|
|
337
|
+
"CC_SIDE_EFFECT_LEDGER_RECOVERY_FAILED",
|
|
338
|
+
);
|
|
339
|
+
return {
|
|
340
|
+
count: 1,
|
|
341
|
+
items: [],
|
|
342
|
+
incidents: [{ code }],
|
|
343
|
+
notice:
|
|
344
|
+
"Side-effect recovery notice — the durable side-effect ledger could " +
|
|
345
|
+
"not be verified. Do NOT automatically retry prior irreversible " +
|
|
346
|
+
`operations until the transcript is inspected (${code}).`,
|
|
347
|
+
};
|
|
46
348
|
}
|
|
47
349
|
}
|
|
48
350
|
|
|
351
|
+
function buildMcpResumeRecovery(sessionId, loadRecovery, formatNotice) {
|
|
352
|
+
try {
|
|
353
|
+
const snapshot = strictMcpRecoverySnapshot(loadRecovery(sessionId));
|
|
354
|
+
const unsettled = Object.freeze(
|
|
355
|
+
snapshot.unsettled.map((record) =>
|
|
356
|
+
Object.freeze({
|
|
357
|
+
ledgerId: record.ledgerId,
|
|
358
|
+
serverName: record.serverName,
|
|
359
|
+
toolName: record.toolName,
|
|
360
|
+
effect: record.effect,
|
|
361
|
+
status: "outcome_unknown",
|
|
362
|
+
}),
|
|
363
|
+
),
|
|
364
|
+
);
|
|
365
|
+
const incidents = snapshot.incidents;
|
|
366
|
+
const requiresInspection =
|
|
367
|
+
unsettled.length > 0 ||
|
|
368
|
+
incidents.length > 0 ||
|
|
369
|
+
snapshot.replayDenied.length > 0 ||
|
|
370
|
+
snapshot.admission.blockMode != null;
|
|
371
|
+
let notice = null;
|
|
372
|
+
if (requiresInspection) {
|
|
373
|
+
const formatterProjection = Object.freeze({
|
|
374
|
+
unsettled: Object.freeze(
|
|
375
|
+
snapshot.unsettled.map((record) =>
|
|
376
|
+
Object.freeze({
|
|
377
|
+
ledgerId: record.ledgerId,
|
|
378
|
+
serverName: record.serverName,
|
|
379
|
+
toolName: record.toolName,
|
|
380
|
+
effectContract: Object.freeze({ effect: record.effect }),
|
|
381
|
+
}),
|
|
382
|
+
),
|
|
383
|
+
),
|
|
384
|
+
incidents,
|
|
385
|
+
replayDenied: snapshot.replayDenied,
|
|
386
|
+
});
|
|
387
|
+
notice = formatNotice(formatterProjection);
|
|
388
|
+
if (notice != null && typeof notice !== "string") {
|
|
389
|
+
const error = new TypeError(
|
|
390
|
+
"MCP recovery formatter must return a synchronous string or null",
|
|
391
|
+
);
|
|
392
|
+
error.code = MCP_RECOVERY_INVALID_CODE;
|
|
393
|
+
throw error;
|
|
394
|
+
}
|
|
395
|
+
notice ||=
|
|
396
|
+
"MCP recovery notice — durable MCP state requires inspection. Do NOT " +
|
|
397
|
+
"automatically retry prior MCP actions until recovery is adjudicated.";
|
|
398
|
+
}
|
|
399
|
+
return Object.freeze({
|
|
400
|
+
count: unsettled.length + incidents.length + snapshot.replayDenied.length,
|
|
401
|
+
unsettled,
|
|
402
|
+
incidents,
|
|
403
|
+
headHash: snapshot.headHash,
|
|
404
|
+
recoveryDigest: snapshot.recoveryDigest,
|
|
405
|
+
replayDenied: snapshot.replayDenied,
|
|
406
|
+
remediation: snapshot.remediation,
|
|
407
|
+
notice,
|
|
408
|
+
...(snapshot.admission.blockMode
|
|
409
|
+
? { blockMode: snapshot.admission.blockMode }
|
|
410
|
+
: {}),
|
|
411
|
+
});
|
|
412
|
+
} catch (error) {
|
|
413
|
+
return failClosedMcpRecovery(error);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Build the de-identified recovery payload shared by the IDE envelope and the
|
|
419
|
+
* resumed model. Dependencies are injectable so fail-closed recovery can be
|
|
420
|
+
* tested without touching a user's durable session directory.
|
|
421
|
+
*/
|
|
422
|
+
export function buildResumeRecovery(sessionId, dependencies = {}) {
|
|
423
|
+
const sideEffects = buildSideEffectResumeRecovery(
|
|
424
|
+
sessionId,
|
|
425
|
+
dependencies.loadSideEffectLedger || loadSideEffectLedger,
|
|
426
|
+
);
|
|
427
|
+
const mcp = buildMcpResumeRecovery(
|
|
428
|
+
sessionId,
|
|
429
|
+
dependencies.loadMcpLedgerRecovery || loadMcpLedgerRecovery,
|
|
430
|
+
dependencies.formatMcpLedgerRecoveryNotice || formatMcpLedgerRecoveryNotice,
|
|
431
|
+
);
|
|
432
|
+
if (!sideEffects && !mcp) return null;
|
|
433
|
+
|
|
434
|
+
return {
|
|
435
|
+
count: (sideEffects?.count || 0) + (mcp?.count || 0),
|
|
436
|
+
items: sideEffects?.items || [],
|
|
437
|
+
sideEffectIncidents: sideEffects?.incidents || [],
|
|
438
|
+
...(mcp ? { mcp } : {}),
|
|
439
|
+
notice: [sideEffects?.notice, mcp?.notice].filter(Boolean).join("\n\n"),
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
|
|
49
443
|
// Build a unified envelope for a solicited WS response. The bridge correlates
|
|
50
444
|
// by `requestId` (the inbound request's id) and unwraps `payload` for callers
|
|
51
445
|
// so existing flat-shape consumers keep working unchanged.
|
|
@@ -57,10 +451,10 @@ function envelopeResponse(type, id, payload, sessionId) {
|
|
|
57
451
|
});
|
|
58
452
|
}
|
|
59
453
|
|
|
60
|
-
function envelopeError(id, code, message, sessionId) {
|
|
454
|
+
function envelopeError(id, code, message, sessionId, details = {}) {
|
|
61
455
|
return createCodingAgentEvent(
|
|
62
456
|
CODING_AGENT_EVENT_TYPES.ERROR,
|
|
63
|
-
{ code, message },
|
|
457
|
+
{ ...details, code, message },
|
|
64
458
|
{
|
|
65
459
|
requestId: id,
|
|
66
460
|
sessionId: sessionId || null,
|
|
@@ -94,6 +488,18 @@ async function ensureSessionHandler(server, ws, session) {
|
|
|
94
488
|
session.interaction = new WebSocketInteractionAdapter(ws, session.id, {
|
|
95
489
|
enablePhase5Envelopes,
|
|
96
490
|
envelopeBus: server.envelopeBus || null,
|
|
491
|
+
onPendingApprovalChange: ({ type, payload }) => {
|
|
492
|
+
if (
|
|
493
|
+
server.sessionManager &&
|
|
494
|
+
typeof server.sessionManager.recordSessionStateEvent === "function"
|
|
495
|
+
) {
|
|
496
|
+
server.sessionManager.recordSessionStateEvent(
|
|
497
|
+
session.id,
|
|
498
|
+
type,
|
|
499
|
+
payload,
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
},
|
|
97
503
|
});
|
|
98
504
|
|
|
99
505
|
// Route MCP elicitation through the authenticated WS question channel. The
|
|
@@ -257,6 +663,20 @@ export async function handleSessionResume(server, id, ws, message) {
|
|
|
257
663
|
}
|
|
258
664
|
|
|
259
665
|
const { sessionId } = message;
|
|
666
|
+
const canonicalResume = readSessionHostResumeState(sessionId);
|
|
667
|
+
if (canonicalResume && !canonicalResume.snapshot.verified) {
|
|
668
|
+
server._send(
|
|
669
|
+
ws,
|
|
670
|
+
envelopeError(
|
|
671
|
+
id,
|
|
672
|
+
"CC_SESSION_HOST_SNAPSHOT_UNVERIFIED",
|
|
673
|
+
"Canonical JSONL session is not verified; resume was refused",
|
|
674
|
+
sessionId,
|
|
675
|
+
{ sessionSnapshot: canonicalResume.snapshot },
|
|
676
|
+
),
|
|
677
|
+
);
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
260
680
|
const session = server.sessionManager.resumeSession(sessionId);
|
|
261
681
|
|
|
262
682
|
if (!session) {
|
|
@@ -272,28 +692,116 @@ export async function handleSessionResume(server, id, ws, message) {
|
|
|
272
692
|
return;
|
|
273
693
|
}
|
|
274
694
|
|
|
695
|
+
// A JSONL transcript is the cross-host fact source. A fully verified one
|
|
696
|
+
// replaces a stale DB/WS copy. The damaged case returned above before the
|
|
697
|
+
// manager or agent handler could be resumed; only a genuinely absent JSONL
|
|
698
|
+
// transcript keeps the legacy WS-store compatibility path.
|
|
699
|
+
const sessionSnapshot = canonicalResume?.snapshot || null;
|
|
700
|
+
if (canonicalResume) {
|
|
701
|
+
// Capture the fresh host-owned prefix exactly once. Canonical refreshes
|
|
702
|
+
// later in the WS handler must never rescan a message array that already
|
|
703
|
+
// contains a durable compact-summary system turn, or the summary would be
|
|
704
|
+
// mistaken for host context and duplicated after each claim/settlement.
|
|
705
|
+
let hostSystemPrefix;
|
|
706
|
+
try {
|
|
707
|
+
hostSystemPrefix = captureCanonicalHostSystemPrefix(session);
|
|
708
|
+
} catch {
|
|
709
|
+
server._send(
|
|
710
|
+
ws,
|
|
711
|
+
envelopeError(
|
|
712
|
+
id,
|
|
713
|
+
"CC_SESSION_HOST_PREFIX_INVALID",
|
|
714
|
+
"Canonical WS host system prefix is invalid; resume was refused",
|
|
715
|
+
sessionId,
|
|
716
|
+
{ sessionSnapshot },
|
|
717
|
+
),
|
|
718
|
+
);
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
session.messages = [...hostSystemPrefix, ...canonicalResume.messages];
|
|
722
|
+
session.canonicalJsonlSession = true;
|
|
723
|
+
session.sessionHostSnapshot = sessionSnapshot;
|
|
724
|
+
} else {
|
|
725
|
+
session.canonicalJsonlSession = false;
|
|
726
|
+
session.sessionHostSnapshot = null;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// P0-2: reconcile the crash-safe side-effect ledger. If a dangerous tool was
|
|
730
|
+
// in flight when the prior worker died, warn the IDE client AND inject a
|
|
731
|
+
// system note so the resumed model does not silently replay it.
|
|
732
|
+
const recoveryDependencies = {
|
|
733
|
+
...(server.resumeRecoveryDependencies || {}),
|
|
734
|
+
};
|
|
735
|
+
if (canonicalResume?.recovery) {
|
|
736
|
+
recoveryDependencies.loadMcpLedgerRecovery = () => canonicalResume.recovery;
|
|
737
|
+
}
|
|
738
|
+
let recovery = buildResumeRecovery(session.id, recoveryDependencies);
|
|
739
|
+
session.mcpLedgerRecovery = recovery?.mcp || {
|
|
740
|
+
count: 0,
|
|
741
|
+
unsettled: [],
|
|
742
|
+
incidents: [],
|
|
743
|
+
replayDenied: [],
|
|
744
|
+
notice: null,
|
|
745
|
+
};
|
|
746
|
+
session.mcpLedgerRecoveryRevision =
|
|
747
|
+
Number(session.mcpLedgerRecoveryRevision || 0) + 1;
|
|
748
|
+
replaceResumeRecoveryNotice(session, recovery?.notice || null);
|
|
749
|
+
|
|
750
|
+
// Recovery authority must be attached before a handler is created/refreshed
|
|
751
|
+
// or history is exposed. Otherwise an existing clean controller can admit a
|
|
752
|
+
// turn in the resume window before the unsafe projection reaches it.
|
|
275
753
|
if (!server.sessionHandlers.has(sessionId)) {
|
|
276
754
|
try {
|
|
277
755
|
await ensureSessionHandler(server, ws, session);
|
|
278
756
|
} catch (_err) {
|
|
279
|
-
// Session resumed without live handler.
|
|
757
|
+
// Session resumed without live handler. A future handler still reads the
|
|
758
|
+
// already-attached fail-closed recovery authority from the session.
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
const handler = server.sessionHandlers.get(sessionId);
|
|
762
|
+
if (typeof handler?.refreshMcpRecoveryRuntime === "function") {
|
|
763
|
+
try {
|
|
764
|
+
await handler.refreshMcpRecoveryRuntime();
|
|
765
|
+
} catch (error) {
|
|
766
|
+
const failedMcp = failClosedMcpRecovery(
|
|
767
|
+
error,
|
|
768
|
+
"CC_MCP_RECOVERY_REFRESH_FAILED",
|
|
769
|
+
);
|
|
770
|
+
session.mcpLedgerRecovery = failedMcp;
|
|
771
|
+
session.mcpLedgerRecoveryRevision =
|
|
772
|
+
Number(session.mcpLedgerRecoveryRevision || 0) + 1;
|
|
773
|
+
recovery = Object.freeze({
|
|
774
|
+
...recovery,
|
|
775
|
+
count:
|
|
776
|
+
Math.max(
|
|
777
|
+
0,
|
|
778
|
+
Number(recovery?.count || 0) - Number(recovery?.mcp?.count || 0),
|
|
779
|
+
) + failedMcp.count,
|
|
780
|
+
mcp: failedMcp,
|
|
781
|
+
notice: [recovery?.notice, failedMcp.notice]
|
|
782
|
+
.filter(Boolean)
|
|
783
|
+
.join("\n\n"),
|
|
784
|
+
});
|
|
785
|
+
replaceResumeRecoveryNotice(session, recovery.notice);
|
|
280
786
|
}
|
|
281
787
|
}
|
|
282
788
|
|
|
283
|
-
const history = (
|
|
789
|
+
const history = (
|
|
790
|
+
Array.isArray(session.messages) ? session.messages : []
|
|
791
|
+
).filter((m) => m?.role !== "system");
|
|
284
792
|
const record = createSessionRecord(session, {
|
|
285
793
|
history,
|
|
286
794
|
messageCount: history.length,
|
|
287
795
|
status: "resumed",
|
|
288
796
|
});
|
|
289
|
-
|
|
290
|
-
//
|
|
291
|
-
//
|
|
292
|
-
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
797
|
+
// Runtime-bus subscribers receive control-plane continuity metadata, not
|
|
798
|
+
// transcript content. The direct resume response below still carries the
|
|
799
|
+
// requested history to the authenticated IDE client.
|
|
800
|
+
const runtimeRecord = { ...record, history: [] };
|
|
801
|
+
const stateSnapshot =
|
|
802
|
+
typeof server.sessionManager.getSessionStateSnapshot === "function"
|
|
803
|
+
? server.sessionManager.getSessionStateSnapshot(session.id)
|
|
804
|
+
: null;
|
|
297
805
|
|
|
298
806
|
server.emit(
|
|
299
807
|
RUNTIME_EVENTS.SESSION_RESUME,
|
|
@@ -303,8 +811,10 @@ export async function handleSessionResume(server, id, ws, message) {
|
|
|
303
811
|
sessionId: session.id,
|
|
304
812
|
historyCount: history.length,
|
|
305
813
|
sessionType: session.type || null,
|
|
306
|
-
record,
|
|
814
|
+
record: runtimeRecord,
|
|
815
|
+
...(stateSnapshot ? { stateSnapshot } : {}),
|
|
307
816
|
...(recovery ? { recovery } : {}),
|
|
817
|
+
...(sessionSnapshot ? { sessionSnapshot } : {}),
|
|
308
818
|
},
|
|
309
819
|
{ kind: "server", sessionId: session.id },
|
|
310
820
|
),
|
|
@@ -319,7 +829,9 @@ export async function handleSessionResume(server, id, ws, message) {
|
|
|
319
829
|
sessionId: session.id,
|
|
320
830
|
history,
|
|
321
831
|
record,
|
|
832
|
+
...(stateSnapshot ? { stateSnapshot } : {}),
|
|
322
833
|
...(recovery ? { recovery } : {}),
|
|
834
|
+
...(sessionSnapshot ? { sessionSnapshot } : {}),
|
|
323
835
|
},
|
|
324
836
|
session.id,
|
|
325
837
|
),
|
|
@@ -546,15 +1058,31 @@ export async function handleSessionInterrupt(server, id, ws, message) {
|
|
|
546
1058
|
}
|
|
547
1059
|
|
|
548
1060
|
const handler = server.sessionHandlers.get(sessionId);
|
|
549
|
-
const
|
|
550
|
-
handler && typeof handler.interrupt === "function"
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
1061
|
+
const handlerCanInterrupt =
|
|
1062
|
+
handler && typeof handler.interrupt === "function";
|
|
1063
|
+
const result = handlerCanInterrupt
|
|
1064
|
+
? await handler.interrupt()
|
|
1065
|
+
: {
|
|
1066
|
+
sessionId,
|
|
1067
|
+
interrupted: true,
|
|
1068
|
+
wasProcessing: false,
|
|
1069
|
+
interruptedRequestId: null,
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
if (
|
|
1073
|
+
!handlerCanInterrupt &&
|
|
1074
|
+
typeof server.sessionManager.recordSessionStateEvent === "function"
|
|
1075
|
+
) {
|
|
1076
|
+
server.sessionManager.recordSessionStateEvent(
|
|
1077
|
+
sessionId,
|
|
1078
|
+
"run.interrupted",
|
|
1079
|
+
{
|
|
1080
|
+
requestId: result.interruptedRequestId,
|
|
1081
|
+
interruptedAt: new Date().toISOString(),
|
|
1082
|
+
reason: "client_interrupt",
|
|
1083
|
+
},
|
|
1084
|
+
);
|
|
1085
|
+
}
|
|
558
1086
|
|
|
559
1087
|
server._send(
|
|
560
1088
|
ws,
|