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
@@ -0,0 +1,375 @@
1
+ /**
2
+ * LSPManager — pools language servers by (projectRoot, languageId), syncs open
3
+ * documents, translates positions, and recovers from server crashes.
4
+ *
5
+ * One `LSPClient` is expensive (spawns a process + indexes the project), so we
6
+ * lazily start and reuse one per (root, language) family. The manager owns:
7
+ * - server lifecycle (start / reuse / bounded crash-loop restart / disposeAll)
8
+ * - textDocument/didOpen + didChange (servers only answer about open docs)
9
+ * - diagnostics collection (servers push them via publishDiagnostics)
10
+ * - 1-based (user) ⇄ 0-based (LSP) position conversion, done HERE only
11
+ *
12
+ * The high-level `code-intelligence.js` calls into this; nothing above the
13
+ * manager should touch raw LSP positions/URIs.
14
+ */
15
+
16
+ import fs from "fs";
17
+ import path from "path";
18
+ import { LSPClient, pathToFileUri, normalizeUri } from "./lsp-client.js";
19
+ import { languageIdForFile, resolveServer } from "./lsp-server-registry.js";
20
+
21
+ export const _deps = {
22
+ readFileSync: fs.readFileSync,
23
+ existsSync: fs.existsSync,
24
+ createClient: (opts) => new LSPClient(opts),
25
+ };
26
+
27
+ export class LSPManager {
28
+ /**
29
+ * @param {object} [opts]
30
+ * @param {string} [opts.projectRoot] default root; per-file root inferred otherwise
31
+ * @param {number} [opts.maxRestarts] crashes within the window before a server
32
+ * is quarantined (degrade to text search) instead of re-spawned. Default 3.
33
+ * @param {number} [opts.restartWindowMs] sliding window for the crash count.
34
+ * A server that stays healthy for this long has its crash history pruned and
35
+ * can restart fresh. Default 30000.
36
+ * @param {() => number} [opts.now] injected clock (deterministic crash-loop tests)
37
+ */
38
+ constructor(opts = {}) {
39
+ this.projectRoot = opts.projectRoot || process.cwd();
40
+ /** key `${root}::${serverId}` → { client, languageId, root, restarts } */
41
+ this._servers = new Map();
42
+ /**
43
+ * key → in-flight `_startServer` promise. A server start awaits a real
44
+ * process spawn + `initialize` handshake, and the read-only agent batch
45
+ * fires several `code_intelligence` calls at once (see agent-core.js), so a
46
+ * bare Map.get(miss)→await→Map.set pool double-spawns when two callers race
47
+ * the same key: the second `_servers.set` orphans the first process (leaked
48
+ * OS process + a still-attached diagnostics listener writing stale state).
49
+ * Sharing one in-flight promise per key collapses the race to a single spawn.
50
+ */
51
+ this._starting = new Map();
52
+ /** open document uri → { version, languageId } */
53
+ this._openDocs = new Map();
54
+ /** uri → latest diagnostics array */
55
+ this._diagnostics = new Map();
56
+ /** uri → { count, at } publish bookkeeping (for settle/readiness) */
57
+ this._diagMeta = new Map();
58
+ // Crash-loop guard: a language server that dies is lazily re-spawned on the
59
+ // next request (ensureFor), but a server that crashes on startup would then
60
+ // thrash — re-spawned on EVERY request forever. Bound it: at most
61
+ // `maxRestarts` crashes inside a sliding `restartWindowMs`, after which the
62
+ // server is quarantined (callers degrade to text search) until the window
63
+ // clears. `restarts` was previously a dead field; this makes it real.
64
+ this.maxRestarts = Number.isFinite(opts.maxRestarts) ? opts.maxRestarts : 3;
65
+ this.restartWindowMs = Number.isFinite(opts.restartWindowMs)
66
+ ? opts.restartWindowMs
67
+ : 30000;
68
+ this._now = typeof opts.now === "function" ? opts.now : () => Date.now();
69
+ /** key → array of recent crash timestamps (survives entry re-spawn) */
70
+ this._crashLog = new Map();
71
+ this._disposed = false;
72
+ }
73
+
74
+ /** Recent crash timestamps for `key`, pruned to the sliding window. */
75
+ _recentCrashes(key) {
76
+ const cutoff = this._now() - this.restartWindowMs;
77
+ const pruned = (this._crashLog.get(key) || []).filter((t) => t >= cutoff);
78
+ if (pruned.length) this._crashLog.set(key, pruned);
79
+ else this._crashLog.delete(key);
80
+ return pruned;
81
+ }
82
+
83
+ /**
84
+ * Ensure a server is running for `filePath` and the file is open. Returns
85
+ * `{ client, uri, languageId }`, or `{ unavailable: true, reason }` when no
86
+ * server is installed (caller degrades to text search).
87
+ */
88
+ async ensureFor(
89
+ filePath,
90
+ { root, waitReady = false, readyTimeoutMs = 8000 } = {},
91
+ ) {
92
+ if (this._disposed) throw new Error("LSPManager disposed");
93
+ const abs = path.resolve(filePath);
94
+ const languageId = languageIdForFile(abs);
95
+ if (!languageId) {
96
+ return {
97
+ unavailable: true,
98
+ reason: `no language mapping for ${path.extname(abs) || "file"}`,
99
+ };
100
+ }
101
+ const projectRoot = root || this._inferRoot(abs);
102
+ const resolved = resolveServer(languageId, projectRoot);
103
+ if (!resolved) {
104
+ return {
105
+ unavailable: true,
106
+ reason: `no language server installed for ${languageId} (install one, e.g. typescript-language-server)`,
107
+ };
108
+ }
109
+
110
+ const key = `${projectRoot}::${resolved.id}`;
111
+ let entry = this._servers.get(key);
112
+ if (!entry || !entry.client.running) {
113
+ // A dead/absent server is (re)started — but if it has crash-looped past
114
+ // the cap inside the window, quarantine it so we don't re-spawn on every
115
+ // request. The caller degrades to text search until the window clears.
116
+ const crashes = this._recentCrashes(key);
117
+ if (crashes.length >= this.maxRestarts) {
118
+ const retryInMs = this.restartWindowMs - (this._now() - crashes[0]);
119
+ return {
120
+ unavailable: true,
121
+ reason:
122
+ `${resolved.id} crash-looped (${crashes.length} crashes in ` +
123
+ `${Math.round(this.restartWindowMs / 1000)}s) — quarantined, ` +
124
+ `retrying in ~${Math.max(0, Math.round(retryInMs / 1000))}s`,
125
+ quarantined: true,
126
+ };
127
+ }
128
+ entry = await this._getOrStartServer(key, resolved, projectRoot);
129
+ }
130
+
131
+ const uri = pathToFileUri(abs);
132
+ this._ensureOpen(entry.client, uri, abs, languageId);
133
+
134
+ // One-shot callers (the `cc code-intel` CLI) spawn a cold server per run;
135
+ // the server publishes an empty diagnostics set BEFORE it finishes loading
136
+ // the tsconfig project, so an immediate definition/references/diagnostics
137
+ // query sees a partial project. Waiting for the first publish for THIS doc
138
+ // is a reliable "project loaded far enough" signal. Long-lived callers (the
139
+ // agent session) keep the server warm and pass waitReady:false.
140
+ if (waitReady) {
141
+ await this._waitForFirstPublish(uri, readyTimeoutMs);
142
+ }
143
+ return { client: entry.client, uri, languageId, root: projectRoot };
144
+ }
145
+
146
+ /** Resolve once the server has published diagnostics for `uri` at least once, or timeout. */
147
+ _waitForFirstPublish(rawUri, timeoutMs) {
148
+ const uri = normalizeUri(rawUri);
149
+ if ((this._diagMeta.get(uri)?.count || 0) > 0) return Promise.resolve();
150
+ return new Promise((resolve) => {
151
+ const started = Date.now();
152
+ const timer = setInterval(() => {
153
+ if (
154
+ (this._diagMeta.get(uri)?.count || 0) > 0 ||
155
+ Date.now() - started >= timeoutMs
156
+ ) {
157
+ clearInterval(timer);
158
+ resolve();
159
+ }
160
+ }, 40);
161
+ if (typeof timer.unref === "function") timer.unref();
162
+ });
163
+ }
164
+
165
+ /**
166
+ * Dedupe concurrent starts for `key`: return the in-flight start promise if
167
+ * one exists, otherwise begin one and register it so racing callers share it.
168
+ * The promise self-evicts on settle (resolve OR reject), so a failed start
169
+ * doesn't wedge the key — the next request retries cleanly.
170
+ */
171
+ _getOrStartServer(key, resolved, projectRoot) {
172
+ const inflight = this._starting.get(key);
173
+ if (inflight) return inflight;
174
+ const p = this._startServer(key, resolved, projectRoot).finally(() => {
175
+ this._starting.delete(key);
176
+ });
177
+ this._starting.set(key, p);
178
+ return p;
179
+ }
180
+
181
+ async _startServer(key, resolved, projectRoot) {
182
+ const client = _deps.createClient({
183
+ command: resolved.command,
184
+ args: resolved.args,
185
+ rootPath: projectRoot,
186
+ });
187
+ // Collect pushed diagnostics keyed by document, tracking publish count/time
188
+ // so callers can wait for the project to load (first publish) and settle
189
+ // (last publish) rather than racing the initial empty set tsserver emits.
190
+ client.on("notify:textDocument/publishDiagnostics", (params) => {
191
+ if (params && params.uri) {
192
+ const key = normalizeUri(params.uri);
193
+ this._diagnostics.set(key, params.diagnostics || []);
194
+ const prev = this._diagMeta.get(key) || { count: 0 };
195
+ this._diagMeta.set(key, { count: prev.count + 1, at: Date.now() });
196
+ }
197
+ });
198
+ const entry = {
199
+ client,
200
+ serverId: resolved.id,
201
+ root: projectRoot,
202
+ // How many times THIS key has already been (re)started — crash history
203
+ // survives entry replacement via _crashLog, so this reflects it.
204
+ restarts: (this._crashLog.get(key) || []).length,
205
+ };
206
+ // On crash: record the crash timestamp (bounds the re-spawn loop via the
207
+ // crash-loop guard in ensureFor) and drop this project's open docs so they
208
+ // re-sync against the fresh server on the next ensureFor.
209
+ client.on("exit", () => {
210
+ const log = this._crashLog.get(key) || [];
211
+ log.push(this._now());
212
+ this._crashLog.set(key, log);
213
+ // Drop this project's open docs AND their published-diagnostics
214
+ // bookkeeping. Leaving stale _diagMeta/_diagnostics behind makes the
215
+ // readiness waiters resolve on the PRE-CRASH publish — _waitForFirstPublish
216
+ // sees count>0 and returns immediately; waitForDiagnostics sees an old
217
+ // `at` and settles at once — so a query after a crash+restart returns
218
+ // stale results and races the fresh server's initial empty set, the very
219
+ // thing the publish-count machinery exists to prevent. (_openDocs keys are
220
+ // the raw file URI; _diagMeta/_diagnostics use the normalized key.)
221
+ for (const [uri, meta] of this._openDocs) {
222
+ if (meta.root === projectRoot) {
223
+ this._openDocs.delete(uri);
224
+ const nuri = normalizeUri(uri);
225
+ this._diagnostics.delete(nuri);
226
+ this._diagMeta.delete(nuri);
227
+ }
228
+ }
229
+ });
230
+ await client.start();
231
+ this._servers.set(key, entry);
232
+ return entry;
233
+ }
234
+
235
+ _ensureOpen(client, uri, abs, languageId) {
236
+ const existing = this._openDocs.get(uri);
237
+ let text = "";
238
+ try {
239
+ text = _deps.readFileSync(abs, "utf8");
240
+ } catch {
241
+ text = "";
242
+ }
243
+ if (!existing) {
244
+ client.notify("textDocument/didOpen", {
245
+ textDocument: { uri, languageId, version: 1, text },
246
+ });
247
+ this._openDocs.set(uri, {
248
+ version: 1,
249
+ languageId,
250
+ root: client.rootPath,
251
+ });
252
+ } else {
253
+ // File may have changed on disk since first open — push the latest text so
254
+ // definitions/diagnostics reflect current state (edit-freshness).
255
+ const version = existing.version + 1;
256
+ client.notify("textDocument/didChange", {
257
+ textDocument: { uri, version },
258
+ contentChanges: [{ text }],
259
+ });
260
+ this._openDocs.set(uri, { ...existing, version });
261
+ }
262
+ }
263
+
264
+ /** Notify the server that a document changed on disk (after an edit). */
265
+ async didChangeFile(filePath, { root } = {}) {
266
+ const abs = path.resolve(filePath);
267
+ const uri = pathToFileUri(abs);
268
+ if (!this._openDocs.has(uri)) {
269
+ // Not open yet — opening it (via ensureFor) will read fresh text anyway.
270
+ return this.ensureFor(abs, { root });
271
+ }
272
+ const ready = await this.ensureFor(abs, { root });
273
+ return ready;
274
+ }
275
+
276
+ /** Latest diagnostics for a file (may be empty). Server pushes asynchronously. */
277
+ getDiagnostics(filePath) {
278
+ const uri = normalizeUri(pathToFileUri(path.resolve(filePath)));
279
+ return this._diagnostics.get(uri) || [];
280
+ }
281
+
282
+ /**
283
+ * Wait for diagnostics for `filePath` to publish AND settle, then return the
284
+ * latest set. tsserver publishes an initial (often empty) set the moment a doc
285
+ * opens, then republishes once the project is loaded — resolving on the first
286
+ * publish would return stale/empty results. So we wait for at least one
287
+ * publish, then a `settleMs` quiet window with no further publishes (bounded
288
+ * by `timeoutMs`), and return whatever was published last.
289
+ */
290
+ async waitForDiagnostics(
291
+ filePath,
292
+ { timeoutMs = 3000, settleMs = 600 } = {},
293
+ ) {
294
+ const uri = normalizeUri(pathToFileUri(path.resolve(filePath)));
295
+ return new Promise((resolve) => {
296
+ const started = Date.now();
297
+ const timer = setInterval(() => {
298
+ const meta = this._diagMeta.get(uri);
299
+ const elapsed = Date.now() - started;
300
+ const settled =
301
+ meta && meta.count > 0 && Date.now() - meta.at >= settleMs;
302
+ if (settled || elapsed >= timeoutMs) {
303
+ clearInterval(timer);
304
+ resolve(this._diagnostics.get(uri) || []);
305
+ }
306
+ }, 50);
307
+ if (typeof timer.unref === "function") timer.unref();
308
+ });
309
+ }
310
+
311
+ /** Infer the project root for a file: nearest ancestor with package.json / .git / go.mod / Cargo.toml. */
312
+ _inferRoot(abs) {
313
+ let dir = path.dirname(abs);
314
+ const markers = [
315
+ "package.json",
316
+ ".git",
317
+ "go.mod",
318
+ "Cargo.toml",
319
+ "tsconfig.json",
320
+ "pyproject.toml",
321
+ ];
322
+ for (let i = 0; i < 12; i++) {
323
+ for (const m of markers) {
324
+ if (_deps.existsSync(path.join(dir, m))) return dir;
325
+ }
326
+ const parent = path.dirname(dir);
327
+ if (parent === dir) break;
328
+ dir = parent;
329
+ }
330
+ return this.projectRoot;
331
+ }
332
+
333
+ /** Shut down every server and clear state. Idempotent. */
334
+ async disposeAll() {
335
+ this._disposed = true;
336
+ const clients = [...this._servers.values()].map((e) => e.client);
337
+ this._servers.clear();
338
+ this._openDocs.clear();
339
+ this._diagnostics.clear();
340
+ this._diagMeta.clear();
341
+ await Promise.all(clients.map((c) => c.stop().catch(() => {})));
342
+ }
343
+
344
+ get activeServerCount() {
345
+ return this._servers.size;
346
+ }
347
+
348
+ /** Snapshot of running servers: `[{ serverId, root, pid }]` (for bench / doctor). */
349
+ listServers() {
350
+ const out = [];
351
+ for (const entry of this._servers.values()) {
352
+ out.push({
353
+ serverId: entry.serverId,
354
+ root: entry.root,
355
+ pid: entry.client.pid,
356
+ });
357
+ }
358
+ return out;
359
+ }
360
+ }
361
+
362
+ // ---- position helpers (the ONLY place that converts between coordinate spaces) ----
363
+
364
+ /** 1-based user position → 0-based LSP position. */
365
+ export function toLspPosition({ line, col }) {
366
+ return {
367
+ line: Math.max(0, (line || 1) - 1),
368
+ character: Math.max(0, (col || 1) - 1),
369
+ };
370
+ }
371
+
372
+ /** 0-based LSP position → 1-based user position. */
373
+ export function fromLspPosition(pos) {
374
+ return { line: (pos?.line || 0) + 1, col: (pos?.character || 0) + 1 };
375
+ }
@@ -0,0 +1,196 @@
1
+ /**
2
+ * LSP server registry — maps a language id to the language-server command that
3
+ * serves it, and probes whether that command is actually installed.
4
+ *
5
+ * Design constraint (see optimization plan): the CLI must NOT depend on any
6
+ * language server as an npm dependency (they are heavy and language-specific).
7
+ * Instead we DETECT servers on PATH / `node_modules/.bin`, and when none is
8
+ * available the caller degrades gracefully to text search. Plugins may register
9
+ * extra servers via `.lsp.json`.
10
+ *
11
+ * Pure + injectable: filesystem/exec probing goes through `_deps` so the
12
+ * detection logic is unit-testable without a real toolchain.
13
+ */
14
+
15
+ import fs from "fs";
16
+ import path from "path";
17
+ import { execFileSync } from "child_process";
18
+
19
+ export const _deps = {
20
+ existsSync: fs.existsSync,
21
+ execFileSync,
22
+ };
23
+
24
+ // Extension → LSP languageId. Kept small and explicit; unknown extensions get
25
+ // no LSP (text-search fallback).
26
+ const EXTENSION_LANGUAGE = {
27
+ ".ts": "typescript",
28
+ ".tsx": "typescriptreact",
29
+ ".mts": "typescript",
30
+ ".cts": "typescript",
31
+ ".js": "javascript",
32
+ ".jsx": "javascriptreact",
33
+ ".mjs": "javascript",
34
+ ".cjs": "javascript",
35
+ ".py": "python",
36
+ ".pyi": "python",
37
+ ".go": "go",
38
+ ".rs": "rust",
39
+ ".java": "java",
40
+ ".vue": "vue",
41
+ };
42
+
43
+ // languageId → server definition. `bin` names are tried in order; the first one
44
+ // resolvable wins. `args` is passed verbatim. Several languageIds can share one
45
+ // server family (TS server handles JS too).
46
+ const BUILTIN_SERVERS = {
47
+ typescript: tsServer(),
48
+ typescriptreact: tsServer(),
49
+ javascript: tsServer(),
50
+ javascriptreact: tsServer(),
51
+ python: {
52
+ id: "pyright",
53
+ bins: ["pyright-langserver", "pylsp"],
54
+ // pyright wants --stdio; pylsp defaults to stdio with no args. Resolved per-bin.
55
+ argsFor: (bin) => (bin.startsWith("pyright") ? ["--stdio"] : []),
56
+ },
57
+ go: { id: "gopls", bins: ["gopls"], argsFor: () => [] },
58
+ rust: { id: "rust-analyzer", bins: ["rust-analyzer"], argsFor: () => [] },
59
+ java: { id: "jdtls", bins: ["jdtls"], argsFor: () => [] },
60
+ };
61
+
62
+ function tsServer() {
63
+ return {
64
+ id: "typescript-language-server",
65
+ bins: ["typescript-language-server"],
66
+ argsFor: () => ["--stdio"],
67
+ };
68
+ }
69
+
70
+ // Registry of plugin-contributed servers, keyed by languageId. Wins over
71
+ // builtins if a plugin explicitly overrides.
72
+ const pluginServers = new Map();
73
+
74
+ /**
75
+ * Register an extra language server (from a plugin `.lsp.json`).
76
+ * @param {object} def { languageId, extensions?, command, args?, id? }
77
+ */
78
+ export function registerLanguageServer(def) {
79
+ if (!def || !def.languageId || !def.command) {
80
+ throw new Error("registerLanguageServer requires { languageId, command }");
81
+ }
82
+ pluginServers.set(def.languageId, {
83
+ id: def.id || def.command,
84
+ bins: [def.command],
85
+ argsFor: () => (Array.isArray(def.args) ? def.args : []),
86
+ fromPlugin: true,
87
+ });
88
+ if (Array.isArray(def.extensions)) {
89
+ for (const ext of def.extensions) {
90
+ EXTENSION_LANGUAGE[ext.startsWith(".") ? ext : "." + ext] =
91
+ def.languageId;
92
+ }
93
+ }
94
+ }
95
+
96
+ /** Test/reset hook — clears plugin registrations. */
97
+ export function _resetPluginServers() {
98
+ pluginServers.clear();
99
+ }
100
+
101
+ /** Map a file path to its LSP languageId, or null if unsupported. */
102
+ export function languageIdForFile(filePath) {
103
+ const ext = path.extname(String(filePath || "")).toLowerCase();
104
+ return EXTENSION_LANGUAGE[ext] || null;
105
+ }
106
+
107
+ /**
108
+ * Resolve a runnable server command for a languageId within a project root, or
109
+ * null if none is installed. Checks (in order): project `node_modules/.bin`,
110
+ * then PATH (via `resolveBin`).
111
+ *
112
+ * @returns {{ languageId, id, command, args } | null}
113
+ */
114
+ export function resolveServer(languageId, projectRoot) {
115
+ const def = pluginServers.get(languageId) || BUILTIN_SERVERS[languageId];
116
+ if (!def) return null;
117
+ for (const bin of def.bins) {
118
+ const command = resolveBin(bin, projectRoot);
119
+ if (command) {
120
+ return {
121
+ languageId,
122
+ id: def.id,
123
+ command,
124
+ args: def.argsFor(bin),
125
+ };
126
+ }
127
+ }
128
+ return null;
129
+ }
130
+
131
+ /**
132
+ * Find an executable by name: project-local `node_modules/.bin` first (so a
133
+ * repo-pinned server wins), then the system PATH. Returns an absolute path, or
134
+ * null. On Windows the `.cmd`/`.exe` variants are probed too.
135
+ */
136
+ export function resolveBin(bin, projectRoot) {
137
+ const isWin = process.platform === "win32";
138
+ const candidates = isWin ? [bin + ".cmd", bin + ".exe", bin] : [bin];
139
+
140
+ // 1) project node_modules/.bin (walk up a couple levels for monorepos)
141
+ if (projectRoot) {
142
+ let dir = projectRoot;
143
+ for (let i = 0; i < 4; i++) {
144
+ const binDir = path.join(dir, "node_modules", ".bin");
145
+ for (const c of candidates) {
146
+ const full = path.join(binDir, c);
147
+ if (_deps.existsSync(full)) return full;
148
+ }
149
+ const parent = path.dirname(dir);
150
+ if (parent === dir) break;
151
+ dir = parent;
152
+ }
153
+ }
154
+
155
+ // 2) PATH
156
+ const pathEnv = process.env.PATH || process.env.Path || "";
157
+ const sep = isWin ? ";" : ":";
158
+ for (const entry of pathEnv.split(sep)) {
159
+ if (!entry) continue;
160
+ for (const c of candidates) {
161
+ const full = path.join(entry, c);
162
+ if (_deps.existsSync(full)) return full;
163
+ }
164
+ }
165
+ return null;
166
+ }
167
+
168
+ /**
169
+ * Report which builtin servers are available on this machine — used by
170
+ * `cc doctor` and `cc code-intel status` so the user sees why LSP is or isn't
171
+ * active without guessing.
172
+ * @returns {Array<{ languageId, id, available, command }>}
173
+ */
174
+ export function probeServers(projectRoot) {
175
+ const seen = new Set();
176
+ const out = [];
177
+ const all = { ...BUILTIN_SERVERS };
178
+ for (const [lid, def] of pluginServers) all[lid] = def;
179
+ for (const [languageId, def] of Object.entries(all)) {
180
+ if (seen.has(def.id)) continue; // one row per server family
181
+ seen.add(def.id);
182
+ const resolved = resolveServer(languageId, projectRoot);
183
+ out.push({
184
+ languageId,
185
+ id: def.id,
186
+ available: Boolean(resolved),
187
+ command: resolved ? resolved.command : null,
188
+ });
189
+ }
190
+ return out;
191
+ }
192
+
193
+ /** All extensions the registry can currently map (for docs/diagnostics). */
194
+ export function supportedExtensions() {
195
+ return Object.keys(EXTENSION_LANGUAGE).sort();
196
+ }
@@ -57,6 +57,90 @@ export function ensureMatrixTables(db) {
57
57
  `);
58
58
  }
59
59
 
60
+ /**
61
+ * Rehydrate _rooms/_messages/_spaceChildren from the persisted matrix_rooms/
62
+ * matrix_events tables. The `cc` CLI runs every command in a fresh process, so
63
+ * without this the Maps start empty and a room joined / message sent / space
64
+ * child added in a prior invocation is invisible (`cc matrix rooms`/`messages`/
65
+ * `space children` show nothing; sending to a persisted room can't find it).
66
+ * Call after ensureMatrixTables(db).
67
+ *
68
+ * Caveats reflecting the write side: room `type` is not a persisted column, so
69
+ * spaces are re-identified by their `!space_` roomId prefix (matching
70
+ * createSpace). removeSpaceChild is not persisted (no tombstone event), so a
71
+ * removed child re-appears after rehydration — a separate pre-existing gap,
72
+ * out of scope here.
73
+ */
74
+ export function loadFromDb(db) {
75
+ if (!db) return 0;
76
+ _rooms.clear();
77
+ _messages.clear();
78
+ _spaceChildren.clear();
79
+
80
+ const roomRows = db.prepare(`SELECT * FROM matrix_rooms`).all();
81
+ for (const row of roomRows) {
82
+ const isSpace =
83
+ typeof row.room_id === "string" && row.room_id.startsWith("!space_");
84
+ const room = {
85
+ id: row.id,
86
+ roomId: row.room_id,
87
+ name: row.name,
88
+ topic: row.topic ?? null,
89
+ isEncrypted: !!row.is_encrypted,
90
+ memberCount: row.member_count ?? 0,
91
+ lastEventAt: row.last_event_at ?? null,
92
+ joinedAt: row.joined_at ?? null,
93
+ status: row.status,
94
+ createdAt: row.created_at ?? null,
95
+ };
96
+ if (isSpace) {
97
+ room.type = "m.space";
98
+ if (!_spaceChildren.has(row.room_id))
99
+ _spaceChildren.set(row.room_id, new Map());
100
+ }
101
+ _rooms.set(row.id, room);
102
+ }
103
+
104
+ const eventRows = db.prepare(`SELECT * FROM matrix_events`).all();
105
+ for (const row of eventRows) {
106
+ let content = {};
107
+ try {
108
+ content = row.content ? JSON.parse(row.content) : {};
109
+ } catch {
110
+ content = {};
111
+ }
112
+
113
+ if (row.event_type === "m.space.child") {
114
+ // Space child state event: content is { state_key, content: { via } }.
115
+ const childRoomId = content.state_key;
116
+ const via =
117
+ content.content && Array.isArray(content.content.via)
118
+ ? content.content.via
119
+ : ["matrix.org"];
120
+ if (childRoomId) {
121
+ if (!_spaceChildren.has(row.room_id))
122
+ _spaceChildren.set(row.room_id, new Map());
123
+ _spaceChildren.get(row.room_id).set(childRoomId, { via });
124
+ }
125
+ continue; // space-child events are not messages
126
+ }
127
+
128
+ _messages.set(row.id, {
129
+ id: row.id,
130
+ eventId: row.event_id,
131
+ roomId: row.room_id,
132
+ sender: row.sender,
133
+ eventType: row.event_type,
134
+ content,
135
+ originServerTs: row.origin_server_ts ?? null,
136
+ isEncrypted: !!row.is_encrypted,
137
+ createdAt: row.created_at ?? null,
138
+ });
139
+ }
140
+
141
+ return _rooms.size + _messages.size + _spaceChildren.size;
142
+ }
143
+
60
144
  /* ── Login ─────────────────────────────────────────────────── */
61
145
 
62
146
  export function login(db, homeserver, userId, password) {
@@ -7,7 +7,7 @@
7
7
 
8
8
  import fs from "fs";
9
9
  import path from "path";
10
- import { likePrefix } from "./sql-like.js";
10
+ import { likePrefix, escapeLike } from "./sql-like.js";
11
11
 
12
12
  /**
13
13
  * Atomically write a UTF-8 file: a crash mid-write must not truncate MEMORY.md
@@ -98,12 +98,14 @@ export function searchMemory(db, query, options = {}) {
98
98
  if (!query || !query.trim()) return [];
99
99
 
100
100
  const limit = Math.max(1, parseInt(options.limit) || 20);
101
- const pattern = `%${query}%`;
101
+ // Escape LIKE wildcards so a query containing % / _ is matched literally
102
+ // rather than as a wildcard (`search "%"` would otherwise match every entry).
103
+ const pattern = `%${escapeLike(query)}%`;
102
104
 
103
105
  return db
104
106
  .prepare(
105
107
  `SELECT * FROM memory_entries
106
- WHERE content LIKE ?
108
+ WHERE content LIKE ? ESCAPE '\\'
107
109
  ORDER BY importance DESC, created_at DESC
108
110
  LIMIT ?`,
109
111
  )