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
@@ -53,6 +53,33 @@ export const _deps = {
53
53
  runTask: null, // injected at runtime to avoid circular import
54
54
  };
55
55
 
56
+ export const COWORK_SCHEDULER_UNKNOWN_LEASE_EXPIRES_AT =
57
+ "9999-12-31T23:59:59.999Z";
58
+
59
+ function coworkSchedulerError(
60
+ code,
61
+ message,
62
+ { retryable = false, retryAt } = {},
63
+ ) {
64
+ const error = new Error(message);
65
+ error.code = code;
66
+ error.retryable = retryable;
67
+ if (retryAt !== undefined) error.retryAt = retryAt;
68
+ return error;
69
+ }
70
+
71
+ function normalizedDate(value, label) {
72
+ const date =
73
+ value instanceof Date ? new Date(value.getTime()) : new Date(value);
74
+ if (!Number.isFinite(date.getTime())) {
75
+ throw coworkSchedulerError(
76
+ "COWORK_SCHEDULER_TIME_INVALID",
77
+ `${label} must be a valid date`,
78
+ );
79
+ }
80
+ return date;
81
+ }
82
+
56
83
  // ─── Cron parser ─────────────────────────────────────────────────────────────
57
84
 
58
85
  const FIELD_RANGES = [
@@ -293,9 +320,7 @@ function _withScheduleLock(cwd, body) {
293
320
 
294
321
  /** Atomically replace the full schedule list under a fail-closed lock. */
295
322
  export function saveSchedules(cwd, schedules) {
296
- return _withScheduleLock(cwd, () =>
297
- _saveSchedulesUnlocked(cwd, schedules),
298
- );
323
+ return _withScheduleLock(cwd, () => _saveSchedulesUnlocked(cwd, schedules));
299
324
  }
300
325
 
301
326
  // ─── CRUD ────────────────────────────────────────────────────────────────────
@@ -363,6 +388,191 @@ export function updateScheduleRunState(cwd, id, { lastRunAt, lastStatus }) {
363
388
  });
364
389
  }
365
390
 
391
+ /** Return one schedule by id, or null when it does not exist. */
392
+ export function getSchedule(cwd, id) {
393
+ if (typeof id !== "string" || id.length === 0) return null;
394
+ return (
395
+ loadSchedules(cwd, { failOnMalformed: true }).find(
396
+ (schedule) => schedule.id === id,
397
+ ) || null
398
+ );
399
+ }
400
+
401
+ /**
402
+ * Bind a scheduler-kernel occurrence before starting the Cowork task.
403
+ * The same JSONL lock used by the legacy driver closes both old-first and
404
+ * new-first claim races during migration.
405
+ */
406
+ export function bindSchedulerScheduleFire(
407
+ cwd,
408
+ id,
409
+ { deliveryId, occurrenceId, snapshotDigest, attempt, at = _deps.now() } = {},
410
+ ) {
411
+ if (
412
+ typeof deliveryId !== "string" ||
413
+ typeof occurrenceId !== "string" ||
414
+ typeof snapshotDigest !== "string" ||
415
+ deliveryId.length === 0 ||
416
+ occurrenceId.length === 0 ||
417
+ snapshotDigest.length === 0 ||
418
+ !Number.isSafeInteger(attempt) ||
419
+ attempt < 1
420
+ ) {
421
+ throw coworkSchedulerError(
422
+ "COWORK_SCHEDULER_BINDING_INVALID",
423
+ "Cowork scheduler binding requires deliveryId, occurrenceId, snapshotDigest, and a positive attempt",
424
+ );
425
+ }
426
+ const now = normalizedDate(at, "cowork scheduler binding time");
427
+ const nowMs = now.getTime();
428
+ return _withScheduleLock(cwd, () => {
429
+ const schedules = loadSchedules(cwd, { failOnMalformed: true });
430
+ const schedule = schedules.find((entry) => entry.id === id);
431
+ if (!schedule) {
432
+ throw coworkSchedulerError(
433
+ "COWORK_SCHEDULER_SCHEDULE_NOT_FOUND",
434
+ `Cowork schedule does not exist: ${id}`,
435
+ );
436
+ }
437
+ const prior = schedule.schedulerExecution;
438
+ if (prior?.status === "running") {
439
+ throw coworkSchedulerError(
440
+ "COWORK_SCHEDULER_OUTCOME_UNKNOWN",
441
+ `Cowork schedule outcome is unknown: ${id}`,
442
+ );
443
+ }
444
+ if (
445
+ prior?.status === "succeeded" &&
446
+ prior.occurrenceId === occurrenceId &&
447
+ prior.snapshotDigest === snapshotDigest
448
+ ) {
449
+ return schedule;
450
+ }
451
+ // A legacy runner may have completed after the kernel enqueued this fire
452
+ // but before it acquired the JSONL lock. Its durable delivery id is
453
+ // terminal evidence for the same logical fire, so never overwrite it with
454
+ // a new scheduler claim.
455
+ if (schedule.lastDeliveryId === deliveryId) return schedule;
456
+
457
+ const active = schedule.activeDelivery;
458
+ const activeExpiresAt = Date.parse(active?.leaseExpiresAt || "");
459
+ if (active && Number.isFinite(activeExpiresAt) && activeExpiresAt > nowMs) {
460
+ throw coworkSchedulerError(
461
+ "COWORK_SCHEDULER_LEGACY_CLAIM_ACTIVE",
462
+ `Cowork schedule is already claimed: ${id}`,
463
+ { retryable: true, retryAt: activeExpiresAt },
464
+ );
465
+ }
466
+
467
+ const fence =
468
+ Math.max(
469
+ Number(schedule.deliveryFence) || 0,
470
+ Number(active?.fence) || 0,
471
+ ) + 1;
472
+ schedule.deliveryFence = fence;
473
+ schedule.activeDelivery = {
474
+ deliveryId,
475
+ ownerId: `scheduler:${occurrenceId}:${attempt}`,
476
+ fence,
477
+ claimedAt: now.toISOString(),
478
+ leaseExpiresAt: COWORK_SCHEDULER_UNKNOWN_LEASE_EXPIRES_AT,
479
+ };
480
+ schedule.schedulerExecution = {
481
+ deliveryId,
482
+ occurrenceId,
483
+ snapshotDigest,
484
+ attempt,
485
+ status: "running",
486
+ startedAt: now.toISOString(),
487
+ };
488
+ _saveSchedulesUnlocked(cwd, schedules);
489
+ return schedule;
490
+ });
491
+ }
492
+
493
+ /**
494
+ * Atomically settle scheduler evidence and the legacy Cowork delivery state.
495
+ * A known failure may keep a short legacy-visible fence until retryAt; an
496
+ * unknown outcome never calls this function and therefore remains fenced.
497
+ */
498
+ export function completeSchedulerScheduleFire(
499
+ cwd,
500
+ id,
501
+ {
502
+ deliveryId,
503
+ occurrenceId,
504
+ snapshotDigest,
505
+ attempt,
506
+ outcome,
507
+ result = null,
508
+ error = null,
509
+ retryAt,
510
+ at = _deps.now(),
511
+ } = {},
512
+ ) {
513
+ if (!["succeeded", "failed"].includes(outcome)) {
514
+ throw coworkSchedulerError(
515
+ "COWORK_SCHEDULER_OUTCOME_INVALID",
516
+ "Cowork scheduler outcome must be succeeded or failed",
517
+ );
518
+ }
519
+ const now = normalizedDate(at, "cowork scheduler completion time");
520
+ const retryAtMs =
521
+ retryAt === undefined || retryAt === null ? null : Number(retryAt);
522
+ if (retryAtMs !== null && !Number.isSafeInteger(retryAtMs)) {
523
+ throw coworkSchedulerError(
524
+ "COWORK_SCHEDULER_RETRY_TIME_INVALID",
525
+ "Cowork scheduler retryAt must be a safe epoch millisecond",
526
+ );
527
+ }
528
+ return _withScheduleLock(cwd, () => {
529
+ const schedules = loadSchedules(cwd, { failOnMalformed: true });
530
+ const schedule = schedules.find((entry) => entry.id === id);
531
+ if (!schedule) {
532
+ throw coworkSchedulerError(
533
+ "COWORK_SCHEDULER_SCHEDULE_NOT_FOUND",
534
+ `Cowork schedule does not exist: ${id}`,
535
+ );
536
+ }
537
+ const evidence = schedule.schedulerExecution;
538
+ if (
539
+ !evidence ||
540
+ evidence.deliveryId !== deliveryId ||
541
+ evidence.occurrenceId !== occurrenceId ||
542
+ evidence.snapshotDigest !== snapshotDigest ||
543
+ evidence.attempt !== attempt ||
544
+ evidence.status !== "running"
545
+ ) {
546
+ throw coworkSchedulerError(
547
+ "COWORK_SCHEDULER_BINDING_MISMATCH",
548
+ `Cowork scheduler evidence does not match the active claim: ${id}`,
549
+ );
550
+ }
551
+
552
+ schedule.schedulerExecution = {
553
+ ...evidence,
554
+ status: outcome,
555
+ endedAt: now.toISOString(),
556
+ ...(outcome === "succeeded" ? { result } : { error }),
557
+ };
558
+ if (outcome === "succeeded") {
559
+ schedule.lastDeliveryId = deliveryId;
560
+ schedule.lastRunAt = now.toISOString();
561
+ schedule.lastStatus = result?.status || "completed";
562
+ schedule.activeDelivery = null;
563
+ } else if (retryAtMs !== null && retryAtMs > now.getTime()) {
564
+ schedule.activeDelivery = {
565
+ ...schedule.activeDelivery,
566
+ leaseExpiresAt: new Date(retryAtMs).toISOString(),
567
+ };
568
+ } else {
569
+ schedule.activeDelivery = null;
570
+ }
571
+ _saveSchedulesUnlocked(cwd, schedules);
572
+ return schedule;
573
+ });
574
+ }
575
+
366
576
  /**
367
577
  * Claim one concrete cron fire before launching its side effect. The persisted
368
578
  * delivery id prevents two scheduler processes from running the same fire; an
@@ -564,9 +774,7 @@ export class CoworkCronScheduler {
564
774
  this._emit({ type: "invalid-cron", id: s.id, error: err.message });
565
775
  continue;
566
776
  }
567
- const fireKey = `${s.id}:${
568
- matcher.hasSeconds ? _secondKey(now) : _minuteKey(now)
569
- }`;
777
+ const fireKey = coworkCronFireKey(s, now);
570
778
  if (this._firedKeys.has(fireKey)) continue;
571
779
  if (this._running.has(s.id)) continue;
572
780
  const isDue = matcher(now);
@@ -634,27 +842,30 @@ export class CoworkCronScheduler {
634
842
  deliveryId: claim.deliveryId,
635
843
  });
636
844
 
637
- const renewal = setInterval(() => {
638
- try {
639
- const renewed = renewScheduleFire(this.cwd, schedule.id, claim, {
640
- leaseMs: this.leaseMs,
641
- });
642
- if (!renewed) {
845
+ const renewal = setInterval(
846
+ () => {
847
+ try {
848
+ const renewed = renewScheduleFire(this.cwd, schedule.id, claim, {
849
+ leaseMs: this.leaseMs,
850
+ });
851
+ if (!renewed) {
852
+ this._emit({
853
+ type: "schedule-lease-lost",
854
+ id: schedule.id,
855
+ deliveryId: claim.deliveryId,
856
+ });
857
+ }
858
+ } catch (err) {
643
859
  this._emit({
644
- type: "schedule-lease-lost",
860
+ type: "schedule-lease-renewal-failed",
645
861
  id: schedule.id,
646
862
  deliveryId: claim.deliveryId,
863
+ error: err.message,
647
864
  });
648
865
  }
649
- } catch (err) {
650
- this._emit({
651
- type: "schedule-lease-renewal-failed",
652
- id: schedule.id,
653
- deliveryId: claim.deliveryId,
654
- error: err.message,
655
- });
656
- }
657
- }, Math.max(1000, Math.floor(this.leaseMs / 3)));
866
+ },
867
+ Math.max(1000, Math.floor(this.leaseMs / 3)),
868
+ );
658
869
  renewal.unref?.();
659
870
 
660
871
  let result = null;
@@ -718,12 +929,19 @@ export class CoworkCronScheduler {
718
929
  }
719
930
  }
720
931
 
721
- function _minuteKey(date) {
932
+ export function coworkCronMinuteKey(date) {
722
933
  return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}-${date.getHours()}-${date.getMinutes()}`;
723
934
  }
724
935
 
725
- function _secondKey(date) {
726
- return `${_minuteKey(date)}-${date.getSeconds()}`;
936
+ export function coworkCronSecondKey(date) {
937
+ return `${coworkCronMinuteKey(date)}-${date.getSeconds()}`;
938
+ }
939
+
940
+ export function coworkCronFireKey(schedule, date) {
941
+ const matcher = parseCron(schedule.cron);
942
+ return `${schedule.id}:${
943
+ matcher.hasSeconds ? coworkCronSecondKey(date) : coworkCronMinuteKey(date)
944
+ }`;
727
945
  }
728
946
 
729
947
  // =====================================================================
@@ -719,34 +719,37 @@ export function createDeliveryFlow(config = {}, { now } = {}) {
719
719
  }
720
720
 
721
721
  function actionPayload(state, action, payload, now) {
722
+ const callerPayload = jsonClone(payload || {});
722
723
  const common = {
723
724
  flowId: state.flowId,
724
725
  revision: state.revision,
725
726
  commitSha: state.commitSha,
726
727
  diffDigest: state.diff?.digest || null,
728
+ baseCommitSha: state.diff?.baseCommitSha || null,
729
+ changedFiles: jsonClone(state.diff?.changedFiles || []),
727
730
  };
728
731
  if (action === DELIVERY_ACTION.RUN_GATES) {
729
732
  return {
733
+ ...callerPayload,
730
734
  ...common,
731
735
  gateSelection: state.gateSelection,
732
736
  requiredGates: state.requiredGates,
733
- ...jsonClone(payload || {}),
734
737
  };
735
738
  }
736
739
  if (action === DELIVERY_ACTION.RUN_PREVIEW) {
737
740
  return {
741
+ ...callerPayload,
738
742
  ...common,
739
743
  changedFiles: state.diff?.changedFiles || [],
740
- ...jsonClone(payload || {}),
741
744
  };
742
745
  }
743
746
  if (action === DELIVERY_ACTION.APPLY_FIX) {
744
747
  return {
748
+ ...callerPayload,
745
749
  ...common,
746
750
  round: state.round + 1,
747
751
  failures: state.failures,
748
752
  review: state.review?.report || null,
749
- ...jsonClone(payload || {}),
750
753
  };
751
754
  }
752
755
  if (action === DELIVERY_ACTION.PUBLISH_EVIDENCE) {
@@ -754,13 +757,26 @@ function actionPayload(state, action, payload, now) {
754
757
  now: isoNow(now),
755
758
  });
756
759
  return {
760
+ ...callerPayload,
757
761
  ...common,
758
762
  record,
759
763
  readiness: assessDeliveryEvidence(record),
760
- ...jsonClone(payload || {}),
761
764
  };
762
765
  }
763
- return { ...common, ...jsonClone(payload || {}) };
766
+ if (action === DELIVERY_ACTION.MERGE) {
767
+ return {
768
+ ...callerPayload,
769
+ ...common,
770
+ pr: jsonClone(state.pr),
771
+ evidence: state.evidence
772
+ ? {
773
+ recordDigest: state.evidence.record?.recordDigest || null,
774
+ artifact: jsonClone(state.evidence.artifact),
775
+ }
776
+ : null,
777
+ };
778
+ }
779
+ return { ...callerPayload, ...common };
764
780
  }
765
781
 
766
782
  export function requestDeliveryAction(
@@ -941,6 +957,15 @@ function settleFix(state, result) {
941
957
  ? jsonClone(result.changedFiles)
942
958
  : state.diff.changedFiles,
943
959
  };
960
+ // A fixer can touch files outside the original analyzer corpus. Until a new
961
+ // complete impact analysis is supplied, reruns conservatively expand to the
962
+ // authoritative full required-gate matrix instead of reusing stale impact
963
+ // selection evidence.
964
+ state.gateSelection = selectImpactedGates({
965
+ changedFiles: state.diff.changedFiles,
966
+ requiredGates: state.requiredGates,
967
+ analysis: {},
968
+ });
944
969
  state.gateResults = [];
945
970
  state.previewArtifacts = [];
946
971
  state.review = null;