chainlesschain 0.162.182 → 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.
Files changed (176) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-DzZ5_xoj.js → AIOps-BapS7lz4.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-DeLXddIg.js → ActionButton-CXYdXEUI.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-rvDCmet1.js → Analytics-CKR5Lexn.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-Yt6QVDnp.js → AppLayout-DATVUOXB.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-BS112K5L.js → Artifacts-vb_0ZlV1.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-0wJuQrNu.js → Audit-BI1l9GWt.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-B90PMgbn.js → BackgroundAgents-BFXbaUEf.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-TkgMglQQ.js → Backup-DEYBJJ6H.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CQVS9p1l.js → BaseInput-COdzeO0M.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-YTjQHoC7.js → Chat-oSN6sfM5.js} +6 -6
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-CI_jT0ru.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-5bwaOabq.js → Checkbox-BezEa4tm.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-BFmNQ_Xe.js → Codegen-CNEL0Ife.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-BT_u4Dzp.js → Col-Bf2Y2Bn1.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-CJP52u5b.js → Community-BfUlu4Hc.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-BpzhJE9i.js → Compact-BN4xWP9e.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-Cg7rfslp.js → Compliance-Bt6BKmEP.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-JisxL6Yy.js → Cowork-DKLp8YxO.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-Bu7Ug_MC.js → Cron-o7Hhw6ky.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-CvuqoLdj.js → Crosschain-DaNXWJIw.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-C2u9G8Pu.js → DID-B-Qa2mha.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-BFt5Yv3d.js → Dashboard-CMX0Qnxw.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-DIaT9Wxq.js → Dropdown-BLuLyRu_.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-D_A601Y4.js → EmailListRenderer-CFBAeMij.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard--IyQ8I8w.js → FamilyGuardDashboard-DWzXQ67V.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-BihWHxuY.js → Federation-DB1QSLgr.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-BB8dOXc_.js → FormItemContext-C-OKCToP.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-DQYhj1HH.js → GenericCardRenderer-DMJFtFZf.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-B-2QZxGf.js → Git-DsGSujOV.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-CusSb-nG.js → Governance-B0iS9NEW.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BAjmvPPL.js → Inference-CH004H7c.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DoNYWKYq.js → KnowledgeGraph-Q9MTQ83c.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-B8fKWD-n.js → Logs-B_fyjZK9.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-BlJm1J7E.js → MarkdownRenderer-C0o4FtpD.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-CyOscbSL.js → Marketplace-BIStF9d1.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-Ex6Om5da.js → McpTools-pGfal768.js} +5 -5
  38. package/src/assets/web-panel/assets/{Memory-CDcD8l8r.js → Memory-xbNqpIqB.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-xfBqoFDg.js → MobileBridge-B5EQGrIK.js} +1 -1
  40. package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +1 -0
  41. package/src/assets/web-panel/assets/{Mtc-CIWd36OV.js → Mtc-a_rmfxJH.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-CPX0ouuA.js → MtcAudit-BmKuofUr.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-BDJsIUuW.js → Multisig-BQbJ-CAN.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-DEkbuD3N.js → NLProgramming-JtPJKX25.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-DJpHRhH1.js → Notes-ZFKznTSG.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-C1UZ-Qd5.js → NotificationSettings-B6aHRBBR.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-GlJtqLjT.js → OrderTableRenderer-DdcsOqEz.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-Bbhj0fac.js → Organization-BFDTAUgS.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-1H04x3kx.js → Overflow-0FoTfbWH.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CDpPe3et.js → P2P-CWd90etw.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-MUX0Bpvw.js → PdhVaultBrowser-DtCGC-W-.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-A07-0Ci1.js → Permissions-CvQ7nr7T.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-DhhDWxAZ.js → PersonalDataHub-rdNPcR-Z.js} +5 -5
  54. package/src/assets/web-panel/assets/{Pipeline-CyfbJfe-.js → Pipeline-CmrfiNOs.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-CNFps3ED.js → Privacy-D7ep1h_t.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit--T-u3Dr5.js → ProjectInit-C0xKINHS.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-DJmrK2fC.js → ProjectSettings-AOmZFp-F.js} +2 -2
  58. package/src/assets/web-panel/assets/Projects-BWHSkXZP.js +1 -0
  59. package/src/assets/web-panel/assets/{Providers-DLzzbOZd.js → Providers-Cb7JCTPL.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-CexOomKS.js → QrScannerModal-BDMehcXC.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-QklGi19_.js → QuickAsk-BF6_1nvx.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Bb9kwSw8.js → Recommend-BHfT-A28.js} +1 -1
  63. package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +5 -0
  64. package/src/assets/web-panel/assets/{Reputation-Dr5cLP0N.js → Reputation-CsWHLEcj.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-oCQHYv5t.js → Row-D6srnWhm.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-IFDEykIR.js → RssFeed-Xhr-KyVd.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-CspVIxDc.js → Search-vIbIJvwL.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-Bm66o_DH.js → Security-Bzi5Aiko.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-DvanNqXl.js → Services-BHtVX52P.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-CHjEe9_O.js → Skeleton-C0R8B2jf.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-Cb8jWjMX.js → Skills-DtT6rWOX.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-DxZm1491.js → Sla-0B37mxVU.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-DWxEEclC.js → SpeechSettings-0V2jE1Bs.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-FIvOFw5p.js → SyncSettings-CYedRzaj.js} +2 -2
  75. package/src/assets/web-panel/assets/Tasks-D-R1x8vm.js +1 -0
  76. package/src/assets/web-panel/assets/{Templates-CaNjzV_t.js → Templates-BKoHztGT.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-DjlP6TmH.js → Tenant--17nwVNZ.js} +1 -1
  78. package/src/assets/web-panel/assets/Terminal-Dnkos7vW.js +3 -0
  79. package/src/assets/web-panel/assets/{TimelineRenderer-DoZ8y7y8.js → TimelineRenderer-C5jx4AE3.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-390cg2TC.js → Tokens-DYJKYa9t.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-CLrtCj5_.js → Trigger-DChpWiQ9.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-DpESfSPn.js → Trust-DfWG52EA.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-CN6279O0.js → UkeySign-CMugYcyA.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-DPtAUlSe.js → VideoEditing-BOSmrHAd.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-nKOMV_1n.js → Wallet-D5g3k3Sa.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-HuXlSOc4.js → WebAuthn-D-7u4Mkc.js} +5 -5
  87. package/src/assets/web-panel/assets/{WorkflowEditor-CUfFjARi.js → WorkflowEditor-CFzZMSUJ.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-6Eq0PcZJ.js → chat-VbR6l6mc.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-BP_Sf6Iy.js → colors-BSZn8EDS.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-BufMKIh5.js → compact-item-y74obMEq.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-BBMXxWSW.js → createContext-C326bjex.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-D3Bho_6u.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-fUK_tRO2.js → hasIn-D_INJQT_.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-LvCBfTLo.js → index-4PIeTM--.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CgiECHu2.js → index-4eyH-eC2.js} +1 -1
  96. package/src/assets/web-panel/assets/index-5iAFwYx1.js +1 -0
  97. package/src/assets/web-panel/assets/{index-DLpIs_P_.js → index-9PIVuXqo.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-cpEli44X.js → index-B7SrC-On.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-6GmBa4Kg.js → index-BJi3UqBt.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-D9vU25ij.js → index-BY8-nCgs.js} +1 -1
  101. package/src/assets/web-panel/assets/index-BfnB7LPx.js +1 -0
  102. package/src/assets/web-panel/assets/{index-B2vS66eI.js → index-Bfw2hf2s.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DVsqvI4M.js → index-BjcWKg1S.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-C44atv4k.js → index-BnSfnSMP.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BWKoBU8R.js → index-Bnua8IX3.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-GwdRUZ-x.js → index-C-ZCaUJc.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-pum7HYBA.js → index-C2NyllnW.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-B9WYSn4m.js → index-C327pLbw.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bkg4ZePE.js → index-CMHqs3Jb.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DmkMXwnR.js → index-CfLJ42kv.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-Dyngbd29.js → index-Cr3uuz0C.js} +19 -19
  112. package/src/assets/web-panel/assets/{index-t8N1tSeX.js → index-CsovTpx9.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-DocdRcbd.js → index-CzE53HiB.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-fzaMtSJ8.js → index-DBkzrpiL.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CE2DdTP2.js → index-DNMxIsDg.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-wKTLbKyc.js → index-DUU2606o.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-uCbEN7cY.js → index-DdyjrCAu.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-CZ6Yt17L.js → index-DkH1JvEt.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-CwSf5pnf.js → index-Dlxh9D8D.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-3FuwBewR.js → index-DuIkfnTF.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-CW_G-MXw.js → index-DwHSZLXg.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-BHy6yNiF.js → index-E_v1ZCTP.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-wV6iGdpY.js → index-FQBsuExX.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-DASluSqY.js → index-GA80ir_u.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BMLHv389.js → index-IZAWt0H8.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-B7Etk0Te.js → index-Iw0FfqUz.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-D4_MuGkd.js → index-KF9Zmqln.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Cp8vhyZy.js → index-abmn_8Yz.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-2A5ph8b2.js → index-gINyI1rh.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CeASi4fr.js → index-jYaogFE8.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CGjmILDm.js → index-nSn2-C4N.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DPdUNk1i.js → index-qMA4GYdQ.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-V5Fo95FM.js → initDefaultProps-DI0Zaf8-.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BYWU0hUT.js → motion-BZDKSy3Z.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-Cr1M-J2h.js → move-DsIW01Vp.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-BysQKi2N.js → mtc-parser-CohkDhsf.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-D1zHU8GC.js → omit-DpiN5rzg.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-CUArxtfi.js → pickAttrs-qbuqni3y.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-ChoYEys0.js → placementArrow-mBky6714.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-BQRs3Mo7.js → responsiveObserve-Bas3eQ2K.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-B8zbsCkg.js → slide-CBx_SKoK.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-C2U8Gs6h.js → statusUtils-BlYguJSV.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-Dd8MgL_V.js → styleChecker-BCYQmRGv.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-hknqY5NH.js → useFlexGapSupport-Dp5dybLM.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-CLTAmcfw.js → useFs-DHAMBgA2.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-ByegHbiB.js → usePersonalDataHub-W6jsSw76.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-DqlAy5DP.js → vnode-BkI6aayc.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-DiXiztQn.js → zoom-C_IMGueq.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/commands/agent.js +9 -0
  151. package/src/commands/background-session.js +49 -0
  152. package/src/commands/plugin.js +235 -23
  153. package/src/commands/session.js +13 -0
  154. package/src/data/changelog.json +13 -0
  155. package/src/harness/jsonl-session-store.js +6 -4
  156. package/src/lib/agent-team/team-runner.js +19 -1
  157. package/src/lib/background-agent-supervisor.js +49 -0
  158. package/src/lib/plugin-runtime/install.js +226 -7
  159. package/src/lib/plugin-runtime/scopes.js +13 -2
  160. package/src/lib/plugin-usage-attribution.js +44 -0
  161. package/src/lib/process-execution-broker/index.js +252 -1
  162. package/src/lib/process-execution-broker/platform-sandbox.js +1251 -101
  163. package/src/lib/session-usage.js +77 -0
  164. package/src/repl/agent-repl.js +6 -6
  165. package/src/runtime/headless-runner.js +9 -1
  166. package/src/runtime/headless-stream.js +20 -1
  167. package/src/runtime/mcp-config.js +15 -5
  168. package/src/assets/web-panel/assets/ChatBubbleRenderer-PR074hUN.js +0 -1
  169. package/src/assets/web-panel/assets/MobileProjects-BwObMMA2.js +0 -1
  170. package/src/assets/web-panel/assets/Projects-Qx_MdX9k.js +0 -1
  171. package/src/assets/web-panel/assets/RemoteSession-DZuVNNN5.js +0 -5
  172. package/src/assets/web-panel/assets/Tasks-CyuLnDFR.js +0 -1
  173. package/src/assets/web-panel/assets/Terminal-DwzGMniO.js +0 -3
  174. package/src/assets/web-panel/assets/devWarning-DgVKduH2.js +0 -1
  175. package/src/assets/web-panel/assets/index-DOZTSoS7.js +0 -1
  176. package/src/assets/web-panel/assets/index-DhpvjpqI.js +0 -1
@@ -26,22 +26,32 @@ import {
26
26
  listInstalledVersions,
27
27
  activeVersion,
28
28
  discoverPlugins,
29
+ DISABLED_FILENAME,
29
30
  } from "./scopes.js";
30
- import { verifyPluginManifest } from "../plugin-security.js";
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 res = installFromDirectory(dir, opts);
154
- return info ? { ...res, source: info.url, ref: info.ref || null } : res;
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: info ? info.url : null,
273
+ source: sourceMetadata?.source || null,
274
+ ref: sourceMetadata?.ref || null,
222
275
  };
223
276
  }
224
277
 
225
- const res = installFromDirectory(dir, { ...opts, scope, force: true });
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: info ? info.url : null,
232
- ref: info ? info.ref || null : null,
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
  /**
@@ -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
@@ -139,6 +147,8 @@ export function discoverPlugins(opts = {}) {
139
147
  if (!dirExists(root, opts.strictIo === true)) continue;
140
148
  for (const encoded of listDirs(root, opts.strictIo === true)) {
141
149
  const nameDir = path.join(root, encoded);
150
+ const enabled = !_deps.existsSync(path.join(nameDir, DISABLED_FILENAME));
151
+ if (!enabled && opts.includeDisabled !== true) continue;
142
152
  const version = activeVersionForDir(nameDir, opts.strictIo === true);
143
153
  if (!version) continue;
144
154
  const versionDir = path.join(nameDir, version);
@@ -158,6 +168,7 @@ export function discoverPlugins(opts = {}) {
158
168
  version: manifest.metadata?.version || version,
159
169
  root: versionDir,
160
170
  manifest,
171
+ enabled,
161
172
  });
162
173
  }
163
174
  }
@@ -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
+ }