chainlesschain 0.162.175 → 0.162.177

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 (311) hide show
  1. package/package.json +10 -10
  2. package/src/assets/web-panel/assets/{AIOps-DherW0Rh.js → AIOps-DT-VPWuN.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-CDGfqt2Y.js → ActionButton-DyOreOVN.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-BYhkzdgD.js → Analytics-DslNsKux.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-cEKk1cpb.js → AppLayout-BNJJAYME.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-_aXR3WWc.js → Artifacts-DoaAtEcY.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-CYAf-gY7.js → Audit-DPG3WdJ9.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-D4Q20phR.js → BackgroundAgents-C_JO6R5G.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-Cq0Tyk58.js → Backup-Cv3BooyX.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CPj_CdAv.js → BaseInput-D2uQXWu-.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-BQ-Qq0es.js → Chat-B4Vczyf3.js} +4 -4
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-DE6reP99.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-rke6l3yg.js → Checkbox-qTgk4VeP.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-DiacrIPq.js → Codegen-DlLWcIzj.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-Cx3BY-Up.js → Col-DNO73qp7.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-DfmWiQy8.js → Community-vRDNpc4j.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-DdQnpxy5.js → Compact-CEWtIXni.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-lzliOH_r.js → Compliance-KgYC9Fxi.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-CYx4Un5k.js → Cowork-zj5wvkpT.js} +2 -2
  20. package/src/assets/web-panel/assets/{Cron-BGDcPFlo.js → Cron-BLDoCozU.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-0_X5g2ri.js → Crosschain-BYnff4VY.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-C0PEf3Eu.js → DID-C75VFsVm.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-DULQjQ58.js → Dashboard-C4Gutni2.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-DGRHRbW6.js → Dropdown-B5dbO4Kx.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-ChX8XPwB.js → EmailListRenderer-BDipZtHJ.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-Dyq6IBNu.js → FamilyGuardDashboard-DmIzt8jj.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-DH1NfAL2.js → Federation-D9QOS-uW.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-BN1I_uNi.js → FormItemContext-B47HRwAm.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-Dq_2UYpe.js → GenericCardRenderer-3R4mXmgV.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-BAy1yvI2.js → Git-DrNXZf1C.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-Db6Q2iSy.js → Governance-BGd7JR98.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-0ub6yHcr.js → Inference-D-2he1ed.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DtLetM36.js → KnowledgeGraph-C0sHIbK5.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-Bcoy7CUd.js → Logs-DiBQO-jL.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-BfEMFAXf.js → MarkdownRenderer-DL_5eV2D.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-tt2rzwRR.js → Marketplace-VR59OdrC.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-BhOgX-MU.js → McpTools-DrPzwSd3.js} +3 -3
  38. package/src/assets/web-panel/assets/{Memory-BJUxeWBL.js → Memory-CBgKALwQ.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-BwUY2G9w.js → MobileBridge-pQ9Tn-Mn.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-BLRfHhqi.js → MobileProjects-mASB6jyj.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-B2WMboOm.js → Mtc-DTMgE7HC.js} +2 -2
  42. package/src/assets/web-panel/assets/{MtcAudit-8pNEXO63.js → MtcAudit-CwTnCtiL.js} +2 -2
  43. package/src/assets/web-panel/assets/{Multisig-C1wm5a_1.js → Multisig-ngm6WU8f.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-C1QpKF7g.js → NLProgramming-4YO4Qww9.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-CiQUcxFu.js → Notes-DP1k45mF.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-BblDPJ_x.js → NotificationSettings-r2H8yPKb.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-DRjYcPtb.js → OrderTableRenderer-CoM_Zw0J.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-Dp3VKB0X.js → Organization-DrO7jRWS.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Czx161m9.js → Overflow-Cnwu4i4t.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-ClFi6wOs.js → P2P-zi-cDwA_.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CRweW0lz.js → PdhVaultBrowser-DBEryDv7.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-BzcRoqTn.js → Permissions-lqXK2C3x.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-ChGTpNMd.js → PersonalDataHub-b63T3HJM.js} +2 -2
  54. package/src/assets/web-panel/assets/{Pipeline-BMOOpKWA.js → Pipeline-Kep5KAGW.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-D0AZHObH.js → Privacy-CHdvOAh1.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-yYFlZ6Ja.js → ProjectInit-BhKfdwe9.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-DJNVuMQs.js → ProjectSettings-Yavk9K8A.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-Br0rBWH1.js → Projects-CN8E_5Mq.js} +1 -1
  59. package/src/assets/web-panel/assets/Providers-Bfym6SQn.js +1 -0
  60. package/src/assets/web-panel/assets/{QrScannerModal-81NZOitV.js → QrScannerModal-CLSQcrlR.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-Dic2lCbJ.js → QuickAsk-VPa2WKQN.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Dh9iwViE.js → Recommend-CGXR8jVU.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-Bq9VYEFy.js → RemoteSession-C_20YfMB.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-CxFZ-NbJ.js → Reputation-awZh68UV.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-BVSLcaX2.js → Row-Ctb4oiYN.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-BbC-5DOH.js → RssFeed-D3sdjvUV.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-BfjZ1GCr.js → Search-C-zfA4kT.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-CVjhOV5r.js → Security-D9XlmHA3.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-D45u-Aqe.js → Services-C3UKnr41.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-WkGoK4he.js → Skeleton-BQxagZfF.js} +1 -1
  71. package/src/assets/web-panel/assets/Skills-q6eb6KPZ.js +1 -0
  72. package/src/assets/web-panel/assets/{Sla-Bf4QTF3E.js → Sla-DveENvek.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-DVpZdbMN.js → SpeechSettings-BFjXLNgF.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-DEEojoMS.js → SyncSettings-BpHgbaP9.js} +2 -2
  75. package/src/assets/web-panel/assets/Tasks-DvepRb8-.js +1 -0
  76. package/src/assets/web-panel/assets/{Templates-Bzl-9wY5.js → Templates-DEiaoyve.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-0khxUOB8.js → Tenant-ITg774nY.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-DWGYhAYU.js → Terminal-D3ZBcvnb.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-B0Y4LONc.js → TimelineRenderer-BsLU6JjU.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-DEE07SFh.js → Tokens-Cb5Pquc9.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-BM7xvA5z.js → Trigger-Dwfy-m9N.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-Dv3ijvvZ.js → Trust-CnlSRGG0.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-B1-enmMt.js → UkeySign-Y4TlvKVo.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-DYiIPByd.js → VideoEditing-BpKLtTTO.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-D-y374BQ.js → Wallet-LLBzIq8x.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-HBDjcUhi.js → WebAuthn-BeSRiusP.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-sKn4qTID.js → WorkflowEditor-BK_l1tXO.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-TVYhaBXj.js → chat-DYd-X7Wg.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-DMADxY9v.js → colors-C9uip71j.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-OftcHpO_.js → compact-item-JBrfjUP6.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-DW1zVUSN.js → createContext-D03fbuiq.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-B8LQ8leS.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-CaUathNp.js → hasIn-DLQOR6l-.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-Cmdv6Dev.js → index-5YN7F5bO.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-iDmgT2Dg.js → index-6GuLRpBQ.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-77kgkUgY.js → index-B0X76LjX.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-CM8W07sc.js → index-B46YcgsV.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-C9JoaYSs.js → index-BNCdRmWf.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CpDtN0dl.js → index-BYv-LWdy.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CZXYI5LU.js → index-Ba-Ps_AJ.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DWVZ3T0t.js → index-BcBZwlnG.js} +1 -1
  102. package/src/assets/web-panel/assets/{index--5UvwqH_.js → index-BdH9l8wl.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BBNg08cD.js → index-BfOs_bmg.js} +3 -3
  104. package/src/assets/web-panel/assets/index-Bh8BPtqR.js +1 -0
  105. package/src/assets/web-panel/assets/{index-s-EnkUCn.js → index-BnQgRjsm.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Lr0MO-GU.js → index-BpYKLrUT.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-B-19mFhn.js → index-BuNFCZCx.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CeCIYYG7.js → index-ByHO3SqZ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-hXq7QRA_.js → index-C2zmOsyD.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-8YelceUU.js → index-CChQBM1d.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-B52Ztt8Q.js → index-CChaISMb.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DKjqFpYa.js → index-CILVyK3b.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DAfT3EMd.js → index-CL0ixCxk.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-sm1sGIxW.js → index-CS63r8h3.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DHi634g9.js → index-CVZWiUE_.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BEzLLVYd.js → index-Ce0Bf1YF.js} +1 -1
  117. package/src/assets/web-panel/assets/index-CeVrHLzZ.js +1 -0
  118. package/src/assets/web-panel/assets/{index-pSVCBsG4.js → index-Ck17i0OD.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-GUKz4Pv9.js → index-Cpn19c9k.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CKNdnJRo.js → index-CqWk1FLG.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Bg-7FpaL.js → index-CwoDpKzW.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DYwwUKDg.js → index-D-1SqEpQ.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DZdT8nio.js → index-D4UY5Z60.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BvRw4Fna.js → index-D8KvuDz0.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-kdMl_0zL.js → index-DNMAAUVk.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CK-p7Hji.js → index-DYLZY4uh.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-DXcqvWBp.js → index-DaokIHt3.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BFVbDpqg.js → index-Q7mmL6w4.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BJ1PjRY3.js → index-SO6lgMg0.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BSp1Ofvx.js → index-iahNhZwm.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BupSWDcl.js → index-l08afIbV.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D63QVAiJ.js → index-rIxxfdTN.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-DdcKTlQR.js → initDefaultProps-CG9z1c6w.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-CL-hTBQj.js → motion-B1Ky7Zff.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-qYSAkxNG.js → move-DME8X2P1.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-ZwRSZtRP.js → mtc-parser-cuJYSWB7.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-Bld-8ftI.js → omit-UI_EE0uZ.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-DGHs-a9Z.js → pickAttrs-BIoE_Z_V.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-DRQPMyI5.js → placementArrow-B48-9HKN.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-C5MJG_Yo.js → responsiveObserve-D7x_GDgD.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-VZ-fpZCD.js → slide-DjzC5_7m.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-9ocfCyHk.js → statusUtils-C6BIymhh.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-B6QAwAN5.js → styleChecker-B4dGrdD9.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-Bq1twor3.js → useFlexGapSupport-Bken4aNE.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-DKZq96tz.js → useFs-BMlqECqv.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-D0RmRVXf.js → usePersonalDataHub-DLdrfmMa.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-D6kEj_tt.js → vnode-CKJQmxa0.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-2yfasoQf.js → zoom-CaZunuau.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/auth/npm-auth.js +30 -5
  151. package/src/commands/agenda.js +83 -5
  152. package/src/commands/agent.js +42 -4
  153. package/src/commands/background-session.js +11 -4
  154. package/src/commands/batch.js +79 -27
  155. package/src/commands/changelog.js +15 -4
  156. package/src/commands/config.js +70 -5
  157. package/src/commands/context.js +36 -2
  158. package/src/commands/eval.js +21 -6
  159. package/src/commands/hook.js +2 -2
  160. package/src/commands/hub.js +19 -1
  161. package/src/commands/loop.js +9 -2
  162. package/src/commands/memory.js +21 -6
  163. package/src/commands/permissions.js +57 -1
  164. package/src/commands/plugin.js +2 -0
  165. package/src/commands/review.js +23 -11
  166. package/src/commands/routine.js +31 -8
  167. package/src/commands/session.js +11 -3
  168. package/src/commands/skill.js +2 -0
  169. package/src/commands/statusline.js +3 -3
  170. package/src/commands/team.js +20 -7
  171. package/src/commands/update.js +65 -10
  172. package/src/data/changelog.json +293 -51
  173. package/src/gateways/terminal/PtyManager.js +8 -1
  174. package/src/gateways/ws/message-dispatcher.js +3 -0
  175. package/src/gateways/ws/session-protocol.js +26 -0
  176. package/src/gateways/ws/ws-agent-handler.js +107 -69
  177. package/src/gateways/ws/ws-server.js +74 -2
  178. package/src/harness/background-task-manager.js +18 -6
  179. package/src/harness/background-task-worker.js +11 -18
  180. package/src/harness/jsonl-session-store.js +13 -6
  181. package/src/harness/mcp-client.js +195 -2
  182. package/src/harness/worktree-isolator.js +18 -21
  183. package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +15 -0
  184. package/src/lib/agent-coordinator.js +4 -0
  185. package/src/lib/agent-core.js +5 -0
  186. package/src/lib/agent-ipc-bus.js +44 -5
  187. package/src/lib/agent-sandbox.js +16 -2
  188. package/src/lib/agent-schedule-store.js +55 -0
  189. package/src/lib/agent-team/team-worktree.js +28 -6
  190. package/src/lib/agent-tool-admission.js +104 -0
  191. package/src/lib/agent-worktree.js +20 -19
  192. package/src/lib/api-key-helper.js +10 -2
  193. package/src/lib/async-hook-supervisor.cjs +135 -15
  194. package/src/lib/async-hook-supervisor.js +47 -0
  195. package/src/lib/background-agent-supervisor.js +35 -12
  196. package/src/lib/background-task-manager.js +5 -1
  197. package/src/lib/changelog.js +76 -11
  198. package/src/lib/channels/channel-manager.js +6 -0
  199. package/src/lib/channels/telegram-channel.js +11 -1
  200. package/src/lib/channels/webhook-channel.js +15 -3
  201. package/src/lib/checkpoint-store.js +10 -2
  202. package/src/lib/chrome-connector.js +6 -2
  203. package/src/lib/claude-code-bridge.js +24 -8
  204. package/src/lib/cli-anything-bridge.js +82 -25
  205. package/src/lib/cloud/bundle.js +12 -2
  206. package/src/lib/code-review.js +32 -8
  207. package/src/lib/computer-use/control-backend.js +18 -3
  208. package/src/lib/context-breakdown.js +46 -0
  209. package/src/lib/context-source-ledger.js +43 -0
  210. package/src/lib/diff-review-follow-up.js +154 -0
  211. package/src/lib/doctor-checkup.js +18 -6
  212. package/src/lib/downloader.js +17 -3
  213. package/src/lib/ensure-utf8.js +11 -3
  214. package/src/lib/eval/tasks.js +25 -31
  215. package/src/lib/event-runtime-producer.js +58 -0
  216. package/src/lib/event-runtime-store.js +354 -0
  217. package/src/lib/event-runtime-worker.js +109 -0
  218. package/src/lib/execution-backend.js +72 -21
  219. package/src/lib/git-integration.js +19 -4
  220. package/src/lib/hook-manager.js +6 -15
  221. package/src/lib/hook-runner.cjs +88 -8
  222. package/src/lib/hook-runner.js +55 -0
  223. package/src/lib/hooks-v2-producers.js +15 -0
  224. package/src/lib/hooks-v2-runtime.js +70 -21
  225. package/src/lib/host-adb-bridge.js +129 -24
  226. package/src/lib/ide-context.js +128 -1
  227. package/src/lib/interaction-adapter.js +39 -0
  228. package/src/lib/json-schema-validate.js +190 -36
  229. package/src/lib/lan-pairing-preflight.js +13 -2
  230. package/src/lib/lsp/__tests__/benchmark.test.js +61 -0
  231. package/src/lib/lsp/__tests__/lsp-client.test.js +6 -1
  232. package/src/lib/lsp/__tests__/lsp-server-registry.test.js +18 -0
  233. package/src/lib/lsp/benchmark.js +20 -4
  234. package/src/lib/lsp/lsp-client.js +22 -3
  235. package/src/lib/lsp/lsp-manager.js +4 -0
  236. package/src/lib/lsp/lsp-server-registry.js +11 -2
  237. package/src/lib/mcp-oauth.js +8 -2
  238. package/src/lib/npm-invocation.js +29 -0
  239. package/src/lib/orchestrator.js +8 -2
  240. package/src/lib/packer/pack-update-applier.js +14 -2
  241. package/src/lib/packer/pkg-runner.js +13 -2
  242. package/src/lib/packer/precheck.js +33 -16
  243. package/src/lib/packer/smoke-runner.js +18 -5
  244. package/src/lib/packer/web-panel-builder.js +16 -2
  245. package/src/lib/paths.js +1 -1
  246. package/src/lib/permission-rules.cjs +5 -1
  247. package/src/lib/personal-data-hub-aichat-wizard.js +22 -6
  248. package/src/lib/personal-data-hub-wiring.js +27 -3
  249. package/src/lib/plan-mode.js +204 -11
  250. package/src/lib/plugin-monitor-supervisor.js +48 -6
  251. package/src/lib/plugin-runtime/bin.js +45 -0
  252. package/src/lib/plugin-runtime/hooks.js +14 -1
  253. package/src/lib/plugin-runtime/install.js +11 -3
  254. package/src/lib/plugin-runtime/lsp.js +3 -0
  255. package/src/lib/plugin-runtime/mcp.js +8 -1
  256. package/src/lib/plugin-runtime/monitors.js +4 -0
  257. package/src/lib/plugin-runtime/plugin-options.js +74 -7
  258. package/src/lib/plugin-runtime/signature.js +45 -0
  259. package/src/lib/pr-create.js +21 -8
  260. package/src/lib/pr-link-ledger.js +15 -3
  261. package/src/lib/process-execution-broker/credential-agent.js +23 -3
  262. package/src/lib/process-execution-broker/index.js +315 -38
  263. package/src/lib/process-execution-broker/patch-child-process.js +2 -3
  264. package/src/lib/process-manager.js +18 -3
  265. package/src/lib/publish-workspace.js +14 -6
  266. package/src/lib/repl-bang-memorize.js +10 -2
  267. package/src/lib/repl-goal.js +19 -2
  268. package/src/lib/secret-store.js +159 -0
  269. package/src/lib/service-manager.js +64 -29
  270. package/src/lib/settings-hook-events.cjs +74 -9
  271. package/src/lib/settings-hook-events.js +20 -0
  272. package/src/lib/settings-hooks.cjs +4 -0
  273. package/src/lib/side-effect-ledger.js +22 -0
  274. package/src/lib/skill-packs/generator.js +18 -9
  275. package/src/lib/skill-process-broker.js +71 -0
  276. package/src/lib/slash-commands.js +10 -2
  277. package/src/lib/status-line.cjs +28 -7
  278. package/src/lib/status-line.js +33 -0
  279. package/src/lib/sub-agent-context.js +5 -0
  280. package/src/lib/sub-agent-profiles.js +4 -0
  281. package/src/lib/turn-context.js +14 -8
  282. package/src/lib/unattended-action-policy.js +83 -0
  283. package/src/lib/update-notice.js +6 -2
  284. package/src/lib/with-file-lock.js +7 -0
  285. package/src/lib/ws-server.js +1 -0
  286. package/src/repl/agent-repl.js +60 -23
  287. package/src/repl/clipboard-copy.js +8 -2
  288. package/src/repl/pr-comments.js +30 -7
  289. package/src/runtime/agent-core.js +554 -118
  290. package/src/runtime/agent-runtime.js +1 -0
  291. package/src/runtime/coding-agent-contract-shared.cjs +52 -0
  292. package/src/runtime/coding-agent-policy.cjs +20 -0
  293. package/src/runtime/diagnostics.js +73 -8
  294. package/src/runtime/headless-runner.js +88 -10
  295. package/src/runtime/headless-stream.js +343 -21
  296. package/src/runtime/mcp-config.js +16 -1
  297. package/src/runtime/session-slash-commands.js +506 -0
  298. package/src/skills/video-editing/extractors/audio-extractor.js +13 -5
  299. package/src/skills/video-editing/extractors/video-extractor.js +13 -3
  300. package/src/skills/video-editing/media-process.js +20 -0
  301. package/src/skills/video-editing/render/audio-mix.js +13 -3
  302. package/src/skills/video-editing/render/ffmpeg-concat.js +7 -2
  303. package/src/skills/video-editing/render/ffmpeg-extract.js +7 -2
  304. package/src/workers/background-agent-worker.js +6 -2
  305. package/src/assets/web-panel/assets/ChatBubbleRenderer-Ci97vNTs.js +0 -1
  306. package/src/assets/web-panel/assets/Providers-zZRhNtSu.js +0 -1
  307. package/src/assets/web-panel/assets/Skills-D_jvQZcj.js +0 -1
  308. package/src/assets/web-panel/assets/Tasks-DFwxpLIk.js +0 -1
  309. package/src/assets/web-panel/assets/devWarning-CLOk6rdE.js +0 -1
  310. package/src/assets/web-panel/assets/index-CSgUfMTM.js +0 -1
  311. package/src/assets/web-panel/assets/index-DliSZvAP.js +0 -1
@@ -30,6 +30,110 @@ export const TOOL_TIER = Object.freeze({
30
30
  EXTENSION: "extension",
31
31
  });
32
32
 
33
+ const ADMISSION_BOOLEAN_FIELDS = Object.freeze([
34
+ "enforce",
35
+ "capabilityGranted",
36
+ "policyAllowed",
37
+ "permissionGranted",
38
+ "budgetOk",
39
+ "uiSupported",
40
+ ]);
41
+ const ADMISSION_TEXT_FIELDS = Object.freeze([
42
+ "source",
43
+ "version",
44
+ "scope",
45
+ "tier",
46
+ ]);
47
+ const ADMISSION_TEXT_PATTERN = /^[A-Za-z0-9@][A-Za-z0-9_.:/@+-]{0,127}$/;
48
+ const RESERVED_TOOL_NAMES = new Set(["__proto__", "prototype", "constructor"]);
49
+
50
+ /**
51
+ * Parse the IDE-to-CLI CC_TOOL_ADMISSION envelope. Only decision/provenance
52
+ * fields are accepted; arguments, prompts and credentials have no place in
53
+ * this contract. Invalid input throws so a host that opted into enforcement
54
+ * cannot silently fall back to an ungoverned session.
55
+ */
56
+ export function parseToolAdmissionConfig(input) {
57
+ if (input == null || input === "") return null;
58
+ let raw;
59
+ try {
60
+ raw = typeof input === "string" ? input : JSON.stringify(input);
61
+ } catch {
62
+ throw new Error("tool admission config is not valid JSON");
63
+ }
64
+ if (typeof raw !== "string") {
65
+ throw new Error("tool admission config must be an object");
66
+ }
67
+ if (Buffer.byteLength(raw, "utf8") > 32768) {
68
+ throw new Error("tool admission config exceeds 32 KiB");
69
+ }
70
+ let value;
71
+ try {
72
+ value = typeof input === "string" ? JSON.parse(input) : input;
73
+ } catch {
74
+ throw new Error("tool admission config is not valid JSON");
75
+ }
76
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
77
+ throw new Error("tool admission config must be an object");
78
+ }
79
+ if (value.enforce !== true) {
80
+ throw new Error("tool admission config must set enforce=true");
81
+ }
82
+
83
+ const sanitize = (entry, label) => {
84
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
85
+ throw new Error(`${label} must be an object`);
86
+ }
87
+ const out = {};
88
+ for (const field of ADMISSION_BOOLEAN_FIELDS) {
89
+ if (entry[field] !== undefined) {
90
+ if (typeof entry[field] !== "boolean") {
91
+ throw new Error(`${label}.${field} must be boolean`);
92
+ }
93
+ out[field] = entry[field];
94
+ }
95
+ }
96
+ for (const field of ADMISSION_TEXT_FIELDS) {
97
+ if (entry[field] !== undefined) {
98
+ if (
99
+ typeof entry[field] !== "string" ||
100
+ !ADMISSION_TEXT_PATTERN.test(entry[field])
101
+ ) {
102
+ throw new Error(`${label}.${field} must be a safe identifier`);
103
+ }
104
+ out[field] = entry[field];
105
+ }
106
+ }
107
+ return out;
108
+ };
109
+
110
+ const config = sanitize(value, "toolAdmission");
111
+ config.enforce = true;
112
+ if (value.tools !== undefined) {
113
+ if (
114
+ !value.tools ||
115
+ typeof value.tools !== "object" ||
116
+ Array.isArray(value.tools)
117
+ ) {
118
+ throw new Error("toolAdmission.tools must be an object");
119
+ }
120
+ const entries = Object.entries(value.tools);
121
+ if (entries.length > 256)
122
+ throw new Error("toolAdmission.tools exceeds 256 entries");
123
+ config.tools = {};
124
+ for (const [name, entry] of entries) {
125
+ if (
126
+ !/^[A-Za-z0-9_.:-]{1,160}$/.test(name) ||
127
+ RESERVED_TOOL_NAMES.has(name)
128
+ ) {
129
+ throw new Error(`invalid tool admission name: ${name}`);
130
+ }
131
+ config.tools[name] = sanitize(entry, `toolAdmission.tools.${name}`);
132
+ }
133
+ }
134
+ return config;
135
+ }
136
+
33
137
  /** Normalize a tier label; anything unrecognized → EXTENSION (fail-closed). */
34
138
  export function normalizeToolTier(value) {
35
139
  const s = String(value || "")
@@ -11,24 +11,28 @@
11
11
  * a merge hint. Removal failures fail-open to "kept".
12
12
  */
13
13
 
14
- import { execFileSync, execSync } from "child_process";
15
14
  import { existsSync, realpathSync } from "node:fs";
16
15
  import { resolve } from "node:path";
17
16
  import { createWorktree, removeWorktree } from "./worktree-isolator.js";
18
17
  import { findProjectRoot } from "./project-instructions.js";
18
+ import executionBroker from "./process-execution-broker/index.js";
19
19
 
20
20
  export const _deps = {
21
- execFileSync,
22
- execSync,
21
+ execFileSync: executionBroker.execFileSync.bind(executionBroker),
23
22
  createWorktree,
24
23
  removeWorktree,
25
24
  };
26
25
 
27
- function git(cmd, cwd, deps) {
28
- return (deps.execSync || execSync)(`git ${cmd}`, {
26
+ function git(args, cwd, deps, options = {}) {
27
+ const run = deps.execFileSync || _deps.execFileSync;
28
+ return run("git", args, {
29
29
  cwd,
30
30
  encoding: "utf8",
31
- stdio: ["ignore", "pipe", "ignore"],
31
+ stdio: options.stdio || ["ignore", "pipe", "ignore"],
32
+ origin: options.origin || "agent-worktree:query",
33
+ policy: "allow",
34
+ scope: "agent-worktree",
35
+ shell: false,
32
36
  });
33
37
  }
34
38
 
@@ -90,17 +94,17 @@ export function validateAgentWorktree(info, { deps = _deps } = {}) {
90
94
  }
91
95
 
92
96
  const repoTop = canonicalPath(
93
- git("rev-parse --show-toplevel", info.repoRoot, deps).trim(),
97
+ git(["rev-parse", "--show-toplevel"], info.repoRoot, deps).trim(),
94
98
  );
95
99
  const worktreeTop = canonicalPath(
96
- git("rev-parse --show-toplevel", worktreePath, deps).trim(),
100
+ git(["rev-parse", "--show-toplevel"], worktreePath, deps).trim(),
97
101
  );
98
102
  if (repoTop !== repo || worktreeTop !== worktree) {
99
103
  return { valid: false, reason: "worktree path identity mismatch" };
100
104
  }
101
105
 
102
106
  const registered = parseRegisteredWorktrees(
103
- git("worktree list --porcelain", info.repoRoot, deps),
107
+ git(["worktree", "list", "--porcelain"], info.repoRoot, deps),
104
108
  ).find((entry) => {
105
109
  try {
106
110
  return canonicalPath(entry.path) === worktree;
@@ -138,16 +142,13 @@ function removeVerifiedAgentWorktree(info, deps) {
138
142
  return null;
139
143
  }
140
144
 
141
- const run = deps.execFileSync || execFileSync;
142
- run("git", ["worktree", "remove", info.path], {
143
- cwd: info.repoRoot,
144
- encoding: "utf8",
145
+ git(["worktree", "remove", info.path], info.repoRoot, deps, {
146
+ origin: "agent-worktree:cleanup",
145
147
  stdio: ["ignore", "pipe", "pipe"],
146
148
  });
147
149
  try {
148
- run("git", ["branch", "-D", "--", info.branch], {
149
- cwd: info.repoRoot,
150
- encoding: "utf8",
150
+ git(["branch", "-D", "--", info.branch], info.repoRoot, deps, {
151
+ origin: "agent-worktree:cleanup",
151
152
  stdio: ["ignore", "pipe", "pipe"],
152
153
  });
153
154
  return null;
@@ -174,7 +175,7 @@ export function setupAgentWorktree({
174
175
  const suffix = Math.random().toString(36).slice(2, 6);
175
176
  const branch = `cc-agent-${stamp}-${suffix}`;
176
177
  const info = (deps.createWorktree || createWorktree)(repoRoot, branch);
177
- const baseSha = git("rev-parse HEAD", info.path, deps).trim();
178
+ const baseSha = git(["rev-parse", "HEAD"], info.path, deps).trim();
178
179
  return { ...info, repoRoot, baseSha };
179
180
  }
180
181
 
@@ -205,8 +206,8 @@ export function finishAgentWorktree(info, { deps = _deps } = {}) {
205
206
  let headSha = null;
206
207
  let readable = false;
207
208
  try {
208
- dirty = git("status --porcelain", info.path, deps).trim().length > 0;
209
- headSha = git("rev-parse HEAD", info.path, deps).trim();
209
+ dirty = git(["status", "--porcelain"], info.path, deps).trim().length > 0;
210
+ headSha = git(["rev-parse", "HEAD"], info.path, deps).trim();
210
211
  readable = true;
211
212
  } catch {
212
213
  /* unreadable → keep, never destroy work we cannot verify */
@@ -14,7 +14,7 @@
14
14
  * rule). Cached per process (5 min) so multi-call runs don't re-spawn it.
15
15
  */
16
16
 
17
- import { execSync } from "node:child_process";
17
+ import { executionBroker } from "./process-execution-broker/index.js";
18
18
 
19
19
  const TTL_MS = 5 * 60 * 1000;
20
20
  const _cache = new Map(); // helper command → { key, at }
@@ -31,7 +31,15 @@ export function resolveApiKeyFromHelper(helperCmd, opts = {}) {
31
31
  const now = opts.now || Date.now;
32
32
  const hit = _cache.get(cmd);
33
33
  if (hit && now() - hit.at < TTL_MS) return hit.key;
34
- const exec = opts.exec || execSync;
34
+ const exec =
35
+ opts.exec ||
36
+ ((command, options) =>
37
+ executionBroker.execSync(command, {
38
+ ...options,
39
+ origin: "credential:api-key-helper",
40
+ policy: "allow",
41
+ scope: "credential",
42
+ }));
35
43
  try {
36
44
  const out = exec(cmd, {
37
45
  encoding: "utf-8",
@@ -28,11 +28,10 @@
28
28
  * - tree-reaping of every child on stopAll() / process 'exit', so a session
29
29
  * never leaves an orphan hook process.
30
30
  *
31
- * `_deps.spawn` / `_deps.now` are injected so the whole supervisor is unit-
31
+ * Process runners and `_deps.now` are injected so the whole supervisor is unit-
32
32
  * testable with fake child processes (no real shell).
33
33
  */
34
34
 
35
- const cpDefault = require("node:child_process");
36
35
  const { tryParseDecision } = require("./hook-runner.cjs");
37
36
 
38
37
  const DEFAULT_TIMEOUT_MS = 60000;
@@ -52,8 +51,10 @@ class AsyncHookSupervisor {
52
51
  ? Number(opts.maxConcurrent)
53
52
  : DEFAULT_MAX_CONCURRENT;
54
53
  this._deps = {
55
- spawn: opts.spawn || cpDefault.spawn,
56
- spawnSync: opts.spawnSync || cpDefault.spawnSync,
54
+ run: opts.run || opts.spawn || null,
55
+ runSync: opts.runSync || opts.spawnSync || null,
56
+ killProcess: opts.killProcess || process.kill.bind(process),
57
+ platform: opts.platform || process.platform,
57
58
  now: opts.now || (() => Date.now()),
58
59
  };
59
60
  this._running = new Map(); // key -> { child, timer }
@@ -125,8 +126,12 @@ class AsyncHookSupervisor {
125
126
  return;
126
127
  }
127
128
  try {
128
- if (process.platform === "win32") {
129
- const r = this._deps.spawnSync(
129
+ if (this._deps.platform === "win32") {
130
+ // Snapshot before taskkill: a policy-restricted taskkill may terminate
131
+ // the shell and then fail on its descendants, orphaning them so a
132
+ // parent-PID query performed afterward can no longer find the tree.
133
+ const descendants = this._windowsDescendantPids(pid);
134
+ const r = this._deps.runSync(
130
135
  "taskkill",
131
136
  ["/PID", String(pid), "/T", "/F"],
132
137
  { windowsHide: true },
@@ -135,20 +140,27 @@ class AsyncHookSupervisor {
135
140
  // tree snapshot and termination. Repeat once so that race cannot
136
141
  // leave a short-lived hook grandchild orphaned.
137
142
  if (!r?.error && r?.status === 0) {
138
- this._deps.spawnSync(
139
- "taskkill",
140
- ["/PID", String(pid), "/T", "/F"],
141
- { windowsHide: true },
142
- );
143
+ this._deps.runSync("taskkill", ["/PID", String(pid), "/T", "/F"], {
144
+ windowsHide: true,
145
+ });
143
146
  }
144
- // If taskkill couldn't launch, fall back to a direct kill.
147
+ // Restricted runners can launch taskkill but still receive a non-zero
148
+ // access/policy result. Enumerate the tree while it is still alive,
149
+ // then terminate descendants leaf-first before killing the shell.
145
150
  if (r && (r.error || (r.status != null && r.status !== 0))) {
151
+ for (const descendant of descendants.reverse()) {
152
+ try {
153
+ this._deps.killProcess(descendant, "SIGKILL");
154
+ } catch {
155
+ /* already gone */
156
+ }
157
+ }
146
158
  child.kill(signal);
147
159
  }
148
160
  } else {
149
161
  // Negative pid → the whole process group (requires the detached spawn).
150
162
  try {
151
- process.kill(-pid, signal);
163
+ this._deps.killProcess(-pid, signal);
152
164
  } catch {
153
165
  child.kill(signal);
154
166
  }
@@ -162,6 +174,102 @@ class AsyncHookSupervisor {
162
174
  }
163
175
  }
164
176
 
177
+ /**
178
+ * Snapshot a Windows process tree for the taskkill-denied fallback. Query the
179
+ * process table once instead of issuing a quoted WMIC `where` expression for
180
+ * every level: Node/cmd quoting can silently turn that expression into an
181
+ * invalid WMIC alias query. PowerShell/CIM covers systems where WMIC has been
182
+ * removed. Traversal is bounded + cycle-safe so corrupt data cannot stall
183
+ * session teardown.
184
+ */
185
+ _windowsDescendantPids(rootPid) {
186
+ if (this._deps.platform !== "win32") return [];
187
+ const root = Number(rootPid);
188
+ if (!Number.isInteger(root) || root <= 0) return [];
189
+ let output = "";
190
+ let shouldTryCim = false;
191
+ try {
192
+ const result = this._deps.runSync(
193
+ "wmic",
194
+ [
195
+ "path",
196
+ "Win32_Process",
197
+ "get",
198
+ "ParentProcessId,ProcessId",
199
+ "/format:csv",
200
+ ],
201
+ {
202
+ encoding: "utf8",
203
+ windowsHide: true,
204
+ timeout: 3000,
205
+ },
206
+ );
207
+ if (!result?.error && result?.status === 0) {
208
+ output = String(result.stdout || "");
209
+ } else if (result?.error?.code === "ENOENT") {
210
+ shouldTryCim = true;
211
+ }
212
+ } catch {
213
+ shouldTryCim = true;
214
+ }
215
+ if (!output && shouldTryCim) {
216
+ try {
217
+ const result = this._deps.runSync(
218
+ "powershell.exe",
219
+ [
220
+ "-NoProfile",
221
+ "-NonInteractive",
222
+ "-Command",
223
+ "Get-CimInstance Win32_Process | ForEach-Object { '{0},{1}' -f $_.ParentProcessId,$_.ProcessId }",
224
+ ],
225
+ {
226
+ encoding: "utf8",
227
+ windowsHide: true,
228
+ timeout: 3000,
229
+ },
230
+ );
231
+ if (!result?.error && result?.status === 0) {
232
+ output = String(result.stdout || "");
233
+ }
234
+ } catch {
235
+ return [];
236
+ }
237
+ }
238
+
239
+ const childrenByParent = new Map();
240
+ for (const line of output.split(/\r?\n/)) {
241
+ const fields = line.trim().split(",");
242
+ if (fields.length < 2) continue;
243
+ const parentPid = Number(fields.at(-2));
244
+ const childPid = Number(fields.at(-1));
245
+ if (
246
+ !Number.isInteger(parentPid) ||
247
+ parentPid < 0 ||
248
+ !Number.isInteger(childPid) ||
249
+ childPid <= 0
250
+ ) {
251
+ continue;
252
+ }
253
+ const children = childrenByParent.get(parentPid) || [];
254
+ children.push(childPid);
255
+ childrenByParent.set(parentPid, children);
256
+ }
257
+
258
+ const seen = new Set([root]);
259
+ const pending = [root];
260
+ const descendants = [];
261
+ while (pending.length > 0 && seen.size <= 256) {
262
+ const parentPid = pending.shift();
263
+ for (const childPid of childrenByParent.get(parentPid) || []) {
264
+ if (seen.has(childPid)) continue;
265
+ seen.add(childPid);
266
+ descendants.push(childPid);
267
+ pending.push(childPid);
268
+ }
269
+ }
270
+ return descendants;
271
+ }
272
+
165
273
  /** Install the process-exit reaper exactly once, only when a child exists. */
166
274
  _installExitHook() {
167
275
  if (this._exitHookInstalled) return;
@@ -251,17 +359,29 @@ class AsyncHookSupervisor {
251
359
 
252
360
  let child;
253
361
  try {
254
- child = this._deps.spawn(hook.command, {
362
+ const spawnOptions = {
255
363
  cwd: opts.cwd || process.cwd(),
256
364
  shell: true,
257
365
  // POSIX: own process group so a timeout / stopAll can signal the whole
258
366
  // tree (shell + the real hook command), not just the shell wrapper.
259
367
  // No-op on Windows, where the tree is reaped via `taskkill /T` instead.
260
- detached: process.platform !== "win32",
368
+ detached: this._deps.platform !== "win32",
261
369
  env: {
262
370
  ...process.env,
263
371
  CLAUDE_HOOK_EVENT: hook.event || payload.hook_event_name || "",
264
372
  },
373
+ };
374
+ if (typeof this._deps.run !== "function") {
375
+ throw new Error("async hook process runner unavailable");
376
+ }
377
+ child = this._deps.run(hook.command, {
378
+ ...spawnOptions,
379
+ origin: hook.origin || "async-hook:command",
380
+ policy: "allow",
381
+ scope: "async-hook",
382
+ pluginId: hook.pluginId || null,
383
+ pluginVersion: hook.pluginVersion || null,
384
+ pluginSource: hook.pluginSource || null,
265
385
  });
266
386
  } catch (err) {
267
387
  this._record(hook, {
@@ -0,0 +1,47 @@
1
+ import supervisor from "./async-hook-supervisor.cjs";
2
+ import executionBroker from "./process-execution-broker/index.js";
3
+
4
+ const brokerRunner = executionBroker.spawn.bind(executionBroker);
5
+ const brokerSyncRunner = executionBroker.spawnSync.bind(executionBroker);
6
+
7
+ export const _processDeps = {
8
+ run: brokerRunner,
9
+ runSync: brokerSyncRunner,
10
+ };
11
+
12
+ function runAsyncHook(command, options = {}) {
13
+ return _processDeps.run(command, [], {
14
+ ...options,
15
+ origin: options.origin || "async-hook:command",
16
+ policy: "allow",
17
+ scope: "async-hook",
18
+ });
19
+ }
20
+
21
+ function runAsyncHookSupervisorCommand(command, args, options = {}) {
22
+ return _processDeps.runSync(command, args, {
23
+ ...options,
24
+ origin: options.origin || "async-hook:supervisor",
25
+ policy: "allow",
26
+ scope: "async-hook",
27
+ });
28
+ }
29
+
30
+ export class AsyncHookSupervisor extends supervisor.AsyncHookSupervisor {
31
+ constructor(options = {}) {
32
+ super({
33
+ ...options,
34
+ run: options.run || options.spawn || runAsyncHook,
35
+ runSync:
36
+ options.runSync || options.spawnSync || runAsyncHookSupervisorCommand,
37
+ });
38
+ }
39
+ }
40
+
41
+ export const { DEFAULT_TIMEOUT_MS, DEFAULT_MAX_CONCURRENT } = supervisor;
42
+
43
+ export default {
44
+ AsyncHookSupervisor,
45
+ DEFAULT_TIMEOUT_MS,
46
+ DEFAULT_MAX_CONCURRENT,
47
+ };
@@ -1,4 +1,3 @@
1
- import { spawn, spawnSync } from "node:child_process";
2
1
  import {
3
2
  closeSync,
4
3
  existsSync,
@@ -21,6 +20,7 @@ import {
21
20
  finishAgentWorktree,
22
21
  validateAgentWorktree,
23
22
  } from "./agent-worktree.js";
23
+ import executionBroker from "./process-execution-broker/index.js";
24
24
 
25
25
  export const DEFAULT_HEARTBEAT_INTERVAL_MS = 5000;
26
26
  export const DEFAULT_HEARTBEAT_STALE_MS = 120000;
@@ -42,6 +42,16 @@ export const PID_IDENTITY_TOLERANCE_MS = 60000;
42
42
  const START_TIME_CACHE_TTL_MS = 10000;
43
43
  const _startTimeCache = new Map();
44
44
 
45
+ function runSupervisorCommand(file, args, options, origin) {
46
+ return _deps.spawnSync(file, args, {
47
+ ...options,
48
+ origin,
49
+ policy: "allow",
50
+ scope: "background-agent",
51
+ shell: false,
52
+ });
53
+ }
54
+
45
55
  /** CIM_DATETIME (`20260711120000.500000+480`) → epoch ms, null when unparseable. */
46
56
  export function parseCimDateToMs(raw) {
47
57
  const m =
@@ -77,7 +87,7 @@ function defaultReadProcessStartTimeMs(pid) {
77
87
  // wmic first (fast, ~100-300ms); PowerShell CIM as fallback (wmic is
78
88
  // removed from recent Windows 11 builds).
79
89
  try {
80
- const r = spawnSync(
90
+ const r = runSupervisorCommand(
81
91
  "wmic",
82
92
  [
83
93
  "process",
@@ -88,6 +98,7 @@ function defaultReadProcessStartTimeMs(pid) {
88
98
  "/value",
89
99
  ],
90
100
  { windowsHide: true, encoding: "utf8", timeout: 5000 },
101
+ "background-agent:process-start-time",
91
102
  );
92
103
  if (!r.error && r.status === 0) {
93
104
  const m = /CreationDate=([^\r\n]+)/.exec(r.stdout || "");
@@ -101,10 +112,11 @@ function defaultReadProcessStartTimeMs(pid) {
101
112
  const script =
102
113
  `$p = Get-CimInstance Win32_Process -Filter 'ProcessId=${target}' -ErrorAction SilentlyContinue; ` +
103
114
  "if ($p -and $p.CreationDate) { [DateTimeOffset]::new($p.CreationDate).ToUnixTimeMilliseconds() }";
104
- const r = spawnSync(
115
+ const r = runSupervisorCommand(
105
116
  "powershell",
106
117
  ["-NoProfile", "-NonInteractive", "-Command", script],
107
118
  { windowsHide: true, encoding: "utf8", timeout: 10000 },
119
+ "background-agent:process-start-time",
108
120
  );
109
121
  if (!r.error && r.status === 0) {
110
122
  const n = Number(String(r.stdout || "").trim());
@@ -118,10 +130,15 @@ function defaultReadProcessStartTimeMs(pid) {
118
130
  // POSIX: `ps -o lstart=` gives an absolute start timestamp on Linux + macOS
119
131
  // (procps and BSD ps both support it; busybox ps does not → null → open).
120
132
  try {
121
- const r = spawnSync("ps", ["-o", "lstart=", "-p", String(target)], {
122
- encoding: "utf8",
123
- timeout: 5000,
124
- });
133
+ const r = runSupervisorCommand(
134
+ "ps",
135
+ ["-o", "lstart=", "-p", String(target)],
136
+ {
137
+ encoding: "utf8",
138
+ timeout: 5000,
139
+ },
140
+ "background-agent:process-start-time",
141
+ );
125
142
  if (!r.error && r.status === 0) {
126
143
  const t = Date.parse(String(r.stdout || "").trim());
127
144
  if (Number.isFinite(t) && t > 0) return t;
@@ -147,13 +164,14 @@ function defaultKillProcessTree(pid, signal = "SIGKILL") {
147
164
  if (target === process.pid) return false;
148
165
  try {
149
166
  if (process.platform === "win32") {
150
- const r = _deps.spawnSync(
167
+ const r = runSupervisorCommand(
151
168
  "taskkill",
152
169
  ["/PID", String(target), "/T", "/F"],
153
170
  {
154
171
  windowsHide: true,
155
172
  encoding: "utf8",
156
173
  },
174
+ "background-agent:process-tree-kill",
157
175
  );
158
176
  return !r.error && r.status === 0;
159
177
  }
@@ -170,8 +188,8 @@ function defaultKillProcessTree(pid, signal = "SIGKILL") {
170
188
  }
171
189
 
172
190
  export const _deps = {
173
- spawn,
174
- spawnSync,
191
+ spawn: executionBroker.spawn.bind(executionBroker),
192
+ spawnSync: executionBroker.spawnSync.bind(executionBroker),
175
193
  // Single POSIX signal seam: every kill this module issues goes through here
176
194
  // so tests can stub it — a bare `process.kill` is NOT interceptable and a
177
195
  // fixture recording a live pid would eat a REAL signal (the shard-2/4
@@ -741,7 +759,7 @@ export function resumeBackgroundAgent(id, prompt, options = {}) {
741
759
  }
742
760
 
743
761
  /**
744
- * Fail fast on an unusable cwd. Without this, spawn() surfaces a bad cwd as
762
+ * Fail fast on an unusable cwd. Without this, process launch surfaces a bad cwd as
745
763
  * an ASYNC 'error' event on the detached child — which nothing listened to
746
764
  * (uncaught exception with no context) — and the pre-written state/job files
747
765
  * stayed behind as a phantom "running" session. Deleted, file-replaced, and
@@ -826,6 +844,10 @@ export function launchBackgroundAgent({
826
844
  detached: true,
827
845
  stdio: "ignore",
828
846
  windowsHide: true,
847
+ origin: "background-agent:worker",
848
+ policy: "allow",
849
+ scope: "background-agent",
850
+ shell: false,
829
851
  });
830
852
  } catch (error) {
831
853
  rmSync(jobFile, { force: true });
@@ -922,13 +944,14 @@ export function stopBackgroundAgent(id) {
922
944
  return { ...lost, stopped: false };
923
945
  }
924
946
  if (process.platform === "win32") {
925
- const killed = _deps.spawnSync(
947
+ const killed = runSupervisorCommand(
926
948
  "taskkill",
927
949
  ["/PID", String(state.pid), "/T", "/F"],
928
950
  {
929
951
  windowsHide: true,
930
952
  encoding: "utf8",
931
953
  },
954
+ "background-agent:stop-tree",
932
955
  );
933
956
  if (killed.error || (killed.status !== 0 && isProcessAlive(state.pid))) {
934
957
  throw new Error(
@@ -1 +1,5 @@
1
- export { TaskStatus, BackgroundTaskManager } from "../harness/background-task-manager.js";
1
+ export {
2
+ _deps,
3
+ TaskStatus,
4
+ BackgroundTaskManager,
5
+ } from "../harness/background-task-manager.js";