chainlesschain 0.162.149 → 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.
- package/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-BJif14yR.js → AIOps-CBLvrjeG.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CXek6gJY.js → ActionButton-DYv2GtE0.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BgQhdAJi.js → Analytics-CL6PZ-Ww.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DTYl5NtR.js → AppLayout-xuyHt4uA.js} +3 -3
- package/src/assets/web-panel/assets/{Audit-BzATQAeR.js → Audit-DOvSVycq.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BzdPEQhL.js → Backup-DMhfTswr.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BM0KVh8E.js → BaseInput-CQxDdm63.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-D7fHXHkz.js → Chat-BEeNhK2a.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Wm34RR-b.js → ChatBubbleRenderer-8nul8eTq.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CAiSQ9vO.js → Checkbox-CL04O-ER.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Df40CrEe.js → Codegen-C50o-n7x.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DIT2fNFU.js → Col-CH-bDkzs.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CSTIbW2k.js → Community-DqAIMvSe.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DtqXZZUi.js → Compact-C43fo_my.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CUtzw6o7.js → Compliance-BERnMrdP.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CezmlnmU.js → Cowork-Baw3w1gp.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-P4BITarg.js → Cron-BEqAHF1-.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BRRiYwvq.js → Crosschain-CvnmKwK4.js} +1 -1
- package/src/assets/web-panel/assets/{DID-L5ijB9i4.js → DID-iMPxgVdt.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CFxro4ob.js → Dashboard--4SJX3YR.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BmAFCQ71.js → Dropdown-BgLV6xgz.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DJBCEuon.js → EmailListRenderer-Bvb8oUD8.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-z4oLq6eT.js → FamilyGuardDashboard-DpXPjJB5.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DsVCpHMF.js → Federation-BbFfJ1Xi.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DP3bP5th.js → FormItemContext-DeGq1B-q.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BAXP2Gc6.js → GenericCardRenderer-CNW7s9zM.js} +1 -1
- package/src/assets/web-panel/assets/{Git-I3g_bAw9.js → Git-L1PjW-lT.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-jHS5-ioS.js → Governance-PK-X58to.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CPL7sfx9.js → Inference-BePWEH-d.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Jf236h4C.js → KnowledgeGraph-LF_sBvdL.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Cm2tcSKg.js → Logs-BKkfk9hy.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-CZK82rhi.js → Marketplace-BNMqUDla.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CZCeji7a.js → McpTools-w4WPiyz2.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-3l2KVS9k.js → Memory-DUKMVGNi.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-VYdpoLh6.js → MobileBridge-BWhiEyTJ.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CiB9cmm1.js → MobileProjects-Ocf5JEkX.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-wCFZbBuL.js → Mtc-D2B6MMhU.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-1a3THIyG.js → MtcAudit-DdYjCq1O.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DMzLB2hG.js → Multisig-Cb1hfuUZ.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-D9wZbf6l.js → NLProgramming-CTeImGp7.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-hrFe2ZM-.js → Notes-BjYNc7eQ.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-CHGX5Jwm.js → NotificationSettings-Dn_NtRXQ.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-DVYYIizh.js +1 -0
- package/src/assets/web-panel/assets/{Organization-By7FkhtY.js → Organization-Be2Kmr5j.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow--khGSzJn.js → Overflow-Cu_-qRlR.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CAG9dH35.js → P2P-DD2HoGzE.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-B3SQZmK9.js → PdhVaultBrowser-BRI7DVth.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-D35ec6JA.js → Permissions-C9Srcs2M.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-CxBF7hW_.js → PersonalDataHub-CUqcMgo1.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-s6EtOO1s.js → Pipeline-HBrQGLXt.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BbJYmWmO.js → Privacy-D-B0vjwh.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-VGQq1jMT.js → ProjectInit-eTeLIu9e.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-B1ew3Teh.js → ProjectSettings-DrRqCsC6.js} +2 -2
- package/src/assets/web-panel/assets/Projects-1G9DNOhI.js +1 -0
- package/src/assets/web-panel/assets/{Providers-mrO47FIK.js → Providers-RkTZzpxP.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-IJF2mHyw.js → QrScannerModal-BSCUgsgC.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CU0wN_Z0.js → QuickAsk-CHgyM3Bz.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DhN37R6G.js → Recommend-0lry4OZq.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-D_xOX_hu.js → RemoteSession-Cn45UroZ.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-D_Ssv7uH.js → Reputation-Q-Zjb707.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Kx5dKxX7.js → Row-BdM70oda.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BlGwqZkY.js → RssFeed-DmOAKKap.js} +2 -2
- package/src/assets/web-panel/assets/{Search-hLFQzxpb.js → Search-Dwavbm07.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DMlvsVt4.js → Security-DukXFCnk.js} +3 -3
- package/src/assets/web-panel/assets/{Services-Bd0Qsj2m.js → Services-BIlRnITu.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DFclq9X3.js → Skeleton-YYVQdhhQ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BNtln2qY.js → Skills-B8_iYHz2.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Dch5H19G.js → Sla-BdVrhT31.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-2UfQcU1g.js → SpeechSettings-CD3ggRx7.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CD9YQr4i.js → SyncSettings-Bp02VZFH.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BNu-7MzI.js → Tasks-DEVmCEsr.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D1n9CaIR.js → Templates-B6czWc4N.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DenL3iBW.js → Tenant-BCJLv17r.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-ZzU0Io1Y.js → Terminal-CD132d2Y.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-D87IfukO.js → TimelineRenderer-ZB-CvkZl.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BkiZc8E3.js → Tokens-BnSY0S-s.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BNRSytGN.js → Trigger-VZw9Oy2w.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-Bwbd4X2m.js → Trust-pZq7Hjd2.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B8O2bs0o.js → UkeySign-DnQaqk4q.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C2fL8zmH.js → VideoEditing-BEUfmvJV.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BORYDdE1.js → Wallet-CoZKMXJ2.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-C0V5S2FM.js → WebAuthn-CBOGVx1I.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-2dR0fcHL.js → WorkflowEditor-huSKn7TT.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BmuAFAn8.js → chat-A_3w6FBO.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CN3smMcK.js → colors-D1Bem9Oy.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DCnxb4kW.js → compact-item-CJYJj0oO.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-vlR43pHn.js → createContext-BkbFiKT4.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-WDr3_M_N.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D04tHYFd.js → hasIn-CKvUafVY.js} +1 -1
- package/src/assets/web-panel/assets/{index-0DnaZGkC.js → index-AjrSPnvv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BudvKQfG.js → index-B8i0lViZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BeGDEXFs.js → index-B9Svn0zc.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5LZVZ0L.js → index-BHdHSX06.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTPEZTk1.js → index-BHdailyo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIpY0qM5.js → index-BJwlEnYo.js} +1 -1
- package/src/assets/web-panel/assets/{index-CsAsCPJ6.js → index-BOoAQjJz.js} +1 -1
- package/src/assets/web-panel/assets/{index-ljuBiQW9.js → index-BSgWxAOG.js} +1 -1
- package/src/assets/web-panel/assets/{index-hpvvtAZ3.js → index-BdutMsne.js} +1 -1
- package/src/assets/web-panel/assets/{index-_FIkN3jd.js → index-BiDWxzbn.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-6NO5il.js → index-By5a0T_W.js} +1 -1
- package/src/assets/web-panel/assets/{index-B78xL3s2.js → index-C-WIY-FQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClhAHDK3.js → index-C37f6iey.js} +1 -1
- package/src/assets/web-panel/assets/{index-ToUh2b1-.js → index-C9bWmTcO.js} +1 -1
- package/src/assets/web-panel/assets/{index-D28DeAAB.js → index-CBaosWRO.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8vwp4qp.js → index-CBlBVJ_m.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqhASEL4.js → index-CD62EEGo.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDwLgQY9.js → index-CUj-l7GM.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbVsQBOH.js → index-CVS8Ymuq.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cr-A0FYJ.js → index-ChkXUj3f.js} +1 -1
- package/src/assets/web-panel/assets/{index-D65_XseV.js → index-Cj0OZ-37.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXRg8GFQ.js → index-Co3OFL0t.js} +1 -1
- package/src/assets/web-panel/assets/{index-430S68MN.js → index-Crp8CbRg.js} +1 -1
- package/src/assets/web-panel/assets/{index-CngCC8hC.js → index-D22zNXiS.js} +1 -1
- package/src/assets/web-panel/assets/{index-HhNjnCfe.js → index-DTs_D1OL.js} +1 -1
- package/src/assets/web-panel/assets/{index-CP9m9Ggr.js → index-DfgCdFrN.js} +3 -3
- package/src/assets/web-panel/assets/{index-jzR7Ujuw.js → index-DjYrecNb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTOCnIQ7.js → index-DpW9cf3e.js} +1 -1
- package/src/assets/web-panel/assets/index-Dwix3p4g.js +1 -0
- package/src/assets/web-panel/assets/{index-D_n8_vfI.js → index-F--HuPG1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BasvsWDM.js → index-Fuk6t_3K.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnXebZLL.js → index-JEAGMii9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYAtmqiv.js → index-PF-mpv8K.js} +1 -1
- package/src/assets/web-panel/assets/index-SHaoZ0CA.js +1 -0
- package/src/assets/web-panel/assets/{index-DTWg-18U.js → index-b-sbVdjQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5Sxb1sE.js → index-pyvMVX8r.js} +1 -1
- package/src/assets/web-panel/assets/{index-TslMTwNy.js → index-qNTtOVi_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTtRscUa.js → index-tgO8iza6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbADHwhr.js → index-ttDQVhZy.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C3wUb4je.js → initDefaultProps-DtrnfsZH.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D-jYFUNA.js → motion-D4zqSaX3.js} +1 -1
- package/src/assets/web-panel/assets/{move-tqb8nwJ2.js → move-CGFGOUQj.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DSOjMJMz.js → mtc-parser-DH2HvkJl.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CJ7VimIW.js → omit-jJ2at5HX.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-qXiG1iT3.js → pickAttrs-CRyMT1Fv.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CkGBcy1Z.js → placementArrow-DZ_CX0Pt.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-D3WvTlLO.js → responsiveObserve-wruHk-h5.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BEE2ftge.js → slide-BGgx8q67.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CsfBpxiG.js → statusUtils-Do5M7gKm.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-xPrIiJPI.js → styleChecker-CRa-GZpX.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C5Yd-SCR.js → useFlexGapSupport-BxPcq6pj.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-D_MDS8HI.js → useFs-v5O2ZcJm.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BqJh-usA.js → usePersonalDataHub--z2FU0Px.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-chm_p-gz.js → vnode-1emidVKd.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-3-YDNz0Z.js → zoom-CcJaRyHs.js} +1 -1
- package/src/assets/web-panel/index.html +1 -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/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/gateways/ws/message-dispatcher.js +5 -2
- package/src/gateways/ws/remote-session-protocol.js +103 -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/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/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/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/install.js +9 -1
- package/src/lib/plugin-runtime/policy.js +9 -1
- package/src/lib/plugin-runtime/remote-source.js +240 -0
- package/src/lib/pqc-manager.js +64 -0
- package/src/lib/reputation-optimizer.js +101 -0
- package/src/lib/sandbox-egress-proxy.js +159 -59
- package/src/lib/sandbox-fs-policy.js +112 -0
- package/src/lib/sandbox-network-policy.js +18 -1
- 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/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/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
package/src/lib/logger.js
CHANGED
|
@@ -24,7 +24,10 @@ export function success(message, ...args) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export function warn(message, ...args) {
|
|
27
|
-
|
|
27
|
+
// stderr, not stdout: a warning must never interleave with a command's
|
|
28
|
+
// machine-readable stdout (e.g. `--json` payloads), which `| jq` and other
|
|
29
|
+
// consumers parse. Like error(), warn is never gated by quiet mode.
|
|
30
|
+
console.error(chalk.yellow("⚠"), message, ...args);
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
export function error(message, ...args) {
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* benchmark stats tests — the pure percentile/summarize helpers that turn raw
|
|
3
|
+
* latency samples into a report. No spawning; the harness itself is exercised by
|
|
4
|
+
* the live `cc code-intel bench` run.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect } from "vitest";
|
|
8
|
+
import {
|
|
9
|
+
percentile,
|
|
10
|
+
summarize,
|
|
11
|
+
sumSubtreeRss,
|
|
12
|
+
sumSubtreeRssFromWmicCsv,
|
|
13
|
+
} from "../benchmark.js";
|
|
14
|
+
|
|
15
|
+
describe("percentile", () => {
|
|
16
|
+
it("returns the value for a single sample", () => {
|
|
17
|
+
expect(percentile([5], 50)).toBe(5);
|
|
18
|
+
expect(percentile([5], 95)).toBe(5);
|
|
19
|
+
});
|
|
20
|
+
it("computes median and p95 with interpolation", () => {
|
|
21
|
+
const s = [10, 20, 30, 40, 50];
|
|
22
|
+
expect(percentile(s, 50)).toBe(30);
|
|
23
|
+
// p95 of 5 points: rank = 0.95*4 = 3.8 → 40 + (50-40)*0.8 = 48
|
|
24
|
+
expect(percentile(s, 95)).toBeCloseTo(48, 5);
|
|
25
|
+
});
|
|
26
|
+
it("is order-independent (sorts internally)", () => {
|
|
27
|
+
expect(percentile([50, 10, 30, 40, 20], 50)).toBe(30);
|
|
28
|
+
});
|
|
29
|
+
it("returns null for an empty sample", () => {
|
|
30
|
+
expect(percentile([], 50)).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("summarize", () => {
|
|
35
|
+
it("reports n/min/median/p95/max/mean rounded to 0.1ms", () => {
|
|
36
|
+
const s = summarize([12.34, 5.6, 8.9, 20.1, 3.33]);
|
|
37
|
+
expect(s.n).toBe(5);
|
|
38
|
+
expect(s.min).toBe(3.3);
|
|
39
|
+
expect(s.max).toBe(20.1);
|
|
40
|
+
expect(s.median).toBe(8.9);
|
|
41
|
+
expect(s.mean).toBe(10.1); // (12.34+5.6+8.9+20.1+3.33)/5 = 10.054 → 10.1
|
|
42
|
+
});
|
|
43
|
+
it("handles an empty sample", () => {
|
|
44
|
+
expect(summarize([])).toEqual({ n: 0 });
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("sumSubtreeRss", () => {
|
|
49
|
+
// launcher(100) → node server(200) → worker(300); sibling(400) unrelated
|
|
50
|
+
const rows = [
|
|
51
|
+
{ pid: 100, ppid: 1, val: 5 },
|
|
52
|
+
{ pid: 200, ppid: 100, val: 120 },
|
|
53
|
+
{ pid: 300, ppid: 200, val: 40 },
|
|
54
|
+
{ pid: 400, ppid: 1, val: 999 },
|
|
55
|
+
];
|
|
56
|
+
it("sums a pid and all its transitive descendants (not the launcher alone)", () => {
|
|
57
|
+
expect(sumSubtreeRss(rows, 100)).toBe(165); // 5 + 120 + 40
|
|
58
|
+
});
|
|
59
|
+
it("returns just the leaf when it has no children", () => {
|
|
60
|
+
expect(sumSubtreeRss(rows, 300)).toBe(40);
|
|
61
|
+
});
|
|
62
|
+
it("returns null when the root pid is absent", () => {
|
|
63
|
+
expect(sumSubtreeRss(rows, 555)).toBeNull();
|
|
64
|
+
});
|
|
65
|
+
it("does not loop on a cyclic parent relationship", () => {
|
|
66
|
+
const cyclic = [
|
|
67
|
+
{ pid: 1, ppid: 2, val: 10 },
|
|
68
|
+
{ pid: 2, ppid: 1, val: 20 },
|
|
69
|
+
];
|
|
70
|
+
expect(sumSubtreeRss(cyclic, 1)).toBe(30);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("sumSubtreeRssFromWmicCsv", () => {
|
|
75
|
+
it("parses wmic CSV and sums the subtree in bytes", () => {
|
|
76
|
+
const csv = [
|
|
77
|
+
"Node,ParentProcessId,ProcessId,WorkingSetSize",
|
|
78
|
+
"HOST,1,100,5000",
|
|
79
|
+
"HOST,100,200,120000",
|
|
80
|
+
"HOST,200,300,40000",
|
|
81
|
+
"HOST,1,400,999000",
|
|
82
|
+
].join("\r\n");
|
|
83
|
+
expect(sumSubtreeRssFromWmicCsv(csv, 100)).toBe(165000);
|
|
84
|
+
});
|
|
85
|
+
it("returns null on malformed input", () => {
|
|
86
|
+
expect(sumSubtreeRssFromWmicCsv("garbage\r\n", 100)).toBeNull();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
@@ -90,6 +90,17 @@ describe("LSPClient handshake", () => {
|
|
|
90
90
|
expect.objectContaining({ shell: false }),
|
|
91
91
|
);
|
|
92
92
|
});
|
|
93
|
+
|
|
94
|
+
it("kills the spawned server when the initialize handshake times out (no orphan)", async () => {
|
|
95
|
+
const child = new FakeChild({ autoInit: false }); // never answers initialize
|
|
96
|
+
const client = makeClient(child);
|
|
97
|
+
await expect(client.start({ initTimeoutMs: 20 })).rejects.toThrow(
|
|
98
|
+
/timed out/,
|
|
99
|
+
);
|
|
100
|
+
// The spawned process must be torn down, not left running forever.
|
|
101
|
+
expect(child.killed).toBe(true);
|
|
102
|
+
expect(client.running).toBe(false);
|
|
103
|
+
});
|
|
93
104
|
});
|
|
94
105
|
|
|
95
106
|
describe("LSPClient request/response", () => {
|
|
@@ -141,6 +141,38 @@ describe("ensureFor", () => {
|
|
|
141
141
|
await mgr.disposeAll();
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
+
it("spawns only ONE server when two concurrent calls race the same key", async () => {
|
|
145
|
+
// Regression: ensureFor did Map.get(miss)→await start→Map.set with no
|
|
146
|
+
// in-flight dedupe, so two concurrent calls (the read-only agent batch fires
|
|
147
|
+
// several code_intelligence calls at once) both spawned a server; the second
|
|
148
|
+
// set() orphaned the first process. Gate start() so both calls interleave
|
|
149
|
+
// inside the await window, then assert a single spawn.
|
|
150
|
+
let created = 0;
|
|
151
|
+
let releaseStart;
|
|
152
|
+
const gate = new Promise((r) => {
|
|
153
|
+
releaseStart = r;
|
|
154
|
+
});
|
|
155
|
+
_deps.createClient = (opts) => {
|
|
156
|
+
created += 1;
|
|
157
|
+
lastClient = new FakeClient(opts);
|
|
158
|
+
const origStart = lastClient.start.bind(lastClient);
|
|
159
|
+
lastClient.start = async () => {
|
|
160
|
+
await gate; // hold both starts open until released
|
|
161
|
+
return origStart();
|
|
162
|
+
};
|
|
163
|
+
return lastClient;
|
|
164
|
+
};
|
|
165
|
+
const mgr = new LSPManager();
|
|
166
|
+
const p1 = mgr.ensureFor("/proj/src/a.ts");
|
|
167
|
+
const p2 = mgr.ensureFor("/proj/src/b.ts");
|
|
168
|
+
releaseStart();
|
|
169
|
+
const [r1, r2] = await Promise.all([p1, p2]);
|
|
170
|
+
expect(created).toBe(1); // NOT two — the race is deduped
|
|
171
|
+
expect(mgr.activeServerCount).toBe(1);
|
|
172
|
+
expect(r1.client).toBe(r2.client);
|
|
173
|
+
await mgr.disposeAll();
|
|
174
|
+
});
|
|
175
|
+
|
|
144
176
|
it("returns unavailable for an unsupported extension", async () => {
|
|
145
177
|
const mgr = new LSPManager();
|
|
146
178
|
const ready = await mgr.ensureFor("/proj/readme.txt");
|
|
@@ -251,6 +283,43 @@ describe("diagnostics", () => {
|
|
|
251
283
|
expect(diags[0].message).toBe("boom");
|
|
252
284
|
await mgr.disposeAll();
|
|
253
285
|
});
|
|
286
|
+
|
|
287
|
+
it("clears stale diagnostics + readiness state when the server crashes", async () => {
|
|
288
|
+
const { pathToFileUri } = await import("../lsp-client.js");
|
|
289
|
+
const mgr = new LSPManager();
|
|
290
|
+
await mgr.ensureFor("/proj/src/a.ts");
|
|
291
|
+
lastClient.emit("notify:textDocument/publishDiagnostics", {
|
|
292
|
+
uri: pathToFileUri(path.resolve("/proj/src/a.ts")),
|
|
293
|
+
diagnostics: [
|
|
294
|
+
{
|
|
295
|
+
message: "boom",
|
|
296
|
+
severity: 1,
|
|
297
|
+
range: {
|
|
298
|
+
start: { line: 0, character: 0 },
|
|
299
|
+
end: { line: 0, character: 1 },
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
],
|
|
303
|
+
});
|
|
304
|
+
expect(mgr.getDiagnostics("/proj/src/a.ts")).toHaveLength(1);
|
|
305
|
+
|
|
306
|
+
// Server crashes. Its diagnostics + publish bookkeeping must NOT survive —
|
|
307
|
+
// otherwise the readiness waiters resolve on the pre-crash publish and a
|
|
308
|
+
// post-restart query returns these stale results.
|
|
309
|
+
lastClient.running = false;
|
|
310
|
+
lastClient.emit("exit", 1, null);
|
|
311
|
+
expect(mgr.getDiagnostics("/proj/src/a.ts")).toEqual([]);
|
|
312
|
+
|
|
313
|
+
// A fresh query re-spawns the server; before it publishes, waitForDiagnostics
|
|
314
|
+
// must not hand back the stale set (returns empty within the timeout budget).
|
|
315
|
+
await mgr.ensureFor("/proj/src/a.ts");
|
|
316
|
+
const afterRestart = await mgr.waitForDiagnostics("/proj/src/a.ts", {
|
|
317
|
+
timeoutMs: 60,
|
|
318
|
+
settleMs: 20,
|
|
319
|
+
});
|
|
320
|
+
expect(afterRestart).toEqual([]);
|
|
321
|
+
await mgr.disposeAll();
|
|
322
|
+
});
|
|
254
323
|
});
|
|
255
324
|
|
|
256
325
|
describe("disposeAll", () => {
|
|
@@ -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) ----
|
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) {
|