chainlesschain 0.163.5 → 0.163.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) 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-Cv2EE1Zy.js → AIOps-axqQfwv8.js} +1 -1
  7. package/src/assets/web-panel/assets/{ActionButton-CcpxMLuW.js → ActionButton-DV-Ro0By.js} +1 -1
  8. package/src/assets/web-panel/assets/{Analytics-DE8mJoMI.js → Analytics-Bt72WEVu.js} +3 -3
  9. package/src/assets/web-panel/assets/{AppLayout-DKn9dk9L.js → AppLayout-BtepG55E.js} +5 -5
  10. package/src/assets/web-panel/assets/{Artifacts-Cp3mG3Py.js → Artifacts-B7KaJ7S_.js} +1 -1
  11. package/src/assets/web-panel/assets/{Audit-zvsQfF2C.js → Audit-FNFaUg7A.js} +1 -1
  12. package/src/assets/web-panel/assets/{BackgroundAgents-Bi85SsjN.js → BackgroundAgents-DFb6J2wQ.js} +1 -1
  13. package/src/assets/web-panel/assets/{Backup-Cw47Dj6s.js → Backup-CC7YBhyj.js} +1 -1
  14. package/src/assets/web-panel/assets/{BaseInput-C5Ip2afH.js → BaseInput-RkgTNVtj.js} +1 -1
  15. package/src/assets/web-panel/assets/{Chat-C0iAFkJv.js → Chat-hHEmGZy-.js} +5 -5
  16. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BV9Wv7wO.js → ChatBubbleRenderer-CAP9YhHv.js} +1 -1
  17. package/src/assets/web-panel/assets/{Checkbox-3KZZCiAF.js → Checkbox-z5wXOQP1.js} +1 -1
  18. package/src/assets/web-panel/assets/{Codegen-C8OMbBAz.js → Codegen-DVaDJnxy.js} +1 -1
  19. package/src/assets/web-panel/assets/{Col-B-MB84LJ.js → Col-CJmaRDR5.js} +1 -1
  20. package/src/assets/web-panel/assets/{Community-DpR7Dxao.js → Community-DF29_2bI.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compact-CyDtz0OS.js → Compact-DtkQkBzn.js} +1 -1
  22. package/src/assets/web-panel/assets/{Compliance-5tiRa2An.js → Compliance-xoHDxp7I.js} +1 -1
  23. package/src/assets/web-panel/assets/{Cowork-DnQaKZ5x.js → Cowork-BUm-R7ht.js} +4 -4
  24. package/src/assets/web-panel/assets/{Cron-BaWfoEDf.js → Cron-Cgl14ZkB.js} +2 -2
  25. package/src/assets/web-panel/assets/{Crosschain-Bu0HoHhb.js → Crosschain-BNcbmoqh.js} +1 -1
  26. package/src/assets/web-panel/assets/{DID-31zk8upX.js → DID-Bwja0Zo9.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dashboard-BmVne-e2.js → Dashboard-Bk5XjEdJ.js} +2 -2
  28. package/src/assets/web-panel/assets/{Dropdown-B4PkoOWd.js → Dropdown-Ci36Oitq.js} +1 -1
  29. package/src/assets/web-panel/assets/{EmailListRenderer-BZ6tyFtI.js → EmailListRenderer--U04ZN4q.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-Osozn4Ds.js → FamilyGuardDashboard-B2gNPR2s.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-DaH8TOAP.js → Federation-C4KghYn7.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-tbU0uwis.js → FormItemContext-QL7x_Q_0.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-Df8LQBrL.js → GenericCardRenderer-F3Ryltwm.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-DsMB6-14.js → Git-2HassK5k.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-BnH0dZzd.js → Governance-DoBIp7oe.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-DhnN1N_P.js → Inference--W01QhZ-.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-DnNshAgn.js → KnowledgeGraph-DmvwqGpT.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-BmBFX3_N.js → Logs-BBJ4yAel.js} +2 -2
  39. package/src/assets/web-panel/assets/{MarkdownRenderer-DCslfQU3.js → MarkdownRenderer-BLCZMzhJ.js} +1 -1
  40. package/src/assets/web-panel/assets/{Marketplace-CPEgWDc3.js → Marketplace-D5lNngSI.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-C36qjgF9.js → McpTools-CkEVOMKH.js} +5 -5
  42. package/src/assets/web-panel/assets/{Memory-tNHvrgqN.js → Memory-B1Ow1xVE.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-Xaf6cKjc.js → MobileBridge-SgYbUfb6.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-D2E5TTeO.js → MobileProjects-BWdOvQAj.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-D4AJ2dwV.js → Mtc-DcTXSSma.js} +2 -2
  46. package/src/assets/web-panel/assets/{MtcAudit-Df-gtn2_.js → MtcAudit-Dt3WG4oj.js} +4 -4
  47. package/src/assets/web-panel/assets/{Multisig-DTCHLWld.js → Multisig-B9B38UZx.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-DruZ_1Jb.js → NLProgramming-B0S4GGvG.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-Dx3pdGDs.js → Notes-DZ5U58Ng.js} +4 -4
  50. package/src/assets/web-panel/assets/{NotificationSettings-Bi3L69oL.js → NotificationSettings-PjL5ZW34.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-BHY33m7C.js → OrderTableRenderer-DrAX2ESt.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-BG2ZVEV-.js → Organization-Cv1GYs-c.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-Viwtg4Mn.js → Overflow-Bbkp_PL3.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-Clm_yc1Z.js → P2P-BD8QUgoZ.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-NKmmDiOw.js → PdhVaultBrowser-BO-2PeaB.js} +5 -5
  56. package/src/assets/web-panel/assets/{Permissions-DIL8u9Nk.js → Permissions-D_OPVa02.js} +4 -4
  57. package/src/assets/web-panel/assets/{PersonalDataHub-B-jM4wt-.js → PersonalDataHub-mh-pEmaB.js} +4 -4
  58. package/src/assets/web-panel/assets/{Pipeline-627I__H5.js → Pipeline-6JC2EDdb.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-2DN2qrkW.js → Privacy-CUshzUAG.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-CN4wC0sF.js → ProjectInit-Cs2Aalri.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-K35vsh5H.js → ProjectSettings-1ak49tcj.js} +2 -2
  62. package/src/assets/web-panel/assets/{Projects-B_wQadhX.js → Projects-BV4oApsm.js} +1 -1
  63. package/src/assets/web-panel/assets/{Providers-MckaQUhQ.js → Providers-CXXxvafH.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-BS3mtA_O.js → QrScannerModal-PTcDsF58.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-BHp_nofL.js → QuickAsk-CDwucrJw.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-DlmnPuZj.js → Recommend-CJlLVRXR.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-tsyFbvpy.js → RemoteSession-DlN-ETsO.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-Ba1iWv2D.js → Reputation-DI23LR6m.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-NnlGC--f.js → Row-Cl7UQMrM.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-CjThSIRv.js → RssFeed-CexHNfh8.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-CojUyC5x.js → Search-BneBWvRN.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-c-sxeJEc.js → Security-DX7Phgrp.js} +4 -4
  73. package/src/assets/web-panel/assets/{Services-CtcKEEmF.js → Services-BWXO8Mte.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-CIBBXflN.js → Skeleton-DCyOjKPJ.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-D1XOOK9n.js → Skills-CXqERsTB.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-hRfEp5Sn.js → Sla-bhbrbz8E.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-Dexb1f_6.js → SpeechSettings-3IPU0HBZ.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-BJsSFGYy.js → SyncSettings-DBNTQLbM.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-CfSZ8A1L.js → Tasks-quP0bkN-.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-idDf47W-.js → Templates-BouWmgho.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-C-UsX6w6.js → Tenant-qv0D9s7z.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-BgJtX5n1.js → Terminal-BxvbE8BB.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-DP0BLKTl.js → TimelineRenderer-D-IeLnJ2.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-LwCzqETp.js → Tokens-CFMKKyVG.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-D_9tVch0.js → Trigger-L8as3UuJ.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-BH2UlEWh.js → Trust-MxmA4VZG.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-CIpD0nYb.js → UkeySign-C0VvJYRi.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-9ShhYxK_.js → VideoEditing-Bf5QZj8N.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-C7afGNIG.js → Wallet-BIJ9riRz.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-bUKn6i5R.js → WebAuthn-B8p9Mhkw.js} +4 -4
  91. package/src/assets/web-panel/assets/{WorkflowEditor-CxgQaGyp.js → WorkflowEditor-BVsuaPen.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-DMVkmJwx.js → chat-BfkjoKpV.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-CDzQh5nS.js → colors-DeAlsWK8.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-C51kEF4D.js → compact-item-Cs97bz5j.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-BTk9bXBn.js → createContext-BqbG60LH.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-CMje33rb.js → hasIn-i_RY0b1X.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DpcrFxMI.js → index-0-agYlWL.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BW4F5YDF.js → index-79V_zv1s.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DRG-aqOs.js → index-B-3tEpTc.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BCRvG9lq.js → index-B-JVTrpr.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-DgivOKHA.js → index-B1CbOH1i.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BzCkNylB.js → index-B5UkyA3c.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-x53Vf7la.js → index-BESLFt4q.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-CCLj9hcD.js → index-BOVkf1K3.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CypsfcEq.js → index-BYUVuwKt.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BtlEqHLP.js → index-BcUXAB2s.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-Ld_4mFmC.js → index-BkBi5TmC.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DqU9njjT.js → index-Bm7lLR4c.js} +1 -1
  110. package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +1 -0
  111. package/src/assets/web-panel/assets/{index-CwGPwjUu.js → index-BuLQobzW.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-C5IWTMVl.js → index-CE2VtTlp.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DJfnCuMq.js → index-CED2PL_y.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-hg_emBsi.js → index-CG3PRyAL.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-togc_uYn.js → index-CIG8fQ2_.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-C4rQCS8T.js → index-COdGA-8n.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-0Auljb10.js → index-CeWoNHau.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Cd0hmPxD.js → index-Cf3WCLmy.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BXQBPLyE.js → index-CgsqdnRV.js} +1 -1
  120. package/src/assets/web-panel/assets/index-ChVT0p9u.js +1 -0
  121. package/src/assets/web-panel/assets/{index-h31MwrME.js → index-D2B4VPyP.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-C1oZReaY.js → index-D9evtvg2.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CfC-piWZ.js → index-DUUrv141.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-D9rC-fGW.js → index-DiSkx4UB.js} +3 -3
  125. package/src/assets/web-panel/assets/{index-CvSeVzqe.js → index-Dk2qouAz.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CtM8OT_7.js → index-Dk7-v4hP.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BBz9LIMS.js → index-DmbfhJUP.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BAfY7m7i.js → index-DqBgBpgp.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BVePe_Rf.js → index-PT_5sBMA.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CDLkNkLj.js → index-U4f5izHz.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BTlsE8Df.js → index-YXgLng0K.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-BeEaAEIp.js → index-ZxO_-E8a.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-B0-zMtKA.js → index-dIHr4B_u.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-C1oZQmAA.js → index-gyFpvL7l.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-DRLQyp2A.js → index-s1opAL-M.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-OS-vfbTA.js → index-yObj1O4n.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-vrA8K-ac.js → initDefaultProps-C9h9yKL3.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-ByEzwIAl.js → motion-BvmLsPdu.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-Ck4AWjw-.js → move-CoL4ekU1.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-6p0l9SrB.js → mtc-parser-C4pMy6xV.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-B1CUPQ6R.js → omit-DPuJfNxx.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-B1STg1iW.js → pickAttrs-D0KEeaK2.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-DTTllkBV.js → placementArrow-BpkyINxt.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-AIrrCfBb.js → responsiveObserve-DQI_wOq8.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-C_fPMjdR.js → slide-DYfdDiRg.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-D5ow2yIP.js → statusUtils-B5dtvb0D.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-Dy3hEA--.js → styleChecker-CF310mSj.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-WfzcfSh4.js → useFlexGapSupport-D1Qp4BLp.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-CKSejfas.js → useFs-C7_iyvJK.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-od3zpPBN.js → usePersonalDataHub-DZUt_fIm.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-DRD_2DFA.js → vnode-D3dsi0lZ.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-DmNrEtgf.js → zoom-WdbOlvdQ.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/command-help-index.json +5 -5
  155. package/src/command-manifest.json +1 -1
  156. package/src/commands/agenda.js +76 -4
  157. package/src/commands/agent.js +90 -1
  158. package/src/commands/automation.js +462 -3
  159. package/src/commands/background-session.js +102 -1
  160. package/src/commands/chat.js +11 -2
  161. package/src/commands/compact.js +106 -23
  162. package/src/commands/cowork.js +6 -1
  163. package/src/commands/loop.js +187 -38
  164. package/src/commands/routine.js +12 -5
  165. package/src/commands/scheduler-daemon.js +807 -0
  166. package/src/commands/session-observability.js +305 -0
  167. package/src/commands/session.js +38 -0
  168. package/src/data/changelog.json +28 -2
  169. package/src/gateways/ws/ws-agent-handler.js +439 -5
  170. package/src/harness/jsonl-session-store.js +463 -125
  171. package/src/harness/prompt-compressor.js +86 -13
  172. package/src/harness/provider-backed-compaction.js +100 -27
  173. package/src/lib/advisor-runtime.js +3 -1
  174. package/src/lib/agent-schedule-store.js +737 -47
  175. package/src/lib/agent-team/team-adjudication.js +40 -1
  176. package/src/lib/automation-center-routines.js +363 -0
  177. package/src/lib/automation-center.js +435 -0
  178. package/src/lib/automation-engine.js +568 -19
  179. package/src/lib/automation-execution-authority.js +736 -0
  180. package/src/lib/background-agent-supervisor.js +871 -215
  181. package/src/lib/background-command-argv.js +24 -0
  182. package/src/lib/background-interaction-journal.js +361 -52
  183. package/src/lib/background-interaction-resolver.js +32 -0
  184. package/src/lib/background-launch-profile.js +2 -0
  185. package/src/lib/background-needs-input-incident.js +221 -0
  186. package/src/lib/causal-observability.js +2661 -0
  187. package/src/lib/chat-session-admission.js +76 -0
  188. package/src/lib/cost-budget.js +5 -7
  189. package/src/lib/cowork/ab-comparator-cli.js +11 -0
  190. package/src/lib/cowork/debate-review-cli.js +12 -0
  191. package/src/lib/cowork-adapter.js +159 -38
  192. package/src/lib/cowork-cron.js +673 -19
  193. package/src/lib/cowork-observe.js +5 -1
  194. package/src/lib/cowork-task-runner.js +112 -17
  195. package/src/lib/delivery-coordinator.js +142 -0
  196. package/src/lib/direct-model-usage.js +121 -0
  197. package/src/lib/file-lines.js +183 -47
  198. package/src/lib/llm-pricing.js +12 -17
  199. package/src/lib/loop.js +62 -3
  200. package/src/lib/permission-engine.js +14 -7
  201. package/src/lib/public-ide-capability-manifest.js +2 -0
  202. package/src/lib/routine-store.js +546 -86
  203. package/src/lib/runtime-usage-ledger.js +182 -0
  204. package/src/lib/scheduler-kernel/agenda-adapter.js +604 -29
  205. package/src/lib/scheduler-kernel/authority-resolver.js +163 -0
  206. package/src/lib/scheduler-kernel/automation-adapter.js +994 -0
  207. package/src/lib/scheduler-kernel/automation-event-adapter.js +757 -0
  208. package/src/lib/scheduler-kernel/contract.js +11 -3
  209. package/src/lib/scheduler-kernel/cowork-cron-adapter.js +343 -15
  210. package/src/lib/scheduler-kernel/loop-adapter.js +913 -0
  211. package/src/lib/scheduler-kernel/migration-admin.js +346 -0
  212. package/src/lib/scheduler-kernel/migration-rollback-admin.js +932 -0
  213. package/src/lib/scheduler-kernel/routine-adapter.js +691 -22
  214. package/src/lib/scheduler-kernel/runtime.js +63 -1
  215. package/src/lib/scheduler-kernel/service.js +328 -0
  216. package/src/lib/scheduler-kernel/source-locator-path.js +142 -0
  217. package/src/lib/scheduler-kernel/store.js +3439 -206
  218. package/src/lib/session-host-lease.js +171 -2
  219. package/src/lib/session-host-snapshot.js +14 -3
  220. package/src/lib/session-persistence-failure.js +1 -0
  221. package/src/lib/session-tail.js +179 -34
  222. package/src/lib/session-transcript-structure.js +96 -0
  223. package/src/lib/sub-agent-context.js +328 -22
  224. package/src/lib/ws-agent-handler.js +4 -1
  225. package/src/repl/agent-repl.js +732 -91
  226. package/src/repl/chat-repl.js +5 -1
  227. package/src/runtime/agent-core.js +1274 -208
  228. package/src/runtime/coding-agent-contract-shared.cjs +5 -0
  229. package/src/runtime/fallback-model.js +5 -0
  230. package/src/runtime/headless-runner.js +324 -82
  231. package/src/runtime/headless-stream.js +232 -26
  232. package/src/runtime/policies/agent-policy.js +4 -0
  233. package/src/workers/background-agent-worker.js +468 -98
  234. package/src/assets/web-panel/assets/devWarning-CdwPwYj8.js +0 -1
  235. package/src/assets/web-panel/assets/index-BEeOdfEe.js +0 -1
  236. package/src/assets/web-panel/assets/index-BTe0TOu6.js +0 -1
@@ -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
 
@@ -42,6 +43,7 @@ export const NODE_TYPE = Object.freeze({
42
43
  PARALLEL: "parallel",
43
44
  LOOP: "loop",
44
45
  });
46
+ export const AUTOMATION_SCHEDULER_MIGRATION_SCHEMA_VERSION = 1;
45
47
 
46
48
  /* ── Built-in connector catalog ────────────────────────────── */
47
49
 
@@ -309,6 +311,33 @@ export function ensureAutomationTables(db) {
309
311
  created_at TEXT DEFAULT (datetime('now'))
310
312
  )
311
313
  `);
314
+ db.exec(`
315
+ CREATE TABLE IF NOT EXISTS auto_scheduler_migrations (
316
+ flow_id TEXT PRIMARY KEY NOT NULL,
317
+ schema_version INTEGER NOT NULL CHECK (schema_version = 1),
318
+ state TEXT NOT NULL CHECK (state IN ('prepared', 'retired')),
319
+ migration_id TEXT NOT NULL UNIQUE,
320
+ source_digest TEXT NOT NULL,
321
+ target_job_id TEXT NOT NULL UNIQUE,
322
+ retirement_token TEXT UNIQUE,
323
+ prior_status TEXT NOT NULL CHECK (prior_status = 'active'),
324
+ prior_updated_at TEXT NOT NULL,
325
+ source_snapshot TEXT,
326
+ prepared_at TEXT NOT NULL,
327
+ retired_at TEXT
328
+ )
329
+ `);
330
+ const migrationColumns = new Set(
331
+ db
332
+ .prepare("PRAGMA table_info(auto_scheduler_migrations)")
333
+ .all()
334
+ .map((column) => column.name),
335
+ );
336
+ if (!migrationColumns.has("source_snapshot")) {
337
+ db.exec(
338
+ "ALTER TABLE auto_scheduler_migrations ADD COLUMN source_snapshot TEXT",
339
+ );
340
+ }
312
341
  }
313
342
 
314
343
  /* ── Helpers ───────────────────────────────────────────────── */
@@ -321,6 +350,89 @@ function _now() {
321
350
  return new Date().toISOString();
322
351
  }
323
352
 
353
+ function _stableJsonValue(value) {
354
+ if (Array.isArray(value)) return value.map(_stableJsonValue);
355
+ if (value && typeof value === "object") {
356
+ return Object.fromEntries(
357
+ Object.keys(value)
358
+ .sort()
359
+ .map((key) => [key, _stableJsonValue(value[key])]),
360
+ );
361
+ }
362
+ return value;
363
+ }
364
+
365
+ function _automationMigrationField(value, field) {
366
+ if (typeof value !== "string" || value.trim().length === 0) {
367
+ const error = new Error(
368
+ `automation scheduler migration ${field} is required`,
369
+ );
370
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_INVALID";
371
+ throw error;
372
+ }
373
+ return value.trim();
374
+ }
375
+
376
+ function _automationTransaction(db, callback) {
377
+ if (typeof db.transaction !== "function") return callback();
378
+ const transaction = db.transaction(callback);
379
+ return typeof transaction.immediate === "function"
380
+ ? transaction.immediate()
381
+ : transaction();
382
+ }
383
+
384
+ function _rowToSchedulerMigration(row) {
385
+ if (!row) return null;
386
+ return {
387
+ flowId: row.flow_id,
388
+ schemaVersion: row.schema_version,
389
+ state: row.state,
390
+ migrationId: row.migration_id,
391
+ sourceDigest: row.source_digest,
392
+ targetJobId: row.target_job_id,
393
+ retirementToken: row.retirement_token || null,
394
+ priorStatus: row.prior_status,
395
+ priorUpdatedAt: row.prior_updated_at,
396
+ sourceSnapshot: _parseJSON(row.source_snapshot, null),
397
+ preparedAt: row.prepared_at,
398
+ retiredAt: row.retired_at || null,
399
+ };
400
+ }
401
+
402
+ function _automationMigrationOptionalField(value, field) {
403
+ if (value == null) return null;
404
+ return _automationMigrationField(value, field);
405
+ }
406
+
407
+ function _automationMigrationSourceDefinition(migration) {
408
+ const source = migration?.sourceSnapshot;
409
+ if (
410
+ !source ||
411
+ typeof source !== "object" ||
412
+ source.id !== migration.flowId ||
413
+ source.status !== migration.priorStatus ||
414
+ typeof source.schedule !== "string" ||
415
+ source.schedule.length === 0
416
+ ) {
417
+ const error = new Error(
418
+ `Automation migration source definition is invalid: ${migration?.flowId || "unknown"}`,
419
+ );
420
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_CONFLICT";
421
+ throw error;
422
+ }
423
+ return source;
424
+ }
425
+
426
+ function _assertAutomationSchedulerMutationSafe(db, flowId) {
427
+ const migration = getAutomationSchedulerMigration(db, flowId);
428
+ if (!migration) return;
429
+ const error = new Error(
430
+ `Automation flow scheduler authority is owned by migration ${migration.migrationId}: ${flowId}`,
431
+ );
432
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_ACTIVE";
433
+ throw error;
434
+ }
435
+
324
436
  function _parseJSON(value, fallback) {
325
437
  if (value == null) return fallback;
326
438
  if (typeof value !== "string") return value;
@@ -468,6 +580,292 @@ export function getFlow(db, flowId) {
468
580
  );
469
581
  }
470
582
 
583
+ export function automationMigrationSourceSnapshot(flow) {
584
+ const source = { ...flow };
585
+ delete source.updatedAt;
586
+ delete source.schedulerMigration;
587
+ return _stableJsonValue(source);
588
+ }
589
+
590
+ export function automationMigrationSourceDigest(flow) {
591
+ return crypto
592
+ .createHash("sha256")
593
+ .update("chainlesschain.automation.scheduler-migration-source.v1\0", "utf8")
594
+ .update(JSON.stringify(automationMigrationSourceSnapshot(flow)), "utf8")
595
+ .digest("hex");
596
+ }
597
+
598
+ export function getAutomationSchedulerMigration(db, flowId) {
599
+ return _rowToSchedulerMigration(
600
+ db
601
+ .prepare("SELECT * FROM auto_scheduler_migrations WHERE flow_id = ?")
602
+ .get(flowId),
603
+ );
604
+ }
605
+
606
+ export function automationEffectiveSchedulerFlow(db, flow) {
607
+ if (!flow) return flow;
608
+ const migration = getAutomationSchedulerMigration(db, flow.id);
609
+ if (
610
+ migration?.schemaVersion ===
611
+ AUTOMATION_SCHEDULER_MIGRATION_SCHEMA_VERSION &&
612
+ migration.state === "retired" &&
613
+ migration.priorStatus === FLOW_STATUS.ACTIVE &&
614
+ flow.schedule === null &&
615
+ [FLOW_STATUS.PAUSED, FLOW_STATUS.ACTIVE].includes(flow.status)
616
+ ) {
617
+ const source = _automationMigrationSourceDefinition(migration);
618
+ return {
619
+ ...flow,
620
+ status: source.status,
621
+ schedule: source.schedule,
622
+ updatedAt: migration.priorUpdatedAt,
623
+ schedulerMigration: migration,
624
+ };
625
+ }
626
+ return flow;
627
+ }
628
+
629
+ export function listAutomationSchedulerFlows(db, { limit = 10_000 } = {}) {
630
+ return db
631
+ .prepare(
632
+ `SELECT f.* FROM auto_flows f
633
+ JOIN auto_scheduler_migrations m ON m.flow_id = f.id
634
+ WHERE m.state = 'retired' AND f.schedule IS NULL
635
+ AND f.status IN ('paused', 'active')
636
+ ORDER BY f.created_at DESC LIMIT ?`,
637
+ )
638
+ .all(limit)
639
+ .map(_rowToFlow)
640
+ .map((flow) => automationEffectiveSchedulerFlow(db, flow));
641
+ }
642
+
643
+ export function prepareAutomationSchedulerMigration(
644
+ db,
645
+ flowId,
646
+ { migrationId, sourceDigest, targetJobId } = {},
647
+ ) {
648
+ const migration = _automationMigrationField(migrationId, "migrationId");
649
+ const digest = _automationMigrationField(sourceDigest, "sourceDigest");
650
+ const target = _automationMigrationField(targetJobId, "targetJobId");
651
+ return _automationTransaction(db, () => {
652
+ const flow = getFlow(db, flowId);
653
+ if (!flow) throw new Error(`Flow not found: ${flowId}`);
654
+ if (flow.status !== FLOW_STATUS.ACTIVE) {
655
+ const error = new Error(`Automation flow is not active: ${flowId}`);
656
+ error.code = "AUTOMATION_SCHEDULER_FLOW_NOT_ACTIVE";
657
+ throw error;
658
+ }
659
+ if (automationMigrationSourceDigest(flow) !== digest) {
660
+ const error = new Error(
661
+ `Automation flow changed before migration: ${flowId}`,
662
+ );
663
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_SOURCE_CHANGED";
664
+ throw error;
665
+ }
666
+ const prior = getAutomationSchedulerMigration(db, flowId);
667
+ if (prior) {
668
+ if (
669
+ prior.migrationId !== migration ||
670
+ prior.sourceDigest !== digest ||
671
+ prior.targetJobId !== target ||
672
+ prior.state !== "prepared"
673
+ ) {
674
+ const error = new Error(
675
+ `Automation flow already belongs to another migration: ${flowId}`,
676
+ );
677
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_CONFLICT";
678
+ throw error;
679
+ }
680
+ return prior;
681
+ }
682
+ const now = _now();
683
+ db.prepare(
684
+ `INSERT INTO auto_scheduler_migrations
685
+ (flow_id, schema_version, state, migration_id, source_digest,
686
+ target_job_id, retirement_token, prior_status, prior_updated_at,
687
+ source_snapshot, prepared_at, retired_at)
688
+ VALUES (?, 1, 'prepared', ?, ?, ?, NULL, 'active', ?, ?, ?, NULL)`,
689
+ ).run(
690
+ flowId,
691
+ migration,
692
+ digest,
693
+ target,
694
+ flow.updatedAt,
695
+ JSON.stringify(automationMigrationSourceSnapshot(flow)),
696
+ now,
697
+ );
698
+ return getAutomationSchedulerMigration(db, flowId);
699
+ });
700
+ }
701
+
702
+ export function retireAutomationSchedulerMigration(
703
+ db,
704
+ flowId,
705
+ { migrationId, sourceDigest, targetJobId, retirementToken } = {},
706
+ ) {
707
+ const migration = _automationMigrationField(migrationId, "migrationId");
708
+ const digest = _automationMigrationField(sourceDigest, "sourceDigest");
709
+ const target = _automationMigrationField(targetJobId, "targetJobId");
710
+ const token = _automationMigrationField(retirementToken, "retirementToken");
711
+ return _automationTransaction(db, () => {
712
+ const marker = getAutomationSchedulerMigration(db, flowId);
713
+ const flow = getFlow(db, flowId);
714
+ if (
715
+ !marker ||
716
+ marker.migrationId !== migration ||
717
+ marker.sourceDigest !== digest ||
718
+ marker.targetJobId !== target ||
719
+ !["prepared", "retired"].includes(marker.state) ||
720
+ !flow
721
+ ) {
722
+ const error = new Error(
723
+ `Automation migration changed before retirement: ${flowId}`,
724
+ );
725
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_CONFLICT";
726
+ throw error;
727
+ }
728
+ if (marker.state === "retired") {
729
+ if (
730
+ marker.retirementToken !== token ||
731
+ flow.schedule !== null ||
732
+ ![FLOW_STATUS.PAUSED, FLOW_STATUS.ACTIVE].includes(flow.status)
733
+ ) {
734
+ const error = new Error(
735
+ `Automation migration fence changed: ${flowId}`,
736
+ );
737
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_CONFLICT";
738
+ throw error;
739
+ }
740
+ if (flow.status === FLOW_STATUS.ACTIVE) {
741
+ db.prepare(
742
+ `UPDATE auto_flows SET status = 'paused' WHERE id = ? AND schedule IS NULL`,
743
+ ).run(flowId);
744
+ }
745
+ return automationEffectiveSchedulerFlow(db, flow);
746
+ }
747
+ if (automationMigrationSourceDigest(flow) !== digest) {
748
+ const error = new Error(
749
+ `Automation flow changed before retirement: ${flowId}`,
750
+ );
751
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_SOURCE_CHANGED";
752
+ throw error;
753
+ }
754
+ const now = _now();
755
+ db.prepare(
756
+ `UPDATE auto_flows SET status = 'paused', schedule = NULL, updated_at = ?
757
+ WHERE id = ? AND status = 'active' AND updated_at = ?`,
758
+ ).run(now, flowId, marker.priorUpdatedAt);
759
+ const fenced = getFlow(db, flowId);
760
+ if (fenced?.status !== FLOW_STATUS.PAUSED || fenced.schedule !== null) {
761
+ const error = new Error(
762
+ `Automation flow changed during retirement: ${flowId}`,
763
+ );
764
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_CONFLICT";
765
+ throw error;
766
+ }
767
+ const changed = db
768
+ .prepare(
769
+ `UPDATE auto_scheduler_migrations
770
+ SET state = 'retired', retirement_token = ?, retired_at = ?
771
+ WHERE flow_id = ? AND state = 'prepared'`,
772
+ )
773
+ .run(token, now, flowId);
774
+ if (changed.changes !== 1) {
775
+ const error = new Error(
776
+ `Automation migration changed during retirement: ${flowId}`,
777
+ );
778
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_CONFLICT";
779
+ throw error;
780
+ }
781
+ return automationEffectiveSchedulerFlow(db, getFlow(db, flowId));
782
+ });
783
+ }
784
+
785
+ export function restoreAutomationSchedulerMigration(
786
+ db,
787
+ flowId,
788
+ { migrationId, sourceDigest, targetJobId, retirementToken } = {},
789
+ ) {
790
+ const migration = _automationMigrationField(migrationId, "migrationId");
791
+ const digest = _automationMigrationOptionalField(
792
+ sourceDigest,
793
+ "sourceDigest",
794
+ );
795
+ const target = _automationMigrationField(targetJobId, "targetJobId");
796
+ const token = _automationMigrationOptionalField(
797
+ retirementToken,
798
+ "retirementToken",
799
+ );
800
+ return _automationTransaction(db, () => {
801
+ const marker = getAutomationSchedulerMigration(db, flowId);
802
+ const flow = getFlow(db, flowId);
803
+ if (!marker) {
804
+ if (flow && digest && automationMigrationSourceDigest(flow) === digest) {
805
+ return flow;
806
+ }
807
+ const error = new Error(
808
+ `Automation migration fence changed before rollback: ${flowId}`,
809
+ );
810
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_CONFLICT";
811
+ throw error;
812
+ }
813
+ const source = _automationMigrationSourceDefinition(marker);
814
+ if (
815
+ marker.migrationId !== migration ||
816
+ marker.targetJobId !== target ||
817
+ (digest !== null && marker.sourceDigest !== digest) ||
818
+ marker.priorStatus !== FLOW_STATUS.ACTIVE ||
819
+ !flow
820
+ ) {
821
+ const error = new Error(
822
+ `Automation migration fence changed before rollback: ${flowId}`,
823
+ );
824
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_CONFLICT";
825
+ throw error;
826
+ }
827
+ if (marker.state === "prepared") {
828
+ if (
829
+ token !== null ||
830
+ marker.retirementToken !== null ||
831
+ automationMigrationSourceDigest(flow) !== marker.sourceDigest
832
+ ) {
833
+ const error = new Error(
834
+ `Automation migration fence changed before rollback: ${flowId}`,
835
+ );
836
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_CONFLICT";
837
+ throw error;
838
+ }
839
+ db.prepare("DELETE FROM auto_scheduler_migrations WHERE flow_id = ?").run(
840
+ flowId,
841
+ );
842
+ return flow;
843
+ }
844
+ if (
845
+ marker.state !== "retired" ||
846
+ marker.retirementToken !== token ||
847
+ flow.schedule !== null ||
848
+ ![FLOW_STATUS.PAUSED, FLOW_STATUS.ACTIVE].includes(flow.status) ||
849
+ automationMigrationSourceDigest(
850
+ automationEffectiveSchedulerFlow(db, flow),
851
+ ) !== marker.sourceDigest
852
+ ) {
853
+ const error = new Error(
854
+ `Automation migration fence changed before rollback: ${flowId}`,
855
+ );
856
+ error.code = "AUTOMATION_SCHEDULER_MIGRATION_CONFLICT";
857
+ throw error;
858
+ }
859
+ db.prepare(
860
+ `UPDATE auto_flows SET status = ?, schedule = ?, updated_at = ? WHERE id = ?`,
861
+ ).run(source.status, source.schedule, marker.priorUpdatedAt, flowId);
862
+ db.prepare("DELETE FROM auto_scheduler_migrations WHERE flow_id = ?").run(
863
+ flowId,
864
+ );
865
+ return getFlow(db, flowId);
866
+ });
867
+ }
868
+
471
869
  export function listFlows(db, filters = {}) {
472
870
  const { status, limit = 50 } = filters;
473
871
  const all = db.data?.get("auto_flows") || [];
@@ -499,6 +897,7 @@ export function updateFlowStatus(db, flowId, status) {
499
897
  throw new Error(`Invalid flow status: ${status}`);
500
898
  }
501
899
  _requireFlow(db, flowId);
900
+ _assertAutomationSchedulerMutationSafe(db, flowId);
502
901
  db.prepare(
503
902
  `UPDATE auto_flows SET status = ?, updated_at = ? WHERE id = ?`,
504
903
  ).run(status, _now(), flowId);
@@ -509,6 +908,7 @@ export function updateFlowStatus(db, flowId, status) {
509
908
 
510
909
  export function deleteFlow(db, flowId) {
511
910
  _requireFlow(db, flowId);
911
+ _assertAutomationSchedulerMutationSafe(db, flowId);
512
912
  db.prepare(`DELETE FROM auto_triggers WHERE flow_id = ?`).run(flowId);
513
913
  db.prepare(`DELETE FROM auto_executions WHERE flow_id = ?`).run(flowId);
514
914
  db.prepare(`DELETE FROM auto_flows WHERE id = ?`).run(flowId);
@@ -519,7 +919,14 @@ export function scheduleFlow(db, flowId, cron) {
519
919
  if (!cron || typeof cron !== "string") {
520
920
  throw new Error("cron expression required");
521
921
  }
922
+ // Validate at write time so an invalid schedule cannot poison a resident
923
+ // scheduler loop later. nextCronTime() parses the existing five-field cron
924
+ // dialect and returns the first matching minute.
925
+ if (nextCronTime(cron, Date.now()) === null) {
926
+ throw new Error("cron expression has no occurrence in the next 366 days");
927
+ }
522
928
  _requireFlow(db, flowId);
929
+ _assertAutomationSchedulerMutationSafe(db, flowId);
523
930
  db.prepare(
524
931
  `UPDATE auto_flows SET schedule = ?, updated_at = ? WHERE id = ?`,
525
932
  ).run(cron, _now(), flowId);
@@ -732,29 +1139,45 @@ export function executeFlow(db, flowId, options = {}) {
732
1139
  inputData = {},
733
1140
  triggerType = TRIGGER_TYPE.MANUAL,
734
1141
  testMode = false,
1142
+ executionId,
735
1143
  } = options;
736
- const execId = _genId("exec");
1144
+ const execId =
1145
+ executionId === undefined
1146
+ ? _genId("exec")
1147
+ : _normalizeExecutionId(executionId);
1148
+ const existing = getExecution(db, execId);
1149
+ if (existing) {
1150
+ return _resolveExistingExecution(existing, { flowId, triggerType });
1151
+ }
737
1152
  const startedAt = _now();
738
1153
  const startMs = Date.now();
739
1154
 
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
- );
1155
+ try {
1156
+ db.prepare(
1157
+ `INSERT INTO auto_executions
1158
+ (id, flow_id, trigger_type, input_data, output_data, status, steps_log, duration_ms, error, test_mode, started_at, completed_at)
1159
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
1160
+ ).run(
1161
+ execId,
1162
+ flowId,
1163
+ triggerType,
1164
+ JSON.stringify(inputData),
1165
+ null,
1166
+ EXECUTION_STATUS.RUNNING,
1167
+ JSON.stringify([]),
1168
+ 0,
1169
+ null,
1170
+ testMode ? 1 : 0,
1171
+ startedAt,
1172
+ null,
1173
+ );
1174
+ } catch (error) {
1175
+ // A deterministic scheduler execution id may race another process. Resolve
1176
+ // the winner from durable evidence instead of running the flow twice.
1177
+ const concurrent = getExecution(db, execId);
1178
+ if (!concurrent) throw error;
1179
+ return _resolveExistingExecution(concurrent, { flowId, triggerType });
1180
+ }
758
1181
 
759
1182
  const stepsLog = [];
760
1183
  let finalStatus = EXECUTION_STATUS.SUCCESS;
@@ -817,6 +1240,132 @@ export function executeFlow(db, flowId, options = {}) {
817
1240
  );
818
1241
  }
819
1242
 
1243
+ export function adjudicateAutomationExecution(
1244
+ db,
1245
+ executionId,
1246
+ { flowId, triggerType, decision, requestId } = {},
1247
+ ) {
1248
+ const execId = _normalizeExecutionId(executionId);
1249
+ if (!["confirmed_applied", "confirmed_not_applied"].includes(decision)) {
1250
+ const error = new Error("automation adjudication decision is invalid");
1251
+ error.code = "AUTOMATION_ADJUDICATION_INVALID";
1252
+ throw error;
1253
+ }
1254
+ const marker = JSON.stringify({
1255
+ authority: "scheduler-adjudication",
1256
+ requestId,
1257
+ decision,
1258
+ });
1259
+ const archivedId = `${execId}:adjudication:${String(requestId).slice(-24)}`;
1260
+ const existing = getExecution(db, execId);
1261
+ const archived = getExecution(db, archivedId);
1262
+ if (decision === "confirmed_not_applied" && archived) {
1263
+ if (
1264
+ archived.flowId !== flowId ||
1265
+ archived.triggerType !== triggerType ||
1266
+ archived.error !== marker
1267
+ ) {
1268
+ const error = new Error(
1269
+ `Automation adjudication archive mismatch: ${execId}`,
1270
+ );
1271
+ error.code = "AUTOMATION_ADJUDICATION_EVIDENCE_MISMATCH";
1272
+ throw error;
1273
+ }
1274
+ return archived;
1275
+ }
1276
+ if (!existing) {
1277
+ const error = new Error(`Automation execution not found: ${execId}`);
1278
+ error.code = "AUTOMATION_ADJUDICATION_EVIDENCE_MISMATCH";
1279
+ throw error;
1280
+ }
1281
+ if (existing.flowId !== flowId || existing.triggerType !== triggerType) {
1282
+ const error = new Error(`Automation execution binding mismatch: ${execId}`);
1283
+ error.code = "AUTOMATION_ADJUDICATION_EVIDENCE_MISMATCH";
1284
+ throw error;
1285
+ }
1286
+ if (
1287
+ existing.status !== EXECUTION_STATUS.RUNNING &&
1288
+ existing.error === marker
1289
+ ) {
1290
+ return existing;
1291
+ }
1292
+ if (existing.status !== EXECUTION_STATUS.RUNNING) {
1293
+ const error = new Error(
1294
+ `Automation execution is not outcome-unknown: ${execId}`,
1295
+ );
1296
+ error.code = "AUTOMATION_ADJUDICATION_EVIDENCE_MISMATCH";
1297
+ throw error;
1298
+ }
1299
+ if (decision === "confirmed_not_applied") {
1300
+ const result = db
1301
+ .prepare(
1302
+ `UPDATE auto_executions
1303
+ SET id = ?, status = ?, error = ?, completed_at = ?
1304
+ WHERE id = ? AND status = ?`,
1305
+ )
1306
+ .run(
1307
+ archivedId,
1308
+ EXECUTION_STATUS.CANCELLED,
1309
+ marker,
1310
+ _now(),
1311
+ execId,
1312
+ EXECUTION_STATUS.RUNNING,
1313
+ );
1314
+ if (result.changes !== 1) {
1315
+ const error = new Error(
1316
+ `Automation adjudication changed concurrently: ${execId}`,
1317
+ );
1318
+ error.code = "AUTOMATION_ADJUDICATION_EVIDENCE_MISMATCH";
1319
+ throw error;
1320
+ }
1321
+ return getExecution(db, archivedId);
1322
+ }
1323
+ db.prepare(
1324
+ `UPDATE auto_executions
1325
+ SET status = ?, error = ?, completed_at = ?
1326
+ WHERE id = ? AND status = ?`,
1327
+ ).run(
1328
+ EXECUTION_STATUS.SUCCESS,
1329
+ marker,
1330
+ _now(),
1331
+ execId,
1332
+ EXECUTION_STATUS.RUNNING,
1333
+ );
1334
+ return getExecution(db, execId);
1335
+ }
1336
+
1337
+ function _normalizeExecutionId(value) {
1338
+ if (
1339
+ typeof value !== "string" ||
1340
+ value.length === 0 ||
1341
+ value.length > 256 ||
1342
+ !/^[A-Za-z0-9._:-]+$/.test(value)
1343
+ ) {
1344
+ const error = new Error("executionId must be a safe non-empty identifier");
1345
+ error.code = "AUTOMATION_EXECUTION_ID_INVALID";
1346
+ throw error;
1347
+ }
1348
+ return value;
1349
+ }
1350
+
1351
+ function _resolveExistingExecution(existing, { flowId, triggerType }) {
1352
+ if (existing.flowId !== flowId || existing.triggerType !== triggerType) {
1353
+ const error = new Error(
1354
+ `Execution id is already bound to another automation request: ${existing.id}`,
1355
+ );
1356
+ error.code = "AUTOMATION_EXECUTION_BINDING_MISMATCH";
1357
+ throw error;
1358
+ }
1359
+ if (existing.status === EXECUTION_STATUS.RUNNING) {
1360
+ const error = new Error(
1361
+ `Automation execution outcome is unknown; refusing duplicate execution: ${existing.id}`,
1362
+ );
1363
+ error.code = "AUTOMATION_EXECUTION_OUTCOME_UNKNOWN";
1364
+ throw error;
1365
+ }
1366
+ return existing;
1367
+ }
1368
+
820
1369
  export function fireTrigger(db, triggerId, inputData = {}) {
821
1370
  const trig = getTrigger(db, triggerId);
822
1371
  if (!trig) throw new Error(`Trigger not found: ${triggerId}`);