chainlesschain 0.163.6 → 0.163.7
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/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-DDIUofA8.js → AIOps-axqQfwv8.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Bm-5xYRn.js → ActionButton-DV-Ro0By.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D5UH4ljI.js → Analytics-Bt72WEVu.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-D_ifjOOP.js → AppLayout-BtepG55E.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BY1mXdC7.js → Artifacts-B7KaJ7S_.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-Bujr4Ml3.js → Audit-FNFaUg7A.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-sioKSTcC.js → BackgroundAgents-DFb6J2wQ.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DDOAK8RK.js → Backup-CC7YBhyj.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CtCsVVke.js → BaseInput-RkgTNVtj.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DpNj0vnd.js → Chat-hHEmGZy-.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZta3Ftr.js → ChatBubbleRenderer-CAP9YhHv.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DoHVNSXq.js → Checkbox-z5wXOQP1.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DlVl7Qmv.js → Codegen-DVaDJnxy.js} +1 -1
- package/src/assets/web-panel/assets/{Col-GIqoPYty.js → Col-CJmaRDR5.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CIAPEVji.js → Community-DF29_2bI.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BN7JiI_h.js → Compact-DtkQkBzn.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CqUWCM9B.js → Compliance-xoHDxp7I.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-A4iPp7A4.js → Cowork-BUm-R7ht.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-B2zeXXWb.js → Cron-Cgl14ZkB.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BR2xmWr8.js → Crosschain-BNcbmoqh.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BzFDjrIv.js → DID-Bwja0Zo9.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DKtDo3yA.js → Dashboard-Bk5XjEdJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-RNx43_YG.js → Dropdown-Ci36Oitq.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-SwMt4Rcy.js → EmailListRenderer--U04ZN4q.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-CsYebZ4X.js → FamilyGuardDashboard-B2gNPR2s.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BmRKvBTy.js → Federation-C4KghYn7.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CVxGTA-0.js → FormItemContext-QL7x_Q_0.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-x2iXpyB7.js → GenericCardRenderer-F3Ryltwm.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DfqbkiOP.js → Git-2HassK5k.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-RuHyyj5O.js → Governance-DoBIp7oe.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Bn7uZ7rI.js → Inference--W01QhZ-.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DlP7XefZ.js → KnowledgeGraph-DmvwqGpT.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BYNdOiCd.js → Logs-BBJ4yAel.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-aMtgN-R6.js → MarkdownRenderer-BLCZMzhJ.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-JQYmDqM8.js → Marketplace-D5lNngSI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Cyx4yZ-9.js → McpTools-CkEVOMKH.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-VDuGZTN2.js → Memory-B1Ow1xVE.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-_yKo97gi.js → MobileBridge-SgYbUfb6.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CXRXW3q7.js → MobileProjects-BWdOvQAj.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-acTGtfLH.js → Mtc-DcTXSSma.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-ClpjXfkY.js → MtcAudit-Dt3WG4oj.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-_6Tn3o96.js → Multisig-B9B38UZx.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CK7pbZzP.js → NLProgramming-B0S4GGvG.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Czy6V_P8.js → Notes-DZ5U58Ng.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-Cqx-UVv3.js → NotificationSettings-PjL5ZW34.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-C69WDxGy.js → OrderTableRenderer-DrAX2ESt.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-DFnA9vLQ.js → Organization-Cv1GYs-c.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-ReZkk2yT.js → Overflow-Bbkp_PL3.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DzjSI0aI.js → P2P-BD8QUgoZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DKTf5xIP.js → PdhVaultBrowser-BO-2PeaB.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-DhQ5klhR.js → Permissions-D_OPVa02.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CUL1iHrW.js → PersonalDataHub-mh-pEmaB.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-DU88iu4N.js → Pipeline-6JC2EDdb.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Bw-sYfyK.js → Privacy-CUshzUAG.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bq3Q5y0z.js → ProjectInit-Cs2Aalri.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-C8spzpho.js → ProjectSettings-1ak49tcj.js} +2 -2
- package/src/assets/web-panel/assets/Projects-BV4oApsm.js +1 -0
- package/src/assets/web-panel/assets/{Providers-Bf4eTP9W.js → Providers-CXXxvafH.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-Dme9BDU1.js → QrScannerModal-PTcDsF58.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CIXfv1rE.js → QuickAsk-CDwucrJw.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CIxvdeZ-.js → Recommend-CJlLVRXR.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C6k7MExI.js → RemoteSession-DlN-ETsO.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CISDz2bl.js → Reputation-DI23LR6m.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CdnDxXyf.js → Row-Cl7UQMrM.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-C-QpRHsl.js → RssFeed-CexHNfh8.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DBjaGzSn.js → Search-BneBWvRN.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CQKukOeE.js → Security-DX7Phgrp.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DZz86jWb.js → Services-BWXO8Mte.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-jb8RMK0d.js → Skeleton-DCyOjKPJ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CdY76fZG.js → Skills-CXqERsTB.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-C_CSiZX9.js → Sla-bhbrbz8E.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-3IPU0HBZ.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-qvimGO0O.js → SyncSettings-DBNTQLbM.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Dng5LPJC.js → Tasks-quP0bkN-.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Bwqq5Wll.js → Templates-BouWmgho.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DNWuwP7Z.js → Tenant-qv0D9s7z.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B-6Othpp.js → Terminal-BxvbE8BB.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DKpKZfzx.js → TimelineRenderer-D-IeLnJ2.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DzfGMd2J.js → Tokens-CFMKKyVG.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BXwUi74J.js → Trigger-L8as3UuJ.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BNzUq4ui.js → Trust-MxmA4VZG.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BYugxww4.js → UkeySign-C0VvJYRi.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DdauhtSJ.js → VideoEditing-Bf5QZj8N.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CSC9bCe_.js → Wallet-BIJ9riRz.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-Q8AN3bTO.js → WebAuthn-B8p9Mhkw.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-d-LBGCuA.js → WorkflowEditor-BVsuaPen.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BLVDCgsZ.js → chat-BfkjoKpV.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BZlPSEHl.js → colors-DeAlsWK8.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-IWseP6R6.js → compact-item-Cs97bz5j.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DnVRV3Ao.js → createContext-BqbG60LH.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DLQZA_Wn.js → hasIn-i_RY0b1X.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_N4-Gq9.js → index-0-agYlWL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DB0MJgF_.js → index-79V_zv1s.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOZJBTWZ.js → index-B-3tEpTc.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUq0c7gq.js → index-B-JVTrpr.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dy0R5ZED.js → index-B1CbOH1i.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bxp7uDD8.js → index-B5UkyA3c.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpVrK6fr.js → index-BESLFt4q.js} +1 -1
- package/src/assets/web-panel/assets/{index-CT9vVN-X.js → index-BOVkf1K3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DOoQpuQY.js → index-BYUVuwKt.js} +1 -1
- package/src/assets/web-panel/assets/{index-CINJQEj6.js → index-BcUXAB2s.js} +1 -1
- package/src/assets/web-panel/assets/{index-CarMTIyQ.js → index-BkBi5TmC.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5dgnilC.js → index-Bm7lLR4c.js} +1 -1
- package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +1 -0
- package/src/assets/web-panel/assets/{index-CbQNL0ue.js → index-BuLQobzW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpBaJ3TD.js → index-CE2VtTlp.js} +1 -1
- package/src/assets/web-panel/assets/{index-jWb70ZgZ.js → index-CED2PL_y.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEu2lMBy.js → index-CG3PRyAL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DocEhinm.js → index-CIG8fQ2_.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_LQodeJ.js → index-COdGA-8n.js} +1 -1
- package/src/assets/web-panel/assets/{index-DZpYeqrh.js → index-CeWoNHau.js} +1 -1
- package/src/assets/web-panel/assets/{index-gt8bNefW.js → index-Cf3WCLmy.js} +1 -1
- package/src/assets/web-panel/assets/{index-N_GoWZX4.js → index-CgsqdnRV.js} +1 -1
- package/src/assets/web-panel/assets/index-ChVT0p9u.js +1 -0
- package/src/assets/web-panel/assets/{index-CZDekj7T.js → index-D2B4VPyP.js} +1 -1
- package/src/assets/web-panel/assets/{index-YSw_gxlZ.js → index-D9evtvg2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTbxp4UH.js → index-DUUrv141.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bbj2NS_I.js → index-DiSkx4UB.js} +3 -3
- package/src/assets/web-panel/assets/{index-BZs5bBnk.js → index-Dk2qouAz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DalA0TKC.js → index-Dk7-v4hP.js} +1 -1
- package/src/assets/web-panel/assets/{index-1jeAudHd.js → index-DmbfhJUP.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1ifZtXo.js → index-DqBgBpgp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhA3QEni.js → index-PT_5sBMA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSjilZ9L.js → index-U4f5izHz.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2FqfMvU.js → index-YXgLng0K.js} +1 -1
- package/src/assets/web-panel/assets/{index-COev0W2g.js → index-ZxO_-E8a.js} +1 -1
- package/src/assets/web-panel/assets/{index-M7wxfAbm.js → index-dIHr4B_u.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjWnONdy.js → index-gyFpvL7l.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dkwsi1Kn.js → index-s1opAL-M.js} +1 -1
- package/src/assets/web-panel/assets/{index-hwVDeoC0.js → index-yObj1O4n.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Co67Kqmb.js → initDefaultProps-C9h9yKL3.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BMOxQSF_.js → motion-BvmLsPdu.js} +1 -1
- package/src/assets/web-panel/assets/{move-C5fWDw-N.js → move-CoL4ekU1.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BJevpL0e.js → mtc-parser-C4pMy6xV.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BCzNU8s6.js → omit-DPuJfNxx.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CybWvDPk.js → pickAttrs-D0KEeaK2.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BMWS9HnW.js → placementArrow-BpkyINxt.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BoL2UnGY.js → responsiveObserve-DQI_wOq8.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DWNfXraU.js → slide-DYfdDiRg.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BquTM3tX.js → statusUtils-B5dtvb0D.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BEkCleim.js → styleChecker-CF310mSj.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Oecnq7EA.js → useFlexGapSupport-D1Qp4BLp.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CkDffJ4F.js → useFs-C7_iyvJK.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-qbvKXesB.js → usePersonalDataHub-DZUt_fIm.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-C6v8n6mA.js → vnode-D3dsi0lZ.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-4CTeFILV.js → zoom-WdbOlvdQ.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +2 -2
- package/src/commands/agent.js +90 -1
- package/src/commands/chat.js +11 -2
- package/src/commands/compact.js +106 -23
- package/src/commands/loop.js +28 -10
- package/src/commands/routine.js +1 -1
- package/src/commands/scheduler-daemon.js +359 -2
- package/src/commands/session-observability.js +305 -0
- package/src/commands/session.js +38 -0
- package/src/data/changelog.json +14 -1
- package/src/gateways/ws/ws-agent-handler.js +439 -5
- package/src/harness/jsonl-session-store.js +463 -125
- package/src/harness/prompt-compressor.js +86 -13
- package/src/harness/provider-backed-compaction.js +100 -27
- package/src/lib/advisor-runtime.js +3 -1
- package/src/lib/agent-schedule-store.js +414 -4
- package/src/lib/agent-team/team-adjudication.js +40 -1
- package/src/lib/automation-engine.js +494 -0
- package/src/lib/background-agent-supervisor.js +793 -215
- package/src/lib/background-command-argv.js +24 -0
- package/src/lib/background-interaction-journal.js +361 -52
- package/src/lib/background-interaction-resolver.js +32 -0
- package/src/lib/background-launch-profile.js +2 -0
- package/src/lib/causal-observability.js +2661 -0
- package/src/lib/chat-session-admission.js +76 -0
- package/src/lib/cost-budget.js +5 -7
- package/src/lib/cowork/ab-comparator-cli.js +11 -0
- package/src/lib/cowork/debate-review-cli.js +12 -0
- package/src/lib/cowork-adapter.js +159 -38
- package/src/lib/cowork-cron.js +357 -1
- package/src/lib/cowork-task-runner.js +112 -17
- package/src/lib/delivery-coordinator.js +142 -0
- package/src/lib/direct-model-usage.js +121 -0
- package/src/lib/file-lines.js +183 -47
- package/src/lib/llm-pricing.js +12 -17
- package/src/lib/loop.js +26 -2
- package/src/lib/routine-store.js +380 -21
- package/src/lib/runtime-usage-ledger.js +182 -0
- package/src/lib/scheduler-kernel/agenda-adapter.js +308 -3
- package/src/lib/scheduler-kernel/automation-adapter.js +410 -8
- package/src/lib/scheduler-kernel/automation-event-adapter.js +36 -0
- package/src/lib/scheduler-kernel/cowork-cron-adapter.js +285 -3
- package/src/lib/scheduler-kernel/loop-adapter.js +541 -6
- package/src/lib/scheduler-kernel/migration-admin.js +346 -0
- package/src/lib/scheduler-kernel/migration-rollback-admin.js +932 -0
- package/src/lib/scheduler-kernel/routine-adapter.js +394 -20
- package/src/lib/scheduler-kernel/runtime.js +63 -1
- package/src/lib/scheduler-kernel/source-locator-path.js +142 -0
- package/src/lib/scheduler-kernel/store.js +2586 -85
- package/src/lib/session-host-lease.js +171 -2
- package/src/lib/session-host-snapshot.js +14 -3
- package/src/lib/session-persistence-failure.js +1 -0
- package/src/lib/session-tail.js +179 -34
- package/src/lib/session-transcript-structure.js +96 -0
- package/src/lib/sub-agent-context.js +328 -22
- package/src/lib/ws-agent-handler.js +4 -1
- package/src/repl/agent-repl.js +732 -91
- package/src/repl/chat-repl.js +5 -1
- package/src/runtime/agent-core.js +1272 -207
- package/src/runtime/fallback-model.js +5 -0
- package/src/runtime/headless-runner.js +324 -82
- package/src/runtime/headless-stream.js +232 -26
- package/src/runtime/policies/agent-policy.js +4 -0
- package/src/workers/background-agent-worker.js +403 -96
- package/src/assets/web-panel/assets/Projects-Dd-xuPIc.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-C7tT9iad.js +0 -1
- package/src/assets/web-panel/assets/devWarning-Jzu62CLC.js +0 -1
- package/src/assets/web-panel/assets/index-Zb2MeDSy.js +0 -1
- package/src/assets/web-panel/assets/index-fikqml4k.js +0 -1
package/src/lib/cowork-cron.js
CHANGED
|
@@ -60,6 +60,7 @@ export const _deps = {
|
|
|
60
60
|
|
|
61
61
|
export const COWORK_SCHEDULER_UNKNOWN_LEASE_EXPIRES_AT =
|
|
62
62
|
"9999-12-31T23:59:59.999Z";
|
|
63
|
+
export const COWORK_SCHEDULER_MIGRATION_SCHEMA_VERSION = 1;
|
|
63
64
|
|
|
64
65
|
function coworkSchedulerError(
|
|
65
66
|
code,
|
|
@@ -85,6 +86,81 @@ function normalizedDate(value, label) {
|
|
|
85
86
|
return date;
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
function stableJsonValue(value) {
|
|
90
|
+
if (Array.isArray(value)) return value.map(stableJsonValue);
|
|
91
|
+
if (value && typeof value === "object") {
|
|
92
|
+
return Object.fromEntries(
|
|
93
|
+
Object.keys(value)
|
|
94
|
+
.sort()
|
|
95
|
+
.map((key) => [key, stableJsonValue(value[key])]),
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
return value;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function coworkCronMigrationSourceSnapshot(schedule) {
|
|
102
|
+
const source = { ...schedule };
|
|
103
|
+
delete source.activeDelivery;
|
|
104
|
+
delete source.deliveryFence;
|
|
105
|
+
delete source.schedulerExecution;
|
|
106
|
+
delete source.schedulerMigration;
|
|
107
|
+
delete source.lastDeliveryId;
|
|
108
|
+
delete source.lastRunAt;
|
|
109
|
+
delete source.lastStatus;
|
|
110
|
+
delete source.nextAt;
|
|
111
|
+
delete source.missedRunPolicy;
|
|
112
|
+
return stableJsonValue(source);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function coworkCronMigrationSourceDigest(schedule) {
|
|
116
|
+
return crypto
|
|
117
|
+
.createHash("sha256")
|
|
118
|
+
.update(
|
|
119
|
+
"chainlesschain.cowork-cron.scheduler-migration-source.v1\0",
|
|
120
|
+
"utf8",
|
|
121
|
+
)
|
|
122
|
+
.update(JSON.stringify(coworkCronMigrationSourceSnapshot(schedule)), "utf8")
|
|
123
|
+
.digest("hex");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function migrationField(value, field) {
|
|
127
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
128
|
+
throw coworkSchedulerError(
|
|
129
|
+
"COWORK_SCHEDULER_MIGRATION_INVALID",
|
|
130
|
+
`Cowork scheduler migration ${field} is required`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return value.trim();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function coworkMigrationFence(schedule, nowMs) {
|
|
137
|
+
const migration = schedule.schedulerMigration;
|
|
138
|
+
const expiresAt = Date.parse(schedule.activeDelivery?.leaseExpiresAt || "");
|
|
139
|
+
return (
|
|
140
|
+
migration?.schemaVersion === COWORK_SCHEDULER_MIGRATION_SCHEMA_VERSION &&
|
|
141
|
+
typeof migration.retirementToken === "string" &&
|
|
142
|
+
schedule.activeDelivery?.ownerId ===
|
|
143
|
+
`scheduler-migration:${migration.retirementToken}` &&
|
|
144
|
+
Number.isFinite(expiresAt) &&
|
|
145
|
+
expiresAt > nowMs
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function applyCoworkMigrationFence(schedule, now) {
|
|
150
|
+
const token = schedule.schedulerMigration?.retirementToken;
|
|
151
|
+
if (typeof token !== "string" || token.length === 0) return false;
|
|
152
|
+
const fence = Math.max(Number(schedule.deliveryFence) || 0, 0) + 1;
|
|
153
|
+
schedule.deliveryFence = fence;
|
|
154
|
+
schedule.activeDelivery = {
|
|
155
|
+
deliveryId: `scheduler-migration:${token}`,
|
|
156
|
+
ownerId: `scheduler-migration:${token}`,
|
|
157
|
+
fence,
|
|
158
|
+
claimedAt: now.toISOString(),
|
|
159
|
+
leaseExpiresAt: COWORK_SCHEDULER_UNKNOWN_LEASE_EXPIRES_AT,
|
|
160
|
+
};
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
88
164
|
// ─── Cron parser ─────────────────────────────────────────────────────────────
|
|
89
165
|
|
|
90
166
|
const FIELD_RANGES = [
|
|
@@ -687,6 +763,205 @@ export function getSchedule(cwd, id) {
|
|
|
687
763
|
);
|
|
688
764
|
}
|
|
689
765
|
|
|
766
|
+
export function prepareCoworkSchedulerMigration(
|
|
767
|
+
cwd,
|
|
768
|
+
id,
|
|
769
|
+
{ migrationId, sourceDigest, targetJobId } = {},
|
|
770
|
+
) {
|
|
771
|
+
const migration = migrationField(migrationId, "migrationId");
|
|
772
|
+
const digest = migrationField(sourceDigest, "sourceDigest");
|
|
773
|
+
const target = migrationField(targetJobId, "targetJobId");
|
|
774
|
+
return _withScheduleLock(cwd, () => {
|
|
775
|
+
const schedules = loadSchedules(cwd, { failOnMalformed: true });
|
|
776
|
+
const schedule = schedules.find((entry) => entry.id === id);
|
|
777
|
+
if (!schedule) {
|
|
778
|
+
throw coworkSchedulerError(
|
|
779
|
+
"COWORK_SCHEDULER_SCHEDULE_NOT_FOUND",
|
|
780
|
+
`Cowork schedule does not exist: ${id}`,
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
if (schedule.enabled !== true) {
|
|
784
|
+
throw coworkSchedulerError(
|
|
785
|
+
"COWORK_SCHEDULER_SCHEDULE_DISABLED",
|
|
786
|
+
`Cowork schedule is disabled: ${id}`,
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
if (coworkCronMigrationSourceDigest(schedule) !== digest) {
|
|
790
|
+
throw coworkSchedulerError(
|
|
791
|
+
"COWORK_SCHEDULER_MIGRATION_SOURCE_CHANGED",
|
|
792
|
+
`Cowork schedule changed before migration: ${id}`,
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
const prior = schedule.schedulerMigration;
|
|
796
|
+
if (prior) {
|
|
797
|
+
if (
|
|
798
|
+
prior.schemaVersion !== COWORK_SCHEDULER_MIGRATION_SCHEMA_VERSION ||
|
|
799
|
+
prior.migrationId !== migration ||
|
|
800
|
+
prior.sourceDigest !== digest ||
|
|
801
|
+
prior.targetJobId !== target ||
|
|
802
|
+
prior.state !== "prepared"
|
|
803
|
+
) {
|
|
804
|
+
throw coworkSchedulerError(
|
|
805
|
+
"COWORK_SCHEDULER_MIGRATION_CONFLICT",
|
|
806
|
+
`Cowork schedule already belongs to another migration: ${id}`,
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
return schedule;
|
|
810
|
+
}
|
|
811
|
+
schedule.schedulerMigration = {
|
|
812
|
+
schemaVersion: COWORK_SCHEDULER_MIGRATION_SCHEMA_VERSION,
|
|
813
|
+
state: "prepared",
|
|
814
|
+
migrationId: migration,
|
|
815
|
+
sourceDigest: digest,
|
|
816
|
+
targetJobId: target,
|
|
817
|
+
preparedAt: _deps.now().toISOString(),
|
|
818
|
+
};
|
|
819
|
+
_saveSchedulesUnlocked(cwd, schedules);
|
|
820
|
+
return schedule;
|
|
821
|
+
});
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
export function retireCoworkSchedulerMigration(
|
|
825
|
+
cwd,
|
|
826
|
+
id,
|
|
827
|
+
{
|
|
828
|
+
migrationId,
|
|
829
|
+
sourceDigest,
|
|
830
|
+
targetJobId,
|
|
831
|
+
retirementToken,
|
|
832
|
+
at = _deps.now(),
|
|
833
|
+
} = {},
|
|
834
|
+
) {
|
|
835
|
+
const migration = migrationField(migrationId, "migrationId");
|
|
836
|
+
const digest = migrationField(sourceDigest, "sourceDigest");
|
|
837
|
+
const target = migrationField(targetJobId, "targetJobId");
|
|
838
|
+
const token = migrationField(retirementToken, "retirementToken");
|
|
839
|
+
const now = normalizedDate(at, "cowork scheduler migration retirement");
|
|
840
|
+
return _withScheduleLock(cwd, () => {
|
|
841
|
+
const schedules = loadSchedules(cwd, { failOnMalformed: true });
|
|
842
|
+
const schedule = schedules.find((entry) => entry.id === id);
|
|
843
|
+
if (!schedule) {
|
|
844
|
+
throw coworkSchedulerError(
|
|
845
|
+
"COWORK_SCHEDULER_SCHEDULE_NOT_FOUND",
|
|
846
|
+
`Cowork schedule does not exist: ${id}`,
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
const prior = schedule.schedulerMigration;
|
|
850
|
+
if (
|
|
851
|
+
prior?.schemaVersion !== COWORK_SCHEDULER_MIGRATION_SCHEMA_VERSION ||
|
|
852
|
+
prior.migrationId !== migration ||
|
|
853
|
+
prior.sourceDigest !== digest ||
|
|
854
|
+
prior.targetJobId !== target ||
|
|
855
|
+
!["prepared", "retired"].includes(prior.state)
|
|
856
|
+
) {
|
|
857
|
+
throw coworkSchedulerError(
|
|
858
|
+
"COWORK_SCHEDULER_MIGRATION_CONFLICT",
|
|
859
|
+
`Cowork migration preparation changed before retirement: ${id}`,
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
if (prior.state === "retired") {
|
|
863
|
+
if (
|
|
864
|
+
prior.retirementToken !== token ||
|
|
865
|
+
!coworkMigrationFence(schedule, now.getTime())
|
|
866
|
+
) {
|
|
867
|
+
throw coworkSchedulerError(
|
|
868
|
+
"COWORK_SCHEDULER_MIGRATION_CONFLICT",
|
|
869
|
+
`Cowork migration retirement fence changed: ${id}`,
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
return schedule;
|
|
873
|
+
}
|
|
874
|
+
if (coworkCronMigrationSourceDigest(schedule) !== digest) {
|
|
875
|
+
throw coworkSchedulerError(
|
|
876
|
+
"COWORK_SCHEDULER_MIGRATION_SOURCE_CHANGED",
|
|
877
|
+
`Cowork schedule changed before retirement: ${id}`,
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
const activeExpiresAt = Date.parse(
|
|
881
|
+
schedule.activeDelivery?.leaseExpiresAt || "",
|
|
882
|
+
);
|
|
883
|
+
if (
|
|
884
|
+
schedule.activeDelivery &&
|
|
885
|
+
Number.isFinite(activeExpiresAt) &&
|
|
886
|
+
activeExpiresAt > now.getTime()
|
|
887
|
+
) {
|
|
888
|
+
throw coworkSchedulerError(
|
|
889
|
+
"COWORK_SCHEDULER_LEGACY_CLAIM_ACTIVE",
|
|
890
|
+
`Cowork schedule is already claimed: ${id}`,
|
|
891
|
+
{ retryable: true, retryAt: activeExpiresAt },
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
schedule.schedulerMigration = {
|
|
895
|
+
...prior,
|
|
896
|
+
state: "retired",
|
|
897
|
+
retirementToken: token,
|
|
898
|
+
retiredAt: now.toISOString(),
|
|
899
|
+
};
|
|
900
|
+
applyCoworkMigrationFence(schedule, now);
|
|
901
|
+
_saveSchedulesUnlocked(cwd, schedules);
|
|
902
|
+
return schedule;
|
|
903
|
+
});
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
export function restoreCoworkSchedulerMigration(
|
|
907
|
+
cwd,
|
|
908
|
+
id,
|
|
909
|
+
{ migrationId, sourceDigest, targetJobId, retirementToken } = {},
|
|
910
|
+
) {
|
|
911
|
+
const migration = migrationField(migrationId, "migrationId");
|
|
912
|
+
const expectedDigest = migrationField(sourceDigest, "sourceDigest");
|
|
913
|
+
const target = migrationField(targetJobId, "targetJobId");
|
|
914
|
+
const token =
|
|
915
|
+
retirementToken === null || retirementToken === undefined
|
|
916
|
+
? null
|
|
917
|
+
: migrationField(retirementToken, "retirementToken");
|
|
918
|
+
return _withScheduleLock(cwd, () => {
|
|
919
|
+
const schedules = loadSchedules(cwd, { failOnMalformed: true });
|
|
920
|
+
const schedule = schedules.find((entry) => entry.id === id);
|
|
921
|
+
if (!schedule) {
|
|
922
|
+
throw coworkSchedulerError(
|
|
923
|
+
"COWORK_SCHEDULER_SCHEDULE_NOT_FOUND",
|
|
924
|
+
`Cowork schedule does not exist: ${id}`,
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
const current = schedule.schedulerMigration;
|
|
928
|
+
if (!current) {
|
|
929
|
+
if (
|
|
930
|
+
coworkCronMigrationSourceDigest(schedule) !== expectedDigest ||
|
|
931
|
+
String(schedule.activeDelivery?.ownerId || "").startsWith(
|
|
932
|
+
"scheduler-migration:",
|
|
933
|
+
)
|
|
934
|
+
) {
|
|
935
|
+
throw coworkSchedulerError(
|
|
936
|
+
"COWORK_SCHEDULER_MIGRATION_CONFLICT",
|
|
937
|
+
`Cowork source changed after rollback restoration: ${id}`,
|
|
938
|
+
);
|
|
939
|
+
}
|
|
940
|
+
return schedule;
|
|
941
|
+
}
|
|
942
|
+
if (
|
|
943
|
+
current?.schemaVersion !== COWORK_SCHEDULER_MIGRATION_SCHEMA_VERSION ||
|
|
944
|
+
current.migrationId !== migration ||
|
|
945
|
+
current.sourceDigest !== expectedDigest ||
|
|
946
|
+
current.targetJobId !== target ||
|
|
947
|
+
!["prepared", "retired"].includes(current.state) ||
|
|
948
|
+
coworkCronMigrationSourceDigest(schedule) !== expectedDigest ||
|
|
949
|
+
(current.state === "retired" &&
|
|
950
|
+
(current.retirementToken !== token ||
|
|
951
|
+
schedule.activeDelivery?.ownerId !== `scheduler-migration:${token}`))
|
|
952
|
+
) {
|
|
953
|
+
throw coworkSchedulerError(
|
|
954
|
+
"COWORK_SCHEDULER_MIGRATION_CONFLICT",
|
|
955
|
+
`Cowork migration fence changed before rollback: ${id}`,
|
|
956
|
+
);
|
|
957
|
+
}
|
|
958
|
+
delete schedule.schedulerMigration;
|
|
959
|
+
if (current.state === "retired") schedule.activeDelivery = null;
|
|
960
|
+
_saveSchedulesUnlocked(cwd, schedules);
|
|
961
|
+
return schedule;
|
|
962
|
+
});
|
|
963
|
+
}
|
|
964
|
+
|
|
690
965
|
/**
|
|
691
966
|
* Bind a scheduler-kernel occurrence before starting the Cowork task.
|
|
692
967
|
* The same JSONL lock used by the legacy driver closes both old-first and
|
|
@@ -745,7 +1020,13 @@ export function bindSchedulerScheduleFire(
|
|
|
745
1020
|
|
|
746
1021
|
const active = schedule.activeDelivery;
|
|
747
1022
|
const activeExpiresAt = Date.parse(active?.leaseExpiresAt || "");
|
|
748
|
-
|
|
1023
|
+
const migrationFence = coworkMigrationFence(schedule, nowMs);
|
|
1024
|
+
if (
|
|
1025
|
+
active &&
|
|
1026
|
+
Number.isFinite(activeExpiresAt) &&
|
|
1027
|
+
activeExpiresAt > nowMs &&
|
|
1028
|
+
!migrationFence
|
|
1029
|
+
) {
|
|
749
1030
|
throw coworkSchedulerError(
|
|
750
1031
|
"COWORK_SCHEDULER_LEGACY_CLAIM_ACTIVE",
|
|
751
1032
|
`Cowork schedule is already claimed: ${id}`,
|
|
@@ -857,6 +1138,81 @@ export function completeSchedulerScheduleFire(
|
|
|
857
1138
|
} else {
|
|
858
1139
|
schedule.activeDelivery = null;
|
|
859
1140
|
}
|
|
1141
|
+
if (schedule.enabled === true) applyCoworkMigrationFence(schedule, now);
|
|
1142
|
+
_saveSchedulesUnlocked(cwd, schedules);
|
|
1143
|
+
return schedule;
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
export function adjudicateSchedulerScheduleFire(
|
|
1148
|
+
cwd,
|
|
1149
|
+
id,
|
|
1150
|
+
{
|
|
1151
|
+
deliveryId,
|
|
1152
|
+
occurrenceId,
|
|
1153
|
+
snapshotDigest,
|
|
1154
|
+
attempt,
|
|
1155
|
+
decision,
|
|
1156
|
+
requestId,
|
|
1157
|
+
at = _deps.now(),
|
|
1158
|
+
} = {},
|
|
1159
|
+
) {
|
|
1160
|
+
if (!["confirmed_applied", "confirmed_not_applied"].includes(decision)) {
|
|
1161
|
+
throw coworkSchedulerError(
|
|
1162
|
+
"COWORK_SCHEDULER_ADJUDICATION_INVALID",
|
|
1163
|
+
"Cowork scheduler adjudication decision is invalid",
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
const now = normalizedDate(at, "cowork scheduler adjudication time");
|
|
1167
|
+
return _withScheduleLock(cwd, () => {
|
|
1168
|
+
const schedules = loadSchedules(cwd, { failOnMalformed: true });
|
|
1169
|
+
const schedule = schedules.find((entry) => entry.id === id);
|
|
1170
|
+
if (!schedule) {
|
|
1171
|
+
throw coworkSchedulerError(
|
|
1172
|
+
"COWORK_SCHEDULER_SCHEDULE_NOT_FOUND",
|
|
1173
|
+
`Cowork schedule does not exist: ${id}`,
|
|
1174
|
+
);
|
|
1175
|
+
}
|
|
1176
|
+
const evidence = schedule.schedulerExecution;
|
|
1177
|
+
const targetStatus =
|
|
1178
|
+
decision === "confirmed_applied"
|
|
1179
|
+
? "adjudicated_applied"
|
|
1180
|
+
: "adjudicated_not_applied";
|
|
1181
|
+
if (
|
|
1182
|
+
evidence?.status === targetStatus &&
|
|
1183
|
+
evidence.adjudication?.requestId === requestId &&
|
|
1184
|
+
evidence.adjudication.decision === decision
|
|
1185
|
+
) {
|
|
1186
|
+
return schedule;
|
|
1187
|
+
}
|
|
1188
|
+
if (
|
|
1189
|
+
!evidence ||
|
|
1190
|
+
evidence.deliveryId !== deliveryId ||
|
|
1191
|
+
evidence.occurrenceId !== occurrenceId ||
|
|
1192
|
+
evidence.snapshotDigest !== snapshotDigest ||
|
|
1193
|
+
!Number.isSafeInteger(evidence.attempt) ||
|
|
1194
|
+
evidence.attempt < 1 ||
|
|
1195
|
+
evidence.attempt > attempt ||
|
|
1196
|
+
evidence.status !== "running"
|
|
1197
|
+
) {
|
|
1198
|
+
throw coworkSchedulerError(
|
|
1199
|
+
"COWORK_SCHEDULER_ADJUDICATION_EVIDENCE_MISMATCH",
|
|
1200
|
+
`Cowork scheduler adjudication evidence does not match: ${id}`,
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
schedule.schedulerExecution = {
|
|
1204
|
+
...evidence,
|
|
1205
|
+
status: targetStatus,
|
|
1206
|
+
endedAt: now.toISOString(),
|
|
1207
|
+
adjudication: { requestId, decision },
|
|
1208
|
+
};
|
|
1209
|
+
if (decision === "confirmed_applied") {
|
|
1210
|
+
schedule.lastDeliveryId = deliveryId;
|
|
1211
|
+
schedule.lastRunAt = now.toISOString();
|
|
1212
|
+
schedule.lastStatus = "adjudicated-applied";
|
|
1213
|
+
}
|
|
1214
|
+
schedule.activeDelivery = null;
|
|
1215
|
+
if (schedule.enabled === true) applyCoworkMigrationFence(schedule, now);
|
|
860
1216
|
_saveSchedulesUnlocked(cwd, schedules);
|
|
861
1217
|
return schedule;
|
|
862
1218
|
});
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
isUnsafeSessionId,
|
|
37
37
|
readVerifiedEvents as readVerifiedSessionEvents,
|
|
38
38
|
readVerifiedProjection as readVerifiedSessionProjection,
|
|
39
|
+
sessionHasPersistedEvidence,
|
|
39
40
|
} from "../harness/jsonl-session-store.js";
|
|
40
41
|
|
|
41
42
|
// ─── Dependencies (overridable for testing) ──────────────────────────────────
|
|
@@ -49,6 +50,7 @@ export const _deps = {
|
|
|
49
50
|
appendSessionEventIfHead,
|
|
50
51
|
readVerifiedSessionEvents,
|
|
51
52
|
readVerifiedSessionProjection,
|
|
53
|
+
sessionHasPersistedEvidence,
|
|
52
54
|
randomUUID,
|
|
53
55
|
};
|
|
54
56
|
|
|
@@ -56,6 +58,91 @@ export const _deps = {
|
|
|
56
58
|
|
|
57
59
|
const DEFAULT_MAX_ITERATIONS = 50;
|
|
58
60
|
const DEFAULT_TOKEN_BUDGET = 100_000;
|
|
61
|
+
const COWORK_MCP_CALL_LEDGER_UNSUPPORTED =
|
|
62
|
+
"CC_COWORK_MCP_CALL_LEDGER_UNSUPPORTED";
|
|
63
|
+
const COWORK_MCP_SESSION_UNVERIFIED = "CC_COWORK_MCP_SESSION_UNVERIFIED";
|
|
64
|
+
const PROTECTED_USAGE_FIELDS = Object.freeze([
|
|
65
|
+
"observabilityScope",
|
|
66
|
+
"usageTelemetryProtocol",
|
|
67
|
+
"usageTelemetryVersion",
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
function coworkMcpAdmissionError(code, message, sessionId, cause = null) {
|
|
71
|
+
const error = new Error(message, cause ? { cause } : undefined);
|
|
72
|
+
error.code = code;
|
|
73
|
+
error.sessionId = sessionId;
|
|
74
|
+
return error;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function assertCoworkMcpEventUsageAdmission(event, sessionId) {
|
|
78
|
+
if (event?.type !== "session_start") return;
|
|
79
|
+
const data =
|
|
80
|
+
event.data && typeof event.data === "object" && !Array.isArray(event.data)
|
|
81
|
+
? event.data
|
|
82
|
+
: {};
|
|
83
|
+
if (!PROTECTED_USAGE_FIELDS.some((field) => Object.hasOwn(data, field))) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
throw coworkMcpAdmissionError(
|
|
87
|
+
COWORK_MCP_CALL_LEDGER_UNSUPPORTED,
|
|
88
|
+
"Scoped call-ledger sessions are not supported by Cowork MCP tasks; use agent mode or an IDE host with usage-ledger support",
|
|
89
|
+
sessionId,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function readCoworkMcpUsageAdmission(sessionId) {
|
|
94
|
+
return _deps.readVerifiedSessionProjection(sessionId, () => ({
|
|
95
|
+
accept(event) {
|
|
96
|
+
assertCoworkMcpEventUsageAdmission(event, sessionId);
|
|
97
|
+
},
|
|
98
|
+
finish() {
|
|
99
|
+
return true;
|
|
100
|
+
},
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* An explicitly supplied MCP session can name an existing canonical JSONL
|
|
106
|
+
* authority. Verify it before mounting servers or starting a child model, and
|
|
107
|
+
* refuse protected usage transcripts until Cowork persists the call ledger.
|
|
108
|
+
*/
|
|
109
|
+
export function assertCoworkMcpSessionUsageAdmission(sessionId) {
|
|
110
|
+
if (sessionId == null) return;
|
|
111
|
+
if (typeof sessionId !== "string" || isUnsafeSessionId(sessionId)) {
|
|
112
|
+
throw coworkMcpAdmissionError(
|
|
113
|
+
"CC_COWORK_MCP_SESSION_INVALID",
|
|
114
|
+
"Cowork MCP session id is invalid",
|
|
115
|
+
sessionId,
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let hasEvidence;
|
|
120
|
+
try {
|
|
121
|
+
hasEvidence = _deps.sessionHasPersistedEvidence(sessionId);
|
|
122
|
+
} catch (cause) {
|
|
123
|
+
throw coworkMcpAdmissionError(
|
|
124
|
+
COWORK_MCP_SESSION_UNVERIFIED,
|
|
125
|
+
"Cowork MCP session authority could not be inspected; refusing to start a model or tool",
|
|
126
|
+
sessionId,
|
|
127
|
+
cause,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
if (!hasEvidence) return;
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
if (readCoworkMcpUsageAdmission(sessionId) !== true) {
|
|
134
|
+
throw new Error("verified usage-admission projection was bypassed");
|
|
135
|
+
}
|
|
136
|
+
} catch (cause) {
|
|
137
|
+
if (cause?.code === COWORK_MCP_CALL_LEDGER_UNSUPPORTED) throw cause;
|
|
138
|
+
throw coworkMcpAdmissionError(
|
|
139
|
+
COWORK_MCP_SESSION_UNVERIFIED,
|
|
140
|
+
"Cowork MCP session authority could not be verified; refusing to start a model or tool",
|
|
141
|
+
sessionId,
|
|
142
|
+
cause,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
59
146
|
|
|
60
147
|
function resolveCoworkMcpSessionId(requested) {
|
|
61
148
|
if (requested != null) {
|
|
@@ -152,6 +239,7 @@ function createCoworkMcpRecoveryProjection(sessionId, templateId, onFinish) {
|
|
|
152
239
|
throw error;
|
|
153
240
|
}
|
|
154
241
|
acceptedCount += 1;
|
|
242
|
+
assertCoworkMcpEventUsageAdmission(event, sessionId);
|
|
155
243
|
assertCoworkMcpSessionBindingEvent(event, templateId);
|
|
156
244
|
ledger.accept(event);
|
|
157
245
|
},
|
|
@@ -343,24 +431,13 @@ export function prepareCoworkMcpRuntime(mcp, options = {}) {
|
|
|
343
431
|
});
|
|
344
432
|
}
|
|
345
433
|
} catch (error) {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
"all",
|
|
353
|
-
error?.code || "CC_MCP_LEDGER_EVENT_READ_FAILED",
|
|
434
|
+
if (error?.code === COWORK_MCP_CALL_LEDGER_UNSUPPORTED) throw error;
|
|
435
|
+
throw coworkMcpAdmissionError(
|
|
436
|
+
COWORK_MCP_SESSION_UNVERIFIED,
|
|
437
|
+
"Cowork MCP session authority could not be verified; refusing to start a model or tool",
|
|
438
|
+
sessionId,
|
|
439
|
+
error,
|
|
354
440
|
);
|
|
355
|
-
if (typeof options.onProgress === "function") {
|
|
356
|
-
options.onProgress({
|
|
357
|
-
type: "mcp-recovery",
|
|
358
|
-
sessionId,
|
|
359
|
-
unsettled: 0,
|
|
360
|
-
incidents: 1,
|
|
361
|
-
recovery: recoveryState,
|
|
362
|
-
});
|
|
363
|
-
}
|
|
364
441
|
}
|
|
365
442
|
|
|
366
443
|
const sink = createSessionMcpLedgerSink(
|
|
@@ -423,6 +500,10 @@ export async function runCoworkTask(options = {}) {
|
|
|
423
500
|
throw new Error("userMessage is required");
|
|
424
501
|
}
|
|
425
502
|
|
|
503
|
+
// An explicit canonical authority must be admitted before mounting local MCP
|
|
504
|
+
// servers, constructing a child context, or making any provider call.
|
|
505
|
+
assertCoworkMcpSessionUsageAdmission(mcpSessionId);
|
|
506
|
+
|
|
426
507
|
// Validate file paths before starting
|
|
427
508
|
if (files.length > 0) {
|
|
428
509
|
const missing = files.filter((f) => !_deps.existsSync(f));
|
|
@@ -586,6 +667,7 @@ export async function runCoworkTask(options = {}) {
|
|
|
586
667
|
* @param {object} options - Same as runCoworkTask, plus:
|
|
587
668
|
* @param {number} [options.agents] - Number of parallel agents (default 3, max 10)
|
|
588
669
|
* @param {string} [options.strategy] - Routing strategy (default "round-robin")
|
|
670
|
+
* @param {string} [options.mcpSessionId] - Canonical session authority to admit
|
|
589
671
|
* @param {function} [options.onProgress] - Progress callback
|
|
590
672
|
* @param {AbortSignal} [options.signal] - Cancellation signal
|
|
591
673
|
* @returns {Promise<{ taskId: string, status: string, result: object }>}
|
|
@@ -600,12 +682,18 @@ export async function runCoworkTaskParallel(options = {}) {
|
|
|
600
682
|
strategy,
|
|
601
683
|
onProgress = null,
|
|
602
684
|
signal = null,
|
|
685
|
+
mcpSessionId = null,
|
|
603
686
|
} = options;
|
|
604
687
|
|
|
605
688
|
if (!userMessage || typeof userMessage !== "string") {
|
|
606
689
|
throw new Error("userMessage is required");
|
|
607
690
|
}
|
|
608
691
|
|
|
692
|
+
// Parallel orchestration can make provider calls while decomposing and
|
|
693
|
+
// dispatching work. Apply the same canonical authority gate as sequential
|
|
694
|
+
// Cowork before constructing the orchestrator or starting any provider.
|
|
695
|
+
assertCoworkMcpSessionUsageAdmission(mcpSessionId);
|
|
696
|
+
|
|
609
697
|
if (files.length > 0) {
|
|
610
698
|
const missing = files.filter((f) => !_deps.existsSync(f));
|
|
611
699
|
if (missing.length > 0) {
|
|
@@ -742,6 +830,7 @@ export async function runCoworkTaskParallel(options = {}) {
|
|
|
742
830
|
* @param {string[]} [options.perspectives] - Override template perspectives
|
|
743
831
|
* @param {string} [options.cwd] - Working directory for history
|
|
744
832
|
* @param {object} [options.llmOptions] - LLM provider/model/key
|
|
833
|
+
* @param {string} [options.mcpSessionId] - Canonical session authority to admit
|
|
745
834
|
* @param {function} [options.onProgress] - Progress callback
|
|
746
835
|
* @returns {Promise<{ taskId, status, result }>}
|
|
747
836
|
*/
|
|
@@ -754,12 +843,18 @@ export async function runCoworkDebate(options = {}) {
|
|
|
754
843
|
cwd = process.cwd(),
|
|
755
844
|
llmOptions = {},
|
|
756
845
|
onProgress = null,
|
|
846
|
+
mcpSessionId = null,
|
|
757
847
|
} = options;
|
|
758
848
|
|
|
759
849
|
if (!userMessage || typeof userMessage !== "string") {
|
|
760
850
|
throw new Error("userMessage is required");
|
|
761
851
|
}
|
|
762
852
|
|
|
853
|
+
// Debate performs multiple reviewer calls plus moderator synthesis. Refuse a
|
|
854
|
+
// protected or unverifiable authority before emitting progress or invoking
|
|
855
|
+
// the first reviewer, matching sequential and parallel Cowork admission.
|
|
856
|
+
assertCoworkMcpSessionUsageAdmission(mcpSessionId);
|
|
857
|
+
|
|
763
858
|
if (files.length > 0) {
|
|
764
859
|
const missing = files.filter((f) => !_deps.existsSync(f));
|
|
765
860
|
if (missing.length > 0) {
|