chainlesschain 0.162.181 → 0.162.183
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 +2 -1
- package/scripts/build-windows-sandbox-helper.ps1 +163 -0
- package/src/assets/web-panel/assets/{AIOps-cq0dwbnf.js → AIOps-BapS7lz4.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CvcgGl3w.js → ActionButton-CXYdXEUI.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-hM2-jFqg.js → Analytics-CKR5Lexn.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-B9_Gsd_g.js → AppLayout-DATVUOXB.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-B7bu52Og.js → Artifacts-vb_0ZlV1.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DThfDgqB.js → Audit-BI1l9GWt.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DjlFiD4v.js → BackgroundAgents-BFXbaUEf.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CK9xJKnG.js → Backup-DEYBJJ6H.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DEiSU8K8.js → BaseInput-COdzeO0M.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CpT96czj.js → Chat-oSN6sfM5.js} +6 -6
- package/src/assets/web-panel/assets/ChatBubbleRenderer-CI_jT0ru.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-C1GfDnO0.js → Checkbox-BezEa4tm.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-3DAKgiLx.js → Codegen-CNEL0Ife.js} +1 -1
- package/src/assets/web-panel/assets/{Col-74cOwZU1.js → Col-Bf2Y2Bn1.js} +1 -1
- package/src/assets/web-panel/assets/{Community-tn9Kkz9j.js → Community-BfUlu4Hc.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BcoXH7m4.js → Compact-BN4xWP9e.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DIPGUBgi.js → Compliance-Bt6BKmEP.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-doD5_91c.js → Cowork-DKLp8YxO.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-C-IDvubz.js → Cron-o7Hhw6ky.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CdcCoBdj.js → Crosschain-DaNXWJIw.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DdH5aMMA.js → DID-B-Qa2mha.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DHLA4mm0.js → Dashboard-CMX0Qnxw.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-dEeCt7Md.js → Dropdown-BLuLyRu_.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BMaecFv9.js → EmailListRenderer-CFBAeMij.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DUaUukTN.js → FamilyGuardDashboard-DWzXQ67V.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CMBE0_rp.js → Federation-DB1QSLgr.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-PG-JDbXq.js → FormItemContext-C-OKCToP.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-Bcb0p88m.js → GenericCardRenderer-DMJFtFZf.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Bgv15myB.js → Git-DsGSujOV.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DB8YTArI.js → Governance-B0iS9NEW.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BQMwCWaS.js → Inference-CH004H7c.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-B1_ZziiB.js → KnowledgeGraph-Q9MTQ83c.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DovEEnt_.js → Logs-B_fyjZK9.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-D201OL4T.js → MarkdownRenderer-C0o4FtpD.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BlCXSpyB.js → Marketplace-BIStF9d1.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CsCR09Wj.js → McpTools-pGfal768.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-CBVRLKno.js → Memory-xbNqpIqB.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-C9OIafgA.js → MobileBridge-B5EQGrIK.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-vE-HdvLj.js → Mtc-a_rmfxJH.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CPLaekCd.js → MtcAudit-BmKuofUr.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-C_UP9C2o.js → Multisig-BQbJ-CAN.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-2nODJcU1.js → NLProgramming-JtPJKX25.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BhE-SJGu.js → Notes-ZFKznTSG.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-D21q7BNU.js → NotificationSettings-B6aHRBBR.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-0b62GYOD.js → OrderTableRenderer-DdcsOqEz.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CEqmw_sb.js → Organization-BFDTAUgS.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-MW-gMDO_.js → Overflow-0FoTfbWH.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CY0hjI_G.js → P2P-CWd90etw.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BbWh7Man.js → PdhVaultBrowser-DtCGC-W-.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-ChqEA_4Q.js → Permissions-CvQ7nr7T.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-B3YrbYfD.js → PersonalDataHub-rdNPcR-Z.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-B8WBhhlW.js → Pipeline-CmrfiNOs.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Cmb0PXNx.js → Privacy-D7ep1h_t.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-hF6zW3Nz.js → ProjectInit-C0xKINHS.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BFSVfpW0.js → ProjectSettings-AOmZFp-F.js} +2 -2
- package/src/assets/web-panel/assets/Projects-BWHSkXZP.js +1 -0
- package/src/assets/web-panel/assets/{Providers-B8yux8Dx.js → Providers-Cb7JCTPL.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-N76cQluO.js → QrScannerModal-BDMehcXC.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-ClvZ0KYR.js → QuickAsk-BF6_1nvx.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-B-GfgBpT.js → Recommend-BHfT-A28.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-DJIZzQeG.js → Reputation-CsWHLEcj.js} +1 -1
- package/src/assets/web-panel/assets/{Row-COzxu_bb.js → Row-D6srnWhm.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CoYsJQuE.js → RssFeed-Xhr-KyVd.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DC77Mq9S.js → Search-vIbIJvwL.js} +1 -1
- package/src/assets/web-panel/assets/{Security-Loy2EdMO.js → Security-Bzi5Aiko.js} +4 -4
- package/src/assets/web-panel/assets/{Services-GUD07Eu0.js → Services-BHtVX52P.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DWzkptYU.js → Skeleton-C0R8B2jf.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CEDn1r-Z.js → Skills-DtT6rWOX.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-ub_k4pXh.js → Sla-0B37mxVU.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-D7HLX9CA.js → SpeechSettings-0V2jE1Bs.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DbwOvl6m.js → SyncSettings-CYedRzaj.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-D-R1x8vm.js +1 -0
- package/src/assets/web-panel/assets/{Templates-BNVeIhud.js → Templates-BKoHztGT.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-PS9AzhXU.js → Tenant--17nwVNZ.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-Cgb4eLB_.js → Terminal-Dnkos7vW.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CrmXMOkg.js → TimelineRenderer-C5jx4AE3.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DD-VDHw1.js → Tokens-DYJKYa9t.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BsoN_n-n.js → Trigger-DChpWiQ9.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-n8LmN4ZV.js → Trust-DfWG52EA.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C9_7MImA.js → UkeySign-CMugYcyA.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DyBteNgn.js → VideoEditing-BOSmrHAd.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BS5ixeXI.js → Wallet-D5g3k3Sa.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-spc4UImU.js → WebAuthn-D-7u4Mkc.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-D7iVvaBO.js → WorkflowEditor-CFzZMSUJ.js} +1 -1
- package/src/assets/web-panel/assets/{chat-6CmBkHrL.js → chat-VbR6l6mc.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BGoCLkxI.js → colors-BSZn8EDS.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-fYZBetMO.js → compact-item-y74obMEq.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BeM-1UVj.js → createContext-C326bjex.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-D3Bho_6u.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CE7ZuEnV.js → hasIn-D_INJQT_.js} +1 -1
- package/src/assets/web-panel/assets/{index-ukg99D1V.js → index-4PIeTM--.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2U-ObMq.js → index-4eyH-eC2.js} +1 -1
- package/src/assets/web-panel/assets/index-5iAFwYx1.js +1 -0
- package/src/assets/web-panel/assets/{index-CRLjEP1H.js → index-9PIVuXqo.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfPL-m46.js → index-B7SrC-On.js} +1 -1
- package/src/assets/web-panel/assets/{index--lap6cf7.js → index-BJi3UqBt.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3CDgvNW.js → index-BY8-nCgs.js} +1 -1
- package/src/assets/web-panel/assets/index-BfnB7LPx.js +1 -0
- package/src/assets/web-panel/assets/{index-De0quFDw.js → index-Bfw2hf2s.js} +1 -1
- package/src/assets/web-panel/assets/{index-BunaQCa0.js → index-BjcWKg1S.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsMfoaeo.js → index-BnSfnSMP.js} +1 -1
- package/src/assets/web-panel/assets/{index-C0v6YKKO.js → index-Bnua8IX3.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4SJVjs4.js → index-C-ZCaUJc.js} +1 -1
- package/src/assets/web-panel/assets/{index-BNZDILcO.js → index-C2NyllnW.js} +1 -1
- package/src/assets/web-panel/assets/{index-YjcumOZ4.js → index-C327pLbw.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRnUE8Cb.js → index-CMHqs3Jb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CIpVrf5P.js → index-CfLJ42kv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BEVm0lCS.js → index-Cr3uuz0C.js} +3 -3
- package/src/assets/web-panel/assets/{index-Dw1PyYPm.js → index-CsovTpx9.js} +1 -1
- package/src/assets/web-panel/assets/{index-lJBjB1QX.js → index-CzE53HiB.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpIGIB85.js → index-DBkzrpiL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DoXk5KJ8.js → index-DNMxIsDg.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsvfrESp.js → index-DUU2606o.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cip8emOQ.js → index-DdyjrCAu.js} +1 -1
- package/src/assets/web-panel/assets/{index-ATcSr_2O.js → index-DkH1JvEt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BV551878.js → index-Dlxh9D8D.js} +1 -1
- package/src/assets/web-panel/assets/{index-BU_2qiDk.js → index-DuIkfnTF.js} +1 -1
- package/src/assets/web-panel/assets/{index-zb7rVOhV.js → index-DwHSZLXg.js} +1 -1
- package/src/assets/web-panel/assets/{index-MtOuq2i6.js → index-E_v1ZCTP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8BsdNV_.js → index-FQBsuExX.js} +1 -1
- package/src/assets/web-panel/assets/{index-WUrJ6S1j.js → index-GA80ir_u.js} +1 -1
- package/src/assets/web-panel/assets/{index-RMZ8a7Yt.js → index-IZAWt0H8.js} +1 -1
- package/src/assets/web-panel/assets/{index-D1r9tT3J.js → index-Iw0FfqUz.js} +1 -1
- package/src/assets/web-panel/assets/{index-BowH1eLQ.js → index-KF9Zmqln.js} +1 -1
- package/src/assets/web-panel/assets/{index-Puq6Luf1.js → index-abmn_8Yz.js} +1 -1
- package/src/assets/web-panel/assets/{index-QIpnpZgz.js → index-gINyI1rh.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9Y3k0HI.js → index-jYaogFE8.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4wiTEOM.js → index-nSn2-C4N.js} +1 -1
- package/src/assets/web-panel/assets/{index-DT3zPSVX.js → index-qMA4GYdQ.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CYHMs1ag.js → initDefaultProps-DI0Zaf8-.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DDB2Ffk5.js → motion-BZDKSy3Z.js} +1 -1
- package/src/assets/web-panel/assets/{move-Bg3cD-dX.js → move-DsIW01Vp.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-B5nedjTS.js → mtc-parser-CohkDhsf.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BHyuUILu.js → omit-DpiN5rzg.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-C9YQnEN9.js → pickAttrs-qbuqni3y.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DBUFYUe7.js → placementArrow-mBky6714.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-nBs2Obnk.js → responsiveObserve-Bas3eQ2K.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DkCEaXNU.js → slide-CBx_SKoK.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-aqE1Wi6U.js → statusUtils-BlYguJSV.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CN5bhfHB.js → styleChecker-BCYQmRGv.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-B_oX_kvJ.js → useFlexGapSupport-Dp5dybLM.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-rCuXHeme.js → useFs-DHAMBgA2.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DZR9Abyd.js → usePersonalDataHub-W6jsSw76.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-ConCYQlX.js → vnode-BkI6aayc.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CUdDxG5M.js → zoom-C_IMGueq.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agenda.js +115 -3
- package/src/commands/agent.js +15 -0
- package/src/commands/background-session.js +49 -0
- package/src/commands/plugin.js +235 -23
- package/src/commands/session.js +13 -0
- package/src/data/changelog.json +26 -0
- package/src/gateways/terminal/PtyManager.js +45 -4
- package/src/gateways/ws/ws-server.js +10 -1
- package/src/harness/background-task-manager.js +70 -2
- package/src/harness/jsonl-session-store.js +6 -4
- package/src/harness/worktree-isolator.js +14 -3
- package/src/lib/agent-core.js +1 -0
- package/src/lib/agent-schedule-store.js +45 -22
- package/src/lib/agent-team/team-runner.js +19 -1
- package/src/lib/background-agent-supervisor.js +49 -0
- package/src/lib/hook-runner.js +6 -2
- package/src/lib/packer/pkg-config-generator.js +3 -1
- package/src/lib/plugin-runtime/bin.js +1148 -70
- package/src/lib/plugin-runtime/install.js +226 -7
- package/src/lib/plugin-runtime/manifest.js +68 -12
- package/src/lib/plugin-runtime/scopes.js +33 -12
- package/src/lib/plugin-usage-attribution.js +44 -0
- package/src/lib/process-execution-broker/index.js +626 -48
- package/src/lib/process-execution-broker/platform-sandbox.js +4971 -266
- 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/repl-bang-memorize.js +67 -10
- package/src/lib/session-usage.js +77 -0
- package/src/lib/slash-commands.js +27 -4
- package/src/repl/agent-repl.js +10 -9
- package/src/runtime/agent-core.js +376 -52
- package/src/runtime/agent-runtime.js +13 -1
- package/src/runtime/headless-runner.js +13 -4
- package/src/runtime/headless-stream.js +20 -1
- package/src/runtime/mcp-config.js +15 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BKPPNmZI.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-D_zoJ8Xs.js +0 -1
- package/src/assets/web-panel/assets/Projects-DAWkVFkc.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-mlglCdQi.js +0 -5
- package/src/assets/web-panel/assets/Tasks-CBQzoAu5.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +0 -1
- package/src/assets/web-panel/assets/index-DacrAdc-.js +0 -1
- package/src/assets/web-panel/assets/index-EHzNJozo.js +0 -1
- package/src/lib/process-execution-broker/windows-sandbox.ps1 +0 -999
|
@@ -26,22 +26,32 @@ import {
|
|
|
26
26
|
listInstalledVersions,
|
|
27
27
|
activeVersion,
|
|
28
28
|
discoverPlugins,
|
|
29
|
+
DISABLED_FILENAME,
|
|
29
30
|
} from "./scopes.js";
|
|
30
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
enforcePluginPolicy,
|
|
33
|
+
verifyPluginManifest,
|
|
34
|
+
} from "../plugin-security.js";
|
|
31
35
|
import {
|
|
32
36
|
writePluginLock,
|
|
33
37
|
buildPluginSbom,
|
|
34
38
|
LOCK_FILENAME,
|
|
39
|
+
readPluginLock,
|
|
40
|
+
verifyInstalledSignature,
|
|
35
41
|
} from "./signature.js";
|
|
42
|
+
import { loadManagedPluginPolicy, filterByManagedPolicy } from "./policy.js";
|
|
43
|
+
import { managedSettingsPath } from "../settings-loader.cjs";
|
|
36
44
|
import executionBroker from "../process-execution-broker/index.js";
|
|
37
45
|
|
|
38
46
|
export const MAX_LISTED_PLUGIN_VERSIONS = 64;
|
|
47
|
+
export const SOURCE_METADATA_FILENAME = ".plugin-source.json";
|
|
39
48
|
|
|
40
49
|
export const _deps = {
|
|
41
50
|
existsSync: fs.existsSync,
|
|
42
51
|
mkdirSync: fs.mkdirSync,
|
|
43
52
|
rmSync: fs.rmSync,
|
|
44
53
|
readdirSync: fs.readdirSync,
|
|
54
|
+
readFileSync: fs.readFileSync,
|
|
45
55
|
copyFileSync: fs.copyFileSync,
|
|
46
56
|
lstatSync: fs.lstatSync,
|
|
47
57
|
writeFileSync: fs.writeFileSync,
|
|
@@ -69,6 +79,17 @@ export function installFromDirectory(srcDir, opts = {}) {
|
|
|
69
79
|
);
|
|
70
80
|
}
|
|
71
81
|
const { name, version } = manifest.metadata;
|
|
82
|
+
const sourceMetadata = normalizeSourceMetadata(opts.sourceMetadata);
|
|
83
|
+
if (opts.managedPolicy) {
|
|
84
|
+
enforcePluginPolicy(
|
|
85
|
+
{
|
|
86
|
+
name,
|
|
87
|
+
source: opts.policySource || sourceMetadata?.source || null,
|
|
88
|
+
action: "install",
|
|
89
|
+
},
|
|
90
|
+
opts.managedPolicy,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
72
93
|
|
|
73
94
|
// Optional signature/integrity verification of the manifest at install time
|
|
74
95
|
// (Phase 3.3l). verifyPluginManifest THROWS on any mismatch/failure — a signed
|
|
@@ -108,6 +129,15 @@ export function installFromDirectory(srcDir, opts = {}) {
|
|
|
108
129
|
// unsigned install that forged lock would otherwise survive into the
|
|
109
130
|
// "immutable" version dir and defeat load-time requireSignedPlugins.
|
|
110
131
|
_deps.rmSync(path.join(dest, LOCK_FILENAME), { force: true });
|
|
132
|
+
_deps.rmSync(path.join(dest, SOURCE_METADATA_FILENAME), { force: true });
|
|
133
|
+
|
|
134
|
+
if (sourceMetadata) {
|
|
135
|
+
_deps.writeFileSync(
|
|
136
|
+
path.join(dest, SOURCE_METADATA_FILENAME),
|
|
137
|
+
JSON.stringify(sourceMetadata, null, 2),
|
|
138
|
+
"utf8",
|
|
139
|
+
);
|
|
140
|
+
}
|
|
111
141
|
|
|
112
142
|
// Record the verified signature into the installed (immutable) version dir so
|
|
113
143
|
// load-time enforcement can re-check it. The manifest was copied verbatim, so
|
|
@@ -138,6 +168,8 @@ export function installFromDirectory(srcDir, opts = {}) {
|
|
|
138
168
|
dir: dest,
|
|
139
169
|
warnings: manifest.warnings,
|
|
140
170
|
signatureVerified: verification?.signatureVerified === true,
|
|
171
|
+
sourceMetadata,
|
|
172
|
+
enabled: isPluginEnabled(name, { scope, cwd: opts.cwd }),
|
|
141
173
|
};
|
|
142
174
|
}
|
|
143
175
|
|
|
@@ -150,8 +182,21 @@ export function installFromDirectory(srcDir, opts = {}) {
|
|
|
150
182
|
*/
|
|
151
183
|
export function installFromSource(source, opts = {}) {
|
|
152
184
|
return _withMaterializedSource(source, (dir, info) => {
|
|
153
|
-
const
|
|
154
|
-
|
|
185
|
+
const sourceMetadata =
|
|
186
|
+
normalizeSourceMetadata(opts.sourceMetadata) ||
|
|
187
|
+
normalizeSourceMetadata(
|
|
188
|
+
info
|
|
189
|
+
? { type: "git", source: info.url, ref: info.ref || null }
|
|
190
|
+
: { type: "local", source: path.resolve(String(source || "")) },
|
|
191
|
+
);
|
|
192
|
+
const res = installFromDirectory(dir, { ...opts, sourceMetadata });
|
|
193
|
+
return info
|
|
194
|
+
? {
|
|
195
|
+
...res,
|
|
196
|
+
source: sourceMetadata?.source || null,
|
|
197
|
+
ref: sourceMetadata?.ref || null,
|
|
198
|
+
}
|
|
199
|
+
: res;
|
|
155
200
|
});
|
|
156
201
|
}
|
|
157
202
|
|
|
@@ -202,6 +247,13 @@ export function updatePlugin(source, opts = {}) {
|
|
|
202
247
|
);
|
|
203
248
|
}
|
|
204
249
|
const { name, version } = manifest.metadata;
|
|
250
|
+
const sourceMetadata =
|
|
251
|
+
normalizeSourceMetadata(opts.sourceMetadata) ||
|
|
252
|
+
normalizeSourceMetadata(
|
|
253
|
+
info
|
|
254
|
+
? { type: "git", source: info.url, ref: info.ref || null }
|
|
255
|
+
: { type: "local", source: path.resolve(String(source || "")) },
|
|
256
|
+
);
|
|
205
257
|
const previousVersion = getActiveVersion(name, { scope, cwd: opts.cwd });
|
|
206
258
|
const dest = pluginVersionDir(scope, name, version, { cwd: opts.cwd });
|
|
207
259
|
const sameVersionExists = _deps.existsSync(dest);
|
|
@@ -218,18 +270,24 @@ export function updatePlugin(source, opts = {}) {
|
|
|
218
270
|
previousVersion,
|
|
219
271
|
updated: previousVersion !== version,
|
|
220
272
|
reinstalled: false,
|
|
221
|
-
source:
|
|
273
|
+
source: sourceMetadata?.source || null,
|
|
274
|
+
ref: sourceMetadata?.ref || null,
|
|
222
275
|
};
|
|
223
276
|
}
|
|
224
277
|
|
|
225
|
-
const res = installFromDirectory(dir, {
|
|
278
|
+
const res = installFromDirectory(dir, {
|
|
279
|
+
...opts,
|
|
280
|
+
scope,
|
|
281
|
+
force: true,
|
|
282
|
+
sourceMetadata,
|
|
283
|
+
});
|
|
226
284
|
return {
|
|
227
285
|
...res,
|
|
228
286
|
previousVersion,
|
|
229
287
|
updated: previousVersion !== version,
|
|
230
288
|
reinstalled: sameVersionExists,
|
|
231
|
-
source:
|
|
232
|
-
ref:
|
|
289
|
+
source: sourceMetadata?.source || null,
|
|
290
|
+
ref: sourceMetadata?.ref || null,
|
|
233
291
|
};
|
|
234
292
|
});
|
|
235
293
|
}
|
|
@@ -319,10 +377,26 @@ export function fetchGitRepo(url, ref) {
|
|
|
319
377
|
* invisible and impossible to inspect / uninstall / un-deny.
|
|
320
378
|
*/
|
|
321
379
|
export function listInstalled(opts = {}) {
|
|
380
|
+
let managed = null;
|
|
381
|
+
let managedError = null;
|
|
382
|
+
try {
|
|
383
|
+
managed = loadManagedPluginPolicy({
|
|
384
|
+
env: opts.env,
|
|
385
|
+
managedSettingsFile: opts.managedSettingsFile,
|
|
386
|
+
});
|
|
387
|
+
} catch (error) {
|
|
388
|
+
managedError = error;
|
|
389
|
+
}
|
|
390
|
+
const policySource = managedSettingsPath({
|
|
391
|
+
env: opts.env,
|
|
392
|
+
managedSettingsFile: opts.managedSettingsFile,
|
|
393
|
+
});
|
|
394
|
+
|
|
322
395
|
return discoverPlugins({
|
|
323
396
|
cwd: opts.cwd,
|
|
324
397
|
scopes: opts.scopes,
|
|
325
398
|
skipPolicy: true,
|
|
399
|
+
includeDisabled: true,
|
|
326
400
|
}).map((p) => {
|
|
327
401
|
const allVersions = listInstalledVersions(p.scope, p.name, {
|
|
328
402
|
cwd: opts.cwd,
|
|
@@ -335,6 +409,16 @@ export function listInstalled(opts = {}) {
|
|
|
335
409
|
) {
|
|
336
410
|
versions[versions.length - 1] = p.version;
|
|
337
411
|
}
|
|
412
|
+
const lock = readPluginLock(p.root);
|
|
413
|
+
const signature = verifyInstalledSignature(p);
|
|
414
|
+
const policyResult =
|
|
415
|
+
managed && !managedError
|
|
416
|
+
? filterByManagedPolicy([p], managed)
|
|
417
|
+
: { kept: [p], dropped: [] };
|
|
418
|
+
const policyDrop = policyResult.dropped[0] || null;
|
|
419
|
+
const sbomFiles = Array.isArray(lock?.sbom?.files)
|
|
420
|
+
? lock.sbom.files.slice(0, 100000)
|
|
421
|
+
: [];
|
|
338
422
|
return {
|
|
339
423
|
name: p.name,
|
|
340
424
|
version: p.version,
|
|
@@ -342,6 +426,45 @@ export function listInstalled(opts = {}) {
|
|
|
342
426
|
scope: p.scope,
|
|
343
427
|
dir: p.root,
|
|
344
428
|
ok: p.manifest?.ok === true,
|
|
429
|
+
enabled: p.enabled !== false,
|
|
430
|
+
source: readSourceMetadata(p.root),
|
|
431
|
+
integrity: {
|
|
432
|
+
signature: {
|
|
433
|
+
present: Boolean(lock?.signatureBase64 && lock?.publicKeyPem),
|
|
434
|
+
verified: signature.signed === true,
|
|
435
|
+
reason: signature.signed ? null : signature.reason || "unsigned",
|
|
436
|
+
manifestSha256: lock?.sha256 || null,
|
|
437
|
+
publicKeySha256:
|
|
438
|
+
signature.publicKeySha256 || lock?.publicKeySha256 || null,
|
|
439
|
+
},
|
|
440
|
+
sbom: {
|
|
441
|
+
present: Boolean(lock?.sbom),
|
|
442
|
+
digest: lock?.sbom?.digest || null,
|
|
443
|
+
fileCount: sbomFiles.length,
|
|
444
|
+
totalBytes: Math.min(
|
|
445
|
+
Number.MAX_SAFE_INTEGER,
|
|
446
|
+
sbomFiles.reduce(
|
|
447
|
+
(sum, file) =>
|
|
448
|
+
sum +
|
|
449
|
+
(Number.isFinite(Number(file?.bytes)) && Number(file.bytes) > 0
|
|
450
|
+
? Number(file.bytes)
|
|
451
|
+
: 0),
|
|
452
|
+
0,
|
|
453
|
+
),
|
|
454
|
+
),
|
|
455
|
+
},
|
|
456
|
+
},
|
|
457
|
+
policy: {
|
|
458
|
+
managed: Boolean(managed) || Boolean(managedError),
|
|
459
|
+
source: policySource,
|
|
460
|
+
allowed: !managedError && !policyDrop,
|
|
461
|
+
reason: managedError
|
|
462
|
+
? managedError.message
|
|
463
|
+
: policyDrop?.reason || (managed ? "allowed by managed policy" : ""),
|
|
464
|
+
requireSigned:
|
|
465
|
+
managed?.requireSignedPlugins === true ||
|
|
466
|
+
managed?.requireSignedPlugins === "require",
|
|
467
|
+
},
|
|
345
468
|
};
|
|
346
469
|
});
|
|
347
470
|
}
|
|
@@ -412,11 +535,107 @@ export function setActiveVersion(name, version, opts = {}) {
|
|
|
412
535
|
return { name, version, scope, active: version };
|
|
413
536
|
}
|
|
414
537
|
|
|
538
|
+
/** Enable or disable one scoped plugin without deleting immutable versions. */
|
|
539
|
+
export function setPluginEnabled(name, enabled, opts = {}) {
|
|
540
|
+
const scope = opts.scope || "user";
|
|
541
|
+
const cwd = opts.cwd;
|
|
542
|
+
const nameDir = pluginNameDir(scope, name, { cwd });
|
|
543
|
+
if (
|
|
544
|
+
!_deps.existsSync(nameDir) ||
|
|
545
|
+
listInstalledVersions(scope, name, { cwd }).length === 0
|
|
546
|
+
) {
|
|
547
|
+
throw new Error(`${name} is not installed at ${scope} scope`);
|
|
548
|
+
}
|
|
549
|
+
const marker = path.join(nameDir, DISABLED_FILENAME);
|
|
550
|
+
if (enabled) {
|
|
551
|
+
_deps.rmSync(marker, { force: true });
|
|
552
|
+
} else {
|
|
553
|
+
_deps.writeFileSync(
|
|
554
|
+
marker,
|
|
555
|
+
JSON.stringify(
|
|
556
|
+
{
|
|
557
|
+
disabled: true,
|
|
558
|
+
reason: String(opts.reason || "disabled by user").slice(0, 256),
|
|
559
|
+
},
|
|
560
|
+
null,
|
|
561
|
+
2,
|
|
562
|
+
),
|
|
563
|
+
"utf8",
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
return { name, scope, enabled: Boolean(enabled) };
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/** Current lifecycle state for one scoped plugin. */
|
|
570
|
+
export function isPluginEnabled(name, opts = {}) {
|
|
571
|
+
const scope = opts.scope || "user";
|
|
572
|
+
return !_deps.existsSync(
|
|
573
|
+
path.join(pluginNameDir(scope, name, { cwd: opts.cwd }), DISABLED_FILENAME),
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
|
|
415
577
|
/** Which version is active for a plugin at a scope (or null). */
|
|
416
578
|
export function getActiveVersion(name, opts = {}) {
|
|
417
579
|
return activeVersion(opts.scope || "user", name, { cwd: opts.cwd });
|
|
418
580
|
}
|
|
419
581
|
|
|
582
|
+
function readSourceMetadata(versionDir) {
|
|
583
|
+
const file = path.join(versionDir, SOURCE_METADATA_FILENAME);
|
|
584
|
+
if (!_deps.existsSync(file)) return null;
|
|
585
|
+
try {
|
|
586
|
+
return normalizeSourceMetadata(
|
|
587
|
+
JSON.parse(_deps.readFileSync(file, "utf8")),
|
|
588
|
+
);
|
|
589
|
+
} catch {
|
|
590
|
+
return null;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function normalizeSourceMetadata(value) {
|
|
595
|
+
if (!value || typeof value !== "object") return null;
|
|
596
|
+
const type = ["local", "git", "registry"].includes(value.type)
|
|
597
|
+
? value.type
|
|
598
|
+
: "git";
|
|
599
|
+
const source = sanitizeSource(value.source, type === "local");
|
|
600
|
+
if (!source) return null;
|
|
601
|
+
const metadata = {
|
|
602
|
+
version: 1,
|
|
603
|
+
type,
|
|
604
|
+
source,
|
|
605
|
+
ref: cleanBounded(value.ref, 256),
|
|
606
|
+
};
|
|
607
|
+
const registry = sanitizeSource(value.registry);
|
|
608
|
+
const resolvedSource = sanitizeSource(value.resolvedSource);
|
|
609
|
+
const packageName = cleanBounded(value.package, 256);
|
|
610
|
+
if (registry) metadata.registry = registry;
|
|
611
|
+
if (resolvedSource) metadata.resolvedSource = resolvedSource;
|
|
612
|
+
if (packageName) metadata.package = packageName;
|
|
613
|
+
if (value.offline === true) metadata.offline = true;
|
|
614
|
+
return metadata;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function sanitizeSource(value, preservePath = false) {
|
|
618
|
+
const raw = cleanBounded(value, 4096);
|
|
619
|
+
if (!raw) return null;
|
|
620
|
+
if (preservePath) return raw;
|
|
621
|
+
try {
|
|
622
|
+
const parsed = new URL(raw);
|
|
623
|
+
parsed.username = "";
|
|
624
|
+
parsed.password = "";
|
|
625
|
+
parsed.search = "";
|
|
626
|
+
parsed.hash = "";
|
|
627
|
+
return parsed.toString();
|
|
628
|
+
} catch {
|
|
629
|
+
return raw;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function cleanBounded(value, max) {
|
|
634
|
+
if (typeof value !== "string") return null;
|
|
635
|
+
const clean = value.replace(/\p{Cc}/gu, "").trim();
|
|
636
|
+
return clean ? clean.slice(0, max) : null;
|
|
637
|
+
}
|
|
638
|
+
|
|
420
639
|
// ── guarded recursive copy ────────────────────────────────────────────────
|
|
421
640
|
|
|
422
641
|
/**
|
|
@@ -199,14 +199,15 @@ export function parsePluginManifest(root) {
|
|
|
199
199
|
warnings,
|
|
200
200
|
manifestSandboxPolicy,
|
|
201
201
|
);
|
|
202
|
-
c.bin = resolveBin(
|
|
202
|
+
c.bin = resolveBin(
|
|
203
|
+
abs,
|
|
204
|
+
manifest,
|
|
205
|
+
safeResolve,
|
|
206
|
+
errors,
|
|
207
|
+
warnings,
|
|
208
|
+
manifestSandboxPolicy,
|
|
209
|
+
);
|
|
203
210
|
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
|
-
}
|
|
210
211
|
|
|
211
212
|
// ── declared capabilities + options schema (P1) ──
|
|
212
213
|
const hasPermissions =
|
|
@@ -451,10 +452,17 @@ function resolveLsp(
|
|
|
451
452
|
return out;
|
|
452
453
|
}
|
|
453
454
|
|
|
454
|
-
function resolveBin(
|
|
455
|
+
function resolveBin(
|
|
456
|
+
root,
|
|
457
|
+
manifest,
|
|
458
|
+
safeResolve,
|
|
459
|
+
errors,
|
|
460
|
+
warnings,
|
|
461
|
+
manifestSandboxPolicy,
|
|
462
|
+
) {
|
|
455
463
|
const out = [];
|
|
456
464
|
const seen = new Set();
|
|
457
|
-
const push = (name, rel) => {
|
|
465
|
+
const push = (name, rel, descriptorPolicy = null) => {
|
|
458
466
|
const absPath = safeResolve(rel, `bin["${name}"]`);
|
|
459
467
|
if (!absPath) return;
|
|
460
468
|
if (!_deps.existsSync(absPath)) {
|
|
@@ -462,8 +470,29 @@ function resolveBin(root, manifest, safeResolve, warnings) {
|
|
|
462
470
|
return;
|
|
463
471
|
}
|
|
464
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
|
+
}
|
|
465
489
|
seen.add(name);
|
|
466
|
-
out.push({
|
|
490
|
+
out.push({
|
|
491
|
+
name,
|
|
492
|
+
path: rel,
|
|
493
|
+
absPath,
|
|
494
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
495
|
+
});
|
|
467
496
|
};
|
|
468
497
|
|
|
469
498
|
if (
|
|
@@ -471,8 +500,35 @@ function resolveBin(root, manifest, safeResolve, warnings) {
|
|
|
471
500
|
typeof manifest.bin === "object" &&
|
|
472
501
|
!Array.isArray(manifest.bin)
|
|
473
502
|
) {
|
|
474
|
-
for (const [name,
|
|
475
|
-
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
|
+
);
|
|
476
532
|
}
|
|
477
533
|
return out;
|
|
478
534
|
}
|
|
@@ -42,6 +42,7 @@ export const _deps = {
|
|
|
42
42
|
|
|
43
43
|
// Lowest → highest precedence.
|
|
44
44
|
export const SCOPES = ["user", "project", "local"];
|
|
45
|
+
export const DISABLED_FILENAME = ".disabled";
|
|
45
46
|
|
|
46
47
|
/** Filesystem-safe encoding of a (possibly scoped, e.g. @org/name) plugin name. */
|
|
47
48
|
export function encodeName(name) {
|
|
@@ -105,6 +106,13 @@ export function activeVersion(scope, name, opts = {}) {
|
|
|
105
106
|
return versions[0];
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
/** Whether one scoped plugin install is eligible for runtime discovery. */
|
|
110
|
+
export function isPluginEnabled(scope, name, opts = {}) {
|
|
111
|
+
return !_deps.existsSync(
|
|
112
|
+
path.join(pluginNameDir(scope, name, opts), DISABLED_FILENAME),
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
108
116
|
/**
|
|
109
117
|
* Discover every installed plugin's ACTIVE version across all scopes, applying
|
|
110
118
|
* scope precedence (local > project > user) so a name installed at multiple
|
|
@@ -116,8 +124,8 @@ export function activeVersion(scope, name, opts = {}) {
|
|
|
116
124
|
* for tooling that must see even blocked plugins (e.g. `cc plugin installed`
|
|
117
125
|
* showing why something is blocked). No managed settings file → no filtering.
|
|
118
126
|
*
|
|
119
|
-
* @param {object} [opts] { cwd, scopes?, skipPolicy?, env?, managedSettingsFile? }
|
|
120
|
-
* @returns {Array<{scope, name, version, root, manifest}>}
|
|
127
|
+
* @param {object} [opts] { cwd, scopes?, skipPolicy?, includeDisabled?, env?, managedSettingsFile? }
|
|
128
|
+
* @returns {Array<{scope, name, version, root, manifest, enabled}>}
|
|
121
129
|
*/
|
|
122
130
|
export function discoverPlugins(opts = {}) {
|
|
123
131
|
// `cc agent --bare` (CC_PLUGINS=0): the plugin runtime is fully off. Every
|
|
@@ -136,13 +144,22 @@ export function discoverPlugins(opts = {}) {
|
|
|
136
144
|
const byName = new Map(); // name → record (later scope overrides earlier)
|
|
137
145
|
for (const scope of scopes) {
|
|
138
146
|
const root = scopeRoot(scope, opts);
|
|
139
|
-
if (!dirExists(root)) continue;
|
|
140
|
-
for (const encoded of listDirs(root)) {
|
|
147
|
+
if (!dirExists(root, opts.strictIo === true)) continue;
|
|
148
|
+
for (const encoded of listDirs(root, opts.strictIo === true)) {
|
|
141
149
|
const nameDir = path.join(root, encoded);
|
|
142
|
-
const
|
|
150
|
+
const enabled = !_deps.existsSync(path.join(nameDir, DISABLED_FILENAME));
|
|
151
|
+
if (!enabled && opts.includeDisabled !== true) continue;
|
|
152
|
+
const version = activeVersionForDir(nameDir, opts.strictIo === true);
|
|
143
153
|
if (!version) continue;
|
|
144
154
|
const versionDir = path.join(nameDir, version);
|
|
145
155
|
const manifest = parsePluginManifest(versionDir);
|
|
156
|
+
if (opts.strictIo === true && manifest.ok !== true) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
`plugin manifest is not safely loadable at ${versionDir}: ${
|
|
159
|
+
manifest.errors?.join("; ") || "unknown manifest error"
|
|
160
|
+
}`,
|
|
161
|
+
);
|
|
162
|
+
}
|
|
146
163
|
manifest.scope = scope;
|
|
147
164
|
const name = manifest.metadata?.name || encoded;
|
|
148
165
|
byName.set(name, {
|
|
@@ -151,6 +168,7 @@ export function discoverPlugins(opts = {}) {
|
|
|
151
168
|
version: manifest.metadata?.version || version,
|
|
152
169
|
root: versionDir,
|
|
153
170
|
manifest,
|
|
171
|
+
enabled,
|
|
154
172
|
});
|
|
155
173
|
}
|
|
156
174
|
}
|
|
@@ -188,8 +206,8 @@ export function discoverPlugins(opts = {}) {
|
|
|
188
206
|
|
|
189
207
|
// ── internals ────────────────────────────────────────────────────────────
|
|
190
208
|
|
|
191
|
-
function activeVersionForDir(nameDir) {
|
|
192
|
-
if (!dirExists(nameDir)) return null;
|
|
209
|
+
function activeVersionForDir(nameDir, strictIo = false) {
|
|
210
|
+
if (!dirExists(nameDir, strictIo)) return null;
|
|
193
211
|
const versions = _deps
|
|
194
212
|
.readdirSync(nameDir, { withFileTypes: true })
|
|
195
213
|
.filter((e) => e.isDirectory())
|
|
@@ -202,28 +220,31 @@ function activeVersionForDir(nameDir) {
|
|
|
202
220
|
try {
|
|
203
221
|
const pinned = _deps.readFileSync(activeFile, "utf8").trim();
|
|
204
222
|
if (versions.includes(pinned)) return pinned;
|
|
205
|
-
} catch {
|
|
223
|
+
} catch (error) {
|
|
224
|
+
if (strictIo) throw error;
|
|
206
225
|
/* fall through */
|
|
207
226
|
}
|
|
208
227
|
}
|
|
209
228
|
return versions[0];
|
|
210
229
|
}
|
|
211
230
|
|
|
212
|
-
function dirExists(dir) {
|
|
231
|
+
function dirExists(dir, strictIo = false) {
|
|
213
232
|
try {
|
|
214
233
|
return _deps.existsSync(dir) && _deps.statSync(dir).isDirectory();
|
|
215
|
-
} catch {
|
|
234
|
+
} catch (error) {
|
|
235
|
+
if (strictIo) throw error;
|
|
216
236
|
return false;
|
|
217
237
|
}
|
|
218
238
|
}
|
|
219
239
|
|
|
220
|
-
function listDirs(dir) {
|
|
240
|
+
function listDirs(dir, strictIo = false) {
|
|
221
241
|
try {
|
|
222
242
|
return _deps
|
|
223
243
|
.readdirSync(dir, { withFileTypes: true })
|
|
224
244
|
.filter((e) => e.isDirectory())
|
|
225
245
|
.map((e) => e.name);
|
|
226
|
-
} catch {
|
|
246
|
+
} catch (error) {
|
|
247
|
+
if (strictIo) throw error;
|
|
227
248
|
return [];
|
|
228
249
|
}
|
|
229
250
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract a secret-free plugin identity from a tool result. Plugin bins expose
|
|
3
|
+
* an explicit `plugin_bin` record; extension-tier tools may expose a
|
|
4
|
+
* `toolAttribution.source` in the stable `plugin:<id>` / `plugin/<id>` form.
|
|
5
|
+
*/
|
|
6
|
+
export function extractPluginUsageAttribution(result) {
|
|
7
|
+
const pluginBin =
|
|
8
|
+
result?.plugin_bin && typeof result.plugin_bin === "object"
|
|
9
|
+
? result.plugin_bin
|
|
10
|
+
: null;
|
|
11
|
+
if (pluginBin?.plugin) {
|
|
12
|
+
const plugin = boundedIdentity(pluginBin.plugin, 256);
|
|
13
|
+
if (!plugin) return {};
|
|
14
|
+
return {
|
|
15
|
+
plugin,
|
|
16
|
+
pluginVersion: pluginBin.version
|
|
17
|
+
? boundedIdentity(pluginBin.version, 128) || undefined
|
|
18
|
+
: undefined,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const attribution =
|
|
22
|
+
result?.toolAttribution && typeof result.toolAttribution === "object"
|
|
23
|
+
? result.toolAttribution
|
|
24
|
+
: null;
|
|
25
|
+
const source =
|
|
26
|
+
typeof attribution?.source === "string" ? attribution.source : "";
|
|
27
|
+
const match = source.match(/^plugin(?::|\/)(.+)$/i);
|
|
28
|
+
const plugin = match ? boundedIdentity(match[1], 256) : null;
|
|
29
|
+
return plugin
|
|
30
|
+
? {
|
|
31
|
+
plugin,
|
|
32
|
+
pluginVersion: attribution.version
|
|
33
|
+
? boundedIdentity(attribution.version, 128) || undefined
|
|
34
|
+
: undefined,
|
|
35
|
+
}
|
|
36
|
+
: {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function boundedIdentity(value, max) {
|
|
40
|
+
const clean = String(value ?? "")
|
|
41
|
+
.replace(/\p{Cc}/gu, "")
|
|
42
|
+
.trim();
|
|
43
|
+
return clean ? clean.slice(0, max) : null;
|
|
44
|
+
}
|