chainlesschain 0.163.4 → 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-DB5X7qqV.js → AIOps-DDIUofA8.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DxHRtKLk.js → ActionButton-Bm-5xYRn.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DIH5QrxT.js → Analytics-D5UH4ljI.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-uu0oxVz7.js → AppLayout-D_ifjOOP.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BNSMiW9Y.js → Artifacts-BY1mXdC7.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DcAzB4_x.js → Audit-Bujr4Ml3.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-ClSsvjIc.js → BackgroundAgents-sioKSTcC.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BMciY0js.js → Backup-DDOAK8RK.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Hn3b57Sh.js → BaseInput-CtCsVVke.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CoSlC53V.js → Chat-DpNj0vnd.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CFevJ3So.js → ChatBubbleRenderer-CZta3Ftr.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-B4L4Eu4w.js → Checkbox-DoHVNSXq.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-C77FgRxF.js → Codegen-DlVl7Qmv.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BrLtJLH3.js → Col-GIqoPYty.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Be7pXXhA.js → Community-CIAPEVji.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DuGPecjo.js → Compact-BN7JiI_h.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CzS66mjP.js → Compliance-CqUWCM9B.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CEhjCoyK.js → Cowork-A4iPp7A4.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-D7ir8Vja.js → Cron-B2zeXXWb.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BcXmuLxf.js → Crosschain-BR2xmWr8.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Cto1dtBy.js → DID-BzFDjrIv.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B7KjgwOX.js → Dashboard-DKtDo3yA.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-COMqxijg.js → Dropdown-RNx43_YG.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BZrya-nf.js → EmailListRenderer-SwMt4Rcy.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-AmVeMq0J.js → FamilyGuardDashboard-CsYebZ4X.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-kZU8c-27.js → Federation-BmRKvBTy.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-sOV22v2-.js → FormItemContext-CVxGTA-0.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BUuLtGCz.js → GenericCardRenderer-x2iXpyB7.js} +1 -1
- package/src/assets/web-panel/assets/{Git-K-ZxsLsH.js → Git-DfqbkiOP.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D3OEnawI.js → Governance-RuHyyj5O.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Bll0gRmP.js → Inference-Bn7uZ7rI.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DBXwjr53.js → KnowledgeGraph-DlP7XefZ.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CEzPwEfP.js → Logs-BYNdOiCd.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-aMtgN-R6.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-BYyRyOPz.js → Marketplace-JQYmDqM8.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DVu8w_rM.js → McpTools-Cyx4yZ-9.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-tenuZ_hO.js → Memory-VDuGZTN2.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Bxgy4ozS.js → MobileBridge-_yKo97gi.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Dgx1D6sc.js → MobileProjects-CXRXW3q7.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CRfJ8r8j.js → Mtc-acTGtfLH.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BBJq4Aiz.js → MtcAudit-ClpjXfkY.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-B3ii9lai.js → Multisig-_6Tn3o96.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-FIi-Cubv.js → NLProgramming-CK7pbZzP.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DIq8MPf1.js → Notes-Czy6V_P8.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BFOD9eGd.js → NotificationSettings-Cqx-UVv3.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer--41u7vre.js → OrderTableRenderer-C69WDxGy.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-B_0AWztW.js → Organization-DFnA9vLQ.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-B6I7TuXv.js → Overflow-ReZkk2yT.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Cdf6qens.js → P2P-DzjSI0aI.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-B_0FcQJY.js → PdhVaultBrowser-DKTf5xIP.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-6nFBjsQp.js → Permissions-DhQ5klhR.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-nQYV7xpn.js → PersonalDataHub-CUL1iHrW.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-CBVod5jm.js → Pipeline-DU88iu4N.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-D52jW1Nt.js → Privacy-Bw-sYfyK.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bdx3BYhf.js → ProjectInit-Bq3Q5y0z.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-b7xr4DUa.js → ProjectSettings-C8spzpho.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DhfifCKx.js → Projects-Dd-xuPIc.js} +1 -1
- package/src/assets/web-panel/assets/Providers-Bf4eTP9W.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-FQKSmc3e.js → QrScannerModal-Dme9BDU1.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CSTrhzcF.js → QuickAsk-CIXfv1rE.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CxMABOUh.js → Recommend-CIxvdeZ-.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Cv2T8yRa.js → RemoteSession-C6k7MExI.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CE1k4Vvu.js → Reputation-CISDz2bl.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BNgNcAV_.js → Row-CdnDxXyf.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-5ZiBZ3ph.js → RssFeed-C-QpRHsl.js} +3 -3
- package/src/assets/web-panel/assets/{Search-mDOIF1UV.js → Search-DBjaGzSn.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CtuCTC-e.js → Security-CQKukOeE.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DxFO2Zg7.js → Services-DZz86jWb.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CKmKkH9y.js → Skeleton-jb8RMK0d.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-Bmzl9qkk.js → Skills-CdY76fZG.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-9RqaWHOC.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-CvNuCeBT.js → SyncSettings-qvimGO0O.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-B_sLdcnw.js → Tasks-Dng5LPJC.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D9_YijdK.js → Templates-Bwqq5Wll.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Cuc7BUSP.js → Tenant-DNWuwP7Z.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-6VYRnJgd.js → Terminal-B-6Othpp.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-GtK8xd8Y.js → TimelineRenderer-DKpKZfzx.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BZ94Lt5W.js → Tokens-DzfGMd2J.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DEcZgDaX.js → Trigger-BXwUi74J.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CC3z9THe.js → Trust-BNzUq4ui.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Cvtw8cV3.js → UkeySign-BYugxww4.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CL4e6Bn3.js → VideoEditing-DdauhtSJ.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-ycEemP27.js → Wallet-CSC9bCe_.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DgZ4X_aw.js → WebAuthn-Q8AN3bTO.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-D0qMhSv7.js → WorkflowEditor-d-LBGCuA.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DsAg01Zn.js → chat-BLVDCgsZ.js} +1 -1
- package/src/assets/web-panel/assets/{colors-B0oqAhrQ.js → colors-BZlPSEHl.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CmX0Rabz.js → compact-item-IWseP6R6.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Be4cn1Ub.js → createContext-DnVRV3Ao.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Jzu62CLC.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D5v12kVq.js → hasIn-DLQZA_Wn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BA4oulaP.js → index-1jeAudHd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DM724NgU.js → index-BEu2lMBy.js} +1 -1
- package/src/assets/web-panel/assets/{index-5LGY0JbG.js → index-BOZJBTWZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DikJ0Qqe.js → index-BSjilZ9L.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqltWojQ.js → index-BZs5bBnk.js} +1 -1
- package/src/assets/web-panel/assets/{index-7VKDn-t1.js → index-B_N4-Gq9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXGSbelg.js → index-Bbj2NS_I.js} +3 -3
- package/src/assets/web-panel/assets/{index-CGiIyTZw.js → index-BhA3QEni.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKmsS2jj.js → index-Bxp7uDD8.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3mUHuVc.js → index-C1ifZtXo.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBvyHguy.js → index-C2FqfMvU.js} +1 -1
- package/src/assets/web-panel/assets/{index-q_fQ94SE.js → index-C5dgnilC.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5YVopyr.js → index-CINJQEj6.js} +1 -1
- package/src/assets/web-panel/assets/{index-0eWLkQKT.js → index-COev0W2g.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoAIAZ5C.js → index-CT9vVN-X.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqoCZ5vR.js → index-CZDekj7T.js} +1 -1
- package/src/assets/web-panel/assets/{index-301ogenv.js → index-CarMTIyQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dn2dSdXx.js → index-CbQNL0ue.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKUBj36_.js → index-CpBaJ3TD.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBREnn1V.js → index-DB0MJgF_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRIqLy1m.js → index-DOoQpuQY.js} +1 -1
- package/src/assets/web-panel/assets/{index-jK3ax6Z6.js → index-DTbxp4UH.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1YGjOWC.js → index-DUq0c7gq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyyGTMKd.js → index-DZpYeqrh.js} +1 -1
- package/src/assets/web-panel/assets/{index-_JjRLSD0.js → index-D_LQodeJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyUaFWEk.js → index-DalA0TKC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaE0Ui07.js → index-DjWnONdy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyWBir7N.js → index-Dkwsi1Kn.js} +1 -1
- package/src/assets/web-panel/assets/{index-qMuZ-NRR.js → index-DocEhinm.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ckrk3pIV.js → index-DpVrK6fr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DQRsQen0.js → index-Dy0R5ZED.js} +1 -1
- package/src/assets/web-panel/assets/{index-frSojpHj.js → index-M7wxfAbm.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0BSkxYQ.js → index-N_GoWZX4.js} +1 -1
- package/src/assets/web-panel/assets/{index-8WvYGnON.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-Hfe_dEGx.js → index-gt8bNefW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZ2wUEgr.js → index-hwVDeoC0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZpfzcuy.js → index-jWb70ZgZ.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-D4VdhJ9_.js → initDefaultProps-Co67Kqmb.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CZJA0MQW.js → motion-BMOxQSF_.js} +1 -1
- package/src/assets/web-panel/assets/{move-BqEs7Sb1.js → move-C5fWDw-N.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BpHEtsu1.js → mtc-parser-BJevpL0e.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BW94tY9W.js → omit-BCzNU8s6.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BnBjPWP9.js → pickAttrs-CybWvDPk.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-uUkjQ_hu.js → placementArrow-BMWS9HnW.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B-klUqXK.js → responsiveObserve-BoL2UnGY.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CvY1cNAs.js → slide-DWNfXraU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Ix5sEDT2.js → statusUtils-BquTM3tX.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-C8qcXOne.js → styleChecker-BEkCleim.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-KNF6Kj8f.js → useFlexGapSupport-Oecnq7EA.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DGJr345n.js → useFs-CkDffJ4F.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BboN99rI.js → usePersonalDataHub-qbvKXesB.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Bgt8Vgte.js → vnode-C6v8n6mA.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BhJtErgt.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 +125 -7
- package/src/commands/automation.js +462 -3
- package/src/commands/background-session.js +102 -1
- package/src/commands/cowork.js +30 -13
- package/src/commands/loop.js +167 -36
- package/src/commands/routine.js +50 -13
- package/src/commands/scheduler-daemon.js +450 -0
- package/src/data/changelog.json +27 -1
- package/src/lib/agent-schedule-store.js +509 -36
- 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 +555 -39
- package/src/lib/cowork-observe.js +5 -1
- package/src/lib/loop.js +37 -2
- package/src/lib/micro-compact.js +11 -5
- package/src/lib/permission-engine.js +14 -7
- package/src/lib/process-execution-broker/index.js +14 -3
- package/src/lib/public-ide-capability-manifest.js +2 -0
- package/src/lib/routine-store.js +242 -68
- package/src/lib/scheduler-kernel/agenda-adapter.js +812 -0
- 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 +820 -0
- package/src/lib/scheduler-kernel/loop-adapter.js +378 -0
- package/src/lib/scheduler-kernel/routine-adapter.js +812 -0
- package/src/lib/scheduler-kernel/runtime.js +527 -0
- package/src/lib/scheduler-kernel/service.js +328 -0
- package/src/lib/scheduler-kernel/store.js +940 -98
- package/src/lib/session-message-provenance.js +4 -1
- package/src/repl/agent-repl.js +24 -5
- package/src/runtime/agent-core.js +38 -17
- 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/MarkdownRenderer-CLmCbHx6.js +0 -1
- package/src/assets/web-panel/assets/Providers-Dy_PgDMr.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-CGdzFIYw.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
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import {
|
|
3
|
+
automationExecutionAuthorityDigest,
|
|
4
|
+
automationExecutionAuthoritySnapshot,
|
|
5
|
+
inspectAutomationExecutionAuthority,
|
|
6
|
+
reserveAutomationExecutionAuthority,
|
|
7
|
+
} from "./automation-execution-authority.js";
|
|
8
|
+
import {
|
|
9
|
+
EXECUTION_STATUS,
|
|
10
|
+
FLOW_STATUS,
|
|
11
|
+
TRIGGER_TYPE,
|
|
12
|
+
deleteFlow,
|
|
13
|
+
executeFlow,
|
|
14
|
+
getExecution,
|
|
15
|
+
getFlow,
|
|
16
|
+
listExecutions,
|
|
17
|
+
listFlows,
|
|
18
|
+
listTriggers,
|
|
19
|
+
updateFlowStatus,
|
|
20
|
+
} from "./automation-engine.js";
|
|
21
|
+
import {
|
|
22
|
+
SchedulerKernelError,
|
|
23
|
+
canonicalJson,
|
|
24
|
+
normalizeIdentifier,
|
|
25
|
+
} from "./scheduler-kernel/contract.js";
|
|
26
|
+
import { RoutineStore } from "./routine-store.js";
|
|
27
|
+
import { buildRoutineCenterProjection } from "./automation-center-routines.js";
|
|
28
|
+
|
|
29
|
+
export const AUTOMATION_CENTER_SCHEMA = "chainlesschain.automation-center/v2";
|
|
30
|
+
export const AUTOMATION_CENTER_SCHEMA_VERSION = 2;
|
|
31
|
+
export const AUTOMATION_CENTER_ACTIONS = Object.freeze([
|
|
32
|
+
"run_now",
|
|
33
|
+
"retry_failed",
|
|
34
|
+
"pause",
|
|
35
|
+
"resume",
|
|
36
|
+
"disable",
|
|
37
|
+
"delete",
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
function centerError(code, message, details = undefined) {
|
|
41
|
+
const error = new SchedulerKernelError(code, message, details);
|
|
42
|
+
error.retryable = false;
|
|
43
|
+
return error;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function digest(value) {
|
|
47
|
+
return `sha256:${createHash("sha256")
|
|
48
|
+
.update("chainlesschain.automation-center.v2\0", "utf8")
|
|
49
|
+
.update(canonicalJson(value, "automationCenter"), "utf8")
|
|
50
|
+
.digest("hex")}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function boundedText(value, maximum = 240) {
|
|
54
|
+
return String(value || "")
|
|
55
|
+
.replace(/[\r\n]+/g, " ")
|
|
56
|
+
.slice(0, maximum);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function safeTriggerScope(trigger) {
|
|
60
|
+
const config = trigger?.config || {};
|
|
61
|
+
if (trigger.type === TRIGGER_TYPE.EVENT) {
|
|
62
|
+
return {
|
|
63
|
+
event: boundedText(config.event, 80) || null,
|
|
64
|
+
origins: Array.isArray(config.scope?.origins)
|
|
65
|
+
? config.scope.origins
|
|
66
|
+
.map((value) => boundedText(value, 64))
|
|
67
|
+
.slice(0, 16)
|
|
68
|
+
: [],
|
|
69
|
+
senders: Array.isArray(config.scope?.senders)
|
|
70
|
+
? config.scope.senders
|
|
71
|
+
.map((value) => boundedText(value, 96))
|
|
72
|
+
.slice(0, 32)
|
|
73
|
+
: [],
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (trigger.type === TRIGGER_TYPE.SCHEDULE) {
|
|
77
|
+
return { cron: boundedText(config.cron, 120) || null };
|
|
78
|
+
}
|
|
79
|
+
if (trigger.type === TRIGGER_TYPE.WEBHOOK) {
|
|
80
|
+
// Webhook URLs often embed bearer material. The center reports that a
|
|
81
|
+
// route is configured without reflecting the URL into privileged IDE UI.
|
|
82
|
+
return {
|
|
83
|
+
endpointConfigured: typeof config.url === "string" && Boolean(config.url),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
if (trigger.type === TRIGGER_TYPE.CONDITION) {
|
|
87
|
+
return { expression: boundedText(config.expression, 240) || null };
|
|
88
|
+
}
|
|
89
|
+
return {};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function projectTrigger(trigger) {
|
|
93
|
+
return {
|
|
94
|
+
id: trigger.id,
|
|
95
|
+
type: trigger.type,
|
|
96
|
+
enabled: trigger.enabled === true,
|
|
97
|
+
scope: safeTriggerScope(trigger),
|
|
98
|
+
triggerCount: Number(trigger.triggerCount) || 0,
|
|
99
|
+
lastTriggeredAt: trigger.lastTriggeredAt || null,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function projectExecution(execution) {
|
|
104
|
+
return {
|
|
105
|
+
id: execution.id,
|
|
106
|
+
status: execution.status,
|
|
107
|
+
triggerType: execution.triggerType || null,
|
|
108
|
+
durationMs: Number(execution.durationMs) || 0,
|
|
109
|
+
startedAt: execution.startedAt || null,
|
|
110
|
+
completedAt: execution.completedAt || null,
|
|
111
|
+
error: execution.error ? boundedText(execution.error, 400) : null,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function projectSecurity(db, flow, now) {
|
|
116
|
+
try {
|
|
117
|
+
const result = inspectAutomationExecutionAuthority(db, flow, { now });
|
|
118
|
+
return {
|
|
119
|
+
state: result.ready ? "ready" : "denied",
|
|
120
|
+
ready: result.ready,
|
|
121
|
+
principalId: result.snapshot.principalId,
|
|
122
|
+
connectors: result.snapshot.connectors,
|
|
123
|
+
permissions: result.permissions,
|
|
124
|
+
budget: {
|
|
125
|
+
revision: result.snapshot.budget.revision,
|
|
126
|
+
windowMs: result.snapshot.budget.windowMs,
|
|
127
|
+
maxRuns: result.snapshot.budget.maxRuns,
|
|
128
|
+
maxActionSteps: result.snapshot.budget.maxActionSteps,
|
|
129
|
+
...result.window,
|
|
130
|
+
},
|
|
131
|
+
issue: null,
|
|
132
|
+
};
|
|
133
|
+
} catch (error) {
|
|
134
|
+
const code = boundedText(
|
|
135
|
+
error?.code || "AUTOMATION_EXECUTION_PREFLIGHT_FAILED",
|
|
136
|
+
96,
|
|
137
|
+
);
|
|
138
|
+
return {
|
|
139
|
+
state:
|
|
140
|
+
code === "AUTOMATION_EXECUTION_BUDGET_REQUIRED" ||
|
|
141
|
+
code === "AUTOMATION_EXECUTION_PRINCIPAL_REQUIRED"
|
|
142
|
+
? "unconfigured"
|
|
143
|
+
: "invalid",
|
|
144
|
+
ready: false,
|
|
145
|
+
principalId:
|
|
146
|
+
typeof flow.createdBy === "string" && flow.createdBy
|
|
147
|
+
? flow.createdBy
|
|
148
|
+
: null,
|
|
149
|
+
connectors: [],
|
|
150
|
+
permissions: [],
|
|
151
|
+
budget: null,
|
|
152
|
+
issue: { code, message: boundedText(error?.message || error, 400) },
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function action(id, available, reason, flowId, itemRevision) {
|
|
158
|
+
return {
|
|
159
|
+
id,
|
|
160
|
+
available,
|
|
161
|
+
reason: available ? null : reason,
|
|
162
|
+
preview: available
|
|
163
|
+
? {
|
|
164
|
+
executor: "cli",
|
|
165
|
+
argv: [
|
|
166
|
+
"automation",
|
|
167
|
+
"center-action",
|
|
168
|
+
flowId,
|
|
169
|
+
id,
|
|
170
|
+
"--expected-revision",
|
|
171
|
+
itemRevision,
|
|
172
|
+
"--json",
|
|
173
|
+
],
|
|
174
|
+
mutates: true,
|
|
175
|
+
}
|
|
176
|
+
: null,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function projectFlow(db, flow, { historyLimit, now }) {
|
|
181
|
+
const triggers = listTriggers(db, flow.id).map(projectTrigger);
|
|
182
|
+
const history = listExecutions(db, {
|
|
183
|
+
flowId: flow.id,
|
|
184
|
+
limit: historyLimit,
|
|
185
|
+
}).map(projectExecution);
|
|
186
|
+
const security = projectSecurity(db, flow, now);
|
|
187
|
+
const content = {
|
|
188
|
+
kind: "flow",
|
|
189
|
+
id: flow.id,
|
|
190
|
+
name: boundedText(flow.name, 200),
|
|
191
|
+
description: boundedText(flow.description, 500),
|
|
192
|
+
status: flow.status,
|
|
193
|
+
schedule: flow.schedule || null,
|
|
194
|
+
updatedAt: flow.updatedAt || null,
|
|
195
|
+
triggers,
|
|
196
|
+
history,
|
|
197
|
+
security,
|
|
198
|
+
};
|
|
199
|
+
const revision = digest(content);
|
|
200
|
+
const active = flow.status === FLOW_STATUS.ACTIVE;
|
|
201
|
+
const paused = flow.status === FLOW_STATUS.PAUSED;
|
|
202
|
+
const archived = flow.status === FLOW_STATUS.ARCHIVED;
|
|
203
|
+
const latestFailed = history[0]?.status === EXECUTION_STATUS.FAILED;
|
|
204
|
+
return {
|
|
205
|
+
...content,
|
|
206
|
+
revision,
|
|
207
|
+
actions: [
|
|
208
|
+
action(
|
|
209
|
+
"run_now",
|
|
210
|
+
active && security.ready,
|
|
211
|
+
!active
|
|
212
|
+
? "flow is not active"
|
|
213
|
+
: "permission or budget preflight denied",
|
|
214
|
+
flow.id,
|
|
215
|
+
revision,
|
|
216
|
+
),
|
|
217
|
+
action(
|
|
218
|
+
"retry_failed",
|
|
219
|
+
active && latestFailed && security.ready,
|
|
220
|
+
!active
|
|
221
|
+
? "flow is not active"
|
|
222
|
+
: !latestFailed
|
|
223
|
+
? "latest run did not fail"
|
|
224
|
+
: "permission or budget preflight denied",
|
|
225
|
+
flow.id,
|
|
226
|
+
revision,
|
|
227
|
+
),
|
|
228
|
+
action(
|
|
229
|
+
"pause",
|
|
230
|
+
active,
|
|
231
|
+
"only an active flow can be paused",
|
|
232
|
+
flow.id,
|
|
233
|
+
revision,
|
|
234
|
+
),
|
|
235
|
+
action(
|
|
236
|
+
"resume",
|
|
237
|
+
paused && security.ready,
|
|
238
|
+
!paused
|
|
239
|
+
? "only a paused flow can be resumed"
|
|
240
|
+
: "permission or budget preflight denied",
|
|
241
|
+
flow.id,
|
|
242
|
+
revision,
|
|
243
|
+
),
|
|
244
|
+
action(
|
|
245
|
+
"disable",
|
|
246
|
+
!archived,
|
|
247
|
+
"flow is already disabled",
|
|
248
|
+
flow.id,
|
|
249
|
+
revision,
|
|
250
|
+
),
|
|
251
|
+
action(
|
|
252
|
+
"delete",
|
|
253
|
+
archived,
|
|
254
|
+
"disable the flow before deleting it",
|
|
255
|
+
flow.id,
|
|
256
|
+
revision,
|
|
257
|
+
),
|
|
258
|
+
],
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function buildAutomationCenterProjection(
|
|
263
|
+
db,
|
|
264
|
+
{
|
|
265
|
+
limit = 100,
|
|
266
|
+
historyLimit = 20,
|
|
267
|
+
now = Date.now,
|
|
268
|
+
routineStore = new RoutineStore(),
|
|
269
|
+
} = {},
|
|
270
|
+
) {
|
|
271
|
+
if (typeof now !== "function") {
|
|
272
|
+
throw centerError(
|
|
273
|
+
"AUTOMATION_CENTER_CLOCK_REQUIRED",
|
|
274
|
+
"automation center requires a clock",
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
const boundedLimit = Math.max(1, Math.min(1000, Number(limit) || 100));
|
|
278
|
+
const boundedHistory = Math.max(1, Math.min(100, Number(historyLimit) || 20));
|
|
279
|
+
const flows = listFlows(db, { limit: boundedLimit }).map((flow) =>
|
|
280
|
+
projectFlow(db, flow, { historyLimit: boundedHistory, now }),
|
|
281
|
+
);
|
|
282
|
+
const routineProjection = buildRoutineCenterProjection(routineStore, {
|
|
283
|
+
limit: boundedLimit,
|
|
284
|
+
historyLimit: boundedHistory,
|
|
285
|
+
});
|
|
286
|
+
const items = [...flows, ...routineProjection.items];
|
|
287
|
+
const summary = {
|
|
288
|
+
total: items.length,
|
|
289
|
+
flows: flows.length,
|
|
290
|
+
routines: routineProjection.items.length,
|
|
291
|
+
active: items.filter((item) => item.status === FLOW_STATUS.ACTIVE).length,
|
|
292
|
+
paused: items.filter((item) => item.status === FLOW_STATUS.PAUSED).length,
|
|
293
|
+
needsAttention: items.filter(
|
|
294
|
+
(item) =>
|
|
295
|
+
item.security.ready !== true ||
|
|
296
|
+
item.history[0]?.status === EXECUTION_STATUS.FAILED ||
|
|
297
|
+
item.history[0]?.status === "failed",
|
|
298
|
+
).length,
|
|
299
|
+
};
|
|
300
|
+
return {
|
|
301
|
+
schema: AUTOMATION_CENTER_SCHEMA,
|
|
302
|
+
schemaVersion: AUTOMATION_CENTER_SCHEMA_VERSION,
|
|
303
|
+
authority: "cli",
|
|
304
|
+
connected: true,
|
|
305
|
+
generatedAt: new Date(Number(now())).toISOString(),
|
|
306
|
+
routineCatalogRevision: routineProjection.catalogRevision,
|
|
307
|
+
revision: digest({
|
|
308
|
+
summary,
|
|
309
|
+
mutations: {
|
|
310
|
+
createRoutine: routineProjection.createRoutine.preview.argv,
|
|
311
|
+
routineCatalogRevision: routineProjection.catalogRevision,
|
|
312
|
+
},
|
|
313
|
+
items: items.map((item) => ({
|
|
314
|
+
kind: item.kind,
|
|
315
|
+
id: item.id,
|
|
316
|
+
revision: item.revision,
|
|
317
|
+
})),
|
|
318
|
+
}),
|
|
319
|
+
summary,
|
|
320
|
+
mutations: { createRoutine: routineProjection.createRoutine },
|
|
321
|
+
items,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function executionIdFor(flowId, requestedAction, revision) {
|
|
326
|
+
return `exec-center-${createHash("sha256")
|
|
327
|
+
.update(`${flowId}\0${requestedAction}\0${revision}`, "utf8")
|
|
328
|
+
.digest("hex")}`;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function runAutomationCenterAction(
|
|
332
|
+
db,
|
|
333
|
+
{ flowId, action: requestedAction, expectedRevision, now = Date.now } = {},
|
|
334
|
+
) {
|
|
335
|
+
const id = normalizeIdentifier(flowId, "flowId");
|
|
336
|
+
if (!AUTOMATION_CENTER_ACTIONS.includes(requestedAction)) {
|
|
337
|
+
throw centerError(
|
|
338
|
+
"AUTOMATION_CENTER_ACTION_INVALID",
|
|
339
|
+
`unsupported automation center action: ${requestedAction}`,
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
const flow = getFlow(db, id);
|
|
343
|
+
if (!flow) {
|
|
344
|
+
throw centerError(
|
|
345
|
+
"AUTOMATION_CENTER_FLOW_NOT_FOUND",
|
|
346
|
+
`automation flow not found: ${id}`,
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
const item = projectFlow(db, flow, { historyLimit: 20, now });
|
|
350
|
+
if (expectedRevision !== item.revision) {
|
|
351
|
+
throw centerError(
|
|
352
|
+
"AUTOMATION_CENTER_STALE",
|
|
353
|
+
`automation flow changed before ${requestedAction}: ${id}`,
|
|
354
|
+
{ expectedRevision, currentRevision: item.revision },
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
const capability = item.actions.find((entry) => entry.id === requestedAction);
|
|
358
|
+
if (!capability?.available) {
|
|
359
|
+
throw centerError(
|
|
360
|
+
"AUTOMATION_CENTER_ACTION_UNAVAILABLE",
|
|
361
|
+
capability?.reason ||
|
|
362
|
+
`automation action is unavailable: ${requestedAction}`,
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
let result;
|
|
367
|
+
let retryOf = null;
|
|
368
|
+
if (requestedAction === "pause") {
|
|
369
|
+
result = updateFlowStatus(db, id, FLOW_STATUS.PAUSED);
|
|
370
|
+
} else if (requestedAction === "resume") {
|
|
371
|
+
result = updateFlowStatus(db, id, FLOW_STATUS.ACTIVE);
|
|
372
|
+
} else if (requestedAction === "disable") {
|
|
373
|
+
result = updateFlowStatus(db, id, FLOW_STATUS.ARCHIVED);
|
|
374
|
+
} else if (requestedAction === "delete") {
|
|
375
|
+
if (typeof db.transaction !== "function") {
|
|
376
|
+
throw centerError(
|
|
377
|
+
"AUTOMATION_CENTER_TRANSACTION_REQUIRED",
|
|
378
|
+
"deleting an automation flow requires a transactional database",
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
result = db
|
|
382
|
+
.transaction(() => {
|
|
383
|
+
db.prepare(
|
|
384
|
+
"DELETE FROM auto_execution_budget_reservations WHERE flow_id = ?",
|
|
385
|
+
).run(id);
|
|
386
|
+
db.prepare(
|
|
387
|
+
"DELETE FROM auto_execution_budget_usage WHERE flow_id = ?",
|
|
388
|
+
).run(id);
|
|
389
|
+
db.prepare("DELETE FROM auto_execution_budgets WHERE flow_id = ?").run(
|
|
390
|
+
id,
|
|
391
|
+
);
|
|
392
|
+
deleteFlow(db, id);
|
|
393
|
+
return { deleted: true };
|
|
394
|
+
})
|
|
395
|
+
.immediate();
|
|
396
|
+
} else {
|
|
397
|
+
const authority = automationExecutionAuthoritySnapshot(db, flow);
|
|
398
|
+
const occurrenceId = `automation-center:${requestedAction}:${id}:${item.revision.slice("sha256:".length)}`;
|
|
399
|
+
reserveAutomationExecutionAuthority(
|
|
400
|
+
db,
|
|
401
|
+
flow,
|
|
402
|
+
occurrenceId,
|
|
403
|
+
authority,
|
|
404
|
+
automationExecutionAuthorityDigest(authority, flow),
|
|
405
|
+
{ now },
|
|
406
|
+
);
|
|
407
|
+
let inputData = { source: "automation-center" };
|
|
408
|
+
if (requestedAction === "retry_failed") {
|
|
409
|
+
const failed = getExecution(db, item.history[0].id);
|
|
410
|
+
if (!failed || failed.status !== EXECUTION_STATUS.FAILED) {
|
|
411
|
+
throw centerError(
|
|
412
|
+
"AUTOMATION_CENTER_FAILED_RUN_CHANGED",
|
|
413
|
+
`failed automation run changed before retry: ${id}`,
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
retryOf = failed.id;
|
|
417
|
+
inputData = failed.inputData;
|
|
418
|
+
}
|
|
419
|
+
result = executeFlow(db, id, {
|
|
420
|
+
triggerType: TRIGGER_TYPE.MANUAL,
|
|
421
|
+
inputData,
|
|
422
|
+
executionId: executionIdFor(id, requestedAction, item.revision),
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
return {
|
|
426
|
+
schema: "chainlesschain.automation-center-action/v1",
|
|
427
|
+
schemaVersion: 1,
|
|
428
|
+
authority: "cli",
|
|
429
|
+
flowId: id,
|
|
430
|
+
action: requestedAction,
|
|
431
|
+
previousRevision: item.revision,
|
|
432
|
+
...(retryOf ? { retryOf } : {}),
|
|
433
|
+
result,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import crypto from "crypto";
|
|
14
|
+
import { nextCronTime } from "./agent-schedule-store.js";
|
|
14
15
|
|
|
15
16
|
/* ── Constants ─────────────────────────────────────────────── */
|
|
16
17
|
|
|
@@ -519,6 +520,12 @@ export function scheduleFlow(db, flowId, cron) {
|
|
|
519
520
|
if (!cron || typeof cron !== "string") {
|
|
520
521
|
throw new Error("cron expression required");
|
|
521
522
|
}
|
|
523
|
+
// Validate at write time so an invalid schedule cannot poison a resident
|
|
524
|
+
// scheduler loop later. nextCronTime() parses the existing five-field cron
|
|
525
|
+
// dialect and returns the first matching minute.
|
|
526
|
+
if (nextCronTime(cron, Date.now()) === null) {
|
|
527
|
+
throw new Error("cron expression has no occurrence in the next 366 days");
|
|
528
|
+
}
|
|
522
529
|
_requireFlow(db, flowId);
|
|
523
530
|
db.prepare(
|
|
524
531
|
`UPDATE auto_flows SET schedule = ?, updated_at = ? WHERE id = ?`,
|
|
@@ -732,29 +739,45 @@ export function executeFlow(db, flowId, options = {}) {
|
|
|
732
739
|
inputData = {},
|
|
733
740
|
triggerType = TRIGGER_TYPE.MANUAL,
|
|
734
741
|
testMode = false,
|
|
742
|
+
executionId,
|
|
735
743
|
} = options;
|
|
736
|
-
const execId =
|
|
744
|
+
const execId =
|
|
745
|
+
executionId === undefined
|
|
746
|
+
? _genId("exec")
|
|
747
|
+
: _normalizeExecutionId(executionId);
|
|
748
|
+
const existing = getExecution(db, execId);
|
|
749
|
+
if (existing) {
|
|
750
|
+
return _resolveExistingExecution(existing, { flowId, triggerType });
|
|
751
|
+
}
|
|
737
752
|
const startedAt = _now();
|
|
738
753
|
const startMs = Date.now();
|
|
739
754
|
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
755
|
+
try {
|
|
756
|
+
db.prepare(
|
|
757
|
+
`INSERT INTO auto_executions
|
|
758
|
+
(id, flow_id, trigger_type, input_data, output_data, status, steps_log, duration_ms, error, test_mode, started_at, completed_at)
|
|
759
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
760
|
+
).run(
|
|
761
|
+
execId,
|
|
762
|
+
flowId,
|
|
763
|
+
triggerType,
|
|
764
|
+
JSON.stringify(inputData),
|
|
765
|
+
null,
|
|
766
|
+
EXECUTION_STATUS.RUNNING,
|
|
767
|
+
JSON.stringify([]),
|
|
768
|
+
0,
|
|
769
|
+
null,
|
|
770
|
+
testMode ? 1 : 0,
|
|
771
|
+
startedAt,
|
|
772
|
+
null,
|
|
773
|
+
);
|
|
774
|
+
} catch (error) {
|
|
775
|
+
// A deterministic scheduler execution id may race another process. Resolve
|
|
776
|
+
// the winner from durable evidence instead of running the flow twice.
|
|
777
|
+
const concurrent = getExecution(db, execId);
|
|
778
|
+
if (!concurrent) throw error;
|
|
779
|
+
return _resolveExistingExecution(concurrent, { flowId, triggerType });
|
|
780
|
+
}
|
|
758
781
|
|
|
759
782
|
const stepsLog = [];
|
|
760
783
|
let finalStatus = EXECUTION_STATUS.SUCCESS;
|
|
@@ -817,6 +840,38 @@ export function executeFlow(db, flowId, options = {}) {
|
|
|
817
840
|
);
|
|
818
841
|
}
|
|
819
842
|
|
|
843
|
+
function _normalizeExecutionId(value) {
|
|
844
|
+
if (
|
|
845
|
+
typeof value !== "string" ||
|
|
846
|
+
value.length === 0 ||
|
|
847
|
+
value.length > 256 ||
|
|
848
|
+
!/^[A-Za-z0-9._:-]+$/.test(value)
|
|
849
|
+
) {
|
|
850
|
+
const error = new Error("executionId must be a safe non-empty identifier");
|
|
851
|
+
error.code = "AUTOMATION_EXECUTION_ID_INVALID";
|
|
852
|
+
throw error;
|
|
853
|
+
}
|
|
854
|
+
return value;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function _resolveExistingExecution(existing, { flowId, triggerType }) {
|
|
858
|
+
if (existing.flowId !== flowId || existing.triggerType !== triggerType) {
|
|
859
|
+
const error = new Error(
|
|
860
|
+
`Execution id is already bound to another automation request: ${existing.id}`,
|
|
861
|
+
);
|
|
862
|
+
error.code = "AUTOMATION_EXECUTION_BINDING_MISMATCH";
|
|
863
|
+
throw error;
|
|
864
|
+
}
|
|
865
|
+
if (existing.status === EXECUTION_STATUS.RUNNING) {
|
|
866
|
+
const error = new Error(
|
|
867
|
+
`Automation execution outcome is unknown; refusing duplicate execution: ${existing.id}`,
|
|
868
|
+
);
|
|
869
|
+
error.code = "AUTOMATION_EXECUTION_OUTCOME_UNKNOWN";
|
|
870
|
+
throw error;
|
|
871
|
+
}
|
|
872
|
+
return existing;
|
|
873
|
+
}
|
|
874
|
+
|
|
820
875
|
export function fireTrigger(db, triggerId, inputData = {}) {
|
|
821
876
|
const trig = getTrigger(db, triggerId);
|
|
822
877
|
if (!trig) throw new Error(`Trigger not found: ${triggerId}`);
|