chainlesschain 0.162.176 → 0.162.178

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 (260) hide show
  1. package/README.md +10 -0
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-BDLu5Elz.js → AIOps-DRftcSue.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-DH5us-CK.js → ActionButton-BFvUaMKR.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-BZ0u8IFG.js → Analytics-C0-Rru4P.js} +3 -3
  7. package/src/assets/web-panel/assets/AppLayout-bx-BCljj.js +9 -0
  8. package/src/assets/web-panel/assets/{Artifacts-Br2YBbh_.js → Artifacts-DAJ8B3Un.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-C3C6a482.js → Audit-hOk4L1lr.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-CzHvebcj.js → BackgroundAgents-3pbDpM9z.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-DZNHYDFd.js → Backup-BtziGDn9.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-VRiC4fIx.js → BaseInput-kmshphJ3.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-Cm08WWAD.js → Chat-d7tGSosA.js} +5 -5
  14. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CGHYrugQ.js → ChatBubbleRenderer-p-_PBpX_.js} +1 -1
  15. package/src/assets/web-panel/assets/{Checkbox-DtByk7d7.js → Checkbox-C4Eh4Tz5.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-CphXXOfD.js → Codegen-r7gmhZyA.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-Hz86TnLR.js → Col-U7mDaGlL.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-HP03ltpD.js → Community-Bpu8aH1T.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-B_N1mqQz.js → Compact-CHb2XBJe.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-CVztRpi8.js → Compliance-Cn_r4dey.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-wUVOyZih.js → Cowork-CdMWfDcz.js} +4 -4
  22. package/src/assets/web-panel/assets/{Cron-DW5TLJKw.js → Cron-BtnREHWy.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-CrAFGhWH.js → Crosschain-BKI9TSzr.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-pA-oD8ke.js → DID-pkNubzzJ.js} +2 -2
  25. package/src/assets/web-panel/assets/Dashboard-1rrz1snN.js +3 -0
  26. package/src/assets/web-panel/assets/{Dropdown-EweJcsek.js → Dropdown-DLyFVxDc.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-C9xVLPG4.js → EmailListRenderer-CtUWfYVq.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-CDcEEqlu.js → FamilyGuardDashboard-B8eX2Qe4.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-DtZda9A_.js → Federation-D8lsDGus.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-CiYdcVz3.js → FormItemContext-CRYt_aIw.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-DA13uwA0.js → GenericCardRenderer-ClKzY8_N.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-DzRhZD1O.js → Git-BXj5Dney.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-D5RMgOSb.js → Governance-Cm-I8RMz.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-BgrPfSNk.js → Inference-CPvbhvgt.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-DzjnD571.js → KnowledgeGraph-sYNDZaoi.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-BhWzVDtN.js → Logs-BZY_3CRZ.js} +2 -2
  37. package/src/assets/web-panel/assets/{MarkdownRenderer-BDape9cx.js → MarkdownRenderer-up0BW6pv.js} +1 -1
  38. package/src/assets/web-panel/assets/{Marketplace-DJtL5GV7.js → Marketplace-C5MEJ2Qe.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-CZcQygI7.js → McpTools-ihdrn43I.js} +5 -5
  40. package/src/assets/web-panel/assets/{Memory-DUWSDUUu.js → Memory-Br8bPMlh.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-BTwq2WKY.js → MobileBridge-BNntgrYW.js} +1 -1
  42. package/src/assets/web-panel/assets/MobileProjects-BdV915mw.js +1 -0
  43. package/src/assets/web-panel/assets/{Mtc-BiGugEQm.js → Mtc-A3wDmlqL.js} +5 -5
  44. package/src/assets/web-panel/assets/{MtcAudit-DY7a6gUe.js → MtcAudit-CF-mBLWM.js} +2 -2
  45. package/src/assets/web-panel/assets/{Multisig-BQbDu_w7.js → Multisig-Iy2k_MSo.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-CM2wXTLv.js → NLProgramming-kk0W7HUb.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-DI6gGs1v.js → Notes-B5u5t_4S.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-BsZOLWAB.js → NotificationSettings-BN0POf6_.js} +1 -1
  49. package/src/assets/web-panel/assets/OrderTableRenderer-CHkSUrXB.js +1 -0
  50. package/src/assets/web-panel/assets/{Organization-Cds0_tXr.js → Organization-DwWQESuN.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-WunYMD87.js → Overflow-DG6klrcC.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-Bo6j4DDv.js → P2P-BwJcKkgZ.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-Bh2XPD5f.js → PdhVaultBrowser-BwOHG0in.js} +5 -5
  54. package/src/assets/web-panel/assets/{Permissions-EMvMMC8N.js → Permissions-CGMXe4TX.js} +4 -4
  55. package/src/assets/web-panel/assets/PersonalDataHub-ziYqg7-A.js +8 -0
  56. package/src/assets/web-panel/assets/{Pipeline-BOx8HOgL.js → Pipeline-BzJfeoGt.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-tBeTVQVM.js → Privacy-DLh3Bblx.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-CVYg1W4M.js → ProjectInit-USVWW36c.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-Dvt5I7y1.js → ProjectSettings-CiiOn62h.js} +2 -2
  60. package/src/assets/web-panel/assets/Projects-6V-PNmcA.js +1 -0
  61. package/src/assets/web-panel/assets/{Providers-Ct8xqY-E.js → Providers-CBPWWzpu.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-Cni8Ooja.js → QrScannerModal-QVwoRUq3.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-BJVLKdxr.js → QuickAsk-CXnR-2Vn.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-DPG8Rbbm.js → Recommend-ClaNzjmF.js} +1 -1
  65. package/src/assets/web-panel/assets/{RemoteSession-DsdR7dCt.js → RemoteSession-C3rGw8vJ.js} +2 -2
  66. package/src/assets/web-panel/assets/{Reputation-Csg1YM-b.js → Reputation-Ci-OWAoP.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-D9DoFoEf.js → Row-DRhAwXOS.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-BsvKrXMS.js → RssFeed-BQLJQ2_y.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-DFUStfgQ.js → Search-QQUpkfFd.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-ILg1zxdK.js → Security-DdXKzuKT.js} +4 -4
  71. package/src/assets/web-panel/assets/{Services-Dd41PCaY.js → Services-x2Zh62Qd.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-Bzo1cN80.js → Skeleton-GdY4KwRz.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-BDHh17P0.js → Skills-Bv4tY1Fd.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-jl7UTiRY.js → Sla-C3QnM-11.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-BePa-RF6.js → SpeechSettings-Bl3ytvmI.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-DiqqDKGZ.js → SyncSettings-Wp9IwTsP.js} +2 -2
  77. package/src/assets/web-panel/assets/{Tasks-DYQ_6lxj.js → Tasks-CF3rIrDe.js} +1 -1
  78. package/src/assets/web-panel/assets/{Templates-JiDeI06L.js → Templates-CGfvVVM9.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-hhgI6zwS.js → Tenant-CVXmwQ3U.js} +1 -1
  80. package/src/assets/web-panel/assets/Terminal-bvwrt03E.js +3 -0
  81. package/src/assets/web-panel/assets/{TimelineRenderer-B8uB5Llk.js → TimelineRenderer-D0g74KhH.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-C3b_6r2z.js → Tokens-BH4IwzlT.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-tIP7HKVe.js → Trigger-DJOpM533.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-vjoc11vJ.js → Trust-B43EPRLr.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-DUPBnGuH.js → UkeySign-BmBFG-em.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-CBvhUY5T.js → VideoEditing-n9oJwB8k.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-DUaQ0uA5.js → Wallet-D5QeivHp.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-DllSivjE.js → WebAuthn-DcNy7igO.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-xc8D3uO6.js → WorkflowEditor-BVjc7-5-.js} +1 -1
  90. package/src/assets/web-panel/assets/{chat-BVicU7oA.js → chat-Dy5Tfj3m.js} +1 -1
  91. package/src/assets/web-panel/assets/{colors-DJzLmhLm.js → colors-C4c2CNZU.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-BvYRfThE.js → compact-item-DPa3O5vN.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-DGXxCBKR.js → createContext-TLcfNA6_.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-BAwdDA_5.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-SBDJB1y4.js → hasIn-D41LVFkp.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-D7HimK0M.js → index-0oevYjfT.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DCdRAgjy.js → index-388pLGJ1.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BO1itZaY.js → index-B8nLBZbv.js} +3 -3
  99. package/src/assets/web-panel/assets/{index-DvUTDYXX.js → index-BPTGAjee.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-hxTODbM1.js → index-BPtrOBmW.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-wcCL-miV.js → index-BQiIxHBy.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CKyEivf8.js → index-BSM1cHVK.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BJZf9DhV.js → index-BYPr9fkz.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DHVLJ8q0.js → index-BsQ7Ev6i.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Cs2rmLFt.js → index-Btk9qLL2.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-z1ZylsLq.js → index-BvmziZSG.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-Cf-O_g_8.js → index-BvopLC_T.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DMarmfrv.js → index-C7xhTVyP.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-CoJAO1Lm.js → index-CNk_ZooP.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-9gdI7uUW.js → index-CQrEHoOG.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Bf-ctERC.js → index-CSxex23J.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-MjC4G09d.js → index-CVjgm992.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-e4fXH_WO.js → index-CWK4zOPe.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-xfluRkCT.js → index-CX0VsoP4.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DRfiXB_p.js → index-CXl0YPNG.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-d5BVd-cL.js → index-Cip7LWml.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Dm_77jgR.js → index-Cq_hlWNt.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-YJkzy8ZF.js → index-CzZ49YZL.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CtwqO5qo.js → index-D2Nkivlm.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BYqz4Wrr.js → index-DBUgRs4D.js} +1 -1
  121. package/src/assets/web-panel/assets/index-DEjVkdzq.js +1 -0
  122. package/src/assets/web-panel/assets/{index-CdGY9P8a.js → index-DNsBj2Ob.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DonCnfMr.js → index-Di4X8cfI.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-1SdDS6lR.js → index-DljFsVGI.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DnjPdvR6.js → index-Korc3QIe.js} +1 -1
  126. package/src/assets/web-panel/assets/index-LMOc5xrS.js +1 -0
  127. package/src/assets/web-panel/assets/{index-VMfwIH5G.js → index-MKZDje0H.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DKrvvWm4.js → index-OHAfRu_3.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-FxZzRyE1.js → index-WEJr8PL5.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Crk5NTb0.js → index-WinCp6du.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DCqRS6da.js → index-Yjr6cqSK.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-BTrBGBJs.js → index-iQ6gtFih.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-lpaGoTH3.js → index-pt3s7yvV.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-CloCgBUR.js → index-tQ3igERQ.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-C1zO1KnY.js → initDefaultProps-BFZu87WZ.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-CWLtEGmC.js → motion-DJIo7qvt.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-DzD_C3Vm.js → move-Cfr5qknL.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-D880PYJl.js → mtc-parser-Bgc-OadH.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-CFR_z2ov.js → omit-X3WI-TNp.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-srIhgrSC.js → pickAttrs-pJhU9IxK.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-C1rXpibP.js → placementArrow-BNg_Vj3T.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-C30gRcSS.js → responsiveObserve-TeSEGQ5-.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-CvtKiMfV.js → slide-D_t_P0bv.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-DNHO7ITG.js → statusUtils-DrrIMwAT.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-Dt_Sl-g4.js → styleChecker-BjZCuFRm.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-Cjev42Gh.js → useFlexGapSupport-rTFdlqdQ.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-Baxglj2V.js → useFs-BidCpfLX.js} +1 -1
  148. package/src/assets/web-panel/assets/usePersonalDataHub-C5mHttA9.js +1 -0
  149. package/src/assets/web-panel/assets/{vnode-mIRkdT7o.js → vnode-BrbcRiHZ.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-HzI5DlH_.js → zoom-PISX7AkR.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/commands/__tests__/hub-wechat.test.js +45 -0
  153. package/src/commands/agenda.js +22 -6
  154. package/src/commands/agent.js +3 -3
  155. package/src/commands/background-session.js +16 -6
  156. package/src/commands/batch.js +79 -27
  157. package/src/commands/changelog.js +15 -4
  158. package/src/commands/context.js +33 -1
  159. package/src/commands/eval.js +21 -6
  160. package/src/commands/hook.js +2 -2
  161. package/src/commands/hub.js +473 -39
  162. package/src/commands/init.js +212 -110
  163. package/src/commands/llm.js +22 -6
  164. package/src/commands/loop.js +9 -2
  165. package/src/commands/skill.js +13 -1
  166. package/src/commands/statusline.js +3 -3
  167. package/src/data/changelog.json +53 -5
  168. package/src/gateways/ws/personal-data-hub-protocol.js +22 -2
  169. package/src/harness/background-task-manager.js +18 -6
  170. package/src/harness/background-task-worker.js +11 -18
  171. package/src/harness/golden-transcript.js +3 -0
  172. package/src/harness/mcp-client.js +9 -15
  173. package/src/harness/worktree-isolator.js +18 -21
  174. package/src/index.js +18 -7
  175. package/src/lib/agent-core.js +5 -0
  176. package/src/lib/agent-ipc-bus.js +12 -3
  177. package/src/lib/agent-team/team-worktree.js +28 -6
  178. package/src/lib/agent-worktree.js +20 -19
  179. package/src/lib/approval-authority-store.js +891 -0
  180. package/src/lib/async-hook-supervisor.cjs +134 -24
  181. package/src/lib/async-hook-supervisor.js +47 -0
  182. package/src/lib/background-agent-supervisor.js +35 -12
  183. package/src/lib/background-interaction-resolver.js +399 -54
  184. package/src/lib/background-session-transport.js +3 -1
  185. package/src/lib/background-task-manager.js +5 -1
  186. package/src/lib/changelog.js +57 -0
  187. package/src/lib/chrome-connector.js +6 -2
  188. package/src/lib/claude-code-bridge.js +24 -8
  189. package/src/lib/cli-anything-bridge.js +82 -25
  190. package/src/lib/context-breakdown.js +82 -3
  191. package/src/lib/doctor-checkup.js +18 -6
  192. package/src/lib/eval/tasks.js +25 -31
  193. package/src/lib/event-runtime-host.js +225 -0
  194. package/src/lib/event-runtime-store.js +102 -21
  195. package/src/lib/event-runtime-worker.js +70 -2
  196. package/src/lib/hook-runner.cjs +71 -36
  197. package/src/lib/hook-runner.js +55 -0
  198. package/src/lib/hooks-v2-producers.js +33 -8
  199. package/src/lib/hooks-v2-runtime.js +360 -40
  200. package/src/lib/host-adb-bridge.js +18 -3
  201. package/src/lib/interaction-adapter.js +66 -0
  202. package/src/lib/lsp/__tests__/benchmark.test.js +61 -0
  203. package/src/lib/lsp/__tests__/lsp-client.test.js +6 -1
  204. package/src/lib/lsp/benchmark.js +20 -4
  205. package/src/lib/lsp/lsp-client.js +6 -4
  206. package/src/lib/lsp/lsp-server-registry.js +0 -2
  207. package/src/lib/operation-fingerprint.js +107 -2
  208. package/src/lib/orchestrator.js +8 -2
  209. package/src/lib/packer/pack-update-applier.js +14 -2
  210. package/src/lib/packer/smoke-runner.js +18 -5
  211. package/src/lib/paths.js +1 -1
  212. package/src/lib/pdh-dedicated-batch-collectors.js +124 -0
  213. package/src/lib/personal-data-hub-wiring.js +327 -52
  214. package/src/lib/plugin-monitor-supervisor.js +20 -13
  215. package/src/lib/plugin-runtime/install.js +10 -3
  216. package/src/lib/process-execution-broker/credential-agent.js +954 -111
  217. package/src/lib/process-execution-broker/index.js +369 -85
  218. package/src/lib/process-execution-broker/platform-sandbox.js +320 -140
  219. package/src/lib/provider-http-error.js +94 -0
  220. package/src/lib/remote-approval-bridge.js +222 -26
  221. package/src/lib/repl-bang-memorize.js +10 -2
  222. package/src/lib/repl-goal.js +19 -2
  223. package/src/lib/settings-hook-events.cjs +13 -8
  224. package/src/lib/settings-hook-events.js +20 -0
  225. package/src/lib/side-effect-ledger-store.js +65 -14
  226. package/src/lib/skill-loader.js +215 -12
  227. package/src/lib/skill-packs/generator.js +18 -9
  228. package/src/lib/skill-process-broker.js +85 -0
  229. package/src/lib/slash-commands.js +10 -2
  230. package/src/lib/status-line.cjs +28 -7
  231. package/src/lib/status-line.js +33 -0
  232. package/src/lib/sub-agent-context.js +42 -0
  233. package/src/lib/turn-binding-store.js +64 -15
  234. package/src/lib/turn-binding.js +85 -16
  235. package/src/repl/agent-repl.js +88 -49
  236. package/src/repl/remote-approval.js +13 -13
  237. package/src/repl/repl-turn-binding.js +46 -16
  238. package/src/runtime/agent-core.js +419 -84
  239. package/src/runtime/coding-agent-contract-shared.cjs +16 -0
  240. package/src/runtime/headless-runner.js +172 -44
  241. package/src/runtime/headless-stream.js +221 -11
  242. package/src/runtime/session-slash-commands.js +506 -0
  243. package/src/skills/video-editing/extractors/audio-extractor.js +13 -5
  244. package/src/skills/video-editing/extractors/video-extractor.js +13 -3
  245. package/src/skills/video-editing/media-process.js +20 -0
  246. package/src/skills/video-editing/render/audio-mix.js +13 -3
  247. package/src/skills/video-editing/render/ffmpeg-concat.js +7 -2
  248. package/src/skills/video-editing/render/ffmpeg-extract.js +7 -2
  249. package/src/workers/background-agent-worker.js +76 -40
  250. package/src/assets/web-panel/assets/AppLayout-Duu8xR14.js +0 -9
  251. package/src/assets/web-panel/assets/Dashboard-CXrd5gAw.js +0 -3
  252. package/src/assets/web-panel/assets/MobileProjects-NZvvfDME.js +0 -1
  253. package/src/assets/web-panel/assets/OrderTableRenderer-C48mu09U.js +0 -1
  254. package/src/assets/web-panel/assets/PersonalDataHub-AX3ypUDV.js +0 -9
  255. package/src/assets/web-panel/assets/Projects-Cc7FC9-e.js +0 -1
  256. package/src/assets/web-panel/assets/Terminal-CjTZPa37.js +0 -3
  257. package/src/assets/web-panel/assets/devWarning-BT46Y_QI.js +0 -1
  258. package/src/assets/web-panel/assets/index-B7nuIywP.js +0 -1
  259. package/src/assets/web-panel/assets/index-ycwAfC-i.js +0 -1
  260. package/src/assets/web-panel/assets/usePersonalDataHub-B4NkcLaP.js +0 -1
@@ -8,13 +8,27 @@
8
8
  * that the existing 4-layer skill-loader picks up automatically.
9
9
  */
10
10
 
11
- import { execSync } from "child_process";
12
11
  import fs from "fs";
13
12
  import path from "path";
14
13
  import { getElectronUserDataDir } from "./paths.js";
14
+ import executionBroker from "./process-execution-broker/index.js";
15
15
 
16
16
  /* ---------- _deps injection (Vitest CJS mock pattern) ---------- */
17
- export const _deps = { execSync, fs, path };
17
+ export const _deps = {
18
+ execFileSync: executionBroker.execFileSync.bind(executionBroker),
19
+ fs,
20
+ path,
21
+ };
22
+
23
+ function execCliAnything(file, args, options, origin) {
24
+ return _deps.execFileSync(file, args, {
25
+ ...options,
26
+ origin,
27
+ policy: "allow",
28
+ scope: "cli-anything",
29
+ shell: false,
30
+ });
31
+ }
18
32
 
19
33
  /* ----------------------------------------------------------------
20
34
  * Database helpers
@@ -55,13 +69,16 @@ export function detectPython() {
55
69
 
56
70
  for (const cmd of candidates) {
57
71
  try {
58
- const ver = _deps
59
- .execSync(`${cmd} --version`, {
72
+ const ver = execCliAnything(
73
+ cmd,
74
+ ["--version"],
75
+ {
60
76
  encoding: "utf-8",
61
77
  timeout: 10000,
62
78
  stdio: ["pipe", "pipe", "pipe"],
63
- })
64
- .trim();
79
+ },
80
+ "cli-anything:detect-python",
81
+ ).trim();
65
82
  const match = ver.match(/Python\s+([\d.]+)/i);
66
83
  if (match) {
67
84
  return { found: true, command: cmd, version: match[1] };
@@ -82,11 +99,16 @@ export function detectCliAnything() {
82
99
  if (!py.found) return { installed: false };
83
100
 
84
101
  try {
85
- const out = _deps.execSync(`${py.command} -m pip show cli-anything`, {
86
- encoding: "utf-8",
87
- timeout: 15000,
88
- stdio: ["pipe", "pipe", "pipe"],
89
- });
102
+ const out = execCliAnything(
103
+ py.command,
104
+ ["-m", "pip", "show", "cli-anything"],
105
+ {
106
+ encoding: "utf-8",
107
+ timeout: 15000,
108
+ stdio: ["pipe", "pipe", "pipe"],
109
+ },
110
+ "cli-anything:detect-package",
111
+ );
90
112
  const verMatch = out.match(/Version:\s*([\d.]+)/i);
91
113
  return {
92
114
  installed: true,
@@ -102,11 +124,16 @@ export function detectCliAnything() {
102
124
  * Install CLI-Anything via pip.
103
125
  */
104
126
  export function installCliAnything(pythonCmd) {
105
- _deps.execSync(`${pythonCmd} -m pip install cli-anything`, {
106
- encoding: "utf-8",
107
- timeout: 120000,
108
- stdio: "inherit",
109
- });
127
+ execCliAnything(
128
+ pythonCmd,
129
+ ["-m", "pip", "install", "cli-anything"],
130
+ {
131
+ encoding: "utf-8",
132
+ timeout: 120000,
133
+ stdio: "inherit",
134
+ },
135
+ "cli-anything:install",
136
+ );
110
137
  }
111
138
 
112
139
  /* ----------------------------------------------------------------
@@ -152,11 +179,16 @@ export function scanPathForTools() {
152
179
  export function parseToolHelp(command) {
153
180
  let helpText;
154
181
  try {
155
- helpText = _deps.execSync(`${command} --help`, {
156
- encoding: "utf-8",
157
- timeout: 15000,
158
- stdio: ["pipe", "pipe", "pipe"],
159
- });
182
+ helpText = execCliAnything(
183
+ command,
184
+ ["--help"],
185
+ {
186
+ encoding: "utf-8",
187
+ timeout: 15000,
188
+ stdio: ["pipe", "pipe", "pipe"],
189
+ },
190
+ "cli-anything:tool-help",
191
+ );
160
192
  } catch (err) {
161
193
  const raw = err.stdout || err.stderr || "";
162
194
  helpText = typeof raw === "string" ? raw : raw.toString("utf-8");
@@ -252,19 +284,44 @@ Pass the subcommand and arguments as plain text input:
252
284
  */
253
285
  export function _generateHandlerJs(name, command) {
254
286
  return `"use strict";
255
- const { execSync } = require("child_process");
287
+ const CLI_COMMAND = ${JSON.stringify(command)};
288
+
289
+ function parseArgs(input) {
290
+ const args = [];
291
+ let current = "";
292
+ let inSingle = false;
293
+ let inDouble = false;
294
+ for (const ch of input.trim()) {
295
+ if (ch === "'" && !inDouble) { inSingle = !inSingle; continue; }
296
+ if (ch === '"' && !inSingle) { inDouble = !inDouble; continue; }
297
+ if (/\\s/.test(ch) && !inSingle && !inDouble) {
298
+ if (current) { args.push(current); current = ""; }
299
+ continue;
300
+ }
301
+ current += ch;
302
+ }
303
+ if (inSingle || inDouble) return null;
304
+ if (current) args.push(current);
305
+ return args;
306
+ }
256
307
 
257
308
  module.exports = {
258
309
  async execute(task, context) {
259
310
  const input = (task?.params?.input || task?.action || "").trim();
260
311
  if (!input) return { success: false, error: "No input provided" };
261
- // Security: input is interpolated into a shell command, so reject shell
262
- // metacharacters to prevent command injection from untrusted skill input.
312
+ // Keep the historical shell-character guard for generated-handler
313
+ // compatibility even though the Broker now receives literal argv.
263
314
  if (/[;&|\`$<>()\\n\\r]/.test(input)) {
264
315
  return { success: false, error: "Input contains unsafe shell characters; refused." };
265
316
  }
317
+ const args = parseArgs(input);
318
+ if (!args) return { success: false, error: "Input contains an unmatched quote; refused." };
319
+ const processBroker = context?.processBroker;
320
+ if (!processBroker || typeof processBroker.runFileSync !== "function") {
321
+ return { success: false, error: "Process Broker unavailable for skill execution." };
322
+ }
266
323
  try {
267
- const output = execSync(\`${command} \${input}\`, {
324
+ const output = processBroker.runFileSync(CLI_COMMAND, args, {
268
325
  encoding: "utf-8",
269
326
  timeout: 60000,
270
327
  cwd: context?.projectRoot || process.cwd(),
@@ -84,14 +84,93 @@ export function breakdownSkillSources(skills, estimateTokens) {
84
84
  .map((skill) => ({
85
85
  source: skill?.source || "skill",
86
86
  skill: String(skill?.id || skill?.displayName || "skill"),
87
- tokens: est(
88
- `## Persona: ${skill?.displayName || skill?.id || "skill"}\n${skill?.body || ""}`,
89
- ),
87
+ tokens: Number.isFinite(skill?.tokens)
88
+ ? Math.max(0, skill.tokens)
89
+ : est(
90
+ `## Persona: ${skill?.displayName || skill?.id || "skill"}\n${skill?.body || ""}`,
91
+ ),
90
92
  }))
91
93
  .filter((row) => row.tokens > 0);
92
94
  return { sources, total: sources.reduce((sum, row) => sum + row.tokens, 0) };
93
95
  }
94
96
 
97
+ /** Normalize the content-free two-tier Skill cache snapshot. */
98
+ export function breakdownSkillCache(cache) {
99
+ const descriptors = cache?.descriptors || {};
100
+ const bodies = cache?.bodies || {};
101
+ const savings = cache?.savings || {};
102
+ return {
103
+ descriptors: {
104
+ resident: Number(descriptors.resident) || 0,
105
+ scans: Number(descriptors.scans) || 0,
106
+ cacheHits: Number(descriptors.cacheHits) || 0,
107
+ estimatedTokens: Number(descriptors.estimatedTokens) || 0,
108
+ },
109
+ bodies: {
110
+ resident: Number(bodies.resident) || 0,
111
+ cacheHits: Number(bodies.cacheHits) || 0,
112
+ cacheMisses: Number(bodies.cacheMisses) || 0,
113
+ entries: Array.isArray(bodies.entries)
114
+ ? bodies.entries.map((entry) => ({
115
+ id: String(entry?.id || "skill"),
116
+ source: String(entry?.source || "skill"),
117
+ estimatedTokens: Number(entry?.estimatedTokens) || 0,
118
+ loads: Number(entry?.loads) || 0,
119
+ cacheHits: Number(entry?.cacheHits) || 0,
120
+ loadedBecause: Array.isArray(entry?.loadedBecause)
121
+ ? entry.loadedBecause.map(String)
122
+ : [],
123
+ }))
124
+ : [],
125
+ },
126
+ savings: {
127
+ lazyFileBytes: Number(savings.lazyFileBytes) || 0,
128
+ estimatedTokensAvoided: Number(savings.estimatedTokensAvoided) || 0,
129
+ },
130
+ };
131
+ }
132
+
133
+ /** Actionable, content-free suggestions derived from the measured sources. */
134
+ export function buildContextOptimizations({
135
+ instructions = [],
136
+ mcpSchemas = [],
137
+ skillCache = null,
138
+ } = {}) {
139
+ const suggestions = [];
140
+ if (skillCache?.savings?.estimatedTokensAvoided > 0) {
141
+ suggestions.push({
142
+ kind: "skill_lazy_loading",
143
+ estimatedTokens: skillCache.savings.estimatedTokensAvoided,
144
+ message:
145
+ `${skillCache.descriptors.resident} Skill descriptors stayed discoverable while ` +
146
+ `${skillCache.savings.estimatedTokensAvoided} estimated body tokens remained lazy.`,
147
+ });
148
+ }
149
+ const largestMcp = [...(mcpSchemas || [])].sort(
150
+ (a, b) => (b.tokens || 0) - (a.tokens || 0),
151
+ )[0];
152
+ if (largestMcp?.tokens > 0) {
153
+ suggestions.push({
154
+ kind: "mcp_tool_search",
155
+ estimatedTokens: largestMcp.tokens,
156
+ source: largestMcp.tool || largestMcp.source,
157
+ message: `Consider Tool Search or a narrower MCP allow-list for ${largestMcp.tool || largestMcp.source}.`,
158
+ });
159
+ }
160
+ const largestInstruction = [...(instructions || [])].sort(
161
+ (a, b) => (b.tokens || 0) - (a.tokens || 0),
162
+ )[0];
163
+ if (largestInstruction?.tokens > 0) {
164
+ suggestions.push({
165
+ kind: "instruction_scope",
166
+ estimatedTokens: largestInstruction.tokens,
167
+ source: largestInstruction.source,
168
+ message: `Scope or split ${largestInstruction.source} if it is not needed for every turn.`,
169
+ });
170
+ }
171
+ return suggestions.slice(0, 5);
172
+ }
173
+
95
174
  // role bucket key → { label, kind } for the ranked source list.
96
175
  const MESSAGE_SOURCE_ROWS = [
97
176
  ["system", "system messages", "message"],
@@ -23,9 +23,9 @@ import {
23
23
  statSync,
24
24
  rmSync,
25
25
  } from "node:fs";
26
- import { execSync, spawnSync } from "node:child_process";
27
26
  import { join, basename } from "node:path";
28
27
  import { getHomeDir, getConfigPath } from "./paths.js";
28
+ import executionBroker from "./process-execution-broker/index.js";
29
29
  import {
30
30
  languageIdForFile,
31
31
  resolveServer,
@@ -59,8 +59,8 @@ export const _deps = {
59
59
  readFileSync,
60
60
  statSync,
61
61
  rmSync,
62
- execSync,
63
- spawnSync,
62
+ execFileSync: (...args) => executionBroker.execFileSync(...args),
63
+ spawnSync: (...args) => executionBroker.spawnSync(...args),
64
64
  now: () => Date.now(),
65
65
  };
66
66
 
@@ -549,10 +549,14 @@ async function worktreeSection(opts, deps) {
549
549
  try {
550
550
  const inRepo = (() => {
551
551
  try {
552
- deps.execSync("git rev-parse --is-inside-work-tree", {
552
+ deps.execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
553
553
  cwd,
554
554
  encoding: "utf-8",
555
555
  stdio: ["ignore", "pipe", "ignore"],
556
+ origin: "doctor:git-worktree",
557
+ policy: "allow",
558
+ scope: "diagnostics",
559
+ shell: false,
556
560
  });
557
561
  return true;
558
562
  } catch {
@@ -570,10 +574,14 @@ async function worktreeSection(opts, deps) {
570
574
  );
571
575
  } else {
572
576
  const out =
573
- deps.execSync("git worktree prune --dry-run -v", {
577
+ deps.execFileSync("git", ["worktree", "prune", "--dry-run", "-v"], {
574
578
  cwd,
575
579
  encoding: "utf-8",
576
580
  stdio: ["ignore", "pipe", "ignore"],
581
+ origin: "doctor:git-worktree",
582
+ policy: "allow",
583
+ scope: "diagnostics",
584
+ shell: false,
577
585
  }) || "";
578
586
  const prunable = out.split("\n").filter((l) => l.trim()).length;
579
587
  if (prunable > 0) {
@@ -1138,10 +1146,14 @@ export async function runCheckupFixes(sections, opts = {}) {
1138
1146
  detail: `removed ${removed} file(s)`,
1139
1147
  });
1140
1148
  } else if (fix.id === "git-worktree-prune") {
1141
- deps.execSync("git worktree prune", {
1149
+ deps.execFileSync("git", ["worktree", "prune"], {
1142
1150
  cwd: opts.cwd || process.cwd(),
1143
1151
  encoding: "utf-8",
1144
1152
  stdio: ["ignore", "pipe", "ignore"],
1153
+ origin: "doctor:git-worktree-fix",
1154
+ policy: "allow",
1155
+ scope: "diagnostics",
1156
+ shell: false,
1145
1157
  });
1146
1158
  results.push({
1147
1159
  id: fix.id,
@@ -11,7 +11,24 @@
11
11
 
12
12
  import fs from "fs";
13
13
  import path from "path";
14
- import { execFileSync } from "node:child_process";
14
+ import executionBroker from "../process-execution-broker/index.js";
15
+
16
+ export const _deps = {
17
+ execFileSync: (...args) => executionBroker.execFileSync(...args),
18
+ };
19
+
20
+ function runTaskCheck(dir, script, options = {}) {
21
+ return _deps.execFileSync(process.execPath, [script], {
22
+ cwd: dir,
23
+ timeout: 10000,
24
+ stdio: ["ignore", "pipe", "pipe"],
25
+ ...options,
26
+ origin: "eval:task-check",
27
+ policy: "allow",
28
+ scope: "eval",
29
+ shell: false,
30
+ });
31
+ }
15
32
 
16
33
  function read(dir, rel) {
17
34
  try {
@@ -97,11 +114,8 @@ export const BUILTIN_TASKS = [
97
114
  // Objective check: it must parse AND print OK. Re-run in a child so we
98
115
  // score the actual behavior, not a heuristic on the source.
99
116
  try {
100
- const out = execFileSync(process.execPath, ["bug.js"], {
101
- cwd: dir,
117
+ const out = runTaskCheck(dir, "bug.js", {
102
118
  encoding: "utf8",
103
- timeout: 10000,
104
- stdio: ["ignore", "pipe", "pipe"], // capture stderr, don't inherit
105
119
  });
106
120
  return out.trim() === "OK"
107
121
  ? { pass: true, detail: "node bug.js prints OK" }
@@ -186,11 +200,8 @@ export const BUILTIN_TASKS = [
186
200
  };
187
201
  }
188
202
  try {
189
- const out = execFileSync(process.execPath, ["run-checks.mjs"], {
190
- cwd: dir,
203
+ const out = runTaskCheck(dir, "run-checks.mjs", {
191
204
  encoding: "utf8",
192
- timeout: 10000,
193
- stdio: ["ignore", "pipe", "pipe"],
194
205
  });
195
206
  return out.includes("ALL OK")
196
207
  ? { pass: true, detail: "test suite passes" }
@@ -243,11 +254,8 @@ export const BUILTIN_TASKS = [
243
254
  }
244
255
  // Behavior must be preserved: run main.js and check the output.
245
256
  try {
246
- const out = execFileSync(process.execPath, ["main.js"], {
247
- cwd: dir,
257
+ const out = runTaskCheck(dir, "main.js", {
248
258
  encoding: "utf8",
249
- timeout: 10000,
250
- stdio: ["ignore", "pipe", "pipe"],
251
259
  });
252
260
  return out.trim() === "6"
253
261
  ? { pass: true, detail: "renamed + behavior preserved" }
@@ -290,12 +298,7 @@ export const BUILTIN_TASKS = [
290
298
  if (read(dir, "verify.mjs") == null) {
291
299
  return { pass: false, detail: "verify.mjs not created" };
292
300
  }
293
- const run = () =>
294
- execFileSync(process.execPath, ["verify.mjs"], {
295
- cwd: dir,
296
- timeout: 10000,
297
- stdio: ["ignore", "pipe", "pipe"],
298
- });
301
+ const run = () => runTaskCheck(dir, "verify.mjs");
299
302
  // 1) The verifier must PASS against the correct implementation.
300
303
  try {
301
304
  run();
@@ -383,11 +386,8 @@ export const BUILTIN_TASKS = [
383
386
  };
384
387
  }
385
388
  try {
386
- const out = execFileSync(process.execPath, ["app.mjs"], {
387
- cwd: dir,
389
+ const out = runTaskCheck(dir, "app.mjs", {
388
390
  encoding: "utf8",
389
- timeout: 10000,
390
- stdio: ["ignore", "pipe", "pipe"],
391
391
  }).trim();
392
392
  return out === "Hello, Ada!\nHello, Bob!!!"
393
393
  ? { pass: true, detail: "signature migrated + callers updated" }
@@ -525,11 +525,8 @@ export const BUILTIN_TASKS = [
525
525
  };
526
526
  }
527
527
  try {
528
- const out = execFileSync(process.execPath, ["build.mjs"], {
529
- cwd: dir,
528
+ const out = runTaskCheck(dir, "build.mjs", {
530
529
  encoding: "utf8",
531
- timeout: 10000,
532
- stdio: ["ignore", "pipe", "pipe"],
533
530
  });
534
531
  return out.includes("BUILD OK")
535
532
  ? { pass: true, detail: "build links + passes" }
@@ -620,11 +617,8 @@ export const BUILTIN_TASKS = [
620
617
  return { pass: false, detail: "app.mjs does not use the new toTitle" };
621
618
  }
622
619
  try {
623
- const out = execFileSync(process.execPath, ["run.mjs"], {
624
- cwd: dir,
620
+ const out = runTaskCheck(dir, "run.mjs", {
625
621
  encoding: "utf8",
626
- timeout: 10000,
627
- stdio: ["ignore", "pipe", "pipe"],
628
622
  });
629
623
  return out.trim() === "OK"
630
624
  ? { pass: true, detail: "adapted to new API + manifest bumped" }
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Process-level lifecycle owner for the durable Event Runtime.
3
+ *
4
+ * Producers only append records. This host owns the single non-overlapping
5
+ * drain loop, dispatches records to registered handlers, and exposes a
6
+ * stoppable lifecycle shared by short CLI commands and resident daemons.
7
+ */
8
+
9
+ import { EventEmitter } from "node:events";
10
+ import { EventRuntimeStore } from "./event-runtime-store.js";
11
+ import { EventRuntimeWorker } from "./event-runtime-worker.js";
12
+
13
+ function routeType(event) {
14
+ return String(
15
+ event?.runtime_type ||
16
+ event?.runtimeType ||
17
+ event?.event ||
18
+ event?.type ||
19
+ "*",
20
+ );
21
+ }
22
+
23
+ function routeOrigin(event) {
24
+ return String(event?.origin || "*");
25
+ }
26
+
27
+ function routeKey(queue, type = "*", origin = "*") {
28
+ return `${queue}:${String(type || "*")}:${String(origin || "*")}`;
29
+ }
30
+
31
+ export class EventRuntimeHost extends EventEmitter {
32
+ constructor({
33
+ store = new EventRuntimeStore(),
34
+ intervalMs = 1000,
35
+ worker = null,
36
+ setTimeoutFn = setTimeout,
37
+ clearTimeoutFn = clearTimeout,
38
+ } = {}) {
39
+ super();
40
+ this.store = store;
41
+ this.intervalMs = Math.max(1, Number(intervalMs) || 1000);
42
+ this.setTimeoutFn = setTimeoutFn;
43
+ this.clearTimeoutFn = clearTimeoutFn;
44
+ this.handlers = new Map();
45
+ this.running = false;
46
+ this.timer = null;
47
+ this.inFlight = null;
48
+ this.lastStats = null;
49
+ this.lastError = null;
50
+ this.worker =
51
+ worker ||
52
+ new EventRuntimeWorker({
53
+ store,
54
+ onInbox: (event, record) =>
55
+ this._dispatch("inbox", event, record),
56
+ onOutbox: (event, record) =>
57
+ this._dispatch("outbox", event, record),
58
+ });
59
+ }
60
+
61
+ registerHandler(
62
+ handler,
63
+ { queue = "inbox", type = "*", origin = "*" } = {},
64
+ ) {
65
+ if (typeof handler !== "function") {
66
+ throw new TypeError("Event Runtime handler must be a function");
67
+ }
68
+ if (queue !== "inbox" && queue !== "outbox") {
69
+ throw new Error(`unsupported event queue: ${queue}`);
70
+ }
71
+ const key = routeKey(queue, type, origin);
72
+ const handlers = this.handlers.get(key) || new Set();
73
+ handlers.add(handler);
74
+ this.handlers.set(key, handlers);
75
+ return () => {
76
+ handlers.delete(handler);
77
+ if (handlers.size === 0) this.handlers.delete(key);
78
+ };
79
+ }
80
+
81
+ async _dispatch(queue, event, record) {
82
+ const type = routeType(event);
83
+ const origin = routeOrigin(event);
84
+ const candidates = [
85
+ routeKey(queue, type, origin),
86
+ routeKey(queue, type, "*"),
87
+ routeKey(queue, "*", origin),
88
+ routeKey(queue, "*", "*"),
89
+ ];
90
+ const handlers = [];
91
+ const seen = new Set();
92
+ for (const key of candidates) {
93
+ for (const handler of this.handlers.get(key) || []) {
94
+ if (seen.has(handler)) continue;
95
+ seen.add(handler);
96
+ handlers.push(handler);
97
+ }
98
+ }
99
+ if (handlers.length === 0 && event?.requiresHandler === true) {
100
+ const error = new Error(
101
+ `No Event Runtime handler for ${queue}:${type}:${origin}`,
102
+ );
103
+ error.code = "CC_EVENT_RUNTIME_HANDLER_UNAVAILABLE";
104
+ throw error;
105
+ }
106
+ const results = await Promise.all(
107
+ handlers.map((handler) => handler(event, record)),
108
+ );
109
+ const delivery = {
110
+ queue,
111
+ type,
112
+ origin,
113
+ handlerCount: handlers.length,
114
+ results,
115
+ };
116
+ this.emit("delivered", delivery, event, record);
117
+ this.emit(`${queue}:${type}`, event, record, delivery);
118
+ return delivery;
119
+ }
120
+
121
+ async runOnce() {
122
+ if (this.inFlight) return this.inFlight;
123
+ this.inFlight = Promise.resolve()
124
+ .then(() => this.worker.runOnce())
125
+ .then((stats) => {
126
+ this.lastStats = stats;
127
+ this.lastError = null;
128
+ this.emit("tick", stats);
129
+ return stats;
130
+ })
131
+ .catch((error) => {
132
+ this.lastError = error;
133
+ this.emit("runtime-error", error);
134
+ throw error;
135
+ })
136
+ .finally(() => {
137
+ this.inFlight = null;
138
+ });
139
+ return this.inFlight;
140
+ }
141
+
142
+ _schedule() {
143
+ if (!this.running || this.timer != null) return;
144
+ this.timer = this.setTimeoutFn(async () => {
145
+ this.timer = null;
146
+ try {
147
+ await this.runOnce();
148
+ } catch {
149
+ // The durable records remain pending/retriable. The host keeps running
150
+ // so a transient lock or filesystem failure does not kill the daemon.
151
+ } finally {
152
+ this._schedule();
153
+ }
154
+ }, this.intervalMs);
155
+ this.timer?.unref?.();
156
+ }
157
+
158
+ start({ immediate = true } = {}) {
159
+ if (this.running) return false;
160
+ this.running = true;
161
+ if (immediate) {
162
+ void this.runOnce()
163
+ .catch(() => {})
164
+ .finally(() => this._schedule());
165
+ } else {
166
+ this._schedule();
167
+ }
168
+ this.emit("started");
169
+ return true;
170
+ }
171
+
172
+ async stop({ drain = true } = {}) {
173
+ const wasRunning = this.running;
174
+ this.running = false;
175
+ if (this.timer != null) {
176
+ this.clearTimeoutFn(this.timer);
177
+ this.timer = null;
178
+ }
179
+ if (drain && this.inFlight) {
180
+ try {
181
+ await this.inFlight;
182
+ } catch {
183
+ // Error already exposed through runtime-error/lastError.
184
+ }
185
+ }
186
+ if (wasRunning) this.emit("stopped");
187
+ return wasRunning;
188
+ }
189
+
190
+ status() {
191
+ return {
192
+ running: this.running,
193
+ inFlight: this.inFlight != null,
194
+ handlerRoutes: this.handlers.size,
195
+ lastStats: this.lastStats,
196
+ lastError: this.lastError?.message || null,
197
+ health: this.store.getHealthSnapshot(),
198
+ };
199
+ }
200
+ }
201
+
202
+ let defaultHost = null;
203
+
204
+ export function getDefaultEventRuntimeHost(options = {}) {
205
+ if (!defaultHost) defaultHost = new EventRuntimeHost(options);
206
+ return defaultHost;
207
+ }
208
+
209
+ export function startDefaultEventRuntimeHost(options = {}) {
210
+ if (process.env.CC_EVENT_RUNTIME_DURABLE !== "1" && options.force !== true) {
211
+ return null;
212
+ }
213
+ const host = getDefaultEventRuntimeHost(options);
214
+ host.start({ immediate: options.immediate !== false });
215
+ return host;
216
+ }
217
+
218
+ export async function stopDefaultEventRuntimeHost(options) {
219
+ return defaultHost ? defaultHost.stop(options) : false;
220
+ }
221
+
222
+ export function _resetDefaultEventRuntimeHostForTests() {
223
+ defaultHost = null;
224
+ }
225
+