chainlesschain 0.162.183 → 0.162.184

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 (196) 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-DzAl5fGx.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CXYdXEUI.js → ActionButton-DAHtMGeC.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-CKR5Lexn.js → Analytics-BHQaexv5.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-DATVUOXB.js → AppLayout-Phz_pD0n.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-vb_0ZlV1.js → Artifacts-DHt47kCA.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-BI1l9GWt.js → Audit--Y_8FULl.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-BFXbaUEf.js → BackgroundAgents-N1zchH7D.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-DEYBJJ6H.js → Backup-B_BoyN30.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-COdzeO0M.js → BaseInput-Gl4uQHcT.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-oSN6sfM5.js → Chat-Cg-eIyAZ.js} +6 -6
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-BzeUi3JH.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-BezEa4tm.js → Checkbox-D0MGR2wA.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CNEL0Ife.js → Codegen-BdObJEFn.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-Bf2Y2Bn1.js → Col--ghxXT3z.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-BfUlu4Hc.js → Community-BUFeXOqz.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-BN4xWP9e.js → Compact-DhQO2_Mr.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-Bt6BKmEP.js → Compliance-3HoTqKYd.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-DKLp8YxO.js → Cowork-B3zmO4VW.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-o7Hhw6ky.js → Cron-CJDrZOcc.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-DaNXWJIw.js → Crosschain-SMl15obd.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-B-Qa2mha.js → DID-CgTrTWrl.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-CMX0Qnxw.js → Dashboard-dXFKaKol.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-BLuLyRu_.js → Dropdown-qQHEhCvI.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-CFBAeMij.js → EmailListRenderer-C_ej0MWH.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DWzXQ67V.js → FamilyGuardDashboard-D6ajoE7I.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-DB1QSLgr.js → Federation-Cio2y49h.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-C-OKCToP.js → FormItemContext-ClJz1cYp.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-DMJFtFZf.js → GenericCardRenderer-Dr_8Maca.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-DsGSujOV.js → Git-CevLwp5u.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-B0iS9NEW.js → Governance-CW9YyQUY.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CH004H7c.js → Inference-CQqeAyER.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-Q9MTQ83c.js → KnowledgeGraph-cuGVxHrw.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-B_fyjZK9.js → Logs-DIuHri5d.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-C0o4FtpD.js → MarkdownRenderer-R91Qw5JA.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-BIStF9d1.js → Marketplace-CY1VhFGx.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-pGfal768.js → McpTools-BBAbi1vt.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-xbNqpIqB.js → Memory-BWYGHxJA.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-B5EQGrIK.js → MobileBridge-CPIFkW7A.js} +1 -1
  41. package/src/assets/web-panel/assets/MobileProjects-DQyWxCho.js +1 -0
  42. package/src/assets/web-panel/assets/{Mtc-a_rmfxJH.js → Mtc-Bo3GnQbx.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-BmKuofUr.js → MtcAudit-C8-c4rSW.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-BQbJ-CAN.js → Multisig-ChqMTtoq.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-JtPJKX25.js → NLProgramming-C48TyhvI.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-ZFKznTSG.js → Notes-zogUFWxp.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-B6aHRBBR.js → NotificationSettings-v-K9XpSB.js} +1 -1
  48. package/src/assets/web-panel/assets/OrderTableRenderer-P94JGGNz.js +1 -0
  49. package/src/assets/web-panel/assets/{Organization-BFDTAUgS.js → Organization-Boi1dQfR.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-0FoTfbWH.js → Overflow-DM5YWwgA.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-CWd90etw.js → P2P-C57LKpKK.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-DtCGC-W-.js → PdhVaultBrowser-BFkPqu6Q.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-CvQ7nr7T.js → Permissions-D6fB9YSp.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-rdNPcR-Z.js → PersonalDataHub-Bp7EefEo.js} +3 -3
  55. package/src/assets/web-panel/assets/{Pipeline-CmrfiNOs.js → Pipeline-BVln3hZf.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-D7ep1h_t.js → Privacy-Bf8P3nF6.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-C0xKINHS.js → ProjectInit-DM6wA2E2.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-AOmZFp-F.js → ProjectSettings-CGbc5Iho.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-BWHSkXZP.js → Projects-D0p9EOxm.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-Cb7JCTPL.js → Providers-B2kJcxS6.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-BDMehcXC.js → QrScannerModal-Cxu7dXYy.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-BF6_1nvx.js → QuickAsk-DTlrTPms.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-BHfT-A28.js → Recommend-Cm3X-cCj.js} +1 -1
  64. package/src/assets/web-panel/assets/RemoteSession-DNb2kjvt.js +5 -0
  65. package/src/assets/web-panel/assets/{Reputation-CsWHLEcj.js → Reputation-CZUFFjc1.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-D6srnWhm.js → Row-DAPgloxA.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-Xhr-KyVd.js → RssFeed-dsx9S793.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-vIbIJvwL.js → Search-DnnC8kz-.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-Bzi5Aiko.js → Security-VuZknRMK.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-BHtVX52P.js → Services-B3XNX8Vx.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-C0R8B2jf.js → Skeleton-Dl1nVtCj.js} +1 -1
  72. package/src/assets/web-panel/assets/Skills-CY09CZ_W.js +1 -0
  73. package/src/assets/web-panel/assets/{Sla-0B37mxVU.js → Sla-HzU56n1z.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-0V2jE1Bs.js → SpeechSettings-CRle7Jl2.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-CYedRzaj.js → SyncSettings-DWadz7Sl.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-D-R1x8vm.js → Tasks-CNVTDGg8.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-BKoHztGT.js → Templates-BBAgvrlM.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant--17nwVNZ.js → Tenant-BsbbvGN8.js} +1 -1
  79. package/src/assets/web-panel/assets/Terminal-uscpZI4q.js +3 -0
  80. package/src/assets/web-panel/assets/{TimelineRenderer-C5jx4AE3.js → TimelineRenderer-mTyjNE6r.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-DYJKYa9t.js → Tokens-Bz97oBgs.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-DChpWiQ9.js → Trigger-BTRKC140.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-DfWG52EA.js → Trust-B4A_KuyX.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-CMugYcyA.js → UkeySign-DES9TmLU.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-BOSmrHAd.js → VideoEditing-ClXs7Qxp.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-D5g3k3Sa.js → Wallet-IzZqFz-7.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-D-7u4Mkc.js → WebAuthn-BtOP04g_.js} +3 -3
  88. package/src/assets/web-panel/assets/{WorkflowEditor-CFzZMSUJ.js → WorkflowEditor-_0cqnopY.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-VbR6l6mc.js → chat-ax7193uU.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-BSZn8EDS.js → colors-Bu4WGJah.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-y74obMEq.js → compact-item-BX1dlTW0.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-C326bjex.js → createContext-CktA_Dj7.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-x877iKKS.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-D_INJQT_.js → hasIn-D5wd817l.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CsovTpx9.js → index-5PYYkr8S.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-9PIVuXqo.js → index-A4uBPQCz.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BjcWKg1S.js → index-BAtBNfkr.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CMHqs3Jb.js → index-BLLsUNDc.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-B7SrC-On.js → index-BQtoRyTO.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DUU2606o.js → index-BRfXoRuh.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Iw0FfqUz.js → index-Bad2CYeH.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-Dlxh9D8D.js → index-BcGdL3sG.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DuIkfnTF.js → index-C3HmzCLt.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-E_v1ZCTP.js → index-C8DkWyNr.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-4eyH-eC2.js → index-C8tLR2TG.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BnSfnSMP.js → index-CP8ELJBc.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-DwHSZLXg.js → index-CUForzsG.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-C2NyllnW.js → index-CYRE0NJA.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bnua8IX3.js → index-CeVZaJSC.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-KF9Zmqln.js → index-CfzxR61U.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Cr3uuz0C.js → index-Ci3y1ZAv.js} +3 -3
  112. package/src/assets/web-panel/assets/{index-DBkzrpiL.js → index-CjEJjl5C.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-abmn_8Yz.js → index-Cv7bVWJ5.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-qMA4GYdQ.js → index-D-o4Rwjk.js} +1 -1
  115. package/src/assets/web-panel/assets/index-D7pfPouB.js +1 -0
  116. package/src/assets/web-panel/assets/{index-jYaogFE8.js → index-D9op8poE.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-GA80ir_u.js → index-DF1TysIF.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CzE53HiB.js → index-DYo9S5OT.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-gINyI1rh.js → index-D_cycOET.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-FQBsuExX.js → index-Db3CpWTr.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-IZAWt0H8.js → index-DkD1K-fF.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-C327pLbw.js → index-DmPJ6T6F.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DdyjrCAu.js → index-DmVUeWUk.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CfLJ42kv.js → index-Dzdr0zDf.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DkH1JvEt.js → index-PBLzwYnu.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DNMxIsDg.js → index-bFCaM7Eq.js} +1 -1
  127. package/src/assets/web-panel/assets/index-e4i-VLBd.js +1 -0
  128. package/src/assets/web-panel/assets/{index-C-ZCaUJc.js → index-h3KJZr95.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-Bfw2hf2s.js → index-iHcPtQ2e.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BJi3UqBt.js → index-jzlzm4VK.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BY8-nCgs.js → index-o14NNnxw.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-nSn2-C4N.js → index-tYPSfGbd.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-4PIeTM--.js → index-ytp2H5Zx.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-DI0Zaf8-.js → initDefaultProps-D2Iut83B.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BZDKSy3Z.js → motion-BuaJVdK9.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-DsIW01Vp.js → move-CaEuM92y.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-CohkDhsf.js → mtc-parser-wuKNBwys.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-DpiN5rzg.js → omit-7a3eklaq.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-qbuqni3y.js → pickAttrs-Dn4z7KvJ.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-mBky6714.js → placementArrow-DVn_qT4-.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-Bas3eQ2K.js → responsiveObserve-Dodz1OMQ.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-CBx_SKoK.js → slide-CxoGskbp.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-BlYguJSV.js → statusUtils-DBh_epQH.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-BCYQmRGv.js → styleChecker-RXQ4gG5P.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-Dp5dybLM.js → useFlexGapSupport-1Wxm0HEG.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-DHAMBgA2.js → useFs-CI_ySNxJ.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-W6jsSw76.js → usePersonalDataHub-C6973rZP.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-BkI6aayc.js → vnode-CalynwKr.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-C_IMGueq.js → zoom-CM1cd-Q0.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 +13 -0
  158. package/src/harness/jsonl-session-store.js +57 -6
  159. package/src/harness/mcp-client.js +65 -43
  160. package/src/lib/agent-batch.js +4 -1
  161. package/src/lib/agent-team/team-worktree.js +3 -0
  162. package/src/lib/async-hook-supervisor.cjs +82 -10
  163. package/src/lib/async-hook-supervisor.js +50 -4
  164. package/src/lib/collaboration-run-store.js +362 -0
  165. package/src/lib/hook-runner.cjs +98 -17
  166. package/src/lib/hook-runner.js +77 -6
  167. package/src/lib/hook-shell-command.cjs +148 -0
  168. package/src/lib/hooks-v2-runtime.js +188 -77
  169. package/src/lib/jsonl-session-store.js +2 -0
  170. package/src/lib/lsp/__tests__/lsp-client.test.js +18 -0
  171. package/src/lib/lsp/lsp-client.js +12 -1
  172. package/src/lib/plugin-monitor-supervisor.js +53 -16
  173. package/src/lib/plugin-runtime/bin.js +1 -1
  174. package/src/lib/plugin-runtime/install.js +249 -57
  175. package/src/lib/plugin-runtime/mcp.js +21 -2
  176. package/src/lib/plugin-runtime/monitors.js +19 -3
  177. package/src/lib/plugin-runtime/sandbox-policy.js +99 -0
  178. package/src/lib/process-execution-broker/index.js +453 -12
  179. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +1347 -0
  180. package/src/lib/process-execution-broker/linux-generic-bwrap.js +1260 -0
  181. package/src/lib/process-execution-broker/platform-sandbox.js +580 -56
  182. package/src/lib/session-usage.js +202 -2
  183. package/src/lib/stream-retry.js +29 -0
  184. package/src/repl/agent-repl.js +32 -3
  185. package/src/runtime/agent-core.js +32 -4
  186. package/src/runtime/headless-runner.js +37 -0
  187. package/src/runtime/headless-stream.js +34 -2
  188. package/src/assets/web-panel/assets/ChatBubbleRenderer-CI_jT0ru.js +0 -1
  189. package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +0 -1
  190. package/src/assets/web-panel/assets/OrderTableRenderer-DdcsOqEz.js +0 -1
  191. package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +0 -5
  192. package/src/assets/web-panel/assets/Skills-DtT6rWOX.js +0 -1
  193. package/src/assets/web-panel/assets/Terminal-Dnkos7vW.js +0 -3
  194. package/src/assets/web-panel/assets/devWarning-D3Bho_6u.js +0 -1
  195. package/src/assets/web-panel/assets/index-5iAFwYx1.js +0 -1
  196. package/src/assets/web-panel/assets/index-BfnB7LPx.js +0 -1
@@ -26,9 +26,14 @@ const {
26
26
  loadShellConfig,
27
27
  } = require("./shell-selector.cjs");
28
28
  const { mergeHookDecisions } = require("./hook-event-bus.cjs");
29
+ const { buildManagedHookEnvironment } = require("./hook-environment.cjs");
29
30
  const {
30
- buildManagedHookEnvironment,
31
- } = require("./hook-environment.cjs");
31
+ buildExplicitHookShellInvocation,
32
+ issueTrustedHookSandboxContract,
33
+ requireTrustedHookRoot,
34
+ requiresExplicitHookShell,
35
+ sandboxBoundaryError,
36
+ } = require("./hook-shell-command.cjs");
32
37
 
33
38
  const _deps = { runSync: null, run: null };
34
39
  Object.defineProperties(_deps, {
@@ -125,17 +130,13 @@ function hookSpawnFailure(error) {
125
130
  const sandboxDenied =
126
131
  error?.code === "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED";
127
132
  return {
128
- decision: sandboxDenied
129
- ? HOOK_DECISIONS.BLOCK
130
- : HOOK_DECISIONS.CONTINUE,
133
+ decision: sandboxDenied ? HOOK_DECISIONS.BLOCK : HOOK_DECISIONS.CONTINUE,
131
134
  reason: sandboxDenied
132
135
  ? `hook sandbox denied: ${error.message}`
133
136
  : `hook spawn failed: ${error.message}`,
134
137
  exitCode: null,
135
138
  error: error.message,
136
- ...(sandboxDenied
137
- ? { sandboxDenied: true }
138
- : { nonBlockingError: true }),
139
+ ...(sandboxDenied ? { sandboxDenied: true } : { nonBlockingError: true }),
139
140
  };
140
141
  }
141
142
 
@@ -321,12 +322,17 @@ function _runCommandHookInner(command, input = {}, opts = {}) {
321
322
  let res;
322
323
  try {
323
324
  const sandboxPolicy = resolveHookSandboxPolicy({}, opts);
325
+ const explicitSandboxShell = requiresExplicitHookShell(sandboxPolicy);
326
+ const trustedRoot = explicitSandboxShell
327
+ ? requireTrustedHookRoot(cwd)
328
+ : null;
329
+ const workingDirectory = trustedRoot || cwd || process.cwd();
324
330
  const common = {
325
331
  input: JSON.stringify({
326
332
  ...input,
327
333
  schema_version: input.schema_version ?? HOOK_PAYLOAD_SCHEMA_VERSION,
328
334
  }),
329
- cwd: cwd || process.cwd(),
335
+ cwd: workingDirectory,
330
336
  encoding: "utf-8",
331
337
  timeout,
332
338
  maxBuffer: 8 * 1024 * 1024,
@@ -346,6 +352,7 @@ function _runCommandHookInner(command, input = {}, opts = {}) {
346
352
  pluginId: opts.pluginId || null,
347
353
  pluginVersion: opts.pluginVersion || null,
348
354
  pluginSource: opts.pluginSource || null,
355
+ ...(explicitSandboxShell || usePowershell ? { shell: false } : {}),
349
356
  ...(sandboxPolicy ? { sandboxPolicy } : {}),
350
357
  };
351
358
  const brokerRunSync =
@@ -355,13 +362,42 @@ function _runCommandHookInner(command, input = {}, opts = {}) {
355
362
  ? opts.broker["spawnSync"].bind(opts.broker)
356
363
  : null;
357
364
  if (brokerRunSync) {
358
- const invocation = usePowershell
359
- ? buildPowershellArgv(command, shellKind, {
360
- executionPolicy: loadShellConfig({ cwd: common.cwd })
361
- .executionPolicy,
365
+ const powershellOptions = {
366
+ executionPolicy: loadShellConfig({ cwd: common.cwd }).executionPolicy,
367
+ };
368
+ const invocation = explicitSandboxShell
369
+ ? buildExplicitHookShellInvocation(command, {
370
+ shellKind,
371
+ buildPowershellArgv,
372
+ powershellOptions,
362
373
  })
363
- : { file: command, argv: [] };
364
- res = brokerRunSync(invocation.file, invocation.argv, processOptions);
374
+ : usePowershell
375
+ ? buildPowershellArgv(command, shellKind, powershellOptions)
376
+ : { file: command, argv: [] };
377
+ let brokerOptions = processOptions;
378
+ if (explicitSandboxShell) {
379
+ const issuer = opts.broker?.issueLinuxWorkspaceSandboxExecutionContract;
380
+ const sandboxExecutionContract = issueTrustedHookSandboxContract({
381
+ issuer,
382
+ receiver: opts.broker,
383
+ file: invocation.file,
384
+ args: invocation.argv,
385
+ options: processOptions,
386
+ trustedRoot,
387
+ sync: true,
388
+ label: "trusted plugin hook sandbox contract issuance failed",
389
+ });
390
+ if (process.platform === "linux" && !sandboxExecutionContract) {
391
+ throw sandboxBoundaryError(
392
+ "trusted Linux hook sandbox contract issuer is unavailable",
393
+ );
394
+ }
395
+ brokerOptions = {
396
+ ...processOptions,
397
+ ...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
398
+ };
399
+ }
400
+ res = brokerRunSync(invocation.file, invocation.argv, brokerOptions);
365
401
  } else if (usePowershell) {
366
402
  // Per-hook `shell: powershell|pwsh` (settings hook entry): explicit argv
367
403
  // instead of the default shell; the enterprise ExecutionPolicy override
@@ -374,6 +410,12 @@ function _runCommandHookInner(command, input = {}, opts = {}) {
374
410
  throw new Error("hook process runner unavailable");
375
411
  }
376
412
  res = _deps.runSync(inv.file, inv.argv, processOptions);
413
+ } else if (explicitSandboxShell) {
414
+ if (typeof _deps.runSync !== "function") {
415
+ throw new Error("hook process runner unavailable");
416
+ }
417
+ const invocation = buildExplicitHookShellInvocation(command);
418
+ res = _deps.runSync(invocation.file, invocation.argv, processOptions);
377
419
  } else {
378
420
  if (typeof _deps.runSync !== "function") {
379
421
  throw new Error("hook process runner unavailable");
@@ -467,7 +509,6 @@ async function _runCommandHookInnerAsync(command, input = {}, opts = {}) {
467
509
  : 60000;
468
510
  const shellKind = normalizeShellKind(opts.shell);
469
511
  const usePowershell = shellKind === "powershell" || shellKind === "pwsh";
470
- const wd = cwd || process.cwd();
471
512
  const inputJson = JSON.stringify({
472
513
  ...input,
473
514
  schema_version: input.schema_version ?? HOOK_PAYLOAD_SCHEMA_VERSION,
@@ -485,6 +526,14 @@ async function _runCommandHookInnerAsync(command, input = {}, opts = {}) {
485
526
  } catch (error) {
486
527
  return hookSpawnFailure(error);
487
528
  }
529
+ const explicitSandboxShell = requiresExplicitHookShell(sandboxPolicy);
530
+ let trustedRoot;
531
+ try {
532
+ trustedRoot = explicitSandboxShell ? requireTrustedHookRoot(cwd) : null;
533
+ } catch (error) {
534
+ return hookSpawnFailure(error);
535
+ }
536
+ const wd = trustedRoot || cwd || process.cwd();
488
537
  const processOptions = {
489
538
  cwd: wd,
490
539
  env: spawnEnv,
@@ -494,6 +543,7 @@ async function _runCommandHookInnerAsync(command, input = {}, opts = {}) {
494
543
  pluginId: opts.pluginId || null,
495
544
  pluginVersion: opts.pluginVersion || null,
496
545
  pluginSource: opts.pluginSource || null,
546
+ ...(explicitSandboxShell || usePowershell ? { shell: false } : {}),
497
547
  ...(sandboxPolicy ? { sandboxPolicy } : {}),
498
548
  };
499
549
 
@@ -509,7 +559,38 @@ async function _runCommandHookInnerAsync(command, input = {}, opts = {}) {
509
559
  if (typeof run !== "function") {
510
560
  throw new Error("hook process runner unavailable");
511
561
  }
512
- if (usePowershell) {
562
+ if (explicitSandboxShell) {
563
+ const invocation = buildExplicitHookShellInvocation(command, {
564
+ shellKind,
565
+ buildPowershellArgv,
566
+ powershellOptions: {
567
+ executionPolicy: loadShellConfig({ cwd: wd }).executionPolicy,
568
+ },
569
+ });
570
+ let brokerOptions = processOptions;
571
+ if (brokerRun) {
572
+ const issuer = opts.broker?.issueLinuxWorkspaceSandboxExecutionContract;
573
+ const sandboxExecutionContract = issueTrustedHookSandboxContract({
574
+ issuer,
575
+ receiver: opts.broker,
576
+ file: invocation.file,
577
+ args: invocation.argv,
578
+ options: processOptions,
579
+ trustedRoot,
580
+ label: "trusted plugin hook sandbox contract issuance failed",
581
+ });
582
+ if (process.platform === "linux" && !sandboxExecutionContract) {
583
+ throw sandboxBoundaryError(
584
+ "trusted Linux hook sandbox contract issuer is unavailable",
585
+ );
586
+ }
587
+ brokerOptions = {
588
+ ...processOptions,
589
+ ...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
590
+ };
591
+ }
592
+ child = run(invocation.file, invocation.argv, brokerOptions);
593
+ } else if (usePowershell) {
513
594
  const { executionPolicy } = loadShellConfig({ cwd: wd });
514
595
  const inv = buildPowershellArgv(command, shellKind, { executionPolicy });
515
596
  child = run(inv.file, inv.argv, processOptions);
@@ -1,5 +1,13 @@
1
1
  import runner from "./hook-runner.cjs";
2
2
  import executionBroker from "./process-execution-broker/index.js";
3
+ import hookShellCommand from "./hook-shell-command.cjs";
4
+
5
+ const {
6
+ issueTrustedHookSandboxContract,
7
+ requireTrustedHookRoot,
8
+ requiresExplicitHookShell,
9
+ sandboxBoundaryError,
10
+ } = hookShellCommand;
3
11
 
4
12
  const brokerRunner = executionBroker.spawn.bind(executionBroker);
5
13
  const brokerSyncRunner = executionBroker.spawnSync.bind(executionBroker);
@@ -17,21 +25,84 @@ function normalizeInvocation(argsOrOptions, maybeOptions) {
17
25
 
18
26
  function runHookProcess(file, argsOrOptions, maybeOptions) {
19
27
  const { args, options } = normalizeInvocation(argsOrOptions, maybeOptions);
20
- return _processDeps.run(file, args, {
21
- ...options,
22
- origin: options.origin || "hook",
28
+ const callerOptions = { ...options };
29
+ delete callerOptions.sandboxExecutionContract;
30
+ const processOptions = {
31
+ ...callerOptions,
32
+ origin: callerOptions.origin || "hook",
23
33
  policy: "allow",
24
34
  scope: "hook",
35
+ };
36
+ const requiresContract = requiresExplicitHookShell(
37
+ processOptions.sandboxPolicy,
38
+ );
39
+ const trustedRoot = requiresContract
40
+ ? requireTrustedHookRoot(processOptions.cwd)
41
+ : null;
42
+ const sandboxExecutionContract = requiresContract
43
+ ? issueTrustedHookSandboxContract({
44
+ issuer: executionBroker.issueLinuxWorkspaceSandboxExecutionContract,
45
+ receiver: executionBroker,
46
+ file,
47
+ args,
48
+ options: processOptions,
49
+ trustedRoot,
50
+ })
51
+ : null;
52
+ if (
53
+ process.platform === "linux" &&
54
+ requiresContract &&
55
+ !sandboxExecutionContract
56
+ ) {
57
+ throw sandboxBoundaryError(
58
+ "trusted Linux hook sandbox contract could not be issued",
59
+ );
60
+ }
61
+ return _processDeps.run(file, args, {
62
+ ...processOptions,
63
+ ...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
25
64
  });
26
65
  }
27
66
 
28
67
  function runHookProcessSync(file, argsOrOptions, maybeOptions) {
29
68
  const { args, options } = normalizeInvocation(argsOrOptions, maybeOptions);
30
- return _processDeps.runSync(file, args, {
31
- ...options,
32
- origin: options.origin || "hook",
69
+ const callerOptions = { ...options };
70
+ delete callerOptions.sandboxExecutionContract;
71
+ const processOptions = {
72
+ ...callerOptions,
73
+ origin: callerOptions.origin || "hook",
33
74
  policy: "allow",
34
75
  scope: "hook",
76
+ };
77
+ const requiresContract = requiresExplicitHookShell(
78
+ processOptions.sandboxPolicy,
79
+ );
80
+ const trustedRoot = requiresContract
81
+ ? requireTrustedHookRoot(processOptions.cwd)
82
+ : null;
83
+ const sandboxExecutionContract = requiresContract
84
+ ? issueTrustedHookSandboxContract({
85
+ issuer: executionBroker.issueLinuxWorkspaceSandboxExecutionContract,
86
+ receiver: executionBroker,
87
+ file,
88
+ args,
89
+ options: processOptions,
90
+ trustedRoot,
91
+ sync: true,
92
+ })
93
+ : null;
94
+ if (
95
+ process.platform === "linux" &&
96
+ requiresContract &&
97
+ !sandboxExecutionContract
98
+ ) {
99
+ throw sandboxBoundaryError(
100
+ "trusted Linux hook sandbox contract could not be issued",
101
+ );
102
+ }
103
+ return _processDeps.runSync(file, args, {
104
+ ...processOptions,
105
+ ...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
35
106
  });
36
107
  }
37
108
 
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+
3
+ const path = require("node:path");
4
+
5
+ const STRONG_HOOK_BOUNDARIES = new Set(["filesystem", "network"]);
6
+
7
+ function requiredHookBoundaries(sandboxPolicy) {
8
+ const configured = sandboxPolicy?.requiredBoundaries;
9
+ return Array.isArray(configured) ? configured : [];
10
+ }
11
+
12
+ function requiresExplicitHookShell(sandboxPolicy) {
13
+ return requiredHookBoundaries(sandboxPolicy).some((boundary) =>
14
+ STRONG_HOOK_BOUNDARIES.has(boundary),
15
+ );
16
+ }
17
+
18
+ function sandboxBoundaryError(message) {
19
+ const error = new Error(message);
20
+ error.code = "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED";
21
+ error.sandboxFailClosed = true;
22
+ return error;
23
+ }
24
+
25
+ function asSandboxBoundaryError(error, prefix) {
26
+ if (error?.code === "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED") {
27
+ return error;
28
+ }
29
+ const detail =
30
+ error && typeof error.message === "string" ? error.message : String(error);
31
+ return sandboxBoundaryError(`${prefix}: ${detail}`);
32
+ }
33
+
34
+ function issueTrustedHookSandboxContract({
35
+ issuer,
36
+ receiver = null,
37
+ file,
38
+ args,
39
+ options,
40
+ trustedRoot,
41
+ sync = false,
42
+ label = "trusted hook sandbox contract issuance failed",
43
+ }) {
44
+ if (typeof issuer !== "function") return null;
45
+ try {
46
+ return issuer.call(
47
+ receiver,
48
+ file,
49
+ args,
50
+ options,
51
+ trustedRoot,
52
+ ...(sync ? [{ sync: true }] : []),
53
+ );
54
+ } catch (error) {
55
+ throw asSandboxBoundaryError(error, label);
56
+ }
57
+ }
58
+
59
+ function requireTrustedHookRoot(value, label = "hook working directory") {
60
+ if (
61
+ typeof value !== "string" ||
62
+ !value ||
63
+ value.includes("\0") ||
64
+ !path.isAbsolute(value)
65
+ ) {
66
+ throw sandboxBoundaryError(
67
+ `${label} must be an absolute trusted path for filesystem/network sandboxing`,
68
+ );
69
+ }
70
+ return path.resolve(value);
71
+ }
72
+
73
+ function isPathInside(root, candidate) {
74
+ const relative = path.relative(path.resolve(root), path.resolve(candidate));
75
+ return (
76
+ relative === "" ||
77
+ (relative !== ".." &&
78
+ !relative.startsWith(`..${path.sep}`) &&
79
+ !path.isAbsolute(relative))
80
+ );
81
+ }
82
+
83
+ function quotePosixShellArgument(value) {
84
+ const text = String(value);
85
+ if (text.length === 0) return "''";
86
+ return `'${text.replace(/'/g, `'"'"'`)}'`;
87
+ }
88
+
89
+ function quoteCmdArgument(value) {
90
+ const text = String(value);
91
+ if (text.length === 0) return '""';
92
+ // The command and its arguments are all hook-controlled, but quote cmd.exe
93
+ // metacharacters anyway so an argv entry remains one argument.
94
+ return `"${text
95
+ .replace(/"/g, '""')
96
+ .replace(/([&|<>^])/g, "^$1")
97
+ .replace(/%/g, "%%")}"`;
98
+ }
99
+
100
+ function appendShellArguments(command, args, platform) {
101
+ if (!Array.isArray(args) || args.length === 0) return command;
102
+ const quote =
103
+ platform === "win32" ? quoteCmdArgument : quotePosixShellArgument;
104
+ return `${command} ${args.map((arg) => quote(arg)).join(" ")}`;
105
+ }
106
+
107
+ /**
108
+ * Turn a settings-style shell command into an explicit executable + argv.
109
+ * This is used only when filesystem/network boundaries are requested. Keeping
110
+ * shell selection explicit lets the Broker bind its one-shot contract to the
111
+ * actual launch tuple and guarantees the child spawn itself uses shell:false.
112
+ */
113
+ function buildExplicitHookShellInvocation(
114
+ command,
115
+ {
116
+ args = [],
117
+ platform = process.platform,
118
+ shellKind = null,
119
+ buildPowershellArgv = null,
120
+ powershellOptions = {},
121
+ } = {},
122
+ ) {
123
+ const rendered = appendShellArguments(String(command), args, platform);
124
+ if (
125
+ (shellKind === "powershell" || shellKind === "pwsh") &&
126
+ typeof buildPowershellArgv === "function"
127
+ ) {
128
+ return buildPowershellArgv(rendered, shellKind, powershellOptions);
129
+ }
130
+ if (platform === "win32") {
131
+ return {
132
+ file: process.env.ComSpec || "cmd.exe",
133
+ argv: ["/d", "/s", "/c", rendered],
134
+ };
135
+ }
136
+ return { file: "/bin/sh", argv: ["-c", rendered] };
137
+ }
138
+
139
+ module.exports = {
140
+ buildExplicitHookShellInvocation,
141
+ issueTrustedHookSandboxContract,
142
+ isPathInside,
143
+ requireTrustedHookRoot,
144
+ requiredHookBoundaries,
145
+ requiresExplicitHookShell,
146
+ asSandboxBoundaryError,
147
+ sandboxBoundaryError,
148
+ };