chainlesschain 0.162.148 → 0.162.150

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 (322) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/assets/web-panel/.build-hash +1 -1
  4. package/src/assets/web-panel/assets/{AIOps-DwpCCp64.js → AIOps-CBLvrjeG.js} +1 -1
  5. package/src/assets/web-panel/assets/{ActionButton-C9pBYocA.js → ActionButton-DYv2GtE0.js} +1 -1
  6. package/src/assets/web-panel/assets/{Analytics-BWAkeXxK.js → Analytics-CL6PZ-Ww.js} +3 -3
  7. package/src/assets/web-panel/assets/{AppLayout-CivFGH6B.js → AppLayout-xuyHt4uA.js} +3 -3
  8. package/src/assets/web-panel/assets/{Audit-Cm8hRpZm.js → Audit-DOvSVycq.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-DXdFMsE8.js → Backup-DMhfTswr.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-uAwSTeql.js → BaseInput-CQxDdm63.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-KU8eeJJE.js → Chat-BEeNhK2a.js} +5 -5
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-8nul8eTq.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-C6AMDkjd.js → Checkbox-CL04O-ER.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-t2moDxcO.js → Codegen-C50o-n7x.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-DCcsRRhN.js → Col-CH-bDkzs.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-DtB-8SAC.js → Community-DqAIMvSe.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-CZm8THYA.js → Compact-C43fo_my.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-LiQgC7g1.js → Compliance-BERnMrdP.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-CA8SAxht.js → Cowork-Baw3w1gp.js} +4 -4
  20. package/src/assets/web-panel/assets/{Cron-CtRaF1wD.js → Cron-BEqAHF1-.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-6-br6Hub.js → Crosschain-CvnmKwK4.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-Do2EccrL.js → DID-iMPxgVdt.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-wrXcbzGe.js → Dashboard--4SJX3YR.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-p3FsT245.js → Dropdown-BgLV6xgz.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-D95A2L8q.js → EmailListRenderer-Bvb8oUD8.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-cLuJW2zo.js → FamilyGuardDashboard-DpXPjJB5.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-Brgq_cbN.js → Federation-BbFfJ1Xi.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-DWLCkNgh.js → FormItemContext-DeGq1B-q.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-BBqUfQd6.js → GenericCardRenderer-CNW7s9zM.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-8F090w4I.js → Git-L1PjW-lT.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-CCogEbxb.js → Governance-PK-X58to.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-CfLD7v7C.js → Inference-BePWEH-d.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DDuHJewd.js → KnowledgeGraph-LF_sBvdL.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-CE8KSEVC.js → Logs-BKkfk9hy.js} +2 -2
  35. package/src/assets/web-panel/assets/{Marketplace-DmwpZmhT.js → Marketplace-BNMqUDla.js} +1 -1
  36. package/src/assets/web-panel/assets/{McpTools-Bf7AazU8.js → McpTools-w4WPiyz2.js} +5 -5
  37. package/src/assets/web-panel/assets/{Memory-D0QU_00S.js → Memory-DUKMVGNi.js} +2 -2
  38. package/src/assets/web-panel/assets/{MobileBridge-yXS9xdhx.js → MobileBridge-BWhiEyTJ.js} +1 -1
  39. package/src/assets/web-panel/assets/{MobileProjects-BuDUoGUP.js → MobileProjects-Ocf5JEkX.js} +1 -1
  40. package/src/assets/web-panel/assets/{Mtc-BYyHy28p.js → Mtc-D2B6MMhU.js} +4 -4
  41. package/src/assets/web-panel/assets/{MtcAudit-CK0aqpiZ.js → MtcAudit-DdYjCq1O.js} +4 -4
  42. package/src/assets/web-panel/assets/{Multisig-mNimKYeb.js → Multisig-Cb1hfuUZ.js} +3 -3
  43. package/src/assets/web-panel/assets/{NLProgramming-AioAJ0YA.js → NLProgramming-CTeImGp7.js} +1 -1
  44. package/src/assets/web-panel/assets/{Notes-CVVNCLHE.js → Notes-BjYNc7eQ.js} +4 -4
  45. package/src/assets/web-panel/assets/{NotificationSettings-C4ABj-TK.js → NotificationSettings-Dn_NtRXQ.js} +1 -1
  46. package/src/assets/web-panel/assets/{OrderTableRenderer-DIp8Xcbd.js → OrderTableRenderer-DVYYIizh.js} +1 -1
  47. package/src/assets/web-panel/assets/{Organization-uozl_gWK.js → Organization-Be2Kmr5j.js} +4 -4
  48. package/src/assets/web-panel/assets/{Overflow-BCZOM2hK.js → Overflow-Cu_-qRlR.js} +1 -1
  49. package/src/assets/web-panel/assets/{P2P-CArcaiaj.js → P2P-DD2HoGzE.js} +2 -2
  50. package/src/assets/web-panel/assets/{PdhVaultBrowser-Sgq2Srr8.js → PdhVaultBrowser-BRI7DVth.js} +3 -3
  51. package/src/assets/web-panel/assets/{Permissions-BYrQrXnH.js → Permissions-C9Srcs2M.js} +4 -4
  52. package/src/assets/web-panel/assets/{PersonalDataHub-BzHStAbz.js → PersonalDataHub-CUqcMgo1.js} +3 -3
  53. package/src/assets/web-panel/assets/{Pipeline-k7KqxX1M.js → Pipeline-HBrQGLXt.js} +1 -1
  54. package/src/assets/web-panel/assets/{Privacy-IumTUWqx.js → Privacy-D-B0vjwh.js} +1 -1
  55. package/src/assets/web-panel/assets/{ProjectInit-BRyImYTf.js → ProjectInit-eTeLIu9e.js} +2 -2
  56. package/src/assets/web-panel/assets/{ProjectSettings-BFIqTBFk.js → ProjectSettings-DrRqCsC6.js} +2 -2
  57. package/src/assets/web-panel/assets/{Projects-Dpid9CDg.js → Projects-1G9DNOhI.js} +1 -1
  58. package/src/assets/web-panel/assets/{Providers-CyyFnUPs.js → Providers-RkTZzpxP.js} +1 -1
  59. package/src/assets/web-panel/assets/{QrScannerModal-C82cRx-X.js → QrScannerModal-BSCUgsgC.js} +1 -1
  60. package/src/assets/web-panel/assets/{QuickAsk-DGxDF521.js → QuickAsk-CHgyM3Bz.js} +1 -1
  61. package/src/assets/web-panel/assets/{Recommend-Cns-Am1y.js → Recommend-0lry4OZq.js} +1 -1
  62. package/src/assets/web-panel/assets/{RemoteSession-R7OqAIlg.js → RemoteSession-Cn45UroZ.js} +2 -2
  63. package/src/assets/web-panel/assets/{Reputation-D7mgPIYV.js → Reputation-Q-Zjb707.js} +1 -1
  64. package/src/assets/web-panel/assets/{Row-B3lEURyd.js → Row-BdM70oda.js} +1 -1
  65. package/src/assets/web-panel/assets/{RssFeed-9_UVrpBt.js → RssFeed-DmOAKKap.js} +2 -2
  66. package/src/assets/web-panel/assets/{Search-ClZeO80q.js → Search-Dwavbm07.js} +1 -1
  67. package/src/assets/web-panel/assets/{Security-BNNJczEp.js → Security-DukXFCnk.js} +3 -3
  68. package/src/assets/web-panel/assets/{Services-C5SjrWUj.js → Services-BIlRnITu.js} +2 -2
  69. package/src/assets/web-panel/assets/{Skeleton-Ci_obQ-g.js → Skeleton-YYVQdhhQ.js} +1 -1
  70. package/src/assets/web-panel/assets/{Skills-DdebN15P.js → Skills-B8_iYHz2.js} +1 -1
  71. package/src/assets/web-panel/assets/{Sla-OinZP2vi.js → Sla-BdVrhT31.js} +1 -1
  72. package/src/assets/web-panel/assets/{SpeechSettings-CxzbNF51.js → SpeechSettings-CD3ggRx7.js} +1 -1
  73. package/src/assets/web-panel/assets/{SyncSettings-D06N_66b.js → SyncSettings-Bp02VZFH.js} +2 -2
  74. package/src/assets/web-panel/assets/{Tasks-BdEdW0AZ.js → Tasks-DEVmCEsr.js} +1 -1
  75. package/src/assets/web-panel/assets/{Templates-F1ctKmPa.js → Templates-B6czWc4N.js} +1 -1
  76. package/src/assets/web-panel/assets/{Tenant-CVz1Urot.js → Tenant-BCJLv17r.js} +1 -1
  77. package/src/assets/web-panel/assets/Terminal-CD132d2Y.js +3 -0
  78. package/src/assets/web-panel/assets/{TimelineRenderer-Doitzjmf.js → TimelineRenderer-ZB-CvkZl.js} +1 -1
  79. package/src/assets/web-panel/assets/{Tokens-BpyVRpVA.js → Tokens-BnSY0S-s.js} +1 -1
  80. package/src/assets/web-panel/assets/{Trigger-nWhWYTbU.js → Trigger-VZw9Oy2w.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trust-DK_G-wLx.js → Trust-pZq7Hjd2.js} +1 -1
  82. package/src/assets/web-panel/assets/{UkeySign-B5yBUojO.js → UkeySign-DnQaqk4q.js} +1 -1
  83. package/src/assets/web-panel/assets/{VideoEditing-C5D51qAe.js → VideoEditing-BEUfmvJV.js} +1 -1
  84. package/src/assets/web-panel/assets/{Wallet-CLbL9K7v.js → Wallet-CoZKMXJ2.js} +4 -4
  85. package/src/assets/web-panel/assets/{WebAuthn-DZUelI3V.js → WebAuthn-CBOGVx1I.js} +5 -5
  86. package/src/assets/web-panel/assets/{WorkflowEditor-8RPxt4KW.js → WorkflowEditor-huSKn7TT.js} +1 -1
  87. package/src/assets/web-panel/assets/{chat-4N4tOA3d.js → chat-A_3w6FBO.js} +1 -1
  88. package/src/assets/web-panel/assets/{colors-zbbGVrua.js → colors-D1Bem9Oy.js} +1 -1
  89. package/src/assets/web-panel/assets/{compact-item-D7iMkbnE.js → compact-item-CJYJj0oO.js} +1 -1
  90. package/src/assets/web-panel/assets/{createContext-CBzPJv-w.js → createContext-BkbFiKT4.js} +1 -1
  91. package/src/assets/web-panel/assets/devWarning-WDr3_M_N.js +1 -0
  92. package/src/assets/web-panel/assets/{hasIn-bHdrQSqZ.js → hasIn-CKvUafVY.js} +1 -1
  93. package/src/assets/web-panel/assets/{index-DbE5D0WL.js → index-AjrSPnvv.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-BCr0geV9.js → index-B8i0lViZ.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-CiG1IZao.js → index-B9Svn0zc.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-B1s0Bz9O.js → index-BHdHSX06.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-QFObYeo1.js → index-BHdailyo.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-BnBOpqv3.js → index-BJwlEnYo.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-CdmMoYN1.js → index-BOoAQjJz.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DUyjUkY7.js → index-BSgWxAOG.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-CqdPyWm5.js → index-BdutMsne.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-DmqlJed-.js → index-BiDWxzbn.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-S74FpAIn.js → index-By5a0T_W.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-kmh1TxRa.js → index-C-WIY-FQ.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BTIjjXry.js → index-C37f6iey.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-BS4_Mwk6.js → index-C9bWmTcO.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BBNr77E1.js → index-CBaosWRO.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-QNAG4JtR.js → index-CBlBVJ_m.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bqmx24kh.js → index-CD62EEGo.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CQfu1U78.js → index-CUj-l7GM.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BJ4ZGyW0.js → index-CVS8Ymuq.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-Ci009ijp.js → index-ChkXUj3f.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-oDKNgCsP.js → index-Cj0OZ-37.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BZb8F8YG.js → index-Co3OFL0t.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-308gCGh7.js → index-Crp8CbRg.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CPxkoKgA.js → index-D22zNXiS.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-xYCm6W2h.js → index-DTs_D1OL.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BtbbdLnf.js → index-DfgCdFrN.js} +3 -3
  119. package/src/assets/web-panel/assets/{index-BsKehmmS.js → index-DjYrecNb.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CkxK86vf.js → index-DpW9cf3e.js} +1 -1
  121. package/src/assets/web-panel/assets/index-Dwix3p4g.js +1 -0
  122. package/src/assets/web-panel/assets/{index-CvRMA9uT.js → index-F--HuPG1.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-DE9j5YgT.js → index-Fuk6t_3K.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-B7b1hGry.js → index-JEAGMii9.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-D1YDh7Wr.js → index-PF-mpv8K.js} +1 -1
  126. package/src/assets/web-panel/assets/index-SHaoZ0CA.js +1 -0
  127. package/src/assets/web-panel/assets/{index-CQ6NcfWz.js → index-b-sbVdjQ.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DyoNgbXl.js → index-pyvMVX8r.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DISWAYce.js → index-qNTtOVi_.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-D4XKpj6c.js → index-tgO8iza6.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-CahryTX0.js → index-ttDQVhZy.js} +1 -1
  132. package/src/assets/web-panel/assets/{initDefaultProps-BD55yNBt.js → initDefaultProps-DtrnfsZH.js} +1 -1
  133. package/src/assets/web-panel/assets/{motion-B5Bbe77U.js → motion-D4zqSaX3.js} +1 -1
  134. package/src/assets/web-panel/assets/{move-CTvIqHEH.js → move-CGFGOUQj.js} +1 -1
  135. package/src/assets/web-panel/assets/{mtc-parser-BkNyPQKB.js → mtc-parser-DH2HvkJl.js} +1 -1
  136. package/src/assets/web-panel/assets/{omit-BaXJXgHA.js → omit-jJ2at5HX.js} +1 -1
  137. package/src/assets/web-panel/assets/{pickAttrs-Bw6-YTxH.js → pickAttrs-CRyMT1Fv.js} +1 -1
  138. package/src/assets/web-panel/assets/{placementArrow-BLdbkLqJ.js → placementArrow-DZ_CX0Pt.js} +1 -1
  139. package/src/assets/web-panel/assets/{responsiveObserve-IVYkzntU.js → responsiveObserve-wruHk-h5.js} +1 -1
  140. package/src/assets/web-panel/assets/{slide-DFMFwwtY.js → slide-BGgx8q67.js} +1 -1
  141. package/src/assets/web-panel/assets/{statusUtils-CURYRtZ1.js → statusUtils-Do5M7gKm.js} +1 -1
  142. package/src/assets/web-panel/assets/{styleChecker-Cfz63s1r.js → styleChecker-CRa-GZpX.js} +1 -1
  143. package/src/assets/web-panel/assets/{useFlexGapSupport-COJL0KE3.js → useFlexGapSupport-BxPcq6pj.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFs-YLLojQQf.js → useFs-v5O2ZcJm.js} +1 -1
  145. package/src/assets/web-panel/assets/{usePersonalDataHub-BF_21qUC.js → usePersonalDataHub--z2FU0Px.js} +1 -1
  146. package/src/assets/web-panel/assets/{vnode-9ZpkA7bb.js → vnode-1emidVKd.js} +1 -1
  147. package/src/assets/web-panel/assets/{zoom-DhtAfhl8.js → zoom-CcJaRyHs.js} +1 -1
  148. package/src/assets/web-panel/index.html +1 -1
  149. package/src/assets/web-panel/remote-session-sw.js +43 -0
  150. package/src/command-manifest.json +22 -1
  151. package/src/commands/a2a.js +19 -4
  152. package/src/commands/activitypub.js +20 -3
  153. package/src/commands/agent.js +71 -10
  154. package/src/commands/audit.js +40 -24
  155. package/src/commands/codeintel.js +320 -0
  156. package/src/commands/collab.js +15 -2
  157. package/src/commands/compliance.js +5 -0
  158. package/src/commands/config.js +4 -1
  159. package/src/commands/dao.js +86 -14
  160. package/src/commands/dev.js +2 -0
  161. package/src/commands/did.js +7 -1
  162. package/src/commands/dlp.js +23 -1
  163. package/src/commands/economy.js +29 -3
  164. package/src/commands/eval.js +255 -0
  165. package/src/commands/evomap.js +26 -0
  166. package/src/commands/governance.js +17 -3
  167. package/src/commands/hardening.js +18 -0
  168. package/src/commands/incentive.js +5 -0
  169. package/src/commands/init.js +46 -2
  170. package/src/commands/kg.js +4 -0
  171. package/src/commands/loop.js +6 -1
  172. package/src/commands/lowcode.js +15 -2
  173. package/src/commands/marketplace.js +40 -6
  174. package/src/commands/matrix.js +20 -1
  175. package/src/commands/memory.js +4 -1
  176. package/src/commands/mtc.js +7 -1
  177. package/src/commands/nostr.js +31 -4
  178. package/src/commands/note.js +7 -4
  179. package/src/commands/plugin.js +474 -0
  180. package/src/commands/pqc.js +5 -0
  181. package/src/commands/reputation.js +10 -1
  182. package/src/commands/scim.js +6 -0
  183. package/src/commands/session.js +32 -10
  184. package/src/commands/siem.js +11 -0
  185. package/src/commands/sla.js +18 -3
  186. package/src/commands/social.js +38 -5
  187. package/src/commands/sso.js +10 -2
  188. package/src/commands/stress.js +23 -4
  189. package/src/commands/team.js +463 -0
  190. package/src/commands/tech.js +2 -0
  191. package/src/commands/tenant.js +10 -1
  192. package/src/commands/terraform.js +6 -0
  193. package/src/commands/update.js +1 -1
  194. package/src/commands/zkp.js +20 -0
  195. package/src/gateways/ws/message-dispatcher.js +48 -2
  196. package/src/gateways/ws/remote-session-protocol.js +140 -42
  197. package/src/gateways/ws/ws-server.js +1 -1
  198. package/src/harness/jsonl-session-store.js +12 -5
  199. package/src/harness/plugin-manager.js +16 -4
  200. package/src/harness/prompt-compressor.js +27 -1
  201. package/src/harness/remote-command-ledger.js +189 -0
  202. package/src/harness/remote-session-push-apns.js +246 -0
  203. package/src/harness/remote-session-push-errors.js +15 -0
  204. package/src/harness/remote-session-push-fcm.js +9 -25
  205. package/src/harness/remote-session-push-huawei.js +174 -0
  206. package/src/harness/remote-session-push-oppo.js +171 -0
  207. package/src/harness/remote-session-push-senders.js +42 -0
  208. package/src/harness/remote-session-push-vivo.js +179 -0
  209. package/src/harness/remote-session-push-web.js +299 -0
  210. package/src/harness/remote-session-push-xiaomi.js +99 -0
  211. package/src/harness/worktree-isolator.js +16 -6
  212. package/src/index.js +6 -0
  213. package/src/lib/__tests__/logger.test.js +5 -2
  214. package/src/lib/a2a-protocol.js +25 -1
  215. package/src/lib/activitypub-bridge.js +61 -0
  216. package/src/lib/agent-core.js +4 -0
  217. package/src/lib/agent-economy.js +262 -29
  218. package/src/lib/agent-network.js +7 -1
  219. package/src/lib/agent-sandbox.js +161 -5
  220. package/src/lib/agent-team/task-lease.js +434 -0
  221. package/src/lib/agent-team/team-budget.js +165 -0
  222. package/src/lib/agent-team/team-mailbox.js +106 -0
  223. package/src/lib/agent-team/team-runner.js +282 -0
  224. package/src/lib/agent-team/team-worktree.js +236 -0
  225. package/src/lib/agents.js +18 -0
  226. package/src/lib/async-hook-supervisor.cjs +391 -0
  227. package/src/lib/audit-logger.js +7 -6
  228. package/src/lib/autonomous-developer.js +60 -0
  229. package/src/lib/chat-core.js +17 -4
  230. package/src/lib/collaboration-governance.js +56 -0
  231. package/src/lib/community-governance.js +68 -0
  232. package/src/lib/compliance-manager.js +63 -0
  233. package/src/lib/cross-chain.js +5 -0
  234. package/src/lib/dao-governance.js +151 -2
  235. package/src/lib/did-manager.js +23 -10
  236. package/src/lib/dlp-engine.js +70 -0
  237. package/src/lib/eval/runner.js +251 -0
  238. package/src/lib/eval/tasks.js +626 -0
  239. package/src/lib/eval/trend.js +200 -0
  240. package/src/lib/evolution-system.js +92 -0
  241. package/src/lib/evomap-federation.js +55 -0
  242. package/src/lib/evomap-governance.js +94 -0
  243. package/src/lib/fatal-handler.js +17 -1
  244. package/src/lib/hardening-manager.js +73 -0
  245. package/src/lib/hierarchical-memory.js +14 -8
  246. package/src/lib/knowledge-exporter.js +8 -2
  247. package/src/lib/knowledge-graph.js +79 -0
  248. package/src/lib/llm-providers.js +23 -14
  249. package/src/lib/logger.js +4 -1
  250. package/src/lib/lsp/__tests__/benchmark.test.js +88 -0
  251. package/src/lib/lsp/__tests__/code-intelligence.integration.test.js +129 -0
  252. package/src/lib/lsp/__tests__/code-intelligence.test.js +228 -0
  253. package/src/lib/lsp/__tests__/jsonrpc-stream.test.js +104 -0
  254. package/src/lib/lsp/__tests__/lsp-client.test.js +269 -0
  255. package/src/lib/lsp/__tests__/lsp-manager.test.js +333 -0
  256. package/src/lib/lsp/__tests__/lsp-server-registry.test.js +128 -0
  257. package/src/lib/lsp/benchmark.js +257 -0
  258. package/src/lib/lsp/code-intelligence.js +356 -0
  259. package/src/lib/lsp/jsonrpc-stream.js +139 -0
  260. package/src/lib/lsp/lsp-client.js +339 -0
  261. package/src/lib/lsp/lsp-manager.js +375 -0
  262. package/src/lib/lsp/lsp-server-registry.js +196 -0
  263. package/src/lib/matrix-bridge.js +84 -0
  264. package/src/lib/memory-manager.js +5 -3
  265. package/src/lib/nostr-bridge.js +53 -0
  266. package/src/lib/permission-engine.js +22 -4
  267. package/src/lib/plugin-monitor-supervisor.js +238 -0
  268. package/src/lib/plugin-runtime/__tests__/remote-source.test.js +256 -0
  269. package/src/lib/plugin-runtime/agents.js +51 -0
  270. package/src/lib/plugin-runtime/bin.js +100 -0
  271. package/src/lib/plugin-runtime/hooks.js +100 -0
  272. package/src/lib/plugin-runtime/install.js +396 -0
  273. package/src/lib/plugin-runtime/lsp.js +75 -0
  274. package/src/lib/plugin-runtime/manifest.js +458 -0
  275. package/src/lib/plugin-runtime/mcp.js +89 -0
  276. package/src/lib/plugin-runtime/monitors.js +100 -0
  277. package/src/lib/plugin-runtime/policy.js +152 -0
  278. package/src/lib/plugin-runtime/reload.js +79 -0
  279. package/src/lib/plugin-runtime/remote-source.js +240 -0
  280. package/src/lib/plugin-runtime/scopes.js +197 -0
  281. package/src/lib/plugin-runtime/settings.js +119 -0
  282. package/src/lib/plugin-runtime/signature.js +107 -0
  283. package/src/lib/plugin-runtime/skills.js +43 -0
  284. package/src/lib/plugin-runtime/trust.js +140 -0
  285. package/src/lib/pqc-manager.js +64 -0
  286. package/src/lib/reputation-optimizer.js +101 -0
  287. package/src/lib/sandbox-egress-proxy.js +262 -0
  288. package/src/lib/sandbox-fs-policy.js +112 -0
  289. package/src/lib/sandbox-network-policy.js +151 -0
  290. package/src/lib/sandbox-v2.js +24 -18
  291. package/src/lib/scim-manager.js +36 -0
  292. package/src/lib/session-manager.js +5 -2
  293. package/src/lib/settings-hook-events.cjs +78 -6
  294. package/src/lib/settings-hooks.cjs +30 -3
  295. package/src/lib/settings-loader.cjs +35 -1
  296. package/src/lib/siem-exporter.js +45 -0
  297. package/src/lib/skill-loader.js +38 -2
  298. package/src/lib/skill-marketplace.js +83 -0
  299. package/src/lib/sla-manager.js +88 -0
  300. package/src/lib/social-manager.js +74 -0
  301. package/src/lib/stress-tester.js +65 -0
  302. package/src/lib/tech-learning-engine.js +75 -0
  303. package/src/lib/telemetry/span-recorder.js +237 -0
  304. package/src/lib/tenant-saas.js +107 -0
  305. package/src/lib/terraform-manager.js +67 -0
  306. package/src/lib/token-incentive.js +180 -29
  307. package/src/lib/wallet-manager.js +81 -35
  308. package/src/lib/zkp-engine.js +87 -0
  309. package/src/repl/agent-repl.js +417 -6
  310. package/src/runtime/__tests__/auto-pin.test.js +104 -0
  311. package/src/runtime/agent-core.js +771 -104
  312. package/src/runtime/auto-pin.js +117 -0
  313. package/src/runtime/coding-agent-contract-shared.cjs +82 -8
  314. package/src/runtime/coding-agent-policy.cjs +32 -7
  315. package/src/runtime/fallback-model.js +134 -7
  316. package/src/runtime/headless-runner.js +388 -108
  317. package/src/runtime/mcp-config.js +46 -0
  318. package/src/assets/web-panel/assets/ChatBubbleRenderer-DCNfbdlx.js +0 -1
  319. package/src/assets/web-panel/assets/Terminal-BvAK_Zel.js +0 -3
  320. package/src/assets/web-panel/assets/devWarning-C2Z5LRgq.js +0 -1
  321. package/src/assets/web-panel/assets/index-BGp6Yr-Y.js +0 -1
  322. package/src/assets/web-panel/assets/index-BXiw9dQf.js +0 -1
@@ -59,6 +59,59 @@ export function ensureNostrTables(db) {
59
59
  `);
60
60
  }
61
61
 
62
+ /**
63
+ * Rehydrate the module-level _relays/_events Maps from the persisted
64
+ * nostr_relays/nostr_events tables. The `cc` CLI runs every command in a
65
+ * fresh process, so without this the Maps are empty on read and a relay/event
66
+ * added in a prior invocation is invisible (`cc nostr relays`/`events` show
67
+ * nothing; `dm-decrypt` can't find the DM). Call after ensureNostrTables(db).
68
+ * (_keypairs/_didMappings are intentionally ephemeral — no DB table.)
69
+ */
70
+ export function loadFromDb(db) {
71
+ if (!db) return 0;
72
+ _relays.clear();
73
+ _events.clear();
74
+
75
+ const relayRows = db.prepare(`SELECT * FROM nostr_relays`).all();
76
+ for (const row of relayRows) {
77
+ _relays.set(row.id, {
78
+ id: row.id,
79
+ url: row.url,
80
+ status: row.status,
81
+ lastConnected: row.last_connected ?? null,
82
+ eventCount: row.event_count ?? 0,
83
+ readEnabled: !!row.read_enabled,
84
+ writeEnabled: !!row.write_enabled,
85
+ });
86
+ }
87
+
88
+ const eventRows = db.prepare(`SELECT * FROM nostr_events`).all();
89
+ for (const row of eventRows) {
90
+ let tags = [];
91
+ try {
92
+ tags = row.tags ? JSON.parse(row.tags) : [];
93
+ } catch {
94
+ tags = [];
95
+ }
96
+ _events.set(row.id, {
97
+ id: row.id,
98
+ pubkey: row.pubkey,
99
+ kind: row.kind,
100
+ content: row.content,
101
+ tags,
102
+ sig: row.sig ?? "",
103
+ // write side stores createdAt as unix seconds; the column is an ISO
104
+ // string — convert back so the two process paths agree.
105
+ createdAt: row.created_at
106
+ ? Math.floor(new Date(row.created_at).getTime() / 1000)
107
+ : null,
108
+ relayUrl: row.relay_url ?? null,
109
+ });
110
+ }
111
+
112
+ return _relays.size + _events.size;
113
+ }
114
+
62
115
  /* ── Relay Management ─────────────────────────────────────── */
63
116
 
64
117
  export function listRelays() {
@@ -275,6 +275,24 @@ export function revokePermission(db, userDid, permission) {
275
275
  return result.changes > 0;
276
276
  }
277
277
 
278
+ /**
279
+ * Is a grant still active given its stored `expires_at`?
280
+ *
281
+ * The previous check compared `expires_at > now` as ISO STRINGS. That is
282
+ * fail-open on unvalidated input: an unpadded date ("2026-7-5") or any
283
+ * non-numeric-leading garbage ("next year") sorts lexicographically AFTER a
284
+ * canonical `now` ('7'/'n' > '0'/'2'), so an already-expired or malformed
285
+ * time-limited grant silently became a PERMANENT grant. Compare numerically and
286
+ * treat an unparseable expiry as expired (fail closed) so a typo can never widen
287
+ * access. A null/empty `expires_at` means no expiry.
288
+ */
289
+ function _grantActive(expiresAt, nowMs) {
290
+ if (!expiresAt) return true;
291
+ const t = Date.parse(expiresAt);
292
+ if (Number.isNaN(t)) return false;
293
+ return t > nowMs;
294
+ }
295
+
278
296
  /**
279
297
  * Get all roles and direct permissions for a user.
280
298
  */
@@ -287,15 +305,15 @@ export function getUserPermissions(db, userDid) {
287
305
  .all(userDid);
288
306
 
289
307
  // Filter out expired grants
290
- const now = new Date().toISOString();
291
- const grants = allGrants.filter((g) => !g.expires_at || g.expires_at > now);
308
+ const nowMs = Date.now();
309
+ const grants = allGrants.filter((g) => _grantActive(g.expires_at, nowMs));
292
310
 
293
311
  // Get direct permissions (not expired)
294
312
  const allDirectPerms = db
295
313
  .prepare("SELECT * FROM rbac_direct_permissions WHERE user_did = ?")
296
314
  .all(userDid);
297
- const directPerms = allDirectPerms.filter(
298
- (d) => !d.expires_at || d.expires_at > now,
315
+ const directPerms = allDirectPerms.filter((d) =>
316
+ _grantActive(d.expires_at, nowMs),
299
317
  );
300
318
 
301
319
  // Collect all permissions by looking up each role
@@ -0,0 +1,238 @@
1
+ /**
2
+ * PluginMonitorSupervisor — runs installed plugins' background monitors
3
+ * (Phase 3.3i / Phase 6 down payment). Two modes:
4
+ *
5
+ * - longRunning: spawn the command ONCE and keep it alive (e.g. `tail -f`).
6
+ * - interval: re-run the command every `intervalMs`, capturing each run's
7
+ * output (e.g. a periodic health/log check).
8
+ *
9
+ * Captured stdout/stderr lines are buffered as structured records; the agent
10
+ * loop can `drainOutputs()` them and inject them into the next turn's context
11
+ * (Phase 6: "后台结果可在下一轮注入 additionalContext"). The supervisor owns
12
+ * its children and reaps ALL of them on `stopAll()` plus a `process.once('exit')`
13
+ * backstop, so no monitor process leaks past session end.
14
+ *
15
+ * Guardrails (Phase 6 "去重、并发上限、超时、进程回收"): a per-monitor id
16
+ * dedupes double-starts, `maxConcurrent` caps simultaneous interval runs, and
17
+ * `timeoutMs` kills a hung interval run. Commands run with shell:false (argv,
18
+ * never a shell string) — no injection.
19
+ *
20
+ * spawn is injected via `_deps` so the whole thing is unit-testable without
21
+ * real processes.
22
+ */
23
+
24
+ import { spawn } from "node:child_process";
25
+
26
+ export const _deps = { spawn };
27
+
28
+ const DEFAULT_INTERVAL_MS = 60_000;
29
+ const DEFAULT_TIMEOUT_MS = 30_000;
30
+ const DEFAULT_MAX_CONCURRENT = 8;
31
+ const OUTPUT_RING = 200; // max buffered output records before dropping oldest
32
+
33
+ export class PluginMonitorSupervisor {
34
+ constructor(opts = {}) {
35
+ this.maxConcurrent = opts.maxConcurrent || DEFAULT_MAX_CONCURRENT;
36
+ this.defaultIntervalMs = opts.defaultIntervalMs || DEFAULT_INTERVAL_MS;
37
+ this.timeoutMs = opts.timeoutMs || DEFAULT_TIMEOUT_MS;
38
+ this._spawn = opts.spawn || _deps.spawn;
39
+ // id -> { desc, timer?, child?, running }
40
+ this._monitors = new Map();
41
+ this._outputs = []; // structured records awaiting drain
42
+ this._runningIntervalRuns = 0;
43
+ this._stopped = false;
44
+ this._exitHook = () => this.stopAll();
45
+ this._exitHookInstalled = false;
46
+ }
47
+
48
+ /** True when at least one monitor is registered and not stopped. */
49
+ get size() {
50
+ return this._monitors.size;
51
+ }
52
+
53
+ /**
54
+ * Start a batch of monitor descriptors (from collectPluginMonitors). Skips a
55
+ * monitor whose id is already running (dedupe). Returns the ids started.
56
+ * @param {Array<object>} monitors
57
+ * @returns {string[]} ids actually started
58
+ */
59
+ start(monitors = []) {
60
+ if (this._stopped) return [];
61
+ const started = [];
62
+ for (const desc of monitors) {
63
+ if (!desc || !desc.id) continue;
64
+ if (this._monitors.has(desc.id)) continue; // dedupe double-start
65
+ const entry = { desc, timer: null, child: null, running: false };
66
+ this._monitors.set(desc.id, entry);
67
+ if (desc.mode === "longRunning") {
68
+ this._spawnLongRunning(entry);
69
+ } else {
70
+ // interval: run once immediately, then on a cadence.
71
+ const ms = desc.intervalMs || this.defaultIntervalMs;
72
+ this._runIntervalOnce(entry);
73
+ entry.timer = setInterval(() => this._runIntervalOnce(entry), ms);
74
+ if (typeof entry.timer.unref === "function") entry.timer.unref();
75
+ }
76
+ started.push(desc.id);
77
+ }
78
+ if (started.length > 0) this._installExitHook();
79
+ return started;
80
+ }
81
+
82
+ _installExitHook() {
83
+ if (this._exitHookInstalled) return;
84
+ this._exitHookInstalled = true;
85
+ // Backstop: if the caller forgets stopAll(), reap on process exit so no
86
+ // monitor process outlives the session.
87
+ process.once("exit", this._exitHook);
88
+ }
89
+
90
+ _record(desc, stream, text) {
91
+ const lines = String(text)
92
+ .split(/\r?\n/)
93
+ .filter((l) => l.length > 0);
94
+ for (const line of lines) {
95
+ this._outputs.push({
96
+ id: desc.id,
97
+ plugin: desc.plugin,
98
+ monitor: desc.name,
99
+ stream,
100
+ line,
101
+ });
102
+ if (this._outputs.length > OUTPUT_RING) this._outputs.shift();
103
+ }
104
+ }
105
+
106
+ _spawnLongRunning(entry) {
107
+ const { desc } = entry;
108
+ let child;
109
+ try {
110
+ child = this._spawn(desc.command, desc.args, {
111
+ cwd: desc.cwd,
112
+ env: desc.env ? { ...process.env, ...desc.env } : process.env,
113
+ shell: false,
114
+ stdio: ["ignore", "pipe", "pipe"],
115
+ });
116
+ } catch (err) {
117
+ this._record(desc, "error", `spawn failed: ${err.message}`);
118
+ return;
119
+ }
120
+ entry.child = child;
121
+ child.stdout?.on("data", (d) =>
122
+ this._record(desc, "stdout", d.toString("utf8")),
123
+ );
124
+ child.stderr?.on("data", (d) =>
125
+ this._record(desc, "stderr", d.toString("utf8")),
126
+ );
127
+ child.on("error", (err) => this._record(desc, "error", err.message));
128
+ child.on("exit", (code) => {
129
+ entry.child = null;
130
+ this._record(desc, "exit", `longRunning monitor exited (code ${code})`);
131
+ });
132
+ }
133
+
134
+ _runIntervalOnce(entry) {
135
+ const { desc } = entry;
136
+ if (this._stopped) return;
137
+ if (entry.running) return; // previous run still in flight — skip this tick
138
+ if (this._runningIntervalRuns >= this.maxConcurrent) return; // cap
139
+ entry.running = true;
140
+ this._runningIntervalRuns++;
141
+ let child;
142
+ try {
143
+ child = this._spawn(desc.command, desc.args, {
144
+ cwd: desc.cwd,
145
+ env: desc.env ? { ...process.env, ...desc.env } : process.env,
146
+ shell: false,
147
+ stdio: ["ignore", "pipe", "pipe"],
148
+ });
149
+ } catch (err) {
150
+ this._record(desc, "error", `spawn failed: ${err.message}`);
151
+ entry.running = false;
152
+ this._runningIntervalRuns--;
153
+ return;
154
+ }
155
+ entry.child = child;
156
+ let done = false;
157
+ const finish = () => {
158
+ if (done) return;
159
+ done = true;
160
+ if (killTimer) clearTimeout(killTimer);
161
+ entry.child = null;
162
+ entry.running = false;
163
+ this._runningIntervalRuns--;
164
+ };
165
+ const killTimer = setTimeout(() => {
166
+ this._record(
167
+ desc,
168
+ "error",
169
+ `interval run timed out after ${this.timeoutMs}ms`,
170
+ );
171
+ try {
172
+ child.kill("SIGTERM");
173
+ } catch {
174
+ /* already gone */
175
+ }
176
+ }, this.timeoutMs);
177
+ if (typeof killTimer.unref === "function") killTimer.unref();
178
+ child.stdout?.on("data", (d) =>
179
+ this._record(desc, "stdout", d.toString("utf8")),
180
+ );
181
+ child.stderr?.on("data", (d) =>
182
+ this._record(desc, "stderr", d.toString("utf8")),
183
+ );
184
+ child.on("error", (err) => {
185
+ this._record(desc, "error", err.message);
186
+ finish();
187
+ });
188
+ child.on("exit", () => finish());
189
+ }
190
+
191
+ /**
192
+ * Take and clear all buffered monitor output records (for injection into the
193
+ * next agent turn). Returns [] when nothing has been captured.
194
+ */
195
+ drainOutputs() {
196
+ const out = this._outputs;
197
+ this._outputs = [];
198
+ return out;
199
+ }
200
+
201
+ /** Peek at buffered output without clearing it. */
202
+ peekOutputs() {
203
+ return this._outputs.slice();
204
+ }
205
+
206
+ /** Ids of every registered monitor. */
207
+ ids() {
208
+ return [...this._monitors.keys()];
209
+ }
210
+
211
+ /**
212
+ * Stop and reap EVERYTHING: clear interval timers, kill all children. Safe to
213
+ * call more than once. After this, `start` is a no-op.
214
+ */
215
+ stopAll() {
216
+ this._stopped = true;
217
+ for (const entry of this._monitors.values()) {
218
+ if (entry.timer) {
219
+ clearInterval(entry.timer);
220
+ entry.timer = null;
221
+ }
222
+ if (entry.child) {
223
+ try {
224
+ entry.child.kill("SIGTERM");
225
+ } catch {
226
+ /* already gone */
227
+ }
228
+ entry.child = null;
229
+ }
230
+ }
231
+ this._monitors.clear();
232
+ this._runningIntervalRuns = 0;
233
+ if (this._exitHookInstalled) {
234
+ process.removeListener("exit", this._exitHook);
235
+ this._exitHookInstalled = false;
236
+ }
237
+ }
238
+ }
@@ -0,0 +1,256 @@
1
+ /**
2
+ * remote-source tests — resolving a plugin from a hosted registry/manifest URL,
3
+ * with private-token auth and an offline cache. `fetch` and fs are injected via
4
+ * `_deps` so nothing hits the network or the real disk.
5
+ */
6
+
7
+ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
8
+ import {
9
+ isRemoteSource,
10
+ validateRegistry,
11
+ resolvePluginEntry,
12
+ listRegistryPlugins,
13
+ resolveRegistryToken,
14
+ fetchRegistry,
15
+ resolveRemoteSource,
16
+ registryCachePath,
17
+ _deps,
18
+ } from "../remote-source.js";
19
+
20
+ const REGISTRY = {
21
+ name: "acme",
22
+ plugins: [
23
+ {
24
+ name: "toml-tools",
25
+ source: "https://github.com/x/toml.git",
26
+ ref: "v1.0.0",
27
+ version: "1.0.0",
28
+ description: "TOML LSP",
29
+ sha256: "abc123",
30
+ },
31
+ { name: "py-helpers", source: "owner/py-helpers" },
32
+ ],
33
+ };
34
+
35
+ /** A fake in-memory fs + fetch wired into _deps. */
36
+ function install(fakes = {}) {
37
+ const files = new Map(fakes.files || []);
38
+ _deps.existsSync = (p) => files.has(String(p));
39
+ _deps.readFileSync = (p) => {
40
+ if (!files.has(String(p))) throw new Error("ENOENT");
41
+ return files.get(String(p));
42
+ };
43
+ _deps.writeFileSync = (p, text) => files.set(String(p), text);
44
+ _deps.mkdirSync = () => {};
45
+ if (fakes.fetch) _deps.fetch = fakes.fetch;
46
+ return files;
47
+ }
48
+
49
+ /** Build a fetch that returns JSON once, then throws (to test caching). */
50
+ function okThenOffline(body) {
51
+ let calls = 0;
52
+ return vi.fn(async () => {
53
+ calls++;
54
+ if (calls === 1) {
55
+ return { ok: true, status: 200, text: async () => JSON.stringify(body) };
56
+ }
57
+ throw new Error("ECONNREFUSED");
58
+ });
59
+ }
60
+
61
+ let orig;
62
+ beforeEach(() => {
63
+ orig = { ..._deps };
64
+ delete process.env.CC_PLUGIN_REGISTRY_TOKEN;
65
+ });
66
+ afterEach(() => {
67
+ Object.assign(_deps, orig);
68
+ vi.restoreAllMocks();
69
+ delete process.env.CC_PLUGIN_REGISTRY_TOKEN;
70
+ });
71
+
72
+ describe("isRemoteSource", () => {
73
+ it("recognizes http(s) .json URLs", () => {
74
+ expect(isRemoteSource("https://x.com/registry.json")).toBe(true);
75
+ expect(isRemoteSource("http://x.com/a/b.json?ref=1")).toBe(true);
76
+ });
77
+ it("rejects local dirs, git URLs, and owner/repo", () => {
78
+ expect(isRemoteSource("./plugins/foo")).toBe(false);
79
+ expect(isRemoteSource("https://github.com/x/foo.git")).toBe(false);
80
+ expect(isRemoteSource("owner/repo")).toBe(false);
81
+ });
82
+ });
83
+
84
+ describe("validateRegistry", () => {
85
+ it("accepts a multi-plugin index", () => {
86
+ expect(validateRegistry(REGISTRY).plugins).toHaveLength(2);
87
+ });
88
+ it("wraps a single-plugin manifest into a one-entry registry", () => {
89
+ const r = validateRegistry({
90
+ name: "solo",
91
+ source: "owner/solo",
92
+ ref: "v2",
93
+ });
94
+ expect(r.plugins).toEqual([
95
+ { name: "solo", source: "owner/solo", ref: "v2" },
96
+ ]);
97
+ });
98
+ it("rejects garbage and entries missing name/source", () => {
99
+ expect(() => validateRegistry(null)).toThrow(/not a JSON object/);
100
+ expect(() => validateRegistry({ foo: 1 })).toThrow(
101
+ /plugins.*array.*source/,
102
+ );
103
+ expect(() => validateRegistry({ plugins: [{ name: "x" }] })).toThrow(
104
+ /missing name\/source/,
105
+ );
106
+ });
107
+ });
108
+
109
+ describe("resolvePluginEntry", () => {
110
+ it("selects by name", () => {
111
+ expect(resolvePluginEntry(REGISTRY, "py-helpers").source).toBe(
112
+ "owner/py-helpers",
113
+ );
114
+ });
115
+ it("auto-selects the sole plugin when name omitted", () => {
116
+ const solo = { plugins: [REGISTRY.plugins[0]] };
117
+ expect(resolvePluginEntry(solo).name).toBe("toml-tools");
118
+ });
119
+ it("requires a name when the registry has many", () => {
120
+ expect(() => resolvePluginEntry(REGISTRY)).toThrow(/pick one with --name/);
121
+ });
122
+ it("lists options when the name is unknown", () => {
123
+ expect(() => resolvePluginEntry(REGISTRY, "nope")).toThrow(
124
+ /not found.*toml-tools, py-helpers/s,
125
+ );
126
+ });
127
+ });
128
+
129
+ describe("resolveRegistryToken", () => {
130
+ it("prefers an explicit token, then env, then per-host config", () => {
131
+ expect(
132
+ resolveRegistryToken("https://h/r.json", { token: "explicit" }),
133
+ ).toBe("explicit");
134
+ process.env.CC_PLUGIN_REGISTRY_TOKEN = "envtok";
135
+ expect(resolveRegistryToken("https://h/r.json", {})).toBe("envtok");
136
+ delete process.env.CC_PLUGIN_REGISTRY_TOKEN;
137
+ const config = { plugins: { registryTokens: { "priv.co": "cfgtok" } } };
138
+ expect(resolveRegistryToken("https://priv.co/r.json", { config })).toBe(
139
+ "cfgtok",
140
+ );
141
+ expect(
142
+ resolveRegistryToken("https://other.co/r.json", { config }),
143
+ ).toBeNull();
144
+ });
145
+ });
146
+
147
+ describe("fetchRegistry", () => {
148
+ it("fetches, validates, and caches; sends a bearer token when given", async () => {
149
+ const fetch = vi.fn(async () => ({
150
+ ok: true,
151
+ status: 200,
152
+ text: async () => JSON.stringify(REGISTRY),
153
+ }));
154
+ install({ fetch });
155
+ const { registry, fromCache } = await fetchRegistry("https://h/r.json", {
156
+ token: "t",
157
+ cacheDir: "/cache",
158
+ });
159
+ expect(fromCache).toBe(false);
160
+ expect(registry.plugins).toHaveLength(2);
161
+ const [, init] = fetch.mock.calls[0];
162
+ expect(init.headers.Authorization).toBe("Bearer t");
163
+ });
164
+
165
+ it("falls back to the offline cache when the network fails", async () => {
166
+ const fetch = okThenOffline(REGISTRY);
167
+ install({ fetch });
168
+ // 1st call populates the cache
169
+ await fetchRegistry("https://h/r.json", { cacheDir: "/cache" });
170
+ // 2nd call: network throws → served from cache
171
+ const { registry, fromCache } = await fetchRegistry("https://h/r.json", {
172
+ cacheDir: "/cache",
173
+ });
174
+ expect(fromCache).toBe(true);
175
+ expect(registry.plugins).toHaveLength(2);
176
+ });
177
+
178
+ it("throws on HTTP error with no cache", async () => {
179
+ const fetch = vi.fn(async () => ({
180
+ ok: false,
181
+ status: 404,
182
+ statusText: "Not Found",
183
+ text: async () => "",
184
+ }));
185
+ install({ fetch });
186
+ await expect(
187
+ fetchRegistry("https://h/missing.json", { cacheDir: "/cache" }),
188
+ ).rejects.toThrow(/HTTP 404/);
189
+ });
190
+
191
+ it("throws when offline and nothing is cached", async () => {
192
+ const fetch = vi.fn(async () => {
193
+ throw new Error("ENOTFOUND");
194
+ });
195
+ install({ fetch });
196
+ await expect(
197
+ fetchRegistry("https://h/r.json", { cacheDir: "/cache" }),
198
+ ).rejects.toThrow(/no offline cache/);
199
+ });
200
+ });
201
+
202
+ describe("resolveRemoteSource", () => {
203
+ it("resolves a named entry to a git source string with a #ref and carries sha256", async () => {
204
+ const fetch = vi.fn(async () => ({
205
+ ok: true,
206
+ status: 200,
207
+ text: async () => JSON.stringify(REGISTRY),
208
+ }));
209
+ install({ fetch });
210
+ const r = await resolveRemoteSource("https://h/r.json", {
211
+ name: "toml-tools",
212
+ cacheDir: "/cache",
213
+ });
214
+ expect(r.source).toBe("https://github.com/x/toml.git#v1.0.0");
215
+ expect(r.sha256).toBe("abc123");
216
+ expect(r.fromCache).toBe(false);
217
+ });
218
+
219
+ it("omits the #ref when the entry has none", async () => {
220
+ const fetch = vi.fn(async () => ({
221
+ ok: true,
222
+ status: 200,
223
+ text: async () => JSON.stringify(REGISTRY),
224
+ }));
225
+ install({ fetch });
226
+ const r = await resolveRemoteSource("https://h/r.json", {
227
+ name: "py-helpers",
228
+ cacheDir: "/cache",
229
+ });
230
+ expect(r.source).toBe("owner/py-helpers");
231
+ expect(r.ref).toBeNull();
232
+ });
233
+ });
234
+
235
+ describe("listRegistryPlugins", () => {
236
+ it("flattens entries for display", () => {
237
+ const rows = listRegistryPlugins(REGISTRY);
238
+ expect(rows.map((r) => r.name)).toEqual(["toml-tools", "py-helpers"]);
239
+ expect(rows[0]).toMatchObject({
240
+ version: "1.0.0",
241
+ ref: "v1.0.0",
242
+ description: "TOML LSP",
243
+ });
244
+ });
245
+ });
246
+
247
+ describe("registryCachePath", () => {
248
+ it("is stable and content-addressed by URL", () => {
249
+ const a = registryCachePath("https://h/r.json", "/cache");
250
+ const b = registryCachePath("https://h/r.json", "/cache");
251
+ const c = registryCachePath("https://h/OTHER.json", "/cache");
252
+ expect(a).toBe(b);
253
+ expect(a).not.toBe(c);
254
+ expect(a.endsWith(".json")).toBe(true);
255
+ });
256
+ });
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Discover installed plugins' agent-definition directories so `discoverAgents`
3
+ * can expose them as named subagents (Phase 3.3h — plugin Agent component
4
+ * reaches the agent chain).
5
+ *
6
+ * A plugin ships subagents under `<pluginRoot>/agents/<name>.md` (the same
7
+ * markdown-with-frontmatter shape as `.claude/agents/*.md`), so each installed
8
+ * plugin's `agents/` directory becomes an extra agent-scan layer. Only plugins
9
+ * whose manifest fully validated (`manifest.ok`) contribute.
10
+ *
11
+ * NOT trust-gated: an agent definition is declarative (a system prompt + an
12
+ * optional tool ALLOW-list + model — it can only narrow, never expand,
13
+ * capability) and runs only when the user invokes it BY NAME (`cc agents run …`),
14
+ * exactly like a skill. It is never auto-executed at startup (unlike a hook), so
15
+ * it carries the same trust as a skill's SKILL.md, which is also not gated. The
16
+ * code-bearing components (hooks/LSP/MCP) remain trust-gated.
17
+ */
18
+
19
+ import fs from "fs";
20
+ import path from "path";
21
+ import { discoverPlugins } from "./scopes.js";
22
+
23
+ export const _deps = { existsSync: fs.existsSync };
24
+
25
+ /**
26
+ * @param {object} [opts] { cwd, scopes }
27
+ * @returns {Array<{ name, scope, version, dir }>} one entry per plugin that has
28
+ * an `agents/` directory; `dir` is that directory (a scan root for
29
+ * discoverAgents' walkMd).
30
+ */
31
+ export function discoverPluginAgentLayers(opts = {}) {
32
+ let plugins = [];
33
+ try {
34
+ plugins = discoverPlugins({ cwd: opts.cwd, scopes: opts.scopes });
35
+ } catch {
36
+ return [];
37
+ }
38
+ const out = [];
39
+ for (const p of plugins) {
40
+ if (!p.manifest || p.manifest.ok !== true) continue;
41
+ const agentsDir = path.join(p.root, "agents");
42
+ if (!_deps.existsSync(agentsDir)) continue;
43
+ out.push({
44
+ name: p.name,
45
+ scope: p.scope,
46
+ version: p.version,
47
+ dir: agentsDir,
48
+ });
49
+ }
50
+ return out;
51
+ }