chainlesschain 0.162.181 → 0.162.182

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 (180) hide show
  1. package/package.json +2 -1
  2. package/scripts/build-windows-sandbox-helper.ps1 +163 -0
  3. package/src/assets/web-panel/assets/{AIOps-cq0dwbnf.js → AIOps-DzZ5_xoj.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CvcgGl3w.js → ActionButton-DeLXddIg.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-hM2-jFqg.js → Analytics-rvDCmet1.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-B9_Gsd_g.js → AppLayout-Yt6QVDnp.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-B7bu52Og.js → Artifacts-BS112K5L.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-DThfDgqB.js → Audit-0wJuQrNu.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-DjlFiD4v.js → BackgroundAgents-B90PMgbn.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-CK9xJKnG.js → Backup-TkgMglQQ.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-DEiSU8K8.js → BaseInput-CQVS9p1l.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-CpT96czj.js → Chat-YTjQHoC7.js} +5 -5
  13. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BKPPNmZI.js → ChatBubbleRenderer-PR074hUN.js} +1 -1
  14. package/src/assets/web-panel/assets/{Checkbox-C1GfDnO0.js → Checkbox-5bwaOabq.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-3DAKgiLx.js → Codegen-BFmNQ_Xe.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-74cOwZU1.js → Col-BT_u4Dzp.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-tn9Kkz9j.js → Community-CJP52u5b.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-BcoXH7m4.js → Compact-BpzhJE9i.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-DIPGUBgi.js → Compliance-Cg7rfslp.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-doD5_91c.js → Cowork-JisxL6Yy.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-C-IDvubz.js → Cron-Bu7Ug_MC.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CdcCoBdj.js → Crosschain-CvuqoLdj.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-DdH5aMMA.js → DID-C2u9G8Pu.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-DHLA4mm0.js → Dashboard-BFt5Yv3d.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-dEeCt7Md.js → Dropdown-DIaT9Wxq.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-BMaecFv9.js → EmailListRenderer-D_A601Y4.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DUaUukTN.js → FamilyGuardDashboard--IyQ8I8w.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-CMBE0_rp.js → Federation-BihWHxuY.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-PG-JDbXq.js → FormItemContext-BB8dOXc_.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-Bcb0p88m.js → GenericCardRenderer-DQYhj1HH.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Bgv15myB.js → Git-B-2QZxGf.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-DB8YTArI.js → Governance-CusSb-nG.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-BQMwCWaS.js → Inference-BAjmvPPL.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-B1_ZziiB.js → KnowledgeGraph-DoNYWKYq.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-DovEEnt_.js → Logs-B8fKWD-n.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-D201OL4T.js → MarkdownRenderer-BlJm1J7E.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-BlCXSpyB.js → Marketplace-CyOscbSL.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-CsCR09Wj.js → McpTools-Ex6Om5da.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-CBVRLKno.js → Memory-CDcD8l8r.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C9OIafgA.js → MobileBridge-xfBqoFDg.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-D_zoJ8Xs.js → MobileProjects-BwObMMA2.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-vE-HdvLj.js → Mtc-CIWd36OV.js} +5 -5
  43. package/src/assets/web-panel/assets/{MtcAudit-CPLaekCd.js → MtcAudit-CPX0ouuA.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-C_UP9C2o.js → Multisig-BDJsIUuW.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-2nODJcU1.js → NLProgramming-DEkbuD3N.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-BhE-SJGu.js → Notes-DJpHRhH1.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-D21q7BNU.js → NotificationSettings-C1UZ-Qd5.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-0b62GYOD.js → OrderTableRenderer-GlJtqLjT.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-CEqmw_sb.js → Organization-Bbhj0fac.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-MW-gMDO_.js → Overflow-1H04x3kx.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-CY0hjI_G.js → P2P-CDpPe3et.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-BbWh7Man.js → PdhVaultBrowser-MUX0Bpvw.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-ChqEA_4Q.js → Permissions-A07-0Ci1.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-B3YrbYfD.js → PersonalDataHub-DhhDWxAZ.js} +5 -5
  55. package/src/assets/web-panel/assets/{Pipeline-B8WBhhlW.js → Pipeline-CyfbJfe-.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-Cmb0PXNx.js → Privacy-CNFps3ED.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-hF6zW3Nz.js → ProjectInit--T-u3Dr5.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-BFSVfpW0.js → ProjectSettings-DJmrK2fC.js} +2 -2
  59. package/src/assets/web-panel/assets/{Projects-DAWkVFkc.js → Projects-Qx_MdX9k.js} +1 -1
  60. package/src/assets/web-panel/assets/{Providers-B8yux8Dx.js → Providers-DLzzbOZd.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-N76cQluO.js → QrScannerModal-CexOomKS.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-ClvZ0KYR.js → QuickAsk-QklGi19_.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-B-GfgBpT.js → Recommend-Bb9kwSw8.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-mlglCdQi.js → RemoteSession-DZuVNNN5.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-DJIZzQeG.js → Reputation-Dr5cLP0N.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-COzxu_bb.js → Row-oCQHYv5t.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-CoYsJQuE.js → RssFeed-IFDEykIR.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-DC77Mq9S.js → Search-CspVIxDc.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-Loy2EdMO.js → Security-Bm66o_DH.js} +3 -3
  70. package/src/assets/web-panel/assets/{Services-GUD07Eu0.js → Services-DvanNqXl.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-DWzkptYU.js → Skeleton-CHjEe9_O.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-CEDn1r-Z.js → Skills-Cb8jWjMX.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-ub_k4pXh.js → Sla-DxZm1491.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-D7HLX9CA.js → SpeechSettings-DWxEEclC.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-DbwOvl6m.js → SyncSettings-FIvOFw5p.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-CBQzoAu5.js → Tasks-CyuLnDFR.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-BNVeIhud.js → Templates-CaNjzV_t.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-PS9AzhXU.js → Tenant-DjlP6TmH.js} +1 -1
  79. package/src/assets/web-panel/assets/Terminal-DwzGMniO.js +3 -0
  80. package/src/assets/web-panel/assets/{TimelineRenderer-CrmXMOkg.js → TimelineRenderer-DoZ8y7y8.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-DD-VDHw1.js → Tokens-390cg2TC.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-BsoN_n-n.js → Trigger-CLrtCj5_.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-n8LmN4ZV.js → Trust-DpESfSPn.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-C9_7MImA.js → UkeySign-CN6279O0.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-DyBteNgn.js → VideoEditing-DPtAUlSe.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-BS5ixeXI.js → Wallet-nKOMV_1n.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-spc4UImU.js → WebAuthn-HuXlSOc4.js} +5 -5
  88. package/src/assets/web-panel/assets/{WorkflowEditor-D7iVvaBO.js → WorkflowEditor-CUfFjARi.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-6CmBkHrL.js → chat-6Eq0PcZJ.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-BGoCLkxI.js → colors-BP_Sf6Iy.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-fYZBetMO.js → compact-item-BufMKIh5.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-BeM-1UVj.js → createContext-BBMXxWSW.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-DgVKduH2.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-CE7ZuEnV.js → hasIn-fUK_tRO2.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-QIpnpZgz.js → index-2A5ph8b2.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-BU_2qiDk.js → index-3FuwBewR.js} +1 -1
  97. package/src/assets/web-panel/assets/{index--lap6cf7.js → index-6GmBa4Kg.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-De0quFDw.js → index-B2vS66eI.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-D1r9tT3J.js → index-B7Etk0Te.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-YjcumOZ4.js → index-B9WYSn4m.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-MtOuq2i6.js → index-BHy6yNiF.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-RMZ8a7Yt.js → index-BMLHv389.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-C0v6YKKO.js → index-BWKoBU8R.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-CRnUE8Cb.js → index-Bkg4ZePE.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BsMfoaeo.js → index-C44atv4k.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DoXk5KJ8.js → index-CE2DdTP2.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-B4wiTEOM.js → index-CGjmILDm.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-zb7rVOhV.js → index-CW_G-MXw.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-ATcSr_2O.js → index-CZ6Yt17L.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-C9Y3k0HI.js → index-CeASi4fr.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-B2U-ObMq.js → index-CgiECHu2.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Puq6Luf1.js → index-Cp8vhyZy.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BV551878.js → index-CwSf5pnf.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BowH1eLQ.js → index-D4_MuGkd.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-B3CDgvNW.js → index-D9vU25ij.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-WUrJ6S1j.js → index-DASluSqY.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-CRLjEP1H.js → index-DLpIs_P_.js} +1 -1
  118. package/src/assets/web-panel/assets/index-DOZTSoS7.js +1 -0
  119. package/src/assets/web-panel/assets/{index-DT3zPSVX.js → index-DPdUNk1i.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BunaQCa0.js → index-DVsqvI4M.js} +1 -1
  121. package/src/assets/web-panel/assets/index-DhpvjpqI.js +1 -0
  122. package/src/assets/web-panel/assets/{index-CIpVrf5P.js → index-DmkMXwnR.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-lJBjB1QX.js → index-DocdRcbd.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-BEVm0lCS.js → index-Dyngbd29.js} +19 -19
  125. package/src/assets/web-panel/assets/{index-C4SJVjs4.js → index-GwdRUZ-x.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-ukg99D1V.js → index-LvCBfTLo.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BfPL-m46.js → index-cpEli44X.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CpIGIB85.js → index-fzaMtSJ8.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BNZDILcO.js → index-pum7HYBA.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-Dw1PyYPm.js → index-t8N1tSeX.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-Cip8emOQ.js → index-uCbEN7cY.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DsvfrESp.js → index-wKTLbKyc.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-B8BsdNV_.js → index-wV6iGdpY.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-CYHMs1ag.js → initDefaultProps-V5Fo95FM.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-DDB2Ffk5.js → motion-BYWU0hUT.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-Bg3cD-dX.js → move-Cr1M-J2h.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-B5nedjTS.js → mtc-parser-BysQKi2N.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-BHyuUILu.js → omit-D1zHU8GC.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-C9YQnEN9.js → pickAttrs-CUArxtfi.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-DBUFYUe7.js → placementArrow-ChoYEys0.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-nBs2Obnk.js → responsiveObserve-BQRs3Mo7.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-DkCEaXNU.js → slide-B8zbsCkg.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-aqE1Wi6U.js → statusUtils-C2U8Gs6h.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-CN5bhfHB.js → styleChecker-Dd8MgL_V.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-B_oX_kvJ.js → useFlexGapSupport-hknqY5NH.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-rCuXHeme.js → useFs-CLTAmcfw.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-DZR9Abyd.js → usePersonalDataHub-ByegHbiB.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-ConCYQlX.js → vnode-DqlAy5DP.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CUdDxG5M.js → zoom-DiXiztQn.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/agenda.js +115 -3
  152. package/src/commands/agent.js +6 -0
  153. package/src/data/changelog.json +13 -0
  154. package/src/gateways/terminal/PtyManager.js +45 -4
  155. package/src/gateways/ws/ws-server.js +10 -1
  156. package/src/harness/background-task-manager.js +70 -2
  157. package/src/harness/worktree-isolator.js +14 -3
  158. package/src/lib/agent-core.js +1 -0
  159. package/src/lib/agent-schedule-store.js +45 -22
  160. package/src/lib/hook-runner.js +6 -2
  161. package/src/lib/packer/pkg-config-generator.js +3 -1
  162. package/src/lib/plugin-runtime/bin.js +1148 -70
  163. package/src/lib/plugin-runtime/manifest.js +68 -12
  164. package/src/lib/plugin-runtime/scopes.js +20 -10
  165. package/src/lib/process-execution-broker/index.js +375 -48
  166. package/src/lib/process-execution-broker/platform-sandbox.js +3831 -276
  167. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  168. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  169. package/src/lib/process-execution-broker/windows-sandbox.cs +3856 -0
  170. package/src/lib/repl-bang-memorize.js +67 -10
  171. package/src/lib/slash-commands.js +27 -4
  172. package/src/repl/agent-repl.js +4 -3
  173. package/src/runtime/agent-core.js +376 -52
  174. package/src/runtime/agent-runtime.js +13 -1
  175. package/src/runtime/headless-runner.js +4 -3
  176. package/src/assets/web-panel/assets/Terminal-Cgb4eLB_.js +0 -3
  177. package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +0 -1
  178. package/src/assets/web-panel/assets/index-DacrAdc-.js +0 -1
  179. package/src/assets/web-panel/assets/index-EHzNJozo.js +0 -1
  180. package/src/lib/process-execution-broker/windows-sandbox.ps1 +0 -999
@@ -151,6 +151,56 @@ function runCodeProcess(file, args, options = {}, origin = "run-code") {
151
151
  });
152
152
  }
153
153
 
154
+ function collectWorkspacePluginBinSandboxPolicy(
155
+ pluginBin,
156
+ workspaceCwd,
157
+ executionCwd = workspaceCwd,
158
+ ) {
159
+ const resolvedWorkspaceCwd = path.resolve(workspaceCwd);
160
+ const pluginPolicyBoundaries = new Set();
161
+ for (const policyCwd of new Set([
162
+ resolvedWorkspaceCwd,
163
+ path.resolve(executionCwd),
164
+ ])) {
165
+ const observedPolicy = pluginBin.collectPluginBinSandboxPolicy({
166
+ cwd: policyCwd,
167
+ });
168
+ for (const boundary of observedPolicy?.requiredBoundaries || []) {
169
+ pluginPolicyBoundaries.add(boundary);
170
+ }
171
+ }
172
+ return pluginBin.pinPluginBinSandboxPolicy(
173
+ { requiredBoundaries: [...pluginPolicyBoundaries] },
174
+ { cwd: resolvedWorkspaceCwd },
175
+ );
176
+ }
177
+
178
+ function rethrowRunCodeSandboxFailure(error) {
179
+ if (
180
+ error?.sandboxFailClosed === true ||
181
+ (typeof error?.code === "string" &&
182
+ error.code.startsWith("ERR_PROCESS_SANDBOX"))
183
+ ) {
184
+ throw error;
185
+ }
186
+ }
187
+
188
+ function createPythonInterpreterProbeSandboxFailure(sandboxPolicy) {
189
+ const requiredBoundaries = [...(sandboxPolicy?.requiredBoundaries || [])];
190
+ const error = new Error(
191
+ `Python interpreter discovery cannot run without its required sandbox boundaries: ${requiredBoundaries.join(", ")}`,
192
+ );
193
+ error.code = "ERR_PROCESS_SANDBOX_BOUNDARY_UNSATISFIED";
194
+ error.sandboxReason = "python_interpreter_probe_requires_sandbox";
195
+ error.sandboxFailClosed = true;
196
+ error.requiredBoundaries = requiredBoundaries;
197
+ error.actualGuarantees = [];
198
+ error.missingBoundaries = [...requiredBoundaries];
199
+ error.sandboxBackend = null;
200
+ error.sandboxCandidateBackend = null;
201
+ return error;
202
+ }
203
+
154
204
  // ─── Background shell tasks ────────────────────────────────────────────────
155
205
  //
156
206
  // run_shell is synchronous (execSync) and capped at a foreground timeout, which
@@ -839,6 +889,10 @@ export function getCachedPython() {
839
889
  return _cachedPython;
840
890
  }
841
891
 
892
+ export function _resetCachedPythonForTests() {
893
+ _cachedPython = null;
894
+ }
895
+
842
896
  /**
843
897
  * Gather environment info (cached once per process).
844
898
  * @returns {{ os: string, arch: string, python: string|null, pip: boolean, node: string|null, git: boolean }}
@@ -1189,10 +1243,7 @@ function agentFileToolPathRequests(name, args = {}, workspaceRoots = []) {
1189
1243
  case "notebook_edit":
1190
1244
  return one("path", "write");
1191
1245
  case "move_file":
1192
- return [
1193
- ...one("path", "write"),
1194
- ...one("target_path", "write"),
1195
- ];
1246
+ return [...one("path", "write"), ...one("target_path", "write")];
1196
1247
  case "list_dir":
1197
1248
  return [
1198
1249
  {
@@ -1234,10 +1285,7 @@ function agentFileToolPathRequests(name, args = {}, workspaceRoots = []) {
1234
1285
  }
1235
1286
 
1236
1287
  function guardAgentFileToolPaths(name, args, context, cwd) {
1237
- const workspaceRoots = workspaceRootsFor(
1238
- cwd,
1239
- context.additionalDirectories,
1240
- );
1288
+ const workspaceRoots = workspaceRootsFor(cwd, context.additionalDirectories);
1241
1289
  const requests = agentFileToolPathRequests(name, args || {}, workspaceRoots);
1242
1290
  for (const request of requests) {
1243
1291
  const verdict = resolveSandboxPolicyPath(request.path, {
@@ -3471,25 +3519,117 @@ async function executeToolInner(
3471
3519
  : {}
3472
3520
  : { shell: shellInv.kind };
3473
3521
 
3474
- // PATH-based plugin binaries need explicit provenance at the Broker
3475
- // boundary; otherwise a trusted plugin executable is indistinguishable
3476
- // from an ambient system command in the process audit log.
3477
- let pluginBinProvenance = null;
3522
+ // Policy-bearing plugin bins never enter PATH. Their declared alias is
3523
+ // accepted only as one direct command: resolve it to literal argv, attest
3524
+ // the exact target, then give Broker an absolute command with shell:false.
3525
+ // Resolver failures for a matching strict alias are terminal — falling
3526
+ // back to a shell would bypass target identity and manifest requirements.
3527
+ let pluginBinInvocation = null;
3528
+ let reattestPluginBinInvocation = null;
3529
+ let pluginBinSandboxPolicy = null;
3530
+ let pluginBinSandboxExecutionContract = null;
3478
3531
  try {
3479
- const { resolvePluginBinCommand } =
3480
- await import("../lib/plugin-runtime/bin.js");
3481
- pluginBinProvenance = resolvePluginBinCommand(args.command, { cwd });
3482
- } catch {
3483
- pluginBinProvenance = null;
3532
+ const pluginBin = await import("../lib/plugin-runtime/bin.js");
3533
+ reattestPluginBinInvocation = pluginBin.reattestPluginBinInvocation;
3534
+ pluginBinSandboxPolicy = collectWorkspacePluginBinSandboxPolicy(
3535
+ pluginBin,
3536
+ cwd,
3537
+ args.cwd || cwd,
3538
+ );
3539
+ pluginBinInvocation = pluginBin.resolvePluginBinInvocation(
3540
+ args.command,
3541
+ {
3542
+ cwd,
3543
+ commandCwd: args.cwd || cwd,
3544
+ },
3545
+ );
3546
+ if (pluginBinInvocation?.sandboxPolicy) {
3547
+ pluginBinSandboxPolicy = pluginBin.pinPluginBinSandboxPolicy(
3548
+ {
3549
+ requiredBoundaries: [
3550
+ ...(pluginBinSandboxPolicy?.requiredBoundaries || []),
3551
+ ...(pluginBinInvocation.sandboxPolicy.requiredBoundaries || []),
3552
+ ],
3553
+ },
3554
+ { cwd },
3555
+ );
3556
+ if (
3557
+ process.platform === "linux" ||
3558
+ (process.platform === "win32" &&
3559
+ pluginBinInvocation.runtime === "node")
3560
+ ) {
3561
+ try {
3562
+ pluginBinSandboxExecutionContract =
3563
+ pluginBin.createPluginSandboxExecutionContract(
3564
+ pluginBinInvocation,
3565
+ );
3566
+ } catch (error) {
3567
+ if (error?.pluginBinFailClosed) throw error;
3568
+ const contractError = new Error(
3569
+ `plugin sandbox execution contract could not be created: ${error.message}`,
3570
+ );
3571
+ contractError.code = "ERR_PLUGIN_SANDBOX_CONTRACT_UNATTESTED";
3572
+ contractError.pluginBinFailClosed = true;
3573
+ throw contractError;
3574
+ }
3575
+ }
3576
+ }
3577
+ } catch (err) {
3578
+ if (err?.pluginBinFailClosed) {
3579
+ const policyVia =
3580
+ err.code === "ERR_PLUGIN_BIN_DISCOVERY_FAILED"
3581
+ ? "plugin-bin-pinned-sandbox-policy"
3582
+ : "plugin-bin-direct-invocation";
3583
+ return attachDescriptor(
3584
+ {
3585
+ error: `[Plugin bin] ${err.message}`,
3586
+ policy: {
3587
+ decision: "deny",
3588
+ via: policyVia,
3589
+ reason: err.code || "plugin_bin_resolution_failed",
3590
+ },
3591
+ shellCommandPolicy: shellPolicy,
3592
+ approval: approvalOutcome,
3593
+ },
3594
+ override || runtimeDescriptor,
3595
+ );
3596
+ }
3597
+ pluginBinInvocation = null;
3484
3598
  }
3485
- const processOrigin = pluginBinProvenance
3599
+ const processOrigin = pluginBinInvocation
3486
3600
  ? "plugin:bin"
3487
3601
  : "tool:run_shell";
3488
- const processProvenance = pluginBinProvenance
3602
+ const processProvenance = {
3603
+ ...(pluginBinInvocation
3604
+ ? {
3605
+ pluginId: pluginBinInvocation.pluginId,
3606
+ pluginVersion: pluginBinInvocation.pluginVersion,
3607
+ pluginSource: pluginBinInvocation.pluginSource,
3608
+ pluginExecutableIdentity: pluginBinInvocation.executableIdentity,
3609
+ }
3610
+ : {}),
3611
+ ...(pluginBinSandboxPolicy
3612
+ ? { sandboxPolicy: pluginBinSandboxPolicy }
3613
+ : {}),
3614
+ ...(pluginBinSandboxExecutionContract
3615
+ ? {
3616
+ sandboxExecutionContract: pluginBinSandboxExecutionContract,
3617
+ }
3618
+ : {}),
3619
+ };
3620
+ const pluginBinResult = pluginBinInvocation
3489
3621
  ? {
3490
- pluginId: pluginBinProvenance.pluginId,
3491
- pluginVersion: pluginBinProvenance.pluginVersion,
3492
- pluginSource: pluginBinProvenance.pluginSource,
3622
+ plugin_bin: {
3623
+ plugin: pluginBinInvocation.pluginId,
3624
+ version: pluginBinInvocation.pluginVersion,
3625
+ name: pluginBinInvocation.binName,
3626
+ target: pluginBinInvocation.binPath,
3627
+ runtime: pluginBinInvocation.runtime,
3628
+ sha256: pluginBinInvocation.executableIdentity.sha256,
3629
+ identity_attested: true,
3630
+ launch_identity_reattested: false,
3631
+ direct_argv: true,
3632
+ },
3493
3633
  }
3494
3634
  : {};
3495
3635
 
@@ -3504,6 +3644,23 @@ async function executeToolInner(
3504
3644
  policy: { decision: "deny", via: "sandbox" },
3505
3645
  });
3506
3646
  }
3647
+ if (
3648
+ (process.platform === "linux" || process.platform === "win32") &&
3649
+ pluginBinSandboxPolicy?.requiredBoundaries?.length > 0
3650
+ ) {
3651
+ return attachDescriptor({
3652
+ error:
3653
+ "[Plugin bin] The current strong plugin boundary supports foreground execution only; background execution is fail-closed until Broker-owned process-tree teardown is available.",
3654
+ policy: {
3655
+ decision: "deny",
3656
+ via: "plugin-bin-pinned-sandbox-policy",
3657
+ reason: "background_execution_unsupported",
3658
+ },
3659
+ ...pluginBinResult,
3660
+ shellCommandPolicy: shellPolicy,
3661
+ approval: approvalOutcome,
3662
+ });
3663
+ }
3507
3664
  // Free memory from idle background tasks before adding another, so a
3508
3665
  // long agent run can't accumulate forgotten dev servers (no-op unless
3509
3666
  // the machine is actually under memory pressure).
@@ -3559,9 +3716,29 @@ async function executeToolInner(
3559
3716
  scope: "agent",
3560
3717
  ...processProvenance,
3561
3718
  };
3562
- const child = shellInv.useDefaultShell
3563
- ? broker.spawn(args.command, [], brokerOpts)
3564
- : broker.spawn(shellInv.file, shellInv.argv, brokerOpts);
3719
+ let child;
3720
+ if (pluginBinInvocation) {
3721
+ reattestPluginBinInvocation(pluginBinInvocation);
3722
+ pluginBinResult.plugin_bin.launch_identity_reattested = true;
3723
+ child = broker.spawn(
3724
+ pluginBinSandboxExecutionContract?.kind ===
3725
+ "strict-plugin-node-bin"
3726
+ ? pluginBinSandboxExecutionContract.runtimePath
3727
+ : pluginBinInvocation.command,
3728
+ pluginBinInvocation.args,
3729
+ {
3730
+ ...brokerOpts,
3731
+ cwd:
3732
+ pluginBinSandboxExecutionContract?.workingDirectory ||
3733
+ brokerOpts.cwd,
3734
+ shell: false,
3735
+ },
3736
+ );
3737
+ } else {
3738
+ child = shellInv.useDefaultShell
3739
+ ? broker.spawn(args.command, [], brokerOpts)
3740
+ : broker.spawn(shellInv.file, shellInv.argv, brokerOpts);
3741
+ }
3565
3742
  task.child = child;
3566
3743
  if (child.stdout) {
3567
3744
  child.stdout.setEncoding("utf8");
@@ -3612,6 +3789,7 @@ async function executeToolInner(
3612
3789
  status: task.status,
3613
3790
  command: task.command,
3614
3791
  ...shellMeta,
3792
+ ...pluginBinResult,
3615
3793
  hint: "Poll output and completion with the check_shell tool using this task_id. Kill long-lived servers with check_shell { task_id, kill: true } when done.",
3616
3794
  shellCommandPolicy: shellPolicy,
3617
3795
  approval: approvalOutcome,
@@ -3621,6 +3799,23 @@ async function executeToolInner(
3621
3799
  }
3622
3800
 
3623
3801
  if (sandbox) {
3802
+ if (pluginBinSandboxPolicy) {
3803
+ return attachDescriptor(
3804
+ {
3805
+ error:
3806
+ "[Plugin bin] A strict plugin bin policy cannot be combined with the legacy ephemeral shell sandbox. Run without that sandbox so the ProcessExecutionBroker can enforce the pinned plugin boundary union.",
3807
+ policy: {
3808
+ decision: "deny",
3809
+ via: "plugin-bin-pinned-sandbox-policy",
3810
+ reason: "conflicting_sandbox_routes",
3811
+ },
3812
+ ...pluginBinResult,
3813
+ shellCommandPolicy: shellPolicy,
3814
+ approval: approvalOutcome,
3815
+ },
3816
+ override || runtimeDescriptor,
3817
+ );
3818
+ }
3624
3819
  const { executeSandboxedShell, sandboxSummary } =
3625
3820
  await import("../lib/agent-sandbox.js");
3626
3821
  // Domain-restricted networking is ENFORCED by routing the sandboxed
@@ -3741,7 +3936,35 @@ async function executeToolInner(
3741
3936
  scope: "agent",
3742
3937
  ...processProvenance,
3743
3938
  };
3744
- if (shellInv.useDefaultShell) {
3939
+ if (pluginBinInvocation) {
3940
+ reattestPluginBinInvocation(pluginBinInvocation);
3941
+ pluginBinResult.plugin_bin.launch_identity_reattested = true;
3942
+ const res = broker.spawnSync(
3943
+ pluginBinSandboxExecutionContract?.kind === "strict-plugin-node-bin"
3944
+ ? pluginBinSandboxExecutionContract.runtimePath
3945
+ : pluginBinInvocation.command,
3946
+ pluginBinInvocation.args,
3947
+ {
3948
+ ...brokerExecOpts,
3949
+ cwd:
3950
+ pluginBinSandboxExecutionContract?.workingDirectory ||
3951
+ brokerExecOpts.cwd,
3952
+ shell: false,
3953
+ windowsHide: true,
3954
+ },
3955
+ );
3956
+ if (res.error) throw res.error;
3957
+ if (res.status !== 0) {
3958
+ const e = new Error(
3959
+ `Plugin bin failed (exit ${res.status}): ${pluginBinInvocation.binName}`,
3960
+ );
3961
+ e.status = res.status;
3962
+ e.stdout = res.stdout;
3963
+ e.stderr = res.stderr;
3964
+ throw e;
3965
+ }
3966
+ output = res.stdout ?? "";
3967
+ } else if (shellInv.useDefaultShell) {
3745
3968
  output = broker.execSync(args.command, brokerExecOpts);
3746
3969
  } else {
3747
3970
  // PowerShell route: explicit argv, no intermediate default shell.
@@ -3783,6 +4006,7 @@ async function executeToolInner(
3783
4006
  {
3784
4007
  stdout: output.substring(0, 30000),
3785
4008
  ...shellMeta,
4009
+ ...pluginBinResult,
3786
4010
  shellCommandPolicy: shellPolicy,
3787
4011
  approval: approvalOutcome,
3788
4012
  },
@@ -3803,6 +4027,7 @@ async function executeToolInner(
3803
4027
  stderr: (err.stderr || "").substring(0, 2000),
3804
4028
  exitCode: err.status,
3805
4029
  ...shellMeta,
4030
+ ...pluginBinResult,
3806
4031
  shellCommandPolicy: shellPolicy,
3807
4032
  approval: approvalOutcome,
3808
4033
  },
@@ -4315,6 +4540,9 @@ async function executeToolInner(
4315
4540
  : 60000;
4316
4541
  const entry = store.createMonitor({
4317
4542
  command: args.command,
4543
+ // Bind the persisted command to the host/session workspace. This
4544
+ // value comes from executeTool's trusted context, never model args.
4545
+ workspaceCwd: path.resolve(cwd),
4318
4546
  intervalMs,
4319
4547
  stopWhen: args.stop_when || null,
4320
4548
  notify: args.notify_title ? { title: args.notify_title } : null,
@@ -5160,6 +5388,54 @@ async function _executeRunCode(args, cwd) {
5160
5388
  };
5161
5389
  }
5162
5390
 
5391
+ // Every agent-generated interpreter process inherits the tighten-only union
5392
+ // of strict Plugin bin boundaries visible from this workspace. Discover and
5393
+ // pin it before creating a persistent directory, writing a temporary script,
5394
+ // or probing an interpreter so discovery failure cannot fall through to an
5395
+ // unbounded native spawn.
5396
+ let pluginBinSandboxPolicy = null;
5397
+ try {
5398
+ const pluginBin = await import("../lib/plugin-runtime/bin.js");
5399
+ pluginBinSandboxPolicy = collectWorkspacePluginBinSandboxPolicy(
5400
+ pluginBin,
5401
+ cwd,
5402
+ );
5403
+ } catch (error) {
5404
+ return {
5405
+ error: `[Plugin bin] ${error.message}`,
5406
+ policy: {
5407
+ decision: "deny",
5408
+ via: "plugin-bin-pinned-sandbox-policy",
5409
+ reason: error.code || "ERR_PLUGIN_BIN_SANDBOX_POLICY_DISCOVERY_FAILED",
5410
+ },
5411
+ };
5412
+ }
5413
+ const pluginBinSandboxOptions = pluginBinSandboxPolicy
5414
+ ? { sandboxPolicy: pluginBinSandboxPolicy }
5415
+ : {};
5416
+
5417
+ // cli-anything's Python discovery probes candidate executables through its
5418
+ // own Broker call. That probe cannot inherit this run_code invocation's
5419
+ // pinned Plugin sandbox policy, so never launch it when strict boundaries
5420
+ // are required. A previously cached interpreter is safe to execute here
5421
+ // because the real script (and any pip/retry process) still goes through
5422
+ // runCodeProcess with the exact pinned policy below.
5423
+ let cachedPythonInterpreter = null;
5424
+ if (
5425
+ lang === "python" &&
5426
+ pluginBinSandboxPolicy?.requiredBoundaries?.length > 0
5427
+ ) {
5428
+ if (
5429
+ _cachedPython?.found === true &&
5430
+ typeof _cachedPython.command === "string" &&
5431
+ _cachedPython.command.trim()
5432
+ ) {
5433
+ cachedPythonInterpreter = _cachedPython.command;
5434
+ } else {
5435
+ throw createPythonInterpreterProbeSandboxFailure(pluginBinSandboxPolicy);
5436
+ }
5437
+ }
5438
+
5163
5439
  // Determine script path
5164
5440
  let scriptPath;
5165
5441
  if (persist) {
@@ -5182,8 +5458,12 @@ async function _executeRunCode(args, cwd) {
5182
5458
  // Determine interpreter
5183
5459
  let interpreter;
5184
5460
  if (lang === "python") {
5185
- const py = getCachedPython();
5186
- interpreter = py.found ? py.command : "python";
5461
+ if (cachedPythonInterpreter) {
5462
+ interpreter = cachedPythonInterpreter;
5463
+ } else {
5464
+ const py = getCachedPython();
5465
+ interpreter = py.found ? py.command : "python";
5466
+ }
5187
5467
  } else if (lang === "node") {
5188
5468
  interpreter = "node";
5189
5469
  } else {
@@ -5198,8 +5478,13 @@ async function _executeRunCode(args, cwd) {
5198
5478
  encoding: "utf8",
5199
5479
  timeout: timeoutSec * 1000,
5200
5480
  maxBuffer: 5 * 1024 * 1024,
5481
+ ...pluginBinSandboxOptions,
5201
5482
  });
5202
5483
  } catch (err) {
5484
+ // Broker boundary errors carry the required/actual/missing guarantees and
5485
+ // backend attestation. Preserve that exact structured error for callers
5486
+ // instead of flattening it into run_code's generic runtime classifier.
5487
+ rethrowRunCodeSandboxFailure(err);
5203
5488
  const stderr = (err.stderr || "").toString();
5204
5489
  const message = err.message || "";
5205
5490
  const classified = classifyError(stderr, message, err.status, lang);
@@ -5291,6 +5576,36 @@ async function _executeRunCode(args, cwd) {
5291
5576
  /* unified audit must never affect the install itself */
5292
5577
  }
5293
5578
 
5579
+ const autoInstallFailure = (installError) => {
5580
+ recordInstallAudit({
5581
+ package: packageName,
5582
+ interpreter,
5583
+ cwd,
5584
+ outcome: "failed",
5585
+ detail: (
5586
+ installError.stderr ||
5587
+ installError.message ||
5588
+ ""
5589
+ ).substring(0, 200),
5590
+ });
5591
+ auditUnifiedInstall(
5592
+ "failed",
5593
+ (installError.stderr || installError.message || "").substring(
5594
+ 0,
5595
+ 200,
5596
+ ),
5597
+ );
5598
+ return {
5599
+ error: (stderr || message).substring(0, 5000),
5600
+ stderr: stderr.substring(0, 5000),
5601
+ exitCode: err.status,
5602
+ language: lang,
5603
+ ...classified,
5604
+ hint: `Failed to auto-install "${packageName}". ${(installError.stderr || installError.message || "").substring(0, 500)}`,
5605
+ scriptPath: persist ? scriptPath : undefined,
5606
+ };
5607
+ };
5608
+
5294
5609
  // Attempt pip install
5295
5610
  try {
5296
5611
  runCodeProcess(
@@ -5302,18 +5617,27 @@ async function _executeRunCode(args, cwd) {
5302
5617
  timeout: 120000,
5303
5618
  maxBuffer: 2 * 1024 * 1024,
5304
5619
  stdio: ["pipe", "pipe", "pipe"],
5620
+ ...pluginBinSandboxOptions,
5305
5621
  },
5306
5622
  "run-code-install",
5307
5623
  );
5308
- recordInstallAudit({
5309
- package: packageName,
5310
- interpreter,
5311
- cwd,
5312
- outcome: "installed",
5313
- });
5314
- auditUnifiedInstall("installed");
5624
+ } catch (pipErr) {
5625
+ const failure = autoInstallFailure(pipErr);
5626
+ rethrowRunCodeSandboxFailure(pipErr);
5627
+ return failure;
5628
+ }
5629
+ recordInstallAudit({
5630
+ package: packageName,
5631
+ interpreter,
5632
+ cwd,
5633
+ outcome: "installed",
5634
+ });
5635
+ auditUnifiedInstall("installed");
5315
5636
 
5316
- // Retry execution
5637
+ // Keep retry separate from the install catch: either Broker call can
5638
+ // carry an independently attested fail-closed boundary error, and
5639
+ // neither may be flattened into the legacy auto-install result.
5640
+ try {
5317
5641
  const retryStart = Date.now();
5318
5642
  const retryOutput = runCodeProcess(
5319
5643
  interpreter,
@@ -5323,6 +5647,7 @@ async function _executeRunCode(args, cwd) {
5323
5647
  encoding: "utf8",
5324
5648
  timeout: timeoutSec * 1000,
5325
5649
  maxBuffer: 5 * 1024 * 1024,
5650
+ ...pluginBinSandboxOptions,
5326
5651
  },
5327
5652
  "run-code-retry",
5328
5653
  );
@@ -5336,25 +5661,24 @@ async function _executeRunCode(args, cwd) {
5336
5661
  autoInstalled: [packageName],
5337
5662
  scriptPath: persist ? scriptPath : undefined,
5338
5663
  };
5339
- } catch (pipErr) {
5340
- recordInstallAudit({
5341
- package: packageName,
5342
- interpreter,
5343
- cwd,
5344
- outcome: "failed",
5345
- detail: (pipErr.stderr || pipErr.message || "").substring(0, 200),
5346
- });
5347
- auditUnifiedInstall(
5348
- "failed",
5349
- (pipErr.stderr || pipErr.message || "").substring(0, 200),
5664
+ } catch (retryErr) {
5665
+ rethrowRunCodeSandboxFailure(retryErr);
5666
+ const retryStderr = (retryErr.stderr || "").toString();
5667
+ const retryMessage = retryErr.message || "";
5668
+ const retryClassified = classifyError(
5669
+ retryStderr,
5670
+ retryMessage,
5671
+ retryErr.status,
5672
+ lang,
5350
5673
  );
5351
5674
  return {
5352
- error: (stderr || message).substring(0, 5000),
5353
- stderr: stderr.substring(0, 5000),
5354
- exitCode: err.status,
5675
+ error: (retryStderr || retryMessage).substring(0, 5000),
5676
+ stderr: retryStderr.substring(0, 5000),
5677
+ exitCode: retryErr.status,
5355
5678
  language: lang,
5356
- ...classified,
5357
- hint: `Failed to auto-install "${packageName}". ${(pipErr.stderr || pipErr.message || "").substring(0, 500)}`,
5679
+ ...retryClassified,
5680
+ hint: `Package "${packageName}" was installed, but the script retry failed.`,
5681
+ autoInstalled: [packageName],
5358
5682
  scriptPath: persist ? scriptPath : undefined,
5359
5683
  };
5360
5684
  }
@@ -23,6 +23,7 @@ import { MCPClient, MCPServerConfig } from "../harness/mcp-client.js";
23
23
  import sharedManagedToolPolicy from "./coding-agent-managed-tool-policy.cjs";
24
24
  import { findProjectRoot, loadProjectConfig } from "../lib/project-detector.js";
25
25
  import { loadConfig } from "../lib/config-manager.js";
26
+ import { collectWorkspacePluginBinSandboxPolicy } from "../lib/plugin-runtime/bin.js";
26
27
 
27
28
  const {
28
29
  DEFAULT_ALLOWED_MCP_SERVER_NAMES,
@@ -63,6 +64,8 @@ export class AgentRuntime {
63
64
  createSessionManager:
64
65
  deps.createSessionManager ||
65
66
  ((options) => new WSSessionManager(options)),
67
+ createPtyManager:
68
+ deps.createPtyManager || ((options) => new PtyManager(options)),
66
69
  createMcpClient: deps.createMcpClient || (() => new MCPClient()),
67
70
  createMcpServerConfig:
68
71
  deps.createMcpServerConfig || ((db) => new MCPServerConfig(db)),
@@ -449,6 +452,7 @@ export class AgentRuntime {
449
452
  const projectName =
450
453
  projectConfig?.name || (projectRoot ? path.basename(projectRoot) : null);
451
454
  const mode = projectRoot ? "project" : "global";
455
+ const workspacePolicyCwd = path.resolve(projectRoot || process.cwd());
452
456
 
453
457
  let db = null;
454
458
  let rawDb = null;
@@ -492,6 +496,7 @@ export class AgentRuntime {
492
496
  maxConnections: 20,
493
497
  timeout: 60000,
494
498
  sessionManager,
499
+ projectRoot: workspacePolicyCwd,
495
500
  });
496
501
  // ChainlessChainWSServer extends EventEmitter and emits "error"
497
502
  // synchronously on bind failure (in addition to rejecting start()).
@@ -530,7 +535,14 @@ export class AgentRuntime {
530
535
  // matching topics through `terminalHandlers.handlers`, falling back to
531
536
  // the original CLI dispatcher for everything else.
532
537
  const wsBroadcastRef = { current: null };
533
- const ptyManager = new PtyManager();
538
+ const ptyManager = this.deps.createPtyManager({
539
+ policyCwd: workspacePolicyCwd,
540
+ resolveSandboxPolicy: ({ workspaceCwd, executionCwd }) =>
541
+ collectWorkspacePluginBinSandboxPolicy({
542
+ workspaceCwd,
543
+ executionCwd,
544
+ }),
545
+ });
534
546
  const terminal = createTerminalHandlers({
535
547
  ptyManager,
536
548
  broadcast: (frame) => wsBroadcastRef.current?.(frame),
@@ -433,9 +433,10 @@ export async function runAgentHeadless(options = {}, deps = {}) {
433
433
  }
434
434
  }
435
435
 
436
- // Put trusted plugins' bin/ executables on PATH for this headless run (Phase
437
- // 3.3n) so run_shell can invoke them by name. Trust-gated. The process exits
438
- // at the end of the run, so no explicit restore is needed.
436
+ // Preserve PATH compatibility for trusted legacy bin components that have no
437
+ // sandboxPolicy. Policy-bearing bins are excluded here and resolved as exact
438
+ // direct Broker invocations by agent-core. The process exits at the end of
439
+ // the run, so no explicit restore is needed.
439
440
  try {
440
441
  const { applyPluginBinPath } = await import("../lib/plugin-runtime/bin.js");
441
442
  applyPluginBinPath({ cwd });
@@ -1,3 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./xterm-BZcWGsqw.js","./markdown-CsiA8-E5.js","./markdown-Dfs9RUU9.css","./addon-fit-CK6X9sAG.js","./xterm-DFuMZ0ql.css"])))=>i.map(i=>d[i]);
2
- import{u as fe,_ as me,d as U,e as V}from"./index-BEVm0lCS.js";import{I as z,J as x,U as _,Q as D,S as K,K as T,V as R,c as A,F as Q,Z,R as E,o as G,f as H,w as $,n as q,b as ee,r as S,P as y,_ as ve,a2 as we,a3 as he,a4 as _e}from"./vendor-Bn1JzzAn.js";import{R as ye,b as pe,at as ge}from"./icons-DG5UD-6K.js";const k=new Map,C=new Map,F=new Set,N=new Set;let te=!1;function xe(c){te||(te=!0,c.onMessage(o=>{if(!(!o||typeof o.type!="string")){if(o.type==="terminal.stdout"){const{sessionId:s,data:e,seq:i}=o.payload||{};if(!s)return;let w;try{const d=atob(e||""),f=new Uint8Array(d.length);for(let n=0;n<d.length;n++)f[n]=d.charCodeAt(n);w=new TextDecoder("utf-8").decode(f)}catch{w=""}const u={sessionId:s,data:w,seq:i};k.get(s)?.forEach(d=>d(u)),F.forEach(d=>d(u))}else if(o.type==="terminal.exit"){const{sessionId:s,exitCode:e,signal:i}=o.payload||{};if(!s)return;const w={sessionId:s,exitCode:e,signal:i};C.get(s)?.forEach(u=>u(w)),N.forEach(u=>u(w))}}}))}function ne(c){const o=new TextEncoder().encode(c);let s="";for(let e=0;e<o.length;e++)s+=String.fromCharCode(o[e]);return btoa(s)}function ae(c){const o=atob(c||""),s=new Uint8Array(o.length);for(let e=0;e<o.length;e++)s[e]=o.charCodeAt(e);return new TextDecoder("utf-8").decode(s)}function oe(){const c=fe();xe(c);async function o(n={}){const a=await c.sendRaw({type:"terminal.create",payload:{shell:n.shell,cwd:n.cwd,env:n.env,cols:n.cols,rows:n.rows}});if(a.ok===!1)throw new Error(a.error||"terminal_create_failed");return a.result??a}async function s(){const n=await c.sendRaw({type:"terminal.list",payload:{}});if(n.ok===!1)throw new Error(n.error||"terminal_list_failed");const a=n.result??n;return Array.isArray(a.sessions)?a.sessions:[]}async function e(n,a){const r=await c.sendRaw({type:"terminal.stdin",payload:{sessionId:n,data:ne(String(a))}});if(r.ok===!1)throw new Error(r.error||"terminal_stdin_failed");return r.result??r}async function i(n,a,r){const h=await c.sendRaw({type:"terminal.resize",payload:{sessionId:n,cols:a,rows:r}});if(h.ok===!1)throw new Error(h.error||"terminal_resize_failed");return h.result??h}async function w(n){const a=await c.sendRaw({type:"terminal.close",payload:{sessionId:n}});if(a.ok===!1)throw new Error(a.error||"terminal_close_failed");return a.result??a}async function u(n,a=0){const r=await c.sendRaw({type:"terminal.history",payload:{sessionId:n,fromSeq:a}});if(r.ok===!1)throw new Error(r.error||"terminal_history_failed");const h=r.result??r;return{truncated:!!h.truncated,chunks:(h.chunks||[]).map(L=>({seq:L.seq,data:ae(L.data)}))}}function d(n,a){return n?(k.has(n)||k.set(n,new Set),k.get(n).add(a),()=>{k.get(n)?.delete(a),k.get(n)?.size===0&&k.delete(n)}):(F.add(a),()=>F.delete(a))}function f(n,a){return n?(C.has(n)||C.set(n,new Set),C.get(n).add(a),()=>{C.get(n)?.delete(a),C.get(n)?.size===0&&C.delete(n)}):(N.add(a),()=>N.delete(a))}return{create:o,list:s,stdin:e,resize:i,close:w,history:u,onStdout:d,onExit:f,_internal:{stdoutSubs:k,exitSubs:C,toBase64Utf8:ne,fromBase64Utf8:ae}}}const Se={__name:"Terminal",setup(c,{expose:o}){o();const s=oe(),e=S([]),i=S(null),w=S("pwsh"),u=S(!1),d=S(!1),f=S(""),n=S(""),a=S([]),r=[{value:"pwsh",label:"PowerShell"},{value:"cmd",label:"CMD"},{value:"bash",label:"Bash"},{value:"wsl",label:"WSL"}],h=ee(()=>e.value.find(t=>t.id===i.value));function L(t){return t?t.slice(0,8):""}let O=null,M=null;async function I(){if(O)return{xtermMod:O,fitAddonMod:M};try{O=await V(()=>import("./xterm-BZcWGsqw.js").then(t=>t.x),__vite__mapDeps([0,1,2]),import.meta.url),M=await V(()=>import("./addon-fit-CK6X9sAG.js").then(t=>t.a),__vite__mapDeps([3,1,2]),import.meta.url),await V(()=>Promise.resolve({}),__vite__mapDeps([4]),import.meta.url)}catch(t){throw n.value="xterm 资源加载失败:"+(t?.message||"未知错误"),t}return{xtermMod:O,fitAddonMod:M}}async function B(t){await q();const{xtermMod:l,fitAddonMod:p}=await I(),b=a.value.find(v=>v?.dataset?.sessionId===t.id);if(!b)return;const m=new l.Terminal({cursorBlink:!0,fontFamily:'Consolas, "Courier New", monospace',fontSize:13,theme:{background:"#1e1e1e",foreground:"#d4d4d4"},convertEol:!1}),P=new p.FitAddon;m.loadAddon(P),m.open(b);try{P.fit()}catch{}t.xterm=m,t.fitAddon=P;const ie=m.onData(v=>{s.stdin(t.id,v).catch(g=>{String(g?.message||"").includes("dangerous_keyword_blocked")?U.warning("该命令被桌面端拦截(高危关键字)"):U.error("stdin 失败: "+(g?.message||g))})}),ce=s.onStdout(t.id,({data:v,seq:g})=>{t.lastSeq=g,m.write(v)}),de=s.onExit(t.id,({exitCode:v,signal:g})=>{t.alive=!1,t.exitCode=v,t.signal=g,m.writeln(`\r
3
- \x1B[33m[session exited, code=${v}, signal=${g??"-"}]\x1B[0m`)});t.offs=()=>{try{ie.dispose?.()}catch{}ce(),de()};try{const{chunks:v,truncated:g}=await s.history(t.id,0);g&&m.writeln("\x1B[2m[history truncated — earlier output was evicted]\x1B[0m");for(const J of v)m.write(J.data),t.lastSeq=J.seq}catch(v){m.writeln(`\x1B[31m[history fetch failed: ${v?.message||v}]\x1B[0m`)}const j=new ResizeObserver(()=>{try{P.fit(),s.resize(t.id,m.cols,m.rows).catch(()=>{})}catch{}});j.observe(b);const ue=t.offs;t.offs=()=>{try{j.disconnect()}catch{}ue()}}async function re(){u.value=!0,f.value="";try{const t=await s.create({shell:w.value,cols:80,rows:24}),l={id:t.sessionId,shell:t.shell,cwd:"",alive:!0,lastSeq:0,exitCode:null,xterm:null,fitAddon:null,offs:()=>{}};e.value.push(l),i.value=l.id,await B(l)}catch(t){f.value=t?.message||String(t)}finally{u.value=!1}}async function se(t){try{await s.close(t)}catch(l){f.value=l?.message||String(l)}setTimeout(()=>W(t),500)}function W(t){const l=e.value.findIndex(b=>b.id===t);if(l===-1)return;const p=e.value[l];try{p.offs?.()}catch{}try{p.xterm?.dispose?.()}catch{}e.value.splice(l,1),i.value===t&&(i.value=e.value[0]?.id||null)}function le(t){i.value=t,q(()=>{const l=e.value.find(p=>p.id===t);try{l?.fitAddon?.fit()}catch{}})}async function X(){d.value=!0,f.value="";try{const t=await s.list();for(const l of t){const p=e.value.find(m=>m.id===l.id);if(p){p.alive=l.alive,p.lastSeq=l.lastSeq;continue}const b={id:l.id,shell:l.shell,cwd:l.cwd,alive:l.alive,lastSeq:l.lastSeq,exitCode:null,xterm:null,fitAddon:null,offs:()=>{}};e.value.push(b),await B(b)}!i.value&&e.value.length>0&&(i.value=e.value[0].id)}catch(t){f.value=t?.message||String(t)}finally{d.value=!1}}G(async()=>{await X()}),H(()=>{for(const t of e.value){try{t.offs?.()}catch{}try{t.xterm?.dispose?.()}catch{}}}),$(i,()=>{q(()=>{const t=h.value;try{t?.fitAddon?.fit()}catch{}})});const Y={term:s,sessions:e,activeId:i,newShell:w,creating:u,loadingList:d,error:f,warning:n,xtermContainers:a,shellOptions:r,active:h,shortId:L,get xtermMod(){return O},set xtermMod(t){O=t},get fitAddonMod(){return M},set fitAddonMod(t){M=t},loadXterm:I,mountXterm:B,onCreate:re,onClose:se,removeSession:W,activate:le,refreshList:X,ref:S,computed:ee,onMounted:G,onBeforeUnmount:H,nextTick:q,watch:$,get message(){return U},get PlusOutlined(){return ge},get CloseOutlined(){return pe},get ReloadOutlined(){return ye},get useTerminal(){return oe}};return Object.defineProperty(Y,"__isScriptSetup",{enumerable:!1,value:!0}),Y}},be={class:"terminal-page"},ke={class:"terminal-header"},Ce={class:"page-sub"},Ae={class:"terminal-body"},Ee={class:"session-tabs"},Oe=["onClick"],Te={class:"session-shell"},Re={class:"session-id"},Me={key:0,class:"session-empty"},ze={class:"xterm-host"},Le=["data-session-id"],Pe={key:0,class:"xterm-placeholder"},De={key:1,class:"terminal-footer"},qe={key:0,class:"footer-exit"};function Be(c,o,s,e,i,w){const u=z("a-tag"),d=z("a-select"),f=z("a-button"),n=z("a-space"),a=z("a-alert");return y(),x("div",be,[_("div",ke,[_("div",null,[o[3]||(o[3]=_("h2",{class:"page-title"},"远程终端",-1)),_("p",Ce,[o[2]||(o[2]=D(" 桌面端托管的 PTY 会话;Android 端可远程操控同一通道 ",-1)),e.warning?(y(),K(u,{key:0,color:"orange",style:{"margin-left":"8px"}},{default:T(()=>[D(E(e.warning),1)]),_:1})):R("v-if",!0)])]),A(n,null,{default:T(()=>[A(d,{value:e.newShell,"onUpdate:value":o[0]||(o[0]=r=>e.newShell=r),style:{width:"130px"},size:"small",options:e.shellOptions},null,8,["value"]),A(f,{type:"primary",size:"small",loading:e.creating,onClick:e.onCreate},{icon:T(()=>[A(e.PlusOutlined)]),default:T(()=>[o[4]||(o[4]=D(" 新会话 ",-1))]),_:1},8,["loading"]),A(f,{size:"small",loading:e.loadingList,onClick:e.refreshList},{icon:T(()=>[A(e.ReloadOutlined)]),default:T(()=>[o[5]||(o[5]=D(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),e.error?(y(),K(a,{key:0,message:e.error,type:"error","show-icon":"",closable:"",style:{"margin-bottom":"12px"},onClose:o[1]||(o[1]=r=>e.error="")},null,8,["message"])):R("v-if",!0),_("div",Ae,[_("div",Ee,[(y(!0),x(Q,null,Z(e.sessions,r=>(y(),x("div",{key:r.id,class:ve(["session-tab",{active:r.id===e.activeId,dead:!r.alive}]),onClick:h=>e.activate(r.id)},[_("span",Te,E(r.shell),1),_("span",Re,E(e.shortId(r.id)),1),A(e.CloseOutlined,{class:"session-close",onClick:we(h=>e.onClose(r.id),["stop"])},null,8,["onClick"])],10,Oe))),128)),e.sessions.length===0?(y(),x("div",Me,' 点击 "新会话" 创建第一个终端 ')):R("v-if",!0)]),_("div",ze,[(y(!0),x(Q,null,Z(e.sessions,r=>he((y(),x("div",{key:r.id,ref_for:!0,ref:"xtermContainers","data-session-id":r.id,class:"xterm-container"},null,8,Le)),[[_e,r.id===e.activeId]])),128)),e.sessions.length===0?(y(),x("div",Pe,[...o[6]||(o[6]=[_("span",null,"无活跃会话",-1)])])):R("v-if",!0)])]),e.active?(y(),x("div",De,[_("span",null,E(e.active.shell)+" · "+E(e.active.cwd||"(默认 cwd)")+" · seq "+E(e.active.lastSeq),1),e.active.alive?R("v-if",!0):(y(),x("span",qe,"已退出 (code="+E(e.active.exitCode??"-")+")",1))])):R("v-if",!0)])}const Ne=me(Se,[["render",Be],["__scopeId","data-v-65366a29"],["__file","/tmp/cc-web-panel-8U3FtY/repo/packages/web-panel/src/views/Terminal.vue"]]);export{Ne as default};
@@ -1 +0,0 @@
1
- import{Q as r}from"./index-BEVm0lCS.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
@@ -1 +0,0 @@
1
- import{C as o}from"./Col-74cOwZU1.js";import{a0 as t}from"./index-BEVm0lCS.js";import"./vendor-Bn1JzzAn.js";import"./index-B3CDgvNW.js";import"./icons-DG5UD-6K.js";const s=t(o);export{s as default};