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
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { nextCronTime } from "../agent-schedule-store.js";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
executeRoutine,
|
|
5
|
+
routineEffectiveSchedulerView,
|
|
6
|
+
routineMigrationSourceDigest,
|
|
7
|
+
routineMigrationSourceSnapshot,
|
|
8
|
+
} from "../routine-store.js";
|
|
4
9
|
import {
|
|
5
10
|
SchedulerKernelError,
|
|
6
11
|
canonicalJson,
|
|
@@ -8,10 +13,12 @@ import {
|
|
|
8
13
|
normalizeIdentifier,
|
|
9
14
|
} from "./contract.js";
|
|
10
15
|
import { SchedulerRuntime } from "./runtime.js";
|
|
16
|
+
import { schedulerMigrationSourceDigest } from "./store.js";
|
|
11
17
|
import {
|
|
12
18
|
bindSchedulerAuthorityPolicy,
|
|
13
19
|
createSchedulerAuthorityResolver,
|
|
14
20
|
} from "./authority-resolver.js";
|
|
21
|
+
import { canonicalSchedulerSourcePath } from "./source-locator-path.js";
|
|
15
22
|
|
|
16
23
|
export const ROUTINE_SCHEDULER_KIND = "routine";
|
|
17
24
|
export const ROUTINE_SCHEDULER_CAPABILITY = "agent.execute";
|
|
@@ -389,6 +396,243 @@ export function syncRoutineSchedulerJob(schedulerStore, routine, options = {}) {
|
|
|
389
396
|
}
|
|
390
397
|
}
|
|
391
398
|
|
|
399
|
+
export function migrateRoutineSchedule({
|
|
400
|
+
routineStore,
|
|
401
|
+
schedulerStore,
|
|
402
|
+
routine,
|
|
403
|
+
}) {
|
|
404
|
+
const effective = routineEffectiveSchedulerView(routine);
|
|
405
|
+
const snapshot = routineDefinitionSnapshot(effective);
|
|
406
|
+
if (!["cron", "once", "github"].includes(snapshot.trigger.kind)) {
|
|
407
|
+
throw routineError(
|
|
408
|
+
"SCHEDULER_ROUTINE_MIGRATION_TRIGGER_UNSUPPORTED",
|
|
409
|
+
`Routine trigger has no legacy driver to migrate: ${snapshot.id}`,
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
const directory = canonicalSchedulerSourcePath(routineStore.dir);
|
|
413
|
+
const sourceScope = { store: "routines", directory };
|
|
414
|
+
const sourceLocator = {
|
|
415
|
+
schemaVersion: 1,
|
|
416
|
+
type: "routine-store",
|
|
417
|
+
directory,
|
|
418
|
+
};
|
|
419
|
+
let prepared = schedulerStore.getActiveDomainMigrationBySource({
|
|
420
|
+
domain: "routine",
|
|
421
|
+
sourceScope,
|
|
422
|
+
sourceId: snapshot.id,
|
|
423
|
+
});
|
|
424
|
+
if (!prepared && routineStore.dir !== directory) {
|
|
425
|
+
const ambiguousLegacy = schedulerStore.getActiveDomainMigrationBySource({
|
|
426
|
+
domain: "routine",
|
|
427
|
+
sourceScope: { store: "routines", directory: routineStore.dir },
|
|
428
|
+
sourceId: snapshot.id,
|
|
429
|
+
});
|
|
430
|
+
if (ambiguousLegacy) {
|
|
431
|
+
throw routineError(
|
|
432
|
+
"SCHEDULER_ROUTINE_MIGRATION_SOURCE_UNBOUND",
|
|
433
|
+
`Legacy Routine migration uses a non-canonical path scope and cannot be bound safely: ${snapshot.id}`,
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
const channel =
|
|
438
|
+
snapshot.trigger.kind === "github"
|
|
439
|
+
? ROUTINE_SCHEDULER_CHANNELS.GITHUB
|
|
440
|
+
: ROUTINE_SCHEDULER_CHANNELS.SCHEDULED;
|
|
441
|
+
// GitHub occurrences use per-batch jobs. A disabled guard job owns the
|
|
442
|
+
// migration namespace while actual batches remain independently immutable.
|
|
443
|
+
const desired =
|
|
444
|
+
channel === ROUTINE_SCHEDULER_CHANNELS.GITHUB
|
|
445
|
+
? {
|
|
446
|
+
...buildRoutineSchedulerJob(effective, {
|
|
447
|
+
channel: ROUTINE_SCHEDULER_CHANNELS.SCHEDULED,
|
|
448
|
+
}),
|
|
449
|
+
id: routineSchedulerJobId(snapshot.id, channel),
|
|
450
|
+
trigger: {
|
|
451
|
+
source: "routine-store",
|
|
452
|
+
channel,
|
|
453
|
+
routineKind: "github",
|
|
454
|
+
},
|
|
455
|
+
enabled: true,
|
|
456
|
+
}
|
|
457
|
+
: buildRoutineSchedulerJob(effective, { channel });
|
|
458
|
+
desired.authority = bindSchedulerAuthorityPolicy(
|
|
459
|
+
schedulerStore,
|
|
460
|
+
desired.authority,
|
|
461
|
+
);
|
|
462
|
+
const sourceSnapshot = routineMigrationSourceSnapshot(routine);
|
|
463
|
+
const sourceDigest = routineMigrationSourceDigest(routine);
|
|
464
|
+
if (prepared) {
|
|
465
|
+
const migrationEntries = prepared.entries.filter(
|
|
466
|
+
(candidate) =>
|
|
467
|
+
candidate.domain === "routine" && candidate.sourceId === snapshot.id,
|
|
468
|
+
);
|
|
469
|
+
if (prepared.entries.length !== 1 || migrationEntries.length !== 1) {
|
|
470
|
+
throw routineError(
|
|
471
|
+
"SCHEDULER_ROUTINE_MIGRATION_DOMAIN_MISMATCH",
|
|
472
|
+
"Routine belongs to an invalid mixed-domain migration",
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
const [migrationEntry] = migrationEntries;
|
|
476
|
+
schedulerStore.bindDomainMigrationSourceLocator({
|
|
477
|
+
migrationId: prepared.id,
|
|
478
|
+
entryId: migrationEntry.entryId,
|
|
479
|
+
sourceLocator,
|
|
480
|
+
expectedSourceDigest: migrationEntry.sourceDigest,
|
|
481
|
+
expectedTargetJobId: migrationEntry.targetJobId,
|
|
482
|
+
});
|
|
483
|
+
prepared = schedulerStore.getDomainMigration(prepared.id);
|
|
484
|
+
} else {
|
|
485
|
+
prepared = schedulerStore.prepareDomainMigration({
|
|
486
|
+
entries: [
|
|
487
|
+
{
|
|
488
|
+
domain: "routine",
|
|
489
|
+
sourceId: snapshot.id,
|
|
490
|
+
sourceScope,
|
|
491
|
+
sourceLocator,
|
|
492
|
+
source: sourceSnapshot,
|
|
493
|
+
targetJob: desired,
|
|
494
|
+
rollbackStrategy: "disable",
|
|
495
|
+
},
|
|
496
|
+
],
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
if (
|
|
500
|
+
prepared.entries.length !== 1 ||
|
|
501
|
+
prepared.entries[0].domain !== "routine"
|
|
502
|
+
) {
|
|
503
|
+
throw routineError(
|
|
504
|
+
"SCHEDULER_ROUTINE_MIGRATION_DOMAIN_MISMATCH",
|
|
505
|
+
"Routine belongs to an invalid mixed-domain migration",
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
if (
|
|
509
|
+
prepared.entries[0].sourceDigest !==
|
|
510
|
+
schedulerMigrationSourceDigest(sourceSnapshot) ||
|
|
511
|
+
prepared.entries[0].targetJobId !== desired.id
|
|
512
|
+
) {
|
|
513
|
+
throw routineError(
|
|
514
|
+
"SCHEDULER_ROUTINE_MIGRATION_SOURCE_CHANGED",
|
|
515
|
+
`Routine changed after migration started: ${snapshot.id}`,
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
let migration = prepared;
|
|
519
|
+
if (["rolling_back", "rolled_back"].includes(migration.state)) {
|
|
520
|
+
throw routineError(
|
|
521
|
+
"SCHEDULER_ROUTINE_MIGRATION_STATE_CONFLICT",
|
|
522
|
+
`Routine migration cannot resume from state ${migration.state}`,
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
if (migration.state === "retired") {
|
|
526
|
+
routineStore.retireForSchedulerMigration(snapshot.id, {
|
|
527
|
+
migrationId: migration.id,
|
|
528
|
+
sourceDigest,
|
|
529
|
+
targetJobId: desired.id,
|
|
530
|
+
retirementToken: migration.entries[0].retirementToken,
|
|
531
|
+
});
|
|
532
|
+
return migration;
|
|
533
|
+
}
|
|
534
|
+
if (migration.state === "prepared") {
|
|
535
|
+
routineStore.prepareSchedulerMigration(snapshot.id, {
|
|
536
|
+
migrationId: migration.id,
|
|
537
|
+
sourceDigest,
|
|
538
|
+
targetJobId: desired.id,
|
|
539
|
+
});
|
|
540
|
+
migration = schedulerStore.applyDomainMigration(migration.id);
|
|
541
|
+
}
|
|
542
|
+
if (migration.state === "applied") {
|
|
543
|
+
migration = schedulerStore.verifyDomainMigration(migration.id, {
|
|
544
|
+
sources: [
|
|
545
|
+
{ entryId: migration.entries[0].entryId, source: sourceSnapshot },
|
|
546
|
+
],
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
const retiring =
|
|
550
|
+
migration.state === "retiring"
|
|
551
|
+
? migration
|
|
552
|
+
: schedulerStore.beginDomainMigrationRetirement(migration.id);
|
|
553
|
+
const entry = retiring.entries[0];
|
|
554
|
+
const retired = routineStore.retireForSchedulerMigration(snapshot.id, {
|
|
555
|
+
migrationId: migration.id,
|
|
556
|
+
sourceDigest,
|
|
557
|
+
targetJobId: desired.id,
|
|
558
|
+
retirementToken: entry.retirementToken,
|
|
559
|
+
});
|
|
560
|
+
schedulerStore.confirmDomainMigrationEntryRetired({
|
|
561
|
+
migrationId: migration.id,
|
|
562
|
+
entryId: entry.entryId,
|
|
563
|
+
retirementToken: entry.retirementToken,
|
|
564
|
+
source: retired,
|
|
565
|
+
});
|
|
566
|
+
return schedulerStore.getDomainMigration(migration.id);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
export function rollbackRoutineMigration({
|
|
570
|
+
routineStore,
|
|
571
|
+
schedulerStore,
|
|
572
|
+
migrationId,
|
|
573
|
+
}) {
|
|
574
|
+
const directory = canonicalSchedulerSourcePath(routineStore.dir);
|
|
575
|
+
const assertRollbackBinding = (migration) => {
|
|
576
|
+
if (
|
|
577
|
+
migration?.id !== migrationId ||
|
|
578
|
+
!Array.isArray(migration.entries) ||
|
|
579
|
+
migration.entries.length === 0 ||
|
|
580
|
+
migration.entries.some((entry) => entry.domain !== "routine")
|
|
581
|
+
) {
|
|
582
|
+
throw routineError(
|
|
583
|
+
"SCHEDULER_ROUTINE_MIGRATION_DOMAIN_MISMATCH",
|
|
584
|
+
"Routine rollback cannot operate on a mixed-domain migration",
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
for (const entry of migration.entries) {
|
|
588
|
+
const locator = entry.sourceLocator;
|
|
589
|
+
if (
|
|
590
|
+
locator?.schemaVersion !== 1 ||
|
|
591
|
+
locator.type !== "routine-store" ||
|
|
592
|
+
locator.directory !== directory
|
|
593
|
+
) {
|
|
594
|
+
throw routineError(
|
|
595
|
+
"SCHEDULER_ROUTINE_MIGRATION_SOURCE_UNBOUND",
|
|
596
|
+
`Routine rollback source locator does not match its store: ${entry.sourceId}`,
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return migration;
|
|
601
|
+
};
|
|
602
|
+
const current = assertRollbackBinding(
|
|
603
|
+
schedulerStore.getDomainMigration(migrationId),
|
|
604
|
+
);
|
|
605
|
+
if (current.state === "rolled_back") {
|
|
606
|
+
return { ...current, deduplicated: true };
|
|
607
|
+
}
|
|
608
|
+
const migration = assertRollbackBinding(
|
|
609
|
+
schedulerStore.beginDomainMigrationRollback(migrationId),
|
|
610
|
+
);
|
|
611
|
+
if (migration.state === "rolled_back") return migration;
|
|
612
|
+
const entries = migration.entries;
|
|
613
|
+
for (const entry of entries) {
|
|
614
|
+
if (entry.state === "rolled_back") continue;
|
|
615
|
+
schedulerStore.restoreDomainMigrationEntrySource({
|
|
616
|
+
migrationId,
|
|
617
|
+
entryId: entry.entryId,
|
|
618
|
+
retirementToken: entry.retirementToken,
|
|
619
|
+
restoreSource: () => {
|
|
620
|
+
const current = routineStore.get(entry.sourceId);
|
|
621
|
+
const restored = current.schedulerMigration
|
|
622
|
+
? routineStore.restoreFromSchedulerMigration(entry.sourceId, {
|
|
623
|
+
migrationId,
|
|
624
|
+
sourceDigest: routineMigrationSourceDigest(current),
|
|
625
|
+
targetJobId: entry.targetJobId,
|
|
626
|
+
retirementToken: entry.retirementToken,
|
|
627
|
+
})
|
|
628
|
+
: current;
|
|
629
|
+
return routineMigrationSourceSnapshot(restored);
|
|
630
|
+
},
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
return schedulerStore.getDomainMigration(migrationId);
|
|
634
|
+
}
|
|
635
|
+
|
|
392
636
|
export function scheduledRoutineFireAt(routine) {
|
|
393
637
|
const snapshot = routineSnapshot(routine);
|
|
394
638
|
if (snapshot.trigger.kind === "once") {
|
|
@@ -528,7 +772,47 @@ export function createRoutineSchedulerAdapter({ routineStore, runAgent } = {}) {
|
|
|
528
772
|
}
|
|
529
773
|
return {
|
|
530
774
|
kind: ROUTINE_SCHEDULER_KIND,
|
|
531
|
-
async
|
|
775
|
+
async adjudicate({ occurrence, adjudication }) {
|
|
776
|
+
const payload = occurrence.payload;
|
|
777
|
+
const expected = payload?.routine;
|
|
778
|
+
const runId = routineSchedulerRunId(occurrence.id);
|
|
779
|
+
if (
|
|
780
|
+
!expected ||
|
|
781
|
+
typeof routineStore.recordRunAdjudication !== "function"
|
|
782
|
+
) {
|
|
783
|
+
throw routineError(
|
|
784
|
+
"SCHEDULER_ROUTINE_ADJUDICATION_UNSUPPORTED",
|
|
785
|
+
`Routine adjudication cannot be applied: ${occurrence.id}`,
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
routineStore.recordRunAdjudication(runId, {
|
|
789
|
+
decision: adjudication.decision,
|
|
790
|
+
requestId: adjudication.requestId,
|
|
791
|
+
occurrenceId: occurrence.id,
|
|
792
|
+
snapshotDigest: payload.snapshotDigest,
|
|
793
|
+
});
|
|
794
|
+
if (adjudication.decision === "confirmed_applied") {
|
|
795
|
+
const current = routineStore.get(expected.id);
|
|
796
|
+
if (current) {
|
|
797
|
+
routineStore.update(expected.id, {
|
|
798
|
+
lastFiredAt: occurrence.scheduledFor,
|
|
799
|
+
...(current.trigger.kind === "once" || current.schedulerMigration
|
|
800
|
+
? { enabled: false }
|
|
801
|
+
: {}),
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
return {
|
|
805
|
+
settled: true,
|
|
806
|
+
result: {
|
|
807
|
+
runId,
|
|
808
|
+
status: "adjudicated-applied",
|
|
809
|
+
adjudicationRequestId: adjudication.requestId,
|
|
810
|
+
},
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
return { continue: true };
|
|
814
|
+
},
|
|
815
|
+
async execute({ occurrence, adjudication }) {
|
|
532
816
|
const payload = occurrence.payload;
|
|
533
817
|
const expected = payload?.routine;
|
|
534
818
|
if (!expected) {
|
|
@@ -579,10 +863,11 @@ export function createRoutineSchedulerAdapter({ routineStore, runAgent } = {}) {
|
|
|
579
863
|
`Routine run evidence does not match occurrence: ${occurrence.id}`,
|
|
580
864
|
);
|
|
581
865
|
}
|
|
866
|
+
const effectiveCurrent = routineEffectiveSchedulerView(current);
|
|
582
867
|
const currentDigest =
|
|
583
868
|
payload.snapshotType === "definition"
|
|
584
|
-
? routineDefinitionDigest(
|
|
585
|
-
: routineSnapshotDigest(
|
|
869
|
+
? routineDefinitionDigest(effectiveCurrent)
|
|
870
|
+
: routineSnapshotDigest(effectiveCurrent);
|
|
586
871
|
if (!existingRun && currentDigest !== payload.snapshotDigest) {
|
|
587
872
|
throw routineError(
|
|
588
873
|
"SCHEDULER_ROUTINE_STALE_SNAPSHOT",
|
|
@@ -592,26 +877,32 @@ export function createRoutineSchedulerAdapter({ routineStore, runAgent } = {}) {
|
|
|
592
877
|
if (
|
|
593
878
|
payload.channel !== ROUTINE_SCHEDULER_CHANNELS.MANUAL &&
|
|
594
879
|
!existingRun &&
|
|
595
|
-
|
|
880
|
+
effectiveCurrent.enabled !== true
|
|
596
881
|
) {
|
|
597
882
|
throw routineError(
|
|
598
883
|
"SCHEDULER_ROUTINE_DISABLED",
|
|
599
884
|
`Routine was disabled before scheduled execution: ${expected.id}`,
|
|
600
885
|
);
|
|
601
886
|
}
|
|
602
|
-
const execution = await executeRoutine(
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
:
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
887
|
+
const execution = await executeRoutine(
|
|
888
|
+
routineStore,
|
|
889
|
+
effectiveCurrent,
|
|
890
|
+
runAgent,
|
|
891
|
+
{
|
|
892
|
+
trigger:
|
|
893
|
+
payload.channel === ROUTINE_SCHEDULER_CHANNELS.MANUAL
|
|
894
|
+
? "manual"
|
|
895
|
+
: payload.channel === ROUTINE_SCHEDULER_CHANNELS.GITHUB
|
|
896
|
+
? `github:${payload.github.events
|
|
897
|
+
.map((event) => event.type)
|
|
898
|
+
.join(",")}`
|
|
899
|
+
: current.trigger.kind,
|
|
900
|
+
runId: schedulerRunId,
|
|
901
|
+
schedulerOccurrenceId: occurrence.id,
|
|
902
|
+
schedulerSnapshotDigest: payload.snapshotDigest,
|
|
903
|
+
...(adjudication ? { adjudication } : {}),
|
|
904
|
+
},
|
|
905
|
+
);
|
|
615
906
|
if (execution.status !== "ok") {
|
|
616
907
|
throw routineError(
|
|
617
908
|
"SCHEDULER_ROUTINE_EXECUTION_FAILED",
|
|
@@ -647,6 +938,7 @@ export class RoutineSchedulerBridge {
|
|
|
647
938
|
leaseMs,
|
|
648
939
|
renewIntervalMs,
|
|
649
940
|
authorityResolver,
|
|
941
|
+
migrateLegacy = true,
|
|
650
942
|
} = {}) {
|
|
651
943
|
if (typeof now !== "function") {
|
|
652
944
|
throw routineError(
|
|
@@ -657,6 +949,7 @@ export class RoutineSchedulerBridge {
|
|
|
657
949
|
this.routineStore = routineStore;
|
|
658
950
|
this.schedulerStore = schedulerStore;
|
|
659
951
|
this.now = now;
|
|
952
|
+
this.migrateLegacy = migrateLegacy !== false;
|
|
660
953
|
this.runtime = new SchedulerRuntime({
|
|
661
954
|
store: schedulerStore,
|
|
662
955
|
adapters: [createRoutineSchedulerAdapter({ routineStore, runAgent })],
|
|
@@ -688,7 +981,32 @@ export class RoutineSchedulerBridge {
|
|
|
688
981
|
"Routine GitHub scheduler requires a fetchEvents function",
|
|
689
982
|
);
|
|
690
983
|
}
|
|
691
|
-
const
|
|
984
|
+
const activeMigration =
|
|
985
|
+
this.migrateLegacy &&
|
|
986
|
+
this.schedulerStore.getActiveDomainMigrationBySource({
|
|
987
|
+
domain: "routine",
|
|
988
|
+
sourceScope: {
|
|
989
|
+
store: "routines",
|
|
990
|
+
directory: canonicalSchedulerSourcePath(this.routineStore.dir),
|
|
991
|
+
},
|
|
992
|
+
sourceId: routine.id,
|
|
993
|
+
});
|
|
994
|
+
if (
|
|
995
|
+
this.migrateLegacy &&
|
|
996
|
+
((routine.schedulerMigration && activeMigration?.state !== "retired") ||
|
|
997
|
+
activeMigration?.state !== undefined ||
|
|
998
|
+
(routine.enabled === true &&
|
|
999
|
+
!routine.schedulerMigration &&
|
|
1000
|
+
routine.trigger?.kind === "github"))
|
|
1001
|
+
) {
|
|
1002
|
+
migrateRoutineSchedule({
|
|
1003
|
+
routineStore: this.routineStore,
|
|
1004
|
+
schedulerStore: this.schedulerStore,
|
|
1005
|
+
routine,
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
const stored = this.routineStore.get(routine.id);
|
|
1009
|
+
const current = routineEffectiveSchedulerView(stored);
|
|
692
1010
|
if (
|
|
693
1011
|
!current ||
|
|
694
1012
|
current.enabled !== true ||
|
|
@@ -762,6 +1080,31 @@ export class RoutineSchedulerBridge {
|
|
|
762
1080
|
async runDue({ signal } = {}) {
|
|
763
1081
|
const results = [];
|
|
764
1082
|
const observedOccurrences = new Set();
|
|
1083
|
+
if (!signal?.aborted && this.migrateLegacy) {
|
|
1084
|
+
const sourceScope = {
|
|
1085
|
+
store: "routines",
|
|
1086
|
+
directory: canonicalSchedulerSourcePath(this.routineStore.dir),
|
|
1087
|
+
};
|
|
1088
|
+
const candidates = this.routineStore.list().filter((routine) => {
|
|
1089
|
+
const activeMigration =
|
|
1090
|
+
this.schedulerStore.getActiveDomainMigrationBySource({
|
|
1091
|
+
domain: "routine",
|
|
1092
|
+
sourceScope,
|
|
1093
|
+
sourceId: routine.id,
|
|
1094
|
+
});
|
|
1095
|
+
if (routine.schedulerMigration) {
|
|
1096
|
+
return activeMigration?.state !== "retired";
|
|
1097
|
+
}
|
|
1098
|
+
return activeMigration?.state !== undefined;
|
|
1099
|
+
});
|
|
1100
|
+
for (const routine of candidates) {
|
|
1101
|
+
migrateRoutineSchedule({
|
|
1102
|
+
routineStore: this.routineStore,
|
|
1103
|
+
schedulerStore: this.schedulerStore,
|
|
1104
|
+
routine,
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
765
1108
|
const recovered = await this.runtime.runUntilIdle({
|
|
766
1109
|
limit: 10_000,
|
|
767
1110
|
signal,
|
|
@@ -783,7 +1126,21 @@ export class RoutineSchedulerBridge {
|
|
|
783
1126
|
if (signal?.aborted) return results;
|
|
784
1127
|
|
|
785
1128
|
const now = normalizeEpochMs(Number(this.now()), "now");
|
|
786
|
-
const due =
|
|
1129
|
+
const due = [
|
|
1130
|
+
...this.routineStore.due(now),
|
|
1131
|
+
...this.routineStore.schedulerMigrated().filter((routine) => {
|
|
1132
|
+
if (routine.trigger.kind === "cron") {
|
|
1133
|
+
const from = routine.lastFiredAt || routine.createdAt || 0;
|
|
1134
|
+
const next = nextCronTime(routine.trigger.cron, from);
|
|
1135
|
+
return next !== null && next <= now;
|
|
1136
|
+
}
|
|
1137
|
+
return (
|
|
1138
|
+
routine.trigger.kind === "once" &&
|
|
1139
|
+
!routine.lastFiredAt &&
|
|
1140
|
+
routine.trigger.at <= now
|
|
1141
|
+
);
|
|
1142
|
+
}),
|
|
1143
|
+
];
|
|
787
1144
|
for (const routine of due) {
|
|
788
1145
|
const occurrence = enqueueScheduledRoutine(this.schedulerStore, routine);
|
|
789
1146
|
if (observedOccurrences.has(occurrence.id)) continue;
|
|
@@ -797,6 +1154,23 @@ export class RoutineSchedulerBridge {
|
|
|
797
1154
|
result,
|
|
798
1155
|
});
|
|
799
1156
|
}
|
|
1157
|
+
if (this.migrateLegacy) {
|
|
1158
|
+
const candidates = this.routineStore
|
|
1159
|
+
.list()
|
|
1160
|
+
.filter(
|
|
1161
|
+
(routine) =>
|
|
1162
|
+
routine.enabled === true &&
|
|
1163
|
+
!routine.schedulerMigration &&
|
|
1164
|
+
["cron", "once"].includes(routine.trigger?.kind),
|
|
1165
|
+
);
|
|
1166
|
+
for (const routine of candidates) {
|
|
1167
|
+
migrateRoutineSchedule({
|
|
1168
|
+
routineStore: this.routineStore,
|
|
1169
|
+
schedulerStore: this.schedulerStore,
|
|
1170
|
+
routine,
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
800
1174
|
return results;
|
|
801
1175
|
}
|
|
802
1176
|
}
|
|
@@ -409,11 +409,67 @@ export class SchedulerRuntime {
|
|
|
409
409
|
occurrence,
|
|
410
410
|
authority: occurrence.authority,
|
|
411
411
|
decision,
|
|
412
|
+
adjudication:
|
|
413
|
+
typeof this.store.getOccurrenceAdjudication === "function"
|
|
414
|
+
? this.store.getOccurrenceAdjudication(occurrence.id)
|
|
415
|
+
: null,
|
|
412
416
|
signal: linked.controller.signal,
|
|
413
417
|
renewLease: renew,
|
|
414
418
|
};
|
|
415
419
|
try {
|
|
416
|
-
|
|
420
|
+
let result;
|
|
421
|
+
if (context.adjudication?.status === "pending") {
|
|
422
|
+
const allowedAttempts =
|
|
423
|
+
context.adjudication.decision === "confirmed_applied"
|
|
424
|
+
? [
|
|
425
|
+
context.adjudication.expectedAttempt + 1,
|
|
426
|
+
context.adjudication.expectedAttempt + 2,
|
|
427
|
+
]
|
|
428
|
+
: [context.adjudication.expectedAttempt + 1];
|
|
429
|
+
if (
|
|
430
|
+
!allowedAttempts.includes(occurrence.attempt) ||
|
|
431
|
+
context.adjudication.expectedFence >= occurrence.fence
|
|
432
|
+
) {
|
|
433
|
+
throw runtimeError(
|
|
434
|
+
"SCHEDULER_RUNTIME_ADJUDICATION_BINDING_MISMATCH",
|
|
435
|
+
`Scheduler adjudication is not bound to this claim: ${occurrence.id}`,
|
|
436
|
+
);
|
|
437
|
+
}
|
|
438
|
+
if (typeof adapter.adjudicate !== "function") {
|
|
439
|
+
throw runtimeError(
|
|
440
|
+
"SCHEDULER_RUNTIME_ADJUDICATION_UNSUPPORTED",
|
|
441
|
+
`Scheduler adapter cannot apply an outcome-unknown adjudication: ${job.kind}`,
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
const resolution = await adapter.adjudicate(context);
|
|
445
|
+
if (
|
|
446
|
+
context.adjudication.decision === "confirmed_applied" &&
|
|
447
|
+
resolution?.settled !== true
|
|
448
|
+
) {
|
|
449
|
+
throw runtimeError(
|
|
450
|
+
"SCHEDULER_RUNTIME_ADJUDICATION_INVALID",
|
|
451
|
+
"confirmed_applied adjudication must settle without replay",
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
if (
|
|
455
|
+
context.adjudication.decision === "confirmed_not_applied" &&
|
|
456
|
+
resolution?.continue !== true
|
|
457
|
+
) {
|
|
458
|
+
throw runtimeError(
|
|
459
|
+
"SCHEDULER_RUNTIME_ADJUDICATION_INVALID",
|
|
460
|
+
"confirmed_not_applied adjudication must explicitly authorize one execution",
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
result =
|
|
464
|
+
resolution?.settled === true
|
|
465
|
+
? (resolution.result ?? {
|
|
466
|
+
adjudicationRequestId: context.adjudication.requestId,
|
|
467
|
+
decision: context.adjudication.decision,
|
|
468
|
+
})
|
|
469
|
+
: await adapter.execute(context);
|
|
470
|
+
} else {
|
|
471
|
+
result = await adapter.execute(context);
|
|
472
|
+
}
|
|
417
473
|
if (leaseError) throw leaseError;
|
|
418
474
|
if (linked.controller.signal.aborted) {
|
|
419
475
|
const aborted = runtimeError(
|
|
@@ -429,6 +485,9 @@ export class SchedulerRuntime {
|
|
|
429
485
|
fence: occurrence.fence,
|
|
430
486
|
outcome: "succeeded",
|
|
431
487
|
result: result ?? null,
|
|
488
|
+
...(context.adjudication?.status === "pending"
|
|
489
|
+
? { adjudicationRequestId: context.adjudication.requestId }
|
|
490
|
+
: {}),
|
|
432
491
|
});
|
|
433
492
|
return settledResult(settled);
|
|
434
493
|
} catch (error) {
|
|
@@ -453,6 +512,9 @@ export class SchedulerRuntime {
|
|
|
453
512
|
outcome: "failed",
|
|
454
513
|
error: safeError(settlementError),
|
|
455
514
|
retryable: policy.retryable,
|
|
515
|
+
...(context.adjudication?.status === "pending"
|
|
516
|
+
? { adjudicationRequestId: context.adjudication.requestId }
|
|
517
|
+
: {}),
|
|
456
518
|
...(policy.retryAt === undefined ? {} : { retryAt: policy.retryAt }),
|
|
457
519
|
});
|
|
458
520
|
return settledResult(settled);
|