chainlesschain 0.163.3 → 0.163.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/package.json +3 -2
  2. package/scripts/command-lifecycle-report.mjs +330 -38
  3. package/src/assets/web-panel/assets/{AIOps-DIY6KxV-.js → AIOps-Cv2EE1Zy.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-BXH0muPt.js → ActionButton-CcpxMLuW.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-D39w8vmg.js → Analytics-DE8mJoMI.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-CUU1zvLs.js → AppLayout-DKn9dk9L.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-D8azHO3T.js → Artifacts-Cp3mG3Py.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-D0tAwXTg.js → Audit-zvsQfF2C.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-C29mhJll.js → BackgroundAgents-Bi85SsjN.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-D6Aa1Gro.js → Backup-Cw47Dj6s.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-B1uoHbPQ.js → BaseInput-C5Ip2afH.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-Bs4DLOR5.js → Chat-C0iAFkJv.js} +5 -5
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-DUYIBSle.js → ChatBubbleRenderer-BV9Wv7wO.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-CNcBPEa4.js → Checkbox-3KZZCiAF.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CIY89763.js → Codegen-C8OMbBAz.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-CsPYFmgo.js → Col-B-MB84LJ.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-BBocEge4.js → Community-DpR7Dxao.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-TQ8Ux0Lf.js → Compact-CyDtz0OS.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-DfBsZTft.js → Compliance-5tiRa2An.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-Cg-I6FVH.js → Cowork-DnQaKZ5x.js} +4 -4
  21. package/src/assets/web-panel/assets/{Cron-DTQzfRTp.js → Cron-BaWfoEDf.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-DGxEKGpR.js → Crosschain-Bu0HoHhb.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-DLZ1RDSr.js → DID-31zk8upX.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-XneICKNI.js → Dashboard-BmVne-e2.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-BRU00J1-.js → Dropdown-B4PkoOWd.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-BzCbJuAy.js → EmailListRenderer-BZ6tyFtI.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D7BRyNBG.js → FamilyGuardDashboard-Osozn4Ds.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-D9DeFIhW.js → Federation-DaH8TOAP.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-6rAtA9Ko.js → FormItemContext-tbU0uwis.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-8Hqy80pU.js → GenericCardRenderer-Df8LQBrL.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Cmvkj1rt.js → Git-DsMB6-14.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-BRiQUjjw.js → Governance-BnH0dZzd.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CKN_EzVf.js → Inference-DhnN1N_P.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-BCDHwpwQ.js → KnowledgeGraph-DnNshAgn.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-DK9ovhaB.js → Logs-BmBFX3_N.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-D53pHiHy.js → MarkdownRenderer-DCslfQU3.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-BILPGakp.js → Marketplace-CPEgWDc3.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-DTVCOr9-.js → McpTools-C36qjgF9.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-Hzc1iow4.js → Memory-tNHvrgqN.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-GXfgnGYV.js → MobileBridge-Xaf6cKjc.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-B-3TJWsS.js → MobileProjects-D2E5TTeO.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-DwSJMWtK.js → Mtc-D4AJ2dwV.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-D2uxf-DA.js → MtcAudit-Df-gtn2_.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-DG6kbKK0.js → Multisig-DTCHLWld.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-f5p49EDU.js → NLProgramming-DruZ_1Jb.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-FUgHyzSD.js → Notes-Dx3pdGDs.js} +4 -4
  47. package/src/assets/web-panel/assets/{NotificationSettings-DCHGee7e.js → NotificationSettings-Bi3L69oL.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-Dm6LlIoa.js → OrderTableRenderer-BHY33m7C.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-BawA7qAg.js → Organization-BG2ZVEV-.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-D6a5wZU1.js → Overflow-Viwtg4Mn.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-K8WavwnA.js → P2P-Clm_yc1Z.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-4JAJYaqx.js → PdhVaultBrowser-NKmmDiOw.js} +5 -5
  53. package/src/assets/web-panel/assets/{Permissions-BDWvi8PD.js → Permissions-DIL8u9Nk.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-DF_K4E9i.js → PersonalDataHub-B-jM4wt-.js} +4 -4
  55. package/src/assets/web-panel/assets/{Pipeline-BYeZlesI.js → Pipeline-627I__H5.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-BIHlgnIc.js → Privacy-2DN2qrkW.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-Cvf-6B5P.js → ProjectInit-CN4wC0sF.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-CnwfJrRz.js → ProjectSettings-K35vsh5H.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-B_wQadhX.js +1 -0
  60. package/src/assets/web-panel/assets/{Providers-CxC7JuYv.js → Providers-MckaQUhQ.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-VLf3gAfL.js → QrScannerModal-BS3mtA_O.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-B5vGjRiF.js → QuickAsk-BHp_nofL.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend--UW4iYs-.js → Recommend-DlmnPuZj.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-DMSPcfKR.js → RemoteSession-tsyFbvpy.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-kQXlEHmj.js → Reputation-Ba1iWv2D.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-CxGu3pit.js → Row-NnlGC--f.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-Bi5lo8MZ.js → RssFeed-CjThSIRv.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-Cq_H5RTh.js → Search-CojUyC5x.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-YFbmkaQS.js → Security-c-sxeJEc.js} +3 -3
  70. package/src/assets/web-panel/assets/{Services-DLOGdaLm.js → Services-CtcKEEmF.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-CteIxb3D.js → Skeleton-CIBBXflN.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-CccopaIZ.js → Skills-D1XOOK9n.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-AzfEQKX1.js → Sla-hRfEp5Sn.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-ekGo5l77.js → SpeechSettings-Dexb1f_6.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-BmZmAgYH.js → SyncSettings-BJsSFGYy.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-D7q3Z4uL.js → Tasks-CfSZ8A1L.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-CX1Tgeka.js → Templates-idDf47W-.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-Zc59jF4i.js → Tenant-C-UsX6w6.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-CXOD7y83.js → Terminal-BgJtX5n1.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-B1aBHPBo.js → TimelineRenderer-DP0BLKTl.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-zALlOq_U.js → Tokens-LwCzqETp.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-CQfJMXaq.js → Trigger-D_9tVch0.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-BU0RcM-w.js → Trust-BH2UlEWh.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-IFZ3HsbH.js → UkeySign-CIpD0nYb.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-BzslgW0v.js → VideoEditing-9ShhYxK_.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-BZAcQNS6.js → Wallet-C7afGNIG.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-CBK1DMi0.js → WebAuthn-bUKn6i5R.js} +3 -3
  88. package/src/assets/web-panel/assets/{WorkflowEditor-BlMTPzO-.js → WorkflowEditor-CxgQaGyp.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-B51-8QVn.js → chat-DMVkmJwx.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-504RTByU.js → colors-CDzQh5nS.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-C-GP6IQM.js → compact-item-C51kEF4D.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-DOkIj7ID.js → createContext-BTk9bXBn.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-CdwPwYj8.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-DN7V-_FW.js → hasIn-CMje33rb.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CKTfZyfU.js → index-0Auljb10.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-D9LyiN-L.js → index-B0-zMtKA.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DEMPUVa3.js → index-BAfY7m7i.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-Bkxhaeta.js → index-BBz9LIMS.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-7jIqHbzw.js → index-BCRvG9lq.js} +1 -1
  100. package/src/assets/web-panel/assets/index-BEeOdfEe.js +1 -0
  101. package/src/assets/web-panel/assets/index-BTe0TOu6.js +1 -0
  102. package/src/assets/web-panel/assets/{index-P2mfY27Z.js → index-BTlsE8Df.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DAOpQvl_.js → index-BVePe_Rf.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CYopNjcJ.js → index-BW4F5YDF.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B_vGU-Js.js → index-BXQBPLyE.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-kt_5rfcZ.js → index-BeEaAEIp.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Cao5DZy7.js → index-BtlEqHLP.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DA2f1UV3.js → index-BzCkNylB.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-B2-x9bS8.js → index-C1oZQmAA.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-D1phyca8.js → index-C1oZReaY.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-FcV8J_Qz.js → index-C4rQCS8T.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-C3TSohzc.js → index-C5IWTMVl.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-CySTJKeq.js → index-CCLj9hcD.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-C9_48OzU.js → index-CDLkNkLj.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-so8eIIxF.js → index-Cd0hmPxD.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CX78k-qf.js → index-CfC-piWZ.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DE-hmI2l.js → index-CtM8OT_7.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-kAqQXfP6.js → index-CvSeVzqe.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-C0k_Nqg9.js → index-CwGPwjUu.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CP2A226L.js → index-CypsfcEq.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CfiEM64n.js → index-D9rC-fGW.js} +3 -3
  122. package/src/assets/web-panel/assets/{index-yYTQZypF.js → index-DJfnCuMq.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-f4Bo4KXm.js → index-DRG-aqOs.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-By6u5IV1.js → index-DRLQyp2A.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-ConjaJro.js → index-DgivOKHA.js} +1 -1
  126. package/src/assets/web-panel/assets/{index--n-ZciV3.js → index-DpcrFxMI.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CqcLo5WV.js → index-DqU9njjT.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CUhQpiYv.js → index-Ld_4mFmC.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-C4DV_5uA.js → index-OS-vfbTA.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DaA__-q1.js → index-h31MwrME.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BFIFJ5Dr.js → index-hg_emBsi.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-C8UltbXK.js → index-togc_uYn.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-et5JIPHO.js → index-x53Vf7la.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-CPYEIdpV.js → initDefaultProps-vrA8K-ac.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-Cjim9pxs.js → motion-ByEzwIAl.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-DuU-cgz3.js → move-Ck4AWjw-.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-DJHNAkta.js → mtc-parser-6p0l9SrB.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-DSQBgdBj.js → omit-B1CUPQ6R.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-CTmT_j5m.js → pickAttrs-B1STg1iW.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-Lfm6v-r4.js → placementArrow-DTTllkBV.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-CgrcPcDi.js → responsiveObserve-AIrrCfBb.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-CuE3110i.js → slide-C_fPMjdR.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-DiK5nbpf.js → statusUtils-D5ow2yIP.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-DPEJdQaZ.js → styleChecker-Dy3hEA--.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-CnnodGmp.js → useFlexGapSupport-WfzcfSh4.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-DWF84Yav.js → useFs-CKSejfas.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-a5b5Dw2f.js → usePersonalDataHub-od3zpPBN.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-DAluzXOq.js → vnode-DRD_2DFA.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-Dokg7uAZ.js → zoom-DmNrEtgf.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/command-help-index.json +1 -1
  152. package/src/commands/agenda.js +52 -6
  153. package/src/commands/artifacts.js +98 -0
  154. package/src/commands/cowork.js +24 -12
  155. package/src/commands/mcp.js +1 -1
  156. package/src/commands/review.js +221 -22
  157. package/src/commands/routine.js +40 -10
  158. package/src/commands/session-mcp-recovery.js +5 -5
  159. package/src/data/changelog.json +27 -1
  160. package/src/gateways/ws/ws-agent-handler.js +492 -14
  161. package/src/harness/jsonl-session-store.js +39 -1
  162. package/src/harness/mcp-client.js +172 -29
  163. package/src/harness/prompt-compressor.js +24 -0
  164. package/src/harness/provider-backed-compaction.js +205 -0
  165. package/src/lib/agent-schedule-store.js +197 -4
  166. package/src/lib/app-preview.js +3 -0
  167. package/src/lib/command-lifecycle-report.js +1340 -145
  168. package/src/lib/cowork-cron.js +243 -25
  169. package/src/lib/delivery-coordinator.js +30 -5
  170. package/src/lib/delivery-production-adapter.js +1777 -0
  171. package/src/lib/delivery-production-runner.js +240 -0
  172. package/src/lib/durable-security-store.js +29 -17
  173. package/src/lib/execution-trace/trace-context.cjs +179 -0
  174. package/src/lib/execution-trace/trace-context.js +8 -175
  175. package/src/lib/mcp-call-ledger-store.js +58 -6
  176. package/src/lib/mcp-host-recovery-runtime.js +2 -0
  177. package/src/lib/mcp-ledger-recovery-admission.js +39 -3
  178. package/src/lib/mcp-recovery-adjudication.js +256 -19
  179. package/src/lib/mcp-sandbox-policy.js +29 -0
  180. package/src/lib/mcp-stdio-capsule-builder-worker.cjs +495 -0
  181. package/src/lib/mcp-stdio-executable-identity.js +33 -2
  182. package/src/lib/mcp-stdio-immutable-vfs-resolver.cjs +830 -0
  183. package/src/lib/mcp-stdio-package-materialization.js +721 -333
  184. package/src/lib/micro-compact.js +11 -5
  185. package/src/lib/observability/index.js +2 -0
  186. package/src/lib/observability/otlp-exporter.js +2 -2
  187. package/src/lib/packer/pack-update-applier.js +8 -1
  188. package/src/lib/packer/pkg-config-generator.js +34 -0
  189. package/src/lib/process-execution-broker/index.js +48 -8
  190. package/src/lib/process-execution-broker/platform-sandbox.js +82 -1
  191. package/src/lib/routine-store.js +76 -3
  192. package/src/lib/scheduler-kernel/agenda-adapter.js +542 -0
  193. package/src/lib/scheduler-kernel/contract.js +315 -0
  194. package/src/lib/scheduler-kernel/cowork-cron-adapter.js +774 -0
  195. package/src/lib/scheduler-kernel/routine-adapter.js +517 -0
  196. package/src/lib/scheduler-kernel/runtime.js +527 -0
  197. package/src/lib/scheduler-kernel/store.js +1455 -0
  198. package/src/lib/session-host-lease.js +403 -30
  199. package/src/lib/session-message-provenance.js +4 -1
  200. package/src/lib/session-persistence-failure.js +4 -1
  201. package/src/lib/sub-agent-context.js +8 -0
  202. package/src/repl/agent-repl.js +309 -43
  203. package/src/runtime/agent-core.js +1079 -105
  204. package/src/runtime/headless-runner.js +260 -166
  205. package/src/runtime/headless-stream.js +254 -25
  206. package/src/assets/web-panel/assets/Projects-b-jPXzF4.js +0 -1
  207. package/src/assets/web-panel/assets/devWarning-kB0nCNwN.js +0 -1
  208. package/src/assets/web-panel/assets/index-Bya64sZE.js +0 -1
  209. package/src/assets/web-panel/assets/index-D_FWpDZM.js +0 -1
@@ -0,0 +1,517 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { nextCronTime } from "../agent-schedule-store.js";
3
+ import { executeRoutine } from "../routine-store.js";
4
+ import {
5
+ SchedulerKernelError,
6
+ canonicalJson,
7
+ normalizeEpochMs,
8
+ normalizeIdentifier,
9
+ } from "./contract.js";
10
+ import { SchedulerRuntime } from "./runtime.js";
11
+
12
+ export const ROUTINE_SCHEDULER_KIND = "routine";
13
+ export const ROUTINE_SCHEDULER_CAPABILITY = "agent.execute";
14
+ export const ROUTINE_SCHEDULER_CHANNELS = Object.freeze({
15
+ SCHEDULED: "scheduled",
16
+ MANUAL: "manual",
17
+ });
18
+
19
+ function routineError(code, message, details = undefined, cause = undefined) {
20
+ const error = new SchedulerKernelError(
21
+ code,
22
+ message,
23
+ details,
24
+ cause ? { cause } : undefined,
25
+ );
26
+ error.retryable = false;
27
+ return error;
28
+ }
29
+
30
+ function normalizeRoutine(routine) {
31
+ if (!routine || typeof routine !== "object" || Array.isArray(routine)) {
32
+ throw routineError(
33
+ "SCHEDULER_ROUTINE_INVALID",
34
+ "Routine scheduler adapter requires a routine object",
35
+ );
36
+ }
37
+ const id = normalizeIdentifier(routine.id, "routine.id");
38
+ const name = normalizeIdentifier(routine.name, "routine.name");
39
+ if (typeof routine.prompt !== "string" || routine.prompt.length === 0) {
40
+ throw routineError(
41
+ "SCHEDULER_ROUTINE_INVALID",
42
+ `Routine prompt is missing: ${id}`,
43
+ );
44
+ }
45
+ if (
46
+ !routine.trigger ||
47
+ typeof routine.trigger !== "object" ||
48
+ Array.isArray(routine.trigger) ||
49
+ typeof routine.trigger.kind !== "string"
50
+ ) {
51
+ throw routineError(
52
+ "SCHEDULER_ROUTINE_INVALID",
53
+ `Routine trigger is missing: ${id}`,
54
+ );
55
+ }
56
+ return {
57
+ id,
58
+ name,
59
+ prompt: routine.prompt,
60
+ trigger: routine.trigger,
61
+ enabled: routine.enabled === true,
62
+ createdAt: normalizeEpochMs(
63
+ Number(routine.createdAt ?? 0),
64
+ "routine.createdAt",
65
+ ),
66
+ lastFiredAt:
67
+ routine.lastFiredAt === null || routine.lastFiredAt === undefined
68
+ ? null
69
+ : normalizeEpochMs(Number(routine.lastFiredAt), "routine.lastFiredAt"),
70
+ lastSeenGithubEventId:
71
+ routine.lastSeenGithubEventId === null ||
72
+ routine.lastSeenGithubEventId === undefined
73
+ ? null
74
+ : normalizeIdentifier(
75
+ String(routine.lastSeenGithubEventId),
76
+ "routine.lastSeenGithubEventId",
77
+ ),
78
+ };
79
+ }
80
+
81
+ export function routineSnapshot(routine) {
82
+ return normalizeRoutine(routine);
83
+ }
84
+
85
+ export function routineDefinitionSnapshot(routine) {
86
+ const snapshot = normalizeRoutine(routine);
87
+ return {
88
+ id: snapshot.id,
89
+ name: snapshot.name,
90
+ prompt: snapshot.prompt,
91
+ trigger: snapshot.trigger,
92
+ enabled: snapshot.enabled,
93
+ createdAt: snapshot.createdAt,
94
+ };
95
+ }
96
+
97
+ export function routineSnapshotDigest(routine) {
98
+ return createHash("sha256")
99
+ .update("chainlesschain.scheduler.routine.v1\0", "utf8")
100
+ .update(canonicalJson(routineSnapshot(routine), "routineSnapshot"), "utf8")
101
+ .digest("hex");
102
+ }
103
+
104
+ export function routineDefinitionDigest(routine) {
105
+ return createHash("sha256")
106
+ .update("chainlesschain.scheduler.routine-definition.v1\0", "utf8")
107
+ .update(
108
+ canonicalJson(
109
+ routineDefinitionSnapshot(routine),
110
+ "routineDefinitionSnapshot",
111
+ ),
112
+ "utf8",
113
+ )
114
+ .digest("hex");
115
+ }
116
+
117
+ function normalizeChannel(channel) {
118
+ if (!Object.values(ROUTINE_SCHEDULER_CHANNELS).includes(channel)) {
119
+ throw routineError(
120
+ "SCHEDULER_ROUTINE_INVALID_CHANNEL",
121
+ `Unsupported routine scheduler channel: ${channel}`,
122
+ );
123
+ }
124
+ return channel;
125
+ }
126
+
127
+ export function routineSchedulerJobId(routineId, channel) {
128
+ return `routine:${normalizeIdentifier(routineId, "routineId")}:${normalizeChannel(channel)}`;
129
+ }
130
+
131
+ export function routineSchedulerRunId(occurrenceId) {
132
+ return `run-scheduler-${normalizeIdentifier(occurrenceId, "occurrenceId")}`;
133
+ }
134
+
135
+ export function buildRoutineSchedulerJob(
136
+ routine,
137
+ { channel = ROUTINE_SCHEDULER_CHANNELS.SCHEDULED } = {},
138
+ ) {
139
+ const normalizedChannel = normalizeChannel(channel);
140
+ const snapshot =
141
+ normalizedChannel === ROUTINE_SCHEDULER_CHANNELS.MANUAL
142
+ ? routineDefinitionSnapshot(routine)
143
+ : routineSnapshot(routine);
144
+ const snapshotType =
145
+ normalizedChannel === ROUTINE_SCHEDULER_CHANNELS.MANUAL
146
+ ? "definition"
147
+ : "state";
148
+ const snapshotDigest =
149
+ snapshotType === "definition"
150
+ ? routineDefinitionDigest(snapshot)
151
+ : routineSnapshotDigest(snapshot);
152
+ return {
153
+ id: routineSchedulerJobId(snapshot.id, normalizedChannel),
154
+ kind: ROUTINE_SCHEDULER_KIND,
155
+ trigger: {
156
+ source: "routine-store",
157
+ channel: normalizedChannel,
158
+ routineKind: snapshot.trigger.kind,
159
+ },
160
+ payload: {
161
+ channel: normalizedChannel,
162
+ routine: snapshot,
163
+ snapshotType,
164
+ snapshotDigest,
165
+ },
166
+ authority: {
167
+ schemaVersion: 1,
168
+ principal: { type: "routine", id: snapshot.id },
169
+ tenantId: null,
170
+ workspaceId: null,
171
+ requestedCapabilities: [ROUTINE_SCHEDULER_CAPABILITY],
172
+ authorizationRefs: {
173
+ decisionId: null,
174
+ policyRevision: null,
175
+ grantIds: [],
176
+ approvalIds: [],
177
+ delegationIds: [],
178
+ },
179
+ },
180
+ enabled:
181
+ normalizedChannel === ROUTINE_SCHEDULER_CHANNELS.MANUAL
182
+ ? true
183
+ : snapshot.enabled,
184
+ // More than one claim is required to recover a process crash. Deterministic
185
+ // run evidence prevents a completed/unknown agent outcome from executing
186
+ // twice, while ordinary adapter failures remain explicitly non-retryable.
187
+ maxAttempts: 3,
188
+ };
189
+ }
190
+
191
+ function comparableJob(job) {
192
+ return {
193
+ kind: job.kind,
194
+ trigger: job.trigger,
195
+ payload: job.payload,
196
+ authority: job.authority,
197
+ enabled: job.enabled,
198
+ maxAttempts: job.maxAttempts,
199
+ };
200
+ }
201
+
202
+ function sameJob(current, desired) {
203
+ return (
204
+ current !== null &&
205
+ canonicalJson(comparableJob(current), "currentJob") ===
206
+ canonicalJson(comparableJob(desired), "desiredJob")
207
+ );
208
+ }
209
+
210
+ export function syncRoutineSchedulerJob(schedulerStore, routine, options = {}) {
211
+ const desired = buildRoutineSchedulerJob(routine, options);
212
+ let current = schedulerStore.getJob(desired.id);
213
+ if (!current) {
214
+ try {
215
+ return schedulerStore.createJob(desired);
216
+ } catch (error) {
217
+ if (error?.code !== "SCHEDULER_CONFLICT") throw error;
218
+ current = schedulerStore.getJob(desired.id);
219
+ }
220
+ }
221
+ if (sameJob(current, desired)) return current;
222
+ try {
223
+ return schedulerStore.updateJob(current.id, current.revision, {
224
+ kind: desired.kind,
225
+ trigger: desired.trigger,
226
+ payload: desired.payload,
227
+ authority: desired.authority,
228
+ enabled: desired.enabled,
229
+ maxAttempts: desired.maxAttempts,
230
+ });
231
+ } catch (error) {
232
+ if (error?.code !== "SCHEDULER_REVISION_CONFLICT") throw error;
233
+ const latest = schedulerStore.getJob(desired.id);
234
+ if (sameJob(latest, desired)) return latest;
235
+ throw error;
236
+ }
237
+ }
238
+
239
+ export function scheduledRoutineFireAt(routine) {
240
+ const snapshot = routineSnapshot(routine);
241
+ if (snapshot.trigger.kind === "once") {
242
+ return normalizeEpochMs(Number(snapshot.trigger.at), "routine.trigger.at");
243
+ }
244
+ if (snapshot.trigger.kind === "cron") {
245
+ const from = snapshot.lastFiredAt ?? snapshot.createdAt;
246
+ const scheduledFor = nextCronTime(snapshot.trigger.cron, from);
247
+ if (scheduledFor === null) {
248
+ throw routineError(
249
+ "SCHEDULER_ROUTINE_NO_NEXT_FIRE",
250
+ `Routine cron has no next occurrence: ${snapshot.id}`,
251
+ );
252
+ }
253
+ return scheduledFor;
254
+ }
255
+ throw routineError(
256
+ "SCHEDULER_ROUTINE_NOT_TIME_DRIVEN",
257
+ `Routine is not driven by cron/once: ${snapshot.id}`,
258
+ );
259
+ }
260
+
261
+ export function enqueueScheduledRoutine(schedulerStore, routine) {
262
+ const job = syncRoutineSchedulerJob(schedulerStore, routine, {
263
+ channel: ROUTINE_SCHEDULER_CHANNELS.SCHEDULED,
264
+ });
265
+ const scheduledFor = scheduledRoutineFireAt(routine);
266
+ return schedulerStore.enqueueOccurrence({
267
+ jobId: job.id,
268
+ scheduledFor,
269
+ triggerKey: `${routine.trigger.kind}:${scheduledFor}`,
270
+ });
271
+ }
272
+
273
+ export function enqueueManualRoutine(
274
+ schedulerStore,
275
+ routine,
276
+ { now = Date.now(), requestId = randomUUID() } = {},
277
+ ) {
278
+ const scheduledFor = normalizeEpochMs(Number(now), "now");
279
+ const request = normalizeIdentifier(requestId, "requestId");
280
+ const job = syncRoutineSchedulerJob(schedulerStore, routine, {
281
+ channel: ROUTINE_SCHEDULER_CHANNELS.MANUAL,
282
+ });
283
+ return schedulerStore.enqueueOccurrence({
284
+ jobId: job.id,
285
+ scheduledFor,
286
+ triggerKey: `manual:${request}`,
287
+ });
288
+ }
289
+
290
+ export function authorizeRoutineOccurrence({ job, occurrence }) {
291
+ try {
292
+ const payload = occurrence?.payload;
293
+ const authority = occurrence?.authority;
294
+ const routineId = payload?.routine?.id;
295
+ const expectedDigest =
296
+ payload?.snapshotType === "definition"
297
+ ? routineDefinitionDigest(payload.routine)
298
+ : payload?.snapshotType === "state"
299
+ ? routineSnapshotDigest(payload.routine)
300
+ : null;
301
+ const allowed =
302
+ job?.kind === ROUTINE_SCHEDULER_KIND &&
303
+ typeof routineId === "string" &&
304
+ authority?.principal?.type === "routine" &&
305
+ authority?.principal?.id === routineId &&
306
+ Array.isArray(authority?.requestedCapabilities) &&
307
+ authority.requestedCapabilities.length === 1 &&
308
+ authority.requestedCapabilities[0] === ROUTINE_SCHEDULER_CAPABILITY &&
309
+ payload?.snapshotDigest === expectedDigest;
310
+ return {
311
+ allowed,
312
+ reason: allowed ? "routine_snapshot_bound" : "routine_authority_mismatch",
313
+ };
314
+ } catch {
315
+ return { allowed: false, reason: "routine_authority_malformed" };
316
+ }
317
+ }
318
+
319
+ export function createRoutineSchedulerAdapter({ routineStore, runAgent } = {}) {
320
+ if (!routineStore || typeof routineStore.get !== "function") {
321
+ throw routineError(
322
+ "SCHEDULER_ROUTINE_STORE_REQUIRED",
323
+ "Routine scheduler adapter requires a RoutineStore",
324
+ );
325
+ }
326
+ if (typeof runAgent !== "function") {
327
+ throw routineError(
328
+ "SCHEDULER_ROUTINE_RUNNER_REQUIRED",
329
+ "Routine scheduler adapter requires a runAgent function",
330
+ );
331
+ }
332
+ return {
333
+ kind: ROUTINE_SCHEDULER_KIND,
334
+ async execute({ occurrence }) {
335
+ const payload = occurrence.payload;
336
+ const expected = payload?.routine;
337
+ if (!expected) {
338
+ throw routineError(
339
+ "SCHEDULER_ROUTINE_SNAPSHOT_INVALID",
340
+ "Routine occurrence snapshot is missing or invalid",
341
+ );
342
+ }
343
+ const expectedDigest =
344
+ payload?.snapshotType === "definition"
345
+ ? routineDefinitionDigest(expected)
346
+ : payload?.snapshotType === "state"
347
+ ? routineSnapshotDigest(expected)
348
+ : null;
349
+ if (payload.snapshotDigest !== expectedDigest) {
350
+ throw routineError(
351
+ "SCHEDULER_ROUTINE_SNAPSHOT_INVALID",
352
+ "Routine occurrence snapshot is missing or invalid",
353
+ );
354
+ }
355
+ const current = routineStore.get(expected.id);
356
+ if (!current) {
357
+ throw routineError(
358
+ "SCHEDULER_ROUTINE_NOT_FOUND",
359
+ `Routine disappeared before execution: ${expected.id}`,
360
+ );
361
+ }
362
+ const schedulerRunId = routineSchedulerRunId(occurrence.id);
363
+ const existingRun = routineStore.getRun?.(schedulerRunId) ?? null;
364
+ if (
365
+ existingRun &&
366
+ (existingRun.routineId !== expected.id ||
367
+ existingRun.schedulerOccurrenceId !== occurrence.id ||
368
+ existingRun.schedulerSnapshotDigest !== payload.snapshotDigest)
369
+ ) {
370
+ throw routineError(
371
+ "SCHEDULER_ROUTINE_RUN_BINDING_MISMATCH",
372
+ `Routine run evidence does not match occurrence: ${occurrence.id}`,
373
+ );
374
+ }
375
+ const currentDigest =
376
+ payload.snapshotType === "definition"
377
+ ? routineDefinitionDigest(current)
378
+ : routineSnapshotDigest(current);
379
+ if (!existingRun && currentDigest !== payload.snapshotDigest) {
380
+ throw routineError(
381
+ "SCHEDULER_ROUTINE_STALE_SNAPSHOT",
382
+ `Routine changed after occurrence enqueue: ${expected.id}`,
383
+ );
384
+ }
385
+ if (
386
+ payload.channel === ROUTINE_SCHEDULER_CHANNELS.SCHEDULED &&
387
+ !existingRun &&
388
+ current.enabled !== true
389
+ ) {
390
+ throw routineError(
391
+ "SCHEDULER_ROUTINE_DISABLED",
392
+ `Routine was disabled before scheduled execution: ${expected.id}`,
393
+ );
394
+ }
395
+ const execution = await executeRoutine(routineStore, current, runAgent, {
396
+ trigger:
397
+ payload.channel === ROUTINE_SCHEDULER_CHANNELS.MANUAL
398
+ ? "manual"
399
+ : current.trigger.kind,
400
+ runId: schedulerRunId,
401
+ schedulerOccurrenceId: occurrence.id,
402
+ schedulerSnapshotDigest: payload.snapshotDigest,
403
+ });
404
+ if (execution.status !== "ok") {
405
+ throw routineError(
406
+ "SCHEDULER_ROUTINE_EXECUTION_FAILED",
407
+ `Routine agent run failed: ${expected.id}`,
408
+ { runId: execution.runId, exitCode: execution.exitCode },
409
+ );
410
+ }
411
+ return execution;
412
+ },
413
+ classifyError(error) {
414
+ return { retryable: error?.retryable !== false };
415
+ },
416
+ };
417
+ }
418
+
419
+ function completedRunId(result) {
420
+ if (
421
+ result.status === "succeeded" &&
422
+ typeof result.result?.runId === "string"
423
+ ) {
424
+ return result.result.runId;
425
+ }
426
+ return null;
427
+ }
428
+
429
+ export class RoutineSchedulerBridge {
430
+ constructor({
431
+ routineStore,
432
+ schedulerStore,
433
+ runAgent,
434
+ now = Date.now,
435
+ ownerId,
436
+ leaseMs,
437
+ renewIntervalMs,
438
+ } = {}) {
439
+ if (typeof now !== "function") {
440
+ throw routineError(
441
+ "SCHEDULER_ROUTINE_CLOCK_REQUIRED",
442
+ "Routine scheduler bridge requires a clock function",
443
+ );
444
+ }
445
+ this.routineStore = routineStore;
446
+ this.schedulerStore = schedulerStore;
447
+ this.now = now;
448
+ this.runtime = new SchedulerRuntime({
449
+ store: schedulerStore,
450
+ adapters: [createRoutineSchedulerAdapter({ routineStore, runAgent })],
451
+ authorize: authorizeRoutineOccurrence,
452
+ ...(ownerId === undefined ? {} : { ownerId }),
453
+ ...(leaseMs === undefined ? {} : { leaseMs }),
454
+ ...(renewIntervalMs === undefined ? {} : { renewIntervalMs }),
455
+ });
456
+ }
457
+
458
+ async trigger(routine, { requestId, signal } = {}) {
459
+ const occurrence = enqueueManualRoutine(this.schedulerStore, routine, {
460
+ now: this.now(),
461
+ ...(requestId === undefined ? {} : { requestId }),
462
+ });
463
+ const result = await this.runtime.runOccurrence(occurrence.id, { signal });
464
+ return { routine: routine.id, occurrence: occurrence.id, result };
465
+ }
466
+
467
+ async runDue({ signal } = {}) {
468
+ const results = [];
469
+ const observedOccurrences = new Set();
470
+ const recovered = await this.runtime.runUntilIdle({
471
+ limit: 10_000,
472
+ signal,
473
+ jobKind: ROUTINE_SCHEDULER_KIND,
474
+ });
475
+ for (const result of recovered.results) {
476
+ const occurrence = result.occurrence;
477
+ const routineId = occurrence?.payload?.routine?.id;
478
+ if (typeof routineId !== "string") continue;
479
+ observedOccurrences.add(occurrence.id);
480
+ results.push({
481
+ routine: routineId,
482
+ occurrence: occurrence.id,
483
+ deduplicated: false,
484
+ recovered: true,
485
+ result,
486
+ });
487
+ }
488
+ if (signal?.aborted) return results;
489
+
490
+ const now = normalizeEpochMs(Number(this.now()), "now");
491
+ const due = this.routineStore.due(now);
492
+ for (const routine of due) {
493
+ const occurrence = enqueueScheduledRoutine(this.schedulerStore, routine);
494
+ if (observedOccurrences.has(occurrence.id)) continue;
495
+ const result = await this.runtime.runOccurrence(occurrence.id, {
496
+ signal,
497
+ });
498
+ results.push({
499
+ routine: routine.id,
500
+ occurrence: occurrence.id,
501
+ deduplicated: occurrence.deduplicated,
502
+ result,
503
+ });
504
+ }
505
+ return results;
506
+ }
507
+ }
508
+
509
+ export function routineBridgeRunId(entry) {
510
+ const result = entry?.result ?? entry;
511
+ return (
512
+ completedRunId(result) ??
513
+ (typeof result?.error?.details?.runId === "string"
514
+ ? result.error.details.runId
515
+ : null)
516
+ );
517
+ }