chainlesschain 0.163.5 → 0.163.6
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/completions/_cc +1 -1
- package/completions/cc.bash +1 -1
- package/completions/cc.fish +1 -1
- package/completions/cc.ps1 +1 -1
- package/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-Cv2EE1Zy.js → AIOps-DDIUofA8.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CcpxMLuW.js → ActionButton-Bm-5xYRn.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DE8mJoMI.js → Analytics-D5UH4ljI.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DKn9dk9L.js → AppLayout-D_ifjOOP.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-Cp3mG3Py.js → Artifacts-BY1mXdC7.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-zvsQfF2C.js → Audit-Bujr4Ml3.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-Bi85SsjN.js → BackgroundAgents-sioKSTcC.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cw47Dj6s.js → Backup-DDOAK8RK.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C5Ip2afH.js → BaseInput-CtCsVVke.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-C0iAFkJv.js → Chat-DpNj0vnd.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BV9Wv7wO.js → ChatBubbleRenderer-CZta3Ftr.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-3KZZCiAF.js → Checkbox-DoHVNSXq.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-C8OMbBAz.js → Codegen-DlVl7Qmv.js} +1 -1
- package/src/assets/web-panel/assets/{Col-B-MB84LJ.js → Col-GIqoPYty.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DpR7Dxao.js → Community-CIAPEVji.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CyDtz0OS.js → Compact-BN7JiI_h.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-5tiRa2An.js → Compliance-CqUWCM9B.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DnQaKZ5x.js → Cowork-A4iPp7A4.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-BaWfoEDf.js → Cron-B2zeXXWb.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-Bu0HoHhb.js → Crosschain-BR2xmWr8.js} +1 -1
- package/src/assets/web-panel/assets/{DID-31zk8upX.js → DID-BzFDjrIv.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-BmVne-e2.js → Dashboard-DKtDo3yA.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-B4PkoOWd.js → Dropdown-RNx43_YG.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BZ6tyFtI.js → EmailListRenderer-SwMt4Rcy.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Osozn4Ds.js → FamilyGuardDashboard-CsYebZ4X.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DaH8TOAP.js → Federation-BmRKvBTy.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-tbU0uwis.js → FormItemContext-CVxGTA-0.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Df8LQBrL.js → GenericCardRenderer-x2iXpyB7.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DsMB6-14.js → Git-DfqbkiOP.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BnH0dZzd.js → Governance-RuHyyj5O.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DhnN1N_P.js → Inference-Bn7uZ7rI.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DnNshAgn.js → KnowledgeGraph-DlP7XefZ.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BmBFX3_N.js → Logs-BYNdOiCd.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DCslfQU3.js → MarkdownRenderer-aMtgN-R6.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-CPEgWDc3.js → Marketplace-JQYmDqM8.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-C36qjgF9.js → McpTools-Cyx4yZ-9.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-tNHvrgqN.js → Memory-VDuGZTN2.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Xaf6cKjc.js → MobileBridge-_yKo97gi.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-D2E5TTeO.js → MobileProjects-CXRXW3q7.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-D4AJ2dwV.js → Mtc-acTGtfLH.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-Df-gtn2_.js → MtcAudit-ClpjXfkY.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-DTCHLWld.js → Multisig-_6Tn3o96.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-DruZ_1Jb.js → NLProgramming-CK7pbZzP.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Dx3pdGDs.js → Notes-Czy6V_P8.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-Bi3L69oL.js → NotificationSettings-Cqx-UVv3.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BHY33m7C.js → OrderTableRenderer-C69WDxGy.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BG2ZVEV-.js → Organization-DFnA9vLQ.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Viwtg4Mn.js → Overflow-ReZkk2yT.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Clm_yc1Z.js → P2P-DzjSI0aI.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-NKmmDiOw.js → PdhVaultBrowser-DKTf5xIP.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-DIL8u9Nk.js → Permissions-DhQ5klhR.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-B-jM4wt-.js → PersonalDataHub-CUL1iHrW.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-627I__H5.js → Pipeline-DU88iu4N.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-2DN2qrkW.js → Privacy-Bw-sYfyK.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CN4wC0sF.js → ProjectInit-Bq3Q5y0z.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-K35vsh5H.js → ProjectSettings-C8spzpho.js} +2 -2
- package/src/assets/web-panel/assets/Projects-Dd-xuPIc.js +1 -0
- package/src/assets/web-panel/assets/{Providers-MckaQUhQ.js → Providers-Bf4eTP9W.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BS3mtA_O.js → QrScannerModal-Dme9BDU1.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BHp_nofL.js → QuickAsk-CIXfv1rE.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DlmnPuZj.js → Recommend-CIxvdeZ-.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-tsyFbvpy.js → RemoteSession-C6k7MExI.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-Ba1iWv2D.js → Reputation-CISDz2bl.js} +1 -1
- package/src/assets/web-panel/assets/{Row-NnlGC--f.js → Row-CdnDxXyf.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CjThSIRv.js → RssFeed-C-QpRHsl.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CojUyC5x.js → Search-DBjaGzSn.js} +1 -1
- package/src/assets/web-panel/assets/{Security-c-sxeJEc.js → Security-CQKukOeE.js} +3 -3
- package/src/assets/web-panel/assets/{Services-CtcKEEmF.js → Services-DZz86jWb.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CIBBXflN.js → Skeleton-jb8RMK0d.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-D1XOOK9n.js → Skills-CdY76fZG.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-hRfEp5Sn.js → Sla-C_CSiZX9.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-C7tT9iad.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-BJsSFGYy.js → SyncSettings-qvimGO0O.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CfSZ8A1L.js → Tasks-Dng5LPJC.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-idDf47W-.js → Templates-Bwqq5Wll.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-C-UsX6w6.js → Tenant-DNWuwP7Z.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BgJtX5n1.js → Terminal-B-6Othpp.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DP0BLKTl.js → TimelineRenderer-DKpKZfzx.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-LwCzqETp.js → Tokens-DzfGMd2J.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-D_9tVch0.js → Trigger-BXwUi74J.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BH2UlEWh.js → Trust-BNzUq4ui.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CIpD0nYb.js → UkeySign-BYugxww4.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-9ShhYxK_.js → VideoEditing-DdauhtSJ.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-C7afGNIG.js → Wallet-CSC9bCe_.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-bUKn6i5R.js → WebAuthn-Q8AN3bTO.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-CxgQaGyp.js → WorkflowEditor-d-LBGCuA.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DMVkmJwx.js → chat-BLVDCgsZ.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CDzQh5nS.js → colors-BZlPSEHl.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-C51kEF4D.js → compact-item-IWseP6R6.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BTk9bXBn.js → createContext-DnVRV3Ao.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Jzu62CLC.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CMje33rb.js → hasIn-DLQZA_Wn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBz9LIMS.js → index-1jeAudHd.js} +1 -1
- package/src/assets/web-panel/assets/{index-hg_emBsi.js → index-BEu2lMBy.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRG-aqOs.js → index-BOZJBTWZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDLkNkLj.js → index-BSjilZ9L.js} +1 -1
- package/src/assets/web-panel/assets/{index-CvSeVzqe.js → index-BZs5bBnk.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpcrFxMI.js → index-B_N4-Gq9.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9rC-fGW.js → index-Bbj2NS_I.js} +3 -3
- package/src/assets/web-panel/assets/{index-BVePe_Rf.js → index-BhA3QEni.js} +1 -1
- package/src/assets/web-panel/assets/{index-BzCkNylB.js → index-Bxp7uDD8.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAfY7m7i.js → index-C1ifZtXo.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTlsE8Df.js → index-C2FqfMvU.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqU9njjT.js → index-C5dgnilC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtlEqHLP.js → index-CINJQEj6.js} +1 -1
- package/src/assets/web-panel/assets/{index-BeEaAEIp.js → index-COev0W2g.js} +1 -1
- package/src/assets/web-panel/assets/{index-CCLj9hcD.js → index-CT9vVN-X.js} +1 -1
- package/src/assets/web-panel/assets/{index-h31MwrME.js → index-CZDekj7T.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ld_4mFmC.js → index-CarMTIyQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwGPwjUu.js → index-CbQNL0ue.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5IWTMVl.js → index-CpBaJ3TD.js} +1 -1
- package/src/assets/web-panel/assets/{index-BW4F5YDF.js → index-DB0MJgF_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CypsfcEq.js → index-DOoQpuQY.js} +1 -1
- package/src/assets/web-panel/assets/{index-CfC-piWZ.js → index-DTbxp4UH.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCRvG9lq.js → index-DUq0c7gq.js} +1 -1
- package/src/assets/web-panel/assets/{index-0Auljb10.js → index-DZpYeqrh.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4rQCS8T.js → index-D_LQodeJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CtM8OT_7.js → index-DalA0TKC.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1oZQmAA.js → index-DjWnONdy.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRLQyp2A.js → index-Dkwsi1Kn.js} +1 -1
- package/src/assets/web-panel/assets/{index-togc_uYn.js → index-DocEhinm.js} +1 -1
- package/src/assets/web-panel/assets/{index-x53Vf7la.js → index-DpVrK6fr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DgivOKHA.js → index-Dy0R5ZED.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0-zMtKA.js → index-M7wxfAbm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXQBPLyE.js → index-N_GoWZX4.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1oZReaY.js → index-YSw_gxlZ.js} +1 -1
- package/src/assets/web-panel/assets/index-Zb2MeDSy.js +1 -0
- package/src/assets/web-panel/assets/index-fikqml4k.js +1 -0
- package/src/assets/web-panel/assets/{index-Cd0hmPxD.js → index-gt8bNefW.js} +1 -1
- package/src/assets/web-panel/assets/{index-OS-vfbTA.js → index-hwVDeoC0.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJfnCuMq.js → index-jWb70ZgZ.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-vrA8K-ac.js → initDefaultProps-Co67Kqmb.js} +1 -1
- package/src/assets/web-panel/assets/{motion-ByEzwIAl.js → motion-BMOxQSF_.js} +1 -1
- package/src/assets/web-panel/assets/{move-Ck4AWjw-.js → move-C5fWDw-N.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-6p0l9SrB.js → mtc-parser-BJevpL0e.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B1CUPQ6R.js → omit-BCzNU8s6.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-B1STg1iW.js → pickAttrs-CybWvDPk.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DTTllkBV.js → placementArrow-BMWS9HnW.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-AIrrCfBb.js → responsiveObserve-BoL2UnGY.js} +1 -1
- package/src/assets/web-panel/assets/{slide-C_fPMjdR.js → slide-DWNfXraU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-D5ow2yIP.js → statusUtils-BquTM3tX.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Dy3hEA--.js → styleChecker-BEkCleim.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-WfzcfSh4.js → useFlexGapSupport-Oecnq7EA.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CKSejfas.js → useFs-CkDffJ4F.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-od3zpPBN.js → usePersonalDataHub-qbvKXesB.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DRD_2DFA.js → vnode-C6v8n6mA.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DmNrEtgf.js → zoom-4CTeFILV.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/command-manifest.json +1 -1
- package/src/commands/agenda.js +76 -4
- package/src/commands/automation.js +462 -3
- package/src/commands/background-session.js +102 -1
- package/src/commands/cowork.js +6 -1
- package/src/commands/loop.js +167 -36
- package/src/commands/routine.js +11 -4
- package/src/commands/scheduler-daemon.js +450 -0
- package/src/data/changelog.json +15 -2
- package/src/lib/agent-schedule-store.js +323 -43
- package/src/lib/automation-center-routines.js +363 -0
- package/src/lib/automation-center.js +435 -0
- package/src/lib/automation-engine.js +74 -19
- package/src/lib/automation-execution-authority.js +736 -0
- package/src/lib/background-agent-supervisor.js +78 -0
- package/src/lib/background-needs-input-incident.js +221 -0
- package/src/lib/cowork-cron.js +316 -18
- package/src/lib/cowork-observe.js +5 -1
- package/src/lib/loop.js +37 -2
- package/src/lib/permission-engine.js +14 -7
- package/src/lib/public-ide-capability-manifest.js +2 -0
- package/src/lib/routine-store.js +166 -65
- package/src/lib/scheduler-kernel/agenda-adapter.js +297 -27
- package/src/lib/scheduler-kernel/authority-resolver.js +163 -0
- package/src/lib/scheduler-kernel/automation-adapter.js +592 -0
- package/src/lib/scheduler-kernel/automation-event-adapter.js +721 -0
- package/src/lib/scheduler-kernel/contract.js +11 -3
- package/src/lib/scheduler-kernel/cowork-cron-adapter.js +58 -12
- package/src/lib/scheduler-kernel/loop-adapter.js +378 -0
- package/src/lib/scheduler-kernel/routine-adapter.js +303 -8
- package/src/lib/scheduler-kernel/service.js +328 -0
- package/src/lib/scheduler-kernel/store.js +828 -96
- package/src/runtime/agent-core.js +2 -1
- package/src/runtime/coding-agent-contract-shared.cjs +5 -0
- package/src/workers/background-agent-worker.js +91 -28
- package/src/assets/web-panel/assets/Projects-B_wQadhX.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-Dexb1f_6.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CdwPwYj8.js +0 -1
- package/src/assets/web-panel/assets/index-BEeOdfEe.js +0 -1
- package/src/assets/web-panel/assets/index-BTe0TOu6.js +0 -1
|
@@ -185,7 +185,9 @@ function applyScheduledAgentSuccess(entry, atMs) {
|
|
|
185
185
|
if (entry.kind === "cron") {
|
|
186
186
|
entry.lastRunAt = atMs;
|
|
187
187
|
entry.runs = (entry.runs || 0) + 1;
|
|
188
|
-
const next = nextCronTime(entry.cron, atMs
|
|
188
|
+
const next = nextCronTime(entry.cron, atMs, {
|
|
189
|
+
timeZone: entry.timeZone || null,
|
|
190
|
+
});
|
|
189
191
|
if (next == null) entry.status = "exhausted";
|
|
190
192
|
else entry.nextAt = next;
|
|
191
193
|
return;
|
|
@@ -196,6 +198,51 @@ function applyScheduledAgentSuccess(entry, atMs) {
|
|
|
196
198
|
);
|
|
197
199
|
}
|
|
198
200
|
|
|
201
|
+
function applyScheduledMonitorSuccess(entry, monitorCheck, atMs) {
|
|
202
|
+
if (
|
|
203
|
+
entry.kind !== "monitor" ||
|
|
204
|
+
!monitorCheck ||
|
|
205
|
+
typeof monitorCheck !== "object" ||
|
|
206
|
+
Array.isArray(monitorCheck) ||
|
|
207
|
+
typeof monitorCheck.matched !== "boolean"
|
|
208
|
+
) {
|
|
209
|
+
throw agendaStoreError(
|
|
210
|
+
"AGENDA_SCHEDULER_MONITOR_RESULT_INVALID",
|
|
211
|
+
`Scheduler monitor result is invalid: ${entry.id}`,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
const mtimeMs =
|
|
215
|
+
monitorCheck.mtimeMs === null || monitorCheck.mtimeMs === undefined
|
|
216
|
+
? null
|
|
217
|
+
: Number(monitorCheck.mtimeMs);
|
|
218
|
+
if (mtimeMs !== null && (!Number.isFinite(mtimeMs) || mtimeMs < 0)) {
|
|
219
|
+
throw agendaStoreError(
|
|
220
|
+
"AGENDA_SCHEDULER_MONITOR_RESULT_INVALID",
|
|
221
|
+
`Scheduler monitor mtime is invalid: ${entry.id}`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
entry.checks = (entry.checks || 0) + 1;
|
|
225
|
+
entry.lastCheckAt = atMs;
|
|
226
|
+
if (mtimeMs !== null && entry.lastMtimeMs == null) {
|
|
227
|
+
entry.lastMtimeMs = mtimeMs;
|
|
228
|
+
}
|
|
229
|
+
if (monitorCheck.matched) {
|
|
230
|
+
entry.status = "matched";
|
|
231
|
+
entry.matchedAt = atMs;
|
|
232
|
+
if (monitorCheck.eventId != null) {
|
|
233
|
+
entry.lastEventId = String(monitorCheck.eventId);
|
|
234
|
+
entry.lastEventAt = atMs;
|
|
235
|
+
}
|
|
236
|
+
if (monitorCheck.authority != null) {
|
|
237
|
+
entry.lastAuthority = String(monitorCheck.authority);
|
|
238
|
+
}
|
|
239
|
+
} else if (entry.maxChecks != null && entry.checks >= entry.maxChecks) {
|
|
240
|
+
entry.status = "exhausted";
|
|
241
|
+
} else {
|
|
242
|
+
entry.nextAt = atMs + entry.intervalMs;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
199
246
|
/** Statuses an entry can never leave — safe to prune. */
|
|
200
247
|
export const TERMINAL_STATUSES = Object.freeze([
|
|
201
248
|
"fired",
|
|
@@ -232,6 +279,61 @@ const CRON_RANGES = [
|
|
|
232
279
|
[0, 6], // day of week (0/7 = Sunday)
|
|
233
280
|
];
|
|
234
281
|
|
|
282
|
+
const CRON_TIME_ZONE_FORMATTERS = new Map();
|
|
283
|
+
|
|
284
|
+
export function normalizeTimeZone(value) {
|
|
285
|
+
if (value == null || value === "") return null;
|
|
286
|
+
if (typeof value !== "string") {
|
|
287
|
+
throw new Error("cron timeZone must be an IANA time zone string");
|
|
288
|
+
}
|
|
289
|
+
const requested = value.trim();
|
|
290
|
+
if (!requested) return null;
|
|
291
|
+
if (requested.length > 128 || /\p{Cc}/u.test(requested)) {
|
|
292
|
+
throw new Error("invalid IANA time zone");
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
296
|
+
timeZone: requested,
|
|
297
|
+
}).resolvedOptions().timeZone;
|
|
298
|
+
} catch {
|
|
299
|
+
throw new Error(`invalid IANA time zone: ${requested}`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function timeZoneFormatter(timeZone) {
|
|
304
|
+
let formatter = CRON_TIME_ZONE_FORMATTERS.get(timeZone);
|
|
305
|
+
if (!formatter) {
|
|
306
|
+
formatter = new Intl.DateTimeFormat("en-US-u-ca-gregory-nu-latn", {
|
|
307
|
+
timeZone,
|
|
308
|
+
year: "numeric",
|
|
309
|
+
month: "2-digit",
|
|
310
|
+
day: "2-digit",
|
|
311
|
+
hour: "2-digit",
|
|
312
|
+
minute: "2-digit",
|
|
313
|
+
hourCycle: "h23",
|
|
314
|
+
});
|
|
315
|
+
CRON_TIME_ZONE_FORMATTERS.set(timeZone, formatter);
|
|
316
|
+
}
|
|
317
|
+
return formatter;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function timeZoneParts(epochMs, timeZone) {
|
|
321
|
+
const values = {};
|
|
322
|
+
for (const part of timeZoneFormatter(timeZone).formatToParts(epochMs)) {
|
|
323
|
+
if (part.type !== "literal") values[part.type] = Number(part.value);
|
|
324
|
+
}
|
|
325
|
+
return {
|
|
326
|
+
year: values.year,
|
|
327
|
+
minute: values.minute,
|
|
328
|
+
hour: values.hour,
|
|
329
|
+
day: values.day,
|
|
330
|
+
month: values.month,
|
|
331
|
+
dayOfWeek: new Date(
|
|
332
|
+
Date.UTC(values.year, values.month - 1, values.day),
|
|
333
|
+
).getUTCDay(),
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
|
|
235
337
|
function parseCronField(field, [min, max]) {
|
|
236
338
|
const values = new Set();
|
|
237
339
|
for (const part of String(field).split(",")) {
|
|
@@ -280,13 +382,175 @@ function cronMatches(sets, date) {
|
|
|
280
382
|
);
|
|
281
383
|
}
|
|
282
384
|
|
|
385
|
+
function timeZoneOffsetAt(epochMs, timeZone) {
|
|
386
|
+
const minuteEpoch = Math.floor(epochMs / 60_000) * 60_000;
|
|
387
|
+
const parts = timeZoneParts(minuteEpoch, timeZone);
|
|
388
|
+
return (
|
|
389
|
+
Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute) -
|
|
390
|
+
minuteEpoch
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function localDayOffsets(year, month, day, timeZone) {
|
|
395
|
+
const reference = Date.UTC(year, month - 1, day, 12, 0, 0);
|
|
396
|
+
return [
|
|
397
|
+
...new Set(
|
|
398
|
+
[-36, -12, 0, 12, 36].map((hours) =>
|
|
399
|
+
timeZoneOffsetAt(reference + hours * 3_600_000, timeZone),
|
|
400
|
+
),
|
|
401
|
+
),
|
|
402
|
+
];
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function epochCandidatesForCivilMinute(
|
|
406
|
+
{ year, month, day, hour, minute },
|
|
407
|
+
timeZone,
|
|
408
|
+
offsets,
|
|
409
|
+
) {
|
|
410
|
+
const civilEpoch = Date.UTC(year, month - 1, day, hour, minute, 0);
|
|
411
|
+
const matches = [];
|
|
412
|
+
for (const offset of offsets) {
|
|
413
|
+
const epoch = civilEpoch - offset;
|
|
414
|
+
const actual = timeZoneParts(epoch, timeZone);
|
|
415
|
+
if (
|
|
416
|
+
actual.year === year &&
|
|
417
|
+
actual.month === month &&
|
|
418
|
+
actual.day === day &&
|
|
419
|
+
actual.hour === hour &&
|
|
420
|
+
actual.minute === minute
|
|
421
|
+
) {
|
|
422
|
+
matches.push(epoch);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return [...new Set(matches)].sort((a, b) => a - b);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function nextCronTimeInTimeZone(sets, fromMs, timeZone) {
|
|
429
|
+
const from = Number(fromMs);
|
|
430
|
+
const firstLocal = timeZoneParts(from, timeZone);
|
|
431
|
+
const firstLocalDay = Date.UTC(
|
|
432
|
+
firstLocal.year,
|
|
433
|
+
firstLocal.month - 1,
|
|
434
|
+
firstLocal.day,
|
|
435
|
+
);
|
|
436
|
+
const minuteLimit = 366 * 24 * 60;
|
|
437
|
+
const lastEpoch = Math.floor(from / 60_000) * 60_000 + minuteLimit * 60_000;
|
|
438
|
+
const hours = [...sets[1]].sort((a, b) => a - b);
|
|
439
|
+
const minutes = [...sets[0]].sort((a, b) => a - b);
|
|
440
|
+
let earliest = null;
|
|
441
|
+
|
|
442
|
+
// Iterate civil dates instead of formatting every real minute. At most two
|
|
443
|
+
// UTC offsets can map a civil minute around a DST transition; verifying each
|
|
444
|
+
// reconstructed candidate preserves missing and repeated wall-time behavior.
|
|
445
|
+
// Start one civil day earlier because a rare midnight rollback can make a
|
|
446
|
+
// future real instant display as the previous local date. Once a later civil
|
|
447
|
+
// date is more than 36 hours beyond the best epoch, no supported IANA offset
|
|
448
|
+
// can map that date back before the current best candidate.
|
|
449
|
+
for (let dayOffset = -1; dayOffset <= 367; dayOffset += 1) {
|
|
450
|
+
const civilDay = firstLocalDay + dayOffset * 86_400_000;
|
|
451
|
+
if (earliest != null && civilDay - 36 * 3_600_000 > earliest) break;
|
|
452
|
+
const date = new Date(civilDay);
|
|
453
|
+
const year = date.getUTCFullYear();
|
|
454
|
+
const month = date.getUTCMonth() + 1;
|
|
455
|
+
const day = date.getUTCDate();
|
|
456
|
+
const dayOfWeek = date.getUTCDay();
|
|
457
|
+
if (
|
|
458
|
+
!sets[2].has(day) ||
|
|
459
|
+
!sets[3].has(month) ||
|
|
460
|
+
(!sets[4].has(dayOfWeek) && !(sets[4].has(7) && dayOfWeek === 0))
|
|
461
|
+
) {
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
const offsets = localDayOffsets(year, month, day, timeZone);
|
|
465
|
+
for (const hour of hours) {
|
|
466
|
+
for (const minute of minutes) {
|
|
467
|
+
for (const epoch of epochCandidatesForCivilMinute(
|
|
468
|
+
{ year, month, day, hour, minute },
|
|
469
|
+
timeZone,
|
|
470
|
+
offsets,
|
|
471
|
+
)) {
|
|
472
|
+
if (
|
|
473
|
+
epoch > from &&
|
|
474
|
+
epoch <= lastEpoch &&
|
|
475
|
+
(earliest == null || epoch < earliest)
|
|
476
|
+
) {
|
|
477
|
+
earliest = epoch;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return earliest;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function previousCronTimeInTimeZone(sets, fromMs, timeZone) {
|
|
487
|
+
const from = Number(fromMs);
|
|
488
|
+
const firstLocal = timeZoneParts(from, timeZone);
|
|
489
|
+
const firstLocalDay = Date.UTC(
|
|
490
|
+
firstLocal.year,
|
|
491
|
+
firstLocal.month - 1,
|
|
492
|
+
firstLocal.day,
|
|
493
|
+
);
|
|
494
|
+
const minuteLimit = 366 * 24 * 60;
|
|
495
|
+
const firstEpoch = Math.floor(from / 60_000) * 60_000 - minuteLimit * 60_000;
|
|
496
|
+
const hours = [...sets[1]].sort((a, b) => b - a);
|
|
497
|
+
const minutes = [...sets[0]].sort((a, b) => b - a);
|
|
498
|
+
let latest = null;
|
|
499
|
+
|
|
500
|
+
// Start one civil day ahead because a rare midnight transition can make a
|
|
501
|
+
// prior real instant display as the following local date.
|
|
502
|
+
for (let dayOffset = 1; dayOffset >= -367; dayOffset -= 1) {
|
|
503
|
+
const civilDay = firstLocalDay + dayOffset * 86_400_000;
|
|
504
|
+
if (latest != null && civilDay + 36 * 3_600_000 < latest) break;
|
|
505
|
+
const date = new Date(civilDay);
|
|
506
|
+
const year = date.getUTCFullYear();
|
|
507
|
+
const month = date.getUTCMonth() + 1;
|
|
508
|
+
const day = date.getUTCDate();
|
|
509
|
+
const dayOfWeek = date.getUTCDay();
|
|
510
|
+
if (
|
|
511
|
+
!sets[2].has(day) ||
|
|
512
|
+
!sets[3].has(month) ||
|
|
513
|
+
(!sets[4].has(dayOfWeek) && !(sets[4].has(7) && dayOfWeek === 0))
|
|
514
|
+
) {
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
const offsets = localDayOffsets(year, month, day, timeZone);
|
|
518
|
+
for (const hour of hours) {
|
|
519
|
+
for (const minute of minutes) {
|
|
520
|
+
for (const epoch of epochCandidatesForCivilMinute(
|
|
521
|
+
{ year, month, day, hour, minute },
|
|
522
|
+
timeZone,
|
|
523
|
+
offsets,
|
|
524
|
+
)) {
|
|
525
|
+
if (
|
|
526
|
+
epoch < from &&
|
|
527
|
+
epoch >= firstEpoch &&
|
|
528
|
+
(latest == null || epoch > latest)
|
|
529
|
+
) {
|
|
530
|
+
latest = epoch;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return latest;
|
|
537
|
+
}
|
|
538
|
+
|
|
283
539
|
/**
|
|
284
|
-
* Next epoch-ms at which `expr` fires strictly after `fromMs
|
|
285
|
-
*
|
|
286
|
-
*
|
|
540
|
+
* Next epoch-ms at which `expr` fires strictly after `fromMs`, at minute
|
|
541
|
+
* granularity. By default this preserves host-local cron behavior; an explicit
|
|
542
|
+
* IANA `timeZone` evaluates the same epoch minutes against that civil clock.
|
|
543
|
+
* A repeated fall-back wall minute therefore maps to both real instants, while
|
|
544
|
+
* a skipped spring-forward wall minute does not exist. Scans up to ~366 days
|
|
545
|
+
* then gives up (returns null) so a never-matching expression can't loop
|
|
546
|
+
* forever.
|
|
287
547
|
*/
|
|
288
|
-
export function nextCronTime(expr, fromMs) {
|
|
548
|
+
export function nextCronTime(expr, fromMs, options = {}) {
|
|
289
549
|
const sets = parseCron(expr);
|
|
550
|
+
const timeZone = normalizeTimeZone(
|
|
551
|
+
typeof options === "string" ? options : options?.timeZone,
|
|
552
|
+
);
|
|
553
|
+
if (timeZone) return nextCronTimeInTimeZone(sets, fromMs, timeZone);
|
|
290
554
|
const cursor = new Date(fromMs);
|
|
291
555
|
cursor.setSeconds(0, 0);
|
|
292
556
|
cursor.setMinutes(cursor.getMinutes() + 1);
|
|
@@ -298,6 +562,25 @@ export function nextCronTime(expr, fromMs) {
|
|
|
298
562
|
return null;
|
|
299
563
|
}
|
|
300
564
|
|
|
565
|
+
/** Previous cron occurrence strictly before `fromMs`, bounded to one year. */
|
|
566
|
+
export function previousCronTime(expr, fromMs, options = {}) {
|
|
567
|
+
const sets = parseCron(expr);
|
|
568
|
+
const timeZone = normalizeTimeZone(
|
|
569
|
+
typeof options === "string" ? options : options?.timeZone,
|
|
570
|
+
);
|
|
571
|
+
if (timeZone) return previousCronTimeInTimeZone(sets, fromMs, timeZone);
|
|
572
|
+
const cursor = new Date(fromMs);
|
|
573
|
+
cursor.setSeconds(0, 0);
|
|
574
|
+
if (cursor.getTime() >= Number(fromMs))
|
|
575
|
+
cursor.setMinutes(cursor.getMinutes() - 1);
|
|
576
|
+
const limit = 366 * 24 * 60;
|
|
577
|
+
for (let i = 0; i < limit; i += 1) {
|
|
578
|
+
if (cronMatches(sets, cursor)) return cursor.getTime();
|
|
579
|
+
cursor.setMinutes(cursor.getMinutes() - 1);
|
|
580
|
+
}
|
|
581
|
+
return null;
|
|
582
|
+
}
|
|
583
|
+
|
|
301
584
|
// ─── store ───────────────────────────────────────────────────────────────
|
|
302
585
|
|
|
303
586
|
export class AgentScheduleStore {
|
|
@@ -390,12 +673,16 @@ export class AgentScheduleStore {
|
|
|
390
673
|
expiresAt = null,
|
|
391
674
|
expiresInMs = null,
|
|
392
675
|
jitterMs = 0,
|
|
676
|
+
timeZone = null,
|
|
393
677
|
} = options;
|
|
394
678
|
if (!prompt || typeof prompt !== "string") {
|
|
395
679
|
throw new Error("cron requires a prompt");
|
|
396
680
|
}
|
|
397
681
|
const now = this._now();
|
|
398
|
-
const
|
|
682
|
+
const normalizedTimeZone = normalizeTimeZone(timeZone);
|
|
683
|
+
const nextAt = nextCronTime(cron, now, {
|
|
684
|
+
timeZone: normalizedTimeZone,
|
|
685
|
+
}); // validates the expression and optional IANA time zone
|
|
399
686
|
if (nextAt == null) {
|
|
400
687
|
throw new Error(`cron "${cron}" has no upcoming match`);
|
|
401
688
|
}
|
|
@@ -406,6 +693,7 @@ export class AgentScheduleStore {
|
|
|
406
693
|
kind: "cron",
|
|
407
694
|
prompt,
|
|
408
695
|
cron,
|
|
696
|
+
...(normalizedTimeZone ? { timeZone: normalizedTimeZone } : {}),
|
|
409
697
|
label: label || null,
|
|
410
698
|
nextAt,
|
|
411
699
|
expiresAt: resolveExpiresAt(expiresAt, expiresInMs, now),
|
|
@@ -609,7 +897,7 @@ export class AgentScheduleStore {
|
|
|
609
897
|
}
|
|
610
898
|
|
|
611
899
|
/**
|
|
612
|
-
* Bind a scheduler claim to the legacy Agenda entry before
|
|
900
|
+
* Bind a scheduler claim to the legacy Agenda entry before execution.
|
|
613
901
|
* The same lock used by legacy `claimDue()` prevents an old/new driver from
|
|
614
902
|
* starting the entry concurrently during migration.
|
|
615
903
|
*/
|
|
@@ -640,7 +928,7 @@ export class AgentScheduleStore {
|
|
|
640
928
|
return withFileLock(
|
|
641
929
|
path.join(this.dir, ".agenda-claims"),
|
|
642
930
|
() => {
|
|
643
|
-
for (const kind of
|
|
931
|
+
for (const kind of SCHEDULE_KINDS) {
|
|
644
932
|
const entries = this._readAll(kind);
|
|
645
933
|
const entry = entries.find((candidate) => candidate.id === id);
|
|
646
934
|
if (!entry) continue;
|
|
@@ -678,7 +966,8 @@ export class AgentScheduleStore {
|
|
|
678
966
|
// Fence an older CLI that only understands the legacy claim field.
|
|
679
967
|
// Terminal scheduler evidence clears this lease; an outcome-unknown
|
|
680
968
|
// execution intentionally keeps it non-expiring until adjudicated so
|
|
681
|
-
// an old runner cannot duplicate an uncertain
|
|
969
|
+
// an old runner cannot duplicate an uncertain external observation or
|
|
970
|
+
// agent side effect.
|
|
682
971
|
entry.executionLease = {
|
|
683
972
|
owner: `scheduler:${occurrenceId}:${attempt}`,
|
|
684
973
|
claimedAt: now,
|
|
@@ -697,10 +986,10 @@ export class AgentScheduleStore {
|
|
|
697
986
|
}
|
|
698
987
|
|
|
699
988
|
/**
|
|
700
|
-
* Atomically publish scheduler evidence and the legacy
|
|
701
|
-
*
|
|
702
|
-
*
|
|
703
|
-
*
|
|
989
|
+
* Atomically publish scheduler evidence and the legacy Agenda state. A
|
|
990
|
+
* successful cron advances and a successful monitor records/re-arms exactly
|
|
991
|
+
* once in the same JSONL replacement that records terminal evidence;
|
|
992
|
+
* failures keep the entry schedulable for the kernel's bounded retry policy.
|
|
704
993
|
*/
|
|
705
994
|
completeSchedulerExecution(
|
|
706
995
|
id,
|
|
@@ -711,6 +1000,7 @@ export class AgentScheduleStore {
|
|
|
711
1000
|
outcome,
|
|
712
1001
|
result = null,
|
|
713
1002
|
error = null,
|
|
1003
|
+
monitorCheck = null,
|
|
714
1004
|
atMs = null,
|
|
715
1005
|
} = {},
|
|
716
1006
|
) {
|
|
@@ -725,7 +1015,7 @@ export class AgentScheduleStore {
|
|
|
725
1015
|
return withFileLock(
|
|
726
1016
|
path.join(this.dir, ".agenda-claims"),
|
|
727
1017
|
() => {
|
|
728
|
-
for (const kind of
|
|
1018
|
+
for (const kind of SCHEDULE_KINDS) {
|
|
729
1019
|
const entries = this._readAll(kind);
|
|
730
1020
|
const entry = entries.find((candidate) => candidate.id === id);
|
|
731
1021
|
if (!entry) continue;
|
|
@@ -742,14 +1032,23 @@ export class AgentScheduleStore {
|
|
|
742
1032
|
`Agenda scheduler evidence does not match the active claim: ${id}`,
|
|
743
1033
|
);
|
|
744
1034
|
}
|
|
1035
|
+
let storedResult = result;
|
|
745
1036
|
if (outcome === "succeeded") {
|
|
746
|
-
|
|
1037
|
+
if (entry.kind === "monitor") {
|
|
1038
|
+
applyScheduledMonitorSuccess(entry, monitorCheck, now);
|
|
1039
|
+
storedResult =
|
|
1040
|
+
result && typeof result === "object" && !Array.isArray(result)
|
|
1041
|
+
? { ...result, status: entry.status }
|
|
1042
|
+
: result;
|
|
1043
|
+
} else {
|
|
1044
|
+
applyScheduledAgentSuccess(entry, now);
|
|
1045
|
+
}
|
|
747
1046
|
}
|
|
748
1047
|
entry.schedulerExecution = {
|
|
749
1048
|
...evidence,
|
|
750
1049
|
status: outcome,
|
|
751
1050
|
endedAt: now,
|
|
752
|
-
...(outcome === "succeeded" ? { result } : { error }),
|
|
1051
|
+
...(outcome === "succeeded" ? { result: storedResult } : { error }),
|
|
753
1052
|
};
|
|
754
1053
|
delete entry.executionLease;
|
|
755
1054
|
this._writeAll(kind, entries);
|
|
@@ -841,7 +1140,9 @@ export class AgentScheduleStore {
|
|
|
841
1140
|
return this._mutate("cron", id, (entry) => {
|
|
842
1141
|
entry.lastRunAt = now;
|
|
843
1142
|
entry.runs = (entry.runs || 0) + 1;
|
|
844
|
-
const next = nextCronTime(entry.cron, now
|
|
1143
|
+
const next = nextCronTime(entry.cron, now, {
|
|
1144
|
+
timeZone: entry.timeZone || null,
|
|
1145
|
+
});
|
|
845
1146
|
if (next == null) {
|
|
846
1147
|
entry.status = "exhausted";
|
|
847
1148
|
} else {
|
|
@@ -866,32 +1167,11 @@ export class AgentScheduleStore {
|
|
|
866
1167
|
) {
|
|
867
1168
|
const now = atMs != null ? atMs : this._now();
|
|
868
1169
|
return this._mutate("monitor", id, (entry) => {
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
if (mtimeMs != null && entry.lastMtimeMs == null) {
|
|
875
|
-
entry.lastMtimeMs = mtimeMs;
|
|
876
|
-
}
|
|
877
|
-
if (matched) {
|
|
878
|
-
entry.status = "matched";
|
|
879
|
-
entry.matchedAt = now;
|
|
880
|
-
// Audit record of the firing: the deterministic monitor-event id + the
|
|
881
|
-
// (always SYSTEM/steer) authority the event was delivered under. Durable
|
|
882
|
-
// on the entry so `cc agenda list --json` and a future resident daemon
|
|
883
|
-
// can recognise / dedup the exact observation. Only stamped when the
|
|
884
|
-
// caller supplies them, so legacy callers stay byte-identical.
|
|
885
|
-
if (eventId != null) {
|
|
886
|
-
entry.lastEventId = String(eventId);
|
|
887
|
-
entry.lastEventAt = now;
|
|
888
|
-
}
|
|
889
|
-
if (authority != null) entry.lastAuthority = String(authority);
|
|
890
|
-
} else if (entry.maxChecks != null && entry.checks >= entry.maxChecks) {
|
|
891
|
-
entry.status = "exhausted";
|
|
892
|
-
} else {
|
|
893
|
-
entry.nextAt = now + entry.intervalMs;
|
|
894
|
-
}
|
|
1170
|
+
applyScheduledMonitorSuccess(
|
|
1171
|
+
entry,
|
|
1172
|
+
{ matched: Boolean(matched), mtimeMs, eventId, authority },
|
|
1173
|
+
now,
|
|
1174
|
+
);
|
|
895
1175
|
});
|
|
896
1176
|
}
|
|
897
1177
|
|