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
|
@@ -16,6 +16,10 @@
|
|
|
16
16
|
|
|
17
17
|
import { emitHooksV2Event } from "../hooks-v2-producers.js";
|
|
18
18
|
|
|
19
|
+
function leaseFencingToken(lease) {
|
|
20
|
+
return lease?.fencingToken ?? lease?.leaseId ?? null;
|
|
21
|
+
}
|
|
22
|
+
|
|
19
23
|
export class TeamRunner {
|
|
20
24
|
/**
|
|
21
25
|
* @param {TaskLeaseRegistry} registry
|
|
@@ -42,6 +46,10 @@ export class TeamRunner {
|
|
|
42
46
|
// Team-wide token/USD/time/task budget (null → unbounded). Consulted before
|
|
43
47
|
// every claim; folded after every settled task.
|
|
44
48
|
this.budget = opts.budget || null;
|
|
49
|
+
// Optional process/session-wide authority shared with non-team sub-agents,
|
|
50
|
+
// tools and background work. TeamBudget remains the team-specific pricing
|
|
51
|
+
// and reservation facade; this budget owns global concurrency + cascade.
|
|
52
|
+
this.sessionBudget = opts.sessionBudget || null;
|
|
45
53
|
this.budgetForTask =
|
|
46
54
|
typeof opts.budgetForTask === "function" ? opts.budgetForTask : null;
|
|
47
55
|
// Directed/broadcast messaging between teammates (null → disabled).
|
|
@@ -68,6 +76,11 @@ export class TeamRunner {
|
|
|
68
76
|
typeof opts.beforeTask === "function" ? opts.beforeTask : null;
|
|
69
77
|
this.afterTask =
|
|
70
78
|
typeof opts.afterTask === "function" ? opts.afterTask : null;
|
|
79
|
+
// A lease that expires and is reacquired receives a new fencing identity.
|
|
80
|
+
// Persist that identity synchronously before the executor can settle under
|
|
81
|
+
// it. Ordinary renewals keep the same identity and do not call this hook.
|
|
82
|
+
this.onLeaseChanged =
|
|
83
|
+
typeof opts.onLeaseChanged === "function" ? opts.onLeaseChanged : null;
|
|
71
84
|
this._executions = 0;
|
|
72
85
|
this._reservedExecutions = 0;
|
|
73
86
|
this._inFlight = 0;
|
|
@@ -78,6 +91,7 @@ export class TeamRunner {
|
|
|
78
91
|
this._activeKeys = new Set();
|
|
79
92
|
this._members = new Map(); // holder → lifecycle record
|
|
80
93
|
this._budgetStopped = false;
|
|
94
|
+
this._registryBudgetReason = null;
|
|
81
95
|
this._fatalError = null;
|
|
82
96
|
// Idle workers wait on graph progress instead of polling the full graph
|
|
83
97
|
// through setTimeout(0). This matters once a team has many workers but only
|
|
@@ -85,6 +99,7 @@ export class TeamRunner {
|
|
|
85
99
|
this._progressWaiters = new Set();
|
|
86
100
|
this._workerCount = 1;
|
|
87
101
|
this._claimControllers = new Set();
|
|
102
|
+
this._claimsByKey = new Map();
|
|
88
103
|
this._wallTimer = null;
|
|
89
104
|
}
|
|
90
105
|
|
|
@@ -152,6 +167,121 @@ export class TeamRunner {
|
|
|
152
167
|
}
|
|
153
168
|
}
|
|
154
169
|
|
|
170
|
+
/** Snapshot of local in-flight claims for an IDE/operator control surface. */
|
|
171
|
+
activeClaims() {
|
|
172
|
+
return Array.from(this._claimsByKey.values()).map((claim) => ({
|
|
173
|
+
key: claim.key,
|
|
174
|
+
holder: claim.holder,
|
|
175
|
+
leaseId: claim.leaseId,
|
|
176
|
+
fencingToken: claim.fencingToken,
|
|
177
|
+
interrupted: !!claim.interruption,
|
|
178
|
+
interruption: claim.interruption ? { ...claim.interruption } : null,
|
|
179
|
+
}));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Request human takeover of an executing task.
|
|
184
|
+
*
|
|
185
|
+
* Aborting the executor cannot prove whether an external side effect landed,
|
|
186
|
+
* so the task always settles fail-closed into adjudication rather than being
|
|
187
|
+
* silently retried. A durable control log supplies requestId/evidenceDigest
|
|
188
|
+
* in production and must bind the exact active holder/lease/fencing identity;
|
|
189
|
+
* keeping this method synchronous makes it safe to call from a file-control
|
|
190
|
+
* watcher or an embedded IDE host.
|
|
191
|
+
*/
|
|
192
|
+
interruptTask(
|
|
193
|
+
key,
|
|
194
|
+
{
|
|
195
|
+
holder = null,
|
|
196
|
+
leaseId = null,
|
|
197
|
+
fencingToken = null,
|
|
198
|
+
reason = "human takeover requested",
|
|
199
|
+
actor = "human",
|
|
200
|
+
requestId = null,
|
|
201
|
+
evidenceDigest = null,
|
|
202
|
+
} = {},
|
|
203
|
+
) {
|
|
204
|
+
const claim = this._claimsByKey.get(key);
|
|
205
|
+
if (!claim) return { ok: false, reason: "not_active" };
|
|
206
|
+
if (
|
|
207
|
+
holder !== claim.holder ||
|
|
208
|
+
leaseId !== claim.leaseId ||
|
|
209
|
+
fencingToken !== claim.fencingToken
|
|
210
|
+
) {
|
|
211
|
+
return { ok: false, reason: "stale_attempt" };
|
|
212
|
+
}
|
|
213
|
+
if (claim.interruption) {
|
|
214
|
+
if (
|
|
215
|
+
requestId &&
|
|
216
|
+
claim.interruption.requestId &&
|
|
217
|
+
requestId !== claim.interruption.requestId
|
|
218
|
+
) {
|
|
219
|
+
return { ok: false, reason: "already_interrupted" };
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
ok: true,
|
|
223
|
+
idempotent: true,
|
|
224
|
+
interruption: { ...claim.interruption },
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
claim.interruption = {
|
|
228
|
+
holder: claim.holder,
|
|
229
|
+
leaseId: claim.leaseId,
|
|
230
|
+
fencingToken: claim.fencingToken,
|
|
231
|
+
requestId: requestId || null,
|
|
232
|
+
actor: actor ? String(actor) : "human",
|
|
233
|
+
reason: String(reason || "human takeover requested"),
|
|
234
|
+
evidenceDigest: evidenceDigest || null,
|
|
235
|
+
requestedAt: this._now(),
|
|
236
|
+
};
|
|
237
|
+
const error = this._interruptionError(claim);
|
|
238
|
+
try {
|
|
239
|
+
claim.abortController.abort(error);
|
|
240
|
+
} catch {
|
|
241
|
+
/* settlement remains fenced by the task lease */
|
|
242
|
+
}
|
|
243
|
+
this._emit("task:interrupt-requested", {
|
|
244
|
+
key,
|
|
245
|
+
holder: claim.holder,
|
|
246
|
+
leaseId: claim.leaseId,
|
|
247
|
+
fencingToken: claim.fencingToken,
|
|
248
|
+
requestId: claim.interruption.requestId,
|
|
249
|
+
actor: claim.interruption.actor,
|
|
250
|
+
reason: claim.interruption.reason,
|
|
251
|
+
});
|
|
252
|
+
this._signalProgress();
|
|
253
|
+
return { ok: true, interruption: { ...claim.interruption } };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Fail the coordinator closed (for example when its durable control log is
|
|
258
|
+
* corrupt or rolled back). Active executors are aborted and settle as
|
|
259
|
+
* adjudication-required because their external outcome may be unknown.
|
|
260
|
+
*/
|
|
261
|
+
abortRun(error, { requireAdjudication = true } = {}) {
|
|
262
|
+
const failure =
|
|
263
|
+
error instanceof Error ? error : new Error(String(error || "team abort"));
|
|
264
|
+
if (requireAdjudication) {
|
|
265
|
+
failure.retryable = false;
|
|
266
|
+
failure.adjudication = {
|
|
267
|
+
code: failure.code || "TEAM_RUN_ABORTED_ADJUDICATION_REQUIRED",
|
|
268
|
+
reason: failure.message,
|
|
269
|
+
evidenceDigest: null,
|
|
270
|
+
requestedAt: this._now(),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
this._setFatal(failure, { phase: "external-control" });
|
|
274
|
+
for (const claim of this._claimsByKey.values()) {
|
|
275
|
+
claim.coordinatorAbort = failure;
|
|
276
|
+
try {
|
|
277
|
+
claim.abortController.abort(failure);
|
|
278
|
+
} catch {
|
|
279
|
+
/* settlement remains fenced by the task lease */
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
return { ok: true, activeClaims: this._claimsByKey.size };
|
|
283
|
+
}
|
|
284
|
+
|
|
155
285
|
/**
|
|
156
286
|
* Run the graph to completion (all tasks terminal) or until no teammate can
|
|
157
287
|
* make progress (everything remaining is blocked/leased). Returns a summary.
|
|
@@ -185,7 +315,9 @@ export class TeamRunner {
|
|
|
185
315
|
}
|
|
186
316
|
for (const controller of this._claimControllers) {
|
|
187
317
|
try {
|
|
188
|
-
|
|
318
|
+
const error = new Error("Team wall-clock budget exhausted");
|
|
319
|
+
error.code = "TEAM_WALL_BUDGET_EXHAUSTED";
|
|
320
|
+
controller.abort(error);
|
|
189
321
|
} catch {
|
|
190
322
|
/* every settlement remains fenced by its lease id */
|
|
191
323
|
}
|
|
@@ -210,6 +342,7 @@ export class TeamRunner {
|
|
|
210
342
|
armWallTimer();
|
|
211
343
|
}
|
|
212
344
|
}
|
|
345
|
+
this.sessionBudget?.start?.();
|
|
213
346
|
const workers = [];
|
|
214
347
|
const workerCount = Math.min(
|
|
215
348
|
this.teammates,
|
|
@@ -244,7 +377,11 @@ export class TeamRunner {
|
|
|
244
377
|
requestedTeammates: this.teammates,
|
|
245
378
|
activeTeammates: workerCount,
|
|
246
379
|
budgetStopped: this._budgetStopped,
|
|
247
|
-
budgetReason:
|
|
380
|
+
budgetReason:
|
|
381
|
+
this.budget?.reason?.() ||
|
|
382
|
+
this.sessionBudget?.reason?.() ||
|
|
383
|
+
this._registryBudgetReason,
|
|
384
|
+
sessionBudgetStatus: this.sessionBudget?.status?.() || null,
|
|
248
385
|
members: this.members(),
|
|
249
386
|
messages: this.mailbox ? this.mailbox.size() : 0,
|
|
250
387
|
mailboxStatus: this.mailbox?.status?.() || null,
|
|
@@ -265,6 +402,15 @@ export class TeamRunner {
|
|
|
265
402
|
this._setState(holder, "shutdown", { reason: "fatal-error" });
|
|
266
403
|
return;
|
|
267
404
|
}
|
|
405
|
+
if (this.sessionBudget?.signal?.aborted) {
|
|
406
|
+
const reason = this.sessionBudget.reason?.() || "session-aborted";
|
|
407
|
+
if (!this._budgetStopped) {
|
|
408
|
+
this._budgetStopped = true;
|
|
409
|
+
this._emit("run:budget-exhausted", { reason });
|
|
410
|
+
}
|
|
411
|
+
this._setState(holder, "shutdown", { reason });
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
268
414
|
if (this._executions + this._reservedExecutions >= this.maxTasks) {
|
|
269
415
|
this._emit("run:budget-exhausted", { maxTasks: this.maxTasks });
|
|
270
416
|
this._setState(holder, "shutdown", { reason: "max-tasks" });
|
|
@@ -319,16 +465,26 @@ export class TeamRunner {
|
|
|
319
465
|
}
|
|
320
466
|
const acq = this.registry.acquire(key, { holder, ttlMs: this.ttlMs });
|
|
321
467
|
if (!acq.ok) {
|
|
468
|
+
if (
|
|
469
|
+
["max-tasks", "max-tokens", "max-usd", "max-wall-ms"].includes(
|
|
470
|
+
acq.reason,
|
|
471
|
+
)
|
|
472
|
+
) {
|
|
473
|
+
this._budgetStopped = true;
|
|
474
|
+
this._registryBudgetReason = acq.reason;
|
|
475
|
+
this._emit("run:budget-exhausted", { reason: acq.reason });
|
|
476
|
+
this._setState(holder, "shutdown", { reason: acq.reason });
|
|
477
|
+
this._signalProgress();
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
322
480
|
// Lost the race to a peer (or it just got blocked) — try another.
|
|
323
481
|
this._setState(holder, "idle");
|
|
324
482
|
await this._tick();
|
|
325
483
|
continue;
|
|
326
484
|
}
|
|
327
|
-
const budgetReservation =
|
|
328
|
-
|
|
329
|
-
this.registry.getTask(key),
|
|
330
|
-
acq.lease,
|
|
331
|
-
);
|
|
485
|
+
const budgetReservation = acq.budgetReservation
|
|
486
|
+
? { ok: true, ...acq.budgetReservation }
|
|
487
|
+
: this._reserveTaskBudget(key, this.registry.getTask(key), acq.lease);
|
|
332
488
|
if (!budgetReservation.ok) {
|
|
333
489
|
this.registry.release(key, {
|
|
334
490
|
holder,
|
|
@@ -350,8 +506,74 @@ export class TeamRunner {
|
|
|
350
506
|
});
|
|
351
507
|
return;
|
|
352
508
|
}
|
|
509
|
+
let sessionWork;
|
|
510
|
+
try {
|
|
511
|
+
sessionWork = this._reserveSessionWork(key, acq.lease);
|
|
512
|
+
} catch (error) {
|
|
513
|
+
this.registry.release(key, {
|
|
514
|
+
holder,
|
|
515
|
+
leaseId: acq.lease.leaseId,
|
|
516
|
+
});
|
|
517
|
+
if (budgetReservation.id) {
|
|
518
|
+
this.budget?.releaseReservation?.(budgetReservation.id);
|
|
519
|
+
}
|
|
520
|
+
this._setFatal(error, {
|
|
521
|
+
phase: "session-budget-acquire",
|
|
522
|
+
key,
|
|
523
|
+
holder,
|
|
524
|
+
});
|
|
525
|
+
this._setState(holder, "shutdown", { reason: "fatal-error" });
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
if (!sessionWork.ok) {
|
|
529
|
+
this.registry.release(key, {
|
|
530
|
+
holder,
|
|
531
|
+
leaseId: acq.lease.leaseId,
|
|
532
|
+
});
|
|
533
|
+
if (budgetReservation.id) {
|
|
534
|
+
this.budget?.releaseReservation?.(budgetReservation.id);
|
|
535
|
+
}
|
|
536
|
+
if (sessionWork.retryable) {
|
|
537
|
+
this._setState(holder, "idle");
|
|
538
|
+
// The occupied global slot may belong to a background task outside
|
|
539
|
+
// this runner, so no TeamRunner progress event is guaranteed.
|
|
540
|
+
await this._tick();
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
if (!this._budgetStopped) {
|
|
544
|
+
this._budgetStopped = true;
|
|
545
|
+
this._emit("run:budget-exhausted", {
|
|
546
|
+
reason: sessionWork.reason,
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
this._setState(holder, "shutdown", {
|
|
550
|
+
reason: sessionWork.reason,
|
|
551
|
+
});
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
353
554
|
this._reservedExecutions++;
|
|
354
|
-
|
|
555
|
+
let claim;
|
|
556
|
+
try {
|
|
557
|
+
claim = this._beginClaim(
|
|
558
|
+
holder,
|
|
559
|
+
key,
|
|
560
|
+
acq.lease,
|
|
561
|
+
budgetReservation,
|
|
562
|
+
sessionWork,
|
|
563
|
+
);
|
|
564
|
+
} catch (error) {
|
|
565
|
+
this._reservedExecutions = Math.max(0, this._reservedExecutions - 1);
|
|
566
|
+
this.registry.release(key, {
|
|
567
|
+
holder,
|
|
568
|
+
leaseId: acq.lease.leaseId,
|
|
569
|
+
});
|
|
570
|
+
if (budgetReservation.id) {
|
|
571
|
+
this.budget?.releaseReservation?.(budgetReservation.id);
|
|
572
|
+
}
|
|
573
|
+
this._setFatal(error, { phase: "session-budget-bind", key, holder });
|
|
574
|
+
this._setState(holder, "shutdown", { reason: "fatal-error" });
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
355
577
|
if (!this._acquireScope(holder, key)) {
|
|
356
578
|
this._abandonClaim(holder, key, claim);
|
|
357
579
|
if (this._fatalError) {
|
|
@@ -378,6 +600,33 @@ export class TeamRunner {
|
|
|
378
600
|
this._setState(holder, "shutdown", { reason: "fatal-error" });
|
|
379
601
|
return;
|
|
380
602
|
}
|
|
603
|
+
// `beforeTask` may persist a durable claim slowly enough to cross the
|
|
604
|
+
// wall-clock deadline. The timer's AbortSignal is advisory: this is the
|
|
605
|
+
// last authoritative fence before handing control to the executor.
|
|
606
|
+
// Preserve an explicit human interruption so `_execute` can settle it
|
|
607
|
+
// fail-closed for adjudication instead of silently abandoning it.
|
|
608
|
+
const preparedBudgetReason = this.budget?.reason?.();
|
|
609
|
+
const preparedSessionReason = this.sessionBudget?.signal?.aborted
|
|
610
|
+
? this.sessionBudget.reason?.() || "session-aborted"
|
|
611
|
+
: null;
|
|
612
|
+
if (
|
|
613
|
+
!claim.interruption &&
|
|
614
|
+
!claim.coordinatorAbort &&
|
|
615
|
+
(preparedBudgetReason === "max-wall-ms" || preparedSessionReason)
|
|
616
|
+
) {
|
|
617
|
+
const reason = preparedSessionReason || preparedBudgetReason;
|
|
618
|
+
if (!this._budgetStopped) {
|
|
619
|
+
this._budgetStopped = true;
|
|
620
|
+
this._emit("run:budget-exhausted", {
|
|
621
|
+
reason,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
this._abandonClaim(holder, key, claim);
|
|
625
|
+
this._setState(holder, "shutdown", {
|
|
626
|
+
reason,
|
|
627
|
+
});
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
381
630
|
await this._execute(holder, key, claim);
|
|
382
631
|
}
|
|
383
632
|
}
|
|
@@ -439,23 +688,70 @@ export class TeamRunner {
|
|
|
439
688
|
};
|
|
440
689
|
}
|
|
441
690
|
|
|
442
|
-
|
|
691
|
+
_reserveSessionWork(key, lease) {
|
|
692
|
+
if (!this.sessionBudget?.acquireWork) return { ok: true, release: null };
|
|
693
|
+
return this.sessionBudget.acquireWork({
|
|
694
|
+
id: `team-task:${lease?.leaseId || key}`,
|
|
695
|
+
kind: "team-task",
|
|
696
|
+
depth: 1,
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
_beginClaim(
|
|
701
|
+
holder,
|
|
702
|
+
key,
|
|
703
|
+
lease,
|
|
704
|
+
budgetReservation = null,
|
|
705
|
+
sessionWork = null,
|
|
706
|
+
) {
|
|
443
707
|
const claim = {
|
|
444
708
|
holder,
|
|
445
709
|
key,
|
|
446
710
|
lease,
|
|
447
711
|
leaseId: lease?.leaseId,
|
|
712
|
+
fencingToken: leaseFencingToken(lease),
|
|
448
713
|
heartbeat: null,
|
|
449
714
|
lost: false,
|
|
450
715
|
abortController: new AbortController(),
|
|
451
716
|
budgetReservation,
|
|
452
717
|
budgetSettled: false,
|
|
718
|
+
sessionWork,
|
|
719
|
+
sessionBudgetSettled: false,
|
|
720
|
+
sessionBudgetUsageHandledByExecutor: false,
|
|
721
|
+
sessionBudgetView: null,
|
|
722
|
+
unregisterSessionAbortable: null,
|
|
723
|
+
interruption: null,
|
|
724
|
+
coordinatorAbort: null,
|
|
453
725
|
};
|
|
454
726
|
// Fence the task immediately after acquire, before any async durable hook.
|
|
455
727
|
// Otherwise a slow beforeTask can outlive the TTL and a peer can run the
|
|
456
728
|
// same side effect concurrently.
|
|
457
729
|
this._activeKeys.add(key);
|
|
458
730
|
this._claimControllers.add(claim.abortController);
|
|
731
|
+
this._claimsByKey.set(key, claim);
|
|
732
|
+
if (this.sessionBudget?.registerAbortable && sessionWork?.id) {
|
|
733
|
+
try {
|
|
734
|
+
claim.unregisterSessionAbortable = this.sessionBudget.registerAbortable(
|
|
735
|
+
`team-claim:${sessionWork.id}`,
|
|
736
|
+
(reason) => {
|
|
737
|
+
if (!claim.abortController.signal.aborted) {
|
|
738
|
+
claim.abortController.abort(reason);
|
|
739
|
+
}
|
|
740
|
+
},
|
|
741
|
+
);
|
|
742
|
+
} catch (error) {
|
|
743
|
+
this._activeKeys.delete(key);
|
|
744
|
+
this._claimControllers.delete(claim.abortController);
|
|
745
|
+
this._claimsByKey.delete(key);
|
|
746
|
+
try {
|
|
747
|
+
sessionWork.release?.();
|
|
748
|
+
} catch {
|
|
749
|
+
// Preserve the registration failure as the authoritative cause. A
|
|
750
|
+
// conforming SessionResourceBudget release is idempotent/nonthrowing.
|
|
751
|
+
}
|
|
752
|
+
throw error;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
459
755
|
const effectiveTtl =
|
|
460
756
|
this.ttlMs > 0 ? this.ttlMs : this.registry.defaultTtlMs || 60000;
|
|
461
757
|
const every = Math.max(
|
|
@@ -470,6 +766,71 @@ export class TeamRunner {
|
|
|
470
766
|
return claim;
|
|
471
767
|
}
|
|
472
768
|
|
|
769
|
+
_applyRenewedLease(claim, lease) {
|
|
770
|
+
const previousLease = claim.lease;
|
|
771
|
+
const previousLeaseId = claim.leaseId;
|
|
772
|
+
const previousFencingToken = claim.fencingToken;
|
|
773
|
+
claim.lease = lease;
|
|
774
|
+
claim.leaseId = lease?.leaseId;
|
|
775
|
+
claim.fencingToken = leaseFencingToken(lease);
|
|
776
|
+
const identityChanged =
|
|
777
|
+
claim.leaseId !== previousLeaseId ||
|
|
778
|
+
claim.fencingToken !== previousFencingToken;
|
|
779
|
+
if (!identityChanged || !this.onLeaseChanged) {
|
|
780
|
+
return { ok: true, identityChanged };
|
|
781
|
+
}
|
|
782
|
+
try {
|
|
783
|
+
const callbackResult = this.onLeaseChanged({
|
|
784
|
+
key: claim.key,
|
|
785
|
+
holder: claim.holder,
|
|
786
|
+
previousLease: previousLease ? { ...previousLease } : null,
|
|
787
|
+
lease: lease ? { ...lease } : null,
|
|
788
|
+
previousLeaseId,
|
|
789
|
+
leaseId: claim.leaseId,
|
|
790
|
+
previousFencingToken,
|
|
791
|
+
fencingToken: claim.fencingToken,
|
|
792
|
+
});
|
|
793
|
+
if (
|
|
794
|
+
callbackResult &&
|
|
795
|
+
(typeof callbackResult === "object" ||
|
|
796
|
+
typeof callbackResult === "function") &&
|
|
797
|
+
typeof callbackResult.then === "function"
|
|
798
|
+
) {
|
|
799
|
+
Promise.resolve(callbackResult).catch(() => {});
|
|
800
|
+
throw new Error("onLeaseChanged must be synchronous");
|
|
801
|
+
}
|
|
802
|
+
return { ok: true, identityChanged: true };
|
|
803
|
+
} catch (error) {
|
|
804
|
+
const cause =
|
|
805
|
+
error instanceof Error
|
|
806
|
+
? error
|
|
807
|
+
: new Error(String(error || "lease identity persistence failed"));
|
|
808
|
+
const failure = new Error(cause.message, { cause });
|
|
809
|
+
failure.code = "TEAM_LEASE_CHANGE_PERSIST_FAILED";
|
|
810
|
+
failure.retryable = false;
|
|
811
|
+
failure.adjudication = failure.adjudication || {
|
|
812
|
+
code: failure.code,
|
|
813
|
+
reason: failure.message,
|
|
814
|
+
evidenceDigest: null,
|
|
815
|
+
requestedAt: this._now(),
|
|
816
|
+
holder: claim.holder,
|
|
817
|
+
leaseId: claim.leaseId,
|
|
818
|
+
fencingToken: claim.fencingToken,
|
|
819
|
+
};
|
|
820
|
+
claim.coordinatorAbort = failure;
|
|
821
|
+
this._setFatal(failure, {
|
|
822
|
+
phase: "lease-change",
|
|
823
|
+
key: claim.key,
|
|
824
|
+
holder: claim.holder,
|
|
825
|
+
});
|
|
826
|
+
return {
|
|
827
|
+
ok: false,
|
|
828
|
+
reason: "lease_change_persist_failed",
|
|
829
|
+
error: failure,
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
473
834
|
_renewClaim(claim) {
|
|
474
835
|
if (!claim || claim.lost) {
|
|
475
836
|
return { ok: false, reason: "lease_lost" };
|
|
@@ -489,11 +850,12 @@ export class TeamRunner {
|
|
|
489
850
|
ttlMs: this.ttlMs,
|
|
490
851
|
});
|
|
491
852
|
if (result?.ok) {
|
|
492
|
-
|
|
493
|
-
|
|
853
|
+
const applied = this._applyRenewedLease(claim, result.lease);
|
|
854
|
+
if (!applied.ok) result = applied;
|
|
494
855
|
}
|
|
495
856
|
} else if (result?.ok) {
|
|
496
|
-
|
|
857
|
+
const applied = this._applyRenewedLease(claim, result.lease);
|
|
858
|
+
if (!applied.ok) result = applied;
|
|
497
859
|
}
|
|
498
860
|
} catch {
|
|
499
861
|
result = { ok: false, reason: "renew_failed" };
|
|
@@ -502,7 +864,7 @@ export class TeamRunner {
|
|
|
502
864
|
claim.lost = true;
|
|
503
865
|
try {
|
|
504
866
|
claim.abortController.abort(
|
|
505
|
-
new Error(`Lease for task "${claim.key}" was lost`),
|
|
867
|
+
result?.error || new Error(`Lease for task "${claim.key}" was lost`),
|
|
506
868
|
);
|
|
507
869
|
} catch {
|
|
508
870
|
/* the fencing token still prevents stale settlement */
|
|
@@ -517,6 +879,112 @@ export class TeamRunner {
|
|
|
517
879
|
if (claim.heartbeat) clearInterval(claim.heartbeat);
|
|
518
880
|
this._activeKeys.delete(claim.key);
|
|
519
881
|
this._claimControllers.delete(claim.abortController);
|
|
882
|
+
if (this._claimsByKey.get(claim.key) === claim) {
|
|
883
|
+
this._claimsByKey.delete(claim.key);
|
|
884
|
+
}
|
|
885
|
+
try {
|
|
886
|
+
claim.unregisterSessionAbortable?.();
|
|
887
|
+
} catch {
|
|
888
|
+
// The session budget may already have delivered and cleared the callback.
|
|
889
|
+
}
|
|
890
|
+
claim.unregisterSessionAbortable = null;
|
|
891
|
+
try {
|
|
892
|
+
claim.sessionWork?.release?.();
|
|
893
|
+
} catch {
|
|
894
|
+
// Session work leases are idempotent.
|
|
895
|
+
}
|
|
896
|
+
claim.sessionWork = null;
|
|
897
|
+
claim.sessionBudgetView = null;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
_sessionBudgetForClaim(claim) {
|
|
901
|
+
if (!this.sessionBudget || !claim) return this.sessionBudget;
|
|
902
|
+
if (claim.sessionBudgetView) return claim.sessionBudgetView;
|
|
903
|
+
const authority = this.sessionBudget;
|
|
904
|
+
const methods = new Map();
|
|
905
|
+
claim.sessionBudgetView = new Proxy(authority, {
|
|
906
|
+
get(target, property) {
|
|
907
|
+
const value = Reflect.get(target, property, target);
|
|
908
|
+
if (typeof value !== "function") return value;
|
|
909
|
+
if (methods.has(property)) return methods.get(property);
|
|
910
|
+
const method =
|
|
911
|
+
property === "recordUsage"
|
|
912
|
+
? (...args) => {
|
|
913
|
+
// Usage charged through the inherited authority is already in
|
|
914
|
+
// the global ledger. Remember that ownership so the task's
|
|
915
|
+
// returned aggregate is not charged a second time.
|
|
916
|
+
claim.sessionBudgetUsageHandledByExecutor = true;
|
|
917
|
+
return value.apply(target, args);
|
|
918
|
+
}
|
|
919
|
+
: value.bind(target);
|
|
920
|
+
methods.set(property, method);
|
|
921
|
+
return method;
|
|
922
|
+
},
|
|
923
|
+
set(target, property, value) {
|
|
924
|
+
return Reflect.set(target, property, value, target);
|
|
925
|
+
},
|
|
926
|
+
});
|
|
927
|
+
return claim.sessionBudgetView;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
_recordSessionUsage(claim, source) {
|
|
931
|
+
if (!this.sessionBudget || claim.sessionBudgetSettled) return;
|
|
932
|
+
claim.sessionBudgetSettled = true;
|
|
933
|
+
if (claim.sessionBudgetUsageHandledByExecutor) return;
|
|
934
|
+
this.sessionBudget.recordUsage({
|
|
935
|
+
usage: source?.usage || null,
|
|
936
|
+
usageRecords: source?.usageRecords || null,
|
|
937
|
+
provider: source?.provider,
|
|
938
|
+
model: source?.model,
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
_sessionBudgetFailure(executionResult = null) {
|
|
943
|
+
const sharedReason = this.sessionBudget?.signal?.reason;
|
|
944
|
+
// Never attach per-task usage to the shared AbortSignal reason: every
|
|
945
|
+
// sibling observes that same Error object and would then re-record the
|
|
946
|
+
// triggering task's usage as its own failure.
|
|
947
|
+
const failure = new Error(
|
|
948
|
+
sharedReason?.message ||
|
|
949
|
+
`Session budget exhausted: ${this.sessionBudget?.reason?.() || "session-aborted"}`,
|
|
950
|
+
sharedReason instanceof Error ? { cause: sharedReason } : undefined,
|
|
951
|
+
);
|
|
952
|
+
failure.code = sharedReason?.code || "ERR_SESSION_RESOURCE_BUDGET";
|
|
953
|
+
failure.budgetReason =
|
|
954
|
+
sharedReason?.budgetReason || this.sessionBudget?.reason?.();
|
|
955
|
+
failure.retryable = false;
|
|
956
|
+
if (executionResult && typeof executionResult === "object") {
|
|
957
|
+
failure.usage = executionResult.usage || null;
|
|
958
|
+
failure.usageRecords = executionResult.usageRecords || null;
|
|
959
|
+
failure.provider = executionResult.provider;
|
|
960
|
+
failure.model = executionResult.model;
|
|
961
|
+
}
|
|
962
|
+
return failure;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
_interruptionError(claim, executionResult = null) {
|
|
966
|
+
const interruption = claim?.interruption || {};
|
|
967
|
+
const error = new Error(interruption.reason || "human takeover requested");
|
|
968
|
+
error.code = "TEAM_TASK_HUMAN_INTERRUPTED";
|
|
969
|
+
error.retryable = false;
|
|
970
|
+
error.adjudication = {
|
|
971
|
+
code: error.code,
|
|
972
|
+
reason: error.message,
|
|
973
|
+
evidenceDigest: interruption.evidenceDigest || null,
|
|
974
|
+
requestedAt: interruption.requestedAt || this._now(),
|
|
975
|
+
requestId: interruption.requestId || null,
|
|
976
|
+
actor: interruption.actor || "human",
|
|
977
|
+
holder: interruption.holder || claim?.holder || null,
|
|
978
|
+
leaseId: interruption.leaseId || claim?.leaseId || null,
|
|
979
|
+
fencingToken: interruption.fencingToken ?? claim?.fencingToken ?? null,
|
|
980
|
+
};
|
|
981
|
+
if (executionResult && typeof executionResult === "object") {
|
|
982
|
+
error.usage = executionResult.usage || null;
|
|
983
|
+
error.usageRecords = executionResult.usageRecords || null;
|
|
984
|
+
error.provider = executionResult.provider;
|
|
985
|
+
error.model = executionResult.model;
|
|
986
|
+
}
|
|
987
|
+
return error;
|
|
520
988
|
}
|
|
521
989
|
|
|
522
990
|
_abandonClaim(holder, key, claim) {
|
|
@@ -683,6 +1151,18 @@ export class TeamRunner {
|
|
|
683
1151
|
})
|
|
684
1152
|
: null;
|
|
685
1153
|
try {
|
|
1154
|
+
if (claim.interruption) {
|
|
1155
|
+
throw this._interruptionError(claim);
|
|
1156
|
+
}
|
|
1157
|
+
if (claim.coordinatorAbort) {
|
|
1158
|
+
throw claim.coordinatorAbort;
|
|
1159
|
+
}
|
|
1160
|
+
// Synchronous observers above (`onEvent`, mailbox, tracing) may abort the
|
|
1161
|
+
// shared authority after the worker's post-beforeTask check. This is the
|
|
1162
|
+
// final fail-closed fence immediately before executor side effects.
|
|
1163
|
+
if (this.sessionBudget?.signal?.aborted) {
|
|
1164
|
+
throw this._sessionBudgetFailure();
|
|
1165
|
+
}
|
|
686
1166
|
const result = await this.runTask({
|
|
687
1167
|
key,
|
|
688
1168
|
task,
|
|
@@ -693,8 +1173,40 @@ export class TeamRunner {
|
|
|
693
1173
|
mailbox: this.mailbox,
|
|
694
1174
|
budget: this.budget,
|
|
695
1175
|
budgetReservation: claim.budgetReservation,
|
|
1176
|
+
sessionBudget: this._sessionBudgetForClaim(claim),
|
|
696
1177
|
signal: claim.abortController.signal,
|
|
697
1178
|
});
|
|
1179
|
+
// The executor may ignore AbortSignal or finish concurrently with an IDE
|
|
1180
|
+
// takeover request. Never turn that race into an automatic success:
|
|
1181
|
+
// preserve usage, then fail closed for explicit adjudication.
|
|
1182
|
+
if (claim.interruption) {
|
|
1183
|
+
throw this._interruptionError(claim, result);
|
|
1184
|
+
}
|
|
1185
|
+
if (claim.coordinatorAbort) {
|
|
1186
|
+
throw claim.coordinatorAbort;
|
|
1187
|
+
}
|
|
1188
|
+
this._recordSessionUsage(claim, result);
|
|
1189
|
+
if (this.sessionBudget?.signal?.aborted) {
|
|
1190
|
+
throw this._sessionBudgetFailure(result);
|
|
1191
|
+
}
|
|
1192
|
+
// Executors are allowed to return after observing (or even ignoring) an
|
|
1193
|
+
// aborted signal. Re-read the authoritative budget before recording or
|
|
1194
|
+
// completing so a late result can never become a phantom success.
|
|
1195
|
+
if (
|
|
1196
|
+
this.budget?.reason?.() === "max-wall-ms" ||
|
|
1197
|
+
claim.abortController.signal.reason?.code ===
|
|
1198
|
+
"TEAM_WALL_BUDGET_EXHAUSTED"
|
|
1199
|
+
) {
|
|
1200
|
+
if (!this._budgetStopped) {
|
|
1201
|
+
this._budgetStopped = true;
|
|
1202
|
+
this._emit("run:budget-exhausted", {
|
|
1203
|
+
reason: "max-wall-ms",
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
const error = new Error("Team wall-clock budget exhausted");
|
|
1207
|
+
error.code = "TEAM_WALL_BUDGET_EXHAUSTED";
|
|
1208
|
+
throw error;
|
|
1209
|
+
}
|
|
698
1210
|
// Fold usage/cost into the team budget regardless — the task DID execute
|
|
699
1211
|
// and consumed resources. `--exec` shell tasks carry no usage → only the
|
|
700
1212
|
// task-count / wall-clock dimensions move.
|
|
@@ -763,8 +1275,9 @@ export class TeamRunner {
|
|
|
763
1275
|
});
|
|
764
1276
|
}
|
|
765
1277
|
} catch (err) {
|
|
1278
|
+
const failure = claim.coordinatorAbort || err;
|
|
766
1279
|
if (span) {
|
|
767
|
-
span.recordException(
|
|
1280
|
+
span.recordException(failure, "task_failure");
|
|
768
1281
|
span.end({ status: "error" });
|
|
769
1282
|
}
|
|
770
1283
|
// A failed task still consumed a task-count slot (and any wall-clock) — fold
|
|
@@ -772,47 +1285,53 @@ export class TeamRunner {
|
|
|
772
1285
|
if (this.budget && !claim.budgetSettled) {
|
|
773
1286
|
this.budget.record(
|
|
774
1287
|
{
|
|
775
|
-
usage:
|
|
776
|
-
usageRecords:
|
|
777
|
-
provider:
|
|
778
|
-
model:
|
|
1288
|
+
usage: failure?.usage || null,
|
|
1289
|
+
usageRecords: failure?.usageRecords || null,
|
|
1290
|
+
provider: failure?.provider,
|
|
1291
|
+
model: failure?.model,
|
|
779
1292
|
reservationId: claim.budgetReservation?.id,
|
|
780
1293
|
},
|
|
781
1294
|
this._now(),
|
|
782
1295
|
);
|
|
783
1296
|
claim.budgetSettled = true;
|
|
784
1297
|
}
|
|
1298
|
+
this._recordSessionUsage(claim, failure);
|
|
785
1299
|
const outcome = this.registry.fail(key, {
|
|
786
1300
|
holder,
|
|
787
1301
|
leaseId: claim.leaseId,
|
|
788
|
-
error:
|
|
789
|
-
retryable:
|
|
1302
|
+
error: failure?.message || String(failure),
|
|
1303
|
+
retryable: failure?.retryable !== false,
|
|
1304
|
+
adjudication: failure?.adjudication || null,
|
|
790
1305
|
});
|
|
791
1306
|
if (outcome?.ok) {
|
|
792
1307
|
this._setState(holder, "failed-task", {
|
|
793
|
-
error:
|
|
1308
|
+
error: failure?.message || String(failure),
|
|
794
1309
|
});
|
|
795
1310
|
this._emit("task:failed", {
|
|
796
1311
|
key,
|
|
797
1312
|
holder,
|
|
798
|
-
error:
|
|
1313
|
+
error: failure?.message || String(failure),
|
|
799
1314
|
retry: outcome.retry === true,
|
|
800
1315
|
attempts: outcome.attempts,
|
|
1316
|
+
interrupted: failure?.code === "TEAM_TASK_HUMAN_INTERRUPTED",
|
|
1317
|
+
requestId: failure?.adjudication?.requestId || null,
|
|
801
1318
|
});
|
|
802
1319
|
await this._notifySettlement({
|
|
803
1320
|
key,
|
|
804
1321
|
holder,
|
|
805
1322
|
status: outcome.retry === true ? "pending" : "failed",
|
|
806
|
-
error:
|
|
1323
|
+
error: failure?.message || String(failure),
|
|
807
1324
|
retry: outcome.retry === true,
|
|
808
1325
|
attempts: outcome.attempts,
|
|
1326
|
+
interrupted: failure?.code === "TEAM_TASK_HUMAN_INTERRUPTED",
|
|
1327
|
+
requestId: failure?.adjudication?.requestId || null,
|
|
809
1328
|
});
|
|
810
1329
|
} else {
|
|
811
1330
|
this._emit("task:failure-discarded", {
|
|
812
1331
|
key,
|
|
813
1332
|
holder,
|
|
814
1333
|
reason: outcome?.reason || "lease_lost",
|
|
815
|
-
error:
|
|
1334
|
+
error: failure?.message || String(failure),
|
|
816
1335
|
ms: this._now() - startedAt,
|
|
817
1336
|
});
|
|
818
1337
|
await this._notifySettlement({
|