chainlesschain 0.165.6 → 0.165.8

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 (238) hide show
  1. package/package.json +2 -1
  2. package/src/assets/web-panel/assets/{AIOps-vfoDb6HZ.js → AIOps-B3gWmXjo.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-Cm5f7p93.js → ActionButton-G9pdT-0e.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-yRuvgWxa.js → Analytics-Ca30J7m2.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-BROsC4h1.js → AppLayout-BtVTm8PU.js} +5 -5
  6. package/src/assets/web-panel/assets/{Artifacts-CimHApb1.js → Artifacts-BhViNa6u.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-DI8kr8zI.js → Audit-DhKq-FnY.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-DSLzKy-n.js → BackgroundAgents-BL0SVbnE.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DkH_n2r1.js → Backup-BWkblnFi.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-CKSrUoRA.js → BaseInput-ClaRNrF8.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-ClwfMXUS.js → Chat-sZE2Z77o.js} +4 -4
  12. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CjMaqfL7.js → ChatBubbleRenderer-BAfKOnRe.js} +1 -1
  13. package/src/assets/web-panel/assets/{Checkbox-BYTehcQG.js → Checkbox-Cvhay5WM.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-B8AMcp6J.js → Codegen-BpejL-4N.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-BNSogPo3.js → Col-g2Ki6g_1.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-JxPvGb8O.js → Community-D2xKbNo9.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-DF7bFAgE.js → Compact-DbL1Pds3.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-Bvhqnwrq.js → Compliance-DGtZCV4c.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-BDS0CJvM.js → Cowork-4kQpoNsI.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-DqvRfxoQ.js → Cron-BxTYXXAN.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-CDcIvnqS.js → Crosschain-k0J0LT2N.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-D7jaUxU3.js → DID-BaqhoPgN.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-B5A18wEV.js → Dashboard-T4RVPIM1.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-_6IVkGag.js → Dropdown-DszOToWq.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-C9PeiKCG.js → EmailListRenderer-C9KJU7HF.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DXjuEHrX.js → FamilyGuardDashboard-Cmr0JnsA.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-B4IAR9zv.js → Federation-BI-_2xZX.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CxQeSNx1.js → FormItemContext-DsnDEPsl.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-B8GS-Y3N.js → GenericCardRenderer-BLncAKKK.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-BS8SouUX.js → Git-BPQhGXDn.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-Dq9aYb5Q.js → Governance-CyElbUQW.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BrCEe9AJ.js → Inference-CcSntBQD.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DybOpiY2.js → KnowledgeGraph-p6e7HZ2r.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-DBpzbRfx.js → Logs-CNEtr-wz.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-Bj9xI0YH.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-Cc7CCSCu.js → Marketplace-Dd2notAJ.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DFaIhOfu.js → McpTools-BBsN2CSW.js} +4 -4
  38. package/src/assets/web-panel/assets/{Memory-KCqlp9ol.js → Memory-Dg2uTvwx.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-Bys84ySN.js → MobileBridge-r1YMRiJV.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-B-6qU-je.js → MobileProjects-C-89kSm4.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-BgY-fvCq.js → Mtc-CrPZcVgf.js} +5 -5
  42. package/src/assets/web-panel/assets/{MtcAudit-B8pCmqQJ.js → MtcAudit-sxi7hqJb.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-BbOmYutA.js → Multisig-CAgOMfF1.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-BocLQz_M.js → NLProgramming-DafaPts3.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-CSwbxEop.js → Notes-CJM-xUW_.js} +3 -3
  46. package/src/assets/web-panel/assets/{NotificationSettings-CqFNSYG3.js → NotificationSettings-L0ZjfAh_.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-C6gMfAk7.js → OrderTableRenderer-BB1CvCK0.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-QrDXVdMJ.js → Organization-DeLtgAD8.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Cxntotjt.js → Overflow-CKC2b10z.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CIdBOwNq.js → P2P-eyf2rzY1.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CT5aP8rD.js → PdhVaultBrowser-5upNIOW8.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-DH7OM8XU.js → Permissions-B8p3W6JK.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CnJqbWce.js → PersonalDataHub-BnRMxTq3.js} +5 -5
  54. package/src/assets/web-panel/assets/{Pipeline-5C3HG1kH.js → Pipeline-DjCNI1li.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-B4yIp7xK.js → Privacy-u6gXLbWT.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-BMvt-2M0.js → ProjectInit-BZAw4tkM.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-CvSTEMRG.js → ProjectSettings-B1Tr72q7.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-BKBJxEek.js → Projects-DO7HFuBQ.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-BdwUqFWN.js → Providers-BjCztyhj.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-DtnCKlTm.js → QrScannerModal-ZWyCUbR1.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-sTbgwyNr.js → QuickAsk-DhDjeW4G.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Bzr14gSb.js → Recommend-R_CN2MuU.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C_TF5IaJ.js → RemoteSession-uxFcujeu.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-GCAM4H2K.js → Reputation-DX8D7rks.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-Dir0r6OQ.js → Row-BYahQILD.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-CpGnlecX.js → RssFeed-CUSQ2tm-.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-DMMamC6u.js → Search-CnN_S8Cs.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-yqay5yG-.js → Security-DcZlh-O4.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-C5i2wh9G.js → Services-ZhBOjzIX.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-vUqk35yj.js → Skeleton-D5Qnq_lI.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-DzcSkhot.js → Skills-BC9cZ3Be.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-CB6qbYNr.js → Sla-DauJ3E8_.js} +1 -1
  73. package/src/assets/web-panel/assets/SpeechSettings-DbNeZ_fh.js +1 -0
  74. package/src/assets/web-panel/assets/{SyncSettings-D-RrsxTJ.js → SyncSettings-DUvJbSct.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-DFxdOJiq.js → Tasks-BXa-5noQ.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-SKAob_Aq.js → Templates-JxaiUt_3.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-BPfsfHQ-.js → Tenant-BW4ERQN8.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-8iw7FpUf.js → Terminal-DltUbdtv.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-C4Gjj5Su.js → TimelineRenderer-CMoZz0Tc.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-COYhN18e.js → Tokens-D_VEV60K.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-B-JzXcf6.js → Trigger-CCXTCs0R.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-BJ5bg0nI.js → Trust-lkGRIPcG.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-BG_ByRMf.js → UkeySign-BfGeQ9HX.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-B3kOnSiU.js → VideoEditing-BEC7pYvc.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-CcoGFnK7.js → Wallet-BZdG24o0.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-DdT8vRC_.js → WebAuthn-yoEddedp.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-CZu3M9N8.js → WorkflowEditor-BXZEprOW.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-DxJt3Qba.js → chat-gg0bzZal.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-DdYfwJaB.js → colors-DjRVRuin.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-BG3SUzwj.js → compact-item-su-dieAc.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-By51z2-1.js → createContext-Ci3S8oKF.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-CxbFX9uH.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-B0apZ3KJ.js → hasIn-D8F10heH.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DE76D-kA.js → index-11wtYQiF.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-BkvcEo4p.js → index-1IgxgALJ.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-Bos5_aMV.js → index-1agckWSq.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BfWYsB9t.js → index-5JqhujnR.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CAhHirVH.js → index-6Tniqk1s.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BYINoRLK.js → index-8Z-8BIlN.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-B5rLiEo0.js → index-BCI5v0yB.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-BZ_0qm4g.js → index-BDJntYmJ.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CWEuZWCK.js → index-BGzixOGZ.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BLIbGOLX.js → index-BMMOVoLD.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-bP_VlDb4.js → index-BTFpdBtt.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B3rWuPMW.js → index-Ba_HyPnE.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-Da_WBdLX.js → index-BbF1IHof.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-RD6O-0C6.js → index-BgT9su_e.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-CpjZhgNd.js → index-BzPB6kGZ.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Q2SCX-MI.js → index-C6ygzplr.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BIrJfqO4.js → index-CC3ZDjzY.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BBPf3TpM.js → index-CEmXRhAE.js} +1 -1
  112. package/src/assets/web-panel/assets/index-CJGOlduY.js +1 -0
  113. package/src/assets/web-panel/assets/{index-Cp6e-hGw.js → index-CMPqd5Cv.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-kf57LJ93.js → index-COWd8uGx.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CW93tZDv.js → index-CPIYSp4H.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BewKYrX9.js → index-CR0h6seT.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-p1_8SbI1.js → index-CUmDhC4j.js} +1 -1
  118. package/src/assets/web-panel/assets/index-CkBCN5yH.js +1 -0
  119. package/src/assets/web-panel/assets/{index-ZxtP8jG7.js → index-CusgZPtc.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BWF8_mkx.js → index-DBAETXft.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BP94CrBV.js → index-DIJ2qFOC.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CNIxXMmN.js → index-Dbq4NMET.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CzmQElZy.js → index-DkMEF5VT.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-ZFbps9po.js → index-DkfQR3hM.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-Dz49VOyQ.js → index-DnLucOn9.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-oxRrmFO9.js → index-DugB_aKa.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Bissefox.js → index-DyLUarhZ.js} +3 -3
  128. package/src/assets/web-panel/assets/{index-DaIz0NAW.js → index-T6_6ygJZ.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-SQqOlR3d.js → index-Tu8eWqh-.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DCn8IcxV.js → index-W7XUgdVL.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-3jWkIu5j.js → index-dHZinfko.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-C1C9i79A.js → index-jyNgp5FI.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-BWJktcg8.js → initDefaultProps-Cv4p8e4w.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BEXBzUFV.js → motion-B8EwmMOw.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-BUKwn2sx.js → move-B8R9F8TK.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-FTI7btqQ.js → mtc-parser-DoFYz5Bp.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-CsLtSPH3.js → omit-CHWYLBjI.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-DWZxsT_S.js → pickAttrs-CXuPDO77.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-Bcfs43CX.js → placementArrow-BaAtUUon.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-a9bcC1p-.js → responsiveObserve-DCc4zcDD.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-BDTzgOXN.js → slide-B_lx89oZ.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-Iq1j_HUg.js → statusUtils-DE8DPmR0.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-DAZEYxeh.js → styleChecker-1ktXOsL_.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-DVkjyDrh.js → useFlexGapSupport-xH89-wjh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-wXTpNTHt.js → useFs-DscvfW5p.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-CtQM_aZr.js → usePersonalDataHub-RdMKQta7.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-hjEoG85v.js → vnode-Z3wTni2T.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-BHVpyKg_.js → zoom-B0iChCsm.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/command-help-index.json +3 -3
  151. package/src/commands/agent.js +91 -60
  152. package/src/commands/git.js +39 -0
  153. package/src/commands/plugin.js +17 -2
  154. package/src/commands/session-group.js +131 -0
  155. package/src/commands/session-location.js +48 -0
  156. package/src/commands/session.js +11 -0
  157. package/src/commands/sync-providers.js +4 -1
  158. package/src/commands/update.js +1 -0
  159. package/src/data/changelog.json +27 -1
  160. package/src/gateways/ws/ws-agent-handler.js +20 -12
  161. package/src/harness/jsonl-session-store.js +279 -37
  162. package/src/harness/mcp-client.js +701 -91
  163. package/src/harness/session-index.js +15 -4
  164. package/src/lib/agent-worktree.js +8 -1
  165. package/src/lib/auto-mode-safety-classifier.js +3 -17
  166. package/src/lib/background-agent-keeper-protocol.js +26 -6
  167. package/src/lib/background-agent-supervisor.js +17 -1
  168. package/src/lib/browser-evidence.js +1405 -0
  169. package/src/lib/chrome-connector.js +465 -79
  170. package/src/lib/claude-project-auto-memory.js +481 -0
  171. package/src/lib/claude-project-storage-layout.js +104 -0
  172. package/src/lib/cloud/cloud-client.js +40 -0
  173. package/src/lib/execution-location-local-supervisor.mjs +226 -0
  174. package/src/lib/execution-location-runner-lifecycle.js +991 -0
  175. package/src/lib/execution-location-target-preflight.js +333 -0
  176. package/src/lib/execution-location-target.js +783 -13
  177. package/src/lib/file-lines.js +6 -1
  178. package/src/lib/gateway-client-resilience.js +571 -0
  179. package/src/lib/gitlab-mr-worktree.js +176 -0
  180. package/src/lib/hooks-v2-producers.js +119 -15
  181. package/src/lib/hooks-v2-workspace-context.js +44 -1
  182. package/src/lib/host-resource-budget.js +295 -0
  183. package/src/lib/ide-context.js +15 -2
  184. package/src/lib/llm-config-defaults.js +43 -0
  185. package/src/lib/mcp-lifecycle-authority.js +887 -0
  186. package/src/lib/mcp-oauth.js +101 -20
  187. package/src/lib/mcp-tls.js +103 -3
  188. package/src/lib/paths.js +260 -32
  189. package/src/lib/permission-request.js +48 -0
  190. package/src/lib/plugin-runtime/bin.js +3 -1
  191. package/src/lib/plugin-runtime/hooks.js +3 -1
  192. package/src/lib/plugin-runtime/install.js +117 -1
  193. package/src/lib/plugin-runtime/lsp.js +4 -4
  194. package/src/lib/plugin-runtime/marketplace-archive-source.js +40 -5
  195. package/src/lib/plugin-runtime/marketplace-catalog.js +13 -2
  196. package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
  197. package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
  198. package/src/lib/plugin-runtime/marketplace-source-adapter.js +33 -8
  199. package/src/lib/plugin-runtime/mcp.js +3 -1
  200. package/src/lib/plugin-runtime/monitors.js +3 -1
  201. package/src/lib/plugin-runtime/remote-source.js +151 -6
  202. package/src/lib/plugin-runtime/settings.js +3 -1
  203. package/src/lib/plugin-runtime/trust.js +274 -13
  204. package/src/lib/process-execution-broker/credential-agent.js +210 -41
  205. package/src/lib/process-execution-broker/index.js +15 -1
  206. package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
  207. package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
  208. package/src/lib/project-mcp-trust.js +165 -10
  209. package/src/lib/resume-session.js +9 -6
  210. package/src/lib/session-core-singletons.js +26 -11
  211. package/src/lib/session-host-lease.js +52 -16
  212. package/src/lib/session-lifecycle-scope.js +153 -0
  213. package/src/lib/session-message-fabric.js +168 -21
  214. package/src/lib/session-projection.js +244 -4
  215. package/src/lib/session-store-guard.js +3 -1
  216. package/src/lib/session-workbench-store.js +466 -0
  217. package/src/lib/spellcheck.js +211 -0
  218. package/src/lib/sub-agent-context.js +9 -9
  219. package/src/lib/sync-cli-db.js +485 -129
  220. package/src/lib/sync-credentials.js +31 -20
  221. package/src/lib/web-fetch.js +112 -40
  222. package/src/lib/web-search.js +127 -61
  223. package/src/lib/workspace-trust.js +793 -0
  224. package/src/repl/agent-repl.js +124 -5
  225. package/src/repl/permission-prompt.js +10 -12
  226. package/src/runtime/agent-core.js +311 -18
  227. package/src/runtime/bootstrap.js +37 -13
  228. package/src/runtime/coding-agent-contract-shared.cjs +11 -4
  229. package/src/runtime/headless-runner.js +234 -36
  230. package/src/runtime/headless-stream.js +181 -6
  231. package/src/runtime/mcp-config.js +298 -8
  232. package/src/runtime/policies/agent-policy.js +8 -0
  233. package/src/runtime/status-diagnostics-lite.js +9 -1
  234. package/src/assets/web-panel/assets/MarkdownRenderer-CFyt8iUd.js +0 -1
  235. package/src/assets/web-panel/assets/SpeechSettings-BHUI7cox.js +0 -1
  236. package/src/assets/web-panel/assets/devWarning-DorRZcI9.js +0 -1
  237. package/src/assets/web-panel/assets/index-BETiL0a3.js +0 -1
  238. package/src/assets/web-panel/assets/index-BhAVHuW8.js +0 -1
@@ -40,6 +40,11 @@ import {
40
40
  } from "../plugin-source-identity.js";
41
41
  import { createMarketplaceNetworkTransport } from "./marketplace-network.js";
42
42
  import { fetchAndMaterializeMarketplaceArchive } from "./marketplace-archive-source.js";
43
+ import {
44
+ createSameOriginMarketplaceHeaderFetch,
45
+ runMarketplaceCommandSource,
46
+ runMarketplaceHeadersHelper,
47
+ } from "./marketplace-command-source.js";
43
48
  import {
44
49
  assertMarketplaceSourceExecutable,
45
50
  normalizeMarketplacePackageSource,
@@ -215,12 +220,27 @@ export async function fetchRegistry(url, opts = {}) {
215
220
  );
216
221
  }
217
222
 
223
+ // This descriptor is local operator configuration, never registry metadata.
224
+ // It is intentionally evaluated only for the registry request and later
225
+ // carried in an opaque authority for the selected same-origin archive.
226
+ const marketplaceRequestHeaders = await resolveMarketplaceCatalogHeaders(
227
+ url,
228
+ opts,
229
+ );
230
+
218
231
  const networkTransport = createMarketplaceNetworkTransport({
219
232
  proxyUrl: opts.proxyUrl,
220
233
  pacFile: opts.pacFile,
221
234
  caFile: opts.caFile,
222
235
  });
223
- const fetchImpl = networkTransport?.fetch || _deps.fetch;
236
+ const transportFetch = networkTransport?.fetch || _deps.fetch;
237
+ const fetchImpl = marketplaceRequestHeaders
238
+ ? createSameOriginMarketplaceHeaderFetch(
239
+ transportFetch,
240
+ new URL(url).origin,
241
+ marketplaceRequestHeaders,
242
+ )
243
+ : transportFetch;
224
244
  let networkErr = null;
225
245
  let cacheFallbackAllowed = false;
226
246
  try {
@@ -283,6 +303,7 @@ export async function fetchRegistry(url, opts = {}) {
283
303
  },
284
304
  url,
285
305
  managedPolicy,
306
+ marketplaceRequestHeaders,
286
307
  );
287
308
  } catch (err) {
288
309
  networkErr = err;
@@ -308,7 +329,14 @@ export async function fetchRegistry(url, opts = {}) {
308
329
  cacheDir,
309
330
  expectedSha256,
310
331
  });
311
- if (cached) return bindFetchedRegistry(cached, url, managedPolicy);
332
+ if (cached) {
333
+ return bindFetchedRegistry(
334
+ cached,
335
+ url,
336
+ managedPolicy,
337
+ marketplaceRequestHeaders,
338
+ );
339
+ }
312
340
  } catch (cacheError) {
313
341
  throw new Error(
314
342
  `could not fetch registry ${displayUrl}: ${publicRegistryErrorMessage(networkErr)}; verified immutable cache rejected: ${publicRegistryCacheErrorMessage(cacheError)}`,
@@ -323,6 +351,38 @@ export async function fetchRegistry(url, opts = {}) {
323
351
  );
324
352
  }
325
353
 
354
+ function configuredMarketplaceHeadersHelper(url, opts) {
355
+ if (opts.headersHelper != null) return opts.headersHelper;
356
+ const marketplace = opts.config?.plugins?.marketplace;
357
+ if (!marketplace || typeof marketplace !== "object") return null;
358
+ let origin = null;
359
+ try {
360
+ origin = new URL(url).origin;
361
+ } catch {
362
+ return null;
363
+ }
364
+ const perOrigin = marketplace.headersHelpers;
365
+ if (
366
+ perOrigin &&
367
+ typeof perOrigin === "object" &&
368
+ Object.prototype.hasOwnProperty.call(perOrigin, origin)
369
+ ) {
370
+ return perOrigin[origin];
371
+ }
372
+ return marketplace.headersHelper ?? null;
373
+ }
374
+
375
+ async function resolveMarketplaceCatalogHeaders(url, opts) {
376
+ const descriptor = configuredMarketplaceHeadersHelper(url, opts);
377
+ if (descriptor == null) return null;
378
+ return runMarketplaceHeadersHelper(descriptor, {
379
+ platform: opts.platform,
380
+ spawn: opts.headersHelperSpawn,
381
+ spawnSync: opts.headersHelperSpawnSync,
382
+ kill: opts.headersHelperKill,
383
+ });
384
+ }
385
+
326
386
  async function readBoundedRegistryResponse(response) {
327
387
  const contentLength = Number(response?.headers?.get?.("content-length"));
328
388
  if (
@@ -584,7 +644,12 @@ function freezeRegistryValue(value) {
584
644
  return Object.freeze(value);
585
645
  }
586
646
 
587
- function bindFetchedRegistry(result, registryUrl, managedPolicy) {
647
+ function bindFetchedRegistry(
648
+ result,
649
+ registryUrl,
650
+ managedPolicy,
651
+ marketplaceRequestHeaders = null,
652
+ ) {
588
653
  const registry = freezeRegistryValue(result.registry);
589
654
  fetchedRegistryAuthorities.set(
590
655
  registry,
@@ -592,6 +657,11 @@ function bindFetchedRegistry(result, registryUrl, managedPolicy) {
592
657
  registryUrl: String(registryUrl),
593
658
  documentSha256: result.documentSha256 || null,
594
659
  managedPolicy,
660
+ // Credential values live only in this per-process, opaque binding. They
661
+ // never enter catalog, cache, provenance, or result JSON.
662
+ marketplaceRequestHeaders: marketplaceRequestHeaders
663
+ ? Object.freeze({ ...marketplaceRequestHeaders })
664
+ : null,
595
665
  }),
596
666
  );
597
667
  return { ...result, registry };
@@ -666,7 +736,7 @@ export function authorizeRegistryPluginEntry(
666
736
  cwd,
667
737
  kindHint: "git",
668
738
  });
669
- } else {
739
+ } else if (normalized.sourceType === "archive") {
670
740
  let registryOrigin;
671
741
  let archiveOrigin;
672
742
  try {
@@ -678,6 +748,8 @@ export function authorizeRegistryPluginEntry(
678
748
  if (archiveOrigin !== registryOrigin) {
679
749
  throw new Error("registry archive source must use the registry origin");
680
750
  }
751
+ } else if (normalized.sourceType !== "command") {
752
+ throw new Error("registry package source type is unsupported");
681
753
  }
682
754
  const authority = Object.freeze({});
683
755
  registryResolutionAuthorities.set(
@@ -694,6 +766,9 @@ export function authorizeRegistryPluginEntry(
694
766
  : null,
695
767
  payloadSha256: null,
696
768
  documentSha256: fetched.documentSha256,
769
+ commandMode:
770
+ normalized.sourceType === "command" ? normalized.commandSpec.mode : null,
771
+ marketplaceRequestHeaders: fetched.marketplaceRequestHeaders,
697
772
  }),
698
773
  );
699
774
  return {
@@ -734,6 +809,7 @@ export function listRegistryPlugins(registry) {
734
809
  : null,
735
810
  sourceType: source.type,
736
811
  ref: source.type === "git" ? source.ref : null,
812
+ ...(source.type === "command" ? { mode: source.mode } : {}),
737
813
  description: p.description || "",
738
814
  enabled: source.type !== "dynamic-disabled",
739
815
  ...(source.type === "dynamic-disabled"
@@ -800,13 +876,20 @@ export async function resolveRemoteSource(url, opts = {}) {
800
876
  token,
801
877
  registryResolutionAuthority: authorized.registryResolutionAuthority,
802
878
  });
803
- return {
879
+ const result = {
804
880
  ...resolvedSource,
805
- entry,
806
881
  fromCache,
807
882
  documentSha256,
808
883
  ...(networkAuthority ? { networkAuthority } : {}),
809
884
  };
885
+ // Command descriptors can contain local paths or credentials. Retain the
886
+ // exact registry entry for the immediate authorized materialization flow,
887
+ // but keep it out of generic result serialization/audit output.
888
+ Object.defineProperty(result, "entry", {
889
+ value: entry,
890
+ enumerable: false,
891
+ });
892
+ return result;
810
893
  }
811
894
 
812
895
  /** Inspect one selected entry without fetching any candidate source bytes. */
@@ -822,6 +905,22 @@ export function inspectRegistryEntrySource(entry) {
822
905
  archiveSpec: packageSource,
823
906
  };
824
907
  }
908
+ if (packageSource.type === "command") {
909
+ const inspected = {
910
+ source: null,
911
+ sourceIdentity: packageSource.identity,
912
+ sourceType: "command",
913
+ ref: null,
914
+ sha256: entry.sha256 || null,
915
+ };
916
+ // The descriptor may contain local credentials. It remains available to
917
+ // the immediate materializer but never spreads into a catalog/result.
918
+ Object.defineProperty(inspected, "commandSpec", {
919
+ value: packageSource,
920
+ enumerable: false,
921
+ });
922
+ return inspected;
923
+ }
825
924
  // Preserve the canonical remote Git validation from the registry security
826
925
  // boundary rather than accepting the adapter's more general local shape.
827
926
  const normalized = normalizeRegistryPluginSource(entry);
@@ -869,6 +968,7 @@ export async function resolveRegistryEntrySource(url, entry, opts = {}) {
869
968
  proxyUrl: opts.proxyUrl,
870
969
  pacFile: opts.pacFile,
871
970
  caFile: opts.caFile,
971
+ requestHeaders: issued.marketplaceRequestHeaders,
872
972
  });
873
973
  const materializedAuthority = Object.freeze({});
874
974
  registryResolutionAuthorities.set(
@@ -886,6 +986,51 @@ export async function resolveRegistryEntrySource(url, entry, opts = {}) {
886
986
  registryResolutionAuthority: materializedAuthority,
887
987
  };
888
988
  }
989
+ if (inspected.sourceType === "command") {
990
+ const command = await runMarketplaceCommandSource(
991
+ {
992
+ executable: inspected.commandSpec.executable,
993
+ args: inspected.commandSpec.args,
994
+ cwd: inspected.commandSpec.cwd,
995
+ env: inspected.commandSpec.env,
996
+ timeoutMs: inspected.commandSpec.timeoutMs,
997
+ maxOutputBytes: inspected.commandSpec.maxOutputBytes,
998
+ mode: inspected.commandSpec.mode,
999
+ },
1000
+ {
1001
+ platform: opts.platform,
1002
+ spawn: opts.commandSpawn,
1003
+ spawnSync: opts.commandSpawnSync,
1004
+ kill: opts.commandKill,
1005
+ },
1006
+ );
1007
+ const materializedAuthority = Object.freeze({});
1008
+ registryResolutionAuthorities.set(
1009
+ materializedAuthority,
1010
+ Object.freeze({
1011
+ ...issued,
1012
+ source: command.source,
1013
+ payloadSha256: command.payloadSha256,
1014
+ commandMode: command.mode,
1015
+ fileCount: command.fileCount,
1016
+ totalBytes: command.totalBytes,
1017
+ }),
1018
+ );
1019
+ return {
1020
+ ...inspected,
1021
+ source: command.source,
1022
+ commandAuthority: Object.freeze({
1023
+ schemaVersion: "cc-plugin-marketplace-command-source/v1",
1024
+ status: "descriptor-executed-and-verified",
1025
+ descriptorIdentity: inspected.sourceIdentity,
1026
+ mode: command.mode,
1027
+ payloadSha256: command.payloadSha256,
1028
+ fileCount: command.fileCount,
1029
+ totalBytes: command.totalBytes,
1030
+ }),
1031
+ registryResolutionAuthority: materializedAuthority,
1032
+ };
1033
+ }
889
1034
  return {
890
1035
  ...inspected,
891
1036
  registryResolutionAuthority: opts.registryResolutionAuthority,
@@ -37,7 +37,9 @@ export function collectPluginSettings(opts = {}) {
37
37
  } catch {
38
38
  return { env: {}, model: null, sources: [] };
39
39
  }
40
- const { trusted, skipped } = partitionByTrust(plugins);
40
+ const { trusted, skipped } = partitionByTrust(plugins, {
41
+ workspaceRoot: opts.cwd,
42
+ });
41
43
  warnUntrustedOnce(
42
44
  skipped.filter((p) => p.manifest?.components?.settings).map((p) => p.name),
43
45
  "settings",
@@ -22,12 +22,21 @@
22
22
  */
23
23
 
24
24
  import path from "path";
25
+ import { createHash } from "node:crypto";
25
26
  import { getElectronUserDataDir } from "../paths.js";
26
27
  import { withFileLock } from "../with-file-lock.js";
27
28
  import {
28
29
  mutateSecurityStore,
29
30
  readSecurityStore,
30
31
  } from "../durable-security-store.js";
32
+ import {
33
+ checkRecordedWorkspaceTrust,
34
+ evaluateWorkspaceTrustDecision,
35
+ projectWorkspaceTrustAudit,
36
+ recordWorkspaceTrustConsent,
37
+ resolveCanonicalWorkspaceRepoIdentity,
38
+ revokeRecordedWorkspaceTrust,
39
+ } from "../workspace-trust.js";
31
40
 
32
41
  export const _deps = {
33
42
  now: () => new Date().toISOString(),
@@ -35,10 +44,16 @@ export const _deps = {
35
44
  // Path of the trust store; injectable so unit tests never touch the real
36
45
  // user-data dir.
37
46
  storePath: () => path.join(getElectronUserDataDir(), "plugin-trust.json"),
47
+ // Test-only seam. Production uses workspace-trust.js's one shared ledger.
48
+ workspaceTrustStorePath: () => null,
38
49
  };
39
50
 
40
51
  const AUTO_TRUSTED_SCOPES = new Set(["user", "local"]);
41
52
 
53
+ function defaultPluginTrustStorePath() {
54
+ return path.join(getElectronUserDataDir(), "plugin-trust.json");
55
+ }
56
+
42
57
  export function loadTrustStore() {
43
58
  return readSecurityStore(_deps.storePath(), "plugin trust");
44
59
  }
@@ -47,26 +62,228 @@ function trustKey(scope, name) {
47
62
  return `${scope}:${name}`;
48
63
  }
49
64
 
65
+ const PLUGIN_WORKSPACE_TRUST_SOURCE = "plugin";
66
+
67
+ function workspaceTrustStoreOptions(options = {}) {
68
+ const sourceStore = options.storePath || _deps.storePath();
69
+ let usesDefaultSourceStore = false;
70
+ try {
71
+ usesDefaultSourceStore =
72
+ path.resolve(sourceStore) === path.resolve(defaultPluginTrustStorePath());
73
+ } catch {
74
+ // Let the source-specific mutation/check fail closed later. This helper
75
+ // must not turn an invalid custom path into the production shared ledger.
76
+ }
77
+ const store =
78
+ options.workspaceTrustStorePath ||
79
+ process.env.CC_WORKSPACE_TRUST_STORE ||
80
+ _deps.workspaceTrustStorePath() ||
81
+ (!usesDefaultSourceStore && typeof sourceStore === "string"
82
+ ? path.join(path.dirname(sourceStore), "workspace-trust-v1.json")
83
+ : null);
84
+ return store ? { storePath: store } : {};
85
+ }
86
+
87
+ function pluginWorkspaceRoot(plugin, options = {}) {
88
+ return (
89
+ options.workspaceRoot ||
90
+ plugin?.workspaceRoot ||
91
+ plugin?.projectRoot ||
92
+ plugin?.cwd ||
93
+ process.cwd()
94
+ );
95
+ }
96
+
97
+ function pluginWorkspaceTrustContext(plugin, options = {}) {
98
+ const scope = String(plugin?.scope || "");
99
+ const name = String(plugin?.name || "");
100
+ const version = String(plugin?.version || "");
101
+ if (!scope || !name || !version) {
102
+ throw new Error("plugin trust requires scope, name, and version");
103
+ }
104
+ const identity = resolveCanonicalWorkspaceRepoIdentity(
105
+ pluginWorkspaceRoot(plugin, options),
106
+ );
107
+ const subject = `${scope}:${name}`;
108
+ const fingerprint = createHash("sha256")
109
+ .update(`${scope}\0${name}\0${version}`, "utf8")
110
+ .digest("hex");
111
+ return { identity, subject, fingerprint };
112
+ }
113
+
114
+ function workspaceTrustKey(plugin, context) {
115
+ const nameDigest = createHash("sha256")
116
+ .update(String(plugin.name), "utf8")
117
+ .digest("hex");
118
+ return `workspace-v1:${context.identity.workspaceId}:${nameDigest}`;
119
+ }
120
+
121
+ function pluginDecision(status, context, consent = "explicit") {
122
+ const decision = evaluateWorkspaceTrustDecision({
123
+ identity: context.identity,
124
+ evidence: [
125
+ {
126
+ source: PLUGIN_WORKSPACE_TRUST_SOURCE,
127
+ consent,
128
+ fingerprint: context.fingerprint,
129
+ decision:
130
+ status === "trusted"
131
+ ? "allow"
132
+ : status === "first-use"
133
+ ? "ask"
134
+ : "deny",
135
+ },
136
+ ],
137
+ });
138
+ return Object.freeze({
139
+ status,
140
+ decision: decision.decision,
141
+ audit: projectWorkspaceTrustAudit(decision),
142
+ });
143
+ }
144
+
50
145
  /**
51
- * May this plugin's code-bearing components run?
52
- * @param {{ scope, name, version }} plugin
146
+ * Evaluate one plugin against the shared canonical workspace trust lattice.
147
+ * User/local scope keeps its established local-install consent model; project
148
+ * scope requires both the source-specific record and the shared v1 record.
53
149
  */
54
- export function isPluginTrusted(plugin) {
55
- if (!plugin || !plugin.name) return false;
56
- if (AUTO_TRUSTED_SCOPES.has(plugin.scope)) return true;
150
+ export function checkPluginWorkspaceTrust(plugin, options = {}) {
151
+ if (!plugin || !plugin.name) {
152
+ return Object.freeze({
153
+ status: "changed",
154
+ decision: "deny",
155
+ audit: projectWorkspaceTrustAudit(null),
156
+ });
157
+ }
158
+ const scope = String(plugin.scope || "");
57
159
  try {
58
- const entry = loadTrustStore()[trustKey(plugin.scope, plugin.name)];
59
- return Boolean(entry && entry.version === plugin.version);
160
+ const context = pluginWorkspaceTrustContext(plugin, options);
161
+ if (AUTO_TRUSTED_SCOPES.has(scope)) {
162
+ return pluginDecision("trusted", context, "scope-default");
163
+ }
164
+ if (scope !== "project") return pluginDecision("changed", context);
165
+
166
+ const store = loadTrustStore();
167
+ const record = store[workspaceTrustKey(plugin, context)];
168
+ const legacy = store[trustKey(scope, plugin.name)];
169
+ if (!record || typeof record !== "object" || Array.isArray(record)) {
170
+ // Old scope:name records have no canonical workspace identity. They
171
+ // remain visible to listTrust(), but require explicit re-consent.
172
+ const shared = checkRecordedWorkspaceTrust({
173
+ identity: context.identity,
174
+ source: PLUGIN_WORKSPACE_TRUST_SOURCE,
175
+ subject: context.subject,
176
+ evidenceFingerprint: context.fingerprint,
177
+ ...workspaceTrustStoreOptions(options),
178
+ });
179
+ if (shared.status === "changed") {
180
+ return Object.freeze({
181
+ status: "changed",
182
+ decision: shared.decision,
183
+ audit: shared.audit,
184
+ });
185
+ }
186
+ if (legacy?.version) {
187
+ // Match the shared migration contract: a legacy allow is downgraded
188
+ // to `ask`, never silently reused. `isPluginTrusted` still refuses to
189
+ // run it until trustPlugin writes canonical v1 consent.
190
+ return Object.freeze({
191
+ ...pluginDecision("first-use", context, "legacy"),
192
+ status: "changed",
193
+ });
194
+ }
195
+ return Object.freeze({
196
+ status: "first-use",
197
+ decision: shared.decision,
198
+ audit: shared.audit,
199
+ });
200
+ }
201
+ const binding = record.workspaceTrust;
202
+ if (
203
+ record.version !== plugin.version ||
204
+ !binding ||
205
+ binding.workspaceId !== context.identity.workspaceId ||
206
+ binding.repositoryId !== context.identity.repositoryId ||
207
+ binding.subject !== context.subject
208
+ ) {
209
+ return pluginDecision("changed", context);
210
+ }
211
+ const shared = checkRecordedWorkspaceTrust({
212
+ identity: context.identity,
213
+ source: PLUGIN_WORKSPACE_TRUST_SOURCE,
214
+ subject: context.subject,
215
+ evidenceFingerprint: context.fingerprint,
216
+ ...workspaceTrustStoreOptions(options),
217
+ });
218
+ return Object.freeze({
219
+ status: shared.status === "trusted" ? "trusted" : "changed",
220
+ decision: shared.decision,
221
+ audit: shared.audit,
222
+ });
60
223
  } catch {
61
- // Project code must stay disabled when the trust store is unavailable.
62
- return false;
224
+ return Object.freeze({
225
+ status: "changed",
226
+ decision: "deny",
227
+ audit: projectWorkspaceTrustAudit(null),
228
+ });
63
229
  }
64
230
  }
65
231
 
232
+ /**
233
+ * May this plugin's code-bearing components run?
234
+ * @param {{ scope, name, version }} plugin
235
+ */
236
+ export function isPluginTrusted(plugin) {
237
+ return checkPluginWorkspaceTrust(plugin).decision === "allow";
238
+ }
239
+
66
240
  /** Trust a plugin (records the exact version). */
67
- export function trustPlugin(name, { scope = "project", version } = {}) {
241
+ export function trustPlugin(
242
+ name,
243
+ { scope = "project", version, workspaceRoot, workspaceTrustStorePath } = {},
244
+ ) {
68
245
  if (!version) throw new Error("trustPlugin requires a version");
69
246
  const file = _deps.storePath();
247
+ const plugin = { scope, name, version, workspaceRoot };
248
+ if (scope === "project") {
249
+ const context = pluginWorkspaceTrustContext(plugin, { workspaceRoot });
250
+ recordWorkspaceTrustConsent({
251
+ identity: context.identity,
252
+ source: PLUGIN_WORKSPACE_TRUST_SOURCE,
253
+ subject: context.subject,
254
+ evidenceFingerprint: context.fingerprint,
255
+ consent: "explicit",
256
+ ...workspaceTrustStoreOptions({
257
+ workspaceTrustStorePath,
258
+ storePath: file,
259
+ }),
260
+ });
261
+ return mutateSecurityStore(
262
+ file,
263
+ "plugin trust",
264
+ (store) => {
265
+ store[workspaceTrustKey(plugin, context)] = {
266
+ name,
267
+ scope,
268
+ version,
269
+ trustedAt: _deps.now(),
270
+ workspaceTrust: {
271
+ schemaVersion: context.identity.schemaVersion,
272
+ workspaceId: context.identity.workspaceId,
273
+ repositoryId: context.identity.repositoryId,
274
+ subject: context.subject,
275
+ },
276
+ };
277
+ return {
278
+ name,
279
+ scope,
280
+ version,
281
+ workspaceId: context.identity.workspaceId,
282
+ };
283
+ },
284
+ { lock: _deps.withFileLock },
285
+ );
286
+ }
70
287
  return mutateSecurityStore(
71
288
  file,
72
289
  "plugin trust",
@@ -79,8 +296,38 @@ export function trustPlugin(name, { scope = "project", version } = {}) {
79
296
  }
80
297
 
81
298
  /** Revoke trust for a plugin at a scope. */
82
- export function untrustPlugin(name, { scope = "project" } = {}) {
299
+ export function untrustPlugin(
300
+ name,
301
+ { scope = "project", workspaceRoot, workspaceTrustStorePath } = {},
302
+ ) {
83
303
  const file = _deps.storePath();
304
+ if (scope === "project") {
305
+ const plugin = { scope, name, version: "trust-revocation", workspaceRoot };
306
+ const context = pluginWorkspaceTrustContext(plugin, { workspaceRoot });
307
+ const result = mutateSecurityStore(
308
+ file,
309
+ "plugin trust",
310
+ (store) => {
311
+ const key = workspaceTrustKey(plugin, context);
312
+ const existed = Object.prototype.hasOwnProperty.call(store, key);
313
+ delete store[key];
314
+ return { name, scope, removed: existed };
315
+ },
316
+ { lock: _deps.withFileLock },
317
+ );
318
+ // Local removal happens first, so a shared-ledger write failure cannot
319
+ // leave the code-bearing plugin authorized.
320
+ revokeRecordedWorkspaceTrust({
321
+ identity: context.identity,
322
+ source: PLUGIN_WORKSPACE_TRUST_SOURCE,
323
+ subject: context.subject,
324
+ ...workspaceTrustStoreOptions({
325
+ workspaceTrustStorePath,
326
+ storePath: file,
327
+ }),
328
+ });
329
+ return result;
330
+ }
84
331
  return mutateSecurityStore(
85
332
  file,
86
333
  "plugin trust",
@@ -97,12 +344,23 @@ export function untrustPlugin(name, { scope = "project" } = {}) {
97
344
  /** All trust entries (for `cc plugin trust --list`). */
98
345
  export function listTrust() {
99
346
  return Object.entries(loadTrustStore()).map(([key, v]) => {
347
+ if (key.startsWith("workspace-v1:") && v?.workspaceTrust) {
348
+ return {
349
+ scope: "project",
350
+ name: typeof v.name === "string" ? v.name : null,
351
+ version: v?.version || null,
352
+ trustedAt: v?.trustedAt || null,
353
+ workspaceId: v.workspaceTrust.workspaceId || null,
354
+ repositoryId: v.workspaceTrust.repositoryId || null,
355
+ };
356
+ }
100
357
  const idx = key.indexOf(":");
101
358
  return {
102
359
  scope: key.slice(0, idx),
103
360
  name: key.slice(idx + 1),
104
361
  version: v?.version || null,
105
362
  trustedAt: v?.trustedAt || null,
363
+ legacy: key.startsWith("project:"),
106
364
  };
107
365
  });
108
366
  }
@@ -111,11 +369,14 @@ export function listTrust() {
111
369
  * Split discovered plugins into those whose code may run and those gated out.
112
370
  * @returns {{ trusted: any[], skipped: any[] }}
113
371
  */
114
- export function partitionByTrust(plugins) {
372
+ export function partitionByTrust(plugins, options = {}) {
115
373
  const trusted = [];
116
374
  const skipped = [];
117
375
  for (const p of plugins || []) {
118
- (isPluginTrusted(p) ? trusted : skipped).push(p);
376
+ (checkPluginWorkspaceTrust(p, options).decision === "allow"
377
+ ? trusted
378
+ : skipped
379
+ ).push(p);
119
380
  }
120
381
  return { trusted, skipped };
121
382
  }