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
@@ -20,6 +20,7 @@
20
20
  import EventEmitter from "events";
21
21
  import { randomUUID } from "crypto";
22
22
  import { createRequire } from "module";
23
+ import path from "node:path";
23
24
  import { RingBuffer } from "./RingBuffer.js";
24
25
  import { executionBroker } from "../../lib/process-execution-broker/index.js";
25
26
 
@@ -91,11 +92,17 @@ export class PtyManager extends EventEmitter {
91
92
  ) {
92
93
  throw new TypeError("resolveSandboxPolicy must be a function or null");
93
94
  }
94
- this._policyCwd = opts.policyCwd || process.cwd();
95
+ this._policyCwd = path.resolve(opts.policyCwd || process.cwd());
95
96
  this._resolveSandboxPolicy = resolveSandboxPolicy;
96
97
  this._deps = {
97
98
  loadNodePty: opts._deps?.loadNodePty || (() => require("node-pty")),
98
99
  spawnPty: opts._deps?.spawnPty || null,
100
+ issueLinuxWorkspaceSandboxExecutionContract:
101
+ opts._deps?.issueLinuxWorkspaceSandboxExecutionContract ||
102
+ executionBroker.issueLinuxWorkspaceSandboxExecutionContract.bind(
103
+ executionBroker,
104
+ ),
105
+ platform: opts._deps?.platform || (() => process.platform),
99
106
  now: opts._deps?.now || (() => Date.now()),
100
107
  };
101
108
  this._sessions = new Map();
@@ -120,7 +127,10 @@ export class PtyManager extends EventEmitter {
120
127
  throw new Error("shell_not_allowed");
121
128
  }
122
129
 
123
- const cwd = req.cwd || this.config.defaultCwd || process.cwd();
130
+ const cwd = path.resolve(
131
+ this._policyCwd,
132
+ req.cwd || this.config.defaultCwd || this._policyCwd,
133
+ );
124
134
  // A remote cwd may discover a stricter policy, but it must never replace
125
135
  // the fixed workspace root supplied by the host. Resolve and validate the
126
136
  // pinned policy before loading node-pty or allocating a native terminal.
@@ -133,15 +143,6 @@ export class PtyManager extends EventEmitter {
133
143
  )
134
144
  : null;
135
145
 
136
- let pty;
137
- try {
138
- pty = this._deps.loadNodePty();
139
- } catch {
140
- const err = new Error("pty_native_unavailable");
141
- err.cause = "node-pty failed to load (native binding missing)";
142
- throw err;
143
- }
144
-
145
146
  const cols = Number.isFinite(req.cols) ? req.cols : 80;
146
147
  const rows = Number.isFinite(req.rows) ? req.rows : 24;
147
148
  const cmd = resolveShellCmd(shell);
@@ -152,9 +153,7 @@ export class PtyManager extends EventEmitter {
152
153
  req.env && typeof req.env === "object" && !Array.isArray(req.env)
153
154
  ? req.env
154
155
  : {};
155
- const spawnPty =
156
- this._deps.spawnPty || executionBroker.spawnPty.bind(executionBroker);
157
- const proc = spawnPty(pty, cmd, [], {
156
+ const brokerSpawnOptions = {
158
157
  name: "xterm-256color",
159
158
  cols,
160
159
  rows,
@@ -163,8 +162,39 @@ export class PtyManager extends EventEmitter {
163
162
  origin: "terminal:pty",
164
163
  policy: "allow",
165
164
  scope: "terminal",
165
+ shell: false,
166
166
  ...(sandboxPolicy ? { sandboxPolicy } : {}),
167
- });
167
+ };
168
+ if (sandboxPolicy && this._deps.platform() === "linux") {
169
+ const contract = this._deps.issueLinuxWorkspaceSandboxExecutionContract(
170
+ cmd,
171
+ [],
172
+ brokerSpawnOptions,
173
+ this._policyCwd,
174
+ { pty: true },
175
+ );
176
+ if (!contract) {
177
+ const error = new Error("pty_sandbox_contract_unavailable");
178
+ error.code = "ERR_PTY_SANDBOX_CONTRACT_UNAVAILABLE";
179
+ error.sandboxFailClosed = true;
180
+ error.requiredBoundaries = [...sandboxPolicy.requiredBoundaries];
181
+ throw error;
182
+ }
183
+ brokerSpawnOptions.sandboxExecutionContract = contract;
184
+ }
185
+
186
+ let pty;
187
+ try {
188
+ pty = this._deps.loadNodePty();
189
+ } catch {
190
+ const err = new Error("pty_native_unavailable");
191
+ err.cause = "node-pty failed to load (native binding missing)";
192
+ throw err;
193
+ }
194
+
195
+ const spawnPty =
196
+ this._deps.spawnPty || executionBroker.spawnPty.bind(executionBroker);
197
+ const proc = spawnPty(pty, cmd, [], brokerSpawnOptions);
168
198
 
169
199
  const sessionId = randomUUID();
170
200
  const session = new PtySession({
@@ -27,6 +27,10 @@ import { runnableTaskModel } from "../../lib/runnable-provider.js";
27
27
  import { PlanState } from "../../lib/plan-mode.js";
28
28
  import { CLISlotFiller } from "../../lib/slot-filler.js";
29
29
  import { createAbortError, isAbortError } from "../../lib/abort-utils.js";
30
+ import {
31
+ resolveRegisteredHostHooksV2Workspace,
32
+ runWithHostHooksV2Workspace,
33
+ } from "../../lib/hooks-v2-workspace-context.js";
30
34
  import { createWsApprovalGate } from "./ws-approval-gate.js";
31
35
 
32
36
  export class WSAgentHandler {
@@ -166,7 +170,7 @@ export class WSAgentHandler {
166
170
  diffReviewFollowUps = new DiffReviewFollowUpTracker(sideEffectLedger);
167
171
  let currentSideEffectOpId = null;
168
172
 
169
- const runAgentTurn = async () => {
173
+ const executeAgentTurn = async () => {
170
174
  for await (const event of agentLoop(session.messages, loopOptions)) {
171
175
  switch (event.type) {
172
176
  case "slot-filling":
@@ -250,6 +254,16 @@ export class WSAgentHandler {
250
254
  }
251
255
  }
252
256
  };
257
+ const hooksWorkspaceBinding = resolveRegisteredHostHooksV2Workspace(
258
+ session.hooksV2WorkspaceBindingId,
259
+ );
260
+ const runAgentTurn = () =>
261
+ hooksWorkspaceBinding
262
+ ? runWithHostHooksV2Workspace(
263
+ hooksWorkspaceBinding.workspaceRoot,
264
+ executeAgentTurn,
265
+ )
266
+ : executeAgentTurn();
253
267
 
254
268
  if (session.mcpClient?.withElicitationContext) {
255
269
  await session.mcpClient.withElicitationContext(
@@ -45,6 +45,52 @@ import {
45
45
  CODING_AGENT_MVP_TOOL_NAMES,
46
46
  listCodingAgentToolNames,
47
47
  } from "../../runtime/coding-agent-contract.js";
48
+ import {
49
+ registerHostHooksV2Workspace,
50
+ releaseRegisteredHostHooksV2Workspace,
51
+ } from "../../lib/hooks-v2-workspace-context.js";
52
+
53
+ function normalizeHostWorkspaceRoot(workspaceRoot) {
54
+ if (
55
+ typeof workspaceRoot !== "string" ||
56
+ workspaceRoot.length === 0 ||
57
+ workspaceRoot.includes("\0")
58
+ ) {
59
+ return null;
60
+ }
61
+ try {
62
+ return path.resolve(workspaceRoot);
63
+ } catch {
64
+ return null;
65
+ }
66
+ }
67
+
68
+ function bindSessionHooksV2Workspace(
69
+ session,
70
+ workspaceRoot,
71
+ { releaseOnClose = false, protectedBindingId = null } = {},
72
+ ) {
73
+ const binding = workspaceRoot
74
+ ? registerHostHooksV2Workspace(workspaceRoot)
75
+ : null;
76
+ Object.defineProperty(session, "hooksV2WorkspaceBindingId", {
77
+ value: binding?.bindingId || null,
78
+ enumerable: false,
79
+ writable: false,
80
+ configurable: false,
81
+ });
82
+ Object.defineProperty(session, "_releaseHooksV2WorkspaceBindingOnClose", {
83
+ value: Boolean(
84
+ binding &&
85
+ releaseOnClose === true &&
86
+ binding.bindingId !== protectedBindingId,
87
+ ),
88
+ enumerable: false,
89
+ writable: false,
90
+ configurable: false,
91
+ });
92
+ return session.hooksV2WorkspaceBindingId;
93
+ }
48
94
 
49
95
  /**
50
96
  * @typedef {object} Session
@@ -85,6 +131,15 @@ export class WSSessionManager {
85
131
  this.db = options.db || null;
86
132
  this.config = options.config || {};
87
133
  this.defaultProjectRoot = options.defaultProjectRoot || process.cwd();
134
+ // Snapshot constructor authority once. Later request fields (and even a
135
+ // mutable compatibility assignment to defaultProjectRoot) cannot replace
136
+ // the root used for strong Hooks v2 execution.
137
+ this._hooksV2HostWorkspaceRoot = normalizeHostWorkspaceRoot(
138
+ this.defaultProjectRoot,
139
+ );
140
+ this._hooksV2HostWorkspaceBindingId = this._hooksV2HostWorkspaceRoot
141
+ ? registerHostHooksV2Workspace(this._hooksV2HostWorkspaceRoot).bindingId
142
+ : null;
88
143
  this.mcpClient = options.mcpClient || null;
89
144
  this.allowedMcpServerNames = Array.isArray(options.allowedMcpServerNames)
90
145
  ? options.allowedMcpServerNames
@@ -324,6 +379,11 @@ export class WSSessionManager {
324
379
  const sessionId = this._generateId();
325
380
  const type = options.type || "agent";
326
381
  const baseProjectRoot = options.projectRoot || this.defaultProjectRoot;
382
+ const hostAuthorizedBaseRoot =
383
+ normalizeHostWorkspaceRoot(baseProjectRoot) ===
384
+ this._hooksV2HostWorkspaceRoot
385
+ ? this._hooksV2HostWorkspaceRoot
386
+ : null;
327
387
  const cfgLlm = this.config?.llm || {};
328
388
  const provider = options.provider || cfgLlm.provider || "ollama";
329
389
  const model =
@@ -435,6 +495,18 @@ export class WSSessionManager {
435
495
  createdAt: new Date().toISOString(),
436
496
  lastActivity: new Date().toISOString(),
437
497
  };
498
+ bindSessionHooksV2Workspace(
499
+ session,
500
+ hostAuthorizedBaseRoot
501
+ ? worktree
502
+ ? normalizeHostWorkspaceRoot(projectRoot)
503
+ : hostAuthorizedBaseRoot
504
+ : null,
505
+ {
506
+ releaseOnClose: Boolean(hostAuthorizedBaseRoot && worktree),
507
+ protectedBindingId: this._hooksV2HostWorkspaceBindingId,
508
+ },
509
+ );
438
510
 
439
511
  if (this.db) {
440
512
  try {
@@ -546,6 +618,15 @@ export class WSSessionManager {
546
618
  createdAt: dbSession.created_at,
547
619
  lastActivity: new Date().toISOString(),
548
620
  };
621
+ const recoveredHooksWorkspaceRoot =
622
+ metadata.worktreeIsolation !== true &&
623
+ normalizeHostWorkspaceRoot(baseProjectRoot) ===
624
+ this._hooksV2HostWorkspaceRoot &&
625
+ normalizeHostWorkspaceRoot(workspace.projectRoot) ===
626
+ this._hooksV2HostWorkspaceRoot
627
+ ? this._hooksV2HostWorkspaceRoot
628
+ : null;
629
+ bindSessionHooksV2Workspace(session, recoveredHooksWorkspaceRoot);
549
630
 
550
631
  this._bindPlanManagerPersistence(session);
551
632
  this.sessions.set(session.id, session);
@@ -564,6 +645,13 @@ export class WSSessionManager {
564
645
  const session = this.sessions.get(sessionId);
565
646
  if (!session) return;
566
647
 
648
+ if (
649
+ session._releaseHooksV2WorkspaceBindingOnClose === true &&
650
+ session.hooksV2WorkspaceBindingId
651
+ ) {
652
+ releaseRegisteredHostHooksV2Workspace(session.hooksV2WorkspaceBindingId);
653
+ }
654
+
567
655
  session.status = "closed";
568
656
 
569
657
  // Persist messages to DB
@@ -0,0 +1,234 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import executionBroker from "../lib/process-execution-broker/index.js";
4
+
5
+ const SUPPORTED_BOUNDARIES = new Set(["filesystem", "network"]);
6
+
7
+ export const _backgroundTaskCommandDeps = {
8
+ execSync: (...args) => executionBroker.execSync(...args),
9
+ execFile: (...args) => executionBroker.execFile(...args),
10
+ issueLinuxWorkspaceSandboxExecutionContract: (...args) =>
11
+ executionBroker.issueLinuxWorkspaceSandboxExecutionContract(...args),
12
+ platform: process.platform,
13
+ };
14
+
15
+ function sandboxError(code, reason, message, requiredBoundaries = []) {
16
+ const error = new Error(message);
17
+ error.code = code;
18
+ error.sandboxReason = reason;
19
+ error.sandboxFailClosed = true;
20
+ error.requiredBoundaries = [...requiredBoundaries];
21
+ error.actualGuarantees = [];
22
+ error.missingBoundaries = [...requiredBoundaries];
23
+ error.sandboxBackend = null;
24
+ error.sandboxCandidateBackend =
25
+ _backgroundTaskCommandDeps.platform === "linux"
26
+ ? "linux-bwrap-workspace"
27
+ : null;
28
+ return error;
29
+ }
30
+
31
+ function normalizeRequiredBoundaries(raw) {
32
+ if (raw === undefined || raw === null || raw === "") return [];
33
+ let parsed;
34
+ try {
35
+ parsed = typeof raw === "string" ? JSON.parse(raw) : raw;
36
+ } catch (cause) {
37
+ const error = sandboxError(
38
+ "ERR_BACKGROUND_TASK_SANDBOX_ENVELOPE_INVALID",
39
+ "background_sandbox_envelope_invalid",
40
+ "Background task sandbox boundary envelope is invalid.",
41
+ );
42
+ error.cause = cause;
43
+ throw error;
44
+ }
45
+ if (!Array.isArray(parsed)) {
46
+ throw sandboxError(
47
+ "ERR_BACKGROUND_TASK_SANDBOX_ENVELOPE_INVALID",
48
+ "background_sandbox_envelope_invalid",
49
+ "Background task sandbox boundaries must use filesystem/network.",
50
+ );
51
+ }
52
+ if (parsed.length === 0) return [];
53
+ if (
54
+ parsed.some(
55
+ (boundary) =>
56
+ typeof boundary !== "string" || !SUPPORTED_BOUNDARIES.has(boundary),
57
+ )
58
+ ) {
59
+ throw sandboxError(
60
+ "ERR_BACKGROUND_TASK_SANDBOX_ENVELOPE_INVALID",
61
+ "background_sandbox_envelope_invalid",
62
+ "Background task sandbox boundaries must use filesystem/network.",
63
+ );
64
+ }
65
+ return [...new Set(parsed)].sort();
66
+ }
67
+
68
+ function canonicalBinding(workspaceCwd, executionCwd, boundaries) {
69
+ try {
70
+ if (
71
+ typeof workspaceCwd !== "string" ||
72
+ !path.isAbsolute(workspaceCwd) ||
73
+ typeof executionCwd !== "string" ||
74
+ !path.isAbsolute(executionCwd)
75
+ ) {
76
+ throw new Error("sandbox paths must be absolute");
77
+ }
78
+ const canonicalRoot = fs.realpathSync.native(workspaceCwd);
79
+ const canonicalCwd = fs.realpathSync.native(executionCwd);
80
+ if (
81
+ canonicalRoot !== workspaceCwd ||
82
+ canonicalCwd !== executionCwd ||
83
+ !fs.statSync(canonicalRoot).isDirectory() ||
84
+ !fs.statSync(canonicalCwd).isDirectory()
85
+ ) {
86
+ throw new Error("sandbox paths must be canonical directories");
87
+ }
88
+ const relative = path.relative(canonicalRoot, canonicalCwd);
89
+ if (
90
+ relative === ".." ||
91
+ relative.startsWith(`..${path.sep}`) ||
92
+ path.isAbsolute(relative)
93
+ ) {
94
+ throw new Error("execution cwd escapes workspace");
95
+ }
96
+ return { workspaceRoot: canonicalRoot, workingDirectory: canonicalCwd };
97
+ } catch (cause) {
98
+ const error = sandboxError(
99
+ "ERR_BACKGROUND_TASK_SANDBOX_BINDING_INVALID",
100
+ "background_sandbox_binding_invalid",
101
+ "Background task sandbox workspace/cwd binding is invalid.",
102
+ boundaries,
103
+ );
104
+ error.cause = cause;
105
+ throw error;
106
+ }
107
+ }
108
+
109
+ function explicitShellInvocation(command) {
110
+ if (_backgroundTaskCommandDeps.platform === "win32") {
111
+ return {
112
+ file: process.env.ComSpec || "cmd.exe",
113
+ args: ["/d", "/s", "/c", command],
114
+ };
115
+ }
116
+ return { file: "/bin/sh", args: ["-c", command] };
117
+ }
118
+
119
+ export function executeBackgroundTaskCommand({
120
+ command,
121
+ cwd,
122
+ type,
123
+ workspaceCwd = "",
124
+ requiredBoundaries = [],
125
+ }) {
126
+ if (
127
+ typeof command !== "string" ||
128
+ command.length === 0 ||
129
+ command.includes("\0")
130
+ ) {
131
+ throw new TypeError("background task command must be non-empty");
132
+ }
133
+ const boundaries = normalizeRequiredBoundaries(requiredBoundaries);
134
+ const hasSandboxEnvelope =
135
+ typeof workspaceCwd === "string" && workspaceCwd.length > 0;
136
+ if (hasSandboxEnvelope !== boundaries.length > 0) {
137
+ throw sandboxError(
138
+ "ERR_BACKGROUND_TASK_SANDBOX_ENVELOPE_INVALID",
139
+ "background_sandbox_envelope_invalid",
140
+ "Background task sandbox root and boundaries must be supplied together.",
141
+ boundaries,
142
+ );
143
+ }
144
+ if (
145
+ boundaries.length > 0 &&
146
+ _backgroundTaskCommandDeps.platform !== "linux"
147
+ ) {
148
+ throw sandboxError(
149
+ "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED",
150
+ "background_platform_backend_unavailable",
151
+ "Background task strong sandbox execution is only available on Linux.",
152
+ boundaries,
153
+ );
154
+ }
155
+
156
+ const commonOptions = {
157
+ cwd: cwd || process.cwd(),
158
+ encoding: "utf-8",
159
+ timeout: 300000,
160
+ maxBuffer: 10 * 1024 * 1024,
161
+ origin: `background-task:command:${type || "unknown"}`,
162
+ policy: "allow",
163
+ scope: "background-task",
164
+ };
165
+ if (boundaries.length === 0) {
166
+ return _backgroundTaskCommandDeps.execSync(command, {
167
+ ...commonOptions,
168
+ shell: true,
169
+ });
170
+ }
171
+
172
+ const binding = canonicalBinding(workspaceCwd, commonOptions.cwd, boundaries);
173
+ const sandboxPolicy = Object.freeze({
174
+ requiredBoundaries: Object.freeze(boundaries),
175
+ });
176
+ const invocation = explicitShellInvocation(command);
177
+ const spawnOptions = {
178
+ ...commonOptions,
179
+ cwd: binding.workingDirectory,
180
+ stdio: ["ignore", "pipe", "pipe"],
181
+ shell: false,
182
+ sandboxPolicy,
183
+ };
184
+ let sandboxExecutionContract;
185
+ try {
186
+ sandboxExecutionContract =
187
+ _backgroundTaskCommandDeps.issueLinuxWorkspaceSandboxExecutionContract(
188
+ invocation.file,
189
+ invocation.args,
190
+ spawnOptions,
191
+ binding.workspaceRoot,
192
+ { sync: false },
193
+ );
194
+ } catch (cause) {
195
+ const error = sandboxError(
196
+ "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED",
197
+ "background_linux_execution_contract_unavailable",
198
+ "Background task could not bind its Linux sandbox contract.",
199
+ boundaries,
200
+ );
201
+ error.cause = cause;
202
+ throw error;
203
+ }
204
+ if (
205
+ _backgroundTaskCommandDeps.platform === "linux" &&
206
+ !sandboxExecutionContract
207
+ ) {
208
+ throw sandboxError(
209
+ "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED",
210
+ "background_linux_execution_contract_unavailable",
211
+ "Background task could not bind its Linux sandbox contract.",
212
+ boundaries,
213
+ );
214
+ }
215
+ return new Promise((resolve, reject) => {
216
+ const options = {
217
+ ...spawnOptions,
218
+ ...(sandboxExecutionContract ? { sandboxExecutionContract } : {}),
219
+ };
220
+ try {
221
+ _backgroundTaskCommandDeps.execFile(
222
+ invocation.file,
223
+ invocation.args,
224
+ options,
225
+ (error, stdout) => {
226
+ if (error) reject(error);
227
+ else resolve(stdout);
228
+ },
229
+ );
230
+ } catch (error) {
231
+ reject(error);
232
+ }
233
+ });
234
+ }