chainlesschain 0.162.180 → 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 (263) hide show
  1. package/package.json +7 -3
  2. package/scripts/build-windows-sandbox-helper.ps1 +163 -0
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-D_TIL54O.js → AIOps-DzZ5_xoj.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-eQwy9r-f.js → ActionButton-DeLXddIg.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-D2eNuDgT.js → Analytics-rvDCmet1.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CFhwOFsf.js → AppLayout-Yt6QVDnp.js} +5 -5
  8. package/src/assets/web-panel/assets/{Artifacts-CJUMw6PB.js → Artifacts-BS112K5L.js} +1 -1
  9. package/src/assets/web-panel/assets/{Audit-CDB9V58o.js → Audit-0wJuQrNu.js} +1 -1
  10. package/src/assets/web-panel/assets/{BackgroundAgents-TBppYFjN.js → BackgroundAgents-B90PMgbn.js} +1 -1
  11. package/src/assets/web-panel/assets/{Backup-CYEOUpzJ.js → Backup-TkgMglQQ.js} +1 -1
  12. package/src/assets/web-panel/assets/{BaseInput-C88fFT2u.js → BaseInput-CQVS9p1l.js} +1 -1
  13. package/src/assets/web-panel/assets/{Chat-mkr1vC3N.js → Chat-YTjQHoC7.js} +6 -6
  14. package/src/assets/web-panel/assets/ChatBubbleRenderer-PR074hUN.js +1 -0
  15. package/src/assets/web-panel/assets/{Checkbox-CVU4xqti.js → Checkbox-5bwaOabq.js} +1 -1
  16. package/src/assets/web-panel/assets/{Codegen-rrNcByz3.js → Codegen-BFmNQ_Xe.js} +1 -1
  17. package/src/assets/web-panel/assets/{Col-Cqu-zCvh.js → Col-BT_u4Dzp.js} +1 -1
  18. package/src/assets/web-panel/assets/{Community-RGRlSgXV.js → Community-CJP52u5b.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compact-DBm6epOK.js → Compact-BpzhJE9i.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compliance-BgKw5iaW.js → Compliance-Cg7rfslp.js} +1 -1
  21. package/src/assets/web-panel/assets/{Cowork-BqQcNO3Z.js → Cowork-JisxL6Yy.js} +3 -3
  22. package/src/assets/web-panel/assets/{Cron-DO5gTFNb.js → Cron-Bu7Ug_MC.js} +2 -2
  23. package/src/assets/web-panel/assets/{Crosschain-B8hbJNuN.js → Crosschain-CvuqoLdj.js} +1 -1
  24. package/src/assets/web-panel/assets/{DID-B08bFJ2C.js → DID-C2u9G8Pu.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dashboard-xNdy_ifo.js → Dashboard-BFt5Yv3d.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dropdown-D-KIZgWL.js → Dropdown-DIaT9Wxq.js} +1 -1
  27. package/src/assets/web-panel/assets/{EmailListRenderer-DKCvsaGo.js → EmailListRenderer-D_A601Y4.js} +1 -1
  28. package/src/assets/web-panel/assets/{FamilyGuardDashboard-D_cfqama.js → FamilyGuardDashboard--IyQ8I8w.js} +1 -1
  29. package/src/assets/web-panel/assets/{Federation-B-UqQD68.js → Federation-BihWHxuY.js} +1 -1
  30. package/src/assets/web-panel/assets/{FormItemContext-BWWvWuJW.js → FormItemContext-BB8dOXc_.js} +1 -1
  31. package/src/assets/web-panel/assets/{GenericCardRenderer-CPchx6N7.js → GenericCardRenderer-DQYhj1HH.js} +1 -1
  32. package/src/assets/web-panel/assets/{Git-Vx4co9Ff.js → Git-B-2QZxGf.js} +2 -2
  33. package/src/assets/web-panel/assets/{Governance-D4x0pp_m.js → Governance-CusSb-nG.js} +1 -1
  34. package/src/assets/web-panel/assets/{Inference-T3KvwPYR.js → Inference-BAjmvPPL.js} +1 -1
  35. package/src/assets/web-panel/assets/{KnowledgeGraph-Ddv3KUv3.js → KnowledgeGraph-DoNYWKYq.js} +1 -1
  36. package/src/assets/web-panel/assets/{Logs-DfH-Dkae.js → Logs-B8fKWD-n.js} +2 -2
  37. package/src/assets/web-panel/assets/{MarkdownRenderer-DHW3PbCq.js → MarkdownRenderer-BlJm1J7E.js} +1 -1
  38. package/src/assets/web-panel/assets/{Marketplace-tjgb0R3D.js → Marketplace-CyOscbSL.js} +1 -1
  39. package/src/assets/web-panel/assets/{McpTools-DHAk5nYX.js → McpTools-Ex6Om5da.js} +5 -5
  40. package/src/assets/web-panel/assets/{Memory-A2Yx7thM.js → Memory-CDcD8l8r.js} +2 -2
  41. package/src/assets/web-panel/assets/{MobileBridge-BEmTVfN5.js → MobileBridge-xfBqoFDg.js} +1 -1
  42. package/src/assets/web-panel/assets/{MobileProjects-DuFHUgE4.js → MobileProjects-BwObMMA2.js} +1 -1
  43. package/src/assets/web-panel/assets/{Mtc-BDSll0OZ.js → Mtc-CIWd36OV.js} +4 -4
  44. package/src/assets/web-panel/assets/{MtcAudit-CuBvluaS.js → MtcAudit-CPX0ouuA.js} +4 -4
  45. package/src/assets/web-panel/assets/{Multisig-BmXAA-Sb.js → Multisig-BDJsIUuW.js} +3 -3
  46. package/src/assets/web-panel/assets/{NLProgramming-ci2stZAe.js → NLProgramming-DEkbuD3N.js} +1 -1
  47. package/src/assets/web-panel/assets/{Notes-D-1RpqnS.js → Notes-DJpHRhH1.js} +3 -3
  48. package/src/assets/web-panel/assets/{NotificationSettings-C0GyitIT.js → NotificationSettings-C1UZ-Qd5.js} +1 -1
  49. package/src/assets/web-panel/assets/{OrderTableRenderer-U2bN-hj5.js → OrderTableRenderer-GlJtqLjT.js} +1 -1
  50. package/src/assets/web-panel/assets/{Organization-BNZgpPci.js → Organization-Bbhj0fac.js} +4 -4
  51. package/src/assets/web-panel/assets/{Overflow-CDidKmUN.js → Overflow-1H04x3kx.js} +1 -1
  52. package/src/assets/web-panel/assets/{P2P-BnreBaXq.js → P2P-CDpPe3et.js} +2 -2
  53. package/src/assets/web-panel/assets/{PdhVaultBrowser-DwJUxO9j.js → PdhVaultBrowser-MUX0Bpvw.js} +3 -3
  54. package/src/assets/web-panel/assets/{Permissions-BQGgJPH0.js → Permissions-A07-0Ci1.js} +4 -4
  55. package/src/assets/web-panel/assets/{PersonalDataHub-k_fSkCwL.js → PersonalDataHub-DhhDWxAZ.js} +5 -5
  56. package/src/assets/web-panel/assets/{Pipeline-WGqKMqau.js → Pipeline-CyfbJfe-.js} +1 -1
  57. package/src/assets/web-panel/assets/{Privacy-DtHj9Ymq.js → Privacy-CNFps3ED.js} +1 -1
  58. package/src/assets/web-panel/assets/{ProjectInit-B3wH2SFC.js → ProjectInit--T-u3Dr5.js} +2 -2
  59. package/src/assets/web-panel/assets/{ProjectSettings-Cd0cgcA1.js → ProjectSettings-DJmrK2fC.js} +2 -2
  60. package/src/assets/web-panel/assets/Projects-Qx_MdX9k.js +1 -0
  61. package/src/assets/web-panel/assets/{Providers-DTpxEXur.js → Providers-DLzzbOZd.js} +1 -1
  62. package/src/assets/web-panel/assets/{QrScannerModal-B2v6gR-C.js → QrScannerModal-CexOomKS.js} +1 -1
  63. package/src/assets/web-panel/assets/{QuickAsk-D3Nr9xXR.js → QuickAsk-QklGi19_.js} +1 -1
  64. package/src/assets/web-panel/assets/{Recommend-C9inoMky.js → Recommend-Bb9kwSw8.js} +1 -1
  65. package/src/assets/web-panel/assets/RemoteSession-DZuVNNN5.js +5 -0
  66. package/src/assets/web-panel/assets/{Reputation-41KFG646.js → Reputation-Dr5cLP0N.js} +1 -1
  67. package/src/assets/web-panel/assets/{Row-DqAaqqCv.js → Row-oCQHYv5t.js} +1 -1
  68. package/src/assets/web-panel/assets/{RssFeed-CMDpCDKc.js → RssFeed-IFDEykIR.js} +3 -3
  69. package/src/assets/web-panel/assets/{Search-B6mtegNL.js → Search-CspVIxDc.js} +1 -1
  70. package/src/assets/web-panel/assets/{Security-BaePFVZ8.js → Security-Bm66o_DH.js} +3 -3
  71. package/src/assets/web-panel/assets/{Services-DeG3Qscl.js → Services-DvanNqXl.js} +2 -2
  72. package/src/assets/web-panel/assets/{Skeleton-D_QP7F90.js → Skeleton-CHjEe9_O.js} +1 -1
  73. package/src/assets/web-panel/assets/{Skills-DLGyUgIA.js → Skills-Cb8jWjMX.js} +1 -1
  74. package/src/assets/web-panel/assets/{Sla-BN2pxW1Q.js → Sla-DxZm1491.js} +1 -1
  75. package/src/assets/web-panel/assets/{SpeechSettings-BWsZPd8B.js → SpeechSettings-DWxEEclC.js} +1 -1
  76. package/src/assets/web-panel/assets/{SyncSettings-VOZRPODW.js → SyncSettings-FIvOFw5p.js} +2 -2
  77. package/src/assets/web-panel/assets/Tasks-CyuLnDFR.js +1 -0
  78. package/src/assets/web-panel/assets/{Templates-eJSob-q0.js → Templates-CaNjzV_t.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tenant-Bdwk8Rwy.js → Tenant-DjlP6TmH.js} +1 -1
  80. package/src/assets/web-panel/assets/Terminal-DwzGMniO.js +3 -0
  81. package/src/assets/web-panel/assets/{TimelineRenderer-D5qkbPKT.js → TimelineRenderer-DoZ8y7y8.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tokens-DKgwn8hI.js → Tokens-390cg2TC.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trigger-HlEHniGM.js → Trigger-CLrtCj5_.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trust-CdPcsBpN.js → Trust-DpESfSPn.js} +1 -1
  85. package/src/assets/web-panel/assets/{UkeySign-vAdXd-vG.js → UkeySign-CN6279O0.js} +1 -1
  86. package/src/assets/web-panel/assets/{VideoEditing-9hHBYFnH.js → VideoEditing-DPtAUlSe.js} +1 -1
  87. package/src/assets/web-panel/assets/{Wallet-Dxh5d1yR.js → Wallet-nKOMV_1n.js} +4 -4
  88. package/src/assets/web-panel/assets/{WebAuthn-BsFmLHkp.js → WebAuthn-HuXlSOc4.js} +5 -5
  89. package/src/assets/web-panel/assets/{WorkflowEditor-Cn0OIwLn.js → WorkflowEditor-CUfFjARi.js} +1 -1
  90. package/src/assets/web-panel/assets/chat-6Eq0PcZJ.js +1 -0
  91. package/src/assets/web-panel/assets/{colors-Du9jzLN0.js → colors-BP_Sf6Iy.js} +1 -1
  92. package/src/assets/web-panel/assets/{compact-item-DhEscfzw.js → compact-item-BufMKIh5.js} +1 -1
  93. package/src/assets/web-panel/assets/{createContext-CwzEfF3i.js → createContext-BBMXxWSW.js} +1 -1
  94. package/src/assets/web-panel/assets/devWarning-DgVKduH2.js +1 -0
  95. package/src/assets/web-panel/assets/{hasIn-DT_GSE6J.js → hasIn-fUK_tRO2.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-tND8-TDU.js → index-2A5ph8b2.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-B8s5FxJY.js → index-3FuwBewR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-53z1YUxX.js → index-6GmBa4Kg.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BFD0cEna.js → index-B2vS66eI.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CQWxDOvM.js → index-B7Etk0Te.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-VeHs6qH0.js → index-B9WYSn4m.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CGvgnfl9.js → index-BHy6yNiF.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-D3llLkYM.js → index-BMLHv389.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-Dny_ZnAO.js → index-BWKoBU8R.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DzjzrOli.js → index-Bkg4ZePE.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DN60VBn5.js → index-C44atv4k.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-v5HLYCVa.js → index-CE2DdTP2.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BF-ZCVGE.js → index-CGjmILDm.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-gFjYdstW.js → index-CW_G-MXw.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-NA2oBLSB.js → index-CZ6Yt17L.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Mobw3PHs.js → index-CeASi4fr.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DWL3SYN3.js → index-CgiECHu2.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-1LoutPJd.js → index-Cp8vhyZy.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BnHhFnwt.js → index-CwSf5pnf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-B6QDWRLk.js → index-D4_MuGkd.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-D-QkW1fp.js → index-D9vU25ij.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-C4SN3by5.js → index-DASluSqY.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CyEhUJcu.js → index-DLpIs_P_.js} +1 -1
  119. package/src/assets/web-panel/assets/index-DOZTSoS7.js +1 -0
  120. package/src/assets/web-panel/assets/{index-BrkJ7JPm.js → index-DPdUNk1i.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-Cnok8mhZ.js → index-DVsqvI4M.js} +1 -1
  122. package/src/assets/web-panel/assets/index-DhpvjpqI.js +1 -0
  123. package/src/assets/web-panel/assets/{index-CAVW0cWM.js → index-DmkMXwnR.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-Cc9aPkv-.js → index-DocdRcbd.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DnVVYKCE.js → index-Dyngbd29.js} +20 -20
  126. package/src/assets/web-panel/assets/{index-D8gt0j7r.js → index-GwdRUZ-x.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-BIYTjbv_.js → index-LvCBfTLo.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DhXay17G.js → index-cpEli44X.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-BQWENaZf.js → index-fzaMtSJ8.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DfRDyY1q.js → index-pum7HYBA.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BgSR2WMG.js → index-t8N1tSeX.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-D5IytTND.js → index-uCbEN7cY.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DtRwLhee.js → index-wKTLbKyc.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-D4kZoXNr.js → index-wV6iGdpY.js} +1 -1
  135. package/src/assets/web-panel/assets/{initDefaultProps-Cvt59c10.js → initDefaultProps-V5Fo95FM.js} +1 -1
  136. package/src/assets/web-panel/assets/{motion-D15pPEzl.js → motion-BYWU0hUT.js} +1 -1
  137. package/src/assets/web-panel/assets/{move-N55KeXJ7.js → move-Cr1M-J2h.js} +1 -1
  138. package/src/assets/web-panel/assets/{mtc-parser-CyFO1bYP.js → mtc-parser-BysQKi2N.js} +1 -1
  139. package/src/assets/web-panel/assets/{omit-B5IXfxU2.js → omit-D1zHU8GC.js} +1 -1
  140. package/src/assets/web-panel/assets/{pickAttrs-CpVqsulV.js → pickAttrs-CUArxtfi.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-ME36sMF3.js → placementArrow-ChoYEys0.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-BXAIR1r-.js → responsiveObserve-BQRs3Mo7.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-BkOX3-Dp.js → slide-B8zbsCkg.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-Cy4Aklpt.js → statusUtils-C2U8Gs6h.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-gUd2T206.js → styleChecker-Dd8MgL_V.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-CaVD4o99.js → useFlexGapSupport-hknqY5NH.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs--pFGl0KD.js → useFs-CLTAmcfw.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-D45iP86i.js → usePersonalDataHub-ByegHbiB.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-BayoChH_.js → vnode-DqlAy5DP.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-CpP38poi.js → zoom-DiXiztQn.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/commands/agenda.js +115 -3
  153. package/src/commands/agent.js +10 -1
  154. package/src/commands/background-session.js +2 -1
  155. package/src/commands/context.js +69 -2
  156. package/src/data/changelog.json +26 -0
  157. package/src/gateways/terminal/PtyManager.js +45 -4
  158. package/src/gateways/ws/background-agent-protocol.js +38 -0
  159. package/src/gateways/ws/message-dispatcher.js +1 -0
  160. package/src/gateways/ws/remote-session-protocol.js +65 -6
  161. package/src/gateways/ws/ws-server.js +18 -2
  162. package/src/harness/background-task-manager.js +70 -2
  163. package/src/harness/feature-flags.js +15 -8
  164. package/src/harness/mcp-client.js +618 -43
  165. package/src/harness/worktree-isolator.js +14 -3
  166. package/src/lazy-dispatch.js +30 -1
  167. package/src/lib/agent-authority.js +22 -0
  168. package/src/lib/agent-core.js +3 -0
  169. package/src/lib/agent-sandbox.js +161 -0
  170. package/src/lib/agent-schedule-store.js +45 -22
  171. package/src/lib/agent-team/team-runner.js +22 -0
  172. package/src/lib/artifact-store.js +35 -0
  173. package/src/lib/async-hook-supervisor.cjs +13 -2
  174. package/src/lib/audit-mtc.js +3 -2
  175. package/src/lib/background-agent-supervisor.js +104 -3
  176. package/src/lib/background-interaction-journal.js +407 -0
  177. package/src/lib/background-interaction-resolver.js +23 -34
  178. package/src/lib/background-session-transport.js +12 -2
  179. package/src/lib/capability-manifest.js +41 -3
  180. package/src/lib/capability-negotiation.js +1 -1
  181. package/src/lib/channels/channel-manager.js +33 -0
  182. package/src/lib/channels/telegram-channel.js +23 -5
  183. package/src/lib/channels/webhook-channel.js +38 -15
  184. package/src/lib/chrome-connector.js +169 -23
  185. package/src/lib/config-manager.js +23 -9
  186. package/src/lib/context-breakdown.js +31 -0
  187. package/src/lib/cowork-cron.js +274 -32
  188. package/src/lib/cross-chain-mtc.js +3 -2
  189. package/src/lib/durable-security-store.js +124 -0
  190. package/src/lib/event-runtime-host.js +67 -6
  191. package/src/lib/event-runtime-store.js +163 -0
  192. package/src/lib/goal-store.js +32 -12
  193. package/src/lib/headless-manifest.js +2 -1
  194. package/src/lib/hook-environment.cjs +58 -0
  195. package/src/lib/hook-manager.js +12 -5
  196. package/src/lib/hook-runner.cjs +122 -28
  197. package/src/lib/hook-runner.js +7 -2
  198. package/src/lib/hooks-v2-producers.js +36 -0
  199. package/src/lib/hooks-v2-runtime.js +329 -52
  200. package/src/lib/interaction-adapter.js +60 -19
  201. package/src/lib/interaction-binding.js +64 -0
  202. package/src/lib/json-schema-output.js +439 -14
  203. package/src/lib/json-schema-validate.js +514 -883
  204. package/src/lib/lan-pairing-tokens.js +115 -57
  205. package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
  206. package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
  207. package/src/lib/lsp/lsp-client.js +4 -0
  208. package/src/lib/lsp/lsp-manager.js +3 -0
  209. package/src/lib/lsp/lsp-server-registry.js +18 -0
  210. package/src/lib/mcp-client.js +1 -0
  211. package/src/lib/mcp-oauth.js +35 -21
  212. package/src/lib/packer/pkg-config-generator.js +3 -0
  213. package/src/lib/permission-decision.js +99 -0
  214. package/src/lib/plugin-monitor-supervisor.js +3 -0
  215. package/src/lib/plugin-runtime/bin.js +1148 -70
  216. package/src/lib/plugin-runtime/capabilities.js +50 -0
  217. package/src/lib/plugin-runtime/capability-consent.js +42 -35
  218. package/src/lib/plugin-runtime/hooks.js +36 -9
  219. package/src/lib/plugin-runtime/install.js +23 -7
  220. package/src/lib/plugin-runtime/lsp.js +4 -0
  221. package/src/lib/plugin-runtime/manifest.js +112 -8
  222. package/src/lib/plugin-runtime/mcp.js +30 -5
  223. package/src/lib/plugin-runtime/monitors.js +11 -0
  224. package/src/lib/plugin-runtime/plugin-options.js +94 -38
  225. package/src/lib/plugin-runtime/policy.js +29 -2
  226. package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
  227. package/src/lib/plugin-runtime/scopes.js +27 -13
  228. package/src/lib/plugin-runtime/trust.js +36 -31
  229. package/src/lib/process-execution-broker/credential-agent.js +114 -16
  230. package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
  231. package/src/lib/process-execution-broker/credential-transport.js +378 -0
  232. package/src/lib/process-execution-broker/index.js +765 -49
  233. package/src/lib/process-execution-broker/platform-sandbox.js +4233 -138
  234. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  235. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  236. package/src/lib/process-execution-broker/windows-sandbox.cs +3856 -0
  237. package/src/lib/project-mcp-trust.js +21 -26
  238. package/src/lib/protocol-replay.js +19 -12
  239. package/src/lib/repl-bang-memorize.js +67 -10
  240. package/src/lib/settings-hooks.cjs +13 -0
  241. package/src/lib/skill-loader.js +83 -10
  242. package/src/lib/slash-commands.js +27 -4
  243. package/src/lib/sync-credentials.js +5 -4
  244. package/src/lib/turn-binding.js +8 -6
  245. package/src/repl/agent-repl.js +117 -31
  246. package/src/repl/repl-turn-binding.js +5 -2
  247. package/src/runtime/agent-core.js +699 -70
  248. package/src/runtime/agent-runtime.js +13 -1
  249. package/src/runtime/coding-agent-contract-shared.cjs +3 -3
  250. package/src/runtime/headless-runner.js +105 -7
  251. package/src/runtime/headless-stream.js +209 -23
  252. package/src/runtime/mcp-config.js +29 -17
  253. package/src/runtime/policies/agent-policy.js +2 -0
  254. package/src/workers/background-agent-worker.js +128 -13
  255. package/src/assets/web-panel/assets/ChatBubbleRenderer-C7bofJuA.js +0 -1
  256. package/src/assets/web-panel/assets/Projects-BbgmyQnS.js +0 -1
  257. package/src/assets/web-panel/assets/RemoteSession-Bqk3EYSu.js +0 -4
  258. package/src/assets/web-panel/assets/Tasks-3bDAUz8K.js +0 -1
  259. package/src/assets/web-panel/assets/Terminal-CsMLKIoV.js +0 -3
  260. package/src/assets/web-panel/assets/chat-CJ19O6Dh.js +0 -1
  261. package/src/assets/web-panel/assets/devWarning-BBMFnsja.js +0 -1
  262. package/src/assets/web-panel/assets/index-Do8JMV4N.js +0 -1
  263. package/src/assets/web-panel/assets/index-UYAJ6iNM.js +0 -1
@@ -239,6 +239,56 @@ export function componentCapabilityDenial(manifest, capabilityNames) {
239
239
  return finding ? { reason: finding.reason } : null;
240
240
  }
241
241
 
242
+ /**
243
+ * Enforce a declared network domain for a direct URL-based plugin component.
244
+ * Stdio children have no direct target here and remain subject to the process
245
+ * sandbox boundary; URL transports can be rejected before any connection.
246
+ */
247
+ export function networkTargetDenial(manifest, targetUrl) {
248
+ if (!manifest || manifest.capabilitiesDeclared !== true || !targetUrl) {
249
+ return null;
250
+ }
251
+ let hostname;
252
+ try {
253
+ hostname = new URL(String(targetUrl)).hostname
254
+ .toLowerCase()
255
+ .replace(/\.$/, "");
256
+ } catch {
257
+ return { reason: `invalid network target URL: ${targetUrl}` };
258
+ }
259
+ const network = manifest.capabilities?.network || {
260
+ any: false,
261
+ domains: [],
262
+ };
263
+ if (network.any === true) return null;
264
+ const allowed = (network.domains || []).some((raw) => {
265
+ let domain = String(raw || "")
266
+ .trim()
267
+ .toLowerCase()
268
+ .replace(/\.$/, "");
269
+ if (!domain) return false;
270
+ if (domain.includes("://")) {
271
+ try {
272
+ domain = new URL(domain).hostname.toLowerCase().replace(/\.$/, "");
273
+ } catch {
274
+ return false;
275
+ }
276
+ } else {
277
+ domain = domain.replace(/:\d+$/, "");
278
+ }
279
+ if (domain.startsWith("*.")) {
280
+ const suffix = domain.slice(1);
281
+ return hostname.endsWith(suffix) && hostname.length > suffix.length;
282
+ }
283
+ return hostname === domain;
284
+ });
285
+ return allowed
286
+ ? null
287
+ : {
288
+ reason: `network target "${hostname}" is outside the plugin's declared domains`,
289
+ };
290
+ }
291
+
242
292
  // ─── options schema ─────────────────────────────────────────────────────────
243
293
 
244
294
  export const OPTION_TYPES = Object.freeze([
@@ -18,21 +18,22 @@
18
18
  * never touch the real user-data dir.
19
19
  */
20
20
 
21
- import fs from "fs";
22
21
  import path from "path";
23
22
  import { getElectronUserDataDir } from "../paths.js";
23
+ import { withFileLock } from "../with-file-lock.js";
24
24
  import {
25
25
  normalizeCapabilities,
26
26
  diffCapabilities,
27
27
  describeCapabilities,
28
28
  } from "./capabilities.js";
29
+ import {
30
+ mutateSecurityStore,
31
+ readSecurityStore,
32
+ } from "../durable-security-store.js";
29
33
 
30
34
  export const _deps = {
31
- existsSync: fs.existsSync,
32
- readFileSync: fs.readFileSync,
33
- writeFileSync: fs.writeFileSync,
34
- mkdirSync: fs.mkdirSync,
35
35
  now: () => new Date().toISOString(),
36
+ withFileLock,
36
37
  // Injectable so unit tests never touch the real user-data dir.
37
38
  storePath: () =>
38
39
  path.join(getElectronUserDataDir(), "plugin-capability-consent.json"),
@@ -43,20 +44,7 @@ function consentKey(scope, name) {
43
44
  }
44
45
 
45
46
  export function loadConsentStore() {
46
- try {
47
- const p = _deps.storePath();
48
- if (!_deps.existsSync(p)) return {};
49
- const data = JSON.parse(_deps.readFileSync(p, "utf8"));
50
- return data && typeof data === "object" && !Array.isArray(data) ? data : {};
51
- } catch {
52
- return {};
53
- }
54
- }
55
-
56
- function saveConsentStore(store) {
57
- const p = _deps.storePath();
58
- _deps.mkdirSync(path.dirname(p), { recursive: true });
59
- _deps.writeFileSync(p, JSON.stringify(store, null, 2), "utf8");
47
+ return readSecurityStore(_deps.storePath(), "plugin capability consent");
60
48
  }
61
49
 
62
50
  /**
@@ -158,8 +146,15 @@ export function resolveConsentAction(
158
146
  /** Load the store and report whether one plugin's declared caps are consented. */
159
147
  export function isPluginCapabilityConsented(plugin, declaredCaps) {
160
148
  if (!plugin || !plugin.name) return false;
161
- const entry = loadConsentStore()[consentKey(plugin.scope, plugin.name)];
162
- return capabilityConsentStatus(declaredCaps, entry).consented;
149
+ if (capabilitiesAreEmpty(declaredCaps)) return true;
150
+ try {
151
+ const entry = loadConsentStore()[consentKey(plugin.scope, plugin.name)];
152
+ return capabilityConsentStatus(declaredCaps, entry).consented;
153
+ } catch {
154
+ // Security reads fail closed: an unavailable/corrupt consent store never
155
+ // turns into permission to use a capability.
156
+ return false;
157
+ }
163
158
  }
164
159
 
165
160
  /** Record consent for a plugin's currently-declared capability set. */
@@ -168,24 +163,36 @@ export function consentPluginCapabilities(
168
163
  { scope = "project", version, capabilities } = {},
169
164
  ) {
170
165
  if (!version) throw new Error("consentPluginCapabilities requires a version");
171
- const store = loadConsentStore();
172
- store[consentKey(scope, name)] = {
173
- version,
174
- capabilities: canonicalCaps(capabilities),
175
- consentedAt: _deps.now(),
176
- };
177
- saveConsentStore(store);
178
- return { name, scope, version };
166
+ const file = _deps.storePath();
167
+ return mutateSecurityStore(
168
+ file,
169
+ "plugin capability consent",
170
+ (store) => {
171
+ store[consentKey(scope, name)] = {
172
+ version,
173
+ capabilities: canonicalCaps(capabilities),
174
+ consentedAt: _deps.now(),
175
+ };
176
+ return { name, scope, version };
177
+ },
178
+ { lock: _deps.withFileLock },
179
+ );
179
180
  }
180
181
 
181
182
  /** Revoke capability consent for a plugin at a scope. */
182
183
  export function revokeCapabilityConsent(name, { scope = "project" } = {}) {
183
- const store = loadConsentStore();
184
- const key = consentKey(scope, name);
185
- const existed = Object.prototype.hasOwnProperty.call(store, key);
186
- delete store[key];
187
- saveConsentStore(store);
188
- return { name, scope, removed: existed };
184
+ const file = _deps.storePath();
185
+ return mutateSecurityStore(
186
+ file,
187
+ "plugin capability consent",
188
+ (store) => {
189
+ const key = consentKey(scope, name);
190
+ const existed = Object.prototype.hasOwnProperty.call(store, key);
191
+ delete store[key];
192
+ return { name, scope, removed: existed };
193
+ },
194
+ { lock: _deps.withFileLock },
195
+ );
189
196
  }
190
197
 
191
198
  /** All consent entries (for `cc plugin consent --list`). */
@@ -18,6 +18,7 @@ import fs from "fs";
18
18
  import { discoverPlugins } from "./scopes.js";
19
19
  import { partitionByTrust, warnUntrustedOnce } from "./trust.js";
20
20
  import { componentCapabilityDenial } from "./capabilities.js";
21
+ import { mergePluginSandboxPolicies } from "./sandbox-policy.js";
21
22
 
22
23
  export const _deps = { readFileSync: fs.readFileSync };
23
24
 
@@ -124,17 +125,43 @@ export function collectPluginHooks(opts = {}) {
124
125
  if (!Array.isArray(entries)) continue;
125
126
  const tagged = entries.map((group) => {
126
127
  if (!group || typeof group !== "object" || !Array.isArray(group.hooks)) return group;
128
+ let groupSandboxPolicy;
129
+ try {
130
+ groupSandboxPolicy = mergePluginSandboxPolicies(
131
+ p.manifest.sandboxPolicy,
132
+ group.sandboxPolicy,
133
+ );
134
+ } catch {
135
+ return null;
136
+ }
137
+ const { sandboxPolicy: _rawGroupPolicy, ...groupConfig } = group;
127
138
  return {
128
- ...group,
129
- hooks: group.hooks.map((hook) => ({
130
- ...hook,
131
- origin: "plugin:hook",
132
- pluginId: p.name,
133
- pluginVersion: p.version || null,
134
- pluginSource: p.manifest?.manifestPath || null,
135
- })),
139
+ ...groupConfig,
140
+ hooks: group.hooks
141
+ .map((hook) => {
142
+ if (!hook || typeof hook !== "object") return hook;
143
+ let sandboxPolicy;
144
+ try {
145
+ sandboxPolicy = mergePluginSandboxPolicies(
146
+ groupSandboxPolicy,
147
+ hook.sandboxPolicy,
148
+ );
149
+ } catch {
150
+ return null;
151
+ }
152
+ const { sandboxPolicy: _rawHookPolicy, ...hookConfig } = hook;
153
+ return {
154
+ ...hookConfig,
155
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
156
+ origin: "plugin:hook",
157
+ pluginId: p.name,
158
+ pluginVersion: p.version || null,
159
+ pluginSource: p.manifest?.manifestPath || null,
160
+ };
161
+ })
162
+ .filter(Boolean),
136
163
  };
137
- });
164
+ }).filter(Boolean);
138
165
  merged[event] = (merged[event] || []).concat(tagged);
139
166
  }
140
167
  }
@@ -35,6 +35,8 @@ import {
35
35
  } from "./signature.js";
36
36
  import executionBroker from "../process-execution-broker/index.js";
37
37
 
38
+ export const MAX_LISTED_PLUGIN_VERSIONS = 64;
39
+
38
40
  export const _deps = {
39
41
  existsSync: fs.existsSync,
40
42
  mkdirSync: fs.mkdirSync,
@@ -321,13 +323,27 @@ export function listInstalled(opts = {}) {
321
323
  cwd: opts.cwd,
322
324
  scopes: opts.scopes,
323
325
  skipPolicy: true,
324
- }).map((p) => ({
325
- name: p.name,
326
- version: p.version,
327
- scope: p.scope,
328
- dir: p.root,
329
- ok: p.manifest?.ok === true,
330
- }));
326
+ }).map((p) => {
327
+ const allVersions = listInstalledVersions(p.scope, p.name, {
328
+ cwd: opts.cwd,
329
+ });
330
+ const versions = allVersions.slice(0, MAX_LISTED_PLUGIN_VERSIONS);
331
+ if (
332
+ p.version &&
333
+ !versions.includes(p.version) &&
334
+ allVersions.includes(p.version)
335
+ ) {
336
+ versions[versions.length - 1] = p.version;
337
+ }
338
+ return {
339
+ name: p.name,
340
+ version: p.version,
341
+ versions,
342
+ scope: p.scope,
343
+ dir: p.root,
344
+ ok: p.manifest?.ok === true,
345
+ };
346
+ });
331
347
  }
332
348
 
333
349
  /**
@@ -73,6 +73,7 @@ export function ensurePluginLspServers(opts = {}) {
73
73
 
74
74
  const denied = [];
75
75
  for (const p of trusted) {
76
+ if (!p.manifest || p.manifest.ok !== true) continue;
76
77
  const servers = p.manifest?.components?.lsp || [];
77
78
  if (servers.length === 0) continue;
78
79
  // Component-level capability gate: a plugin that declared a permissions
@@ -94,6 +95,9 @@ export function ensurePluginLspServers(opts = {}) {
94
95
  pluginId: p.name,
95
96
  pluginVersion: p.version,
96
97
  pluginSource: s.absPath || p.manifest.manifestPath,
98
+ ...(s.sandboxPolicy
99
+ ? { sandboxPolicy: s.sandboxPolicy }
100
+ : {}),
97
101
  });
98
102
  registered.push({ plugin: p.name, languageId: s.languageId, id: s.id });
99
103
  } catch {
@@ -32,6 +32,10 @@ import {
32
32
  normalizeOptionsSchema,
33
33
  auditDeclaredCapabilities,
34
34
  } from "./capabilities.js";
35
+ import {
36
+ mergePluginSandboxPolicies,
37
+ normalizePluginSandboxPolicy,
38
+ } from "./sandbox-policy.js";
35
39
 
36
40
  export const _deps = {
37
41
  existsSync: fs.existsSync,
@@ -137,6 +141,19 @@ export function parsePluginManifest(root) {
137
141
  license: strOr(manifest.license, ""),
138
142
  };
139
143
 
144
+ let manifestSandboxPolicy = null;
145
+ try {
146
+ manifestSandboxPolicy = normalizePluginSandboxPolicy(
147
+ manifest.sandboxPolicy,
148
+ { label: "manifest.sandboxPolicy" },
149
+ );
150
+ if (manifestSandboxPolicy) {
151
+ result.sandboxPolicy = manifestSandboxPolicy;
152
+ }
153
+ } catch (err) {
154
+ errors.push(err.message);
155
+ }
156
+
140
157
  // A helper that resolves a plugin-relative path safely, recording an error if
141
158
  // it escapes the root or is absolute. Returns the absolute path or null.
142
159
  const safeResolve = (rel, label) => {
@@ -174,8 +191,22 @@ export function parsePluginManifest(root) {
174
191
  conventionPath: ["monitors", "monitors.json"],
175
192
  listKey: "monitors",
176
193
  });
177
- c.lsp = resolveLsp(abs, manifest, safeResolve, errors, warnings);
178
- c.bin = resolveBin(abs, manifest, safeResolve, warnings);
194
+ c.lsp = resolveLsp(
195
+ abs,
196
+ manifest,
197
+ safeResolve,
198
+ errors,
199
+ warnings,
200
+ manifestSandboxPolicy,
201
+ );
202
+ c.bin = resolveBin(
203
+ abs,
204
+ manifest,
205
+ safeResolve,
206
+ errors,
207
+ warnings,
208
+ manifestSandboxPolicy,
209
+ );
179
210
  c.settings = resolveSettings(abs, manifest, safeResolve);
180
211
 
181
212
  // ── declared capabilities + options schema (P1) ──
@@ -363,7 +394,14 @@ function extractList(obj, listKey) {
363
394
  return { count: 0, names: [] };
364
395
  }
365
396
 
366
- function resolveLsp(root, manifest, safeResolve, errors, warnings) {
397
+ function resolveLsp(
398
+ root,
399
+ manifest,
400
+ safeResolve,
401
+ errors,
402
+ warnings,
403
+ manifestSandboxPolicy,
404
+ ) {
367
405
  let content = manifest.lsp;
368
406
  // Convention file `.lsp.json`.
369
407
  if (!content) {
@@ -392,21 +430,39 @@ function resolveLsp(root, manifest, safeResolve, errors, warnings) {
392
430
  warnings.push("lsp server entry missing languageId/command — skipped");
393
431
  continue;
394
432
  }
433
+ let sandboxPolicy;
434
+ try {
435
+ sandboxPolicy = mergePluginSandboxPolicies(
436
+ manifestSandboxPolicy,
437
+ s.sandboxPolicy,
438
+ );
439
+ } catch (err) {
440
+ errors.push(`lsp server "${s.languageId}": ${err.message}`);
441
+ continue;
442
+ }
395
443
  out.push({
396
444
  languageId: s.languageId,
397
445
  command: s.command,
398
446
  args: Array.isArray(s.args) ? s.args.map(String) : [],
399
447
  extensions: Array.isArray(s.extensions) ? s.extensions.map(String) : [],
400
448
  id: typeof s.id === "string" ? s.id : s.command,
449
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
401
450
  });
402
451
  }
403
452
  return out;
404
453
  }
405
454
 
406
- function resolveBin(root, manifest, safeResolve, warnings) {
455
+ function resolveBin(
456
+ root,
457
+ manifest,
458
+ safeResolve,
459
+ errors,
460
+ warnings,
461
+ manifestSandboxPolicy,
462
+ ) {
407
463
  const out = [];
408
464
  const seen = new Set();
409
- const push = (name, rel) => {
465
+ const push = (name, rel, descriptorPolicy = null) => {
410
466
  const absPath = safeResolve(rel, `bin["${name}"]`);
411
467
  if (!absPath) return;
412
468
  if (!_deps.existsSync(absPath)) {
@@ -414,8 +470,29 @@ function resolveBin(root, manifest, safeResolve, warnings) {
414
470
  return;
415
471
  }
416
472
  if (seen.has(name)) return;
473
+ let sandboxPolicy;
474
+ try {
475
+ sandboxPolicy = mergePluginSandboxPolicies(
476
+ manifestSandboxPolicy,
477
+ descriptorPolicy,
478
+ );
479
+ } catch (err) {
480
+ errors.push(`bin "${name}": ${err.message}`);
481
+ return;
482
+ }
483
+ if (sandboxPolicy && !/^[A-Za-z0-9._-]+$/.test(name)) {
484
+ errors.push(
485
+ `bin alias "${name}" with sandboxPolicy contains unsupported characters; use letters, numbers, dot, underscore, or hyphen`,
486
+ );
487
+ return;
488
+ }
417
489
  seen.add(name);
418
- out.push({ name, path: rel, absPath });
490
+ out.push({
491
+ name,
492
+ path: rel,
493
+ absPath,
494
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
495
+ });
419
496
  };
420
497
 
421
498
  if (
@@ -423,8 +500,35 @@ function resolveBin(root, manifest, safeResolve, warnings) {
423
500
  typeof manifest.bin === "object" &&
424
501
  !Array.isArray(manifest.bin)
425
502
  ) {
426
- for (const [name, rel] of Object.entries(manifest.bin)) {
427
- if (typeof rel === "string") push(name, rel);
503
+ for (const [name, descriptor] of Object.entries(manifest.bin)) {
504
+ if (typeof descriptor === "string") {
505
+ push(name, descriptor);
506
+ continue;
507
+ }
508
+ if (
509
+ descriptor &&
510
+ typeof descriptor === "object" &&
511
+ !Array.isArray(descriptor)
512
+ ) {
513
+ const unsupported = Object.keys(descriptor).filter(
514
+ (key) => !["path", "sandboxPolicy"].includes(key),
515
+ );
516
+ if (unsupported.length > 0) {
517
+ errors.push(
518
+ `bin "${name}" contains unsupported field: ${unsupported[0]}`,
519
+ );
520
+ continue;
521
+ }
522
+ if (typeof descriptor.path !== "string") {
523
+ errors.push(`bin "${name}".path must be a non-empty string`);
524
+ continue;
525
+ }
526
+ push(name, descriptor.path, descriptor.sandboxPolicy);
527
+ continue;
528
+ }
529
+ errors.push(
530
+ `bin "${name}" must be a path string or { path, sandboxPolicy } object`,
531
+ );
428
532
  }
429
533
  return out;
430
534
  }
@@ -17,7 +17,11 @@
17
17
  import fs from "fs";
18
18
  import { discoverPlugins } from "./scopes.js";
19
19
  import { partitionByTrust, warnUntrustedOnce } from "./trust.js";
20
- import { componentCapabilityDenial } from "./capabilities.js";
20
+ import {
21
+ componentCapabilityDenial,
22
+ networkTargetDenial,
23
+ } from "./capabilities.js";
24
+ import { mergePluginSandboxPolicies } from "./sandbox-policy.js";
21
25
 
22
26
  export const _deps = { readFileSync: fs.readFileSync };
23
27
 
@@ -35,9 +39,8 @@ function warnMcpCapabilityDeniedOnce(entries) {
35
39
  const list = entries.map((e) => `${e.name} (${e.reason})`).join("; ");
36
40
  try {
37
41
  process.stderr.write(
38
- `[plugins] refused MCP server(s) from plugin(s) that declared a permissions ` +
39
- `block but did not declare the 'mcp' capability their server needs: ${list}\n` +
40
- ` add 'mcp' to the plugin's permissions block to enable them.\n`,
42
+ `[plugins] refused MCP server(s) outside declared plugin capabilities: ${list}\n` +
43
+ ` declare 'mcp' and every direct URL domain in the plugin permissions block.\n`,
41
44
  );
42
45
  } catch {
43
46
  /* stderr notice is best-effort */
@@ -119,8 +122,30 @@ export function collectPluginMcpServers(opts = {}) {
119
122
  for (const [name, cfg] of Object.entries(map)) {
120
123
  if (!cfg || typeof cfg !== "object") continue;
121
124
  if (name in servers) continue; // first plugin wins on a clash
125
+ let sandboxPolicy;
126
+ try {
127
+ sandboxPolicy = mergePluginSandboxPolicies(
128
+ p.manifest.sandboxPolicy,
129
+ cfg.sandboxPolicy,
130
+ );
131
+ } catch {
132
+ // An invalid explicit requirement must never degrade to an unsandboxed
133
+ // process. Refuse only this server so independent entries still load.
134
+ continue;
135
+ }
136
+ const targetUrl = cfg.url || cfg.transport?.url || null;
137
+ const networkDenial = networkTargetDenial(p.manifest, targetUrl);
138
+ if (networkDenial) {
139
+ denied.push({
140
+ name: `${p.name}/${name}`,
141
+ reason: networkDenial.reason,
142
+ });
143
+ continue;
144
+ }
145
+ const { sandboxPolicy: _rawSandboxPolicy, ...serverConfig } = cfg;
122
146
  servers[name] = {
123
- ...cfg,
147
+ ...serverConfig,
148
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
124
149
  origin: "plugin:mcp",
125
150
  policy: "allow",
126
151
  pluginId: p.name,
@@ -22,6 +22,7 @@ import fs from "fs";
22
22
  import { discoverPlugins } from "./scopes.js";
23
23
  import { partitionByTrust, warnUntrustedOnce } from "./trust.js";
24
24
  import { componentCapabilityDenial } from "./capabilities.js";
25
+ import { mergePluginSandboxPolicies } from "./sandbox-policy.js";
25
26
 
26
27
  export const _deps = { readFileSync: fs.readFileSync };
27
28
 
@@ -68,6 +69,15 @@ function normalizeMonitor(plugin, raw) {
68
69
  raw.env && typeof raw.env === "object" && !Array.isArray(raw.env)
69
70
  ? raw.env
70
71
  : null;
72
+ let sandboxPolicy;
73
+ try {
74
+ sandboxPolicy = mergePluginSandboxPolicies(
75
+ plugin.manifest?.sandboxPolicy,
76
+ raw.sandboxPolicy,
77
+ );
78
+ } catch {
79
+ return null;
80
+ }
71
81
  return {
72
82
  plugin: plugin.name,
73
83
  scope: plugin.scope,
@@ -85,6 +95,7 @@ function normalizeMonitor(plugin, raw) {
85
95
  pluginId: plugin.name,
86
96
  pluginVersion: plugin.version,
87
97
  pluginSource: plugin.manifest?.manifestPath || null,
98
+ ...(sandboxPolicy ? { sandboxPolicy } : {}),
88
99
  };
89
100
  }
90
101