chainlesschain 0.163.6 → 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 (218) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-DDIUofA8.js → AIOps-axqQfwv8.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-Bm-5xYRn.js → ActionButton-DV-Ro0By.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-D5UH4ljI.js → Analytics-Bt72WEVu.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-D_ifjOOP.js → AppLayout-BtepG55E.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-BY1mXdC7.js → Artifacts-B7KaJ7S_.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-Bujr4Ml3.js → Audit-FNFaUg7A.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-sioKSTcC.js → BackgroundAgents-DFb6J2wQ.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DDOAK8RK.js → Backup-CC7YBhyj.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CtCsVVke.js → BaseInput-RkgTNVtj.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-DpNj0vnd.js → Chat-hHEmGZy-.js} +4 -4
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZta3Ftr.js → ChatBubbleRenderer-CAP9YhHv.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-DoHVNSXq.js → Checkbox-z5wXOQP1.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-DlVl7Qmv.js → Codegen-DVaDJnxy.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-GIqoPYty.js → Col-CJmaRDR5.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-CIAPEVji.js → Community-DF29_2bI.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-BN7JiI_h.js → Compact-DtkQkBzn.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-CqUWCM9B.js → Compliance-xoHDxp7I.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-A4iPp7A4.js → Cowork-BUm-R7ht.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-B2zeXXWb.js → Cron-Cgl14ZkB.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BR2xmWr8.js → Crosschain-BNcbmoqh.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-BzFDjrIv.js → DID-Bwja0Zo9.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-DKtDo3yA.js → Dashboard-Bk5XjEdJ.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-RNx43_YG.js → Dropdown-Ci36Oitq.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-SwMt4Rcy.js → EmailListRenderer--U04ZN4q.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CsYebZ4X.js → FamilyGuardDashboard-B2gNPR2s.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-BmRKvBTy.js → Federation-C4KghYn7.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CVxGTA-0.js → FormItemContext-QL7x_Q_0.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-x2iXpyB7.js → GenericCardRenderer-F3Ryltwm.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-DfqbkiOP.js → Git-2HassK5k.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-RuHyyj5O.js → Governance-DoBIp7oe.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-Bn7uZ7rI.js → Inference--W01QhZ-.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DlP7XefZ.js → KnowledgeGraph-DmvwqGpT.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-BYNdOiCd.js → Logs-BBJ4yAel.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-aMtgN-R6.js → MarkdownRenderer-BLCZMzhJ.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-JQYmDqM8.js → Marketplace-D5lNngSI.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-Cyx4yZ-9.js → McpTools-CkEVOMKH.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-VDuGZTN2.js → Memory-B1Ow1xVE.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-_yKo97gi.js → MobileBridge-SgYbUfb6.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-CXRXW3q7.js → MobileProjects-BWdOvQAj.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-acTGtfLH.js → Mtc-DcTXSSma.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-ClpjXfkY.js → MtcAudit-Dt3WG4oj.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-_6Tn3o96.js → Multisig-B9B38UZx.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-CK7pbZzP.js → NLProgramming-B0S4GGvG.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-Czy6V_P8.js → Notes-DZ5U58Ng.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-Cqx-UVv3.js → NotificationSettings-PjL5ZW34.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-C69WDxGy.js → OrderTableRenderer-DrAX2ESt.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-DFnA9vLQ.js → Organization-Cv1GYs-c.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-ReZkk2yT.js → Overflow-Bbkp_PL3.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-DzjSI0aI.js → P2P-BD8QUgoZ.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-DKTf5xIP.js → PdhVaultBrowser-BO-2PeaB.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-DhQ5klhR.js → Permissions-D_OPVa02.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CUL1iHrW.js → PersonalDataHub-mh-pEmaB.js} +4 -4
  54. package/src/assets/web-panel/assets/{Pipeline-DU88iu4N.js → Pipeline-6JC2EDdb.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-Bw-sYfyK.js → Privacy-CUshzUAG.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-Bq3Q5y0z.js → ProjectInit-Cs2Aalri.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-C8spzpho.js → ProjectSettings-1ak49tcj.js} +2 -2
  58. package/src/assets/web-panel/assets/Projects-BV4oApsm.js +1 -0
  59. package/src/assets/web-panel/assets/{Providers-Bf4eTP9W.js → Providers-CXXxvafH.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-Dme9BDU1.js → QrScannerModal-PTcDsF58.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-CIXfv1rE.js → QuickAsk-CDwucrJw.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-CIxvdeZ-.js → Recommend-CJlLVRXR.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C6k7MExI.js → RemoteSession-DlN-ETsO.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-CISDz2bl.js → Reputation-DI23LR6m.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-CdnDxXyf.js → Row-Cl7UQMrM.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-C-QpRHsl.js → RssFeed-CexHNfh8.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DBjaGzSn.js → Search-BneBWvRN.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-CQKukOeE.js → Security-DX7Phgrp.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-DZz86jWb.js → Services-BWXO8Mte.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-jb8RMK0d.js → Skeleton-DCyOjKPJ.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-CdY76fZG.js → Skills-CXqERsTB.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-C_CSiZX9.js → Sla-bhbrbz8E.js} +1 -1
  73. package/src/assets/web-panel/assets/SpeechSettings-3IPU0HBZ.js +1 -0
  74. package/src/assets/web-panel/assets/{SyncSettings-qvimGO0O.js → SyncSettings-DBNTQLbM.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-Dng5LPJC.js → Tasks-quP0bkN-.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-Bwqq5Wll.js → Templates-BouWmgho.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-DNWuwP7Z.js → Tenant-qv0D9s7z.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-B-6Othpp.js → Terminal-BxvbE8BB.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-DKpKZfzx.js → TimelineRenderer-D-IeLnJ2.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-DzfGMd2J.js → Tokens-CFMKKyVG.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-BXwUi74J.js → Trigger-L8as3UuJ.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-BNzUq4ui.js → Trust-MxmA4VZG.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-BYugxww4.js → UkeySign-C0VvJYRi.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-DdauhtSJ.js → VideoEditing-Bf5QZj8N.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-CSC9bCe_.js → Wallet-BIJ9riRz.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-Q8AN3bTO.js → WebAuthn-B8p9Mhkw.js} +5 -5
  87. package/src/assets/web-panel/assets/{WorkflowEditor-d-LBGCuA.js → WorkflowEditor-BVsuaPen.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-BLVDCgsZ.js → chat-BfkjoKpV.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-BZlPSEHl.js → colors-DeAlsWK8.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-IWseP6R6.js → compact-item-Cs97bz5j.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-DnVRV3Ao.js → createContext-BqbG60LH.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-DLQZA_Wn.js → hasIn-i_RY0b1X.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-B_N4-Gq9.js → index-0-agYlWL.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-DB0MJgF_.js → index-79V_zv1s.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BOZJBTWZ.js → index-B-3tEpTc.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DUq0c7gq.js → index-B-JVTrpr.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-Dy0R5ZED.js → index-B1CbOH1i.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-Bxp7uDD8.js → index-B5UkyA3c.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DpVrK6fr.js → index-BESLFt4q.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CT9vVN-X.js → index-BOVkf1K3.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-DOoQpuQY.js → index-BYUVuwKt.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CINJQEj6.js → index-BcUXAB2s.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CarMTIyQ.js → index-BkBi5TmC.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-C5dgnilC.js → index-Bm7lLR4c.js} +1 -1
  106. package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +1 -0
  107. package/src/assets/web-panel/assets/{index-CbQNL0ue.js → index-BuLQobzW.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CpBaJ3TD.js → index-CE2VtTlp.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-jWb70ZgZ.js → index-CED2PL_y.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BEu2lMBy.js → index-CG3PRyAL.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DocEhinm.js → index-CIG8fQ2_.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-D_LQodeJ.js → index-COdGA-8n.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DZpYeqrh.js → index-CeWoNHau.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-gt8bNefW.js → index-Cf3WCLmy.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-N_GoWZX4.js → index-CgsqdnRV.js} +1 -1
  116. package/src/assets/web-panel/assets/index-ChVT0p9u.js +1 -0
  117. package/src/assets/web-panel/assets/{index-CZDekj7T.js → index-D2B4VPyP.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-YSw_gxlZ.js → index-D9evtvg2.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DTbxp4UH.js → index-DUUrv141.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-Bbj2NS_I.js → index-DiSkx4UB.js} +3 -3
  121. package/src/assets/web-panel/assets/{index-BZs5bBnk.js → index-Dk2qouAz.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DalA0TKC.js → index-Dk7-v4hP.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-1jeAudHd.js → index-DmbfhJUP.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-C1ifZtXo.js → index-DqBgBpgp.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BhA3QEni.js → index-PT_5sBMA.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BSjilZ9L.js → index-U4f5izHz.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-C2FqfMvU.js → index-YXgLng0K.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-COev0W2g.js → index-ZxO_-E8a.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-M7wxfAbm.js → index-dIHr4B_u.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DjWnONdy.js → index-gyFpvL7l.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Dkwsi1Kn.js → index-s1opAL-M.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-hwVDeoC0.js → index-yObj1O4n.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-Co67Kqmb.js → initDefaultProps-C9h9yKL3.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BMOxQSF_.js → motion-BvmLsPdu.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-C5fWDw-N.js → move-CoL4ekU1.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-BJevpL0e.js → mtc-parser-C4pMy6xV.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-BCzNU8s6.js → omit-DPuJfNxx.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-CybWvDPk.js → pickAttrs-D0KEeaK2.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-BMWS9HnW.js → placementArrow-BpkyINxt.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-BoL2UnGY.js → responsiveObserve-DQI_wOq8.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-DWNfXraU.js → slide-DYfdDiRg.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-BquTM3tX.js → statusUtils-B5dtvb0D.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-BEkCleim.js → styleChecker-CF310mSj.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-Oecnq7EA.js → useFlexGapSupport-D1Qp4BLp.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-CkDffJ4F.js → useFs-C7_iyvJK.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-qbvKXesB.js → usePersonalDataHub-DZUt_fIm.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-C6v8n6mA.js → vnode-D3dsi0lZ.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-4CTeFILV.js → zoom-WdbOlvdQ.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +2 -2
  151. package/src/commands/agent.js +90 -1
  152. package/src/commands/chat.js +11 -2
  153. package/src/commands/compact.js +106 -23
  154. package/src/commands/loop.js +28 -10
  155. package/src/commands/routine.js +1 -1
  156. package/src/commands/scheduler-daemon.js +359 -2
  157. package/src/commands/session-observability.js +305 -0
  158. package/src/commands/session.js +38 -0
  159. package/src/data/changelog.json +14 -1
  160. package/src/gateways/ws/ws-agent-handler.js +439 -5
  161. package/src/harness/jsonl-session-store.js +463 -125
  162. package/src/harness/prompt-compressor.js +86 -13
  163. package/src/harness/provider-backed-compaction.js +100 -27
  164. package/src/lib/advisor-runtime.js +3 -1
  165. package/src/lib/agent-schedule-store.js +414 -4
  166. package/src/lib/agent-team/team-adjudication.js +40 -1
  167. package/src/lib/automation-engine.js +494 -0
  168. package/src/lib/background-agent-supervisor.js +793 -215
  169. package/src/lib/background-command-argv.js +24 -0
  170. package/src/lib/background-interaction-journal.js +361 -52
  171. package/src/lib/background-interaction-resolver.js +32 -0
  172. package/src/lib/background-launch-profile.js +2 -0
  173. package/src/lib/causal-observability.js +2661 -0
  174. package/src/lib/chat-session-admission.js +76 -0
  175. package/src/lib/cost-budget.js +5 -7
  176. package/src/lib/cowork/ab-comparator-cli.js +11 -0
  177. package/src/lib/cowork/debate-review-cli.js +12 -0
  178. package/src/lib/cowork-adapter.js +159 -38
  179. package/src/lib/cowork-cron.js +357 -1
  180. package/src/lib/cowork-task-runner.js +112 -17
  181. package/src/lib/delivery-coordinator.js +142 -0
  182. package/src/lib/direct-model-usage.js +121 -0
  183. package/src/lib/file-lines.js +183 -47
  184. package/src/lib/llm-pricing.js +12 -17
  185. package/src/lib/loop.js +26 -2
  186. package/src/lib/routine-store.js +380 -21
  187. package/src/lib/runtime-usage-ledger.js +182 -0
  188. package/src/lib/scheduler-kernel/agenda-adapter.js +308 -3
  189. package/src/lib/scheduler-kernel/automation-adapter.js +410 -8
  190. package/src/lib/scheduler-kernel/automation-event-adapter.js +36 -0
  191. package/src/lib/scheduler-kernel/cowork-cron-adapter.js +285 -3
  192. package/src/lib/scheduler-kernel/loop-adapter.js +541 -6
  193. package/src/lib/scheduler-kernel/migration-admin.js +346 -0
  194. package/src/lib/scheduler-kernel/migration-rollback-admin.js +932 -0
  195. package/src/lib/scheduler-kernel/routine-adapter.js +394 -20
  196. package/src/lib/scheduler-kernel/runtime.js +63 -1
  197. package/src/lib/scheduler-kernel/source-locator-path.js +142 -0
  198. package/src/lib/scheduler-kernel/store.js +2586 -85
  199. package/src/lib/session-host-lease.js +171 -2
  200. package/src/lib/session-host-snapshot.js +14 -3
  201. package/src/lib/session-persistence-failure.js +1 -0
  202. package/src/lib/session-tail.js +179 -34
  203. package/src/lib/session-transcript-structure.js +96 -0
  204. package/src/lib/sub-agent-context.js +328 -22
  205. package/src/lib/ws-agent-handler.js +4 -1
  206. package/src/repl/agent-repl.js +732 -91
  207. package/src/repl/chat-repl.js +5 -1
  208. package/src/runtime/agent-core.js +1272 -207
  209. package/src/runtime/fallback-model.js +5 -0
  210. package/src/runtime/headless-runner.js +324 -82
  211. package/src/runtime/headless-stream.js +232 -26
  212. package/src/runtime/policies/agent-policy.js +4 -0
  213. package/src/workers/background-agent-worker.js +403 -96
  214. package/src/assets/web-panel/assets/Projects-Dd-xuPIc.js +0 -1
  215. package/src/assets/web-panel/assets/SpeechSettings-C7tT9iad.js +0 -1
  216. package/src/assets/web-panel/assets/devWarning-Jzu62CLC.js +0 -1
  217. package/src/assets/web-panel/assets/index-Zb2MeDSy.js +0 -1
  218. package/src/assets/web-panel/assets/index-fikqml4k.js +0 -1
@@ -22,7 +22,7 @@
22
22
  import fs from "fs";
23
23
  import os from "os";
24
24
  import path from "path";
25
- import { randomUUID } from "crypto";
25
+ import { createHash, randomUUID } from "crypto";
26
26
  import { isEntryExpired, effectiveFireAt } from "./schedule-planner.js";
27
27
  import { SUBAGENT_PERMISSION_MODES } from "./subagent-contract.js";
28
28
  import { parseGoalCondition } from "./goal-condition-engine.js";
@@ -30,6 +30,7 @@ import { normalizeActionClass } from "./unattended-action-policy.js";
30
30
  import { withFileLock } from "./with-file-lock.js";
31
31
 
32
32
  export const SCHEDULE_KINDS = Object.freeze(["wakeup", "cron", "monitor"]);
33
+ export const AGENDA_SCHEDULER_MIGRATION_SCHEMA_VERSION = 1;
33
34
 
34
35
  /** A valid absolute-epoch-ms expiry, or null (never expires). */
35
36
  function normalizeExpiresAt(v) {
@@ -168,6 +169,87 @@ function hasLiveExecutionLease(entry, now) {
168
169
  return Number(entry.executionLease?.expiresAt) > Number(now);
169
170
  }
170
171
 
172
+ function stableJsonValue(value) {
173
+ if (Array.isArray(value)) return value.map(stableJsonValue);
174
+ if (value && typeof value === "object") {
175
+ return Object.fromEntries(
176
+ Object.keys(value)
177
+ .sort()
178
+ .map((key) => [key, stableJsonValue(value[key])]),
179
+ );
180
+ }
181
+ return value;
182
+ }
183
+
184
+ function agendaMigrationSource(entry) {
185
+ const source = { ...entry };
186
+ delete source.executionLease;
187
+ delete source.schedulerExecution;
188
+ delete source.schedulerMigration;
189
+ delete source.firedAt;
190
+ delete source.lastRunAt;
191
+ delete source.runs;
192
+ delete source.nextAt;
193
+ delete source.lastCheckAt;
194
+ delete source.checks;
195
+ delete source.lastMtimeMs;
196
+ delete source.lastEventId;
197
+ delete source.lastAuthority;
198
+ delete source.status;
199
+ return source;
200
+ }
201
+
202
+ export function agendaMigrationSourceDigest(entry) {
203
+ return createHash("sha256")
204
+ .update("chainlesschain.agenda.scheduler-migration-source.v1\0", "utf8")
205
+ .update(
206
+ JSON.stringify(stableJsonValue(agendaMigrationSource(entry))),
207
+ "utf8",
208
+ )
209
+ .digest("hex");
210
+ }
211
+
212
+ export function agendaMigrationSourceSnapshot(entry) {
213
+ return stableJsonValue(agendaMigrationSource(entry));
214
+ }
215
+
216
+ function schedulerMigrationFence(entry, now) {
217
+ const migration = entry.schedulerMigration;
218
+ if (
219
+ migration?.schemaVersion !== AGENDA_SCHEDULER_MIGRATION_SCHEMA_VERSION ||
220
+ typeof migration.retirementToken !== "string" ||
221
+ migration.retirementToken.length === 0
222
+ ) {
223
+ return false;
224
+ }
225
+ return (
226
+ hasLiveExecutionLease(entry, now) &&
227
+ entry.executionLease?.owner ===
228
+ `scheduler-migration:${migration.retirementToken}`
229
+ );
230
+ }
231
+
232
+ function applySchedulerMigrationFence(entry, now) {
233
+ const token = entry.schedulerMigration?.retirementToken;
234
+ if (typeof token !== "string" || token.length === 0) return false;
235
+ entry.executionLease = {
236
+ owner: `scheduler-migration:${token}`,
237
+ claimedAt: now,
238
+ expiresAt: Number.MAX_SAFE_INTEGER,
239
+ };
240
+ return true;
241
+ }
242
+
243
+ function normalizeMigrationField(value, field) {
244
+ if (typeof value !== "string" || value.trim().length === 0) {
245
+ throw agendaStoreError(
246
+ "AGENDA_SCHEDULER_MIGRATION_INVALID",
247
+ `Agenda scheduler migration ${field} is required`,
248
+ );
249
+ }
250
+ return value.trim();
251
+ }
252
+
171
253
  function agendaStoreError(code, message, { retryable = false, retryAt } = {}) {
172
254
  const error = new Error(message);
173
255
  error.code = code;
@@ -820,15 +902,246 @@ export class AgentScheduleStore {
820
902
  return this.list().find((entry) => entry.id === id) || null;
821
903
  }
822
904
 
905
+ prepareSchedulerMigration(
906
+ id,
907
+ { migrationId, sourceDigest, targetJobId } = {},
908
+ ) {
909
+ const migration = normalizeMigrationField(migrationId, "migrationId");
910
+ const expectedDigest = normalizeMigrationField(
911
+ sourceDigest,
912
+ "sourceDigest",
913
+ );
914
+ const target = normalizeMigrationField(targetJobId, "targetJobId");
915
+ this._ensureDir();
916
+ return withFileLock(
917
+ path.join(this.dir, ".agenda-claims"),
918
+ () => {
919
+ for (const kind of SCHEDULE_KINDS) {
920
+ const entries = this._readAll(kind);
921
+ const entry = entries.find((candidate) => candidate.id === id);
922
+ if (!entry) continue;
923
+ if (!isSchedulableStatus(entry)) {
924
+ throw agendaStoreError(
925
+ "AGENDA_SCHEDULER_ENTRY_TERMINAL",
926
+ `Agenda entry is not schedulable: ${id}`,
927
+ );
928
+ }
929
+ const actualDigest = agendaMigrationSourceDigest(entry);
930
+ if (actualDigest !== expectedDigest) {
931
+ throw agendaStoreError(
932
+ "AGENDA_SCHEDULER_MIGRATION_SOURCE_CHANGED",
933
+ `Agenda entry changed before migration: ${id}`,
934
+ );
935
+ }
936
+ const prior = entry.schedulerMigration;
937
+ if (prior) {
938
+ if (
939
+ prior.schemaVersion !==
940
+ AGENDA_SCHEDULER_MIGRATION_SCHEMA_VERSION ||
941
+ prior.sourceDigest !== expectedDigest ||
942
+ prior.targetJobId !== target ||
943
+ prior.migrationId !== migration ||
944
+ prior.state !== "prepared"
945
+ ) {
946
+ throw agendaStoreError(
947
+ "AGENDA_SCHEDULER_MIGRATION_CONFLICT",
948
+ `Agenda entry already belongs to another scheduler migration: ${id}`,
949
+ );
950
+ }
951
+ return entry;
952
+ }
953
+ entry.schedulerMigration = {
954
+ schemaVersion: AGENDA_SCHEDULER_MIGRATION_SCHEMA_VERSION,
955
+ state: "prepared",
956
+ migrationId: migration,
957
+ sourceDigest: expectedDigest,
958
+ targetJobId: target,
959
+ preparedAt: this._now(),
960
+ };
961
+ this._writeAll(kind, entries);
962
+ return entry;
963
+ }
964
+ throw agendaStoreError(
965
+ "AGENDA_SCHEDULER_ENTRY_NOT_FOUND",
966
+ `Agenda entry does not exist: ${id}`,
967
+ );
968
+ },
969
+ { failIfUnavailable: true },
970
+ );
971
+ }
972
+
973
+ retireForSchedulerMigration(
974
+ id,
975
+ {
976
+ migrationId,
977
+ sourceDigest,
978
+ targetJobId,
979
+ retirementToken,
980
+ atMs = null,
981
+ } = {},
982
+ ) {
983
+ const migration = normalizeMigrationField(migrationId, "migrationId");
984
+ const expectedDigest = normalizeMigrationField(
985
+ sourceDigest,
986
+ "sourceDigest",
987
+ );
988
+ const target = normalizeMigrationField(targetJobId, "targetJobId");
989
+ const token = normalizeMigrationField(retirementToken, "retirementToken");
990
+ const now = atMs != null ? Number(atMs) : this._now();
991
+ this._ensureDir();
992
+ return withFileLock(
993
+ path.join(this.dir, ".agenda-claims"),
994
+ () => {
995
+ for (const kind of SCHEDULE_KINDS) {
996
+ const entries = this._readAll(kind);
997
+ const entry = entries.find((candidate) => candidate.id === id);
998
+ if (!entry) continue;
999
+ const prior = entry.schedulerMigration;
1000
+ if (
1001
+ prior?.schemaVersion !==
1002
+ AGENDA_SCHEDULER_MIGRATION_SCHEMA_VERSION ||
1003
+ prior.sourceDigest !== expectedDigest ||
1004
+ prior.targetJobId !== target ||
1005
+ prior.migrationId !== migration ||
1006
+ !["prepared", "retired"].includes(prior.state)
1007
+ ) {
1008
+ throw agendaStoreError(
1009
+ "AGENDA_SCHEDULER_MIGRATION_CONFLICT",
1010
+ `Agenda migration preparation changed before retirement: ${id}`,
1011
+ );
1012
+ }
1013
+ if (prior.state === "retired") {
1014
+ if (
1015
+ prior.retirementToken !== token ||
1016
+ !schedulerMigrationFence(entry, now)
1017
+ ) {
1018
+ throw agendaStoreError(
1019
+ "AGENDA_SCHEDULER_MIGRATION_CONFLICT",
1020
+ `Agenda migration retirement fence changed: ${id}`,
1021
+ );
1022
+ }
1023
+ return entry;
1024
+ }
1025
+ if (agendaMigrationSourceDigest(entry) !== expectedDigest) {
1026
+ throw agendaStoreError(
1027
+ "AGENDA_SCHEDULER_MIGRATION_SOURCE_CHANGED",
1028
+ `Agenda entry changed before retirement: ${id}`,
1029
+ );
1030
+ }
1031
+ if (hasLiveExecutionLease(entry, now)) {
1032
+ throw agendaStoreError(
1033
+ "AGENDA_SCHEDULER_LEGACY_CLAIM_ACTIVE",
1034
+ `Agenda entry is already claimed by a legacy runner: ${id}`,
1035
+ {
1036
+ retryable: true,
1037
+ retryAt: Number(entry.executionLease.expiresAt),
1038
+ },
1039
+ );
1040
+ }
1041
+ entry.schedulerMigration = {
1042
+ ...prior,
1043
+ state: "retired",
1044
+ retirementToken: token,
1045
+ retiredAt: now,
1046
+ };
1047
+ applySchedulerMigrationFence(entry, now);
1048
+ this._writeAll(kind, entries);
1049
+ return entry;
1050
+ }
1051
+ throw agendaStoreError(
1052
+ "AGENDA_SCHEDULER_ENTRY_NOT_FOUND",
1053
+ `Agenda entry does not exist: ${id}`,
1054
+ );
1055
+ },
1056
+ { failIfUnavailable: true },
1057
+ );
1058
+ }
1059
+
1060
+ restoreFromSchedulerMigration(
1061
+ id,
1062
+ { migrationId, sourceDigest, targetJobId, retirementToken } = {},
1063
+ ) {
1064
+ const migrationIdValue = normalizeMigrationField(
1065
+ migrationId,
1066
+ "migrationId",
1067
+ );
1068
+ const expectedDigest = normalizeMigrationField(
1069
+ sourceDigest,
1070
+ "sourceDigest",
1071
+ );
1072
+ const target = normalizeMigrationField(targetJobId, "targetJobId");
1073
+ const token =
1074
+ retirementToken === null || retirementToken === undefined
1075
+ ? null
1076
+ : normalizeMigrationField(retirementToken, "retirementToken");
1077
+ this._ensureDir();
1078
+ return withFileLock(
1079
+ path.join(this.dir, ".agenda-claims"),
1080
+ () => {
1081
+ for (const kind of SCHEDULE_KINDS) {
1082
+ const entries = this._readAll(kind);
1083
+ const entry = entries.find((candidate) => candidate.id === id);
1084
+ if (!entry) continue;
1085
+ const migration = entry.schedulerMigration;
1086
+ if (!migration) {
1087
+ if (
1088
+ agendaMigrationSourceDigest(entry) !== expectedDigest ||
1089
+ String(entry.executionLease?.owner || "").startsWith(
1090
+ "scheduler-migration:",
1091
+ )
1092
+ ) {
1093
+ throw agendaStoreError(
1094
+ "AGENDA_SCHEDULER_MIGRATION_CONFLICT",
1095
+ `Agenda source changed after rollback restoration: ${id}`,
1096
+ );
1097
+ }
1098
+ return entry;
1099
+ }
1100
+ if (
1101
+ migration?.schemaVersion !==
1102
+ AGENDA_SCHEDULER_MIGRATION_SCHEMA_VERSION ||
1103
+ migration.sourceDigest !== expectedDigest ||
1104
+ agendaMigrationSourceDigest(entry) !== expectedDigest ||
1105
+ migration.targetJobId !== target ||
1106
+ migration.migrationId !== migrationIdValue ||
1107
+ !["prepared", "retired"].includes(migration.state) ||
1108
+ (migration.state === "retired" &&
1109
+ (migration.retirementToken !== token ||
1110
+ entry.executionLease?.owner !== `scheduler-migration:${token}`))
1111
+ ) {
1112
+ throw agendaStoreError(
1113
+ "AGENDA_SCHEDULER_MIGRATION_CONFLICT",
1114
+ `Agenda migration fence changed before rollback: ${id}`,
1115
+ );
1116
+ }
1117
+ delete entry.schedulerMigration;
1118
+ if (migration.state === "retired") delete entry.executionLease;
1119
+ this._writeAll(kind, entries);
1120
+ return entry;
1121
+ }
1122
+ throw agendaStoreError(
1123
+ "AGENDA_SCHEDULER_ENTRY_NOT_FOUND",
1124
+ `Agenda entry does not exist: ${id}`,
1125
+ );
1126
+ },
1127
+ { failIfUnavailable: true },
1128
+ );
1129
+ }
1130
+
823
1131
  /** Entries whose time has come (pending wakeup / active cron|monitor). */
824
- due(kind = null, atMs = null) {
1132
+ due(kind = null, atMs = null, { schedulerMigration = false } = {}) {
825
1133
  const now = atMs != null ? atMs : this._now();
826
1134
  return this.list(kind).filter((entry) => {
827
1135
  // An entry past its expiry never fires — even if it is not yet retired
828
1136
  // (defense-in-depth: retireExpired need not have run first).
829
1137
  if (isEntryExpired(entry, now)) return false;
830
1138
  if (!isSchedulableStatus(entry)) return false;
831
- if (hasLiveExecutionLease(entry, now)) return false;
1139
+ if (
1140
+ hasLiveExecutionLease(entry, now) &&
1141
+ !(schedulerMigration && schedulerMigrationFence(entry, now))
1142
+ ) {
1143
+ return false;
1144
+ }
832
1145
  // The effective fire time applies the entry's OWN deterministic jitter
833
1146
  // (`entry.jitterMs`, default 0 → base fire time, byte-identical to the
834
1147
  // prior `dueAt`/`nextAt` comparison). A jittered entry fires slightly
@@ -946,7 +1259,8 @@ export class AgentScheduleStore {
946
1259
  ) {
947
1260
  return entry;
948
1261
  }
949
- if (hasLiveExecutionLease(entry, now)) {
1262
+ const migrationFence = schedulerMigrationFence(entry, now);
1263
+ if (hasLiveExecutionLease(entry, now) && !migrationFence) {
950
1264
  throw agendaStoreError(
951
1265
  "AGENDA_SCHEDULER_LEGACY_CLAIM_ACTIVE",
952
1266
  `Agenda entry is already claimed by a legacy runner: ${id}`,
@@ -1051,6 +1365,102 @@ export class AgentScheduleStore {
1051
1365
  ...(outcome === "succeeded" ? { result: storedResult } : { error }),
1052
1366
  };
1053
1367
  delete entry.executionLease;
1368
+ if (isSchedulableStatus(entry))
1369
+ applySchedulerMigrationFence(entry, now);
1370
+ this._writeAll(kind, entries);
1371
+ return entry;
1372
+ }
1373
+ throw agendaStoreError(
1374
+ "AGENDA_SCHEDULER_ENTRY_NOT_FOUND",
1375
+ `Agenda entry does not exist: ${id}`,
1376
+ );
1377
+ },
1378
+ { failIfUnavailable: true },
1379
+ );
1380
+ }
1381
+
1382
+ /**
1383
+ * Resolve start-only scheduler evidence after an operator has verified the
1384
+ * external outcome. This is intentionally separate from normal completion:
1385
+ * it preserves the adjudication identity and can release the non-expiring
1386
+ * legacy fence without pretending that a machine observed a terminal result.
1387
+ */
1388
+ adjudicateSchedulerExecution(
1389
+ id,
1390
+ {
1391
+ occurrenceId,
1392
+ snapshotDigest,
1393
+ attempt,
1394
+ decision,
1395
+ requestId,
1396
+ atMs = null,
1397
+ } = {},
1398
+ ) {
1399
+ if (!["confirmed_applied", "confirmed_not_applied"].includes(decision)) {
1400
+ throw agendaStoreError(
1401
+ "AGENDA_SCHEDULER_ADJUDICATION_INVALID",
1402
+ "Agenda scheduler adjudication decision is invalid",
1403
+ );
1404
+ }
1405
+ const now = atMs != null ? Number(atMs) : this._now();
1406
+ this._ensureDir();
1407
+ return withFileLock(
1408
+ path.join(this.dir, ".agenda-claims"),
1409
+ () => {
1410
+ for (const kind of SCHEDULE_KINDS) {
1411
+ const entries = this._readAll(kind);
1412
+ const entry = entries.find((candidate) => candidate.id === id);
1413
+ if (!entry) continue;
1414
+ const evidence = entry.schedulerExecution;
1415
+ if (
1416
+ evidence?.occurrenceId === occurrenceId &&
1417
+ evidence.snapshotDigest === snapshotDigest &&
1418
+ evidence.adjudication?.requestId === requestId &&
1419
+ evidence.adjudication.decision === decision &&
1420
+ evidence.status ===
1421
+ (decision === "confirmed_applied"
1422
+ ? "adjudicated_applied"
1423
+ : "adjudicated_not_applied")
1424
+ ) {
1425
+ return entry;
1426
+ }
1427
+ if (
1428
+ !evidence ||
1429
+ evidence.occurrenceId !== occurrenceId ||
1430
+ evidence.snapshotDigest !== snapshotDigest ||
1431
+ !Number.isSafeInteger(evidence.attempt) ||
1432
+ evidence.attempt < 1 ||
1433
+ evidence.attempt > attempt ||
1434
+ evidence.status !== "running"
1435
+ ) {
1436
+ throw agendaStoreError(
1437
+ "AGENDA_SCHEDULER_ADJUDICATION_EVIDENCE_MISMATCH",
1438
+ `Agenda scheduler adjudication evidence does not match: ${id}`,
1439
+ );
1440
+ }
1441
+ if (decision === "confirmed_applied") {
1442
+ if (entry.kind === "monitor") {
1443
+ // A generic operator decision proves the prior check ran, but
1444
+ // not whether its observation matched. Pause the monitor rather
1445
+ // than inventing a domain result or rearming a duplicate check.
1446
+ entry.status = "adjudicated";
1447
+ entry.lastCheckAt = now;
1448
+ } else {
1449
+ applyScheduledAgentSuccess(entry, now);
1450
+ }
1451
+ }
1452
+ entry.schedulerExecution = {
1453
+ ...evidence,
1454
+ status:
1455
+ decision === "confirmed_applied"
1456
+ ? "adjudicated_applied"
1457
+ : "adjudicated_not_applied",
1458
+ endedAt: now,
1459
+ adjudication: { requestId, decision },
1460
+ };
1461
+ delete entry.executionLease;
1462
+ if (isSchedulableStatus(entry))
1463
+ applySchedulerMigrationFence(entry, now);
1054
1464
  this._writeAll(kind, entries);
1055
1465
  return entry;
1056
1466
  }
@@ -70,6 +70,10 @@ const EVENT_DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/;
70
70
  const CASE_ID_PATTERN = /^tadj_[a-f0-9]{64}$/;
71
71
  const CLAIM_ID_PATTERN =
72
72
  /^tadj_claim_[a-zA-Z0-9](?:[a-zA-Z0-9._-]{0,126}[a-zA-Z0-9])?$/;
73
+ const WINDOWS_RENAME_TRANSIENT_CODES = new Set(["EACCES", "EBUSY", "EPERM"]);
74
+ const WINDOWS_RENAME_RETRY_DELAYS_MS = Object.freeze([
75
+ 5, 10, 20, 40, 80, 100, 100, 100,
76
+ ]);
73
77
  const DECISIONS = new Set(Object.values(TEAM_ADJUDICATION_DECISIONS));
74
78
  const HEADER_KEYS = new Set([
75
79
  "schema",
@@ -130,6 +134,19 @@ function adjudicationError(code, message, details = {}, cause = null) {
130
134
  return new TeamAdjudicationError(code, message, details, cause);
131
135
  }
132
136
 
137
+ function sleepSync(milliseconds) {
138
+ const duration = Math.max(0, Number(milliseconds) || 0);
139
+ if (duration === 0) return;
140
+ try {
141
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, duration);
142
+ } catch {
143
+ const deadline = Date.now() + duration;
144
+ while (Date.now() < deadline) {
145
+ // SharedArrayBuffer is unavailable; retain a bounded synchronous wait.
146
+ }
147
+ }
148
+ }
149
+
133
150
  function isAdjudicationError(error) {
134
151
  return Object.values(TEAM_ADJUDICATION_ERROR_CODES).includes(error?.code);
135
152
  }
@@ -892,11 +909,13 @@ export class TeamAdjudicationStore {
892
909
  _lock = withFileLock,
893
910
  _randomUUID = randomUUID,
894
911
  _platform = process.platform,
912
+ _sleep = sleepSync,
895
913
  } = {}) {
896
914
  this._fs = _fs;
897
915
  this._lock = _lock;
898
916
  this._randomUUID = _randomUUID;
899
917
  this._platform = _platform;
918
+ this._sleep = typeof _sleep === "function" ? _sleep : sleepSync;
900
919
  this._now = typeof now === "function" ? now : () => Number(now);
901
920
  this.lockTimeoutMs = Math.max(0, Number(lockTimeoutMs) || 0);
902
921
  this.lockStaleMs = Math.max(1, Number(lockStaleMs) || 30_000);
@@ -1161,7 +1180,27 @@ export class TeamAdjudicationStore {
1161
1180
  descriptor = null;
1162
1181
 
1163
1182
  this._assertAuthorityPaths();
1164
- this._fs.renameSync(temporaryPath, canonicalPath);
1183
+ let renameAttempt = 0;
1184
+ for (;;) {
1185
+ try {
1186
+ this._fs.renameSync(temporaryPath, canonicalPath);
1187
+ break;
1188
+ } catch (cause) {
1189
+ const delay = WINDOWS_RENAME_RETRY_DELAYS_MS[renameAttempt];
1190
+ if (
1191
+ this._platform !== "win32" ||
1192
+ !WINDOWS_RENAME_TRANSIENT_CODES.has(cause?.code) ||
1193
+ delay === undefined
1194
+ ) {
1195
+ throw cause;
1196
+ }
1197
+ renameAttempt += 1;
1198
+ this._sleep(delay);
1199
+ // Keep each retry bound to the same canonical authority after
1200
+ // yielding to a transient Windows file-sharing holder.
1201
+ this._assertAuthorityPaths();
1202
+ }
1203
+ }
1165
1204
  renamed = true;
1166
1205
  this._fs.chmodSync(canonicalPath, 0o600);
1167
1206
  const persisted = this._secureRead();