chainlesschain 0.162.179 → 0.162.181
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 +6 -3
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-BF13YdB-.js → AIOps-cq0dwbnf.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-B9y67AjF.js → ActionButton-CvcgGl3w.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-FcdDHoSC.js → Analytics-hM2-jFqg.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CRm_zwSp.js → AppLayout-B9_Gsd_g.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-Cbo7-usf.js → Artifacts-B7bu52Og.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-vMaLpkHC.js → Audit-DThfDgqB.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-FiUY692t.js → BackgroundAgents-DjlFiD4v.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BK80j_GQ.js → Backup-CK9xJKnG.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-ChNMuYR1.js → BaseInput-DEiSU8K8.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-928UREpm.js → Chat-CpT96czj.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BKPPNmZI.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-dFW-zDbe.js → Checkbox-C1GfDnO0.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BCcNJUj2.js → Codegen-3DAKgiLx.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DcEkLv70.js → Col-74cOwZU1.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DihBRRqg.js → Community-tn9Kkz9j.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DGYxwWET.js → Compact-BcoXH7m4.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-OnYe1vS4.js → Compliance-DIPGUBgi.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CmWB54c2.js → Cowork-doD5_91c.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BrANb2uw.js → Cron-C-IDvubz.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-2HgWzSxg.js → Crosschain-CdcCoBdj.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DdDwNI6K.js → DID-DdH5aMMA.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-D6PnE78-.js → Dashboard-DHLA4mm0.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-ClzvSN4O.js → Dropdown-dEeCt7Md.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BUk9B727.js → EmailListRenderer-BMaecFv9.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-C8hi3v7i.js → FamilyGuardDashboard-DUaUukTN.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B5SP8xkg.js → Federation-CMBE0_rp.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DWzJ8AU5.js → FormItemContext-PG-JDbXq.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-3E3Q3rjG.js → GenericCardRenderer-Bcb0p88m.js} +1 -1
- package/src/assets/web-panel/assets/{Git-z8IdCMId.js → Git-Bgv15myB.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CgqCF9lX.js → Governance-DB8YTArI.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-zgS-AuH9.js → Inference-BQMwCWaS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BdbgmESJ.js → KnowledgeGraph-B1_ZziiB.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BHpknnjy.js → Logs-DovEEnt_.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-D201OL4T.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Di9sAR7j.js → Marketplace-BlCXSpyB.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DtnR9Z_A.js → McpTools-CsCR09Wj.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BaX9uuXD.js → Memory-CBVRLKno.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-xelyKWTY.js → MobileBridge-C9OIafgA.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BiFTOGBN.js → MobileProjects-D_zoJ8Xs.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-bV3OzTiO.js → Mtc-vE-HdvLj.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-BkwvFTdZ.js → MtcAudit-CPLaekCd.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-_6HQQ-oC.js → Multisig-C_UP9C2o.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BBYhmWQZ.js → NLProgramming-2nODJcU1.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cq-6dQnU.js → Notes-BhE-SJGu.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-ILZ9zkX6.js → NotificationSettings-D21q7BNU.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DgmTBEvk.js → OrderTableRenderer-0b62GYOD.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CkLnWwCk.js → Organization-CEqmw_sb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CWVHZbhf.js → Overflow-MW-gMDO_.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BXbqETkr.js → P2P-CY0hjI_G.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser--0JR-0ex.js → PdhVaultBrowser-BbWh7Man.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-Cz9_tfSy.js → Permissions-ChqEA_4Q.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Dq7OWYtx.js → PersonalDataHub-B3YrbYfD.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DHPUNcc-.js → Pipeline-B8WBhhlW.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CEAbrDkS.js → Privacy-Cmb0PXNx.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CJYfclXE.js → ProjectInit-hF6zW3Nz.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-oCTgPCgp.js → ProjectSettings-BFSVfpW0.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DAWkVFkc.js +1 -0
- package/src/assets/web-panel/assets/{Providers-BLTZtzTG.js → Providers-B8yux8Dx.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-C0b0TQB3.js → QrScannerModal-N76cQluO.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-tOl6N_gM.js → QuickAsk-ClvZ0KYR.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DPzKr8yr.js → Recommend-B-GfgBpT.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-mlglCdQi.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-Cji1Vl79.js → Reputation-DJIZzQeG.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D-NERWf2.js → Row-COzxu_bb.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DzlgmAlB.js → RssFeed-CoYsJQuE.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Cs0SWSa4.js → Search-DC77Mq9S.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DL7EzcUO.js → Security-Loy2EdMO.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CT-PzgTd.js → Services-GUD07Eu0.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-tByJWdJg.js → Skeleton-DWzkptYU.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-Dnr_6TTl.js → Skills-CEDn1r-Z.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-4O-yq0LY.js → Sla-ub_k4pXh.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BYBVg1oR.js → SpeechSettings-D7HLX9CA.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CpOYPbE5.js → SyncSettings-DbwOvl6m.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CGVhOVh6.js → Tasks-CBQzoAu5.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BuHFxR4X.js → Templates-BNVeIhud.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DxDxHzgf.js → Tenant-PS9AzhXU.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B9g_nISg.js → Terminal-Cgb4eLB_.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DlrBC_4A.js → TimelineRenderer-CrmXMOkg.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DvBlYZ6i.js → Tokens-DD-VDHw1.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dg8G9bhF.js → Trigger-BsoN_n-n.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-COICx4E-.js → Trust-n8LmN4ZV.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B4pOBv7T.js → UkeySign-C9_7MImA.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Qt4NMA8Q.js → VideoEditing-DyBteNgn.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-X1EkQc2Z.js → Wallet-BS5ixeXI.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CyeEFBE5.js → WebAuthn-spc4UImU.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-nwzbMiVQ.js → WorkflowEditor-D7iVvaBO.js} +1 -1
- package/src/assets/web-panel/assets/chat-6CmBkHrL.js +1 -0
- package/src/assets/web-panel/assets/{colors-5Isz5lhJ.js → colors-BGoCLkxI.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DsFQS3Oy.js → compact-item-fYZBetMO.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-OcEXp2uz.js → createContext-BeM-1UVj.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CZvC4p09.js → hasIn-CE7ZuEnV.js} +1 -1
- package/src/assets/web-panel/assets/{index-BF1sab0Q.js → index--lap6cf7.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7yeL3rf.js → index-ATcSr_2O.js} +1 -1
- package/src/assets/web-panel/assets/{index-VkFXA9N-.js → index-B2U-ObMq.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSmGGg5h.js → index-B3CDgvNW.js} +1 -1
- package/src/assets/web-panel/assets/{index-jrNIrpq4.js → index-B4wiTEOM.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8ibl7bc.js → index-B8BsdNV_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DOLozRk8.js → index-BEVm0lCS.js} +10 -10
- package/src/assets/web-panel/assets/{index-BPgc_bdR.js → index-BNZDILcO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTZZzlMO.js → index-BU_2qiDk.js} +1 -1
- package/src/assets/web-panel/assets/{index-Vubi6Tf5.js → index-BV551878.js} +1 -1
- package/src/assets/web-panel/assets/{index-nXrnztXp.js → index-BfPL-m46.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN8lPVpQ.js → index-BowH1eLQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgE2BZl2.js → index-BsMfoaeo.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd5b2JHB.js → index-BunaQCa0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQlGw0nQ.js → index-C0v6YKKO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Do6FJK32.js → index-C4SJVjs4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqvo1f9T.js → index-C9Y3k0HI.js} +1 -1
- package/src/assets/web-panel/assets/{index-LUdgPZg9.js → index-CIpVrf5P.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpD2O7_p.js → index-CRLjEP1H.js} +1 -1
- package/src/assets/web-panel/assets/{index-r_9NG6P7.js → index-CRnUE8Cb.js} +1 -1
- package/src/assets/web-panel/assets/{index-FIgMAfBh.js → index-Cip8emOQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-RsQ1lFDV.js → index-CpIGIB85.js} +1 -1
- package/src/assets/web-panel/assets/{index-DGJupV0S.js → index-D1r9tT3J.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpglwPWl.js → index-DT3zPSVX.js} +1 -1
- package/src/assets/web-panel/assets/index-DacrAdc-.js +1 -0
- package/src/assets/web-panel/assets/{index-CG3B2wCF.js → index-De0quFDw.js} +1 -1
- package/src/assets/web-panel/assets/{index-CxA2PDK1.js → index-DoXk5KJ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaGKOVvQ.js → index-DsvfrESp.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7CtJYXq.js → index-Dw1PyYPm.js} +1 -1
- package/src/assets/web-panel/assets/index-EHzNJozo.js +1 -0
- package/src/assets/web-panel/assets/{index-Bu9NXvIa.js → index-MtOuq2i6.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsZkTaa3.js → index-Puq6Luf1.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPE4zHXF.js → index-QIpnpZgz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bsb-iylv.js → index-RMZ8a7Yt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMtGRQqw.js → index-WUrJ6S1j.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3lWvhk4.js → index-YjcumOZ4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmVbCGx_.js → index-lJBjB1QX.js} +1 -1
- package/src/assets/web-panel/assets/{index-A5SHQW_M.js → index-ukg99D1V.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFJgt6qM.js → index-zb7rVOhV.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cdgep9YT.js → initDefaultProps-CYHMs1ag.js} +1 -1
- package/src/assets/web-panel/assets/{motion-7yn1ACEm.js → motion-DDB2Ffk5.js} +1 -1
- package/src/assets/web-panel/assets/{move-D8o133Xc.js → move-Bg3cD-dX.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CClHIG9V.js → mtc-parser-B5nedjTS.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CLnrPE2d.js → omit-BHyuUILu.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-1CTWoZWl.js → pickAttrs-C9YQnEN9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-xNNtS4Sp.js → placementArrow-DBUFYUe7.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-ypzAofs7.js → responsiveObserve-nBs2Obnk.js} +1 -1
- package/src/assets/web-panel/assets/{slide-QsrY9UwD.js → slide-DkCEaXNU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DSdThzOB.js → statusUtils-aqE1Wi6U.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B_kKM8Ob.js → styleChecker-CN5bhfHB.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CcdTBNV9.js → useFlexGapSupport-B_oX_kvJ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BuAH2XFU.js → useFs-rCuXHeme.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-B3zWiG4A.js → usePersonalDataHub-DZR9Abyd.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-B45Rc-CQ.js → vnode-ConCYQlX.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DaYZDU5f.js → zoom-CUdDxG5M.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +4 -1
- package/src/commands/background-session.js +2 -1
- package/src/commands/context.js +69 -2
- package/src/commands/hub.js +30 -24
- package/src/data/changelog.json +27 -1
- 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 +8 -1
- package/src/harness/feature-flags.js +15 -8
- package/src/harness/mcp-client.js +618 -43
- package/src/lazy-dispatch.js +30 -1
- package/src/lib/agent-authority.js +22 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-sandbox.js +161 -0
- 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 +1 -0
- 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 +1 -0
- package/src/lib/permission-decision.js +99 -0
- package/src/lib/plugin-monitor-supervisor.js +3 -0
- 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 +50 -2
- 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 +7 -3
- 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 +408 -19
- package/src/lib/process-execution-broker/platform-sandbox.js +561 -21
- package/src/lib/process-execution-broker/windows-sandbox.ps1 +999 -0
- package/src/lib/project-mcp-trust.js +21 -26
- package/src/lib/protocol-replay.js +19 -12
- package/src/lib/settings-hooks.cjs +13 -0
- package/src/lib/skill-loader.js +83 -10
- package/src/lib/sync-credentials.js +5 -4
- package/src/lib/turn-binding.js +8 -6
- package/src/repl/agent-repl.js +113 -28
- package/src/repl/repl-turn-binding.js +5 -2
- package/src/runtime/agent-core.js +331 -26
- package/src/runtime/coding-agent-contract-shared.cjs +3 -3
- package/src/runtime/headless-runner.js +101 -4
- 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-DvySUzxJ.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-DkxCweb1.js +0 -1
- package/src/assets/web-panel/assets/Projects-ClomCrN0.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-pRgaWsUK.js +0 -4
- package/src/assets/web-panel/assets/chat-Bvl-ojg2.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CSVgo71Z.js +0 -1
- package/src/assets/web-panel/assets/index-DMIWh9fu.js +0 -1
- package/src/assets/web-panel/assets/index-ssTvV1l6.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,9 +191,22 @@ export function parsePluginManifest(root) {
|
|
|
174
191
|
conventionPath: ["monitors", "monitors.json"],
|
|
175
192
|
listKey: "monitors",
|
|
176
193
|
});
|
|
177
|
-
c.lsp = resolveLsp(
|
|
194
|
+
c.lsp = resolveLsp(
|
|
195
|
+
abs,
|
|
196
|
+
manifest,
|
|
197
|
+
safeResolve,
|
|
198
|
+
errors,
|
|
199
|
+
warnings,
|
|
200
|
+
manifestSandboxPolicy,
|
|
201
|
+
);
|
|
178
202
|
c.bin = resolveBin(abs, manifest, safeResolve, warnings);
|
|
179
203
|
c.settings = resolveSettings(abs, manifest, safeResolve);
|
|
204
|
+
if (manifestSandboxPolicy && c.bin.length > 0) {
|
|
205
|
+
errors.push(
|
|
206
|
+
"manifest.sandboxPolicy cannot currently protect plugin bin executables; " +
|
|
207
|
+
"top-level sandbox requirements with bin are not supported",
|
|
208
|
+
);
|
|
209
|
+
}
|
|
180
210
|
|
|
181
211
|
// ── declared capabilities + options schema (P1) ──
|
|
182
212
|
const hasPermissions =
|
|
@@ -363,7 +393,14 @@ function extractList(obj, listKey) {
|
|
|
363
393
|
return { count: 0, names: [] };
|
|
364
394
|
}
|
|
365
395
|
|
|
366
|
-
function resolveLsp(
|
|
396
|
+
function resolveLsp(
|
|
397
|
+
root,
|
|
398
|
+
manifest,
|
|
399
|
+
safeResolve,
|
|
400
|
+
errors,
|
|
401
|
+
warnings,
|
|
402
|
+
manifestSandboxPolicy,
|
|
403
|
+
) {
|
|
367
404
|
let content = manifest.lsp;
|
|
368
405
|
// Convention file `.lsp.json`.
|
|
369
406
|
if (!content) {
|
|
@@ -392,12 +429,23 @@ function resolveLsp(root, manifest, safeResolve, errors, warnings) {
|
|
|
392
429
|
warnings.push("lsp server entry missing languageId/command — skipped");
|
|
393
430
|
continue;
|
|
394
431
|
}
|
|
432
|
+
let sandboxPolicy;
|
|
433
|
+
try {
|
|
434
|
+
sandboxPolicy = mergePluginSandboxPolicies(
|
|
435
|
+
manifestSandboxPolicy,
|
|
436
|
+
s.sandboxPolicy,
|
|
437
|
+
);
|
|
438
|
+
} catch (err) {
|
|
439
|
+
errors.push(`lsp server "${s.languageId}": ${err.message}`);
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
395
442
|
out.push({
|
|
396
443
|
languageId: s.languageId,
|
|
397
444
|
command: s.command,
|
|
398
445
|
args: Array.isArray(s.args) ? s.args.map(String) : [],
|
|
399
446
|
extensions: Array.isArray(s.extensions) ? s.extensions.map(String) : [],
|
|
400
447
|
id: typeof s.id === "string" ? s.id : s.command,
|
|
448
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
401
449
|
});
|
|
402
450
|
}
|
|
403
451
|
return out;
|
|
@@ -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
|
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import fs from "fs";
|
|
22
22
|
import path from "path";
|
|
23
|
+
import crypto from "node:crypto";
|
|
23
24
|
import { getElectronUserDataDir } from "../paths.js";
|
|
24
25
|
import {
|
|
25
26
|
optionDefaults,
|
|
@@ -31,12 +32,16 @@ import {
|
|
|
31
32
|
isSecretRef,
|
|
32
33
|
secretRef,
|
|
33
34
|
} from "../secret-store.js";
|
|
35
|
+
import { withFileLock } from "../with-file-lock.js";
|
|
34
36
|
|
|
35
37
|
export const _deps = {
|
|
36
38
|
existsSync: fs.existsSync,
|
|
37
39
|
readFileSync: fs.readFileSync,
|
|
40
|
+
renameSync: fs.renameSync,
|
|
41
|
+
unlinkSync: fs.unlinkSync,
|
|
38
42
|
writeFileSync: fs.writeFileSync,
|
|
39
43
|
mkdirSync: fs.mkdirSync,
|
|
44
|
+
withFileLock,
|
|
40
45
|
secretStore: () => createSecretStore(),
|
|
41
46
|
userStorePath: () =>
|
|
42
47
|
path.join(getElectronUserDataDir(), "plugin-options.json"),
|
|
@@ -44,23 +49,54 @@ export const _deps = {
|
|
|
44
49
|
path.join(cwd || process.cwd(), ".chainlesschain", "plugin-options.json"),
|
|
45
50
|
};
|
|
46
51
|
|
|
47
|
-
function readJsonObject(p) {
|
|
52
|
+
function readJsonObject(p, { failIfUnavailable = false } = {}) {
|
|
48
53
|
try {
|
|
49
54
|
if (!_deps.existsSync(p)) return {};
|
|
50
55
|
const data = JSON.parse(_deps.readFileSync(p, "utf8"));
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
if (data && typeof data === "object" && !Array.isArray(data)) return data;
|
|
57
|
+
throw new TypeError("top-level value must be an object");
|
|
58
|
+
} catch (cause) {
|
|
59
|
+
if (failIfUnavailable) {
|
|
60
|
+
const error = new Error(`Plugin option store is unavailable: ${p}`, {
|
|
61
|
+
cause,
|
|
62
|
+
});
|
|
63
|
+
error.code = "PLUGIN_OPTION_STORE_UNAVAILABLE";
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
53
66
|
return {};
|
|
54
67
|
}
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
function writeJsonObject(p, obj) {
|
|
58
71
|
_deps.mkdirSync(path.dirname(p), { recursive: true });
|
|
59
|
-
|
|
72
|
+
const tmp = `${p}.${process.pid}.${crypto.randomUUID()}.tmp`;
|
|
73
|
+
try {
|
|
74
|
+
_deps.writeFileSync(tmp, `${JSON.stringify(obj, null, 2)}\n`, {
|
|
75
|
+
encoding: "utf8",
|
|
76
|
+
mode: 0o600,
|
|
77
|
+
});
|
|
78
|
+
_deps.renameSync(tmp, p);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
try {
|
|
81
|
+
_deps.unlinkSync(tmp);
|
|
82
|
+
} catch {
|
|
83
|
+
// Preserve the original persistence error.
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function withOptionStoreLock(p, body) {
|
|
90
|
+
_deps.mkdirSync(path.dirname(p), { recursive: true, mode: 0o700 });
|
|
91
|
+
return _deps.withFileLock(p, body, { failIfUnavailable: true });
|
|
60
92
|
}
|
|
61
93
|
|
|
62
94
|
/** Load a plugin's option VALUES at the given scope (`user` | `project`). */
|
|
63
|
-
export function loadPluginOptionValues(
|
|
95
|
+
export function loadPluginOptionValues(
|
|
96
|
+
name,
|
|
97
|
+
scope,
|
|
98
|
+
{ cwd, schema, secretStore } = {},
|
|
99
|
+
) {
|
|
64
100
|
const p =
|
|
65
101
|
scope === "project" ? _deps.projectStorePath(cwd) : _deps.userStorePath();
|
|
66
102
|
const store = readJsonObject(p);
|
|
@@ -71,7 +107,9 @@ export function loadPluginOptionValues(name, scope, { cwd, schema, secretStore }
|
|
|
71
107
|
for (const [key, desc] of Object.entries(normalized)) {
|
|
72
108
|
if (!desc?.sensitive || !isSecretRef(out[key])) continue;
|
|
73
109
|
try {
|
|
74
|
-
const value = (secretStore || _deps.secretStore)().get(
|
|
110
|
+
const value = (secretStore || _deps.secretStore)().get(
|
|
111
|
+
out[key].__cc_secret_ref,
|
|
112
|
+
);
|
|
75
113
|
if (value != null) out[key] = value;
|
|
76
114
|
else delete out[key];
|
|
77
115
|
} catch {
|
|
@@ -92,40 +130,58 @@ export function setPluginOptionValues(
|
|
|
92
130
|
) {
|
|
93
131
|
const p =
|
|
94
132
|
scope === "project" ? _deps.projectStorePath(cwd) : _deps.userStorePath();
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
133
|
+
return withOptionStoreLock(p, () => {
|
|
134
|
+
const store = readJsonObject(p, { failIfUnavailable: true });
|
|
135
|
+
const input = values && typeof values === "object" ? values : {};
|
|
136
|
+
const persisted = { ...input };
|
|
137
|
+
const normalized = schema || {};
|
|
138
|
+
let secrets = null;
|
|
139
|
+
const getSecrets = () => {
|
|
140
|
+
if (!secrets) secrets = (secretStore || _deps.secretStore)();
|
|
141
|
+
return secrets;
|
|
142
|
+
};
|
|
143
|
+
const rejectedSensitive = [];
|
|
144
|
+
for (const [key, desc] of Object.entries(normalized)) {
|
|
145
|
+
if (
|
|
146
|
+
!desc?.sensitive ||
|
|
147
|
+
!Object.prototype.hasOwnProperty.call(input, key)
|
|
148
|
+
) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
// Project files are shareable and must never receive a sensitive value.
|
|
152
|
+
if (scope === "project") {
|
|
153
|
+
delete persisted[key];
|
|
154
|
+
rejectedSensitive.push(key);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (input[key] == null || input[key] === "") {
|
|
158
|
+
delete persisted[key];
|
|
159
|
+
try {
|
|
160
|
+
getSecrets().delete(`${name}/${key}`);
|
|
161
|
+
} catch {
|
|
162
|
+
// Missing secrets already behave as absent on read.
|
|
163
|
+
}
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
getSecrets().set(`${name}/${key}`, input[key]);
|
|
167
|
+
persisted[key] = secretRef(`${name}/${key}`);
|
|
112
168
|
}
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
169
|
+
if (rejectedSensitive.length > 0) {
|
|
170
|
+
persisted.__cc_rejected_sensitive = [
|
|
171
|
+
...new Set(rejectedSensitive),
|
|
172
|
+
].sort();
|
|
173
|
+
} else if (
|
|
174
|
+
Object.prototype.hasOwnProperty.call(
|
|
175
|
+
persisted,
|
|
176
|
+
"__cc_rejected_sensitive",
|
|
177
|
+
)
|
|
178
|
+
) {
|
|
179
|
+
delete persisted.__cc_rejected_sensitive;
|
|
117
180
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
persisted.__cc_rejected_sensitive = [...new Set(rejectedSensitive)].sort();
|
|
123
|
-
} else if (Object.prototype.hasOwnProperty.call(persisted, "__cc_rejected_sensitive")) {
|
|
124
|
-
delete persisted.__cc_rejected_sensitive;
|
|
125
|
-
}
|
|
126
|
-
store[name] = persisted;
|
|
127
|
-
writeJsonObject(p, store);
|
|
128
|
-
return { name, scope, path: p };
|
|
181
|
+
store[name] = persisted;
|
|
182
|
+
writeJsonObject(p, store);
|
|
183
|
+
return { name, scope, path: p };
|
|
184
|
+
});
|
|
129
185
|
}
|
|
130
186
|
|
|
131
187
|
/** Provided keys of `values` (that exist in schema) accepted at `scope`. */
|