chainlesschain 0.165.1 → 0.165.3

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 (206) hide show
  1. package/README.md +248 -2
  2. package/package.json +4 -1
  3. package/src/assets/web-panel/assets/{AIOps-CYxFDrcm.js → AIOps-BiHNUlbU.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CPBtdiU2.js → ActionButton-D-UFjDRQ.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-Dayq7Dp7.js → Analytics-DazVsDgW.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-6U7bPb2s.js → AppLayout-DXh9UfNJ.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-D2Iqg_3D.js → Artifacts-CZ6tsceY.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-CdoOB7WV.js → Audit-RyxnBr_h.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-DrnAVB8w.js → BackgroundAgents-BWS51Q6X.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-CesMi5cy.js → Backup-BRtPcUul.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-DaX9ptax.js → BaseInput-CGd4vZYY.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-OrwOPxDS.js → Chat-h8ijVwCg.js} +4 -4
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CvPZFRxM.js → ChatBubbleRenderer-D7tcdDS9.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-DiHbcysC.js → Checkbox-NyF6dPl8.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CbgCkaBJ.js → Codegen-Ci4OOxr5.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-Du5hgrh4.js → Col-CwTkc9BM.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-DsPOBW-p.js → Community-DW_tM82m.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-BwHIFkNC.js → Compact-DEvHRV4S.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-BvrDQSgd.js → Compliance-BbjBEEfD.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-gwAE6arx.js → Cowork-10IXBaBa.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-DW-0l4uF.js → Cron-BZkbpd5I.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-j-NsLesB.js → Crosschain-CFQ8L_6v.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-CibVEBOI.js → DID-BDF6AkXe.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-W4z9vSfe.js → Dashboard-CoOdWMi4.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-DAcrkKxG.js → Dropdown-DEsGmu8Y.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-6GXah-89.js → EmailListRenderer-BS89SWlK.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-TKDCq8Ku.js → FamilyGuardDashboard-C1FpCHiI.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-BXBLlcNm.js → Federation-BzvpVmLA.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-BoJJBkG3.js → FormItemContext-BeC259PQ.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-okjsl46v.js → GenericCardRenderer-azgG3bmV.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Rvs7i6nn.js → Git-BmSSowc5.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-CHSUxXXS.js → Governance-CTBCSyQZ.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-V3BlfxsB.js → Inference-DA5xyk4a.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-C_NlD4aR.js → KnowledgeGraph-D1gPHNig.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-Nn4LNxhA.js → Logs-BPmLf1AR.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-SVAgNnkt.js → MarkdownRenderer-SVLOg49H.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-DEmjFcg-.js → Marketplace-DtUFcR0E.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-DlopXipI.js → McpTools-DS_kqBv-.js} +3 -3
  39. package/src/assets/web-panel/assets/{Memory-BG3ynX60.js → Memory-Fvh7XL7V.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-DeRzWOfT.js → MobileBridge-C7itAP45.js} +1 -1
  41. package/src/assets/web-panel/assets/MobileProjects-DGbP36-3.js +1 -0
  42. package/src/assets/web-panel/assets/{Mtc-BoPbOv1C.js → Mtc-B57MiNLK.js} +6 -6
  43. package/src/assets/web-panel/assets/{MtcAudit-un-rTHp7.js → MtcAudit-BXfCUcM7.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-Ds0oveEB.js → Multisig-yaJ-ZcF6.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-D09JI-yY.js → NLProgramming-CoaUCKrO.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-DTRhiKJn.js → Notes-BKLM_65R.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-BAnnNCim.js → NotificationSettings-DoDtK9uZ.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-Yr-1fSYi.js → OrderTableRenderer-BJ28TGr-.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-S9EAolpj.js → Organization-MuGsdoIb.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-CqcLKqJ8.js → Overflow-BLUN9J4R.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-Dw0F9EcU.js → P2P-DWuoBUPd.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-BDRwUevN.js → PdhVaultBrowser-CUi37YPj.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-D3_c3nKB.js → Permissions-BYQg2pcr.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-CxdMV98x.js → PersonalDataHub-CAxoV2xu.js} +6 -6
  55. package/src/assets/web-panel/assets/{Pipeline-CgjNQFLI.js → Pipeline-B33wGvIO.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-BHghIIht.js → Privacy-A8yXTORP.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-De6pqaKM.js → ProjectInit-D49I2I1O.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-Bg4ZkNYQ.js → ProjectSettings-Ci73jJDw.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-CF-yD6Cn.js +1 -0
  60. package/src/assets/web-panel/assets/Providers-D-etEhg5.js +1 -0
  61. package/src/assets/web-panel/assets/{QrScannerModal-DA2f3Wts.js → QrScannerModal-Brza0ykJ.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-C1FeHDqp.js → QuickAsk-DFydhjxL.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-B5guaUMN.js → Recommend-DLF8_NhA.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-PDADSds3.js → RemoteSession-dyuStW3x.js} +3 -3
  65. package/src/assets/web-panel/assets/{Reputation-eTlRhgvK.js → Reputation-5F3tA6yw.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-D7AqSGY0.js → Row-Ca2A57S5.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-JiuLm4Ja.js → RssFeed-B0bxBkq_.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-CwruahW3.js → Search-CFNvHalZ.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-CdhqaR0b.js → Security-DSoH3Hav.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-CU0ZIlcT.js → Services-BHpfEmBQ.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-CtduPfAb.js → Skeleton-Dsh-QNmn.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-CROXm6AY.js → Skills-BhT1NkSU.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-DiZiABFD.js → Sla-DY9snPeJ.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-B5pLcXUw.js → SpeechSettings-CWaX0_Cx.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-DBX6J1Oe.js → SyncSettings-B690y_TC.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-BLyRJd3-.js → Tasks-2N-w3zWd.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-BKa5qzmk.js → Templates-BjwQOQYC.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-DnD3a4M6.js → Tenant-CUqHErxY.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-DEitQeTb.js → Terminal-C13rXvNy.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-CjHggTDq.js → TimelineRenderer-CpbWcya_.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-CsGT7sfl.js → Tokens-BXHLGXYC.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-yr4rFDrW.js → Trigger-1e5i65o3.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-CLvu1Sjp.js → Trust-FLGqNHs5.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-B0m7yUP8.js → UkeySign-BbaR_LJB.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-C0VvP4lc.js → VideoEditing-NOp4RIov.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-kllBAG1M.js → Wallet-B7DW7bG4.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-C54UQNLx.js → WebAuthn-BptSUWix.js} +5 -5
  88. package/src/assets/web-panel/assets/{WorkflowEditor-B7y8qSvU.js → WorkflowEditor-CAJnDOXS.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-DRzTh8CJ.js → chat-I8LgG1-Z.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-BSMwSnCx.js → colors-CWe7SOVD.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-BTg602H5.js → compact-item-Cx3u3CA3.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-B6EGsdvp.js → createContext-CgD5ArwY.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-DLv_872g.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-DDKqJ8RD.js → hasIn-BfQWiXN8.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-D5CsBShd.js → index-3iKP9OTJ.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Dfv2lKu3.js → index-87gMxqhN.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-C66NpWy5.js → index-B1cX4Rxu.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-DBT3YeQ9.js → index-B6yChzt1.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BVTAl5N2.js → index-BREnPKGo.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CwPUZbMI.js → index-BUAR7RY-.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-th2ihDc0.js → index-Bi24S7Dw.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CmAubjDi.js → index-BiI-xPRH.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-CUEU48o1.js → index-BuEQSorC.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Cf23wVMs.js → index-Bx7BNIRH.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BRqt4fO-.js → index-C-rIKccl.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-C_JzIXUq.js → index-C0nDKhWv.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DiW0sDkz.js → index-C0ztiqtB.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BICn3Qh1.js → index-C1UjHdgZ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-DpTHIRfZ.js → index-CAUnl4Jv.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Co7oM1qr.js → index-CMu16vPC.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CNxg61YP.js → index-CNYFQxAW.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-XFe-1twF.js → index-CQDKYbnv.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-p2HYn89m.js → index-CWZ3REg6.js} +3 -3
  114. package/src/assets/web-panel/assets/{index-Bx044qDj.js → index-CcX4FSPf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BMuGd2--.js → index-Cd79NQAx.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CGNklbP6.js → index-CdRkCwm4.js} +1 -1
  117. package/src/assets/web-panel/assets/index-CdiGCibe.js +1 -0
  118. package/src/assets/web-panel/assets/{index-rjzk9z1Q.js → index-Cy_cCJlr.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-323Hhxxt.js → index-DAVy98u7.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CDTvsX8t.js → index-DCJEY2T0.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DLdrHhML.js → index-DFb-XIKy.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-pqfux8vZ.js → index-DGMYTN5W.js} +1 -1
  123. package/src/assets/web-panel/assets/index-D_0z-gyz.js +1 -0
  124. package/src/assets/web-panel/assets/{index-u2YVld9W.js → index-Dcdm_Z2c.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-CmAInUkX.js → index-DeizoQVZ.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CHfLYwcW.js → index-DlIyt1qF.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CWGax2QW.js → index-DmgtY58H.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Dc77VR3H.js → index-DmrdUwzU.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-D1naNj4U.js → index-Doc0Ftpd.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BsR7Y2NG.js → index-DsQcURkA.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CQlHFN_g.js → index-DslTuqro.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DqFXGzzC.js → index-V-kIHzAV.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-C1GFfuqN.js → index-e8BM1yY1.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-C3Djh9fa.js → initDefaultProps-DiBszVdG.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BzqFmbSe.js → motion-BGIFFozv.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-DJo_FFaW.js → move-D5W7mp7B.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-_tlTiBvk.js → mtc-parser-JFIlxJ7F.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-CB2ZyxUg.js → omit-CQ3o6LIU.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-DZwIFD4u.js → pickAttrs-R8MIlXo3.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-DxZY0dgk.js → placementArrow-sW7ylSky.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-CzzGt7GL.js → responsiveObserve-Cnl39Vbz.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-BaIK52yz.js → slide-sn8tFd14.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-3-FHu9_M.js → statusUtils-IKKY_QxZ.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BkRT68fK.js → styleChecker-BNpV4Nqs.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-DHYwKS-s.js → useFlexGapSupport-BWyT_eoU.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-DVVUhV8p.js → useFs-D09p6_U9.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-CkrFKAzQ.js → usePersonalDataHub-CzW3TkJZ.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-BuBLFz0c.js → vnode-3s3WoAKB.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-kpm6LtXU.js → zoom-Cjy_673s.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/cowork.js +280 -5
  153. package/src/commands/plugin.js +819 -64
  154. package/src/commands/session-location.js +318 -7
  155. package/src/constants.js +2 -2
  156. package/src/data/changelog.json +27 -1
  157. package/src/gateways/ws/action-protocol.js +1 -1
  158. package/src/harness/jsonl-session-store.js +638 -2
  159. package/src/harness/prompt-compressor.js +4 -0
  160. package/src/lib/background-agent-keeper-client.js +29 -0
  161. package/src/lib/background-agent-keeper-protocol.js +78 -3
  162. package/src/lib/background-agent-launch-barrier.js +74 -0
  163. package/src/lib/background-agent-supervisor.js +208 -34
  164. package/src/lib/background-turn-bootstrap-protocol.js +4 -0
  165. package/src/lib/cowork-task-runner.js +70 -0
  166. package/src/lib/cowork-workflow.js +42 -9
  167. package/src/lib/doctor-checkup.js +34 -10
  168. package/src/lib/dynamic-workflow-draft.js +535 -0
  169. package/src/lib/dynamic-workflow-facade.js +11 -11
  170. package/src/lib/dynamic-workflow-runtime.js +2974 -0
  171. package/src/lib/execution-location-contract.js +111 -7
  172. package/src/lib/execution-location-runtime.js +3 -1
  173. package/src/lib/execution-location-target.js +910 -0
  174. package/src/lib/llm-providers.js +1 -0
  175. package/src/lib/mcp-call-ledger-store.js +35 -0
  176. package/src/lib/mcp-call-ledger.js +30 -0
  177. package/src/lib/plugin-runtime/__tests__/remote-source.test.js +34 -16
  178. package/src/lib/plugin-runtime/install.js +4956 -657
  179. package/src/lib/plugin-runtime/manifest.js +3 -1
  180. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +671 -31
  181. package/src/lib/plugin-runtime/marketplace-catalog.js +68 -2
  182. package/src/lib/plugin-runtime/marketplace-impact.js +208 -15
  183. package/src/lib/plugin-runtime/marketplace-network.js +317 -0
  184. package/src/lib/plugin-runtime/marketplace-pac-worker.js +15 -0
  185. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +25 -2
  186. package/src/lib/plugin-runtime/marketplace-source-cache.js +359 -0
  187. package/src/lib/plugin-runtime/policy.js +21 -6
  188. package/src/lib/plugin-runtime/publisher-trust.js +332 -0
  189. package/src/lib/plugin-runtime/remote-source.js +323 -27
  190. package/src/lib/plugin-runtime/scopes.js +317 -41
  191. package/src/lib/plugin-runtime/transaction-journal.js +806 -0
  192. package/src/lib/public-ide-capability-manifest.js +1 -1
  193. package/src/lib/remote-membership-coordinator.js +8 -6
  194. package/src/lib/sub-agent-context.js +268 -2
  195. package/src/lib/task-model-selector.js +1 -1
  196. package/src/lib/with-file-lock.js +266 -27
  197. package/src/runtime/agent-core.js +595 -41
  198. package/src/workers/background-agent-keeper.js +147 -24
  199. package/src/workers/background-agent-worker.js +383 -134
  200. package/src/workers/background-turn-bootstrap.js +13 -8
  201. package/src/assets/web-panel/assets/MobileProjects-Tyd3o2A0.js +0 -1
  202. package/src/assets/web-panel/assets/Projects-CP8vPvzs.js +0 -1
  203. package/src/assets/web-panel/assets/Providers-CUnHbNf-.js +0 -1
  204. package/src/assets/web-panel/assets/devWarning-Dol8jLEP.js +0 -1
  205. package/src/assets/web-panel/assets/index-C3QX5tOl.js +0 -1
  206. package/src/assets/web-panel/assets/index-xYybvEic.js +0 -1
@@ -9,8 +9,15 @@
9
9
  */
10
10
 
11
11
  import net from "node:net";
12
- import { readFileSync, unlinkSync, writeSync } from "node:fs";
13
- import { resolve } from "node:path";
12
+ import {
13
+ readFileSync,
14
+ renameSync,
15
+ rmSync,
16
+ unlinkSync,
17
+ writeFileSync,
18
+ writeSync,
19
+ } from "node:fs";
20
+ import { dirname, resolve } from "node:path";
14
21
  import { fileURLToPath } from "node:url";
15
22
  import { createNdjsonReader } from "../lib/background-session-transport.js";
16
23
  import {
@@ -27,18 +34,24 @@ import {
27
34
  BACKGROUND_AGENT_KEEPER_ARMED,
28
35
  BACKGROUND_AGENT_KEEPER_CLEANUP_CONFIRM_TIMEOUT_MS,
29
36
  BACKGROUND_AGENT_KEEPER_HELLO,
37
+ BACKGROUND_AGENT_KEEPER_HEARTBEAT,
38
+ BACKGROUND_AGENT_KEEPER_IDENTITY_PROBE_DELAY_MS,
39
+ BACKGROUND_AGENT_KEEPER_HEARTBEAT_TIMEOUT_MS,
30
40
  BACKGROUND_AGENT_KEEPER_PERSIST_RETRY_TIMEOUT_MS,
31
41
  BACKGROUND_AGENT_KEEPER_PROTOCOL_VERSION,
32
42
  BACKGROUND_AGENT_KEEPER_READY,
33
43
  BACKGROUND_AGENT_KEEPER_RETIRE,
34
44
  BACKGROUND_AGENT_KEEPER_RETIRED,
35
45
  BACKGROUND_AGENT_KEEPER_STATE_LOCK_TIMEOUT_MS,
46
+ backgroundAgentKeeperLaunchClaimPath,
36
47
  cleanupBackgroundAgentKeeperPipeDirectory,
48
+ createBackgroundAgentKeeperLaunchClaim,
37
49
  createBackgroundAgentKeeperMessage,
38
50
  normalizeBackgroundAgentKeeperHello,
39
51
  normalizeBackgroundAgentKeeperTurn,
40
52
  sameBackgroundAgentKeeperTurn,
41
53
  } from "../lib/background-agent-keeper-protocol.js";
54
+ import { waitForBackgroundAgentLaunchBarrier } from "../lib/background-agent-launch-barrier.js";
42
55
 
43
56
  const STARTUP_TIMEOUT_MS = 30_000;
44
57
  const HEARTBEAT_INTERVAL_MS = 1_000;
@@ -121,6 +134,7 @@ export function runBackgroundAgentKeeperHeartbeat({
121
134
  workerSocket,
122
135
  authenticatedHello,
123
136
  authenticatedWorkerStartedAt,
137
+ workerHeartbeatAt,
124
138
  armedTurn,
125
139
  persistKeeper,
126
140
  finishForWorkerDisconnect,
@@ -129,25 +143,47 @@ export function runBackgroundAgentKeeperHeartbeat({
129
143
  reportPersistenceFailure = reportKeeperPersistenceFailure,
130
144
  }) {
131
145
  if (finishing) return false;
132
- if (
146
+ // Startup is deliberately serialized: the keeper publishes its listening
147
+ // claim, then remains read-only until the worker has claimed and
148
+ // authenticated. Persisting a pre-auth heartbeat would reintroduce the
149
+ // first-write lock race the launch barrier prevents.
150
+ if (!workerSocket || !authenticatedHello) return false;
151
+ const currentTime = now();
152
+ const workerHeartbeatAge = Number.isFinite(workerHeartbeatAt)
153
+ ? Math.max(0, currentTime - workerHeartbeatAt)
154
+ : 0;
155
+ const workerHeartbeatExpired =
133
156
  workerSocket &&
134
157
  authenticatedHello &&
158
+ Number.isFinite(workerHeartbeatAt) &&
159
+ workerHeartbeatAge > BACKGROUND_AGENT_KEEPER_HEARTBEAT_TIMEOUT_MS;
160
+ const workerIdentityProbeDue =
135
161
  armedTurn &&
136
- !workerIdentityAlive(
137
- authenticatedHello.workerPid,
138
- authenticatedWorkerStartedAt,
139
- )
162
+ Number.isFinite(workerHeartbeatAt) &&
163
+ workerHeartbeatAge > BACKGROUND_AGENT_KEEPER_IDENTITY_PROBE_DELAY_MS;
164
+ if (
165
+ workerSocket &&
166
+ authenticatedHello &&
167
+ (workerHeartbeatExpired ||
168
+ (workerIdentityProbeDue &&
169
+ !workerIdentityAlive(
170
+ authenticatedHello.workerPid,
171
+ authenticatedWorkerStartedAt,
172
+ )))
140
173
  ) {
141
- // A Windows named-pipe handle can remain open after its worker dies if a
142
- // platform helper retained a duplicate. Socket EOF alone is therefore
143
- // not a sufficient lifetime signal. The generation-bound worker PID and
144
- // its durable launch anchor provide an independent identity fence.
174
+ // A Windows named-pipe handle and process object can remain observable
175
+ // after its worker dies if a platform helper retained a duplicate.
176
+ // Socket EOF and PID visibility are therefore not sufficient lifetime
177
+ // signals. The authenticated application heartbeat provides an
178
+ // independent bounded fence. Delay the PID/start probe until application
179
+ // heartbeats are already stale so healthy Windows keepers do not create a
180
+ // synchronized WMIC/PowerShell probe storm under normal operation.
145
181
  finishForWorkerDisconnect();
146
182
  workerSocket.destroy();
147
183
  return false;
148
184
  }
149
185
  try {
150
- persistKeeper({ keeperHeartbeatAt: now() });
186
+ persistKeeper({ keeperHeartbeatAt: currentTime });
151
187
  return true;
152
188
  } catch (error) {
153
189
  try {
@@ -226,7 +262,9 @@ export function stopBackgroundAgentKeeperTurnTrees(targets, options = {}) {
226
262
  leaderAlive ||
227
263
  (platform !== "win32" &&
228
264
  target.processGroup === true &&
229
- processTreeExecutionAlive(target.pid, target.startedAt));
265
+ processTreeExecutionAlive(target.pid, target.startedAt, {
266
+ processGroup: true,
267
+ }));
230
268
  if (residualAlive) {
231
269
  failures.push(error?.message || String(error));
232
270
  }
@@ -235,6 +273,46 @@ export function stopBackgroundAgentKeeperTurnTrees(targets, options = {}) {
235
273
  return failures;
236
274
  }
237
275
 
276
+ export async function waitForBackgroundAgentKeeperTurnTreesToStop(
277
+ targets,
278
+ options = {},
279
+ ) {
280
+ const now = options.now || Date.now;
281
+ const sleep =
282
+ options.sleep ||
283
+ ((milliseconds) =>
284
+ new Promise((resolvePromise) =>
285
+ setTimeout(resolvePromise, milliseconds),
286
+ ));
287
+ const processTreeExecutionAlive =
288
+ options.isProcessTreeExecutionAlive ||
289
+ isBackgroundProcessTreeExecutionAlive;
290
+ const timeoutMs = Math.max(
291
+ 1,
292
+ Number(options.timeoutMs) ||
293
+ BACKGROUND_AGENT_KEEPER_CLEANUP_CONFIRM_TIMEOUT_MS,
294
+ );
295
+ // Each strict macOS liveness probe invokes ps. Polling every 10 ms across
296
+ // 20 keepers created a process storm precisely while launchd was trying to
297
+ // reap the killed groups. A 100 ms cadence remains responsive and bounded
298
+ // while leaving the host enough scheduling capacity to establish absence.
299
+ const pollMs = Math.max(1, Number(options.pollMs) || 100);
300
+ const deadline = now() + timeoutMs;
301
+ const observeAlive = () =>
302
+ targets.filter((target) =>
303
+ processTreeExecutionAlive(target.pid, target.startedAt, {
304
+ processGroup: target.processGroup !== false,
305
+ }),
306
+ );
307
+
308
+ let alive = observeAlive();
309
+ while (alive.length > 0 && now() < deadline) {
310
+ await sleep(Math.max(1, Math.min(pollMs, deadline - now())));
311
+ alive = observeAlive();
312
+ }
313
+ return alive;
314
+ }
315
+
238
316
  async function cleanupTurn(job, turn, reason) {
239
317
  const requestedAt = Date.now();
240
318
  const requestedPersistence = await retryKeeperPersistence(() =>
@@ -262,17 +340,7 @@ async function cleanupTurn(job, turn, reason) {
262
340
  );
263
341
  const failures = stopBackgroundAgentKeeperTurnTrees(targets);
264
342
 
265
- const deadline =
266
- Date.now() + BACKGROUND_AGENT_KEEPER_CLEANUP_CONFIRM_TIMEOUT_MS;
267
- let alive = targets.filter((target) =>
268
- isBackgroundProcessTreeExecutionAlive(target.pid, target.startedAt),
269
- );
270
- while (alive.length > 0 && Date.now() < deadline) {
271
- await new Promise((resolvePromise) => setTimeout(resolvePromise, 10));
272
- alive = targets.filter((target) =>
273
- isBackgroundProcessTreeExecutionAlive(target.pid, target.startedAt),
274
- );
275
- }
343
+ const alive = await waitForBackgroundAgentKeeperTurnTreesToStop(targets);
276
344
  const confirmed = alive.length === 0 && failures.length === 0;
277
345
  let finalPersistenceAttempts = 0;
278
346
  const finalPersistence = await retryKeeperPersistence(() => {
@@ -309,6 +377,24 @@ async function cleanupTurn(job, turn, reason) {
309
377
 
310
378
  export async function runBackgroundAgentKeeper(jobFile, options = {}) {
311
379
  const job = JSON.parse(readFileSync(jobFile, "utf8"));
380
+ const launchClaimPath = backgroundAgentKeeperLaunchClaimPath(
381
+ job.id,
382
+ job.keeperGeneration,
383
+ options.backgroundAgentsDirectory || dirname(resolve(jobFile)),
384
+ );
385
+ const launchBarrier = await waitForBackgroundAgentLaunchBarrier({
386
+ id: job.id,
387
+ workerGeneration: job.workerGeneration,
388
+ expectedPid: process.pid,
389
+ pidField: "keeperPid",
390
+ readState: options.readBackgroundAgentState || readBackgroundAgentState,
391
+ timeoutMs: Number(options.launchBarrierTimeoutMs) || undefined,
392
+ sleep: options.launchBarrierSleep,
393
+ });
394
+ if (launchBarrier.status !== "ready") {
395
+ removeJobFile(jobFile);
396
+ return { status: `launch-${launchBarrier.status}` };
397
+ }
312
398
  removeJobFile(jobFile);
313
399
  const startedAt = Date.now();
314
400
  const claim = mutateBackgroundAgentState(job.id, (current) => {
@@ -329,6 +415,25 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
329
415
  };
330
416
  });
331
417
  if (!claim.applied) return { status: "unclaimed" };
418
+ const launchClaim = createBackgroundAgentKeeperLaunchClaim({
419
+ id: job.id,
420
+ workerGeneration: job.workerGeneration,
421
+ keeperGeneration: job.keeperGeneration,
422
+ keeperPid: process.pid,
423
+ token: job.token,
424
+ });
425
+ const launchClaimCandidate = `${launchClaimPath}.${process.pid}.tmp`;
426
+ try {
427
+ writeFileSync(launchClaimCandidate, JSON.stringify(launchClaim), {
428
+ encoding: "utf8",
429
+ mode: 0o600,
430
+ flag: "wx",
431
+ });
432
+ renameSync(launchClaimCandidate, launchClaimPath);
433
+ } catch (error) {
434
+ rmSync(launchClaimCandidate, { force: true });
435
+ throw error;
436
+ }
332
437
 
333
438
  if (process.platform !== "win32") {
334
439
  try {
@@ -342,6 +447,7 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
342
447
  let candidateSocket = null;
343
448
  let authenticatedHello = null;
344
449
  let authenticatedWorkerStartedAt = null;
450
+ let workerHeartbeatAt = null;
345
451
  let armedTurn = null;
346
452
  let finishing = false;
347
453
  let finishResolve;
@@ -460,6 +566,7 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
460
566
  authenticated = true;
461
567
  authenticatedHello = hello;
462
568
  authenticatedWorkerStartedAt = Number(current.startedAt);
569
+ workerHeartbeatAt = Date.now();
463
570
  workerSocket = socket;
464
571
  clearTimeout(helloTimer);
465
572
  persistKeeper({ keeperStatus: "ready", keeperReadyAt: Date.now() });
@@ -477,6 +584,20 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
477
584
  return;
478
585
  }
479
586
 
587
+ if (message.type === BACKGROUND_AGENT_KEEPER_HEARTBEAT) {
588
+ if (
589
+ message.id !== authenticatedHello.id ||
590
+ message.workerGeneration !==
591
+ authenticatedHello.workerGeneration ||
592
+ Number(message.workerPid) !== authenticatedHello.workerPid
593
+ ) {
594
+ socket.destroy();
595
+ return;
596
+ }
597
+ workerHeartbeatAt = Date.now();
598
+ return;
599
+ }
600
+
480
601
  if (
481
602
  message.type !== BACKGROUND_AGENT_KEEPER_ARM &&
482
603
  message.type !== BACKGROUND_AGENT_KEEPER_RETIRE
@@ -613,6 +734,7 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
613
734
  workerSocket,
614
735
  authenticatedHello,
615
736
  authenticatedWorkerStartedAt,
737
+ workerHeartbeatAt,
616
738
  armedTurn,
617
739
  persistKeeper,
618
740
  finishForWorkerDisconnect,
@@ -656,6 +778,7 @@ export async function runBackgroundAgentKeeper(jobFile, options = {}) {
656
778
  // Another keeper can still own a sibling socket in the shared namespace.
657
779
  }
658
780
  }
781
+ rmSync(launchClaimPath, { force: true });
659
782
  return {
660
783
  ...result,
661
784
  authenticatedWorkerPid: authenticatedHello?.workerPid || null,