chainlesschain 0.162.183 → 0.162.185

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 (205) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-BapS7lz4.js → AIOps-Co4ipAKx.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CXYdXEUI.js → ActionButton-BpsoDrDq.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-CKR5Lexn.js → Analytics-DMUqeBik.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-DATVUOXB.js → AppLayout-C6fD_dXr.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-vb_0ZlV1.js → Artifacts-DW0YlQlV.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-BI1l9GWt.js → Audit-DXtHiiFK.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-BFXbaUEf.js → BackgroundAgents-BgmF62U-.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-DEYBJJ6H.js → Backup-D8vhVLQC.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-COdzeO0M.js → BaseInput-D7nCtY2X.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-oSN6sfM5.js → Chat-CBZLEV2G.js} +6 -6
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CI_jT0ru.js → ChatBubbleRenderer-CtDb-2Qu.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-BezEa4tm.js → Checkbox-DJLkeD4M.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CNEL0Ife.js → Codegen-Cs6xO8Fd.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-Bf2Y2Bn1.js → Col-Dtx9wxfT.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-BfUlu4Hc.js → Community-DiigJg4n.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-BN4xWP9e.js → Compact-B67oMDDL.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-Bt6BKmEP.js → Compliance-BBDl-Jos.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-DKLp8YxO.js → Cowork-Ba98hSsa.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-o7Hhw6ky.js → Cron-DBWQZIz7.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-DaNXWJIw.js → Crosschain-OcrKzxAt.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-B-Qa2mha.js → DID-mW2eSbjM.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-CMX0Qnxw.js → Dashboard-BmsDPmKJ.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-BLuLyRu_.js → Dropdown-CVzmCyRx.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-CFBAeMij.js → EmailListRenderer-vVgqKzhh.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DWzXQ67V.js → FamilyGuardDashboard-CWY5t_ZJ.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-DB1QSLgr.js → Federation-ZGomhjxr.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-C-OKCToP.js → FormItemContext-DyaknbLr.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-DMJFtFZf.js → GenericCardRenderer-CmIvN1qr.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-DsGSujOV.js → Git-DQOJIYkG.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-B0iS9NEW.js → Governance-CMiY-EEp.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CH004H7c.js → Inference-D6IXuucf.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-Q9MTQ83c.js → KnowledgeGraph-6jkTL0hV.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-B_fyjZK9.js → Logs-N0jD-349.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-BL1IVXm-.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-BIStF9d1.js → Marketplace-WhYuhBxm.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-pGfal768.js → McpTools-DTeO28xy.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-xbNqpIqB.js → Memory-MSHzPSE-.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-B5EQGrIK.js → MobileBridge-Cyqs3J3W.js} +1 -1
  41. package/src/assets/web-panel/assets/MobileProjects-7IN2hWHg.js +1 -0
  42. package/src/assets/web-panel/assets/{Mtc-a_rmfxJH.js → Mtc-MWBnezNM.js} +5 -5
  43. package/src/assets/web-panel/assets/{MtcAudit-BmKuofUr.js → MtcAudit-DQu35Nu-.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-BQbJ-CAN.js → Multisig-CQS_M-DP.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-JtPJKX25.js → NLProgramming-WD16vQvY.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-ZFKznTSG.js → Notes-DqsiSwOq.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-B6aHRBBR.js → NotificationSettings-D3LoxO-P.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-DdcsOqEz.js → OrderTableRenderer-C5jPoTd6.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-BFDTAUgS.js → Organization-48aMBJso.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-0FoTfbWH.js → Overflow-j-a2XkhR.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-CWd90etw.js → P2P-BYpBNYnh.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-DtCGC-W-.js → PdhVaultBrowser-CYCsrrLg.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-CvQ7nr7T.js → Permissions-ZRXGXDFb.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-rdNPcR-Z.js → PersonalDataHub-6OWUPHyL.js} +5 -5
  55. package/src/assets/web-panel/assets/{Pipeline-CmrfiNOs.js → Pipeline-FcjlDK9E.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-D7ep1h_t.js → Privacy-vD_6Tldp.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-C0xKINHS.js → ProjectInit-B_CHOLXp.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-AOmZFp-F.js → ProjectSettings-rEiqQ2da.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-BWHSkXZP.js → Projects-Bg8obRAM.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-Cb7JCTPL.js → Providers-Dgtt97B4.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-BDMehcXC.js → QrScannerModal-DaGVylZO.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-BF6_1nvx.js → QuickAsk-DP2_2x3u.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-BHfT-A28.js → Recommend-D29yj4ki.js} +1 -1
  64. package/src/assets/web-panel/assets/RemoteSession-Ue2wnBLp.js +5 -0
  65. package/src/assets/web-panel/assets/{Reputation-CsWHLEcj.js → Reputation-CrxIHqeC.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-D6srnWhm.js → Row-BgSzJPCn.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-Xhr-KyVd.js → RssFeed-AwhYOrP9.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-vIbIJvwL.js → Search-D2shpEcm.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-Bzi5Aiko.js → Security-BtKzhTbT.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-BHtVX52P.js → Services-BY0DsUSm.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-C0R8B2jf.js → Skeleton-B3Sb0UI9.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-DtT6rWOX.js → Skills-Ne5w0bDs.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-0B37mxVU.js → Sla-C8VkaP4T.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-0V2jE1Bs.js → SpeechSettings-BQdIEYP9.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-CYedRzaj.js → SyncSettings-CwFafrUg.js} +2 -2
  76. package/src/assets/web-panel/assets/Tasks-yJuKoDlR.js +1 -0
  77. package/src/assets/web-panel/assets/{Templates-BKoHztGT.js → Templates-DYn9qCmx.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant--17nwVNZ.js → Tenant-DkKReHvn.js} +1 -1
  79. package/src/assets/web-panel/assets/Terminal-r6bd-owt.js +3 -0
  80. package/src/assets/web-panel/assets/{TimelineRenderer-C5jx4AE3.js → TimelineRenderer-Mq2juUC3.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-DYJKYa9t.js → Tokens-BnMw7MRi.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-DChpWiQ9.js → Trigger-CTzKp4o9.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-DfWG52EA.js → Trust-BBrSZm9U.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-CMugYcyA.js → UkeySign-D9fDvEMq.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-BOSmrHAd.js → VideoEditing-DUi5ve-0.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-D5g3k3Sa.js → Wallet-C8Fi1P8_.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-D-7u4Mkc.js → WebAuthn-s1LppYi2.js} +5 -5
  88. package/src/assets/web-panel/assets/{WorkflowEditor-CFzZMSUJ.js → WorkflowEditor-DJL2C4lj.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-VbR6l6mc.js → chat-D3F2ndOB.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-BSZn8EDS.js → colors-B7739-e3.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-y74obMEq.js → compact-item-CcJbFTF4.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-C326bjex.js → createContext-CuP_DEFS.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-Cj_36GHq.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-D_INJQT_.js → hasIn-6YEXfIik.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-DuIkfnTF.js → index-4h3lpWJ3.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DBkzrpiL.js → index-BIID4XcP.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-B7SrC-On.js → index-BOHUo3aM.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BnSfnSMP.js → index-BYYSLEjn.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-KF9Zmqln.js → index-Bh4hcNWW.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-C327pLbw.js → index-BhIKnQAW.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-E_v1ZCTP.js → index-Bru_kpZl.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Bfw2hf2s.js → index-BsdSnHQE.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-jYaogFE8.js → index-BxSqVMGh.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Dlxh9D8D.js → index-C3ZA_h1j.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DdyjrCAu.js → index-C3pctdCb.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-abmn_8Yz.js → index-CRuoRapN.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-qMA4GYdQ.js → index-CY0zd_jc.js} +1 -1
  108. package/src/assets/web-panel/assets/index-CezFrAmD.js +1 -0
  109. package/src/assets/web-panel/assets/index-Cxgguez6.js +1 -0
  110. package/src/assets/web-panel/assets/{index-Cr3uuz0C.js → index-CxradkS6.js} +19 -19
  111. package/src/assets/web-panel/assets/{index-DwHSZLXg.js → index-D0K_rFC1.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CMHqs3Jb.js → index-D0zdPyTD.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-Bnua8IX3.js → index-D3haorUt.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BY8-nCgs.js → index-D6Ij_2uw.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-FQBsuExX.js → index-DDRlBaDt.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-C-ZCaUJc.js → index-DGsE7MQz.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-BjcWKg1S.js → index-DHvxXXNA.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-GA80ir_u.js → index-DV11jpeO.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CsovTpx9.js → index-DXdnfDVK.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-nSn2-C4N.js → index-D_75jYWk.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BJi3UqBt.js → index-DjI9MkId.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-gINyI1rh.js → index-DlSvpNMf.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CfLJ42kv.js → index-Dox44j29.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-C2NyllnW.js → index-DpEKmjoa.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Iw0FfqUz.js → index-Dsy7_x4s.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-4eyH-eC2.js → index-Gxw09e9R.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-4PIeTM--.js → index-LfRlSmqe.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-IZAWt0H8.js → index-Nz-MUHD1.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DUU2606o.js → index-b9cuvFEv.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CzE53HiB.js → index-eR6H6NR7.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-9PIVuXqo.js → index-fWgUQZ9d.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DkH1JvEt.js → index-mfWQRSLn.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DNMxIsDg.js → index-yOZYSNmG.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-DI0Zaf8-.js → initDefaultProps-CJ1Bq2L3.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BZDKSy3Z.js → motion-rYJN_vzf.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-DsIW01Vp.js → move-DnDK2gTP.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-CohkDhsf.js → mtc-parser-CKnXy7ES.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-DpiN5rzg.js → omit-3nRc3hWT.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-qbuqni3y.js → pickAttrs-Ddjj3sLu.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-mBky6714.js → placementArrow-CbsbphQY.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-Bas3eQ2K.js → responsiveObserve-D9aZ4VDJ.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-CBx_SKoK.js → slide-D4pvdFj0.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-BlYguJSV.js → statusUtils-C2W-vY-S.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BCYQmRGv.js → styleChecker-Cbq5150d.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-Dp5dybLM.js → useFlexGapSupport-BA2B7R82.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-DHAMBgA2.js → useFs-CLrwg3xg.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-W6jsSw76.js → usePersonalDataHub-DQeAI5qs.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-BkI6aayc.js → vnode-8BDGy-YU.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-C_IMGueq.js → zoom-B2SzFprl.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/agenda.js +74 -1
  152. package/src/commands/background-session.js +11 -1
  153. package/src/commands/batch.js +160 -5
  154. package/src/commands/plugin.js +90 -27
  155. package/src/commands/session.js +31 -1
  156. package/src/commands/team.js +212 -6
  157. package/src/data/changelog.json +26 -0
  158. package/src/gateways/terminal/PtyManager.js +45 -15
  159. package/src/gateways/ws/ws-agent-handler.js +15 -1
  160. package/src/gateways/ws/ws-session-gateway.js +88 -0
  161. package/src/harness/background-task-command-runner.js +234 -0
  162. package/src/harness/background-task-manager.js +150 -20
  163. package/src/harness/background-task-worker.js +17 -11
  164. package/src/harness/jsonl-session-store.js +57 -6
  165. package/src/harness/mcp-client.js +65 -43
  166. package/src/lib/agent-batch.js +4 -1
  167. package/src/lib/agent-team/team-worktree.js +3 -0
  168. package/src/lib/async-hook-supervisor.cjs +82 -10
  169. package/src/lib/async-hook-supervisor.js +50 -4
  170. package/src/lib/background-agent-supervisor.js +46 -0
  171. package/src/lib/collaboration-run-store.js +362 -0
  172. package/src/lib/event-runtime-host.js +12 -10
  173. package/src/lib/hook-runner.cjs +105 -18
  174. package/src/lib/hook-runner.js +79 -6
  175. package/src/lib/hook-shell-command.cjs +148 -0
  176. package/src/lib/hooks-v2-runtime.js +280 -81
  177. package/src/lib/hooks-v2-workspace-context.js +258 -0
  178. package/src/lib/jsonl-session-store.js +2 -0
  179. package/src/lib/lsp/__tests__/lsp-client.test.js +15 -0
  180. package/src/lib/lsp/lsp-client.js +12 -1
  181. package/src/lib/plugin-monitor-supervisor.js +53 -16
  182. package/src/lib/plugin-runtime/bin.js +21 -5
  183. package/src/lib/plugin-runtime/install.js +249 -57
  184. package/src/lib/plugin-runtime/mcp.js +21 -2
  185. package/src/lib/plugin-runtime/monitors.js +19 -3
  186. package/src/lib/plugin-runtime/sandbox-policy.js +100 -4
  187. package/src/lib/process-execution-broker/index.js +1151 -44
  188. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +1557 -0
  189. package/src/lib/process-execution-broker/linux-generic-bwrap.js +1378 -0
  190. package/src/lib/process-execution-broker/platform-sandbox.js +586 -58
  191. package/src/lib/session-usage.js +202 -2
  192. package/src/lib/stream-retry.js +29 -0
  193. package/src/repl/agent-repl.js +40 -3
  194. package/src/runtime/agent-core.js +304 -42
  195. package/src/runtime/headless-runner.js +48 -1
  196. package/src/runtime/headless-stream.js +42 -2
  197. package/src/workers/background-agent-worker.js +5 -11
  198. package/src/assets/web-panel/assets/MarkdownRenderer-C0o4FtpD.js +0 -1
  199. package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +0 -1
  200. package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +0 -5
  201. package/src/assets/web-panel/assets/Tasks-D-R1x8vm.js +0 -1
  202. package/src/assets/web-panel/assets/Terminal-Dnkos7vW.js +0 -3
  203. package/src/assets/web-panel/assets/devWarning-D3Bho_6u.js +0 -1
  204. package/src/assets/web-panel/assets/index-5iAFwYx1.js +0 -1
  205. package/src/assets/web-panel/assets/index-BfnB7LPx.js +0 -1
@@ -26,35 +26,79 @@ import fs from "node:fs/promises";
26
26
  import path from "node:path";
27
27
  import broker from "./process-execution-broker/index.js";
28
28
  import hookEnvironment from "./hook-environment.cjs";
29
+ import hookShellCommand from "./hook-shell-command.cjs";
29
30
  import permissionRules from "./permission-rules.cjs";
30
31
  import { EventRuntimeStore } from "./event-runtime-store.js";
31
32
  import { getDefaultEventRuntimeHost } from "./event-runtime-host.js";
33
+ import {
34
+ currentHostHooksV2WorkspaceBinding,
35
+ currentHostHooksV2WorkspaceRoot,
36
+ registerHostHooksV2Workspace,
37
+ resolveRegisteredHostHooksV2Workspace,
38
+ runWithHostHooksV2Workspace,
39
+ } from "./hooks-v2-workspace-context.js";
32
40
 
33
41
  const { globToRegExp } = permissionRules;
34
42
  const { buildManagedHookEnvironment } = hookEnvironment;
43
+ const {
44
+ buildExplicitHookShellInvocation,
45
+ issueTrustedHookSandboxContract,
46
+ isPathInside,
47
+ requireTrustedHookRoot,
48
+ requiresExplicitHookShell,
49
+ sandboxBoundaryError,
50
+ } = hookShellCommand;
35
51
 
36
52
  const VALID_HOOK_EVENTS = new Set([
37
53
  "Setup",
38
54
  // Session
39
- "PreToolUse", "PostToolUse", "Notification", "Stop", "SubagentStart", "SubagentStop",
40
- "SessionResume", "SessionPause", "PostCompact", "StopFailure",
55
+ "PreToolUse",
56
+ "PostToolUse",
57
+ "Notification",
58
+ "Stop",
59
+ "SubagentStart",
60
+ "SubagentStop",
61
+ "SessionResume",
62
+ "SessionPause",
63
+ "PostCompact",
64
+ "StopFailure",
41
65
  // Auth
42
- "PreCommit", "PostCommit",
66
+ "PreCommit",
67
+ "PostCommit",
43
68
  // Skill
44
- "UserPromptSubmit", "UserPromptExpansion", "SessionStart", "SessionEnd",
69
+ "UserPromptSubmit",
70
+ "UserPromptExpansion",
71
+ "SessionStart",
72
+ "SessionEnd",
45
73
  // Model
46
- "PreCompact", "ModelSelection",
74
+ "PreCompact",
75
+ "ModelSelection",
47
76
  // Config
48
- "ConfigChange", "PermissionAllow", "PermissionDeny", "PermissionRequest", "PermissionDenied",
77
+ "ConfigChange",
78
+ "PermissionAllow",
79
+ "PermissionDeny",
80
+ "PermissionRequest",
81
+ "PermissionDenied",
49
82
  // Timeline
50
83
  "TimelineEntry",
51
84
  // MCP
52
- "McpRequest", "McpResponse", "MCPElicitation", "Elicitation", "ElicitationResult",
85
+ "McpRequest",
86
+ "McpResponse",
87
+ "MCPElicitation",
88
+ "Elicitation",
89
+ "ElicitationResult",
53
90
  // Task / workspace lifecycle
54
- "TaskCreated", "TaskCompleted", "InstructionsLoaded", "CwdChanged",
55
- "WorktreeCreate", "WorktreeRemove", "TeammateIdle",
91
+ "TaskCreated",
92
+ "TaskCompleted",
93
+ "InstructionsLoaded",
94
+ "CwdChanged",
95
+ "WorktreeCreate",
96
+ "WorktreeRemove",
97
+ "TeammateIdle",
56
98
  // Tool aggregate / failure / filesystem lifecycle
57
- "PostToolUseFailure", "PostToolBatch", "FileChanged",
99
+ "PostToolUseFailure",
100
+ "PostToolBatch",
101
+ "FileChanged",
58
102
  ]);
59
103
 
60
104
  const VALID_EXECUTOR_TYPES = new Set([
@@ -137,7 +181,9 @@ function strictestDecision(results) {
137
181
 
138
182
  function hostnameMatches(hostname, pattern) {
139
183
  const host = String(hostname || "").toLowerCase();
140
- const rule = String(pattern || "").trim().toLowerCase();
184
+ const rule = String(pattern || "")
185
+ .trim()
186
+ .toLowerCase();
141
187
  if (!host || !rule) return false;
142
188
  if (rule.startsWith("*.")) {
143
189
  const suffix = rule.slice(1);
@@ -240,12 +286,31 @@ export function resolveHookSandboxPolicy(hook = {}, managedPolicy = {}) {
240
286
  return resolved;
241
287
  }
242
288
 
289
+ function hooksRequireWorkspaceBinding(hooks, managedPolicy) {
290
+ return hooks.some((hook) => {
291
+ if (hook.type !== "command") return false;
292
+ try {
293
+ return requiresExplicitHookShell(
294
+ resolveHookSandboxPolicy(hook, managedPolicy),
295
+ );
296
+ } catch {
297
+ // Invalid policy is fail-closed during execution and must remain so after
298
+ // a crash instead of recovering without workspace authority.
299
+ return true;
300
+ }
301
+ });
302
+ }
303
+
243
304
  export function assertManagedHookPolicy(
244
305
  hook,
245
306
  context = {},
246
307
  policy = {},
247
308
  configDir = null,
309
+ workspaceRoot = null,
248
310
  ) {
311
+ // Retained for API compatibility and non-command policy growth, but never
312
+ // consulted as filesystem authority.
313
+ void context;
249
314
  if (!managedListAllows(hook.type, policy.allowedExecutors)) {
250
315
  throw managedPolicyError(
251
316
  `Hook executor is outside the managed allowlist: ${hook.type}`,
@@ -259,10 +324,7 @@ export function assertManagedHookPolicy(
259
324
  );
260
325
  }
261
326
  const executable = String(hook.command || "");
262
- const commandCandidates = new Set([
263
- executable,
264
- path.basename(executable),
265
- ]);
327
+ const commandCandidates = new Set([executable, path.basename(executable)]);
266
328
  if (
267
329
  Array.isArray(policy.commandAllowlist) &&
268
330
  ![...commandCandidates].some((value) =>
@@ -273,7 +335,11 @@ export function assertManagedHookPolicy(
273
335
  `Hook command is outside the managed allowlist: ${executable}`,
274
336
  );
275
337
  }
276
- const cwd = hook.cwd || context.cwd || configDir || process.cwd();
338
+ // The event context is payload, not workspace authority. Keep this
339
+ // selection identical to _execCommand so a forged context.cwd cannot make
340
+ // the managed-root check approve a different directory than the one the
341
+ // Broker will actually execute in.
342
+ const cwd = hook.cwd || configDir || workspaceRoot || process.cwd();
277
343
  if (!isInsideManagedRoot(cwd, policy.workspaceRoots)) {
278
344
  throw managedPolicyError(
279
345
  `Hook working directory is outside managed workspace roots: ${cwd}`,
@@ -315,7 +381,11 @@ export function fileChangedHookMatches(hook, context = {}) {
315
381
  hook?.globs ?? hook?.paths ?? hook?.glob ?? hook?.if ?? null;
316
382
  if (configured == null) return true;
317
383
  const patterns = (Array.isArray(configured) ? configured : [configured])
318
- .map((value) => String(value || "").trim().replace(/\\/g, "/"))
384
+ .map((value) =>
385
+ String(value || "")
386
+ .trim()
387
+ .replace(/\\/g, "/"),
388
+ )
319
389
  .filter(Boolean);
320
390
  if (patterns.length === 0) return true;
321
391
 
@@ -392,6 +462,17 @@ class HooksV2Runtime extends EventEmitter {
392
462
  constructor(configDir, options = {}) {
393
463
  super();
394
464
  this.configDir = configDir;
465
+ // Both values are host constructor inputs. Hook definitions may select a
466
+ // cwd inside this root, but can never replace the writable root used to
467
+ // issue a Linux one-shot execution contract.
468
+ const configuredWorkspaceRoot = options.workspaceRoot || configDir || null;
469
+ this.workspaceBinding =
470
+ typeof configuredWorkspaceRoot === "string" &&
471
+ path.isAbsolute(configuredWorkspaceRoot)
472
+ ? registerHostHooksV2Workspace(configuredWorkspaceRoot)
473
+ : null;
474
+ this.workspaceRoot =
475
+ this.workspaceBinding?.workspaceRoot || configuredWorkspaceRoot;
395
476
  this.durableStore = options.durableStore || null;
396
477
  this.durableOwner =
397
478
  options.durableOwner ||
@@ -457,14 +538,18 @@ class HooksV2Runtime extends EventEmitter {
457
538
  const config = JSON.parse(content);
458
539
  this.hooks.clear();
459
540
 
460
- const hookDefs = Array.isArray(config) ? config : (config.hooks || []);
541
+ const hookDefs = Array.isArray(config) ? config : config.hooks || [];
461
542
  for (const def of hookDefs) {
462
543
  if (!VALID_HOOK_EVENTS.has(def.event)) {
463
- process.emitWarning(`[hooks-v2] Unknown event type: ${def.event}, skipping`);
544
+ process.emitWarning(
545
+ `[hooks-v2] Unknown event type: ${def.event}, skipping`,
546
+ );
464
547
  continue;
465
548
  }
466
549
  if (!VALID_EXECUTOR_TYPES.has(def.type)) {
467
- process.emitWarning(`[hooks-v2] Unknown executor type: ${def.type} for ${def.event}, skipping`);
550
+ process.emitWarning(
551
+ `[hooks-v2] Unknown executor type: ${def.type} for ${def.event}, skipping`,
552
+ );
468
553
  continue;
469
554
  }
470
555
  const id = def.id || crypto.randomUUID();
@@ -472,7 +557,10 @@ class HooksV2Runtime extends EventEmitter {
472
557
  this.hooks.get(def.event).push({ id, ...def });
473
558
  }
474
559
  this._loaded = true;
475
- this.emit("loaded", { count: hookDefs.length, events: Array.from(this.hooks.keys()) });
560
+ this.emit("loaded", {
561
+ count: hookDefs.length,
562
+ events: Array.from(this.hooks.keys()),
563
+ });
476
564
  } catch (e) {
477
565
  if (e.code !== "ENOENT") {
478
566
  this.emit("load:error", e);
@@ -484,8 +572,10 @@ class HooksV2Runtime extends EventEmitter {
484
572
  * Register a hook programmatically
485
573
  */
486
574
  registerHook(def) {
487
- if (!VALID_HOOK_EVENTS.has(def.event)) throw new Error(`Invalid event: ${def.event}`);
488
- if (!VALID_EXECUTOR_TYPES.has(def.type)) throw new Error(`Invalid executor type: ${def.type}`);
575
+ if (!VALID_HOOK_EVENTS.has(def.event))
576
+ throw new Error(`Invalid event: ${def.event}`);
577
+ if (!VALID_EXECUTOR_TYPES.has(def.type))
578
+ throw new Error(`Invalid executor type: ${def.type}`);
489
579
  const contract = HOOK_EVENT_CONTRACTS[def.event];
490
580
  if (!contract.allowedExecutors.includes(def.type)) {
491
581
  throw new Error(
@@ -501,7 +591,7 @@ class HooksV2Runtime extends EventEmitter {
501
591
 
502
592
  unregisterHook(id) {
503
593
  for (const [event, hooks] of this.hooks.entries()) {
504
- const idx = hooks.findIndex(h => h.id === id);
594
+ const idx = hooks.findIndex((h) => h.id === id);
505
595
  if (idx >= 0) {
506
596
  hooks.splice(idx, 1);
507
597
  return true;
@@ -534,22 +624,34 @@ class HooksV2Runtime extends EventEmitter {
534
624
  (max, hook) => Math.max(max, Number(hook?.timeoutMs) || 30000),
535
625
  0,
536
626
  );
627
+ const durableWorkspaceBinding =
628
+ this.workspaceBinding || currentHostHooksV2WorkspaceBinding();
629
+ const durableWorkspaceBindingRequired = hooksRequireWorkspaceBinding(
630
+ hooks,
631
+ this.managedPolicy,
632
+ );
537
633
  const durableRecord =
538
634
  this.durableStore && options.skipDurable !== true
539
- ? this.durableStore.enqueueInbox(
540
- {
541
- runtime_type: "hooks.v2",
542
- requiresHandler: true,
543
- event: eventName,
544
- context,
545
- },
546
- {
547
- id: context.event_id || context.eventId || null,
548
- claimOwner: this.durableOwner,
549
- leaseMs: longestHookTimeout + this.durableRecoveryBufferMs,
550
- },
551
- )
552
- : null;
635
+ ? this.durableStore.enqueueInbox(
636
+ {
637
+ runtime_type: "hooks.v2",
638
+ requiresHandler: true,
639
+ event: eventName,
640
+ context,
641
+ },
642
+ {
643
+ id: context.event_id || context.eventId || null,
644
+ metadata: {
645
+ hooksV2WorkspaceBindingId:
646
+ durableWorkspaceBinding?.bindingId || null,
647
+ hooksV2WorkspaceBindingRequired:
648
+ durableWorkspaceBindingRequired,
649
+ },
650
+ claimOwner: this.durableOwner,
651
+ leaseMs: longestHookTimeout + this.durableRecoveryBufferMs,
652
+ },
653
+ )
654
+ : null;
553
655
  if (durableRecord?.duplicate) {
554
656
  if (durableRecord.status === "done" && durableRecord.result) {
555
657
  return { ...durableRecord.result, duplicate: true };
@@ -577,7 +679,13 @@ class HooksV2Runtime extends EventEmitter {
577
679
  const runOne = async (hook) => {
578
680
  const execId = crypto.randomUUID();
579
681
  const start = Date.now();
580
- const record = { execId, hookId: hook.id, event: eventName, type: hook.type, startedAt: new Date() };
682
+ const record = {
683
+ execId,
684
+ hookId: hook.id,
685
+ event: eventName,
686
+ type: hook.type,
687
+ startedAt: new Date(),
688
+ };
581
689
 
582
690
  try {
583
691
  assertManagedHookPolicy(
@@ -585,6 +693,7 @@ class HooksV2Runtime extends EventEmitter {
585
693
  context,
586
694
  this.managedPolicy,
587
695
  this.configDir,
696
+ this.workspaceRoot || currentHostHooksV2WorkspaceRoot(),
588
697
  );
589
698
  let result;
590
699
  switch (hook.type) {
@@ -629,9 +738,10 @@ class HooksV2Runtime extends EventEmitter {
629
738
  this.executionLog.push(record);
630
739
  return record;
631
740
  };
632
- const results = options.parallel === false
633
- ? []
634
- : await Promise.all(uniqueHooks.map(runOne));
741
+ const results =
742
+ options.parallel === false
743
+ ? []
744
+ : await Promise.all(uniqueHooks.map(runOne));
635
745
  if (options.parallel === false) {
636
746
  for (const hook of uniqueHooks) results.push(await runOne(hook));
637
747
  }
@@ -643,8 +753,7 @@ class HooksV2Runtime extends EventEmitter {
643
753
  const blocked = decision === "block";
644
754
  const blockingResult = blocking[0]?.result || null;
645
755
  const outcome = {
646
- success:
647
- !blocked && results.every((record) => record.status !== "error"),
756
+ success: !blocked && results.every((record) => record.status !== "error"),
648
757
  results,
649
758
  blocked,
650
759
  requiresApproval: decision === "ask",
@@ -689,24 +798,74 @@ class HooksV2Runtime extends EventEmitter {
689
798
  throw new Error("command hook requires a command");
690
799
  }
691
800
  const budget = hookBudget(hook);
692
- const sandboxPolicy = resolveHookSandboxPolicy(
693
- hook,
694
- this.managedPolicy,
695
- );
801
+ const sandboxPolicy = resolveHookSandboxPolicy(hook, this.managedPolicy);
802
+ const requiresContract = requiresExplicitHookShell(sandboxPolicy);
803
+ const trustedRootSource =
804
+ this.workspaceRoot || currentHostHooksV2WorkspaceRoot();
805
+ const trustedRoot = requiresContract
806
+ ? requireTrustedHookRoot(
807
+ trustedRootSource,
808
+ "Hooks v2 trusted workspace root",
809
+ )
810
+ : null;
811
+ const commandCwd =
812
+ hook.cwd || this.configDir || trustedRoot || process.cwd();
813
+ if (requiresContract) {
814
+ requireTrustedHookRoot(commandCwd, "Hooks v2 hook working directory");
815
+ if (!isPathInside(trustedRoot, commandCwd)) {
816
+ throw sandboxBoundaryError(
817
+ "Hooks v2 hook working directory escapes the trusted workspace root",
818
+ );
819
+ }
820
+ }
821
+ const invocation =
822
+ requiresContract && hook.shell === true
823
+ ? buildExplicitHookShellInvocation(hook.command, {
824
+ args: hook.args || [],
825
+ })
826
+ : {
827
+ file: hook.command,
828
+ argv: hook.args || [],
829
+ };
830
+ const commandOptions = {
831
+ cwd: commandCwd,
832
+ env: buildHookEnvironment(hook, this.managedPolicy),
833
+ stdio: ["pipe", "pipe", "pipe"],
834
+ timeout: budget.timeoutMs,
835
+ shell: requiresContract ? false : hook.shell === true,
836
+ origin: "hook",
837
+ scope: "hook",
838
+ policy: "allow",
839
+ hookName: hook.id,
840
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
841
+ };
842
+ const sandboxExecutionContract = requiresContract
843
+ ? issueTrustedHookSandboxContract({
844
+ issuer:
845
+ this.executionBroker.issueLinuxWorkspaceSandboxExecutionContract,
846
+ receiver: this.executionBroker,
847
+ file: invocation.file,
848
+ args: invocation.argv,
849
+ options: commandOptions,
850
+ trustedRoot,
851
+ label: "trusted Hooks v2 sandbox contract issuance failed",
852
+ })
853
+ : null;
854
+ if (
855
+ process.platform === "linux" &&
856
+ requiresContract &&
857
+ !sandboxExecutionContract
858
+ ) {
859
+ throw sandboxBoundaryError(
860
+ "trusted Linux Hooks v2 sandbox contract could not be issued",
861
+ );
862
+ }
696
863
  const child = await this.executionBroker.spawn(
697
- hook.command,
698
- hook.args || [],
864
+ invocation.file,
865
+ invocation.argv,
699
866
  {
700
- cwd: hook.cwd || this.configDir || process.cwd(),
701
- env: buildHookEnvironment(hook, this.managedPolicy),
702
- stdio: ["pipe", "pipe", "pipe"],
703
- timeout: budget.timeoutMs,
704
- shell: hook.shell === true,
705
- origin: "hook",
706
- scope: "hook",
707
- policy: "allow",
708
- hookName: hook.id,
709
- ...(sandboxPolicy ? { sandboxPolicy } : {}),
867
+ ...commandOptions,
868
+ ...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
710
869
  },
711
870
  );
712
871
  const payload = JSON.stringify({
@@ -716,14 +875,19 @@ class HooksV2Runtime extends EventEmitter {
716
875
  });
717
876
  child.stdin?.end(payload);
718
877
  return new Promise((resolve, reject) => {
719
- let stdout = "", stderr = "";
720
- child.stdout?.on("data", d => stdout += d);
721
- child.stderr?.on("data", d => stderr += d);
878
+ let stdout = "",
879
+ stderr = "";
880
+ child.stdout?.on("data", (d) => (stdout += d));
881
+ child.stderr?.on("data", (d) => (stderr += d));
722
882
  child.on("error", reject);
723
883
  child.on("exit", (code) => {
724
884
  if (code === 0) {
725
885
  let parsed = {};
726
- try { parsed = JSON.parse(stdout); } catch { parsed = { raw: stdout }; }
886
+ try {
887
+ parsed = JSON.parse(stdout);
888
+ } catch {
889
+ parsed = { raw: stdout };
890
+ }
727
891
  resolve({ ...parsed, exitCode: code, stderr });
728
892
  } else {
729
893
  reject(new Error(`Hook command failed with exit ${code}: ${stderr}`));
@@ -763,7 +927,10 @@ class HooksV2Runtime extends EventEmitter {
763
927
  const res = await this.fetchImpl(target, {
764
928
  method,
765
929
  headers,
766
- body: method !== "GET" ? JSON.stringify({ event: hook.event, context }) : undefined,
930
+ body:
931
+ method !== "GET"
932
+ ? JSON.stringify({ event: hook.event, context })
933
+ : undefined,
767
934
  signal: controller.signal,
768
935
  });
769
936
  clearTimeout(timer);
@@ -782,10 +949,7 @@ class HooksV2Runtime extends EventEmitter {
782
949
  throw new Error("prompt hook executor is not configured");
783
950
  }
784
951
  const budget = hookBudget(hook);
785
- const sandboxPolicy = resolveHookSandboxPolicy(
786
- hook,
787
- this.managedPolicy,
788
- );
952
+ const sandboxPolicy = resolveHookSandboxPolicy(hook, this.managedPolicy);
789
953
  return executeWithHookTimeout("prompt", budget, (signal) =>
790
954
  executor({
791
955
  hook,
@@ -805,10 +969,7 @@ class HooksV2Runtime extends EventEmitter {
805
969
  throw new Error("agent hook executor is not configured");
806
970
  }
807
971
  const budget = hookBudget(hook);
808
- const sandboxPolicy = resolveHookSandboxPolicy(
809
- hook,
810
- this.managedPolicy,
811
- );
972
+ const sandboxPolicy = resolveHookSandboxPolicy(hook, this.managedPolicy);
812
973
  return executeWithHookTimeout("agent", budget, (signal) =>
813
974
  executor({
814
975
  hook,
@@ -858,10 +1019,7 @@ class HooksV2Runtime extends EventEmitter {
858
1019
  }
859
1020
  }
860
1021
  const budget = hookBudget(hook);
861
- const sandboxPolicy = resolveHookSandboxPolicy(
862
- hook,
863
- this.managedPolicy,
864
- );
1022
+ const sandboxPolicy = resolveHookSandboxPolicy(hook, this.managedPolicy);
865
1023
  return executeWithHookTimeout("mcp_tool", budget, (signal) =>
866
1024
  executor({
867
1025
  server: hook.server,
@@ -889,7 +1047,12 @@ class HooksV2Runtime extends EventEmitter {
889
1047
  getHookRegistry() {
890
1048
  const registry = {};
891
1049
  for (const [event, hooks] of this.hooks.entries()) {
892
- registry[event] = hooks.map(h => ({ id: h.id, type: h.type, description: h.description, blocking: h.blocking }));
1050
+ registry[event] = hooks.map((h) => ({
1051
+ id: h.id,
1052
+ type: h.type,
1053
+ description: h.description,
1054
+ blocking: h.blocking,
1055
+ }));
893
1056
  }
894
1057
  return registry;
895
1058
  }
@@ -912,12 +1075,48 @@ const hooksRuntime = new HooksV2Runtime(undefined, {
912
1075
  ? new EventRuntimeStore()
913
1076
  : null),
914
1077
  });
915
- defaultEventRuntimeHost?.registerHandler(
916
- (event) =>
917
- hooksRuntime.executeHooks(event.event, event.context || {}, {
1078
+ broker._setHooksEventSink(hooksRuntime);
1079
+
1080
+ export async function executeRecoveredHooksV2Event(
1081
+ runtime,
1082
+ event,
1083
+ record = {},
1084
+ ) {
1085
+ const bindingId = record?.metadata?.hooksV2WorkspaceBindingId || null;
1086
+ const bindingRequired =
1087
+ record?.metadata?.hooksV2WorkspaceBindingRequired === true ||
1088
+ hooksRequireWorkspaceBinding(
1089
+ runtime?.hooks?.get?.(event?.event) || [],
1090
+ runtime?.managedPolicy || {},
1091
+ );
1092
+ if (!bindingId) {
1093
+ if (bindingRequired) {
1094
+ throw sandboxBoundaryError(
1095
+ "durable Hooks v2 recovery requires a trusted host workspace binding",
1096
+ );
1097
+ }
1098
+ return runtime.executeHooks(event.event, event.context || {}, {
1099
+ skipDurable: true,
1100
+ recovered: true,
1101
+ });
1102
+ }
1103
+
1104
+ const binding = resolveRegisteredHostHooksV2Workspace(bindingId);
1105
+ if (!binding) {
1106
+ throw sandboxBoundaryError(
1107
+ "durable Hooks v2 workspace binding is not registered by this host",
1108
+ );
1109
+ }
1110
+ return runWithHostHooksV2Workspace(binding.workspaceRoot, () =>
1111
+ runtime.executeHooks(event.event, event.context || {}, {
918
1112
  skipDurable: true,
919
1113
  recovered: true,
920
1114
  }),
1115
+ );
1116
+ }
1117
+
1118
+ defaultEventRuntimeHost?.registerHandler(
1119
+ (event, record) => executeRecoveredHooksV2Event(hooksRuntime, event, record),
921
1120
  { queue: "inbox", type: "hooks.v2" },
922
1121
  );
923
1122
  export default hooksRuntime;