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.
- package/package.json +7 -3
- package/scripts/build-windows-sandbox-helper.ps1 +163 -0
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-D_TIL54O.js → AIOps-DzZ5_xoj.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-eQwy9r-f.js → ActionButton-DeLXddIg.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D2eNuDgT.js → Analytics-rvDCmet1.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CFhwOFsf.js → AppLayout-Yt6QVDnp.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CJUMw6PB.js → Artifacts-BS112K5L.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CDB9V58o.js → Audit-0wJuQrNu.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-TBppYFjN.js → BackgroundAgents-B90PMgbn.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CYEOUpzJ.js → Backup-TkgMglQQ.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C88fFT2u.js → BaseInput-CQVS9p1l.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-mkr1vC3N.js → Chat-YTjQHoC7.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-PR074hUN.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-CVU4xqti.js → Checkbox-5bwaOabq.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-rrNcByz3.js → Codegen-BFmNQ_Xe.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Cqu-zCvh.js → Col-BT_u4Dzp.js} +1 -1
- package/src/assets/web-panel/assets/{Community-RGRlSgXV.js → Community-CJP52u5b.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DBm6epOK.js → Compact-BpzhJE9i.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BgKw5iaW.js → Compliance-Cg7rfslp.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BqQcNO3Z.js → Cowork-JisxL6Yy.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DO5gTFNb.js → Cron-Bu7Ug_MC.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B8hbJNuN.js → Crosschain-CvuqoLdj.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B08bFJ2C.js → DID-C2u9G8Pu.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-xNdy_ifo.js → Dashboard-BFt5Yv3d.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-D-KIZgWL.js → Dropdown-DIaT9Wxq.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DKCvsaGo.js → EmailListRenderer-D_A601Y4.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-D_cfqama.js → FamilyGuardDashboard--IyQ8I8w.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B-UqQD68.js → Federation-BihWHxuY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BWWvWuJW.js → FormItemContext-BB8dOXc_.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CPchx6N7.js → GenericCardRenderer-DQYhj1HH.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Vx4co9Ff.js → Git-B-2QZxGf.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D4x0pp_m.js → Governance-CusSb-nG.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-T3KvwPYR.js → Inference-BAjmvPPL.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Ddv3KUv3.js → KnowledgeGraph-DoNYWKYq.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DfH-Dkae.js → Logs-B8fKWD-n.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DHW3PbCq.js → MarkdownRenderer-BlJm1J7E.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-tjgb0R3D.js → Marketplace-CyOscbSL.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DHAk5nYX.js → McpTools-Ex6Om5da.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-A2Yx7thM.js → Memory-CDcD8l8r.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BEmTVfN5.js → MobileBridge-xfBqoFDg.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DuFHUgE4.js → MobileProjects-BwObMMA2.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BDSll0OZ.js → Mtc-CIWd36OV.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CuBvluaS.js → MtcAudit-CPX0ouuA.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BmXAA-Sb.js → Multisig-BDJsIUuW.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-ci2stZAe.js → NLProgramming-DEkbuD3N.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-D-1RpqnS.js → Notes-DJpHRhH1.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-C0GyitIT.js → NotificationSettings-C1UZ-Qd5.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-U2bN-hj5.js → OrderTableRenderer-GlJtqLjT.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-BNZgpPci.js → Organization-Bbhj0fac.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CDidKmUN.js → Overflow-1H04x3kx.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BnreBaXq.js → P2P-CDpPe3et.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DwJUxO9j.js → PdhVaultBrowser-MUX0Bpvw.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BQGgJPH0.js → Permissions-A07-0Ci1.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-k_fSkCwL.js → PersonalDataHub-DhhDWxAZ.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-WGqKMqau.js → Pipeline-CyfbJfe-.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DtHj9Ymq.js → Privacy-CNFps3ED.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B3wH2SFC.js → ProjectInit--T-u3Dr5.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Cd0cgcA1.js → ProjectSettings-DJmrK2fC.js} +2 -2
- package/src/assets/web-panel/assets/Projects-Qx_MdX9k.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DTpxEXur.js → Providers-DLzzbOZd.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-B2v6gR-C.js → QrScannerModal-CexOomKS.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-D3Nr9xXR.js → QuickAsk-QklGi19_.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-C9inoMky.js → Recommend-Bb9kwSw8.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-DZuVNNN5.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-41KFG646.js → Reputation-Dr5cLP0N.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DqAaqqCv.js → Row-oCQHYv5t.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CMDpCDKc.js → RssFeed-IFDEykIR.js} +3 -3
- package/src/assets/web-panel/assets/{Search-B6mtegNL.js → Search-CspVIxDc.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BaePFVZ8.js → Security-Bm66o_DH.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DeG3Qscl.js → Services-DvanNqXl.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-D_QP7F90.js → Skeleton-CHjEe9_O.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DLGyUgIA.js → Skills-Cb8jWjMX.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BN2pxW1Q.js → Sla-DxZm1491.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BWsZPd8B.js → SpeechSettings-DWxEEclC.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-VOZRPODW.js → SyncSettings-FIvOFw5p.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-CyuLnDFR.js +1 -0
- package/src/assets/web-panel/assets/{Templates-eJSob-q0.js → Templates-CaNjzV_t.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Bdwk8Rwy.js → Tenant-DjlP6TmH.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-DwzGMniO.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-D5qkbPKT.js → TimelineRenderer-DoZ8y7y8.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DKgwn8hI.js → Tokens-390cg2TC.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-HlEHniGM.js → Trigger-CLrtCj5_.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CdPcsBpN.js → Trust-DpESfSPn.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-vAdXd-vG.js → UkeySign-CN6279O0.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-9hHBYFnH.js → VideoEditing-DPtAUlSe.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Dxh5d1yR.js → Wallet-nKOMV_1n.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BsFmLHkp.js → WebAuthn-HuXlSOc4.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Cn0OIwLn.js → WorkflowEditor-CUfFjARi.js} +1 -1
- package/src/assets/web-panel/assets/chat-6Eq0PcZJ.js +1 -0
- package/src/assets/web-panel/assets/{colors-Du9jzLN0.js → colors-BP_Sf6Iy.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DhEscfzw.js → compact-item-BufMKIh5.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CwzEfF3i.js → createContext-BBMXxWSW.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DgVKduH2.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DT_GSE6J.js → hasIn-fUK_tRO2.js} +1 -1
- package/src/assets/web-panel/assets/{index-tND8-TDU.js → index-2A5ph8b2.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8s5FxJY.js → index-3FuwBewR.js} +1 -1
- package/src/assets/web-panel/assets/{index-53z1YUxX.js → index-6GmBa4Kg.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFD0cEna.js → index-B2vS66eI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQWxDOvM.js → index-B7Etk0Te.js} +1 -1
- package/src/assets/web-panel/assets/{index-VeHs6qH0.js → index-B9WYSn4m.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGvgnfl9.js → index-BHy6yNiF.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3llLkYM.js → index-BMLHv389.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dny_ZnAO.js → index-BWKoBU8R.js} +1 -1
- package/src/assets/web-panel/assets/{index-DzjzrOli.js → index-Bkg4ZePE.js} +1 -1
- package/src/assets/web-panel/assets/{index-DN60VBn5.js → index-C44atv4k.js} +1 -1
- package/src/assets/web-panel/assets/{index-v5HLYCVa.js → index-CE2DdTP2.js} +1 -1
- package/src/assets/web-panel/assets/{index-BF-ZCVGE.js → index-CGjmILDm.js} +1 -1
- package/src/assets/web-panel/assets/{index-gFjYdstW.js → index-CW_G-MXw.js} +1 -1
- package/src/assets/web-panel/assets/{index-NA2oBLSB.js → index-CZ6Yt17L.js} +1 -1
- package/src/assets/web-panel/assets/{index-Mobw3PHs.js → index-CeASi4fr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWL3SYN3.js → index-CgiECHu2.js} +1 -1
- package/src/assets/web-panel/assets/{index-1LoutPJd.js → index-Cp8vhyZy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnHhFnwt.js → index-CwSf5pnf.js} +1 -1
- package/src/assets/web-panel/assets/{index-B6QDWRLk.js → index-D4_MuGkd.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-QkW1fp.js → index-D9vU25ij.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4SN3by5.js → index-DASluSqY.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyEhUJcu.js → index-DLpIs_P_.js} +1 -1
- package/src/assets/web-panel/assets/index-DOZTSoS7.js +1 -0
- package/src/assets/web-panel/assets/{index-BrkJ7JPm.js → index-DPdUNk1i.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cnok8mhZ.js → index-DVsqvI4M.js} +1 -1
- package/src/assets/web-panel/assets/index-DhpvjpqI.js +1 -0
- package/src/assets/web-panel/assets/{index-CAVW0cWM.js → index-DmkMXwnR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cc9aPkv-.js → index-DocdRcbd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnVVYKCE.js → index-Dyngbd29.js} +20 -20
- package/src/assets/web-panel/assets/{index-D8gt0j7r.js → index-GwdRUZ-x.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIYTjbv_.js → index-LvCBfTLo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhXay17G.js → index-cpEli44X.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQWENaZf.js → index-fzaMtSJ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfRDyY1q.js → index-pum7HYBA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgSR2WMG.js → index-t8N1tSeX.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5IytTND.js → index-uCbEN7cY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtRwLhee.js → index-wKTLbKyc.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4kZoXNr.js → index-wV6iGdpY.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cvt59c10.js → initDefaultProps-V5Fo95FM.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D15pPEzl.js → motion-BYWU0hUT.js} +1 -1
- package/src/assets/web-panel/assets/{move-N55KeXJ7.js → move-Cr1M-J2h.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CyFO1bYP.js → mtc-parser-BysQKi2N.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B5IXfxU2.js → omit-D1zHU8GC.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-CpVqsulV.js → pickAttrs-CUArxtfi.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-ME36sMF3.js → placementArrow-ChoYEys0.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BXAIR1r-.js → responsiveObserve-BQRs3Mo7.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BkOX3-Dp.js → slide-B8zbsCkg.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Cy4Aklpt.js → statusUtils-C2U8Gs6h.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-gUd2T206.js → styleChecker-Dd8MgL_V.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CaVD4o99.js → useFlexGapSupport-hknqY5NH.js} +1 -1
- package/src/assets/web-panel/assets/{useFs--pFGl0KD.js → useFs-CLTAmcfw.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D45iP86i.js → usePersonalDataHub-ByegHbiB.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BayoChH_.js → vnode-DqlAy5DP.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CpP38poi.js → zoom-DiXiztQn.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +115 -3
- package/src/commands/agent.js +10 -1
- package/src/commands/background-session.js +2 -1
- package/src/commands/context.js +69 -2
- package/src/data/changelog.json +26 -0
- package/src/gateways/terminal/PtyManager.js +45 -4
- package/src/gateways/ws/background-agent-protocol.js +38 -0
- package/src/gateways/ws/message-dispatcher.js +1 -0
- package/src/gateways/ws/remote-session-protocol.js +65 -6
- package/src/gateways/ws/ws-server.js +18 -2
- package/src/harness/background-task-manager.js +70 -2
- package/src/harness/feature-flags.js +15 -8
- package/src/harness/mcp-client.js +618 -43
- package/src/harness/worktree-isolator.js +14 -3
- package/src/lazy-dispatch.js +30 -1
- package/src/lib/agent-authority.js +22 -0
- package/src/lib/agent-core.js +3 -0
- package/src/lib/agent-sandbox.js +161 -0
- package/src/lib/agent-schedule-store.js +45 -22
- package/src/lib/agent-team/team-runner.js +22 -0
- package/src/lib/artifact-store.js +35 -0
- package/src/lib/async-hook-supervisor.cjs +13 -2
- package/src/lib/audit-mtc.js +3 -2
- package/src/lib/background-agent-supervisor.js +104 -3
- package/src/lib/background-interaction-journal.js +407 -0
- package/src/lib/background-interaction-resolver.js +23 -34
- package/src/lib/background-session-transport.js +12 -2
- package/src/lib/capability-manifest.js +41 -3
- package/src/lib/capability-negotiation.js +1 -1
- package/src/lib/channels/channel-manager.js +33 -0
- package/src/lib/channels/telegram-channel.js +23 -5
- package/src/lib/channels/webhook-channel.js +38 -15
- package/src/lib/chrome-connector.js +169 -23
- package/src/lib/config-manager.js +23 -9
- package/src/lib/context-breakdown.js +31 -0
- package/src/lib/cowork-cron.js +274 -32
- package/src/lib/cross-chain-mtc.js +3 -2
- package/src/lib/durable-security-store.js +124 -0
- package/src/lib/event-runtime-host.js +67 -6
- package/src/lib/event-runtime-store.js +163 -0
- package/src/lib/goal-store.js +32 -12
- package/src/lib/headless-manifest.js +2 -1
- package/src/lib/hook-environment.cjs +58 -0
- package/src/lib/hook-manager.js +12 -5
- package/src/lib/hook-runner.cjs +122 -28
- package/src/lib/hook-runner.js +7 -2
- package/src/lib/hooks-v2-producers.js +36 -0
- package/src/lib/hooks-v2-runtime.js +329 -52
- package/src/lib/interaction-adapter.js +60 -19
- package/src/lib/interaction-binding.js +64 -0
- package/src/lib/json-schema-output.js +439 -14
- package/src/lib/json-schema-validate.js +514 -883
- package/src/lib/lan-pairing-tokens.js +115 -57
- package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
- package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
- package/src/lib/lsp/lsp-client.js +4 -0
- package/src/lib/lsp/lsp-manager.js +3 -0
- package/src/lib/lsp/lsp-server-registry.js +18 -0
- package/src/lib/mcp-client.js +1 -0
- package/src/lib/mcp-oauth.js +35 -21
- package/src/lib/packer/pkg-config-generator.js +3 -0
- package/src/lib/permission-decision.js +99 -0
- package/src/lib/plugin-monitor-supervisor.js +3 -0
- package/src/lib/plugin-runtime/bin.js +1148 -70
- package/src/lib/plugin-runtime/capabilities.js +50 -0
- package/src/lib/plugin-runtime/capability-consent.js +42 -35
- package/src/lib/plugin-runtime/hooks.js +36 -9
- package/src/lib/plugin-runtime/install.js +23 -7
- package/src/lib/plugin-runtime/lsp.js +4 -0
- package/src/lib/plugin-runtime/manifest.js +112 -8
- package/src/lib/plugin-runtime/mcp.js +30 -5
- package/src/lib/plugin-runtime/monitors.js +11 -0
- package/src/lib/plugin-runtime/plugin-options.js +94 -38
- package/src/lib/plugin-runtime/policy.js +29 -2
- package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
- package/src/lib/plugin-runtime/scopes.js +27 -13
- package/src/lib/plugin-runtime/trust.js +36 -31
- package/src/lib/process-execution-broker/credential-agent.js +114 -16
- package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
- package/src/lib/process-execution-broker/credential-transport.js +378 -0
- package/src/lib/process-execution-broker/index.js +765 -49
- package/src/lib/process-execution-broker/platform-sandbox.js +4233 -138
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +3856 -0
- package/src/lib/project-mcp-trust.js +21 -26
- package/src/lib/protocol-replay.js +19 -12
- package/src/lib/repl-bang-memorize.js +67 -10
- package/src/lib/settings-hooks.cjs +13 -0
- package/src/lib/skill-loader.js +83 -10
- package/src/lib/slash-commands.js +27 -4
- package/src/lib/sync-credentials.js +5 -4
- package/src/lib/turn-binding.js +8 -6
- package/src/repl/agent-repl.js +117 -31
- package/src/repl/repl-turn-binding.js +5 -2
- package/src/runtime/agent-core.js +699 -70
- package/src/runtime/agent-runtime.js +13 -1
- package/src/runtime/coding-agent-contract-shared.cjs +3 -3
- package/src/runtime/headless-runner.js +105 -7
- package/src/runtime/headless-stream.js +209 -23
- package/src/runtime/mcp-config.js +29 -17
- package/src/runtime/policies/agent-policy.js +2 -0
- package/src/workers/background-agent-worker.js +128 -13
- package/src/assets/web-panel/assets/ChatBubbleRenderer-C7bofJuA.js +0 -1
- package/src/assets/web-panel/assets/Projects-BbgmyQnS.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-Bqk3EYSu.js +0 -4
- package/src/assets/web-panel/assets/Tasks-3bDAUz8K.js +0 -1
- package/src/assets/web-panel/assets/Terminal-CsMLKIoV.js +0 -3
- package/src/assets/web-panel/assets/chat-CJ19O6Dh.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BBMFnsja.js +0 -1
- package/src/assets/web-panel/assets/index-Do8JMV4N.js +0 -1
- 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
|
-
|
|
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
|
-
|
|
162
|
-
|
|
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
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
...
|
|
129
|
-
hooks: group.hooks
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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(
|
|
178
|
-
|
|
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(
|
|
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(
|
|
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({
|
|
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,
|
|
427
|
-
if (typeof
|
|
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 {
|
|
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)
|
|
39
|
-
`
|
|
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
|
-
...
|
|
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
|
|