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.
Files changed (200) hide show
  1. package/completions/_cc +1 -1
  2. package/completions/cc.bash +1 -1
  3. package/completions/cc.fish +1 -1
  4. package/completions/cc.ps1 +1 -1
  5. package/package.json +1 -1
  6. package/src/assets/web-panel/assets/{AIOps-DB5X7qqV.js → AIOps-DDIUofA8.js} +1 -1
  7. package/src/assets/web-panel/assets/{ActionButton-DxHRtKLk.js → ActionButton-Bm-5xYRn.js} +1 -1
  8. package/src/assets/web-panel/assets/{Analytics-DIH5QrxT.js → Analytics-D5UH4ljI.js} +3 -3
  9. package/src/assets/web-panel/assets/{AppLayout-uu0oxVz7.js → AppLayout-D_ifjOOP.js} +5 -5
  10. package/src/assets/web-panel/assets/{Artifacts-BNSMiW9Y.js → Artifacts-BY1mXdC7.js} +1 -1
  11. package/src/assets/web-panel/assets/{Audit-DcAzB4_x.js → Audit-Bujr4Ml3.js} +1 -1
  12. package/src/assets/web-panel/assets/{BackgroundAgents-ClSsvjIc.js → BackgroundAgents-sioKSTcC.js} +1 -1
  13. package/src/assets/web-panel/assets/{Backup-BMciY0js.js → Backup-DDOAK8RK.js} +1 -1
  14. package/src/assets/web-panel/assets/{BaseInput-Hn3b57Sh.js → BaseInput-CtCsVVke.js} +1 -1
  15. package/src/assets/web-panel/assets/{Chat-CoSlC53V.js → Chat-DpNj0vnd.js} +4 -4
  16. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CFevJ3So.js → ChatBubbleRenderer-CZta3Ftr.js} +1 -1
  17. package/src/assets/web-panel/assets/{Checkbox-B4L4Eu4w.js → Checkbox-DoHVNSXq.js} +1 -1
  18. package/src/assets/web-panel/assets/{Codegen-C77FgRxF.js → Codegen-DlVl7Qmv.js} +1 -1
  19. package/src/assets/web-panel/assets/{Col-BrLtJLH3.js → Col-GIqoPYty.js} +1 -1
  20. package/src/assets/web-panel/assets/{Community-Be7pXXhA.js → Community-CIAPEVji.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compact-DuGPecjo.js → Compact-BN7JiI_h.js} +1 -1
  22. package/src/assets/web-panel/assets/{Compliance-CzS66mjP.js → Compliance-CqUWCM9B.js} +1 -1
  23. package/src/assets/web-panel/assets/{Cowork-CEhjCoyK.js → Cowork-A4iPp7A4.js} +3 -3
  24. package/src/assets/web-panel/assets/{Cron-D7ir8Vja.js → Cron-B2zeXXWb.js} +2 -2
  25. package/src/assets/web-panel/assets/{Crosschain-BcXmuLxf.js → Crosschain-BR2xmWr8.js} +1 -1
  26. package/src/assets/web-panel/assets/{DID-Cto1dtBy.js → DID-BzFDjrIv.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dashboard-B7KjgwOX.js → Dashboard-DKtDo3yA.js} +2 -2
  28. package/src/assets/web-panel/assets/{Dropdown-COMqxijg.js → Dropdown-RNx43_YG.js} +1 -1
  29. package/src/assets/web-panel/assets/{EmailListRenderer-BZrya-nf.js → EmailListRenderer-SwMt4Rcy.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-AmVeMq0J.js → FamilyGuardDashboard-CsYebZ4X.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-kZU8c-27.js → Federation-BmRKvBTy.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-sOV22v2-.js → FormItemContext-CVxGTA-0.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-BUuLtGCz.js → GenericCardRenderer-x2iXpyB7.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-K-ZxsLsH.js → Git-DfqbkiOP.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-D3OEnawI.js → Governance-RuHyyj5O.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-Bll0gRmP.js → Inference-Bn7uZ7rI.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-DBXwjr53.js → KnowledgeGraph-DlP7XefZ.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-CEzPwEfP.js → Logs-BYNdOiCd.js} +2 -2
  39. package/src/assets/web-panel/assets/MarkdownRenderer-aMtgN-R6.js +1 -0
  40. package/src/assets/web-panel/assets/{Marketplace-BYyRyOPz.js → Marketplace-JQYmDqM8.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-DVu8w_rM.js → McpTools-Cyx4yZ-9.js} +4 -4
  42. package/src/assets/web-panel/assets/{Memory-tenuZ_hO.js → Memory-VDuGZTN2.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-Bxgy4ozS.js → MobileBridge-_yKo97gi.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-Dgx1D6sc.js → MobileProjects-CXRXW3q7.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-CRfJ8r8j.js → Mtc-acTGtfLH.js} +5 -5
  46. package/src/assets/web-panel/assets/{MtcAudit-BBJq4Aiz.js → MtcAudit-ClpjXfkY.js} +4 -4
  47. package/src/assets/web-panel/assets/{Multisig-B3ii9lai.js → Multisig-_6Tn3o96.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-FIi-Cubv.js → NLProgramming-CK7pbZzP.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-DIq8MPf1.js → Notes-Czy6V_P8.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-BFOD9eGd.js → NotificationSettings-Cqx-UVv3.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer--41u7vre.js → OrderTableRenderer-C69WDxGy.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-B_0AWztW.js → Organization-DFnA9vLQ.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-B6I7TuXv.js → Overflow-ReZkk2yT.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-Cdf6qens.js → P2P-DzjSI0aI.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-B_0FcQJY.js → PdhVaultBrowser-DKTf5xIP.js} +3 -3
  56. package/src/assets/web-panel/assets/{Permissions-6nFBjsQp.js → Permissions-DhQ5klhR.js} +3 -3
  57. package/src/assets/web-panel/assets/{PersonalDataHub-nQYV7xpn.js → PersonalDataHub-CUL1iHrW.js} +3 -3
  58. package/src/assets/web-panel/assets/{Pipeline-CBVod5jm.js → Pipeline-DU88iu4N.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-D52jW1Nt.js → Privacy-Bw-sYfyK.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-Bdx3BYhf.js → ProjectInit-Bq3Q5y0z.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-b7xr4DUa.js → ProjectSettings-C8spzpho.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-DhfifCKx.js → Projects-Dd-xuPIc.js} +1 -1
  63. package/src/assets/web-panel/assets/Providers-Bf4eTP9W.js +1 -0
  64. package/src/assets/web-panel/assets/{QrScannerModal-FQKSmc3e.js → QrScannerModal-Dme9BDU1.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-CSTrhzcF.js → QuickAsk-CIXfv1rE.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-CxMABOUh.js → Recommend-CIxvdeZ-.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-Cv2T8yRa.js → RemoteSession-C6k7MExI.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-CE1k4Vvu.js → Reputation-CISDz2bl.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-BNgNcAV_.js → Row-CdnDxXyf.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-5ZiBZ3ph.js → RssFeed-C-QpRHsl.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-mDOIF1UV.js → Search-DBjaGzSn.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-CtuCTC-e.js → Security-CQKukOeE.js} +3 -3
  73. package/src/assets/web-panel/assets/{Services-DxFO2Zg7.js → Services-DZz86jWb.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-CKmKkH9y.js → Skeleton-jb8RMK0d.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-Bmzl9qkk.js → Skills-CdY76fZG.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-9RqaWHOC.js → Sla-C_CSiZX9.js} +1 -1
  77. package/src/assets/web-panel/assets/SpeechSettings-C7tT9iad.js +1 -0
  78. package/src/assets/web-panel/assets/{SyncSettings-CvNuCeBT.js → SyncSettings-qvimGO0O.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-B_sLdcnw.js → Tasks-Dng5LPJC.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-D9_YijdK.js → Templates-Bwqq5Wll.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-Cuc7BUSP.js → Tenant-DNWuwP7Z.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-6VYRnJgd.js → Terminal-B-6Othpp.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-GtK8xd8Y.js → TimelineRenderer-DKpKZfzx.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-BZ94Lt5W.js → Tokens-DzfGMd2J.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-DEcZgDaX.js → Trigger-BXwUi74J.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-CC3z9THe.js → Trust-BNzUq4ui.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-Cvtw8cV3.js → UkeySign-BYugxww4.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-CL4e6Bn3.js → VideoEditing-DdauhtSJ.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-ycEemP27.js → Wallet-CSC9bCe_.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-DgZ4X_aw.js → WebAuthn-Q8AN3bTO.js} +5 -5
  91. package/src/assets/web-panel/assets/{WorkflowEditor-D0qMhSv7.js → WorkflowEditor-d-LBGCuA.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-DsAg01Zn.js → chat-BLVDCgsZ.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-B0oqAhrQ.js → colors-BZlPSEHl.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-CmX0Rabz.js → compact-item-IWseP6R6.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-Be4cn1Ub.js → createContext-DnVRV3Ao.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-Jzu62CLC.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-D5v12kVq.js → hasIn-DLQZA_Wn.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BA4oulaP.js → index-1jeAudHd.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DM724NgU.js → index-BEu2lMBy.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-5LGY0JbG.js → index-BOZJBTWZ.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DikJ0Qqe.js → index-BSjilZ9L.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BqltWojQ.js → index-BZs5bBnk.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-7VKDn-t1.js → index-B_N4-Gq9.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BXGSbelg.js → index-Bbj2NS_I.js} +3 -3
  105. package/src/assets/web-panel/assets/{index-CGiIyTZw.js → index-BhA3QEni.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BKmsS2jj.js → index-Bxp7uDD8.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-B3mUHuVc.js → index-C1ifZtXo.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BBvyHguy.js → index-C2FqfMvU.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-q_fQ94SE.js → index-C5dgnilC.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-D5YVopyr.js → index-CINJQEj6.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-0eWLkQKT.js → index-COev0W2g.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BoAIAZ5C.js → index-CT9vVN-X.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CqoCZ5vR.js → index-CZDekj7T.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-301ogenv.js → index-CarMTIyQ.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-Dn2dSdXx.js → index-CbQNL0ue.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DKUBj36_.js → index-CpBaJ3TD.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BBREnn1V.js → index-DB0MJgF_.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BRIqLy1m.js → index-DOoQpuQY.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-jK3ax6Z6.js → index-DTbxp4UH.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-B1YGjOWC.js → index-DUq0c7gq.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CyyGTMKd.js → index-DZpYeqrh.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-_JjRLSD0.js → index-D_LQodeJ.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DyUaFWEk.js → index-DalA0TKC.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BaE0Ui07.js → index-DjWnONdy.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CyWBir7N.js → index-Dkwsi1Kn.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-qMuZ-NRR.js → index-DocEhinm.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Ckrk3pIV.js → index-DpVrK6fr.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DQRsQen0.js → index-Dy0R5ZED.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-frSojpHj.js → index-M7wxfAbm.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-D0BSkxYQ.js → index-N_GoWZX4.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-8WvYGnON.js → index-YSw_gxlZ.js} +1 -1
  132. package/src/assets/web-panel/assets/index-Zb2MeDSy.js +1 -0
  133. package/src/assets/web-panel/assets/index-fikqml4k.js +1 -0
  134. package/src/assets/web-panel/assets/{index-Hfe_dEGx.js → index-gt8bNefW.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CZ2wUEgr.js → index-hwVDeoC0.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-CZpfzcuy.js → index-jWb70ZgZ.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-D4VdhJ9_.js → initDefaultProps-Co67Kqmb.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-CZJA0MQW.js → motion-BMOxQSF_.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-BqEs7Sb1.js → move-C5fWDw-N.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-BpHEtsu1.js → mtc-parser-BJevpL0e.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-BW94tY9W.js → omit-BCzNU8s6.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-BnBjPWP9.js → pickAttrs-CybWvDPk.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-uUkjQ_hu.js → placementArrow-BMWS9HnW.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-B-klUqXK.js → responsiveObserve-BoL2UnGY.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-CvY1cNAs.js → slide-DWNfXraU.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-Ix5sEDT2.js → statusUtils-BquTM3tX.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-C8qcXOne.js → styleChecker-BEkCleim.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-KNF6Kj8f.js → useFlexGapSupport-Oecnq7EA.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-DGJr345n.js → useFs-CkDffJ4F.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-BboN99rI.js → usePersonalDataHub-qbvKXesB.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-Bgt8Vgte.js → vnode-C6v8n6mA.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-BhJtErgt.js → zoom-4CTeFILV.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/command-help-index.json +3 -3
  155. package/src/command-manifest.json +1 -1
  156. package/src/commands/agenda.js +125 -7
  157. package/src/commands/automation.js +462 -3
  158. package/src/commands/background-session.js +102 -1
  159. package/src/commands/cowork.js +30 -13
  160. package/src/commands/loop.js +167 -36
  161. package/src/commands/routine.js +50 -13
  162. package/src/commands/scheduler-daemon.js +450 -0
  163. package/src/data/changelog.json +27 -1
  164. package/src/lib/agent-schedule-store.js +509 -36
  165. package/src/lib/automation-center-routines.js +363 -0
  166. package/src/lib/automation-center.js +435 -0
  167. package/src/lib/automation-engine.js +74 -19
  168. package/src/lib/automation-execution-authority.js +736 -0
  169. package/src/lib/background-agent-supervisor.js +78 -0
  170. package/src/lib/background-needs-input-incident.js +221 -0
  171. package/src/lib/cowork-cron.js +555 -39
  172. package/src/lib/cowork-observe.js +5 -1
  173. package/src/lib/loop.js +37 -2
  174. package/src/lib/micro-compact.js +11 -5
  175. package/src/lib/permission-engine.js +14 -7
  176. package/src/lib/process-execution-broker/index.js +14 -3
  177. package/src/lib/public-ide-capability-manifest.js +2 -0
  178. package/src/lib/routine-store.js +242 -68
  179. package/src/lib/scheduler-kernel/agenda-adapter.js +812 -0
  180. package/src/lib/scheduler-kernel/authority-resolver.js +163 -0
  181. package/src/lib/scheduler-kernel/automation-adapter.js +592 -0
  182. package/src/lib/scheduler-kernel/automation-event-adapter.js +721 -0
  183. package/src/lib/scheduler-kernel/contract.js +11 -3
  184. package/src/lib/scheduler-kernel/cowork-cron-adapter.js +820 -0
  185. package/src/lib/scheduler-kernel/loop-adapter.js +378 -0
  186. package/src/lib/scheduler-kernel/routine-adapter.js +812 -0
  187. package/src/lib/scheduler-kernel/runtime.js +527 -0
  188. package/src/lib/scheduler-kernel/service.js +328 -0
  189. package/src/lib/scheduler-kernel/store.js +940 -98
  190. package/src/lib/session-message-provenance.js +4 -1
  191. package/src/repl/agent-repl.js +24 -5
  192. package/src/runtime/agent-core.js +38 -17
  193. package/src/runtime/coding-agent-contract-shared.cjs +5 -0
  194. package/src/workers/background-agent-worker.js +91 -28
  195. package/src/assets/web-panel/assets/MarkdownRenderer-CLmCbHx6.js +0 -1
  196. package/src/assets/web-panel/assets/Providers-Dy_PgDMr.js +0 -1
  197. package/src/assets/web-panel/assets/SpeechSettings-CGdzFIYw.js +0 -1
  198. package/src/assets/web-panel/assets/devWarning-CP2qzG6D.js +0 -1
  199. package/src/assets/web-panel/assets/index-CKB0vbJU.js +0 -1
  200. 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 = _genId("exec");
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
- db.prepare(
741
- `INSERT INTO auto_executions
742
- (id, flow_id, trigger_type, input_data, output_data, status, steps_log, duration_ms, error, test_mode, started_at, completed_at)
743
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
744
- ).run(
745
- execId,
746
- flowId,
747
- triggerType,
748
- JSON.stringify(inputData),
749
- null,
750
- EXECUTION_STATUS.RUNNING,
751
- JSON.stringify([]),
752
- 0,
753
- null,
754
- testMode ? 1 : 0,
755
- startedAt,
756
- null,
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}`);