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
|
@@ -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`. */
|
|
@@ -164,6 +164,22 @@ export function capabilityConsentRequired(managed, env) {
|
|
|
164
164
|
);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Require every loadable plugin to opt into the capability model with an
|
|
169
|
+
* explicit `permissions` block. Mandatory consent implies this gate: otherwise
|
|
170
|
+
* a legacy plugin could bypass consent simply by omitting the declaration.
|
|
171
|
+
*/
|
|
172
|
+
export function capabilityDeclarationsRequired(managed, env) {
|
|
173
|
+
const runtimeEnv = env || process.env;
|
|
174
|
+
const raw = runtimeEnv.CC_REQUIRE_PLUGIN_CAPABILITIES;
|
|
175
|
+
if (raw != null && /^(1|true|yes|on)$/i.test(String(raw).trim())) return true;
|
|
176
|
+
return (
|
|
177
|
+
managed?.requirePluginCapabilityDeclarations === true ||
|
|
178
|
+
managed?.requirePluginCapabilityDeclarations === "require" ||
|
|
179
|
+
capabilityConsentRequired(managed, runtimeEnv)
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
167
183
|
/**
|
|
168
184
|
* Drop plugins that DECLARE capabilities but whose current capability SET has
|
|
169
185
|
* not been consented (first request or any widening). Fail-closed: a consent
|
|
@@ -175,12 +191,23 @@ export function capabilityConsentRequired(managed, env) {
|
|
|
175
191
|
* @param {Array<{name, scope, manifest}>} plugins
|
|
176
192
|
* @returns {{ kept: Array, dropped: Array<{name, reason}> }}
|
|
177
193
|
*/
|
|
178
|
-
export function filterByCapabilityConsent(
|
|
194
|
+
export function filterByCapabilityConsent(
|
|
195
|
+
plugins,
|
|
196
|
+
{ requireDeclarations = false } = {},
|
|
197
|
+
) {
|
|
179
198
|
const kept = [];
|
|
180
199
|
const dropped = [];
|
|
181
200
|
for (const p of plugins) {
|
|
182
201
|
if (!p.manifest?.capabilitiesDeclared) {
|
|
183
|
-
|
|
202
|
+
if (requireDeclarations) {
|
|
203
|
+
dropped.push({
|
|
204
|
+
name: p.name,
|
|
205
|
+
reason:
|
|
206
|
+
"capability declaration required: add an explicit `permissions` block to plugin.json",
|
|
207
|
+
});
|
|
208
|
+
} else {
|
|
209
|
+
kept.push(p); // migration window: legacy declaration remains compatible
|
|
210
|
+
}
|
|
184
211
|
continue;
|
|
185
212
|
}
|
|
186
213
|
let consented = false;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize the small, declarative sandbox contract exposed to plugins.
|
|
3
|
+
*
|
|
4
|
+
* Plugins may require filesystem and/or network isolation for processes they
|
|
5
|
+
* cause the CLI to spawn. They may not select a sandbox profile or claim other
|
|
6
|
+
* broker guarantees. Keeping this layer narrower than ProcessExecutionBroker's
|
|
7
|
+
* internal contract prevents plugin-controlled policy from weakening managed
|
|
8
|
+
* defaults while still allowing an explicit requirement to fail closed.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export const PLUGIN_SANDBOX_BOUNDARIES = Object.freeze([
|
|
12
|
+
"filesystem",
|
|
13
|
+
"network",
|
|
14
|
+
]);
|
|
15
|
+
|
|
16
|
+
const SUPPORTED_BOUNDARIES = new Set(PLUGIN_SANDBOX_BOUNDARIES);
|
|
17
|
+
|
|
18
|
+
function invalidPolicy(message) {
|
|
19
|
+
const error = new Error(message);
|
|
20
|
+
error.code = "ERR_PLUGIN_SANDBOX_POLICY_INVALID";
|
|
21
|
+
return error;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {unknown} raw
|
|
26
|
+
* @param {{ label?: string }} [opts]
|
|
27
|
+
* @returns {{requiredBoundaries: string[]}|null}
|
|
28
|
+
*/
|
|
29
|
+
export function normalizePluginSandboxPolicy(raw, opts = {}) {
|
|
30
|
+
const label = opts.label || "sandboxPolicy";
|
|
31
|
+
if (raw === undefined || raw === null) return null;
|
|
32
|
+
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
33
|
+
throw invalidPolicy(`${label} must be an object`);
|
|
34
|
+
}
|
|
35
|
+
const unsupportedKeys = Object.keys(raw).filter(
|
|
36
|
+
(key) => key !== "requiredBoundaries",
|
|
37
|
+
);
|
|
38
|
+
if (unsupportedKeys.length > 0) {
|
|
39
|
+
throw invalidPolicy(
|
|
40
|
+
`${label} contains unsupported field: ${unsupportedKeys[0]}`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const boundaries = raw.requiredBoundaries;
|
|
45
|
+
if (boundaries === undefined) return null;
|
|
46
|
+
if (!Array.isArray(boundaries)) {
|
|
47
|
+
throw invalidPolicy(`${label}.requiredBoundaries must be an array`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const requiredBoundaries = [];
|
|
51
|
+
for (const boundary of boundaries) {
|
|
52
|
+
if (
|
|
53
|
+
typeof boundary !== "string" ||
|
|
54
|
+
!SUPPORTED_BOUNDARIES.has(boundary)
|
|
55
|
+
) {
|
|
56
|
+
throw invalidPolicy(
|
|
57
|
+
`${label}.requiredBoundaries contains unsupported boundary: ${String(boundary)}`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
if (!requiredBoundaries.includes(boundary)) {
|
|
61
|
+
requiredBoundaries.push(boundary);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return requiredBoundaries.length > 0 ? { requiredBoundaries } : null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Merge manifest/component/descriptor requirements additively. A child
|
|
70
|
+
* descriptor can require more isolation, but cannot remove a manifest-level
|
|
71
|
+
* requirement.
|
|
72
|
+
*/
|
|
73
|
+
export function mergePluginSandboxPolicies(...policies) {
|
|
74
|
+
const requiredBoundaries = [];
|
|
75
|
+
for (const raw of policies) {
|
|
76
|
+
const policy = normalizePluginSandboxPolicy(raw);
|
|
77
|
+
for (const boundary of policy?.requiredBoundaries || []) {
|
|
78
|
+
if (!requiredBoundaries.includes(boundary)) {
|
|
79
|
+
requiredBoundaries.push(boundary);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return requiredBoundaries.length > 0 ? { requiredBoundaries } : null;
|
|
84
|
+
}
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
filterByManagedPolicy,
|
|
30
30
|
filterByCapabilityConsent,
|
|
31
31
|
capabilityConsentRequired,
|
|
32
|
+
capabilityDeclarationsRequired,
|
|
32
33
|
warnDroppedOnce,
|
|
33
34
|
} from "./policy.js";
|
|
34
35
|
|
|
@@ -135,13 +136,20 @@ export function discoverPlugins(opts = {}) {
|
|
|
135
136
|
const byName = new Map(); // name → record (later scope overrides earlier)
|
|
136
137
|
for (const scope of scopes) {
|
|
137
138
|
const root = scopeRoot(scope, opts);
|
|
138
|
-
if (!dirExists(root)) continue;
|
|
139
|
-
for (const encoded of listDirs(root)) {
|
|
139
|
+
if (!dirExists(root, opts.strictIo === true)) continue;
|
|
140
|
+
for (const encoded of listDirs(root, opts.strictIo === true)) {
|
|
140
141
|
const nameDir = path.join(root, encoded);
|
|
141
|
-
const version = activeVersionForDir(nameDir);
|
|
142
|
+
const version = activeVersionForDir(nameDir, opts.strictIo === true);
|
|
142
143
|
if (!version) continue;
|
|
143
144
|
const versionDir = path.join(nameDir, version);
|
|
144
145
|
const manifest = parsePluginManifest(versionDir);
|
|
146
|
+
if (opts.strictIo === true && manifest.ok !== true) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`plugin manifest is not safely loadable at ${versionDir}: ${
|
|
149
|
+
manifest.errors?.join("; ") || "unknown manifest error"
|
|
150
|
+
}`,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
145
153
|
manifest.scope = scope;
|
|
146
154
|
const name = manifest.metadata?.name || encoded;
|
|
147
155
|
byName.set(name, {
|
|
@@ -163,9 +171,10 @@ export function discoverPlugins(opts = {}) {
|
|
|
163
171
|
managedSettingsFile: opts.managedSettingsFile,
|
|
164
172
|
});
|
|
165
173
|
const consentGate = capabilityConsentRequired(managed, opts.env);
|
|
174
|
+
const declarationsGate = capabilityDeclarationsRequired(managed, opts.env);
|
|
166
175
|
// Default (no managed policy AND consent enforcement off): byte-identical —
|
|
167
176
|
// return every discovered plugin, exactly as before.
|
|
168
|
-
if (!managed && !consentGate) return all;
|
|
177
|
+
if (!managed && !consentGate && !declarationsGate) return all;
|
|
169
178
|
let list = all;
|
|
170
179
|
if (managed) {
|
|
171
180
|
const { kept, dropped } = filterByManagedPolicy(list, managed);
|
|
@@ -174,8 +183,10 @@ export function discoverPlugins(opts = {}) {
|
|
|
174
183
|
}
|
|
175
184
|
// Capability-consent enforcement funnels through the SAME chokepoint, so an
|
|
176
185
|
// un-consented plugin loads NONE of its six component types (opt-in).
|
|
177
|
-
if (consentGate) {
|
|
178
|
-
const { kept, dropped } = filterByCapabilityConsent(list
|
|
186
|
+
if (consentGate || declarationsGate) {
|
|
187
|
+
const { kept, dropped } = filterByCapabilityConsent(list, {
|
|
188
|
+
requireDeclarations: declarationsGate,
|
|
189
|
+
});
|
|
179
190
|
if (dropped.length > 0) warnDroppedOnce(dropped);
|
|
180
191
|
list = kept;
|
|
181
192
|
}
|
|
@@ -184,8 +195,8 @@ export function discoverPlugins(opts = {}) {
|
|
|
184
195
|
|
|
185
196
|
// ── internals ────────────────────────────────────────────────────────────
|
|
186
197
|
|
|
187
|
-
function activeVersionForDir(nameDir) {
|
|
188
|
-
if (!dirExists(nameDir)) return null;
|
|
198
|
+
function activeVersionForDir(nameDir, strictIo = false) {
|
|
199
|
+
if (!dirExists(nameDir, strictIo)) return null;
|
|
189
200
|
const versions = _deps
|
|
190
201
|
.readdirSync(nameDir, { withFileTypes: true })
|
|
191
202
|
.filter((e) => e.isDirectory())
|
|
@@ -198,28 +209,31 @@ function activeVersionForDir(nameDir) {
|
|
|
198
209
|
try {
|
|
199
210
|
const pinned = _deps.readFileSync(activeFile, "utf8").trim();
|
|
200
211
|
if (versions.includes(pinned)) return pinned;
|
|
201
|
-
} catch {
|
|
212
|
+
} catch (error) {
|
|
213
|
+
if (strictIo) throw error;
|
|
202
214
|
/* fall through */
|
|
203
215
|
}
|
|
204
216
|
}
|
|
205
217
|
return versions[0];
|
|
206
218
|
}
|
|
207
219
|
|
|
208
|
-
function dirExists(dir) {
|
|
220
|
+
function dirExists(dir, strictIo = false) {
|
|
209
221
|
try {
|
|
210
222
|
return _deps.existsSync(dir) && _deps.statSync(dir).isDirectory();
|
|
211
|
-
} catch {
|
|
223
|
+
} catch (error) {
|
|
224
|
+
if (strictIo) throw error;
|
|
212
225
|
return false;
|
|
213
226
|
}
|
|
214
227
|
}
|
|
215
228
|
|
|
216
|
-
function listDirs(dir) {
|
|
229
|
+
function listDirs(dir, strictIo = false) {
|
|
217
230
|
try {
|
|
218
231
|
return _deps
|
|
219
232
|
.readdirSync(dir, { withFileTypes: true })
|
|
220
233
|
.filter((e) => e.isDirectory())
|
|
221
234
|
.map((e) => e.name);
|
|
222
|
-
} catch {
|
|
235
|
+
} catch (error) {
|
|
236
|
+
if (strictIo) throw error;
|
|
223
237
|
return [];
|
|
224
238
|
}
|
|
225
239
|
}
|
|
@@ -21,16 +21,17 @@
|
|
|
21
21
|
* running untrusted SHELL/binaries behind the user's back.
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import fs from "fs";
|
|
25
24
|
import path from "path";
|
|
26
25
|
import { getElectronUserDataDir } from "../paths.js";
|
|
26
|
+
import { withFileLock } from "../with-file-lock.js";
|
|
27
|
+
import {
|
|
28
|
+
mutateSecurityStore,
|
|
29
|
+
readSecurityStore,
|
|
30
|
+
} from "../durable-security-store.js";
|
|
27
31
|
|
|
28
32
|
export const _deps = {
|
|
29
|
-
existsSync: fs.existsSync,
|
|
30
|
-
readFileSync: fs.readFileSync,
|
|
31
|
-
writeFileSync: fs.writeFileSync,
|
|
32
|
-
mkdirSync: fs.mkdirSync,
|
|
33
33
|
now: () => new Date().toISOString(),
|
|
34
|
+
withFileLock,
|
|
34
35
|
// Path of the trust store; injectable so unit tests never touch the real
|
|
35
36
|
// user-data dir.
|
|
36
37
|
storePath: () => path.join(getElectronUserDataDir(), "plugin-trust.json"),
|
|
@@ -39,20 +40,7 @@ export const _deps = {
|
|
|
39
40
|
const AUTO_TRUSTED_SCOPES = new Set(["user", "local"]);
|
|
40
41
|
|
|
41
42
|
export function loadTrustStore() {
|
|
42
|
-
|
|
43
|
-
const p = _deps.storePath();
|
|
44
|
-
if (!_deps.existsSync(p)) return {};
|
|
45
|
-
const data = JSON.parse(_deps.readFileSync(p, "utf8"));
|
|
46
|
-
return data && typeof data === "object" && !Array.isArray(data) ? data : {};
|
|
47
|
-
} catch {
|
|
48
|
-
return {};
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function saveTrustStore(store) {
|
|
53
|
-
const p = _deps.storePath();
|
|
54
|
-
_deps.mkdirSync(path.dirname(p), { recursive: true });
|
|
55
|
-
_deps.writeFileSync(p, JSON.stringify(store, null, 2), "utf8");
|
|
43
|
+
return readSecurityStore(_deps.storePath(), "plugin trust");
|
|
56
44
|
}
|
|
57
45
|
|
|
58
46
|
function trustKey(scope, name) {
|
|
@@ -66,27 +54,44 @@ function trustKey(scope, name) {
|
|
|
66
54
|
export function isPluginTrusted(plugin) {
|
|
67
55
|
if (!plugin || !plugin.name) return false;
|
|
68
56
|
if (AUTO_TRUSTED_SCOPES.has(plugin.scope)) return true;
|
|
69
|
-
|
|
70
|
-
|
|
57
|
+
try {
|
|
58
|
+
const entry = loadTrustStore()[trustKey(plugin.scope, plugin.name)];
|
|
59
|
+
return Boolean(entry && entry.version === plugin.version);
|
|
60
|
+
} catch {
|
|
61
|
+
// Project code must stay disabled when the trust store is unavailable.
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
71
64
|
}
|
|
72
65
|
|
|
73
66
|
/** Trust a plugin (records the exact version). */
|
|
74
67
|
export function trustPlugin(name, { scope = "project", version } = {}) {
|
|
75
68
|
if (!version) throw new Error("trustPlugin requires a version");
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
const file = _deps.storePath();
|
|
70
|
+
return mutateSecurityStore(
|
|
71
|
+
file,
|
|
72
|
+
"plugin trust",
|
|
73
|
+
(store) => {
|
|
74
|
+
store[trustKey(scope, name)] = { version, trustedAt: _deps.now() };
|
|
75
|
+
return { name, scope, version };
|
|
76
|
+
},
|
|
77
|
+
{ lock: _deps.withFileLock },
|
|
78
|
+
);
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
/** Revoke trust for a plugin at a scope. */
|
|
83
82
|
export function untrustPlugin(name, { scope = "project" } = {}) {
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
const file = _deps.storePath();
|
|
84
|
+
return mutateSecurityStore(
|
|
85
|
+
file,
|
|
86
|
+
"plugin trust",
|
|
87
|
+
(store) => {
|
|
88
|
+
const key = trustKey(scope, name);
|
|
89
|
+
const existed = Object.prototype.hasOwnProperty.call(store, key);
|
|
90
|
+
delete store[key];
|
|
91
|
+
return { name, scope, removed: existed };
|
|
92
|
+
},
|
|
93
|
+
{ lock: _deps.withFileLock },
|
|
94
|
+
);
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
/** All trust entries (for `cc plugin trust --list`). */
|