chainlesschain 0.163.8 → 0.164.0

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 (228) hide show
  1. package/package.json +4 -1
  2. package/scripts/macos-mcp-launcher-build.mjs +317 -0
  3. package/scripts/macos-mcp-launcher-postinstall.sh +54 -0
  4. package/scripts/macos-mcp-launcher-preinstall.sh +61 -0
  5. package/src/assets/web-panel/assets/{AIOps-CavM7W3k.js → AIOps-D2MEn7fI.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-CUvZGabQ.js → ActionButton-lCW_4Gf0.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-DeBnWnbe.js → Analytics-Bs7i-nsS.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-DbI5kxvd.js → AppLayout-CK7B6S_j.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-D93bigKm.js → Artifacts-C8ILjpyo.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-CBNvfUZa.js → Audit-Bb9cNaWc.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-CJLyh_YU.js → BackgroundAgents-sC9ooXIf.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-D_0yoehD.js → Backup-D-DrsplT.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-TJxmbObW.js → BaseInput-uCNZpwSK.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-CE0dto1q.js → Chat-CsDK1uE9.js} +6 -6
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZ5-yYiD.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-Ck1RVIVo.js → Checkbox-JhTXM1-K.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-qpoyf6DK.js → Codegen-BbzZLnyD.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-DUyPWjIE.js → Col-D4VW4m4j.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-D_S1BemS.js → Community-BXrYawxV.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-BjxeK-Gc.js → Compact-DCihGy1u.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-Dd3CEJsu.js → Compliance-DlyZ-lk8.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-B4QG7-ad.js → Cowork-DvGZrhbO.js} +3 -3
  23. package/src/assets/web-panel/assets/{Cron-BtZnids5.js → Cron-DUncZi8h.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-CHPfCBFD.js → Crosschain-C_hLuUcm.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-DT8DCEOK.js → DID-b6YSUqxr.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-COQab5_U.js → Dashboard-uvM15Cfb.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-BY1PsQuU.js → Dropdown-D1-Nd4qY.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-CsuAuaq3.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
  29. package/src/assets/web-panel/assets/{FamilyGuardDashboard-BqpinD-j.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
  30. package/src/assets/web-panel/assets/{Federation-D0gkfQFv.js → Federation-BbI3HGpv.js} +1 -1
  31. package/src/assets/web-panel/assets/{FormItemContext-BqgE-axK.js → FormItemContext-DSoEKuFu.js} +1 -1
  32. package/src/assets/web-panel/assets/{GenericCardRenderer-D0hJ2KvC.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
  33. package/src/assets/web-panel/assets/{Git-CmMB0uPY.js → Git-DIs9Zhf3.js} +2 -2
  34. package/src/assets/web-panel/assets/{Governance-BnVEI0Dk.js → Governance-jzZXrxcl.js} +1 -1
  35. package/src/assets/web-panel/assets/{Inference-YTAMihRP.js → Inference-JUPjf2ZI.js} +1 -1
  36. package/src/assets/web-panel/assets/{KnowledgeGraph-0ax7VHop.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
  37. package/src/assets/web-panel/assets/{Logs-B9TRcokL.js → Logs-iXiz8BEE.js} +2 -2
  38. package/src/assets/web-panel/assets/MarkdownRenderer-GmB6DOr6.js +1 -0
  39. package/src/assets/web-panel/assets/{Marketplace-B6CSuD_H.js → Marketplace-Y3Xch312.js} +1 -1
  40. package/src/assets/web-panel/assets/{McpTools-CjMXvOVU.js → McpTools-D7kGGbO7.js} +3 -3
  41. package/src/assets/web-panel/assets/{Memory-CXRF71U3.js → Memory-Do_hVxzh.js} +2 -2
  42. package/src/assets/web-panel/assets/{MobileBridge-DQgNp_oS.js → MobileBridge-CtrR0Tas.js} +1 -1
  43. package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +1 -0
  44. package/src/assets/web-panel/assets/{Mtc-6hDTRPe1.js → Mtc-qo5QCTGd.js} +2 -2
  45. package/src/assets/web-panel/assets/{MtcAudit-BlVHU1DS.js → MtcAudit-cq5mnjYj.js} +2 -2
  46. package/src/assets/web-panel/assets/{Multisig-DP9pzEbV.js → Multisig-Bq0MAQHw.js} +3 -3
  47. package/src/assets/web-panel/assets/{NLProgramming-Djorh8EV.js → NLProgramming-DdWE6Vi2.js} +1 -1
  48. package/src/assets/web-panel/assets/{Notes-oLZ-JkUg.js → Notes-BxMBFcIp.js} +4 -4
  49. package/src/assets/web-panel/assets/{NotificationSettings-Cg288VH3.js → NotificationSettings-RTrAcbUe.js} +1 -1
  50. package/src/assets/web-panel/assets/{OrderTableRenderer-Bb1O3Ofr.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
  51. package/src/assets/web-panel/assets/{Organization-CBdo-bHs.js → Organization-SQzIPdqC.js} +2 -2
  52. package/src/assets/web-panel/assets/{Overflow-qZdnVumx.js → Overflow-02yECh22.js} +1 -1
  53. package/src/assets/web-panel/assets/{P2P-D4kNfGNQ.js → P2P-BNg4pNCM.js} +2 -2
  54. package/src/assets/web-panel/assets/{PdhVaultBrowser-DnlMemM7.js → PdhVaultBrowser-BxPJZsD3.js} +5 -5
  55. package/src/assets/web-panel/assets/{Permissions-DHucHFBJ.js → Permissions-CLnDnPAz.js} +3 -3
  56. package/src/assets/web-panel/assets/{PersonalDataHub-BovlOIPR.js → PersonalDataHub-C5m0AjGf.js} +4 -4
  57. package/src/assets/web-panel/assets/{Pipeline-Deru3CQY.js → Pipeline-VwOf5Dhv.js} +1 -1
  58. package/src/assets/web-panel/assets/{Privacy-Bq5oTTbU.js → Privacy-CC0W2hZd.js} +1 -1
  59. package/src/assets/web-panel/assets/{ProjectInit-BfzxVWAz.js → ProjectInit-Dz893Bob.js} +2 -2
  60. package/src/assets/web-panel/assets/{ProjectSettings-CKC6XBtH.js → ProjectSettings-CxQkvl0k.js} +2 -2
  61. package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +1 -0
  62. package/src/assets/web-panel/assets/{Providers-C_jx4TWX.js → Providers-DeB9IkxK.js} +1 -1
  63. package/src/assets/web-panel/assets/{QrScannerModal-BdIHeVGC.js → QrScannerModal-OCeoaswn.js} +1 -1
  64. package/src/assets/web-panel/assets/{QuickAsk-BwZwAcPD.js → QuickAsk-DenotaAj.js} +1 -1
  65. package/src/assets/web-panel/assets/{Recommend-BNTt0L-m.js → Recommend-Cies_jjI.js} +1 -1
  66. package/src/assets/web-panel/assets/{RemoteSession-Biyn2-Ro.js → RemoteSession-Dxzl5n2T.js} +3 -3
  67. package/src/assets/web-panel/assets/{Reputation-D6VpG32B.js → Reputation-CW0mvxgZ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Row-D_74OvQQ.js → Row-SEd32qZU.js} +1 -1
  69. package/src/assets/web-panel/assets/{RssFeed-BTr0a-BQ.js → RssFeed-BSwnJ3Lm.js} +3 -3
  70. package/src/assets/web-panel/assets/{Search-C3MCFoNU.js → Search-xe2m8bkC.js} +1 -1
  71. package/src/assets/web-panel/assets/{Security-CqW9aJ6s.js → Security-Mq2F9Nro.js} +3 -3
  72. package/src/assets/web-panel/assets/{Services-Cw5GNaHF.js → Services-BKGw2V3P.js} +2 -2
  73. package/src/assets/web-panel/assets/{Skeleton-DZps5qeY.js → Skeleton-DW95-Rxf.js} +1 -1
  74. package/src/assets/web-panel/assets/{Skills-C6NQ1znT.js → Skills-CHgChCv_.js} +1 -1
  75. package/src/assets/web-panel/assets/{Sla-DFP8G2Sh.js → Sla-tKh6k3R7.js} +1 -1
  76. package/src/assets/web-panel/assets/{SpeechSettings-ESt6MB6v.js → SpeechSettings-D6UL3dA5.js} +1 -1
  77. package/src/assets/web-panel/assets/{SyncSettings-BHnN98aM.js → SyncSettings-D0Fw8fVL.js} +2 -2
  78. package/src/assets/web-panel/assets/{Tasks-NiSCaOf-.js → Tasks-20x1GB3D.js} +1 -1
  79. package/src/assets/web-panel/assets/{Templates-DsKFhW2C.js → Templates-DJ-lts-a.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tenant-CQ0E0ze5.js → Tenant-BFdGpbs7.js} +1 -1
  81. package/src/assets/web-panel/assets/{Terminal-D_rBu_by.js → Terminal-Xpx61vHL.js} +2 -2
  82. package/src/assets/web-panel/assets/{TimelineRenderer-D3Vm4Po4.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Tokens-DNTxRH6q.js → Tokens-Dellq08f.js} +1 -1
  84. package/src/assets/web-panel/assets/{Trigger-Dgprz1ms.js → Trigger-VKw8d0J-.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trust-B2rUnVBD.js → Trust-DNftdKT5.js} +1 -1
  86. package/src/assets/web-panel/assets/{UkeySign-DEGQNc6_.js → UkeySign-DX9VAKJI.js} +1 -1
  87. package/src/assets/web-panel/assets/{VideoEditing-jlsAx3Eh.js → VideoEditing-B2h3jO8q.js} +1 -1
  88. package/src/assets/web-panel/assets/{Wallet-8jQih1ij.js → Wallet-CjGkof7f.js} +4 -4
  89. package/src/assets/web-panel/assets/{WebAuthn-XLeO6xIB.js → WebAuthn-2Zfcu55P.js} +4 -4
  90. package/src/assets/web-panel/assets/{WorkflowEditor-De_dgDAG.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
  91. package/src/assets/web-panel/assets/{chat-CI19R_Sk.js → chat-CQNfD-YO.js} +1 -1
  92. package/src/assets/web-panel/assets/{colors-DsYTOYN3.js → colors-D4usyFT2.js} +1 -1
  93. package/src/assets/web-panel/assets/{compact-item-CM3-t_Qr.js → compact-item-s4TpjvjX.js} +1 -1
  94. package/src/assets/web-panel/assets/{createContext-BjxlBRZv.js → createContext-BRCSvYxj.js} +1 -1
  95. package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +1 -0
  96. package/src/assets/web-panel/assets/{hasIn-RDaWX_4i.js → hasIn-AdkUbkV-.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BN6UPD2E.js → index--00U6vXZ.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CiECJi-Q.js → index-B2V-eKfK.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CnHH7bnD.js → index-B4JJCfQ2.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-CjTrRt13.js → index-BIoG5yYf.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Dxge-xWl.js → index-BMcimU-2.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-9R6BxAr0.js → index-BPhkFZ1I.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BHNYPO0b.js → index-BQ3DXBtD.js} +3 -3
  104. package/src/assets/web-panel/assets/{index-Cpqm1qfU.js → index-Bad4VNvz.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-B9O9YyWE.js → index-BgiXR_-_.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-B5REnKt8.js → index-BtobShro.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-D6sm5-Xq.js → index-Bw2MEnUk.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DcPFB8qJ.js → index-C1mJtE6q.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BKJr-TZp.js → index-C484EJiS.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-Drlnwr8F.js → index-C5KAQFPQ.js} +1 -1
  111. package/src/assets/web-panel/assets/index-C61cnl3K.js +1 -0
  112. package/src/assets/web-panel/assets/{index-Dsij_KsN.js → index-C7Y8Aluc.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-IeiL9RKc.js → index-CCsM_Ybx.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-B-Z8eFUJ.js → index-CJCFe2Qf.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CyOGN6a5.js → index-CJVEOa4i.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-B0PMlbMs.js → index-CJdQrZth.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-nAH87mQP.js → index-CKC1t3Ic.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BGqqJfL0.js → index-CQhAVU5t.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Cd9OJhHG.js → index-CYdoQsa1.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-D0zcy54x.js → index-Cduu2Hhr.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DIUnNOjG.js → index-CkwiSLhU.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-CVQMeiwH.js → index-Cvyt-zhm.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BlT2VAEK.js → index-D2GjI2oe.js} +1 -1
  124. package/src/assets/web-panel/assets/index-D4XFHxBr.js +1 -0
  125. package/src/assets/web-panel/assets/{index-C0yx-jtQ.js → index-DARsAyUp.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-Bi46Xu4u.js → index-DVKfQ0Ux.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Cd3euP_4.js → index-DZT36ZYq.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BCnZyIMA.js → index-D_XBHopw.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-C4gkzxkw.js → index-DdCB70SS.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-B7WBt_4T.js → index-DzRjHxEv.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DX7tuWVJ.js → index-MMN9V6JF.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-DoQA0-52.js → index-RfMr79MW.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DXXtGMUJ.js → index-_IRVsV9X.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-pPL66J85.js → index-nXyk8GZ9.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-DyIWssPC.js → index-s_buFMEG.js} +1 -1
  136. package/src/assets/web-panel/assets/{initDefaultProps-BTL88of4.js → initDefaultProps-Blmpk7HL.js} +1 -1
  137. package/src/assets/web-panel/assets/{motion-BUB2pXwB.js → motion-DPBJMv1n.js} +1 -1
  138. package/src/assets/web-panel/assets/{move-egCkkOMm.js → move-ButdzCM7.js} +1 -1
  139. package/src/assets/web-panel/assets/{mtc-parser-DAWhZC8c.js → mtc-parser-cyRC_QCe.js} +1 -1
  140. package/src/assets/web-panel/assets/{omit-CvOxe_6d.js → omit-1epSV7hz.js} +1 -1
  141. package/src/assets/web-panel/assets/{pickAttrs-DZUSLZ5Z.js → pickAttrs-DuPY8xJs.js} +1 -1
  142. package/src/assets/web-panel/assets/{placementArrow-BERxGNMY.js → placementArrow-6XZqarhe.js} +1 -1
  143. package/src/assets/web-panel/assets/{responsiveObserve-DZuDfZ9n.js → responsiveObserve-B40pXBWM.js} +1 -1
  144. package/src/assets/web-panel/assets/{slide-DO756sgI.js → slide-jbZ9Wu4n.js} +1 -1
  145. package/src/assets/web-panel/assets/{statusUtils-BRQlIz28.js → statusUtils-BKQQcVy4.js} +1 -1
  146. package/src/assets/web-panel/assets/{styleChecker-DCSfdybl.js → styleChecker-NiKfWjUT.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFlexGapSupport-LD8dWVve.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFs-BX9uW2LK.js → useFs-CUGji7ph.js} +1 -1
  149. package/src/assets/web-panel/assets/{usePersonalDataHub-BPSlPuHU.js → usePersonalDataHub-4veyN2N2.js} +1 -1
  150. package/src/assets/web-panel/assets/{vnode-BmOILC9V.js → vnode-1-nLug-Z.js} +1 -1
  151. package/src/assets/web-panel/assets/{zoom-1iKowKGg.js → zoom-dhCeRDMo.js} +1 -1
  152. package/src/assets/web-panel/index.html +1 -1
  153. package/src/command-help-index.json +3 -3
  154. package/src/commands/cowork.js +174 -19
  155. package/src/commands/permissions.js +240 -16
  156. package/src/commands/plugin.js +1293 -56
  157. package/src/commands/session-location.js +276 -0
  158. package/src/commands/session.js +2 -0
  159. package/src/data/changelog.json +15 -2
  160. package/src/gateways/ws/action-protocol.js +35 -10
  161. package/src/gateways/ws/remote-session-protocol.js +24 -1
  162. package/src/gateways/ws/ws-agent-handler.js +12 -0
  163. package/src/gateways/ws/ws-server.js +48 -12
  164. package/src/harness/jsonl-session-store.js +341 -24
  165. package/src/harness/mcp-client.js +8 -1
  166. package/src/harness/remote-session-audit.js +1 -0
  167. package/src/harness/remote-session-crypto.js +210 -2
  168. package/src/harness/remote-session-registry.js +159 -6
  169. package/src/harness/session-list-index.js +233 -14
  170. package/src/lib/agent-authority.js +6 -0
  171. package/src/lib/background-agent-keeper-client.js +248 -0
  172. package/src/lib/background-agent-keeper-protocol.js +147 -0
  173. package/src/lib/background-agent-supervisor.js +520 -40
  174. package/src/lib/background-interaction-resolver.js +12 -0
  175. package/src/lib/background-turn-bootstrap-protocol.js +126 -0
  176. package/src/lib/cowork-workflow.js +336 -16
  177. package/src/lib/dynamic-workflow-facade.js +648 -0
  178. package/src/lib/execution-location-contract.js +551 -0
  179. package/src/lib/execution-location-runtime.js +130 -0
  180. package/src/lib/ide-context.js +94 -6
  181. package/src/lib/mcp-stdio-package-materialization.js +166 -14
  182. package/src/lib/packer/pkg-config-generator.js +2 -0
  183. package/src/lib/permission-authority.js +77 -0
  184. package/src/lib/permission-side-effect-center.js +495 -0
  185. package/src/lib/plugin-runtime/install.js +514 -13
  186. package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
  187. package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
  188. package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
  189. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
  190. package/src/lib/plugin-security.js +60 -3
  191. package/src/lib/process-execution-broker/index.js +1095 -57
  192. package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
  193. package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
  194. package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
  195. package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
  196. package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
  197. package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
  198. package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
  199. package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
  200. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  201. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  202. package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
  203. package/src/lib/public-ide-capability-manifest.js +3 -0
  204. package/src/lib/remote-approval-bridge.js +123 -17
  205. package/src/lib/remote-membership-authority.js +632 -0
  206. package/src/lib/remote-membership-coordinator.js +2409 -0
  207. package/src/lib/remote-membership-host-store.js +1750 -0
  208. package/src/lib/scoped-permission-store.js +369 -0
  209. package/src/lib/session-anti-rollback-anchor.js +262 -5
  210. package/src/lib/sub-agent-context.js +4 -0
  211. package/src/lib/workflow-definition-contract.js +149 -0
  212. package/src/repl/agent-repl.js +41 -7
  213. package/src/repl/chat-repl.js +2 -0
  214. package/src/repl/clipboard-image.js +735 -16
  215. package/src/repl/ide-status.js +1 -1
  216. package/src/repl/prompt-interactions.js +59 -6
  217. package/src/runtime/agent-core.js +83 -3
  218. package/src/runtime/headless-runner.js +30 -25
  219. package/src/runtime/headless-stream.js +32 -25
  220. package/src/workers/background-agent-keeper.js +498 -0
  221. package/src/workers/background-agent-worker.js +358 -13
  222. package/src/workers/background-turn-bootstrap.js +143 -0
  223. package/src/assets/web-panel/assets/MarkdownRenderer-yySN5YNM.js +0 -1
  224. package/src/assets/web-panel/assets/MobileProjects-DlPwcCbq.js +0 -1
  225. package/src/assets/web-panel/assets/Projects-CMolGhae.js +0 -1
  226. package/src/assets/web-panel/assets/devWarning-S1ld2LwU.js +0 -1
  227. package/src/assets/web-panel/assets/index-Drz6yq0m.js +0 -1
  228. package/src/assets/web-panel/assets/index-uWiUs7S_.js +0 -1
@@ -19,6 +19,7 @@
19
19
  import fs from "fs";
20
20
  import os from "os";
21
21
  import path from "path";
22
+ import crypto from "node:crypto";
22
23
  import { parsePluginManifest, isWithin } from "./manifest.js";
23
24
  import {
24
25
  pluginNameDir,
@@ -65,7 +66,7 @@ const pendingPluginTransactions = new WeakMap();
65
66
  /**
66
67
  * Install a plugin from a local directory into a scope's immutable version dir.
67
68
  * @param {string} srcDir directory containing the plugin (with its manifest)
68
- * @param {object} opts { scope="user", cwd, force=false }
69
+ * @param {object} opts { scope="user", cwd, force=false, expectedIdentity? }
69
70
  * @returns {{ name, version, scope, dir, warnings }}
70
71
  */
71
72
  export function installFromDirectory(srcDir, opts = {}) {
@@ -82,6 +83,7 @@ export function installFromDirectory(srcDir, opts = {}) {
82
83
  );
83
84
  }
84
85
  const { name, version } = manifest.metadata;
86
+ assertExpectedPluginIdentity(name, version, opts.expectedIdentity);
85
87
  const sourceMetadata = normalizeSourceMetadata(opts.sourceMetadata);
86
88
  if (opts.managedPolicy) {
87
89
  enforcePluginPolicy(
@@ -107,11 +109,16 @@ export function installFromDirectory(srcDir, opts = {}) {
107
109
  expectedSha256: sig.sha256,
108
110
  signatureFile: sig.signatureFile,
109
111
  publicKeyFile: sig.publicKeyFile,
112
+ expectedSignatureSha256: sig.expectedSignatureSha256 || null,
113
+ expectedPublicKeyDocumentSha256:
114
+ sig.expectedPublicKeyDocumentSha256 || null,
115
+ expectedPublicKeySha256: sig.expectedPublicKeySha256 || null,
110
116
  requireSignature: sig.requireSignature === true,
111
117
  trustedKeySha256: sig.trustedKeySha256 || null,
112
118
  requireTrustedKey: sig.requireTrustedKey === true,
113
119
  });
114
120
  }
121
+ assertRemoteSignatureInstallBinding(sourceMetadata, verification);
115
122
 
116
123
  const dest = pluginVersionDir(scope, name, version, { cwd: opts.cwd });
117
124
  const destExists = _deps.existsSync(dest);
@@ -148,10 +155,11 @@ export function installFromDirectory(srcDir, opts = {}) {
148
155
  );
149
156
  }
150
157
 
151
- // Record the verified signature into the staged immutable version. The
152
- // manifest and complete component SBOM are re-verified below before any
153
- // active bytes or pointer can change.
154
- if (verification) {
158
+ // Record only a cryptographically verified signature into the staged
159
+ // immutable version. A hash-only registry check is re-run below but must
160
+ // not create a signature lock or imply that the publisher was verified.
161
+ // Signed installs also bind the complete component SBOM before activation.
162
+ if (verification?.signatureVerified === true) {
155
163
  const stagedManifest = path.join(
156
164
  staged,
157
165
  path.relative(src, manifest.manifestPath),
@@ -243,13 +251,14 @@ export function installFromSource(source, opts = {}) {
243
251
  : { type: "local", source: path.resolve(String(source || "")) },
244
252
  );
245
253
  const res = installFromDirectory(dir, { ...opts, sourceMetadata });
246
- return info
247
- ? {
248
- ...res,
249
- source: sourceMetadata?.source || null,
250
- ref: sourceMetadata?.ref || null,
251
- }
252
- : res;
254
+ if (!info) return res;
255
+ const result = {
256
+ ...res,
257
+ source: sourceMetadata?.source || null,
258
+ ref: sourceMetadata?.ref || null,
259
+ };
260
+ transferPendingTransaction(res, result);
261
+ return result;
253
262
  });
254
263
  }
255
264
 
@@ -300,6 +309,7 @@ export function updatePlugin(source, opts = {}) {
300
309
  );
301
310
  }
302
311
  const { name, version } = manifest.metadata;
312
+ assertExpectedPluginIdentity(name, version, opts.expectedIdentity);
303
313
  const sourceMetadata =
304
314
  normalizeSourceMetadata(opts.sourceMetadata) ||
305
315
  normalizeSourceMetadata(
@@ -743,9 +753,463 @@ function normalizeSourceMetadata(value) {
743
753
  if (resolvedSource) metadata.resolvedSource = resolvedSource;
744
754
  if (packageName) metadata.package = packageName;
745
755
  if (value.offline === true) metadata.offline = true;
756
+ if (value.catalogAuthority != null) {
757
+ metadata.catalogAuthority = normalizeCatalogAuthority(
758
+ value.catalogAuthority,
759
+ );
760
+ }
761
+ assertCatalogRemoteArtifactBindings(metadata);
746
762
  return metadata;
747
763
  }
748
764
 
765
+ function assertCatalogRemoteArtifactBindings(metadata) {
766
+ const authority = metadata.catalogAuthority;
767
+ const evidence = authority?.remoteArtifactEvidence;
768
+ if (!evidence) return;
769
+ if (metadata.type !== "registry" || !metadata.registry) {
770
+ throw new Error(
771
+ "remote marketplace artifact evidence requires registry source metadata",
772
+ );
773
+ }
774
+ let registryOrigin;
775
+ try {
776
+ registryOrigin = new URL(metadata.registry).origin;
777
+ } catch {
778
+ throw new Error("remote marketplace artifact registry URL is invalid");
779
+ }
780
+ if (registryOrigin !== evidence.registryOrigin) {
781
+ throw new Error(
782
+ "remote marketplace artifact evidence registry origin does not match the selected registry",
783
+ );
784
+ }
785
+
786
+ const expectations = authority.artifactExpectations || {};
787
+ const expectedSignature = expectations.signature || {};
788
+ const expectsRemoteSignature = Boolean(
789
+ expectedSignature.url &&
790
+ expectedSignature.publicKeyUrl &&
791
+ expectedSignature.publicKeySha256,
792
+ );
793
+ if (expectsRemoteSignature !== Boolean(evidence.signature)) {
794
+ throw new Error(
795
+ "remote signature evidence does not match the catalog artifact declaration",
796
+ );
797
+ }
798
+ if (evidence.signature) {
799
+ const actual = evidence.signature;
800
+ if (
801
+ actual.url !== expectedSignature.url ||
802
+ actual.publicKey.url !== expectedSignature.publicKeyUrl ||
803
+ actual.publicKey.spkiSha256 !== expectedSignature.publicKeySha256 ||
804
+ (expectedSignature.documentSha256 &&
805
+ actual.signatureSha256 !== expectedSignature.documentSha256) ||
806
+ (expectedSignature.publicKeyDocumentSha256 &&
807
+ actual.publicKey.documentSha256 !==
808
+ expectedSignature.publicKeyDocumentSha256)
809
+ ) {
810
+ throw new Error(
811
+ "remote signature evidence does not match catalog URL or digest expectations",
812
+ );
813
+ }
814
+ }
815
+
816
+ const expectedSbom = expectations.sbom || {};
817
+ const expectsRemoteSbom = Boolean(
818
+ expectedSbom.url && expectedSbom.documentSha256,
819
+ );
820
+ if (expectsRemoteSbom !== Boolean(evidence.sbom)) {
821
+ throw new Error(
822
+ "remote SBOM evidence does not match the catalog artifact declaration",
823
+ );
824
+ }
825
+ if (evidence.sbom) {
826
+ const actual = evidence.sbom;
827
+ if (
828
+ actual.url !== expectedSbom.url ||
829
+ actual.expectedDocumentSha256 !== expectedSbom.documentSha256 ||
830
+ actual.documentSha256 !== expectedSbom.documentSha256 ||
831
+ actual.format !== expectedSbom.format
832
+ ) {
833
+ throw new Error(
834
+ "remote SBOM evidence does not match catalog URL, format, or digest expectations",
835
+ );
836
+ }
837
+ }
838
+ }
839
+
840
+ function assertRemoteSignatureInstallBinding(sourceMetadata, verification) {
841
+ const signature =
842
+ sourceMetadata?.catalogAuthority?.remoteArtifactEvidence?.signature;
843
+ if (!signature) return;
844
+ if (verification?.signatureVerified !== true) {
845
+ throw new Error(
846
+ "remote marketplace signature was not verified against the fetched plugin manifest",
847
+ );
848
+ }
849
+ if (
850
+ verification.signatureSha256 !== signature.signatureSha256 ||
851
+ verification.publicKeyDocumentSha256 !==
852
+ signature.publicKey.documentSha256 ||
853
+ verification.publicKeySha256 !== signature.publicKey.spkiSha256
854
+ ) {
855
+ throw new Error(
856
+ "remote marketplace signature bytes changed before installer verification",
857
+ );
858
+ }
859
+ }
860
+
861
+ function normalizeCatalogAuthority(value) {
862
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
863
+ throw new Error("catalogAuthority must be an object");
864
+ }
865
+ const catalogDigest = cleanBounded(value.catalogDigest, 64);
866
+ const candidateId = cleanBounded(value.candidateId, 64);
867
+ const candidateDigest = cleanBounded(value.candidateDigest, 64);
868
+ const selectionDigest = cleanBounded(value.selectionDigest, 64);
869
+ const updateImpactDigest = cleanBounded(value.updateImpactDigest, 64);
870
+ const artifactExpectations = normalizeArtifactExpectations(
871
+ value.artifactExpectations,
872
+ );
873
+ const remoteArtifactEvidence = normalizeRemoteArtifactEvidence(
874
+ value.remoteArtifactEvidence,
875
+ );
876
+ if (!/^[a-f0-9]{64}$/.test(catalogDigest || "")) {
877
+ throw new Error(
878
+ "catalogAuthority.catalogDigest must be a SHA-256 hex digest",
879
+ );
880
+ }
881
+ if (!/^candidate-[a-f0-9]{20}$/.test(candidateId || "")) {
882
+ throw new Error("catalogAuthority.candidateId is invalid");
883
+ }
884
+ if (candidateDigest && !/^[a-f0-9]{64}$/.test(candidateDigest)) {
885
+ throw new Error(
886
+ "catalogAuthority.candidateDigest must be a SHA-256 hex digest",
887
+ );
888
+ }
889
+ if (selectionDigest && !/^[a-f0-9]{64}$/.test(selectionDigest)) {
890
+ throw new Error(
891
+ "catalogAuthority.selectionDigest must be a SHA-256 hex digest",
892
+ );
893
+ }
894
+ if (updateImpactDigest && !/^[a-f0-9]{64}$/.test(updateImpactDigest)) {
895
+ throw new Error(
896
+ "catalogAuthority.updateImpactDigest must be a SHA-256 hex digest",
897
+ );
898
+ }
899
+ const governanceStatus = ["complete", "incomplete"].includes(
900
+ value.governanceStatus,
901
+ )
902
+ ? value.governanceStatus
903
+ : "incomplete";
904
+ const registryStatus = ["online", "cached"].includes(value.registryStatus)
905
+ ? value.registryStatus
906
+ : "online";
907
+ const versionAuthority = [
908
+ "registry-declared-unverified",
909
+ "deferred-to-plugin-manifest",
910
+ ].includes(value.versionAuthority)
911
+ ? value.versionAuthority
912
+ : "deferred-to-plugin-manifest";
913
+ const selectionSourceCount = Number.isInteger(value.selectionSourceCount)
914
+ ? value.selectionSourceCount
915
+ : null;
916
+ if (
917
+ selectionDigest &&
918
+ (!selectionSourceCount ||
919
+ selectionSourceCount < 1 ||
920
+ selectionSourceCount > 16)
921
+ ) {
922
+ throw new Error(
923
+ "catalogAuthority.selectionSourceCount must be between 1 and 16",
924
+ );
925
+ }
926
+ return {
927
+ schemaVersion: "cc-plugin-marketplace-catalog/v1",
928
+ installPreflightSchemaVersion: "cc-plugin-marketplace-install-preflight/v1",
929
+ catalogDigest,
930
+ candidateId,
931
+ ...(candidateDigest ? { candidateDigest } : {}),
932
+ ...(selectionDigest
933
+ ? {
934
+ selectionSchemaVersion:
935
+ "cc-plugin-marketplace-candidate-selection/v1",
936
+ selectionDigest,
937
+ selectionSourceCount,
938
+ }
939
+ : {}),
940
+ ...(updateImpactDigest ? { updateImpactDigest } : {}),
941
+ ...(artifactExpectations ? { artifactExpectations } : {}),
942
+ ...(remoteArtifactEvidence ? { remoteArtifactEvidence } : {}),
943
+ preflightStatus: "allowed",
944
+ governanceStatus,
945
+ registryStatus,
946
+ versionAuthority,
947
+ };
948
+ }
949
+
950
+ function normalizeArtifactExpectations(value) {
951
+ if (!value || typeof value !== "object" || Array.isArray(value)) return null;
952
+ const digest = (candidate, label) => {
953
+ const normalized = cleanBounded(candidate, 64);
954
+ if (normalized && !/^[a-f0-9]{64}$/i.test(normalized)) {
955
+ throw new Error(`${label} must be a SHA-256 hex digest`);
956
+ }
957
+ return normalized?.toLowerCase() || null;
958
+ };
959
+ const status = (candidate) =>
960
+ ["declared", "missing"].includes(candidate) ? candidate : "missing";
961
+ const manifestSha256 = digest(
962
+ value.manifest?.sha256,
963
+ "catalogAuthority.artifactExpectations.manifest.sha256",
964
+ );
965
+ const signatureKeySha256 = digest(
966
+ value.signature?.publicKeySha256,
967
+ "catalogAuthority.artifactExpectations.signature.publicKeySha256",
968
+ );
969
+ const sbomSha256 = digest(
970
+ value.sbom?.payloadSha256 ?? value.sbom?.sha256,
971
+ "catalogAuthority.artifactExpectations.sbom.sha256",
972
+ );
973
+ const signatureDocumentSha256 = digest(
974
+ value.signature?.documentSha256,
975
+ "catalogAuthority.artifactExpectations.signature.documentSha256",
976
+ );
977
+ const signaturePublicKeyDocumentSha256 = digest(
978
+ value.signature?.publicKeyDocumentSha256,
979
+ "catalogAuthority.artifactExpectations.signature.publicKeyDocumentSha256",
980
+ );
981
+ const sbomDocumentSha256 = digest(
982
+ value.sbom?.documentSha256,
983
+ "catalogAuthority.artifactExpectations.sbom.documentSha256",
984
+ );
985
+ return {
986
+ manifest: {
987
+ status: status(value.manifest?.status),
988
+ sha256: manifestSha256,
989
+ },
990
+ signature: {
991
+ status: status(value.signature?.status),
992
+ algorithm: cleanBounded(value.signature?.algorithm, 64),
993
+ publicKeySha256: signatureKeySha256,
994
+ documentSha256: signatureDocumentSha256,
995
+ publicKeyDocumentSha256: signaturePublicKeyDocumentSha256,
996
+ url: sanitizeSource(value.signature?.url),
997
+ publicKeyUrl: sanitizeSource(value.signature?.publicKeyUrl),
998
+ },
999
+ sbom: {
1000
+ status: status(value.sbom?.status),
1001
+ format: cleanBounded(value.sbom?.format, 128),
1002
+ sha256: sbomSha256,
1003
+ payloadSha256: sbomSha256,
1004
+ documentSha256: sbomDocumentSha256,
1005
+ url: sanitizeSource(value.sbom?.url),
1006
+ },
1007
+ license: {
1008
+ status: status(value.license?.status),
1009
+ expression: cleanBounded(value.license?.expression, 256),
1010
+ },
1011
+ };
1012
+ }
1013
+
1014
+ function normalizeRemoteArtifactEvidence(value) {
1015
+ if (value == null) return null;
1016
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1017
+ throw new Error(
1018
+ "catalogAuthority.remoteArtifactEvidence must be an object",
1019
+ );
1020
+ }
1021
+ if (
1022
+ value.schemaVersion !== "cc-plugin-marketplace-remote-artifact-evidence/v1"
1023
+ ) {
1024
+ throw new Error(
1025
+ "catalogAuthority.remoteArtifactEvidence schemaVersion is invalid",
1026
+ );
1027
+ }
1028
+ const digest = (candidate, label) => {
1029
+ const normalized = cleanBounded(candidate, 64)?.toLowerCase() || null;
1030
+ if (!normalized || !/^[a-f0-9]{64}$/.test(normalized)) {
1031
+ throw new Error(`${label} must be a SHA-256 hex digest`);
1032
+ }
1033
+ return normalized;
1034
+ };
1035
+ const boundedBytes = (candidate, maximum, label) => {
1036
+ if (
1037
+ !Number.isSafeInteger(candidate) ||
1038
+ candidate < 0 ||
1039
+ candidate > maximum
1040
+ ) {
1041
+ throw new Error(`${label} is outside the allowed byte limit`);
1042
+ }
1043
+ return candidate;
1044
+ };
1045
+ const normalizeArtifactUrl = (candidate, label) => {
1046
+ const sanitized = sanitizeSource(candidate);
1047
+ if (!sanitized || !/^https?:\/\//i.test(sanitized)) {
1048
+ throw new Error(`${label} must be an http(s) URL`);
1049
+ }
1050
+ return sanitized;
1051
+ };
1052
+ const normalizeRegistryOrigin = (candidate) => {
1053
+ const sanitized = normalizeArtifactUrl(
1054
+ candidate,
1055
+ "catalogAuthority.remoteArtifactEvidence.registryOrigin",
1056
+ );
1057
+ return new URL(sanitized).origin;
1058
+ };
1059
+ const signature = value.signature
1060
+ ? {
1061
+ status:
1062
+ value.signature.status === "fetched"
1063
+ ? "fetched"
1064
+ : (() => {
1065
+ throw new Error(
1066
+ "catalogAuthority.remoteArtifactEvidence.signature.status is invalid",
1067
+ );
1068
+ })(),
1069
+ url: normalizeArtifactUrl(
1070
+ value.signature.url,
1071
+ "catalogAuthority.remoteArtifactEvidence.signature.url",
1072
+ ),
1073
+ signatureSha256: digest(
1074
+ value.signature.signatureSha256,
1075
+ "catalogAuthority.remoteArtifactEvidence.signature.signatureSha256",
1076
+ ),
1077
+ bytes: boundedBytes(
1078
+ value.signature.bytes,
1079
+ 16 * 1024,
1080
+ "catalogAuthority.remoteArtifactEvidence.signature.bytes",
1081
+ ),
1082
+ fromCache: value.signature.fromCache === true,
1083
+ publicKey: {
1084
+ url: normalizeArtifactUrl(
1085
+ value.signature.publicKey?.url,
1086
+ "catalogAuthority.remoteArtifactEvidence.signature.publicKey.url",
1087
+ ),
1088
+ documentSha256: digest(
1089
+ value.signature.publicKey?.documentSha256,
1090
+ "catalogAuthority.remoteArtifactEvidence.signature.publicKey.documentSha256",
1091
+ ),
1092
+ spkiSha256: digest(
1093
+ value.signature.publicKey?.spkiSha256,
1094
+ "catalogAuthority.remoteArtifactEvidence.signature.publicKey.spkiSha256",
1095
+ ),
1096
+ bytes: boundedBytes(
1097
+ value.signature.publicKey?.bytes,
1098
+ 64 * 1024,
1099
+ "catalogAuthority.remoteArtifactEvidence.signature.publicKey.bytes",
1100
+ ),
1101
+ fromCache: value.signature.publicKey?.fromCache === true,
1102
+ },
1103
+ }
1104
+ : null;
1105
+ const sbom = value.sbom
1106
+ ? {
1107
+ status:
1108
+ value.sbom.status === "digest-verified"
1109
+ ? "digest-verified"
1110
+ : (() => {
1111
+ throw new Error(
1112
+ "catalogAuthority.remoteArtifactEvidence.sbom.status is invalid",
1113
+ );
1114
+ })(),
1115
+ url: normalizeArtifactUrl(
1116
+ value.sbom.url,
1117
+ "catalogAuthority.remoteArtifactEvidence.sbom.url",
1118
+ ),
1119
+ format: cleanBounded(value.sbom.format, 128),
1120
+ expectedDocumentSha256: digest(
1121
+ value.sbom.expectedDocumentSha256,
1122
+ "catalogAuthority.remoteArtifactEvidence.sbom.expectedDocumentSha256",
1123
+ ),
1124
+ documentSha256: digest(
1125
+ value.sbom.documentSha256,
1126
+ "catalogAuthority.remoteArtifactEvidence.sbom.documentSha256",
1127
+ ),
1128
+ bytes: boundedBytes(
1129
+ value.sbom.bytes,
1130
+ 16 * 1024 * 1024,
1131
+ "catalogAuthority.remoteArtifactEvidence.sbom.bytes",
1132
+ ),
1133
+ fromCache: value.sbom.fromCache === true,
1134
+ }
1135
+ : null;
1136
+ if (!signature && !sbom) {
1137
+ throw new Error(
1138
+ "catalogAuthority.remoteArtifactEvidence must bind at least one artifact",
1139
+ );
1140
+ }
1141
+ if (sbom && sbom.expectedDocumentSha256 !== sbom.documentSha256) {
1142
+ throw new Error(
1143
+ "catalogAuthority.remoteArtifactEvidence SBOM digest is not verified",
1144
+ );
1145
+ }
1146
+ const claims = {
1147
+ publisherIdentityVerified: value.claims?.publisherIdentityVerified === true,
1148
+ signatureBytesFetched: value.claims?.signatureBytesFetched === true,
1149
+ publicKeyFingerprintVerified:
1150
+ value.claims?.publicKeyFingerprintVerified === true,
1151
+ manifestSignatureVerified: value.claims?.manifestSignatureVerified === true,
1152
+ sbomDocumentDigestVerified:
1153
+ value.claims?.sbomDocumentDigestVerified === true,
1154
+ sbomPayloadCompared: value.claims?.sbomPayloadCompared === true,
1155
+ };
1156
+ if (claims.publisherIdentityVerified || claims.manifestSignatureVerified) {
1157
+ throw new Error(
1158
+ "remote artifact fetch evidence cannot assert publisher identity or manifest verification",
1159
+ );
1160
+ }
1161
+ if (
1162
+ (!signature &&
1163
+ (claims.signatureBytesFetched || claims.publicKeyFingerprintVerified)) ||
1164
+ (!sbom && claims.sbomDocumentDigestVerified) ||
1165
+ claims.sbomPayloadCompared
1166
+ ) {
1167
+ throw new Error(
1168
+ "remote artifact fetch evidence claims do not match the recorded artifacts",
1169
+ );
1170
+ }
1171
+ if (
1172
+ signature &&
1173
+ (!claims.signatureBytesFetched || !claims.publicKeyFingerprintVerified)
1174
+ ) {
1175
+ throw new Error(
1176
+ "remote signature artifact evidence is missing verification claims",
1177
+ );
1178
+ }
1179
+ if (sbom && !claims.sbomDocumentDigestVerified) {
1180
+ throw new Error(
1181
+ "remote SBOM artifact evidence is missing digest verification",
1182
+ );
1183
+ }
1184
+ if (value.status !== "verified") {
1185
+ throw new Error(
1186
+ "catalogAuthority.remoteArtifactEvidence.status must be verified",
1187
+ );
1188
+ }
1189
+ const authority = {
1190
+ schemaVersion: "cc-plugin-marketplace-remote-artifact-evidence/v1",
1191
+ status: "verified",
1192
+ registryOrigin: normalizeRegistryOrigin(value.registryOrigin),
1193
+ signature,
1194
+ sbom,
1195
+ claims,
1196
+ };
1197
+ const evidenceDigest = digest(
1198
+ value.evidenceDigest,
1199
+ "catalogAuthority.remoteArtifactEvidence.evidenceDigest",
1200
+ );
1201
+ const actualDigest = crypto
1202
+ .createHash("sha256")
1203
+ .update(canonicalJson(authority))
1204
+ .digest("hex");
1205
+ if (evidenceDigest !== actualDigest) {
1206
+ throw new Error(
1207
+ "catalogAuthority.remoteArtifactEvidence.evidenceDigest does not match its authority",
1208
+ );
1209
+ }
1210
+ return { ...authority, evidenceDigest };
1211
+ }
1212
+
749
1213
  function sanitizeSource(value, preservePath = false) {
750
1214
  const raw = cleanBounded(value, 4096);
751
1215
  if (!raw) return null;
@@ -768,6 +1232,32 @@ function cleanBounded(value, max) {
768
1232
  return clean ? clean.slice(0, max) : null;
769
1233
  }
770
1234
 
1235
+ function canonicalJson(value) {
1236
+ if (value == null || typeof value !== "object") return JSON.stringify(value);
1237
+ if (Array.isArray(value)) {
1238
+ return `[${value.map((item) => canonicalJson(item)).join(",")}]`;
1239
+ }
1240
+ return `{${Object.keys(value)
1241
+ .sort()
1242
+ .map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`)
1243
+ .join(",")}}`;
1244
+ }
1245
+
1246
+ function assertExpectedPluginIdentity(name, version, expectedIdentity) {
1247
+ const expectedName = cleanBounded(expectedIdentity?.name, 256);
1248
+ const expectedVersion = cleanBounded(expectedIdentity?.version, 128);
1249
+ if (expectedName && name !== expectedName) {
1250
+ throw new Error(
1251
+ `plugin identity mismatch: registry selected ${expectedName}, fetched manifest declares ${name}`,
1252
+ );
1253
+ }
1254
+ if (expectedVersion && version !== expectedVersion) {
1255
+ throw new Error(
1256
+ `plugin version mismatch: registry selected ${expectedVersion}, fetched manifest declares ${version}`,
1257
+ );
1258
+ }
1259
+ }
1260
+
771
1261
  // ── guarded recursive copy ────────────────────────────────────────────────
772
1262
 
773
1263
  /**
@@ -801,13 +1291,24 @@ function validateStagedInstall(root, { name, version, verification }) {
801
1291
  : "";
802
1292
  throw new Error(`staged plugin failed load validation${details}`);
803
1293
  }
804
- if (verification) {
1294
+ if (verification?.signatureVerified === true) {
805
1295
  const signature = verifyInstalledSignature({ root });
806
1296
  if (!signature.signed) {
807
1297
  throw new Error(
808
1298
  `staged plugin failed signature/SBOM validation: ${signature.reason || "unknown error"}`,
809
1299
  );
810
1300
  }
1301
+ } else if (verification?.sha256) {
1302
+ try {
1303
+ verifyPluginManifest({
1304
+ manifestFile: parsed.manifestPath,
1305
+ expectedSha256: verification.sha256,
1306
+ });
1307
+ } catch (error) {
1308
+ throw new Error(
1309
+ `staged plugin failed manifest digest validation: ${error.message}`,
1310
+ );
1311
+ }
811
1312
  }
812
1313
  }
813
1314