chainlesschain 0.162.149 → 0.162.151
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.
- package/README.md +1 -1
- package/package.json +3 -2
- package/src/assets/web-panel/assets/{AIOps-BJif14yR.js → AIOps-DuEOzebi.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CXek6gJY.js → ActionButton-C6GiJa5H.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BgQhdAJi.js → Analytics-BBIiL_pO.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DTYl5NtR.js → AppLayout-CuI2gZRy.js} +3 -3
- package/src/assets/web-panel/assets/{Audit-BzATQAeR.js → Audit-CbUjfr-K.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BzdPEQhL.js → Backup-CsSW9ljf.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BM0KVh8E.js → BaseInput-kM3rLe7F.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-D7fHXHkz.js → Chat-kfE51YN3.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Wm34RR-b.js → ChatBubbleRenderer-Bg2FTW6A.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CAiSQ9vO.js → Checkbox-jYb1uj-M.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Df40CrEe.js → Codegen-X9XiD5Lj.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DIT2fNFU.js → Col-BfbHu1xI.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CSTIbW2k.js → Community-c4oJMFS-.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DtqXZZUi.js → Compact-BFmnZpH7.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CUtzw6o7.js → Compliance-s9shVHBS.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CezmlnmU.js → Cowork-C5da--TC.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-P4BITarg.js → Cron-9kNbyNE4.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BRRiYwvq.js → Crosschain-C1k3NJD4.js} +1 -1
- package/src/assets/web-panel/assets/{DID-L5ijB9i4.js → DID-DkheEvNK.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CFxro4ob.js → Dashboard-C3FuSGmJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BmAFCQ71.js → Dropdown-CAV6FMFD.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DJBCEuon.js → EmailListRenderer-Cc-Ulc4l.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-z4oLq6eT.js → FamilyGuardDashboard-8CitHEtv.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DsVCpHMF.js → Federation-DFSZ5KDt.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DP3bP5th.js → FormItemContext-CEWCtnG2.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BAXP2Gc6.js → GenericCardRenderer-CwRzNzmX.js} +1 -1
- package/src/assets/web-panel/assets/{Git-I3g_bAw9.js → Git-0rgDM7cJ.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-jHS5-ioS.js → Governance-CfBKtK9F.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CPL7sfx9.js → Inference-CzcUVvud.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Jf236h4C.js → KnowledgeGraph-Dwc4YL4A.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Cm2tcSKg.js → Logs-DgFPwR2F.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-CZK82rhi.js → Marketplace-DnpPTbGU.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CZCeji7a.js → McpTools-DRxxINyW.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-3l2KVS9k.js → Memory-OhmW_6Z3.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-VYdpoLh6.js → MobileBridge-DkTW-RK5.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CiB9cmm1.js → MobileProjects-DpCGV_lI.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-wCFZbBuL.js → Mtc--vmkL0AS.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-1a3THIyG.js → MtcAudit-DGoFWjD4.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-DMzLB2hG.js → Multisig-B4kWgq95.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-D9wZbf6l.js → NLProgramming-YQwvommE.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-hrFe2ZM-.js → Notes-CgjtUADJ.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CHGX5Jwm.js → NotificationSettings-6JDrpBG5.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-PM6IlxjO.js +1 -0
- package/src/assets/web-panel/assets/{Organization-By7FkhtY.js → Organization-8McOT_OF.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow--khGSzJn.js → Overflow-DAZpSCGc.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CAG9dH35.js → P2P-B7l2ZWLy.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-B3SQZmK9.js → PdhVaultBrowser-W1Ud-NAL.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-D35ec6JA.js → Permissions-Czm_w9u_.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CxBF7hW_.js → PersonalDataHub-B4F0_ZVM.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-s6EtOO1s.js → Pipeline-B37aFiWv.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BbJYmWmO.js → Privacy-94KBnRrD.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-VGQq1jMT.js → ProjectInit-B5h8_dlh.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-B1ew3Teh.js → ProjectSettings-lmeI3Lpm.js} +2 -2
- package/src/assets/web-panel/assets/Projects-D5AYOasl.js +1 -0
- package/src/assets/web-panel/assets/{Providers-mrO47FIK.js → Providers-B3cNWwJg.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-IJF2mHyw.js → QrScannerModal-CHRvOw1R.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CU0wN_Z0.js → QuickAsk-D1JMgFEd.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DhN37R6G.js → Recommend-EYWGR79p.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-D_xOX_hu.js → RemoteSession-BAMC2pJt.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-D_Ssv7uH.js → Reputation-X2Hk1XG_.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Kx5dKxX7.js → Row-Eq98LRtU.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BlGwqZkY.js → RssFeed-i76s6z_o.js} +2 -2
- package/src/assets/web-panel/assets/{Search-hLFQzxpb.js → Search-D_Es7CAI.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DMlvsVt4.js → Security-kayD2e94.js} +3 -3
- package/src/assets/web-panel/assets/{Services-Bd0Qsj2m.js → Services-Ctsm6ul8.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DFclq9X3.js → Skeleton-CRNYlfdf.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BNtln2qY.js → Skills-DkZYpF4-.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Dch5H19G.js → Sla-DXkoBcOP.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-2UfQcU1g.js → SpeechSettings-DXi_GI1d.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CD9YQr4i.js → SyncSettings-rNKpfomn.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BNu-7MzI.js → Tasks-XF4uPtG-.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D1n9CaIR.js → Templates-i0Hzfeyu.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DenL3iBW.js → Tenant-sMpHAi27.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-BoZvaYAl.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-D87IfukO.js → TimelineRenderer-yuC6K7Rf.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BkiZc8E3.js → Tokens-B8O8i0s6.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BNRSytGN.js → Trigger-Bv6yrlCr.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-Bwbd4X2m.js → Trust-C4mW95Ev.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B8O2bs0o.js → UkeySign-DV6yKaHn.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C2fL8zmH.js → VideoEditing-UI479-sD.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BORYDdE1.js → Wallet-M5oV9EVP.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-C0V5S2FM.js → WebAuthn-DDyDHPDR.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-2dR0fcHL.js → WorkflowEditor-RoBv4rqk.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BmuAFAn8.js → chat-Cw1mE5LS.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CN3smMcK.js → colors-BFP62Gwf.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DCnxb4kW.js → compact-item-17HL6pyC.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-vlR43pHn.js → createContext-D55X4fZX.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CqbHYuRc.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D04tHYFd.js → hasIn-D3E5mNsP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbVsQBOH.js → index--44J50mc.js} +1 -1
- package/src/assets/web-panel/assets/{index-TslMTwNy.js → index-ASPYTzMK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTOCnIQ7.js → index-BC6zxOlU.js} +1 -1
- package/src/assets/web-panel/assets/{index-ljuBiQW9.js → index-BEa1RW4c.js} +1 -1
- package/src/assets/web-panel/assets/{index-jzR7Ujuw.js → index-BQmZg5si.js} +1 -1
- package/src/assets/web-panel/assets/{index-BudvKQfG.js → index-BY_xZ2jy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CP9m9Ggr.js → index-BgN5G5vF.js} +3 -3
- package/src/assets/web-panel/assets/{index-Cr-A0FYJ.js → index-BnGpft-Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5LZVZ0L.js → index-Bq83UBDr.js} +1 -1
- package/src/assets/web-panel/assets/{index-ToUh2b1-.js → index-Bzpp2z2S.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbADHwhr.js → index-CFYGn88j.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClhAHDK3.js → index-CGyTos4p.js} +1 -1
- package/src/assets/web-panel/assets/index-CKBI1U5K.js +1 -0
- package/src/assets/web-panel/assets/{index-C-6NO5il.js → index-CLEzsZ8A.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8vwp4qp.js → index-CR9rNUvi.js} +1 -1
- package/src/assets/web-panel/assets/{index-_FIkN3jd.js → index-CW6LLoJO.js} +1 -1
- package/src/assets/web-panel/assets/{index-D65_XseV.js → index-C_MfcrLf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnXebZLL.js → index-Cdvk2_2q.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_n8_vfI.js → index-CjCwi7we.js} +1 -1
- package/src/assets/web-panel/assets/index-CkLp6DTO.js +1 -0
- package/src/assets/web-panel/assets/{index-DDwLgQY9.js → index-CvCFKojj.js} +1 -1
- package/src/assets/web-panel/assets/{index-430S68MN.js → index-D4LHSde4.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXRg8GFQ.js → index-DCLu84x-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTtRscUa.js → index-DD_qGBrt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BasvsWDM.js → index-DIRvdwBX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BeGDEXFs.js → index-DOjA8bvj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CsAsCPJ6.js → index-Da27u6j0.js} +1 -1
- package/src/assets/web-panel/assets/{index-D28DeAAB.js → index-DkBVYlE4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CngCC8hC.js → index-DtAnPBWP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B78xL3s2.js → index-DzG7mkgW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIpY0qM5.js → index-H9_X1Cg_.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5Sxb1sE.js → index-ITeEHb8L.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTPEZTk1.js → index-KtLJXn4s.js} +1 -1
- package/src/assets/web-panel/assets/{index-hpvvtAZ3.js → index-RYZgFIwo.js} +1 -1
- package/src/assets/web-panel/assets/{index-HhNjnCfe.js → index-gAVxDiTZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTWg-18U.js → index-paVubXzn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqhASEL4.js → index-tUH_6bdJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYAtmqiv.js → index-tVRPgYGr.js} +1 -1
- package/src/assets/web-panel/assets/{index-0DnaZGkC.js → index-uSsiwgZ2.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C3wUb4je.js → initDefaultProps-Ckp7xVZS.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D-jYFUNA.js → motion-DUZgCpn6.js} +1 -1
- package/src/assets/web-panel/assets/{move-tqb8nwJ2.js → move-B2rttglH.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DSOjMJMz.js → mtc-parser-BYWcLTuN.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CJ7VimIW.js → omit-DhHqKeFx.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-qXiG1iT3.js → pickAttrs-ANpJaWMO.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CkGBcy1Z.js → placementArrow-CfZWe7CA.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-D3WvTlLO.js → responsiveObserve-D7Xz2y-R.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BEE2ftge.js → slide-DekqCBY9.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CsfBpxiG.js → statusUtils-BET6XU7h.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-xPrIiJPI.js → styleChecker-qHmJjV62.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C5Yd-SCR.js → useFlexGapSupport-BoMCTNyu.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-D_MDS8HI.js → useFs-TdW-NgFC.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BqJh-usA.js → usePersonalDataHub-Dyox7wCu.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-chm_p-gz.js → vnode-XUn5S8CP.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-3-YDNz0Z.js → zoom-Ls77i8hn.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-manifest.json +8 -1
- package/src/commands/a2a.js +19 -4
- package/src/commands/activitypub.js +20 -3
- package/src/commands/agent.js +27 -5
- package/src/commands/audit.js +40 -24
- package/src/commands/changelog.js +148 -0
- package/src/commands/codeintel.js +68 -0
- package/src/commands/collab.js +15 -2
- package/src/commands/compliance.js +5 -0
- package/src/commands/config.js +4 -1
- package/src/commands/dao.js +86 -14
- package/src/commands/dev.js +2 -0
- package/src/commands/did.js +7 -1
- package/src/commands/dlp.js +23 -1
- package/src/commands/economy.js +29 -3
- package/src/commands/eval.js +7 -0
- package/src/commands/evomap.js +26 -0
- package/src/commands/governance.js +17 -3
- package/src/commands/hardening.js +18 -0
- package/src/commands/incentive.js +5 -0
- package/src/commands/init.js +46 -2
- package/src/commands/kg.js +4 -0
- package/src/commands/loop.js +6 -1
- package/src/commands/lowcode.js +15 -2
- package/src/commands/marketplace.js +40 -6
- package/src/commands/matrix.js +20 -1
- package/src/commands/memory.js +4 -1
- package/src/commands/mtc.js +7 -1
- package/src/commands/nostr.js +31 -4
- package/src/commands/note.js +7 -4
- package/src/commands/plugin.js +125 -5
- package/src/commands/pqc.js +5 -0
- package/src/commands/reputation.js +10 -1
- package/src/commands/scim.js +6 -0
- package/src/commands/session.js +32 -10
- package/src/commands/siem.js +11 -0
- package/src/commands/sla.js +18 -3
- package/src/commands/social.js +38 -5
- package/src/commands/sso.js +10 -2
- package/src/commands/stress.js +23 -4
- package/src/commands/team.js +9 -2
- package/src/commands/tech.js +2 -0
- package/src/commands/tenant.js +10 -1
- package/src/commands/terraform.js +6 -0
- package/src/commands/update.js +1 -1
- package/src/commands/zkp.js +20 -0
- package/src/data/changelog.json +189 -0
- package/src/gateways/ws/message-dispatcher.js +5 -2
- package/src/gateways/ws/remote-session-protocol.js +110 -42
- package/src/harness/jsonl-session-store.js +12 -5
- package/src/harness/plugin-manager.js +16 -4
- package/src/harness/remote-command-ledger.js +46 -15
- package/src/harness/worktree-isolator.js +16 -6
- package/src/index.js +2 -0
- package/src/lib/__tests__/logger.test.js +5 -2
- package/src/lib/a2a-protocol.js +25 -1
- package/src/lib/activitypub-bridge.js +61 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-economy.js +262 -29
- package/src/lib/agent-network.js +7 -1
- package/src/lib/agent-team/team-runner.js +25 -9
- package/src/lib/agent-team/team-worktree.js +36 -4
- package/src/lib/async-hook-supervisor.cjs +102 -16
- package/src/lib/audit-logger.js +7 -6
- package/src/lib/autonomous-developer.js +60 -0
- package/src/lib/changelog.js +252 -0
- package/src/lib/chat-core.js +17 -4
- package/src/lib/collaboration-governance.js +56 -0
- package/src/lib/community-governance.js +68 -0
- package/src/lib/compliance-manager.js +63 -0
- package/src/lib/cross-chain.js +5 -0
- package/src/lib/dao-governance.js +151 -2
- package/src/lib/did-manager.js +23 -10
- package/src/lib/dlp-engine.js +70 -0
- package/src/lib/eval/runner.js +89 -1
- package/src/lib/eval/tasks.js +170 -0
- package/src/lib/eval/trend.js +16 -1
- package/src/lib/evolution-system.js +92 -0
- package/src/lib/evomap-federation.js +55 -0
- package/src/lib/evomap-governance.js +94 -0
- package/src/lib/fatal-handler.js +17 -1
- package/src/lib/hardening-manager.js +73 -0
- package/src/lib/hierarchical-memory.js +14 -8
- package/src/lib/knowledge-exporter.js +8 -2
- package/src/lib/knowledge-graph.js +79 -0
- package/src/lib/llm-providers.js +23 -14
- package/src/lib/logger.js +4 -1
- package/src/lib/lsp/__tests__/benchmark.test.js +88 -0
- package/src/lib/lsp/__tests__/lsp-client.test.js +11 -0
- package/src/lib/lsp/__tests__/lsp-manager.test.js +69 -0
- package/src/lib/lsp/benchmark.js +257 -0
- package/src/lib/lsp/lsp-client.js +30 -9
- package/src/lib/lsp/lsp-manager.js +54 -2
- package/src/lib/lsp/lsp-server-registry.js +15 -4
- package/src/lib/matrix-bridge.js +84 -0
- package/src/lib/memory-manager.js +5 -3
- package/src/lib/nostr-bridge.js +53 -0
- package/src/lib/permission-engine.js +22 -4
- package/src/lib/plugin-runtime/__tests__/remote-source.test.js +256 -0
- package/src/lib/plugin-runtime/hooks.js +20 -4
- package/src/lib/plugin-runtime/install.js +9 -1
- package/src/lib/plugin-runtime/monitors.js +20 -4
- package/src/lib/plugin-runtime/policy.js +9 -1
- package/src/lib/plugin-runtime/remote-source.js +240 -0
- package/src/lib/plugin-runtime/signature.js +16 -0
- package/src/lib/pqc-manager.js +64 -0
- package/src/lib/reputation-optimizer.js +101 -0
- package/src/lib/sandbox-egress-proxy.js +195 -59
- package/src/lib/sandbox-fs-policy.js +112 -0
- package/src/lib/sandbox-network-policy.js +44 -5
- package/src/lib/sandbox-v2.js +14 -14
- package/src/lib/scim-manager.js +36 -0
- package/src/lib/session-manager.js +5 -2
- package/src/lib/settings-hooks.cjs +1 -0
- package/src/lib/siem-exporter.js +45 -0
- package/src/lib/skill-loader.js +20 -2
- package/src/lib/skill-marketplace.js +83 -0
- package/src/lib/sla-manager.js +88 -0
- package/src/lib/social-manager.js +74 -0
- package/src/lib/stress-tester.js +65 -0
- package/src/lib/tech-learning-engine.js +75 -0
- package/src/lib/telemetry/span-recorder.js +12 -1
- package/src/lib/tenant-saas.js +107 -0
- package/src/lib/terraform-manager.js +67 -0
- package/src/lib/token-incentive.js +180 -29
- package/src/lib/wallet-manager.js +81 -35
- package/src/lib/zkp-engine.js +87 -0
- package/src/repl/agent-repl.js +17 -2
- package/src/runtime/__tests__/auto-pin.test.js +104 -0
- package/src/runtime/agent-core.js +241 -68
- package/src/runtime/auto-pin.js +117 -0
- package/src/runtime/headless-runner.js +35 -0
- package/src/assets/web-panel/assets/OrderTableRenderer-CRIFE2Tj.js +0 -1
- package/src/assets/web-panel/assets/Projects-CGcNIs_g.js +0 -1
- package/src/assets/web-panel/assets/Terminal-ZzU0Io1Y.js +0 -3
- package/src/assets/web-panel/assets/devWarning-DxwmsL4j.js +0 -1
- package/src/assets/web-panel/assets/index-Cg2ldRfU.js +0 -1
- package/src/assets/web-panel/assets/index-Dwzo-dtJ.js +0 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LSP code-intelligence latency benchmark.
|
|
3
|
+
*
|
|
4
|
+
* Measures the two numbers the Phase 2 acceptance criteria call for on real
|
|
5
|
+
* repos: **startup latency** (cold spawn + project index + first answer) and
|
|
6
|
+
* **per-query latency** (warm def / refs / hover / diagnostics / symbols), plus
|
|
7
|
+
* best-effort server-process RSS. Pure timing/stat helpers are separated out so
|
|
8
|
+
* they are unit-testable without spawning anything.
|
|
9
|
+
*
|
|
10
|
+
* Deliberately drives the SAME `CodeIntelligence` the agent tool uses, so the
|
|
11
|
+
* numbers reflect real agent-path latency, not a synthetic micro-path.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { CodeIntelligence } from "./code-intelligence.js";
|
|
15
|
+
|
|
16
|
+
/** now() in fractional milliseconds — injectable for deterministic tests. */
|
|
17
|
+
export const _deps = {
|
|
18
|
+
now: () => Number(process.hrtime.bigint() / 1000n) / 1000,
|
|
19
|
+
sampleRss: sampleRssDefault,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** p-th percentile (0..100) of an UNSORTED sample via linear interpolation. */
|
|
23
|
+
export function percentile(samples, p) {
|
|
24
|
+
if (!samples.length) return null;
|
|
25
|
+
const sorted = [...samples].sort((a, b) => a - b);
|
|
26
|
+
if (sorted.length === 1) return sorted[0];
|
|
27
|
+
const rank = (p / 100) * (sorted.length - 1);
|
|
28
|
+
const lo = Math.floor(rank);
|
|
29
|
+
const hi = Math.ceil(rank);
|
|
30
|
+
if (lo === hi) return sorted[lo];
|
|
31
|
+
return sorted[lo] + (sorted[hi] - sorted[lo]) * (rank - lo);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Summary stats for a latency sample (all in ms), rounded to 0.1ms. */
|
|
35
|
+
export function summarize(samples) {
|
|
36
|
+
if (!samples.length) return { n: 0 };
|
|
37
|
+
const round = (x) => (x == null ? null : Math.round(x * 10) / 10);
|
|
38
|
+
const sum = samples.reduce((a, b) => a + b, 0);
|
|
39
|
+
return {
|
|
40
|
+
n: samples.length,
|
|
41
|
+
min: round(Math.min(...samples)),
|
|
42
|
+
median: round(percentile(samples, 50)),
|
|
43
|
+
p95: round(percentile(samples, 95)),
|
|
44
|
+
max: round(Math.max(...samples)),
|
|
45
|
+
mean: round(sum / samples.length),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Run the benchmark. Returns a structured report; never throws for the
|
|
51
|
+
* "no server installed" case (returns { available:false, reason }).
|
|
52
|
+
*
|
|
53
|
+
* @param {object} opts
|
|
54
|
+
* @param {string} opts.projectRoot
|
|
55
|
+
* @param {string} opts.file a real source file in the project
|
|
56
|
+
* @param {number} [opts.runs=20] timed iterations per operation
|
|
57
|
+
* @param {number} [opts.warmup=2] untimed warmup iterations per operation
|
|
58
|
+
* @param {(msg:string)=>void} [opts.onProgress]
|
|
59
|
+
*/
|
|
60
|
+
export async function runLatencyBenchmark(opts) {
|
|
61
|
+
const {
|
|
62
|
+
projectRoot,
|
|
63
|
+
file,
|
|
64
|
+
runs = 20,
|
|
65
|
+
warmup = 2,
|
|
66
|
+
onProgress = () => {},
|
|
67
|
+
} = opts;
|
|
68
|
+
const ci = new CodeIntelligence({ projectRoot, coldStart: true });
|
|
69
|
+
const report = {
|
|
70
|
+
file,
|
|
71
|
+
runs,
|
|
72
|
+
available: true,
|
|
73
|
+
coldStartMs: null,
|
|
74
|
+
probe: null,
|
|
75
|
+
ops: {},
|
|
76
|
+
server: null,
|
|
77
|
+
};
|
|
78
|
+
try {
|
|
79
|
+
// --- cold start: first query pays spawn + project index ---
|
|
80
|
+
onProgress("cold start (spawn + index + first query)…");
|
|
81
|
+
const t0 = _deps.now();
|
|
82
|
+
const first = await ci.documentSymbols(file);
|
|
83
|
+
report.coldStartMs = round1(_deps.now() - t0);
|
|
84
|
+
if (!first.available) {
|
|
85
|
+
return { available: false, reason: first.reason };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// --- choose a probe position from a real symbol (so def/refs have a target) ---
|
|
89
|
+
const probe = pickProbe(first.symbols);
|
|
90
|
+
report.probe = probe;
|
|
91
|
+
|
|
92
|
+
// best-effort server memory now that it's warm
|
|
93
|
+
report.server = await captureServerInfo(ci);
|
|
94
|
+
|
|
95
|
+
// --- timed operations (warm) ---
|
|
96
|
+
const ops = [
|
|
97
|
+
{ name: "document_symbols", run: () => ci.documentSymbols(file) },
|
|
98
|
+
{
|
|
99
|
+
name: "definition",
|
|
100
|
+
run: () => ci.definition(file, probe.line, probe.col),
|
|
101
|
+
needsProbe: true,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "references",
|
|
105
|
+
run: () => ci.references(file, probe.line, probe.col),
|
|
106
|
+
needsProbe: true,
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: "hover",
|
|
110
|
+
run: () => ci.hover(file, probe.line, probe.col),
|
|
111
|
+
needsProbe: true,
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "diagnostics",
|
|
115
|
+
run: () => ci.diagnostics(file, { timeoutMs: 4000 }),
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
for (const op of ops) {
|
|
120
|
+
if (op.needsProbe && !probe) {
|
|
121
|
+
report.ops[op.name] = { skipped: "no probe symbol" };
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
onProgress(`${op.name} …`);
|
|
125
|
+
for (let i = 0; i < warmup; i++) await op.run();
|
|
126
|
+
const samples = [];
|
|
127
|
+
for (let i = 0; i < runs; i++) {
|
|
128
|
+
const s = _deps.now();
|
|
129
|
+
await op.run();
|
|
130
|
+
samples.push(_deps.now() - s);
|
|
131
|
+
}
|
|
132
|
+
report.ops[op.name] = summarize(samples);
|
|
133
|
+
}
|
|
134
|
+
return report;
|
|
135
|
+
} finally {
|
|
136
|
+
await ci.dispose();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function pickProbe(symbols) {
|
|
141
|
+
if (!Array.isArray(symbols) || !symbols.length) return null;
|
|
142
|
+
// Prefer a function/method/class — those have meaningful def/refs.
|
|
143
|
+
const preferred = symbols.find((s) =>
|
|
144
|
+
["function", "method", "class"].includes(s.kind),
|
|
145
|
+
);
|
|
146
|
+
const s = preferred || symbols[0];
|
|
147
|
+
return { line: s.line, col: s.col, name: s.name, kind: s.kind };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function captureServerInfo(ci) {
|
|
151
|
+
try {
|
|
152
|
+
const servers = ci.manager.listServers();
|
|
153
|
+
if (!servers.length) return null;
|
|
154
|
+
const s = servers[0];
|
|
155
|
+
const rssMb = s.pid != null ? await _deps.sampleRss(s.pid) : null;
|
|
156
|
+
return { serverId: s.serverId, pid: s.pid, rssMb };
|
|
157
|
+
} catch {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Best-effort resident-set-size (MB) of the server, summed over the pid AND its
|
|
164
|
+
* descendants. This matters on Windows: a `.cmd` server is launched through
|
|
165
|
+
* `cmd.exe /c`, so the tracked pid is the launcher and the real language server
|
|
166
|
+
* (node/tsserver) is a child — measuring only the launcher reports a few MB and
|
|
167
|
+
* lies. We sum the whole subtree. Returns null if it can't be read (never throws
|
|
168
|
+
* — memory is a bonus metric, not load-bearing).
|
|
169
|
+
*/
|
|
170
|
+
async function sampleRssDefault(pid) {
|
|
171
|
+
const { execFileSync } = await import("child_process");
|
|
172
|
+
try {
|
|
173
|
+
if (process.platform === "win32") {
|
|
174
|
+
// One snapshot of every process → parent map → sum the subtree at `pid`.
|
|
175
|
+
const csv = execFileSync(
|
|
176
|
+
"wmic",
|
|
177
|
+
[
|
|
178
|
+
"process",
|
|
179
|
+
"get",
|
|
180
|
+
"ProcessId,ParentProcessId,WorkingSetSize",
|
|
181
|
+
"/format:csv",
|
|
182
|
+
],
|
|
183
|
+
{ encoding: "utf8", windowsHide: true, maxBuffer: 16 * 1024 * 1024 },
|
|
184
|
+
);
|
|
185
|
+
const bytes = sumSubtreeRssFromWmicCsv(csv, pid);
|
|
186
|
+
return bytes != null ? Math.round(bytes / (1024 * 1024)) : null;
|
|
187
|
+
}
|
|
188
|
+
// POSIX: not wrapped, so the pid is the real server. Sum pid + children.
|
|
189
|
+
const out = execFileSync("ps", ["-o", "pid=,ppid=,rss="], {
|
|
190
|
+
encoding: "utf8",
|
|
191
|
+
});
|
|
192
|
+
const rows = out
|
|
193
|
+
.trim()
|
|
194
|
+
.split(/\r?\n/)
|
|
195
|
+
.map((l) => l.trim().split(/\s+/).map(Number));
|
|
196
|
+
const kb = sumSubtreeRss(
|
|
197
|
+
rows.map(([p, pp, rss]) => ({ pid: p, ppid: pp, val: rss })),
|
|
198
|
+
pid,
|
|
199
|
+
);
|
|
200
|
+
return kb != null ? Math.round(kb / 1024) : null;
|
|
201
|
+
} catch {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/** Parse `wmic ... /format:csv` output and sum WorkingSetSize over pid's subtree (bytes). */
|
|
207
|
+
export function sumSubtreeRssFromWmicCsv(csv, rootPid) {
|
|
208
|
+
const lines = csv
|
|
209
|
+
.split(/\r?\n/)
|
|
210
|
+
.map((l) => l.trim())
|
|
211
|
+
.filter(Boolean);
|
|
212
|
+
const header = lines.find((l) => /ProcessId/i.test(l));
|
|
213
|
+
if (!header) return null;
|
|
214
|
+
const cols = header.split(",");
|
|
215
|
+
const iPid = cols.findIndex((c) => /^ProcessId$/i.test(c));
|
|
216
|
+
const iPpid = cols.findIndex((c) => /^ParentProcessId$/i.test(c));
|
|
217
|
+
const iRss = cols.findIndex((c) => /^WorkingSetSize$/i.test(c));
|
|
218
|
+
if (iPid < 0 || iPpid < 0 || iRss < 0) return null;
|
|
219
|
+
const rows = [];
|
|
220
|
+
for (const l of lines) {
|
|
221
|
+
if (l === header || /ProcessId/i.test(l)) continue;
|
|
222
|
+
const f = l.split(",");
|
|
223
|
+
const pid = Number(f[iPid]);
|
|
224
|
+
const ppid = Number(f[iPpid]);
|
|
225
|
+
const val = Number(f[iRss]);
|
|
226
|
+
if (Number.isFinite(pid))
|
|
227
|
+
rows.push({ pid, ppid, val: Number.isFinite(val) ? val : 0 });
|
|
228
|
+
}
|
|
229
|
+
return sumSubtreeRss(rows, rootPid);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Sum `val` over `rootPid` and all its transitive descendants. */
|
|
233
|
+
export function sumSubtreeRss(rows, rootPid) {
|
|
234
|
+
const childrenOf = new Map();
|
|
235
|
+
const valOf = new Map();
|
|
236
|
+
for (const r of rows) {
|
|
237
|
+
valOf.set(r.pid, r.val);
|
|
238
|
+
if (!childrenOf.has(r.ppid)) childrenOf.set(r.ppid, []);
|
|
239
|
+
childrenOf.get(r.ppid).push(r.pid);
|
|
240
|
+
}
|
|
241
|
+
if (!valOf.has(rootPid)) return null;
|
|
242
|
+
let total = 0;
|
|
243
|
+
const seen = new Set();
|
|
244
|
+
const stack = [rootPid];
|
|
245
|
+
while (stack.length) {
|
|
246
|
+
const p = stack.pop();
|
|
247
|
+
if (seen.has(p)) continue;
|
|
248
|
+
seen.add(p);
|
|
249
|
+
total += valOf.get(p) || 0;
|
|
250
|
+
for (const c of childrenOf.get(p) || []) stack.push(c);
|
|
251
|
+
}
|
|
252
|
+
return total;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function round1(x) {
|
|
256
|
+
return Math.round(x * 10) / 10;
|
|
257
|
+
}
|
|
@@ -57,6 +57,11 @@ export class LSPClient extends EventEmitter {
|
|
|
57
57
|
return Boolean(this._child) && !this._closed;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
/** OS pid of the language-server process, or null before start / after exit. */
|
|
61
|
+
get pid() {
|
|
62
|
+
return this._child ? (this._child.pid ?? null) : null;
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
/** Spawn the process and run the initialize handshake. Resolves when ready. */
|
|
61
66
|
async start({ initTimeoutMs = DEFAULT_INIT_TIMEOUT_MS } = {}) {
|
|
62
67
|
if (this._child) throw new Error("LSPClient already started");
|
|
@@ -100,15 +105,31 @@ export class LSPClient extends EventEmitter {
|
|
|
100
105
|
this.emit("stderr", chunk.toString("utf8"));
|
|
101
106
|
});
|
|
102
107
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
try {
|
|
109
|
+
const initResult = await this.request(
|
|
110
|
+
"initialize",
|
|
111
|
+
this._initializeParams(),
|
|
112
|
+
{ timeoutMs: initTimeoutMs },
|
|
113
|
+
);
|
|
114
|
+
this.serverCapabilities = initResult?.capabilities || {};
|
|
115
|
+
this.notify("initialized", {});
|
|
116
|
+
this._initialized = true;
|
|
117
|
+
return this.serverCapabilities;
|
|
118
|
+
} catch (err) {
|
|
119
|
+
// The process spawned but the initialize handshake failed or timed out (a
|
|
120
|
+
// hung/slow/broken server). Don't leave it orphaned: an init HANG never
|
|
121
|
+
// fires 'exit', and the manager's crash-loop guard only counts exits, so
|
|
122
|
+
// the process would linger forever holding a port/file locks. Tear it down
|
|
123
|
+
// before rethrowing so the caller's failure path doesn't leak a server.
|
|
124
|
+
this._closed = true;
|
|
125
|
+
this._failAll(err);
|
|
126
|
+
try {
|
|
127
|
+
this._child.kill();
|
|
128
|
+
} catch {
|
|
129
|
+
/* already dead */
|
|
130
|
+
}
|
|
131
|
+
throw err;
|
|
132
|
+
}
|
|
112
133
|
}
|
|
113
134
|
|
|
114
135
|
_initializeParams() {
|
|
@@ -39,6 +39,16 @@ export class LSPManager {
|
|
|
39
39
|
this.projectRoot = opts.projectRoot || process.cwd();
|
|
40
40
|
/** key `${root}::${serverId}` → { client, languageId, root, restarts } */
|
|
41
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();
|
|
42
52
|
/** open document uri → { version, languageId } */
|
|
43
53
|
this._openDocs = new Map();
|
|
44
54
|
/** uri → latest diagnostics array */
|
|
@@ -115,7 +125,7 @@ export class LSPManager {
|
|
|
115
125
|
quarantined: true,
|
|
116
126
|
};
|
|
117
127
|
}
|
|
118
|
-
entry = await this.
|
|
128
|
+
entry = await this._getOrStartServer(key, resolved, projectRoot);
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
const uri = pathToFileUri(abs);
|
|
@@ -152,6 +162,22 @@ export class LSPManager {
|
|
|
152
162
|
});
|
|
153
163
|
}
|
|
154
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
|
+
|
|
155
181
|
async _startServer(key, resolved, projectRoot) {
|
|
156
182
|
const client = _deps.createClient({
|
|
157
183
|
command: resolved.command,
|
|
@@ -184,8 +210,21 @@ export class LSPManager {
|
|
|
184
210
|
const log = this._crashLog.get(key) || [];
|
|
185
211
|
log.push(this._now());
|
|
186
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.)
|
|
187
221
|
for (const [uri, meta] of this._openDocs) {
|
|
188
|
-
if (meta.root === projectRoot)
|
|
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
|
+
}
|
|
189
228
|
}
|
|
190
229
|
});
|
|
191
230
|
await client.start();
|
|
@@ -305,6 +344,19 @@ export class LSPManager {
|
|
|
305
344
|
get activeServerCount() {
|
|
306
345
|
return this._servers.size;
|
|
307
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
|
+
}
|
|
308
360
|
}
|
|
309
361
|
|
|
310
362
|
// ---- position helpers (the ONLY place that converts between coordinate spaces) ----
|
|
@@ -70,6 +70,13 @@ function tsServer() {
|
|
|
70
70
|
// Registry of plugin-contributed servers, keyed by languageId. Wins over
|
|
71
71
|
// builtins if a plugin explicitly overrides.
|
|
72
72
|
const pluginServers = new Map();
|
|
73
|
+
// Plugin-contributed extension→languageId overrides, kept SEPARATE from the
|
|
74
|
+
// builtin EXTENSION_LANGUAGE map so `_resetPluginServers` (used by
|
|
75
|
+
// `/reload-plugins`) can fully roll them back. Mutating the builtin map
|
|
76
|
+
// directly meant an uninstalled/untrusted plugin's `.py`→"mylang" remap
|
|
77
|
+
// survived a reload — languageIdForFile kept returning the dead languageId and
|
|
78
|
+
// the builtin server for that extension became unreachable until process exit.
|
|
79
|
+
const pluginExtensions = new Map();
|
|
73
80
|
|
|
74
81
|
/**
|
|
75
82
|
* Register an extra language server (from a plugin `.lsp.json`).
|
|
@@ -87,21 +94,25 @@ export function registerLanguageServer(def) {
|
|
|
87
94
|
});
|
|
88
95
|
if (Array.isArray(def.extensions)) {
|
|
89
96
|
for (const ext of def.extensions) {
|
|
90
|
-
|
|
91
|
-
|
|
97
|
+
pluginExtensions.set(
|
|
98
|
+
ext.startsWith(".") ? ext : "." + ext,
|
|
99
|
+
def.languageId,
|
|
100
|
+
);
|
|
92
101
|
}
|
|
93
102
|
}
|
|
94
103
|
}
|
|
95
104
|
|
|
96
|
-
/** Test/reset hook — clears plugin registrations. */
|
|
105
|
+
/** Test/reset hook — clears plugin registrations (servers AND extension maps). */
|
|
97
106
|
export function _resetPluginServers() {
|
|
98
107
|
pluginServers.clear();
|
|
108
|
+
pluginExtensions.clear();
|
|
99
109
|
}
|
|
100
110
|
|
|
101
111
|
/** Map a file path to its LSP languageId, or null if unsupported. */
|
|
102
112
|
export function languageIdForFile(filePath) {
|
|
103
113
|
const ext = path.extname(String(filePath || "")).toLowerCase();
|
|
104
|
-
|
|
114
|
+
// Plugin overrides win over builtins (same precedence as pluginServers).
|
|
115
|
+
return pluginExtensions.get(ext) || EXTENSION_LANGUAGE[ext] || null;
|
|
105
116
|
}
|
|
106
117
|
|
|
107
118
|
/**
|
package/src/lib/matrix-bridge.js
CHANGED
|
@@ -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
|
-
|
|
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
|
)
|
package/src/lib/nostr-bridge.js
CHANGED
|
@@ -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
|
|
291
|
-
const grants = allGrants.filter((g) =>
|
|
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
|
|
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
|