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
|
@@ -0,0 +1,884 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only checkpoint restore recovery projections.
|
|
3
|
+
*
|
|
4
|
+
* This module intentionally owns no mutation path. It consumes only the
|
|
5
|
+
* verified output of CheckpointRestoreSagaStore.listPending()/load(), removes
|
|
6
|
+
* private workspace-owner evidence, and derives conservative action
|
|
7
|
+
* preconditions for a future command/controller layer.
|
|
8
|
+
*
|
|
9
|
+
* An action marked `candidate` is visible for adjudication. Only `eligible`
|
|
10
|
+
* may be treated as executable, and every executable action still requires
|
|
11
|
+
* the command layer to revalidate the exact sequence, head hash and owner
|
|
12
|
+
* digest immediately before mutation.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
CHECKPOINT_RESTORE_SAGA_PHASES,
|
|
17
|
+
CHECKPOINT_RESTORE_SAGA_TERMINAL_PHASES,
|
|
18
|
+
} from "./checkpoint-restore-saga.js";
|
|
19
|
+
|
|
20
|
+
export const CHECKPOINT_RESTORE_RECOVERY_PROJECTION_SCHEMA =
|
|
21
|
+
"chainlesschain.checkpoint-restore-recovery-projection";
|
|
22
|
+
export const CHECKPOINT_RESTORE_RECOVERY_LIST_SCHEMA =
|
|
23
|
+
"chainlesschain.checkpoint-restore-recovery-list";
|
|
24
|
+
export const CHECKPOINT_RESTORE_RECOVERY_PROJECTION_VERSION = 1;
|
|
25
|
+
export const MAX_CHECKPOINT_RESTORE_RECOVERY_LIST_LIMIT = 64;
|
|
26
|
+
|
|
27
|
+
const HASH_PATTERN = /^sha256:[a-f0-9]{64}$/;
|
|
28
|
+
const OPERATION_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/;
|
|
29
|
+
const SAFE_ERROR_CODE_PATTERN = /^[A-Z][A-Z0-9_]{0,127}$/;
|
|
30
|
+
|
|
31
|
+
const PHASES = new Set(CHECKPOINT_RESTORE_SAGA_PHASES);
|
|
32
|
+
const RECOVERY_PHASES = new Set(["recovery_required", "recovery_started"]);
|
|
33
|
+
const TERMINAL_PHASES = new Set(CHECKPOINT_RESTORE_SAGA_TERMINAL_PHASES);
|
|
34
|
+
const WORKSPACE_ROLLBACK_CANDIDATE_BASE_PHASES = new Set([
|
|
35
|
+
"mutation_started",
|
|
36
|
+
"rollback_prepared",
|
|
37
|
+
"rollback_started",
|
|
38
|
+
]);
|
|
39
|
+
const WORKSPACE_ROLLBACK_SETTLED_BASE_PHASES = new Set([
|
|
40
|
+
"workspace_rolled_back",
|
|
41
|
+
"session_rollback_committed",
|
|
42
|
+
]);
|
|
43
|
+
const POST_APPLY_BASE_PHASES = new Set([
|
|
44
|
+
"workspace_applied",
|
|
45
|
+
"session_committed",
|
|
46
|
+
]);
|
|
47
|
+
const ROLLBACK_BINDING_BASE_PHASES = new Set([
|
|
48
|
+
"rollback_prepared",
|
|
49
|
+
"rollback_started",
|
|
50
|
+
"workspace_rolled_back",
|
|
51
|
+
"session_rollback_committed",
|
|
52
|
+
]);
|
|
53
|
+
const ABORT_CANDIDATE_BASE_PHASES = new Set([
|
|
54
|
+
"created",
|
|
55
|
+
"locked",
|
|
56
|
+
"prepared",
|
|
57
|
+
"intent_committed",
|
|
58
|
+
"safety_ready",
|
|
59
|
+
]);
|
|
60
|
+
const ABORT_ELIGIBLE_BASE_PHASES = new Set(["created", "locked"]);
|
|
61
|
+
const ENUM_FIELDS = Object.freeze({
|
|
62
|
+
restoreKind: new Set(["copy", "git", "timeline"]),
|
|
63
|
+
restoreSurface: new Set(["direct", "timeline"]),
|
|
64
|
+
intentAuthority: new Set(["operation", "session"]),
|
|
65
|
+
safetyCoverage: new Set(["full", "partial", "none", "unknown"]),
|
|
66
|
+
});
|
|
67
|
+
const TEXT_FIELD_LIMITS = Object.freeze({
|
|
68
|
+
checkpointNamespace: 256,
|
|
69
|
+
checkpointId: 256,
|
|
70
|
+
checkpointIdentity: 1024,
|
|
71
|
+
sessionId: 256,
|
|
72
|
+
timelineEntryId: 256,
|
|
73
|
+
});
|
|
74
|
+
const DIAGNOSTIC_STATUSES = new Set([
|
|
75
|
+
"orphan_unpublished",
|
|
76
|
+
"archived",
|
|
77
|
+
"purge_pending",
|
|
78
|
+
"purged_receipt",
|
|
79
|
+
"purge_receipt_temporary",
|
|
80
|
+
"terminal_unarchived",
|
|
81
|
+
"orphan_temporary",
|
|
82
|
+
"busy",
|
|
83
|
+
"corrupt",
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
function freezeArray(values) {
|
|
87
|
+
return Object.freeze([...values]);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function isPlainObject(value) {
|
|
91
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
92
|
+
const prototype = Object.getPrototypeOf(value);
|
|
93
|
+
return prototype === Object.prototype || prototype === null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function assertOperationId(operationId, label = "operationId") {
|
|
97
|
+
if (
|
|
98
|
+
typeof operationId !== "string" ||
|
|
99
|
+
!OPERATION_ID_PATTERN.test(operationId)
|
|
100
|
+
) {
|
|
101
|
+
throw new TypeError(
|
|
102
|
+
`${label} must be a safe checkpoint restore identifier`,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
return operationId;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function assertStore(store) {
|
|
109
|
+
if (
|
|
110
|
+
!store ||
|
|
111
|
+
typeof store !== "object" ||
|
|
112
|
+
typeof store.listPending !== "function" ||
|
|
113
|
+
typeof store.load !== "function"
|
|
114
|
+
) {
|
|
115
|
+
throw new TypeError(
|
|
116
|
+
"checkpoint restore recovery reader requires listPending/load dependencies",
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return store;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function assertSaga(saga) {
|
|
123
|
+
if (!isPlainObject(saga)) {
|
|
124
|
+
throw new TypeError("checkpoint restore saga projection must be an object");
|
|
125
|
+
}
|
|
126
|
+
const operationId = assertOperationId(saga.operationId);
|
|
127
|
+
if (
|
|
128
|
+
!Number.isSafeInteger(saga.seq) ||
|
|
129
|
+
saga.seq < 1 ||
|
|
130
|
+
typeof saga.headHash !== "string" ||
|
|
131
|
+
!HASH_PATTERN.test(saga.headHash) ||
|
|
132
|
+
!PHASES.has(saga.phase) ||
|
|
133
|
+
typeof saga.workspaceIdentity !== "string" ||
|
|
134
|
+
!HASH_PATTERN.test(saga.workspaceIdentity) ||
|
|
135
|
+
!Array.isArray(saga.events) ||
|
|
136
|
+
saga.events.length !== saga.seq
|
|
137
|
+
) {
|
|
138
|
+
throw new TypeError("checkpoint restore saga projection is not canonical");
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const terminal = TERMINAL_PHASES.has(saga.phase);
|
|
142
|
+
if (saga.terminal !== terminal || saga.pending !== !terminal) {
|
|
143
|
+
throw new TypeError(
|
|
144
|
+
"checkpoint restore saga terminal flags are inconsistent",
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
for (let index = 0; index < saga.events.length; index += 1) {
|
|
149
|
+
const event = saga.events[index];
|
|
150
|
+
if (
|
|
151
|
+
!isPlainObject(event) ||
|
|
152
|
+
event.operationId !== operationId ||
|
|
153
|
+
event.seq !== index + 1 ||
|
|
154
|
+
!PHASES.has(event.phase) ||
|
|
155
|
+
!Number.isSafeInteger(event.timestamp) ||
|
|
156
|
+
event.timestamp < 0 ||
|
|
157
|
+
typeof event.hash !== "string" ||
|
|
158
|
+
!HASH_PATTERN.test(event.hash) ||
|
|
159
|
+
!isPlainObject(event.evidence)
|
|
160
|
+
) {
|
|
161
|
+
throw new TypeError(
|
|
162
|
+
"checkpoint restore saga event projection is invalid",
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const head = saga.events.at(-1);
|
|
168
|
+
if (
|
|
169
|
+
head.seq !== saga.seq ||
|
|
170
|
+
head.phase !== saga.phase ||
|
|
171
|
+
head.hash !== saga.headHash
|
|
172
|
+
) {
|
|
173
|
+
throw new TypeError(
|
|
174
|
+
"checkpoint restore saga head projection is inconsistent",
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
return saga;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function latestEvidence(events, key) {
|
|
181
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
182
|
+
const evidence = events[index].evidence;
|
|
183
|
+
if (Object.hasOwn(evidence, key)) return evidence[key];
|
|
184
|
+
}
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function optionalHash(value) {
|
|
189
|
+
return typeof value === "string" && HASH_PATTERN.test(value) ? value : null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function optionalEnum(field, value) {
|
|
193
|
+
return typeof value === "string" && ENUM_FIELDS[field]?.has(value)
|
|
194
|
+
? value
|
|
195
|
+
: null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function optionalText(field, value) {
|
|
199
|
+
const limit = TEXT_FIELD_LIMITS[field];
|
|
200
|
+
return typeof value === "string" && value.length <= limit ? value : null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function optionalCount(value) {
|
|
204
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function boundedEvidenceText(value, maximum) {
|
|
208
|
+
if (
|
|
209
|
+
typeof value !== "string" ||
|
|
210
|
+
value.length === 0 ||
|
|
211
|
+
value.length > maximum ||
|
|
212
|
+
value.trim() !== value
|
|
213
|
+
) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
217
|
+
const code = value.charCodeAt(index);
|
|
218
|
+
if (code < 32 || code === 127) return false;
|
|
219
|
+
}
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
function strictConsistentEvidence(events, key, validator) {
|
|
224
|
+
let projected = null;
|
|
225
|
+
let present = false;
|
|
226
|
+
for (const event of events) {
|
|
227
|
+
if (!Object.hasOwn(event.evidence, key)) continue;
|
|
228
|
+
const value = event.evidence[key];
|
|
229
|
+
if (!validator(value) || (present && value !== projected)) {
|
|
230
|
+
throw new TypeError(`checkpoint restore rollback ${key} is invalid`);
|
|
231
|
+
}
|
|
232
|
+
projected = value;
|
|
233
|
+
present = true;
|
|
234
|
+
}
|
|
235
|
+
return present ? projected : null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function projectRollbackEvidence(events, basePhase, hasSessionAuthority) {
|
|
239
|
+
const empty = () =>
|
|
240
|
+
Object.freeze({
|
|
241
|
+
phase: null,
|
|
242
|
+
recoveryRequestId: null,
|
|
243
|
+
rollbackPrestateDigest: null,
|
|
244
|
+
rollbackPlanIdentity: null,
|
|
245
|
+
originalMutationTargetCount: null,
|
|
246
|
+
targetCount: null,
|
|
247
|
+
rolledBackCount: null,
|
|
248
|
+
rollbackStateDigest: null,
|
|
249
|
+
resultDigest: null,
|
|
250
|
+
sessionRollbackCommitDigest: null,
|
|
251
|
+
});
|
|
252
|
+
const recoveryStarts = events.filter(
|
|
253
|
+
(event) =>
|
|
254
|
+
event.phase === "recovery_started" &&
|
|
255
|
+
Object.hasOwn(event.evidence, "recoveryRequestId"),
|
|
256
|
+
);
|
|
257
|
+
for (const event of recoveryStarts) {
|
|
258
|
+
if (!boundedEvidenceText(event.evidence.recoveryRequestId, 256)) {
|
|
259
|
+
throw new TypeError(
|
|
260
|
+
"checkpoint restore rollback recoveryRequestId is invalid",
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const recoveryRequestId = recoveryStarts.at(-1)?.evidence.recoveryRequestId;
|
|
265
|
+
if (recoveryRequestId === undefined) {
|
|
266
|
+
if (ROLLBACK_BINDING_BASE_PHASES.has(basePhase)) {
|
|
267
|
+
throw new TypeError(
|
|
268
|
+
"checkpoint restore rollback recoveryRequestId is missing",
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
return empty();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const rollbackEvents = events.filter(
|
|
275
|
+
(event) => event.evidence.recoveryRequestId === recoveryRequestId,
|
|
276
|
+
);
|
|
277
|
+
const phaseRank = new Map([
|
|
278
|
+
["recovery_started", 0],
|
|
279
|
+
["rollback_prepared", 1],
|
|
280
|
+
["rollback_started", 2],
|
|
281
|
+
["workspace_rolled_back", 3],
|
|
282
|
+
["session_rollback_committed", 4],
|
|
283
|
+
["rolled_back", 5],
|
|
284
|
+
]);
|
|
285
|
+
let requestPhase = "recovery_started";
|
|
286
|
+
for (const event of rollbackEvents) {
|
|
287
|
+
if (
|
|
288
|
+
phaseRank.has(event.phase) &&
|
|
289
|
+
phaseRank.get(event.phase) > phaseRank.get(requestPhase)
|
|
290
|
+
) {
|
|
291
|
+
requestPhase = event.phase;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const rollback = {
|
|
295
|
+
phase: requestPhase,
|
|
296
|
+
recoveryRequestId: strictConsistentEvidence(
|
|
297
|
+
rollbackEvents,
|
|
298
|
+
"recoveryRequestId",
|
|
299
|
+
(value) => boundedEvidenceText(value, 256),
|
|
300
|
+
),
|
|
301
|
+
rollbackPrestateDigest: strictConsistentEvidence(
|
|
302
|
+
rollbackEvents,
|
|
303
|
+
"rollbackPrestateDigest",
|
|
304
|
+
(value) => typeof value === "string" && HASH_PATTERN.test(value),
|
|
305
|
+
),
|
|
306
|
+
rollbackPlanIdentity: strictConsistentEvidence(
|
|
307
|
+
rollbackEvents,
|
|
308
|
+
"rollbackPlanIdentity",
|
|
309
|
+
(value) => typeof value === "string" && HASH_PATTERN.test(value),
|
|
310
|
+
),
|
|
311
|
+
originalMutationTargetCount: strictConsistentEvidence(
|
|
312
|
+
rollbackEvents,
|
|
313
|
+
"originalMutationTargetCount",
|
|
314
|
+
(value) => Number.isSafeInteger(value) && value >= 0,
|
|
315
|
+
),
|
|
316
|
+
targetCount: strictConsistentEvidence(
|
|
317
|
+
rollbackEvents,
|
|
318
|
+
"targetCount",
|
|
319
|
+
(value) => Number.isSafeInteger(value) && value >= 0,
|
|
320
|
+
),
|
|
321
|
+
rolledBackCount: strictConsistentEvidence(
|
|
322
|
+
rollbackEvents,
|
|
323
|
+
"rolledBackCount",
|
|
324
|
+
(value) => Number.isSafeInteger(value) && value >= 0,
|
|
325
|
+
),
|
|
326
|
+
rollbackStateDigest: strictConsistentEvidence(
|
|
327
|
+
rollbackEvents,
|
|
328
|
+
"rollbackStateDigest",
|
|
329
|
+
(value) => typeof value === "string" && HASH_PATTERN.test(value),
|
|
330
|
+
),
|
|
331
|
+
resultDigest: strictConsistentEvidence(
|
|
332
|
+
rollbackEvents,
|
|
333
|
+
"resultDigest",
|
|
334
|
+
(value) => typeof value === "string" && HASH_PATTERN.test(value),
|
|
335
|
+
),
|
|
336
|
+
sessionRollbackCommitDigest: strictConsistentEvidence(
|
|
337
|
+
rollbackEvents,
|
|
338
|
+
"sessionRollbackCommitDigest",
|
|
339
|
+
(value) => typeof value === "string" && HASH_PATTERN.test(value),
|
|
340
|
+
),
|
|
341
|
+
};
|
|
342
|
+
const bindingComplete = [
|
|
343
|
+
"recoveryRequestId",
|
|
344
|
+
"rollbackPrestateDigest",
|
|
345
|
+
"rollbackPlanIdentity",
|
|
346
|
+
"originalMutationTargetCount",
|
|
347
|
+
"targetCount",
|
|
348
|
+
].every((field) => rollback[field] !== null);
|
|
349
|
+
const workspaceSettlementComplete = [
|
|
350
|
+
"rolledBackCount",
|
|
351
|
+
"rollbackStateDigest",
|
|
352
|
+
"resultDigest",
|
|
353
|
+
].every((field) => rollback[field] !== null);
|
|
354
|
+
const bindingRequired = [
|
|
355
|
+
"rollback_prepared",
|
|
356
|
+
"rollback_started",
|
|
357
|
+
"workspace_rolled_back",
|
|
358
|
+
"session_rollback_committed",
|
|
359
|
+
"rolled_back",
|
|
360
|
+
].includes(requestPhase);
|
|
361
|
+
const workspaceSettlementRequired = [
|
|
362
|
+
"workspace_rolled_back",
|
|
363
|
+
"session_rollback_committed",
|
|
364
|
+
"rolled_back",
|
|
365
|
+
].includes(requestPhase);
|
|
366
|
+
if (
|
|
367
|
+
(bindingRequired && !bindingComplete) ||
|
|
368
|
+
(workspaceSettlementRequired && !workspaceSettlementComplete) ||
|
|
369
|
+
((requestPhase === "session_rollback_committed" ||
|
|
370
|
+
(requestPhase === "rolled_back" && hasSessionAuthority)) &&
|
|
371
|
+
rollback.sessionRollbackCommitDigest === null) ||
|
|
372
|
+
(rollback.originalMutationTargetCount !== null &&
|
|
373
|
+
rollback.targetCount !== null &&
|
|
374
|
+
rollback.targetCount > rollback.originalMutationTargetCount) ||
|
|
375
|
+
(rollback.rolledBackCount !== null &&
|
|
376
|
+
(rollback.targetCount === null ||
|
|
377
|
+
rollback.rolledBackCount !== rollback.targetCount))
|
|
378
|
+
) {
|
|
379
|
+
throw new TypeError(
|
|
380
|
+
"checkpoint restore rollback evidence is incomplete or inconsistent",
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
return Object.freeze(rollback);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function safeErrorCode(value) {
|
|
387
|
+
return typeof value === "string" && SAFE_ERROR_CODE_PATTERN.test(value)
|
|
388
|
+
? value
|
|
389
|
+
: null;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function recoveryBasePhase(events) {
|
|
393
|
+
let basePhase = null;
|
|
394
|
+
for (const event of events) {
|
|
395
|
+
if (
|
|
396
|
+
!RECOVERY_PHASES.has(event.phase) &&
|
|
397
|
+
!TERMINAL_PHASES.has(event.phase)
|
|
398
|
+
) {
|
|
399
|
+
basePhase = event.phase;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return basePhase;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function recoveryStatus({ phase, basePhase, terminal, hasSessionAuthority }) {
|
|
406
|
+
if (terminal) return "terminal";
|
|
407
|
+
if (["rollback_prepared", "rollback_started"].includes(basePhase)) {
|
|
408
|
+
return "rollback_in_progress";
|
|
409
|
+
}
|
|
410
|
+
if (basePhase === "workspace_rolled_back") {
|
|
411
|
+
return hasSessionAuthority
|
|
412
|
+
? "workspace_rolled_back_pending_session"
|
|
413
|
+
: "workspace_rolled_back_pending_terminal";
|
|
414
|
+
}
|
|
415
|
+
if (basePhase === "session_rollback_committed") {
|
|
416
|
+
return "session_rollback_pending_terminal";
|
|
417
|
+
}
|
|
418
|
+
if (phase === "recovery_required") return "recovery_required";
|
|
419
|
+
if (phase === "recovery_started") return "recovery_in_progress";
|
|
420
|
+
return "pending";
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function action({ candidate, eligible, blockers, prerequisites }) {
|
|
424
|
+
return Object.freeze({
|
|
425
|
+
candidate: candidate === true,
|
|
426
|
+
eligible: eligible === true,
|
|
427
|
+
blockers: freezeArray(blockers),
|
|
428
|
+
prerequisites: freezeArray(prerequisites),
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function unavailableActions(blocker) {
|
|
433
|
+
const unavailable = () =>
|
|
434
|
+
action({
|
|
435
|
+
candidate: false,
|
|
436
|
+
eligible: false,
|
|
437
|
+
blockers: [blocker],
|
|
438
|
+
prerequisites: [],
|
|
439
|
+
});
|
|
440
|
+
return Object.freeze({
|
|
441
|
+
mode: "read_only_preflight",
|
|
442
|
+
abort: unavailable(),
|
|
443
|
+
resume: unavailable(),
|
|
444
|
+
rollback: unavailable(),
|
|
445
|
+
release: unavailable(),
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function deriveActionEligibility({
|
|
450
|
+
phase,
|
|
451
|
+
basePhase,
|
|
452
|
+
terminal,
|
|
453
|
+
clean,
|
|
454
|
+
workspaceLockOwnerDigest,
|
|
455
|
+
hasSessionAuthority,
|
|
456
|
+
hasFullSafety,
|
|
457
|
+
}) {
|
|
458
|
+
const pending = !terminal;
|
|
459
|
+
const knownBasePhase = basePhase !== null;
|
|
460
|
+
const recoveryClaimed = RECOVERY_PHASES.has(phase);
|
|
461
|
+
const commonMutationPrerequisites = [
|
|
462
|
+
"exact_seq_and_head_match",
|
|
463
|
+
"workspace_owner_status_verification",
|
|
464
|
+
"workspace_state_verification",
|
|
465
|
+
];
|
|
466
|
+
if (hasSessionAuthority) {
|
|
467
|
+
commonMutationPrerequisites.push("session_state_verification");
|
|
468
|
+
}
|
|
469
|
+
if (!recoveryClaimed) {
|
|
470
|
+
commonMutationPrerequisites.push("recovery_claim");
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const abortCandidate =
|
|
474
|
+
pending &&
|
|
475
|
+
knownBasePhase &&
|
|
476
|
+
clean &&
|
|
477
|
+
ABORT_CANDIDATE_BASE_PHASES.has(basePhase);
|
|
478
|
+
const abortSupported = ABORT_ELIGIBLE_BASE_PHASES.has(basePhase);
|
|
479
|
+
const abortOwnerBindingComplete =
|
|
480
|
+
basePhase === "created"
|
|
481
|
+
? workspaceLockOwnerDigest === null
|
|
482
|
+
: workspaceLockOwnerDigest !== null;
|
|
483
|
+
const abortEligible = false;
|
|
484
|
+
const abortBlockers = [];
|
|
485
|
+
if (!pending) abortBlockers.push("saga_is_terminal");
|
|
486
|
+
if (!knownBasePhase) abortBlockers.push("base_phase_unknown");
|
|
487
|
+
if (!clean) abortBlockers.push("saga_has_orphan_temporary_files");
|
|
488
|
+
if (
|
|
489
|
+
pending &&
|
|
490
|
+
knownBasePhase &&
|
|
491
|
+
!ABORT_CANDIDATE_BASE_PHASES.has(basePhase)
|
|
492
|
+
) {
|
|
493
|
+
abortBlockers.push("abort_not_safe_after_mutation_boundary");
|
|
494
|
+
}
|
|
495
|
+
if (abortCandidate && !abortSupported) {
|
|
496
|
+
abortBlockers.push(
|
|
497
|
+
"controller_phase_not_supported",
|
|
498
|
+
"session_intent_state_unverified",
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
if (abortCandidate && basePhase === "created" && !abortOwnerBindingComplete) {
|
|
502
|
+
abortBlockers.push("unexpected_workspace_owner_digest");
|
|
503
|
+
}
|
|
504
|
+
if (abortCandidate && basePhase === "locked" && !abortOwnerBindingComplete) {
|
|
505
|
+
abortBlockers.push("workspace_owner_digest_missing");
|
|
506
|
+
}
|
|
507
|
+
if (abortCandidate && abortSupported && abortOwnerBindingComplete) {
|
|
508
|
+
abortBlockers.push("workspace_owner_status_unverified");
|
|
509
|
+
}
|
|
510
|
+
const abortPrerequisites = abortCandidate
|
|
511
|
+
? [
|
|
512
|
+
"exact_seq_and_head_match",
|
|
513
|
+
basePhase === "created"
|
|
514
|
+
? "workspace_owner_absence_verification"
|
|
515
|
+
: "workspace_owner_digest_match",
|
|
516
|
+
...(basePhase === "created"
|
|
517
|
+
? []
|
|
518
|
+
: ["workspace_owner_status_verification"]),
|
|
519
|
+
...(!abortSupported ? ["session_intent_state_verification"] : []),
|
|
520
|
+
...(hasSessionAuthority ? ["session_state_verification"] : []),
|
|
521
|
+
]
|
|
522
|
+
: [];
|
|
523
|
+
|
|
524
|
+
const resumeCandidate = pending && knownBasePhase && clean;
|
|
525
|
+
const resumeBlockers = [];
|
|
526
|
+
if (!pending) resumeBlockers.push("saga_is_terminal");
|
|
527
|
+
if (!knownBasePhase) resumeBlockers.push("base_phase_unknown");
|
|
528
|
+
if (!clean) resumeBlockers.push("saga_has_orphan_temporary_files");
|
|
529
|
+
if (resumeCandidate) {
|
|
530
|
+
resumeBlockers.push(
|
|
531
|
+
"workspace_owner_status_unverified",
|
|
532
|
+
"workspace_state_unverified",
|
|
533
|
+
);
|
|
534
|
+
if (hasSessionAuthority) {
|
|
535
|
+
resumeBlockers.push("session_state_unverified");
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
const workspaceRollbackPhase =
|
|
540
|
+
WORKSPACE_ROLLBACK_CANDIDATE_BASE_PHASES.has(basePhase);
|
|
541
|
+
const workspaceRollbackSettled =
|
|
542
|
+
WORKSPACE_ROLLBACK_SETTLED_BASE_PHASES.has(basePhase);
|
|
543
|
+
const workspaceRollbackSupported =
|
|
544
|
+
workspaceRollbackPhase || workspaceRollbackSettled;
|
|
545
|
+
const postApplySettlement = POST_APPLY_BASE_PHASES.has(basePhase);
|
|
546
|
+
const rollbackCandidate =
|
|
547
|
+
pending &&
|
|
548
|
+
knownBasePhase &&
|
|
549
|
+
clean &&
|
|
550
|
+
workspaceRollbackSupported &&
|
|
551
|
+
hasFullSafety;
|
|
552
|
+
const rollbackBlockers = [];
|
|
553
|
+
if (!pending) rollbackBlockers.push("saga_is_terminal");
|
|
554
|
+
if (!knownBasePhase) rollbackBlockers.push("base_phase_unknown");
|
|
555
|
+
if (!clean) rollbackBlockers.push("saga_has_orphan_temporary_files");
|
|
556
|
+
if (pending && knownBasePhase && postApplySettlement) {
|
|
557
|
+
rollbackBlockers.push("workspace_rollback_not_partial_mutation");
|
|
558
|
+
} else if (pending && knownBasePhase && !workspaceRollbackSupported) {
|
|
559
|
+
rollbackBlockers.push("workspace_mutation_not_proven");
|
|
560
|
+
}
|
|
561
|
+
if (pending && workspaceRollbackSupported && !hasFullSafety) {
|
|
562
|
+
rollbackBlockers.push("full_safety_evidence_missing");
|
|
563
|
+
}
|
|
564
|
+
if (rollbackCandidate) {
|
|
565
|
+
rollbackBlockers.push(
|
|
566
|
+
"workspace_owner_status_unverified",
|
|
567
|
+
"workspace_state_unverified",
|
|
568
|
+
"safety_checkpoint_unverified",
|
|
569
|
+
);
|
|
570
|
+
if (hasSessionAuthority) {
|
|
571
|
+
rollbackBlockers.push("session_state_unverified");
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const releaseCandidate = terminal;
|
|
576
|
+
const releaseEligible = false;
|
|
577
|
+
const releaseBlockers = [];
|
|
578
|
+
if (!terminal) releaseBlockers.push("saga_is_not_terminal");
|
|
579
|
+
if (!clean) releaseBlockers.push("saga_has_orphan_temporary_files");
|
|
580
|
+
if (terminal && clean) {
|
|
581
|
+
releaseBlockers.push("workspace_owner_status_unverified");
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return Object.freeze({
|
|
585
|
+
mode: "read_only_preflight",
|
|
586
|
+
abort: action({
|
|
587
|
+
candidate: abortCandidate,
|
|
588
|
+
eligible: abortEligible,
|
|
589
|
+
blockers: abortBlockers,
|
|
590
|
+
prerequisites: abortPrerequisites,
|
|
591
|
+
}),
|
|
592
|
+
resume: action({
|
|
593
|
+
candidate: resumeCandidate,
|
|
594
|
+
eligible: false,
|
|
595
|
+
blockers: resumeBlockers,
|
|
596
|
+
prerequisites: resumeCandidate ? commonMutationPrerequisites : [],
|
|
597
|
+
}),
|
|
598
|
+
rollback: action({
|
|
599
|
+
candidate: rollbackCandidate,
|
|
600
|
+
eligible: false,
|
|
601
|
+
blockers: rollbackBlockers,
|
|
602
|
+
prerequisites: rollbackCandidate
|
|
603
|
+
? [...commonMutationPrerequisites, "verified_full_safety_checkpoint"]
|
|
604
|
+
: [],
|
|
605
|
+
}),
|
|
606
|
+
release: action({
|
|
607
|
+
candidate: releaseCandidate,
|
|
608
|
+
eligible: releaseEligible,
|
|
609
|
+
blockers: releaseBlockers,
|
|
610
|
+
prerequisites: releaseCandidate
|
|
611
|
+
? ["exact_seq_and_head_match", "live_workspace_owner_fence"]
|
|
612
|
+
: [],
|
|
613
|
+
}),
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* Project one already-verified saga without returning its event/evidence
|
|
619
|
+
* objects. In particular, workspaceRoot and workspaceLockOwner are never part
|
|
620
|
+
* of the returned object.
|
|
621
|
+
*/
|
|
622
|
+
export function projectCheckpointRestoreRecovery(input) {
|
|
623
|
+
const saga = assertSaga(input);
|
|
624
|
+
const events = saga.events;
|
|
625
|
+
const basePhase = recoveryBasePhase(events);
|
|
626
|
+
const restoreKind = optionalEnum(
|
|
627
|
+
"restoreKind",
|
|
628
|
+
latestEvidence(events, "restoreKind"),
|
|
629
|
+
);
|
|
630
|
+
const restoreSurface = optionalEnum(
|
|
631
|
+
"restoreSurface",
|
|
632
|
+
latestEvidence(events, "restoreSurface"),
|
|
633
|
+
);
|
|
634
|
+
const intentAuthority = optionalEnum(
|
|
635
|
+
"intentAuthority",
|
|
636
|
+
latestEvidence(events, "intentAuthority"),
|
|
637
|
+
);
|
|
638
|
+
const sessionId = optionalText(
|
|
639
|
+
"sessionId",
|
|
640
|
+
latestEvidence(events, "sessionId"),
|
|
641
|
+
);
|
|
642
|
+
const timelineEntryId = optionalText(
|
|
643
|
+
"timelineEntryId",
|
|
644
|
+
latestEvidence(events, "timelineEntryId"),
|
|
645
|
+
);
|
|
646
|
+
const safetyCoverage = optionalEnum(
|
|
647
|
+
"safetyCoverage",
|
|
648
|
+
latestEvidence(events, "safetyCoverage"),
|
|
649
|
+
);
|
|
650
|
+
const safetyId = optionalText(
|
|
651
|
+
"checkpointId",
|
|
652
|
+
latestEvidence(events, "safetyId"),
|
|
653
|
+
);
|
|
654
|
+
const safetyIdentity = optionalText(
|
|
655
|
+
"checkpointIdentity",
|
|
656
|
+
latestEvidence(events, "safetyIdentity"),
|
|
657
|
+
);
|
|
658
|
+
const safetyPlanIdentity = optionalText(
|
|
659
|
+
"checkpointIdentity",
|
|
660
|
+
latestEvidence(events, "safetyPlanIdentity"),
|
|
661
|
+
);
|
|
662
|
+
const workspaceLockOwnerDigest = optionalHash(
|
|
663
|
+
latestEvidence(events, "lockOwnerDigest"),
|
|
664
|
+
);
|
|
665
|
+
const workspaceOwnerEvidencePresent = events.some((event) =>
|
|
666
|
+
Object.hasOwn(event.evidence, "workspaceLockOwner"),
|
|
667
|
+
);
|
|
668
|
+
const orphanTemporaryFilesPresent =
|
|
669
|
+
Array.isArray(saga.orphanTemporaryFiles) &&
|
|
670
|
+
saga.orphanTemporaryFiles.length > 0;
|
|
671
|
+
const clean = !orphanTemporaryFilesPresent;
|
|
672
|
+
const hasSessionAuthority =
|
|
673
|
+
intentAuthority === "session" ||
|
|
674
|
+
sessionId !== null ||
|
|
675
|
+
timelineEntryId !== null;
|
|
676
|
+
const hasFullSafety =
|
|
677
|
+
safetyCoverage === "full" &&
|
|
678
|
+
safetyId !== null &&
|
|
679
|
+
safetyIdentity !== null &&
|
|
680
|
+
safetyPlanIdentity !== null;
|
|
681
|
+
const rollback = projectRollbackEvidence(
|
|
682
|
+
events,
|
|
683
|
+
basePhase,
|
|
684
|
+
hasSessionAuthority,
|
|
685
|
+
);
|
|
686
|
+
const actionEligibility = deriveActionEligibility({
|
|
687
|
+
phase: saga.phase,
|
|
688
|
+
basePhase,
|
|
689
|
+
terminal: saga.terminal,
|
|
690
|
+
clean,
|
|
691
|
+
workspaceLockOwnerDigest,
|
|
692
|
+
hasSessionAuthority,
|
|
693
|
+
hasFullSafety,
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
return Object.freeze({
|
|
697
|
+
schema: CHECKPOINT_RESTORE_RECOVERY_PROJECTION_SCHEMA,
|
|
698
|
+
version: CHECKPOINT_RESTORE_RECOVERY_PROJECTION_VERSION,
|
|
699
|
+
operationId: saga.operationId,
|
|
700
|
+
phase: saga.phase,
|
|
701
|
+
basePhase,
|
|
702
|
+
status: recoveryStatus({
|
|
703
|
+
phase: saga.phase,
|
|
704
|
+
basePhase,
|
|
705
|
+
terminal: saga.terminal,
|
|
706
|
+
hasSessionAuthority,
|
|
707
|
+
}),
|
|
708
|
+
pending: saga.pending,
|
|
709
|
+
terminal: saga.terminal,
|
|
710
|
+
seq: saga.seq,
|
|
711
|
+
headHash: saga.headHash,
|
|
712
|
+
workspaceIdentity: saga.workspaceIdentity,
|
|
713
|
+
fence: Object.freeze({
|
|
714
|
+
expectedSeq: saga.seq,
|
|
715
|
+
expectedHash: saga.headHash,
|
|
716
|
+
// Historical saga evidence is diagnostic only. A command must inspect
|
|
717
|
+
// the current canonical workspace lock before deriving an owner fence.
|
|
718
|
+
ownerAuthority: "unverified",
|
|
719
|
+
recordedOwnerDigest: workspaceLockOwnerDigest,
|
|
720
|
+
}),
|
|
721
|
+
createdAt: events[0].timestamp,
|
|
722
|
+
updatedAt: events.at(-1).timestamp,
|
|
723
|
+
restore: Object.freeze({
|
|
724
|
+
kind: restoreKind,
|
|
725
|
+
surface: restoreSurface,
|
|
726
|
+
intentAuthority,
|
|
727
|
+
checkpointNamespace: optionalText(
|
|
728
|
+
"checkpointNamespace",
|
|
729
|
+
latestEvidence(events, "checkpointNamespace"),
|
|
730
|
+
),
|
|
731
|
+
checkpointId: optionalText(
|
|
732
|
+
"checkpointId",
|
|
733
|
+
latestEvidence(events, "checkpointId"),
|
|
734
|
+
),
|
|
735
|
+
checkpointIdentity: optionalText(
|
|
736
|
+
"checkpointIdentity",
|
|
737
|
+
latestEvidence(events, "checkpointIdentity"),
|
|
738
|
+
),
|
|
739
|
+
sessionId,
|
|
740
|
+
timelineEntryId,
|
|
741
|
+
}),
|
|
742
|
+
progress: Object.freeze({
|
|
743
|
+
targetCount: optionalCount(latestEvidence(events, "targetCount")),
|
|
744
|
+
appliedCount: optionalCount(latestEvidence(events, "appliedCount")),
|
|
745
|
+
}),
|
|
746
|
+
safety: Object.freeze({
|
|
747
|
+
coverage: safetyCoverage,
|
|
748
|
+
checkpointId: safetyId,
|
|
749
|
+
checkpointIdentity: safetyIdentity,
|
|
750
|
+
planIdentity: safetyPlanIdentity,
|
|
751
|
+
complete: hasFullSafety,
|
|
752
|
+
}),
|
|
753
|
+
rollback,
|
|
754
|
+
authority: Object.freeze({
|
|
755
|
+
workspaceOwnerEvidencePresent,
|
|
756
|
+
workspaceOwnerDigestPresent: workspaceLockOwnerDigest !== null,
|
|
757
|
+
complete:
|
|
758
|
+
workspaceOwnerEvidencePresent && workspaceLockOwnerDigest !== null,
|
|
759
|
+
}),
|
|
760
|
+
recovery: Object.freeze({
|
|
761
|
+
errorCode: safeErrorCode(latestEvidence(events, "errorCode")),
|
|
762
|
+
reasonPresent: events.some((event) =>
|
|
763
|
+
Object.hasOwn(event.evidence, "reason"),
|
|
764
|
+
),
|
|
765
|
+
actionRecorded: events.some((event) =>
|
|
766
|
+
Object.hasOwn(event.evidence, "recoveryAction"),
|
|
767
|
+
),
|
|
768
|
+
}),
|
|
769
|
+
integrity: Object.freeze({
|
|
770
|
+
clean,
|
|
771
|
+
orphanTemporaryFilesPresent,
|
|
772
|
+
}),
|
|
773
|
+
actionEligibility,
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
function projectDiagnostic(input) {
|
|
778
|
+
if (!isPlainObject(input)) {
|
|
779
|
+
throw new TypeError("checkpoint restore recovery diagnostic is invalid");
|
|
780
|
+
}
|
|
781
|
+
const operationId = assertOperationId(
|
|
782
|
+
input.operationId,
|
|
783
|
+
"diagnostic operationId",
|
|
784
|
+
);
|
|
785
|
+
const status = DIAGNOSTIC_STATUSES.has(input.status)
|
|
786
|
+
? input.status
|
|
787
|
+
: "unavailable";
|
|
788
|
+
return Object.freeze({
|
|
789
|
+
operationId,
|
|
790
|
+
status,
|
|
791
|
+
code: safeErrorCode(input.code),
|
|
792
|
+
recoverable: input.recoverable === true,
|
|
793
|
+
actionEligibility: unavailableActions("verified_saga_projection_required"),
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/** Read one bounded page using CheckpointRestoreSagaStore.listPending(). */
|
|
798
|
+
export function listCheckpointRestoreRecoveries({
|
|
799
|
+
store,
|
|
800
|
+
afterOperationId = "",
|
|
801
|
+
limit = MAX_CHECKPOINT_RESTORE_RECOVERY_LIST_LIMIT,
|
|
802
|
+
} = {}) {
|
|
803
|
+
const readerStore = assertStore(store);
|
|
804
|
+
if (
|
|
805
|
+
(afterOperationId !== "" && !OPERATION_ID_PATTERN.test(afterOperationId)) ||
|
|
806
|
+
!Number.isSafeInteger(limit) ||
|
|
807
|
+
limit < 1 ||
|
|
808
|
+
limit > MAX_CHECKPOINT_RESTORE_RECOVERY_LIST_LIMIT
|
|
809
|
+
) {
|
|
810
|
+
throw new TypeError(
|
|
811
|
+
"checkpoint restore recovery listing requires a safe cursor and bounded limit",
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
const listed = readerStore.listPending({ afterOperationId, limit });
|
|
816
|
+
if (!Array.isArray(listed)) {
|
|
817
|
+
throw new TypeError(
|
|
818
|
+
"checkpoint restore listPending dependency returned no page",
|
|
819
|
+
);
|
|
820
|
+
}
|
|
821
|
+
const items = freezeArray(listed.map(projectCheckpointRestoreRecovery));
|
|
822
|
+
const diagnostics = freezeArray(
|
|
823
|
+
(Array.isArray(listed.diagnostics) ? listed.diagnostics : []).map(
|
|
824
|
+
projectDiagnostic,
|
|
825
|
+
),
|
|
826
|
+
);
|
|
827
|
+
const truncated = listed.truncated === true;
|
|
828
|
+
const budgetExhausted = listed.budgetExhausted === true;
|
|
829
|
+
const nextCursor = truncated ? listed.nextCursor : null;
|
|
830
|
+
if (
|
|
831
|
+
(truncated &&
|
|
832
|
+
(typeof nextCursor !== "string" ||
|
|
833
|
+
(nextCursor !== "" && !OPERATION_ID_PATTERN.test(nextCursor)))) ||
|
|
834
|
+
(!truncated && listed.nextCursor != null) ||
|
|
835
|
+
(budgetExhausted && !truncated)
|
|
836
|
+
) {
|
|
837
|
+
throw new TypeError("checkpoint restore pagination metadata is invalid");
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
return Object.freeze({
|
|
841
|
+
schema: CHECKPOINT_RESTORE_RECOVERY_LIST_SCHEMA,
|
|
842
|
+
version: CHECKPOINT_RESTORE_RECOVERY_PROJECTION_VERSION,
|
|
843
|
+
items,
|
|
844
|
+
diagnostics,
|
|
845
|
+
page: Object.freeze({
|
|
846
|
+
afterOperationId,
|
|
847
|
+
limit,
|
|
848
|
+
returned: items.length,
|
|
849
|
+
diagnostics: diagnostics.length,
|
|
850
|
+
truncated,
|
|
851
|
+
budgetExhausted,
|
|
852
|
+
nextCursor,
|
|
853
|
+
}),
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/** Read one verified active saga using CheckpointRestoreSagaStore.load(). */
|
|
858
|
+
export function showCheckpointRestoreRecovery({ store, operationId } = {}) {
|
|
859
|
+
const readerStore = assertStore(store);
|
|
860
|
+
const safeOperationId = assertOperationId(operationId);
|
|
861
|
+
return projectCheckpointRestoreRecovery(readerStore.load(safeOperationId));
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Small dependency-injected adapter for future CLI/IDE command wiring.
|
|
866
|
+
* Constructing it performs no filesystem access.
|
|
867
|
+
*/
|
|
868
|
+
export function createCheckpointRestoreRecoveryReader({ store } = {}) {
|
|
869
|
+
const readerStore = assertStore(store);
|
|
870
|
+
return Object.freeze({
|
|
871
|
+
list(options = {}) {
|
|
872
|
+
return listCheckpointRestoreRecoveries({
|
|
873
|
+
...options,
|
|
874
|
+
store: readerStore,
|
|
875
|
+
});
|
|
876
|
+
},
|
|
877
|
+
show(operationId) {
|
|
878
|
+
return showCheckpointRestoreRecovery({
|
|
879
|
+
store: readerStore,
|
|
880
|
+
operationId,
|
|
881
|
+
});
|
|
882
|
+
},
|
|
883
|
+
});
|
|
884
|
+
}
|