chainlesschain 0.163.4 → 0.163.5
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-DB5X7qqV.js → AIOps-Cv2EE1Zy.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DxHRtKLk.js → ActionButton-CcpxMLuW.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DIH5QrxT.js → Analytics-DE8mJoMI.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-uu0oxVz7.js → AppLayout-DKn9dk9L.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BNSMiW9Y.js → Artifacts-Cp3mG3Py.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DcAzB4_x.js → Audit-zvsQfF2C.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-ClSsvjIc.js → BackgroundAgents-Bi85SsjN.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BMciY0js.js → Backup-Cw47Dj6s.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Hn3b57Sh.js → BaseInput-C5Ip2afH.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CoSlC53V.js → Chat-C0iAFkJv.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CFevJ3So.js → ChatBubbleRenderer-BV9Wv7wO.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-B4L4Eu4w.js → Checkbox-3KZZCiAF.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-C77FgRxF.js → Codegen-C8OMbBAz.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BrLtJLH3.js → Col-B-MB84LJ.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Be7pXXhA.js → Community-DpR7Dxao.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DuGPecjo.js → Compact-CyDtz0OS.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CzS66mjP.js → Compliance-5tiRa2An.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CEhjCoyK.js → Cowork-DnQaKZ5x.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-D7ir8Vja.js → Cron-BaWfoEDf.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BcXmuLxf.js → Crosschain-Bu0HoHhb.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Cto1dtBy.js → DID-31zk8upX.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B7KjgwOX.js → Dashboard-BmVne-e2.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-COMqxijg.js → Dropdown-B4PkoOWd.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BZrya-nf.js → EmailListRenderer-BZ6tyFtI.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-AmVeMq0J.js → FamilyGuardDashboard-Osozn4Ds.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-kZU8c-27.js → Federation-DaH8TOAP.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-sOV22v2-.js → FormItemContext-tbU0uwis.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BUuLtGCz.js → GenericCardRenderer-Df8LQBrL.js} +1 -1
- package/src/assets/web-panel/assets/{Git-K-ZxsLsH.js → Git-DsMB6-14.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D3OEnawI.js → Governance-BnH0dZzd.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Bll0gRmP.js → Inference-DhnN1N_P.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DBXwjr53.js → KnowledgeGraph-DnNshAgn.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CEzPwEfP.js → Logs-BmBFX3_N.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-DCslfQU3.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-BYyRyOPz.js → Marketplace-CPEgWDc3.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DVu8w_rM.js → McpTools-C36qjgF9.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-tenuZ_hO.js → Memory-tNHvrgqN.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Bxgy4ozS.js → MobileBridge-Xaf6cKjc.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Dgx1D6sc.js → MobileProjects-D2E5TTeO.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CRfJ8r8j.js → Mtc-D4AJ2dwV.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BBJq4Aiz.js → MtcAudit-Df-gtn2_.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-B3ii9lai.js → Multisig-DTCHLWld.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-FIi-Cubv.js → NLProgramming-DruZ_1Jb.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DIq8MPf1.js → Notes-Dx3pdGDs.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-BFOD9eGd.js → NotificationSettings-Bi3L69oL.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer--41u7vre.js → OrderTableRenderer-BHY33m7C.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-B_0AWztW.js → Organization-BG2ZVEV-.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-B6I7TuXv.js → Overflow-Viwtg4Mn.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Cdf6qens.js → P2P-Clm_yc1Z.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-B_0FcQJY.js → PdhVaultBrowser-NKmmDiOw.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-6nFBjsQp.js → Permissions-DIL8u9Nk.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-nQYV7xpn.js → PersonalDataHub-B-jM4wt-.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-CBVod5jm.js → Pipeline-627I__H5.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-D52jW1Nt.js → Privacy-2DN2qrkW.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bdx3BYhf.js → ProjectInit-CN4wC0sF.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-b7xr4DUa.js → ProjectSettings-K35vsh5H.js} +2 -2
- package/src/assets/web-panel/assets/Projects-B_wQadhX.js +1 -0
- package/src/assets/web-panel/assets/Providers-MckaQUhQ.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-FQKSmc3e.js → QrScannerModal-BS3mtA_O.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CSTrhzcF.js → QuickAsk-BHp_nofL.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CxMABOUh.js → Recommend-DlmnPuZj.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Cv2T8yRa.js → RemoteSession-tsyFbvpy.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CE1k4Vvu.js → Reputation-Ba1iWv2D.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BNgNcAV_.js → Row-NnlGC--f.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-5ZiBZ3ph.js → RssFeed-CjThSIRv.js} +3 -3
- package/src/assets/web-panel/assets/{Search-mDOIF1UV.js → Search-CojUyC5x.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CtuCTC-e.js → Security-c-sxeJEc.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DxFO2Zg7.js → Services-CtcKEEmF.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CKmKkH9y.js → Skeleton-CIBBXflN.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-Bmzl9qkk.js → Skills-D1XOOK9n.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-9RqaWHOC.js → Sla-hRfEp5Sn.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CGdzFIYw.js → SpeechSettings-Dexb1f_6.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CvNuCeBT.js → SyncSettings-BJsSFGYy.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-B_sLdcnw.js → Tasks-CfSZ8A1L.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D9_YijdK.js → Templates-idDf47W-.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Cuc7BUSP.js → Tenant-C-UsX6w6.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-6VYRnJgd.js → Terminal-BgJtX5n1.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-GtK8xd8Y.js → TimelineRenderer-DP0BLKTl.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BZ94Lt5W.js → Tokens-LwCzqETp.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DEcZgDaX.js → Trigger-D_9tVch0.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CC3z9THe.js → Trust-BH2UlEWh.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Cvtw8cV3.js → UkeySign-CIpD0nYb.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CL4e6Bn3.js → VideoEditing-9ShhYxK_.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-ycEemP27.js → Wallet-C7afGNIG.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DgZ4X_aw.js → WebAuthn-bUKn6i5R.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-D0qMhSv7.js → WorkflowEditor-CxgQaGyp.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DsAg01Zn.js → chat-DMVkmJwx.js} +1 -1
- package/src/assets/web-panel/assets/{colors-B0oqAhrQ.js → colors-CDzQh5nS.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CmX0Rabz.js → compact-item-C51kEF4D.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Be4cn1Ub.js → createContext-BTk9bXBn.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CdwPwYj8.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D5v12kVq.js → hasIn-CMje33rb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyyGTMKd.js → index-0Auljb10.js} +1 -1
- package/src/assets/web-panel/assets/{index-frSojpHj.js → index-B0-zMtKA.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3mUHuVc.js → index-BAfY7m7i.js} +1 -1
- package/src/assets/web-panel/assets/{index-BA4oulaP.js → index-BBz9LIMS.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1YGjOWC.js → index-BCRvG9lq.js} +1 -1
- package/src/assets/web-panel/assets/index-BEeOdfEe.js +1 -0
- package/src/assets/web-panel/assets/index-BTe0TOu6.js +1 -0
- package/src/assets/web-panel/assets/{index-BBvyHguy.js → index-BTlsE8Df.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGiIyTZw.js → index-BVePe_Rf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBREnn1V.js → index-BW4F5YDF.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0BSkxYQ.js → index-BXQBPLyE.js} +1 -1
- package/src/assets/web-panel/assets/{index-0eWLkQKT.js → index-BeEaAEIp.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5YVopyr.js → index-BtlEqHLP.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKmsS2jj.js → index-BzCkNylB.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaE0Ui07.js → index-C1oZQmAA.js} +1 -1
- package/src/assets/web-panel/assets/{index-8WvYGnON.js → index-C1oZReaY.js} +1 -1
- package/src/assets/web-panel/assets/{index-_JjRLSD0.js → index-C4rQCS8T.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKUBj36_.js → index-C5IWTMVl.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoAIAZ5C.js → index-CCLj9hcD.js} +1 -1
- package/src/assets/web-panel/assets/{index-DikJ0Qqe.js → index-CDLkNkLj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Hfe_dEGx.js → index-Cd0hmPxD.js} +1 -1
- package/src/assets/web-panel/assets/{index-jK3ax6Z6.js → index-CfC-piWZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyUaFWEk.js → index-CtM8OT_7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqltWojQ.js → index-CvSeVzqe.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dn2dSdXx.js → index-CwGPwjUu.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRIqLy1m.js → index-CypsfcEq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXGSbelg.js → index-D9rC-fGW.js} +3 -3
- package/src/assets/web-panel/assets/{index-CZpfzcuy.js → index-DJfnCuMq.js} +1 -1
- package/src/assets/web-panel/assets/{index-5LGY0JbG.js → index-DRG-aqOs.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyWBir7N.js → index-DRLQyp2A.js} +1 -1
- package/src/assets/web-panel/assets/{index-DQRsQen0.js → index-DgivOKHA.js} +1 -1
- package/src/assets/web-panel/assets/{index-7VKDn-t1.js → index-DpcrFxMI.js} +1 -1
- package/src/assets/web-panel/assets/{index-q_fQ94SE.js → index-DqU9njjT.js} +1 -1
- package/src/assets/web-panel/assets/{index-301ogenv.js → index-Ld_4mFmC.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZ2wUEgr.js → index-OS-vfbTA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqoCZ5vR.js → index-h31MwrME.js} +1 -1
- package/src/assets/web-panel/assets/{index-DM724NgU.js → index-hg_emBsi.js} +1 -1
- package/src/assets/web-panel/assets/{index-qMuZ-NRR.js → index-togc_uYn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ckrk3pIV.js → index-x53Vf7la.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-D4VdhJ9_.js → initDefaultProps-vrA8K-ac.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CZJA0MQW.js → motion-ByEzwIAl.js} +1 -1
- package/src/assets/web-panel/assets/{move-BqEs7Sb1.js → move-Ck4AWjw-.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BpHEtsu1.js → mtc-parser-6p0l9SrB.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BW94tY9W.js → omit-B1CUPQ6R.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BnBjPWP9.js → pickAttrs-B1STg1iW.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-uUkjQ_hu.js → placementArrow-DTTllkBV.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B-klUqXK.js → responsiveObserve-AIrrCfBb.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CvY1cNAs.js → slide-C_fPMjdR.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Ix5sEDT2.js → statusUtils-D5ow2yIP.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-C8qcXOne.js → styleChecker-Dy3hEA--.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-KNF6Kj8f.js → useFlexGapSupport-WfzcfSh4.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DGJr345n.js → useFs-CKSejfas.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BboN99rI.js → usePersonalDataHub-od3zpPBN.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Bgt8Vgte.js → vnode-DRD_2DFA.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BhJtErgt.js → zoom-DmNrEtgf.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +52 -6
- package/src/commands/cowork.js +24 -12
- package/src/commands/routine.js +40 -10
- package/src/data/changelog.json +13 -0
- package/src/lib/agent-schedule-store.js +197 -4
- package/src/lib/cowork-cron.js +243 -25
- package/src/lib/micro-compact.js +11 -5
- package/src/lib/process-execution-broker/index.js +14 -3
- package/src/lib/routine-store.js +76 -3
- package/src/lib/scheduler-kernel/agenda-adapter.js +542 -0
- package/src/lib/scheduler-kernel/cowork-cron-adapter.js +774 -0
- package/src/lib/scheduler-kernel/routine-adapter.js +517 -0
- package/src/lib/scheduler-kernel/runtime.js +527 -0
- package/src/lib/scheduler-kernel/store.js +112 -2
- package/src/lib/session-message-provenance.js +4 -1
- package/src/repl/agent-repl.js +24 -5
- package/src/runtime/agent-core.js +36 -16
- package/src/assets/web-panel/assets/MarkdownRenderer-CLmCbHx6.js +0 -1
- package/src/assets/web-panel/assets/Projects-DhfifCKx.js +0 -1
- package/src/assets/web-panel/assets/Providers-Dy_PgDMr.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CP2qzG6D.js +0 -1
- package/src/assets/web-panel/assets/index-CKB0vbJU.js +0 -1
- package/src/assets/web-panel/assets/index-DgoXmwqB.js +0 -1
package/src/lib/cowork-cron.js
CHANGED
|
@@ -53,6 +53,33 @@ export const _deps = {
|
|
|
53
53
|
runTask: null, // injected at runtime to avoid circular import
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
+
export const COWORK_SCHEDULER_UNKNOWN_LEASE_EXPIRES_AT =
|
|
57
|
+
"9999-12-31T23:59:59.999Z";
|
|
58
|
+
|
|
59
|
+
function coworkSchedulerError(
|
|
60
|
+
code,
|
|
61
|
+
message,
|
|
62
|
+
{ retryable = false, retryAt } = {},
|
|
63
|
+
) {
|
|
64
|
+
const error = new Error(message);
|
|
65
|
+
error.code = code;
|
|
66
|
+
error.retryable = retryable;
|
|
67
|
+
if (retryAt !== undefined) error.retryAt = retryAt;
|
|
68
|
+
return error;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function normalizedDate(value, label) {
|
|
72
|
+
const date =
|
|
73
|
+
value instanceof Date ? new Date(value.getTime()) : new Date(value);
|
|
74
|
+
if (!Number.isFinite(date.getTime())) {
|
|
75
|
+
throw coworkSchedulerError(
|
|
76
|
+
"COWORK_SCHEDULER_TIME_INVALID",
|
|
77
|
+
`${label} must be a valid date`,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
return date;
|
|
81
|
+
}
|
|
82
|
+
|
|
56
83
|
// ─── Cron parser ─────────────────────────────────────────────────────────────
|
|
57
84
|
|
|
58
85
|
const FIELD_RANGES = [
|
|
@@ -293,9 +320,7 @@ function _withScheduleLock(cwd, body) {
|
|
|
293
320
|
|
|
294
321
|
/** Atomically replace the full schedule list under a fail-closed lock. */
|
|
295
322
|
export function saveSchedules(cwd, schedules) {
|
|
296
|
-
return _withScheduleLock(cwd, () =>
|
|
297
|
-
_saveSchedulesUnlocked(cwd, schedules),
|
|
298
|
-
);
|
|
323
|
+
return _withScheduleLock(cwd, () => _saveSchedulesUnlocked(cwd, schedules));
|
|
299
324
|
}
|
|
300
325
|
|
|
301
326
|
// ─── CRUD ────────────────────────────────────────────────────────────────────
|
|
@@ -363,6 +388,191 @@ export function updateScheduleRunState(cwd, id, { lastRunAt, lastStatus }) {
|
|
|
363
388
|
});
|
|
364
389
|
}
|
|
365
390
|
|
|
391
|
+
/** Return one schedule by id, or null when it does not exist. */
|
|
392
|
+
export function getSchedule(cwd, id) {
|
|
393
|
+
if (typeof id !== "string" || id.length === 0) return null;
|
|
394
|
+
return (
|
|
395
|
+
loadSchedules(cwd, { failOnMalformed: true }).find(
|
|
396
|
+
(schedule) => schedule.id === id,
|
|
397
|
+
) || null
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Bind a scheduler-kernel occurrence before starting the Cowork task.
|
|
403
|
+
* The same JSONL lock used by the legacy driver closes both old-first and
|
|
404
|
+
* new-first claim races during migration.
|
|
405
|
+
*/
|
|
406
|
+
export function bindSchedulerScheduleFire(
|
|
407
|
+
cwd,
|
|
408
|
+
id,
|
|
409
|
+
{ deliveryId, occurrenceId, snapshotDigest, attempt, at = _deps.now() } = {},
|
|
410
|
+
) {
|
|
411
|
+
if (
|
|
412
|
+
typeof deliveryId !== "string" ||
|
|
413
|
+
typeof occurrenceId !== "string" ||
|
|
414
|
+
typeof snapshotDigest !== "string" ||
|
|
415
|
+
deliveryId.length === 0 ||
|
|
416
|
+
occurrenceId.length === 0 ||
|
|
417
|
+
snapshotDigest.length === 0 ||
|
|
418
|
+
!Number.isSafeInteger(attempt) ||
|
|
419
|
+
attempt < 1
|
|
420
|
+
) {
|
|
421
|
+
throw coworkSchedulerError(
|
|
422
|
+
"COWORK_SCHEDULER_BINDING_INVALID",
|
|
423
|
+
"Cowork scheduler binding requires deliveryId, occurrenceId, snapshotDigest, and a positive attempt",
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
const now = normalizedDate(at, "cowork scheduler binding time");
|
|
427
|
+
const nowMs = now.getTime();
|
|
428
|
+
return _withScheduleLock(cwd, () => {
|
|
429
|
+
const schedules = loadSchedules(cwd, { failOnMalformed: true });
|
|
430
|
+
const schedule = schedules.find((entry) => entry.id === id);
|
|
431
|
+
if (!schedule) {
|
|
432
|
+
throw coworkSchedulerError(
|
|
433
|
+
"COWORK_SCHEDULER_SCHEDULE_NOT_FOUND",
|
|
434
|
+
`Cowork schedule does not exist: ${id}`,
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
const prior = schedule.schedulerExecution;
|
|
438
|
+
if (prior?.status === "running") {
|
|
439
|
+
throw coworkSchedulerError(
|
|
440
|
+
"COWORK_SCHEDULER_OUTCOME_UNKNOWN",
|
|
441
|
+
`Cowork schedule outcome is unknown: ${id}`,
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
if (
|
|
445
|
+
prior?.status === "succeeded" &&
|
|
446
|
+
prior.occurrenceId === occurrenceId &&
|
|
447
|
+
prior.snapshotDigest === snapshotDigest
|
|
448
|
+
) {
|
|
449
|
+
return schedule;
|
|
450
|
+
}
|
|
451
|
+
// A legacy runner may have completed after the kernel enqueued this fire
|
|
452
|
+
// but before it acquired the JSONL lock. Its durable delivery id is
|
|
453
|
+
// terminal evidence for the same logical fire, so never overwrite it with
|
|
454
|
+
// a new scheduler claim.
|
|
455
|
+
if (schedule.lastDeliveryId === deliveryId) return schedule;
|
|
456
|
+
|
|
457
|
+
const active = schedule.activeDelivery;
|
|
458
|
+
const activeExpiresAt = Date.parse(active?.leaseExpiresAt || "");
|
|
459
|
+
if (active && Number.isFinite(activeExpiresAt) && activeExpiresAt > nowMs) {
|
|
460
|
+
throw coworkSchedulerError(
|
|
461
|
+
"COWORK_SCHEDULER_LEGACY_CLAIM_ACTIVE",
|
|
462
|
+
`Cowork schedule is already claimed: ${id}`,
|
|
463
|
+
{ retryable: true, retryAt: activeExpiresAt },
|
|
464
|
+
);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
const fence =
|
|
468
|
+
Math.max(
|
|
469
|
+
Number(schedule.deliveryFence) || 0,
|
|
470
|
+
Number(active?.fence) || 0,
|
|
471
|
+
) + 1;
|
|
472
|
+
schedule.deliveryFence = fence;
|
|
473
|
+
schedule.activeDelivery = {
|
|
474
|
+
deliveryId,
|
|
475
|
+
ownerId: `scheduler:${occurrenceId}:${attempt}`,
|
|
476
|
+
fence,
|
|
477
|
+
claimedAt: now.toISOString(),
|
|
478
|
+
leaseExpiresAt: COWORK_SCHEDULER_UNKNOWN_LEASE_EXPIRES_AT,
|
|
479
|
+
};
|
|
480
|
+
schedule.schedulerExecution = {
|
|
481
|
+
deliveryId,
|
|
482
|
+
occurrenceId,
|
|
483
|
+
snapshotDigest,
|
|
484
|
+
attempt,
|
|
485
|
+
status: "running",
|
|
486
|
+
startedAt: now.toISOString(),
|
|
487
|
+
};
|
|
488
|
+
_saveSchedulesUnlocked(cwd, schedules);
|
|
489
|
+
return schedule;
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Atomically settle scheduler evidence and the legacy Cowork delivery state.
|
|
495
|
+
* A known failure may keep a short legacy-visible fence until retryAt; an
|
|
496
|
+
* unknown outcome never calls this function and therefore remains fenced.
|
|
497
|
+
*/
|
|
498
|
+
export function completeSchedulerScheduleFire(
|
|
499
|
+
cwd,
|
|
500
|
+
id,
|
|
501
|
+
{
|
|
502
|
+
deliveryId,
|
|
503
|
+
occurrenceId,
|
|
504
|
+
snapshotDigest,
|
|
505
|
+
attempt,
|
|
506
|
+
outcome,
|
|
507
|
+
result = null,
|
|
508
|
+
error = null,
|
|
509
|
+
retryAt,
|
|
510
|
+
at = _deps.now(),
|
|
511
|
+
} = {},
|
|
512
|
+
) {
|
|
513
|
+
if (!["succeeded", "failed"].includes(outcome)) {
|
|
514
|
+
throw coworkSchedulerError(
|
|
515
|
+
"COWORK_SCHEDULER_OUTCOME_INVALID",
|
|
516
|
+
"Cowork scheduler outcome must be succeeded or failed",
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
const now = normalizedDate(at, "cowork scheduler completion time");
|
|
520
|
+
const retryAtMs =
|
|
521
|
+
retryAt === undefined || retryAt === null ? null : Number(retryAt);
|
|
522
|
+
if (retryAtMs !== null && !Number.isSafeInteger(retryAtMs)) {
|
|
523
|
+
throw coworkSchedulerError(
|
|
524
|
+
"COWORK_SCHEDULER_RETRY_TIME_INVALID",
|
|
525
|
+
"Cowork scheduler retryAt must be a safe epoch millisecond",
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
return _withScheduleLock(cwd, () => {
|
|
529
|
+
const schedules = loadSchedules(cwd, { failOnMalformed: true });
|
|
530
|
+
const schedule = schedules.find((entry) => entry.id === id);
|
|
531
|
+
if (!schedule) {
|
|
532
|
+
throw coworkSchedulerError(
|
|
533
|
+
"COWORK_SCHEDULER_SCHEDULE_NOT_FOUND",
|
|
534
|
+
`Cowork schedule does not exist: ${id}`,
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
const evidence = schedule.schedulerExecution;
|
|
538
|
+
if (
|
|
539
|
+
!evidence ||
|
|
540
|
+
evidence.deliveryId !== deliveryId ||
|
|
541
|
+
evidence.occurrenceId !== occurrenceId ||
|
|
542
|
+
evidence.snapshotDigest !== snapshotDigest ||
|
|
543
|
+
evidence.attempt !== attempt ||
|
|
544
|
+
evidence.status !== "running"
|
|
545
|
+
) {
|
|
546
|
+
throw coworkSchedulerError(
|
|
547
|
+
"COWORK_SCHEDULER_BINDING_MISMATCH",
|
|
548
|
+
`Cowork scheduler evidence does not match the active claim: ${id}`,
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
schedule.schedulerExecution = {
|
|
553
|
+
...evidence,
|
|
554
|
+
status: outcome,
|
|
555
|
+
endedAt: now.toISOString(),
|
|
556
|
+
...(outcome === "succeeded" ? { result } : { error }),
|
|
557
|
+
};
|
|
558
|
+
if (outcome === "succeeded") {
|
|
559
|
+
schedule.lastDeliveryId = deliveryId;
|
|
560
|
+
schedule.lastRunAt = now.toISOString();
|
|
561
|
+
schedule.lastStatus = result?.status || "completed";
|
|
562
|
+
schedule.activeDelivery = null;
|
|
563
|
+
} else if (retryAtMs !== null && retryAtMs > now.getTime()) {
|
|
564
|
+
schedule.activeDelivery = {
|
|
565
|
+
...schedule.activeDelivery,
|
|
566
|
+
leaseExpiresAt: new Date(retryAtMs).toISOString(),
|
|
567
|
+
};
|
|
568
|
+
} else {
|
|
569
|
+
schedule.activeDelivery = null;
|
|
570
|
+
}
|
|
571
|
+
_saveSchedulesUnlocked(cwd, schedules);
|
|
572
|
+
return schedule;
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
|
|
366
576
|
/**
|
|
367
577
|
* Claim one concrete cron fire before launching its side effect. The persisted
|
|
368
578
|
* delivery id prevents two scheduler processes from running the same fire; an
|
|
@@ -564,9 +774,7 @@ export class CoworkCronScheduler {
|
|
|
564
774
|
this._emit({ type: "invalid-cron", id: s.id, error: err.message });
|
|
565
775
|
continue;
|
|
566
776
|
}
|
|
567
|
-
const fireKey =
|
|
568
|
-
matcher.hasSeconds ? _secondKey(now) : _minuteKey(now)
|
|
569
|
-
}`;
|
|
777
|
+
const fireKey = coworkCronFireKey(s, now);
|
|
570
778
|
if (this._firedKeys.has(fireKey)) continue;
|
|
571
779
|
if (this._running.has(s.id)) continue;
|
|
572
780
|
const isDue = matcher(now);
|
|
@@ -634,27 +842,30 @@ export class CoworkCronScheduler {
|
|
|
634
842
|
deliveryId: claim.deliveryId,
|
|
635
843
|
});
|
|
636
844
|
|
|
637
|
-
const renewal = setInterval(
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
845
|
+
const renewal = setInterval(
|
|
846
|
+
() => {
|
|
847
|
+
try {
|
|
848
|
+
const renewed = renewScheduleFire(this.cwd, schedule.id, claim, {
|
|
849
|
+
leaseMs: this.leaseMs,
|
|
850
|
+
});
|
|
851
|
+
if (!renewed) {
|
|
852
|
+
this._emit({
|
|
853
|
+
type: "schedule-lease-lost",
|
|
854
|
+
id: schedule.id,
|
|
855
|
+
deliveryId: claim.deliveryId,
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
} catch (err) {
|
|
643
859
|
this._emit({
|
|
644
|
-
type: "schedule-lease-
|
|
860
|
+
type: "schedule-lease-renewal-failed",
|
|
645
861
|
id: schedule.id,
|
|
646
862
|
deliveryId: claim.deliveryId,
|
|
863
|
+
error: err.message,
|
|
647
864
|
});
|
|
648
865
|
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
id: schedule.id,
|
|
653
|
-
deliveryId: claim.deliveryId,
|
|
654
|
-
error: err.message,
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
}, Math.max(1000, Math.floor(this.leaseMs / 3)));
|
|
866
|
+
},
|
|
867
|
+
Math.max(1000, Math.floor(this.leaseMs / 3)),
|
|
868
|
+
);
|
|
658
869
|
renewal.unref?.();
|
|
659
870
|
|
|
660
871
|
let result = null;
|
|
@@ -718,12 +929,19 @@ export class CoworkCronScheduler {
|
|
|
718
929
|
}
|
|
719
930
|
}
|
|
720
931
|
|
|
721
|
-
function
|
|
932
|
+
export function coworkCronMinuteKey(date) {
|
|
722
933
|
return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}-${date.getHours()}-${date.getMinutes()}`;
|
|
723
934
|
}
|
|
724
935
|
|
|
725
|
-
function
|
|
726
|
-
return `${
|
|
936
|
+
export function coworkCronSecondKey(date) {
|
|
937
|
+
return `${coworkCronMinuteKey(date)}-${date.getSeconds()}`;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
export function coworkCronFireKey(schedule, date) {
|
|
941
|
+
const matcher = parseCron(schedule.cron);
|
|
942
|
+
return `${schedule.id}:${
|
|
943
|
+
matcher.hasSeconds ? coworkCronSecondKey(date) : coworkCronMinuteKey(date)
|
|
944
|
+
}`;
|
|
727
945
|
}
|
|
728
946
|
|
|
729
947
|
// =====================================================================
|
package/src/lib/micro-compact.js
CHANGED
|
@@ -23,10 +23,10 @@ export function microCompact(messages, opts = {}) {
|
|
|
23
23
|
return { messages, stats: { trimmed: 0, saved: 0, kept: 0 } };
|
|
24
24
|
}
|
|
25
25
|
const keepRecent = Number.isFinite(opts.keepRecent)
|
|
26
|
-
? opts.keepRecent
|
|
26
|
+
? Math.max(0, Math.trunc(opts.keepRecent))
|
|
27
27
|
: DEFAULT_KEEP_RECENT;
|
|
28
28
|
const maxChars = Number.isFinite(opts.maxToolChars)
|
|
29
|
-
? opts.maxToolChars
|
|
29
|
+
? Math.max(0, Math.trunc(opts.maxToolChars))
|
|
30
30
|
: DEFAULT_MAX_TOOL_CHARS;
|
|
31
31
|
// messages at index >= cutoff are "recent" and never touched.
|
|
32
32
|
const cutoff = Math.max(0, messages.length - keepRecent);
|
|
@@ -38,12 +38,18 @@ export function microCompact(messages, opts = {}) {
|
|
|
38
38
|
if (!m || m.role !== "tool") return m; // only old tool results
|
|
39
39
|
const content = typeof m.content === "string" ? m.content : "";
|
|
40
40
|
if (content.length <= maxChars) return m; // small enough already
|
|
41
|
+
const fullMarker = `\n… [tool result trimmed — ${content.length} chars]`;
|
|
42
|
+
const marker =
|
|
43
|
+
fullMarker.length <= maxChars
|
|
44
|
+
? fullMarker
|
|
45
|
+
: "…[trimmed]".slice(0, maxChars);
|
|
46
|
+
const head = content.slice(0, Math.max(0, maxChars - marker.length));
|
|
47
|
+
const compactedContent = `${head}${marker}`;
|
|
41
48
|
trimmed += 1;
|
|
42
|
-
saved += content.length -
|
|
43
|
-
const head = content.slice(0, maxChars);
|
|
49
|
+
saved += content.length - compactedContent.length;
|
|
44
50
|
return {
|
|
45
51
|
...m,
|
|
46
|
-
content:
|
|
52
|
+
content: compactedContent,
|
|
47
53
|
_microCompacted: true,
|
|
48
54
|
};
|
|
49
55
|
});
|
|
@@ -66,7 +66,8 @@ const SUPPORTED_SANDBOX_PROFILES = new Set([
|
|
|
66
66
|
// evidence, not authority to invoke a privileged post-spawn closure.
|
|
67
67
|
const admittedWindowsMcpCodeSnapshotPlans = new WeakSet();
|
|
68
68
|
|
|
69
|
-
//
|
|
69
|
+
// Keep the broker on the shared CommonJS trace singleton so CommonJS and ESM
|
|
70
|
+
// consumers observe the same AsyncLocalStorage without loader warnings.
|
|
70
71
|
let _traceCtx = null;
|
|
71
72
|
const _ipcBus = null;
|
|
72
73
|
|
|
@@ -3354,7 +3355,12 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
3354
3355
|
delete spawnOpts.mcpStdioExecutableIdentityDigest;
|
|
3355
3356
|
if (traceCtx) {
|
|
3356
3357
|
spawnOpts.env = { ...(spawnOpts.env || process.env) };
|
|
3357
|
-
|
|
3358
|
+
Object.assign(
|
|
3359
|
+
spawnOpts.env,
|
|
3360
|
+
getTraceCtx()?.traceContext?.getPropagationEnv?.() || {
|
|
3361
|
+
TRACEPARENT: traceCtx.traceparent,
|
|
3362
|
+
},
|
|
3363
|
+
);
|
|
3358
3364
|
}
|
|
3359
3365
|
|
|
3360
3366
|
// P0-1: Credential filtering (default-on) — strip secrets from env/args
|
|
@@ -3658,7 +3664,12 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
3658
3664
|
this._stripAuditControlOptions(spawnOpts);
|
|
3659
3665
|
if (traceCtx) {
|
|
3660
3666
|
spawnOpts.env = { ...(spawnOpts.env || process.env) };
|
|
3661
|
-
|
|
3667
|
+
Object.assign(
|
|
3668
|
+
spawnOpts.env,
|
|
3669
|
+
getTraceCtx()?.traceContext?.getPropagationEnv?.() || {
|
|
3670
|
+
TRACEPARENT: traceCtx.traceparent,
|
|
3671
|
+
},
|
|
3672
|
+
);
|
|
3662
3673
|
}
|
|
3663
3674
|
|
|
3664
3675
|
// P0-1: Credential filtering agent — strip secrets from env/args before spawn
|
package/src/lib/routine-store.js
CHANGED
|
@@ -204,13 +204,24 @@ export class RoutineStore {
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
recordRunStart(routineId, meta = {}) {
|
|
207
|
-
const runId =
|
|
207
|
+
const runId =
|
|
208
|
+
typeof meta.runId === "string" && meta.runId.trim()
|
|
209
|
+
? meta.runId.trim()
|
|
210
|
+
: `run-${Date.now().toString(36)}-${randomBytes(3).toString("hex")}`;
|
|
211
|
+
if (
|
|
212
|
+
runId.length > 512 ||
|
|
213
|
+
[...runId].some((char) => char.codePointAt(0) < 32)
|
|
214
|
+
) {
|
|
215
|
+
throw new Error("routine runId is invalid");
|
|
216
|
+
}
|
|
208
217
|
this._appendRun({
|
|
209
218
|
type: "start",
|
|
210
219
|
runId,
|
|
211
220
|
routineId,
|
|
212
221
|
trigger: meta.trigger || null,
|
|
213
222
|
pid: meta.pid || null,
|
|
223
|
+
schedulerOccurrenceId: meta.schedulerOccurrenceId || null,
|
|
224
|
+
schedulerSnapshotDigest: meta.schedulerSnapshotDigest || null,
|
|
214
225
|
startedAt: this._now(),
|
|
215
226
|
});
|
|
216
227
|
return runId;
|
|
@@ -263,6 +274,15 @@ export class RoutineStore {
|
|
|
263
274
|
.map(({ type: _t, ...rest }) => rest);
|
|
264
275
|
}
|
|
265
276
|
|
|
277
|
+
getRun(runId) {
|
|
278
|
+
if (typeof runId !== "string" || runId.length === 0) return null;
|
|
279
|
+
return (
|
|
280
|
+
this.listRuns({ limit: Number.MAX_SAFE_INTEGER }).find(
|
|
281
|
+
(run) => run.runId === runId,
|
|
282
|
+
) || null
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
266
286
|
/** Per-routine aggregate for `cc routine list`: runs, ok/failed, cost. */
|
|
267
287
|
summarize(routineId) {
|
|
268
288
|
const runs = this.listRuns({ routineId, limit: 1000 });
|
|
@@ -286,10 +306,51 @@ export class RoutineStore {
|
|
|
286
306
|
* lastFiredAt (and disable a fired `once`). `runAgent({prompt})` must resolve
|
|
287
307
|
* `{ exitCode, output, usage?, costUsd?, pid? }`.
|
|
288
308
|
*/
|
|
289
|
-
export async function
|
|
309
|
+
export async function executeRoutine(store, routine, runAgent, meta = {}) {
|
|
310
|
+
const requestedRunId =
|
|
311
|
+
typeof meta.runId === "string" && meta.runId.trim()
|
|
312
|
+
? meta.runId.trim()
|
|
313
|
+
: null;
|
|
314
|
+
const existing = requestedRunId ? store.getRun(requestedRunId) : null;
|
|
315
|
+
if (existing) {
|
|
316
|
+
if (existing.routineId !== routine.id) {
|
|
317
|
+
const error = new Error("routine runId is bound to another routine");
|
|
318
|
+
error.code = "ROUTINE_RUN_ID_CONFLICT";
|
|
319
|
+
error.retryable = false;
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
if (existing.status === "running") {
|
|
323
|
+
const error = new Error(
|
|
324
|
+
"routine run outcome is unknown; refusing duplicate execution",
|
|
325
|
+
);
|
|
326
|
+
error.code = "ROUTINE_RUN_OUTCOME_UNKNOWN";
|
|
327
|
+
error.retryable = false;
|
|
328
|
+
throw error;
|
|
329
|
+
}
|
|
330
|
+
const current = store.get(routine.id);
|
|
331
|
+
if (current) {
|
|
332
|
+
store.update(routine.id, {
|
|
333
|
+
lastFiredAt: existing.startedAt,
|
|
334
|
+
...(current.trigger.kind === "once" ? { enabled: false } : {}),
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
runId: existing.runId,
|
|
339
|
+
status: existing.status,
|
|
340
|
+
exitCode: existing.exitCode,
|
|
341
|
+
usage: existing.usage || null,
|
|
342
|
+
costUsd: Number.isFinite(existing.costUsd) ? existing.costUsd : null,
|
|
343
|
+
durationMs: existing.durationMs ?? null,
|
|
344
|
+
recovered: true,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
290
348
|
const startedAt = store._now();
|
|
291
349
|
const runId = store.recordRunStart(routine.id, {
|
|
292
350
|
trigger: meta.trigger || routine.trigger.kind,
|
|
351
|
+
...(requestedRunId ? { runId: requestedRunId } : {}),
|
|
352
|
+
schedulerOccurrenceId: meta.schedulerOccurrenceId || null,
|
|
353
|
+
schedulerSnapshotDigest: meta.schedulerSnapshotDigest || null,
|
|
293
354
|
});
|
|
294
355
|
let result;
|
|
295
356
|
try {
|
|
@@ -316,7 +377,19 @@ export async function fireRoutine(store, routine, runAgent, meta = {}) {
|
|
|
316
377
|
lastFiredAt: startedAt,
|
|
317
378
|
...(routine.trigger.kind === "once" ? { enabled: false } : {}),
|
|
318
379
|
});
|
|
319
|
-
return
|
|
380
|
+
return {
|
|
381
|
+
runId,
|
|
382
|
+
status: result.exitCode === 0 ? "ok" : "failed",
|
|
383
|
+
exitCode: result.exitCode,
|
|
384
|
+
usage: result.usage || null,
|
|
385
|
+
costUsd: Number.isFinite(result.costUsd) ? result.costUsd : null,
|
|
386
|
+
durationMs: store._now() - startedAt,
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export async function fireRoutine(store, routine, runAgent, meta = {}) {
|
|
391
|
+
const execution = await executeRoutine(store, routine, runAgent, meta);
|
|
392
|
+
return execution.runId;
|
|
320
393
|
}
|
|
321
394
|
|
|
322
395
|
/**
|