chainlesschain 0.162.148 → 0.162.150
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-DwpCCp64.js → AIOps-CBLvrjeG.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-C9pBYocA.js → ActionButton-DYv2GtE0.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BWAkeXxK.js → Analytics-CL6PZ-Ww.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CivFGH6B.js → AppLayout-xuyHt4uA.js} +3 -3
- package/src/assets/web-panel/assets/{Audit-Cm8hRpZm.js → Audit-DOvSVycq.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DXdFMsE8.js → Backup-DMhfTswr.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-uAwSTeql.js → BaseInput-CQxDdm63.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-KU8eeJJE.js → Chat-BEeNhK2a.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-8nul8eTq.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-C6AMDkjd.js → Checkbox-CL04O-ER.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-t2moDxcO.js → Codegen-C50o-n7x.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DCcsRRhN.js → Col-CH-bDkzs.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DtB-8SAC.js → Community-DqAIMvSe.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CZm8THYA.js → Compact-C43fo_my.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-LiQgC7g1.js → Compliance-BERnMrdP.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CA8SAxht.js → Cowork-Baw3w1gp.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-CtRaF1wD.js → Cron-BEqAHF1-.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-6-br6Hub.js → Crosschain-CvnmKwK4.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Do2EccrL.js → DID-iMPxgVdt.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-wrXcbzGe.js → Dashboard--4SJX3YR.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-p3FsT245.js → Dropdown-BgLV6xgz.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-D95A2L8q.js → EmailListRenderer-Bvb8oUD8.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-cLuJW2zo.js → FamilyGuardDashboard-DpXPjJB5.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Brgq_cbN.js → Federation-BbFfJ1Xi.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DWLCkNgh.js → FormItemContext-DeGq1B-q.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BBqUfQd6.js → GenericCardRenderer-CNW7s9zM.js} +1 -1
- package/src/assets/web-panel/assets/{Git-8F090w4I.js → Git-L1PjW-lT.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CCogEbxb.js → Governance-PK-X58to.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CfLD7v7C.js → Inference-BePWEH-d.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DDuHJewd.js → KnowledgeGraph-LF_sBvdL.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CE8KSEVC.js → Logs-BKkfk9hy.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-DmwpZmhT.js → Marketplace-BNMqUDla.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Bf7AazU8.js → McpTools-w4WPiyz2.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-D0QU_00S.js → Memory-DUKMVGNi.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-yXS9xdhx.js → MobileBridge-BWhiEyTJ.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BuDUoGUP.js → MobileProjects-Ocf5JEkX.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BYyHy28p.js → Mtc-D2B6MMhU.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-CK0aqpiZ.js → MtcAudit-DdYjCq1O.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-mNimKYeb.js → Multisig-Cb1hfuUZ.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-AioAJ0YA.js → NLProgramming-CTeImGp7.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CVVNCLHE.js → Notes-BjYNc7eQ.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-C4ABj-TK.js → NotificationSettings-Dn_NtRXQ.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DIp8Xcbd.js → OrderTableRenderer-DVYYIizh.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-uozl_gWK.js → Organization-Be2Kmr5j.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BCZOM2hK.js → Overflow-Cu_-qRlR.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CArcaiaj.js → P2P-DD2HoGzE.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Sgq2Srr8.js → PdhVaultBrowser-BRI7DVth.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BYrQrXnH.js → Permissions-C9Srcs2M.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-BzHStAbz.js → PersonalDataHub-CUqcMgo1.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-k7KqxX1M.js → Pipeline-HBrQGLXt.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-IumTUWqx.js → Privacy-D-B0vjwh.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BRyImYTf.js → ProjectInit-eTeLIu9e.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BFIqTBFk.js → ProjectSettings-DrRqCsC6.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Dpid9CDg.js → Projects-1G9DNOhI.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-CyyFnUPs.js → Providers-RkTZzpxP.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-C82cRx-X.js → QrScannerModal-BSCUgsgC.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DGxDF521.js → QuickAsk-CHgyM3Bz.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Cns-Am1y.js → Recommend-0lry4OZq.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-R7OqAIlg.js → RemoteSession-Cn45UroZ.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-D7mgPIYV.js → Reputation-Q-Zjb707.js} +1 -1
- package/src/assets/web-panel/assets/{Row-B3lEURyd.js → Row-BdM70oda.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-9_UVrpBt.js → RssFeed-DmOAKKap.js} +2 -2
- package/src/assets/web-panel/assets/{Search-ClZeO80q.js → Search-Dwavbm07.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BNNJczEp.js → Security-DukXFCnk.js} +3 -3
- package/src/assets/web-panel/assets/{Services-C5SjrWUj.js → Services-BIlRnITu.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Ci_obQ-g.js → Skeleton-YYVQdhhQ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DdebN15P.js → Skills-B8_iYHz2.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-OinZP2vi.js → Sla-BdVrhT31.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CxzbNF51.js → SpeechSettings-CD3ggRx7.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-D06N_66b.js → SyncSettings-Bp02VZFH.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BdEdW0AZ.js → Tasks-DEVmCEsr.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-F1ctKmPa.js → Templates-B6czWc4N.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CVz1Urot.js → Tenant-BCJLv17r.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-CD132d2Y.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-Doitzjmf.js → TimelineRenderer-ZB-CvkZl.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BpyVRpVA.js → Tokens-BnSY0S-s.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-nWhWYTbU.js → Trigger-VZw9Oy2w.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DK_G-wLx.js → Trust-pZq7Hjd2.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B5yBUojO.js → UkeySign-DnQaqk4q.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C5D51qAe.js → VideoEditing-BEUfmvJV.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CLbL9K7v.js → Wallet-CoZKMXJ2.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DZUelI3V.js → WebAuthn-CBOGVx1I.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-8RPxt4KW.js → WorkflowEditor-huSKn7TT.js} +1 -1
- package/src/assets/web-panel/assets/{chat-4N4tOA3d.js → chat-A_3w6FBO.js} +1 -1
- package/src/assets/web-panel/assets/{colors-zbbGVrua.js → colors-D1Bem9Oy.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-D7iMkbnE.js → compact-item-CJYJj0oO.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CBzPJv-w.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-bHdrQSqZ.js → hasIn-CKvUafVY.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbE5D0WL.js → index-AjrSPnvv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCr0geV9.js → index-B8i0lViZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiG1IZao.js → index-B9Svn0zc.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1s0Bz9O.js → index-BHdHSX06.js} +1 -1
- package/src/assets/web-panel/assets/{index-QFObYeo1.js → index-BHdailyo.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnBOpqv3.js → index-BJwlEnYo.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdmMoYN1.js → index-BOoAQjJz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUyjUkY7.js → index-BSgWxAOG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqdPyWm5.js → index-BdutMsne.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmqlJed-.js → index-BiDWxzbn.js} +1 -1
- package/src/assets/web-panel/assets/{index-S74FpAIn.js → index-By5a0T_W.js} +1 -1
- package/src/assets/web-panel/assets/{index-kmh1TxRa.js → index-C-WIY-FQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTIjjXry.js → index-C37f6iey.js} +1 -1
- package/src/assets/web-panel/assets/{index-BS4_Mwk6.js → index-C9bWmTcO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBNr77E1.js → index-CBaosWRO.js} +1 -1
- package/src/assets/web-panel/assets/{index-QNAG4JtR.js → index-CBlBVJ_m.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqmx24kh.js → index-CD62EEGo.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQfu1U78.js → index-CUj-l7GM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJ4ZGyW0.js → index-CVS8Ymuq.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ci009ijp.js → index-ChkXUj3f.js} +1 -1
- package/src/assets/web-panel/assets/{index-oDKNgCsP.js → index-Cj0OZ-37.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZb8F8YG.js → index-Co3OFL0t.js} +1 -1
- package/src/assets/web-panel/assets/{index-308gCGh7.js → index-Crp8CbRg.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPxkoKgA.js → index-D22zNXiS.js} +1 -1
- package/src/assets/web-panel/assets/{index-xYCm6W2h.js → index-DTs_D1OL.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtbbdLnf.js → index-DfgCdFrN.js} +3 -3
- package/src/assets/web-panel/assets/{index-BsKehmmS.js → index-DjYrecNb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkxK86vf.js → index-DpW9cf3e.js} +1 -1
- package/src/assets/web-panel/assets/index-Dwix3p4g.js +1 -0
- package/src/assets/web-panel/assets/{index-CvRMA9uT.js → index-F--HuPG1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE9j5YgT.js → index-Fuk6t_3K.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7b1hGry.js → index-JEAGMii9.js} +1 -1
- package/src/assets/web-panel/assets/{index-D1YDh7Wr.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-CQ6NcfWz.js → index-b-sbVdjQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyoNgbXl.js → index-pyvMVX8r.js} +1 -1
- package/src/assets/web-panel/assets/{index-DISWAYce.js → index-qNTtOVi_.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4XKpj6c.js → index-tgO8iza6.js} +1 -1
- package/src/assets/web-panel/assets/{index-CahryTX0.js → index-ttDQVhZy.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BD55yNBt.js → initDefaultProps-DtrnfsZH.js} +1 -1
- package/src/assets/web-panel/assets/{motion-B5Bbe77U.js → motion-D4zqSaX3.js} +1 -1
- package/src/assets/web-panel/assets/{move-CTvIqHEH.js → move-CGFGOUQj.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BkNyPQKB.js → mtc-parser-DH2HvkJl.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BaXJXgHA.js → omit-jJ2at5HX.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Bw6-YTxH.js → pickAttrs-CRyMT1Fv.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BLdbkLqJ.js → placementArrow-DZ_CX0Pt.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-IVYkzntU.js → responsiveObserve-wruHk-h5.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DFMFwwtY.js → slide-BGgx8q67.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CURYRtZ1.js → statusUtils-Do5M7gKm.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Cfz63s1r.js → styleChecker-CRa-GZpX.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-COJL0KE3.js → useFlexGapSupport-BxPcq6pj.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-YLLojQQf.js → useFs-v5O2ZcJm.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BF_21qUC.js → usePersonalDataHub--z2FU0Px.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-9ZpkA7bb.js → vnode-1emidVKd.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DhtAfhl8.js → zoom-CcJaRyHs.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/assets/web-panel/remote-session-sw.js +43 -0
- package/src/command-manifest.json +22 -1
- package/src/commands/a2a.js +19 -4
- package/src/commands/activitypub.js +20 -3
- package/src/commands/agent.js +71 -10
- package/src/commands/audit.js +40 -24
- package/src/commands/codeintel.js +320 -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 +255 -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 +474 -0
- 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 +463 -0
- 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 +48 -2
- package/src/gateways/ws/remote-session-protocol.js +140 -42
- package/src/gateways/ws/ws-server.js +1 -1
- package/src/harness/jsonl-session-store.js +12 -5
- package/src/harness/plugin-manager.js +16 -4
- package/src/harness/prompt-compressor.js +27 -1
- package/src/harness/remote-command-ledger.js +189 -0
- package/src/harness/remote-session-push-apns.js +246 -0
- package/src/harness/remote-session-push-errors.js +15 -0
- package/src/harness/remote-session-push-fcm.js +9 -25
- package/src/harness/remote-session-push-huawei.js +174 -0
- package/src/harness/remote-session-push-oppo.js +171 -0
- package/src/harness/remote-session-push-senders.js +42 -0
- package/src/harness/remote-session-push-vivo.js +179 -0
- package/src/harness/remote-session-push-web.js +299 -0
- package/src/harness/remote-session-push-xiaomi.js +99 -0
- package/src/harness/worktree-isolator.js +16 -6
- package/src/index.js +6 -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 +4 -0
- package/src/lib/agent-economy.js +262 -29
- package/src/lib/agent-network.js +7 -1
- package/src/lib/agent-sandbox.js +161 -5
- package/src/lib/agent-team/task-lease.js +434 -0
- package/src/lib/agent-team/team-budget.js +165 -0
- package/src/lib/agent-team/team-mailbox.js +106 -0
- package/src/lib/agent-team/team-runner.js +282 -0
- package/src/lib/agent-team/team-worktree.js +236 -0
- package/src/lib/agents.js +18 -0
- package/src/lib/async-hook-supervisor.cjs +391 -0
- 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 +251 -0
- package/src/lib/eval/tasks.js +626 -0
- package/src/lib/eval/trend.js +200 -0
- 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__/code-intelligence.integration.test.js +129 -0
- package/src/lib/lsp/__tests__/code-intelligence.test.js +228 -0
- package/src/lib/lsp/__tests__/jsonrpc-stream.test.js +104 -0
- package/src/lib/lsp/__tests__/lsp-client.test.js +269 -0
- package/src/lib/lsp/__tests__/lsp-manager.test.js +333 -0
- package/src/lib/lsp/__tests__/lsp-server-registry.test.js +128 -0
- package/src/lib/lsp/benchmark.js +257 -0
- package/src/lib/lsp/code-intelligence.js +356 -0
- package/src/lib/lsp/jsonrpc-stream.js +139 -0
- package/src/lib/lsp/lsp-client.js +339 -0
- package/src/lib/lsp/lsp-manager.js +375 -0
- package/src/lib/lsp/lsp-server-registry.js +196 -0
- 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-monitor-supervisor.js +238 -0
- package/src/lib/plugin-runtime/__tests__/remote-source.test.js +256 -0
- package/src/lib/plugin-runtime/agents.js +51 -0
- package/src/lib/plugin-runtime/bin.js +100 -0
- package/src/lib/plugin-runtime/hooks.js +100 -0
- package/src/lib/plugin-runtime/install.js +396 -0
- package/src/lib/plugin-runtime/lsp.js +75 -0
- package/src/lib/plugin-runtime/manifest.js +458 -0
- package/src/lib/plugin-runtime/mcp.js +89 -0
- package/src/lib/plugin-runtime/monitors.js +100 -0
- package/src/lib/plugin-runtime/policy.js +152 -0
- package/src/lib/plugin-runtime/reload.js +79 -0
- package/src/lib/plugin-runtime/remote-source.js +240 -0
- package/src/lib/plugin-runtime/scopes.js +197 -0
- package/src/lib/plugin-runtime/settings.js +119 -0
- package/src/lib/plugin-runtime/signature.js +107 -0
- package/src/lib/plugin-runtime/skills.js +43 -0
- package/src/lib/plugin-runtime/trust.js +140 -0
- package/src/lib/pqc-manager.js +64 -0
- package/src/lib/reputation-optimizer.js +101 -0
- package/src/lib/sandbox-egress-proxy.js +262 -0
- package/src/lib/sandbox-fs-policy.js +112 -0
- package/src/lib/sandbox-network-policy.js +151 -0
- package/src/lib/sandbox-v2.js +24 -18
- package/src/lib/scim-manager.js +36 -0
- package/src/lib/session-manager.js +5 -2
- package/src/lib/settings-hook-events.cjs +78 -6
- package/src/lib/settings-hooks.cjs +30 -3
- package/src/lib/settings-loader.cjs +35 -1
- package/src/lib/siem-exporter.js +45 -0
- package/src/lib/skill-loader.js +38 -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 +237 -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 +417 -6
- package/src/runtime/__tests__/auto-pin.test.js +104 -0
- package/src/runtime/agent-core.js +771 -104
- package/src/runtime/auto-pin.js +117 -0
- package/src/runtime/coding-agent-contract-shared.cjs +82 -8
- package/src/runtime/coding-agent-policy.cjs +32 -7
- package/src/runtime/fallback-model.js +134 -7
- package/src/runtime/headless-runner.js +388 -108
- package/src/runtime/mcp-config.js +46 -0
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DCNfbdlx.js +0 -1
- package/src/assets/web-panel/assets/Terminal-BvAK_Zel.js +0 -3
- package/src/assets/web-panel/assets/devWarning-C2Z5LRgq.js +0 -1
- package/src/assets/web-panel/assets/index-BGp6Yr-Y.js +0 -1
- package/src/assets/web-panel/assets/index-BXiw9dQf.js +0 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin `bin` component — put a trusted plugin's executables on PATH for the
|
|
3
|
+
* session (Phase 3.3n). A plugin ships helper executables under `bin/`; making
|
|
4
|
+
* them resolvable means the agent's `run_shell` (and monitors/hooks, which
|
|
5
|
+
* inherit the process env) can invoke `some-plugin-tool` by name.
|
|
6
|
+
*
|
|
7
|
+
* Wiring: prepend the trusted plugins' bin dirs to `process.env.PATH` at session
|
|
8
|
+
* start and RESTORE the original PATH at session end — session-scoped, so no
|
|
9
|
+
* plugin executable stays resolvable after the session. Every child process
|
|
10
|
+
* inherits process.env, so this one mutation covers run_shell (foreground +
|
|
11
|
+
* background), the monitor supervisor, and hook commands uniformly.
|
|
12
|
+
*
|
|
13
|
+
* SECURITY: an executable on PATH runs code, so — like hooks/LSP/MCP/monitors —
|
|
14
|
+
* only TRUSTED plugins contribute (user/local auto-trusted; project needs
|
|
15
|
+
* `cc plugin trust`). An untrusted cloned-repo plugin can NOT shadow a system
|
|
16
|
+
* command or get its binary invoked.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import path from "path";
|
|
20
|
+
import { discoverPlugins } from "./scopes.js";
|
|
21
|
+
import { partitionByTrust, warnUntrustedOnce } from "./trust.js";
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Collect trusted, installed plugins' `bin/` directories.
|
|
25
|
+
* @param {object} [opts] { cwd, scopes }
|
|
26
|
+
* @returns {Array<{plugin, scope, version, dir}>}
|
|
27
|
+
*/
|
|
28
|
+
export function collectPluginBinDirs(opts = {}) {
|
|
29
|
+
let plugins = [];
|
|
30
|
+
try {
|
|
31
|
+
plugins = discoverPlugins({ cwd: opts.cwd, scopes: opts.scopes });
|
|
32
|
+
} catch {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
const { trusted, skipped } = partitionByTrust(plugins);
|
|
36
|
+
warnUntrustedOnce(
|
|
37
|
+
skipped
|
|
38
|
+
.filter((p) => p.manifest?.components?.bin?.length)
|
|
39
|
+
.map((p) => p.name),
|
|
40
|
+
"bin",
|
|
41
|
+
);
|
|
42
|
+
const out = [];
|
|
43
|
+
for (const p of trusted) {
|
|
44
|
+
if (!p.manifest || p.manifest.ok !== true) continue;
|
|
45
|
+
const bins = p.manifest.components?.bin;
|
|
46
|
+
if (!Array.isArray(bins) || bins.length === 0) continue;
|
|
47
|
+
// Every bin entry's absPath is a file inside the plugin's bin dir; collect
|
|
48
|
+
// the unique parent directories (usually just `<root>/bin`).
|
|
49
|
+
const dirs = new Set(bins.map((b) => path.dirname(b.absPath)));
|
|
50
|
+
for (const dir of dirs) {
|
|
51
|
+
out.push({
|
|
52
|
+
plugin: p.name,
|
|
53
|
+
scope: p.scope,
|
|
54
|
+
version: p.version,
|
|
55
|
+
dir,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Prepend trusted plugins' bin dirs to `env.PATH` (defaults to process.env).
|
|
64
|
+
* Returns a `restore()` that puts PATH back, plus the dirs added. Idempotent per
|
|
65
|
+
* call — a dir already on PATH is not added twice.
|
|
66
|
+
*
|
|
67
|
+
* @param {object} [opts] { cwd, scopes, env }
|
|
68
|
+
* @returns {{ added: string[], restore: () => void }}
|
|
69
|
+
*/
|
|
70
|
+
export function applyPluginBinPath(opts = {}) {
|
|
71
|
+
const env = opts.env || process.env;
|
|
72
|
+
const dirs = collectPluginBinDirs({ cwd: opts.cwd, scopes: opts.scopes }).map(
|
|
73
|
+
(b) => b.dir,
|
|
74
|
+
);
|
|
75
|
+
const prevPath = env.PATH;
|
|
76
|
+
if (dirs.length === 0) {
|
|
77
|
+
return { added: [], restore: () => {} };
|
|
78
|
+
}
|
|
79
|
+
const existing = new Set(
|
|
80
|
+
String(prevPath || "")
|
|
81
|
+
.split(path.delimiter)
|
|
82
|
+
.filter(Boolean),
|
|
83
|
+
);
|
|
84
|
+
const added = dirs.filter((d) => !existing.has(d));
|
|
85
|
+
if (added.length === 0) {
|
|
86
|
+
return { added: [], restore: () => {} };
|
|
87
|
+
}
|
|
88
|
+
env.PATH = [...added, prevPath].filter(Boolean).join(path.delimiter);
|
|
89
|
+
let restored = false;
|
|
90
|
+
return {
|
|
91
|
+
added,
|
|
92
|
+
restore: () => {
|
|
93
|
+
if (restored) return;
|
|
94
|
+
restored = true;
|
|
95
|
+
// Restore only if nothing else re-touched PATH out from under us; either
|
|
96
|
+
// way, put the recorded previous value back (session-scoped semantics).
|
|
97
|
+
env.PATH = prevPath;
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge installed plugins' `hooks/hooks.json` into the effective settings-hook
|
|
3
|
+
* map (Phase 3.3c — plugin Hook component reaches the agent lifecycle).
|
|
4
|
+
*
|
|
5
|
+
* A plugin ships lifecycle hooks in the same shape as `.claude/settings.json`
|
|
6
|
+
* `hooks`: a map of event name → array of `{ matcher?, hooks: [{type,command}] }`
|
|
7
|
+
* entries, optionally wrapped under a top-level `hooks` key. Those entries are
|
|
8
|
+
* concatenated onto whatever the user's settings already declared, so a plugin
|
|
9
|
+
* ADDS hooks without being able to silently replace the user's.
|
|
10
|
+
*
|
|
11
|
+
* Only plugins whose manifest fully validated (`manifest.ok`) contribute. Note:
|
|
12
|
+
* a hook can run a shell command, so a plugin's hooks carry the same trust as
|
|
13
|
+
* the user installing it (same as an npm package's lifecycle scripts) and run
|
|
14
|
+
* through the existing hook-runner (which applies the project-hook trust model).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import fs from "fs";
|
|
18
|
+
import { discoverPlugins } from "./scopes.js";
|
|
19
|
+
import { partitionByTrust, warnUntrustedOnce } from "./trust.js";
|
|
20
|
+
|
|
21
|
+
export const _deps = { readFileSync: fs.readFileSync };
|
|
22
|
+
|
|
23
|
+
/** Accept either `{ hooks: {Event:[...]} }` (plugin wrap) or `{Event:[...]}`. */
|
|
24
|
+
function normalizeHookMap(parsed) {
|
|
25
|
+
if (
|
|
26
|
+
parsed &&
|
|
27
|
+
typeof parsed === "object" &&
|
|
28
|
+
!Array.isArray(parsed) &&
|
|
29
|
+
parsed.hooks &&
|
|
30
|
+
typeof parsed.hooks === "object" &&
|
|
31
|
+
!Array.isArray(parsed.hooks)
|
|
32
|
+
) {
|
|
33
|
+
return parsed.hooks;
|
|
34
|
+
}
|
|
35
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
36
|
+
? parsed
|
|
37
|
+
: {};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Collect + merge every installed plugin's hook entries into one event map.
|
|
42
|
+
* @param {object} [opts] { cwd, scopes }
|
|
43
|
+
* @returns {Record<string, Array>} event name → concatenated hook entries
|
|
44
|
+
*/
|
|
45
|
+
export function collectPluginHooks(opts = {}) {
|
|
46
|
+
let plugins = [];
|
|
47
|
+
try {
|
|
48
|
+
plugins = discoverPlugins({ cwd: opts.cwd, scopes: opts.scopes });
|
|
49
|
+
} catch {
|
|
50
|
+
return {};
|
|
51
|
+
}
|
|
52
|
+
// A hook runs a shell command — gate it behind trust so a cloned repo's
|
|
53
|
+
// project plugin can't run commands the moment the agent starts.
|
|
54
|
+
const { trusted, skipped } = partitionByTrust(plugins);
|
|
55
|
+
warnUntrustedOnce(
|
|
56
|
+
skipped.filter((p) => p.manifest?.components?.hooks).map((p) => p.name),
|
|
57
|
+
"hooks",
|
|
58
|
+
);
|
|
59
|
+
const merged = {};
|
|
60
|
+
for (const p of trusted) {
|
|
61
|
+
if (!p.manifest || p.manifest.ok !== true) continue;
|
|
62
|
+
const h = p.manifest.components?.hooks;
|
|
63
|
+
if (!h || !h.absPath) continue;
|
|
64
|
+
let parsed;
|
|
65
|
+
try {
|
|
66
|
+
parsed = JSON.parse(_deps.readFileSync(h.absPath, "utf8"));
|
|
67
|
+
} catch {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const map = normalizeHookMap(parsed);
|
|
71
|
+
for (const [event, entries] of Object.entries(map)) {
|
|
72
|
+
if (!Array.isArray(entries)) continue;
|
|
73
|
+
merged[event] = (merged[event] || []).concat(entries);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return merged;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Return a settings-hook map that ADDS the installed plugins' hooks to the
|
|
81
|
+
* user's own. Returns the input unchanged when no plugin contributes hooks.
|
|
82
|
+
*
|
|
83
|
+
* @param {object|null} settingsHooks the user's loaded settings hooks
|
|
84
|
+
* @param {object} [opts] { cwd, scopes }
|
|
85
|
+
*/
|
|
86
|
+
export function mergePluginHooks(settingsHooks, opts = {}) {
|
|
87
|
+
const plugin = collectPluginHooks(opts);
|
|
88
|
+
const events = Object.keys(plugin);
|
|
89
|
+
if (events.length === 0) return settingsHooks;
|
|
90
|
+
const out =
|
|
91
|
+
settingsHooks && typeof settingsHooks === "object"
|
|
92
|
+
? { ...settingsHooks }
|
|
93
|
+
: {};
|
|
94
|
+
for (const event of events) {
|
|
95
|
+
out[event] = (Array.isArray(out[event]) ? out[event] : []).concat(
|
|
96
|
+
plugin[event],
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin install lifecycle (Phase 3.3d) — put a plugin ONTO disk in an immutable
|
|
3
|
+
* scope version directory, so the component wirings (skills / lsp / hooks) built
|
|
4
|
+
* in 3.2–3.3c actually reach the agent for a real user instead of only for
|
|
5
|
+
* hand-placed fixtures.
|
|
6
|
+
*
|
|
7
|
+
* installFromDirectory(src, {scope}) → validate manifest → copy into
|
|
8
|
+
* <scopeRoot>/<encodedName>/<version>/ → mark that version active
|
|
9
|
+
* listInstalled({cwd}) → discover across scopes
|
|
10
|
+
* uninstall(name, {scope, version}) → remove a version (or the whole plugin)
|
|
11
|
+
* setActiveVersion(name, version) → repoint `.active` (rollback)
|
|
12
|
+
*
|
|
13
|
+
* Version directories are immutable: re-installing the same version refuses
|
|
14
|
+
* unless `force`, so an in-flight session keeps running its bytes. The copy
|
|
15
|
+
* skips symlinks (a symlink could later resolve outside the sandbox) and only
|
|
16
|
+
* writes inside the destination version dir.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import fs from "fs";
|
|
20
|
+
import os from "os";
|
|
21
|
+
import path from "path";
|
|
22
|
+
import { spawnSync } from "child_process";
|
|
23
|
+
import { parsePluginManifest, isWithin } from "./manifest.js";
|
|
24
|
+
import {
|
|
25
|
+
pluginNameDir,
|
|
26
|
+
pluginVersionDir,
|
|
27
|
+
listInstalledVersions,
|
|
28
|
+
activeVersion,
|
|
29
|
+
discoverPlugins,
|
|
30
|
+
} from "./scopes.js";
|
|
31
|
+
import { verifyPluginManifest } from "../plugin-security.js";
|
|
32
|
+
import { writePluginLock } from "./signature.js";
|
|
33
|
+
|
|
34
|
+
export const _deps = {
|
|
35
|
+
existsSync: fs.existsSync,
|
|
36
|
+
mkdirSync: fs.mkdirSync,
|
|
37
|
+
rmSync: fs.rmSync,
|
|
38
|
+
readdirSync: fs.readdirSync,
|
|
39
|
+
copyFileSync: fs.copyFileSync,
|
|
40
|
+
lstatSync: fs.lstatSync,
|
|
41
|
+
writeFileSync: fs.writeFileSync,
|
|
42
|
+
mkdtempSync: fs.mkdtempSync,
|
|
43
|
+
spawnSync,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Install a plugin from a local directory into a scope's immutable version dir.
|
|
48
|
+
* @param {string} srcDir directory containing the plugin (with its manifest)
|
|
49
|
+
* @param {object} opts { scope="user", cwd, force=false }
|
|
50
|
+
* @returns {{ name, version, scope, dir, warnings }}
|
|
51
|
+
*/
|
|
52
|
+
export function installFromDirectory(srcDir, opts = {}) {
|
|
53
|
+
const scope = opts.scope || "user";
|
|
54
|
+
const src = path.resolve(srcDir);
|
|
55
|
+
if (!_deps.existsSync(src)) {
|
|
56
|
+
throw new Error(`source directory does not exist: ${src}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const manifest = parsePluginManifest(src);
|
|
60
|
+
if (!manifest.ok) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`plugin manifest is invalid:\n - ${manifest.errors.join("\n - ")}`,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
const { name, version } = manifest.metadata;
|
|
66
|
+
|
|
67
|
+
// Optional signature/integrity verification of the manifest at install time
|
|
68
|
+
// (Phase 3.3l). verifyPluginManifest THROWS on any mismatch/failure — a signed
|
|
69
|
+
// install that fails verification must not land on disk (fail-closed). On
|
|
70
|
+
// success we record a `.plugin-lock.json` so load-time requireSignedPlugins
|
|
71
|
+
// can re-check it without the original signature/key files.
|
|
72
|
+
let verification = null;
|
|
73
|
+
const sig = opts.signature;
|
|
74
|
+
if (sig && (sig.sha256 || sig.signatureFile || sig.requireSignature)) {
|
|
75
|
+
verification = verifyPluginManifest({
|
|
76
|
+
manifestFile: manifest.manifestPath,
|
|
77
|
+
expectedSha256: sig.sha256,
|
|
78
|
+
signatureFile: sig.signatureFile,
|
|
79
|
+
publicKeyFile: sig.publicKeyFile,
|
|
80
|
+
requireSignature: sig.requireSignature === true,
|
|
81
|
+
trustedKeySha256: sig.trustedKeySha256 || null,
|
|
82
|
+
requireTrustedKey: sig.requireTrustedKey === true,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const dest = pluginVersionDir(scope, name, version, { cwd: opts.cwd });
|
|
87
|
+
if (_deps.existsSync(dest)) {
|
|
88
|
+
if (!opts.force) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`${name}@${version} is already installed at ${scope} scope (immutable). ` +
|
|
91
|
+
`Use --force to reinstall, or bump the version.`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
_deps.rmSync(dest, { recursive: true, force: true });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
_deps.mkdirSync(dest, { recursive: true });
|
|
98
|
+
copyDirGuarded(src, dest, dest);
|
|
99
|
+
|
|
100
|
+
// Record the verified signature into the installed (immutable) version dir so
|
|
101
|
+
// load-time enforcement can re-check it. The manifest was copied verbatim, so
|
|
102
|
+
// its bytes/sha in `dest` match what we verified in `src`.
|
|
103
|
+
if (verification) {
|
|
104
|
+
const destManifest = path.join(
|
|
105
|
+
dest,
|
|
106
|
+
path.relative(src, manifest.manifestPath),
|
|
107
|
+
);
|
|
108
|
+
writePluginLock(dest, {
|
|
109
|
+
manifestFile: destManifest,
|
|
110
|
+
sha256: verification.sha256,
|
|
111
|
+
publicKeySha256: verification.publicKeySha256,
|
|
112
|
+
signatureVerified: verification.signatureVerified === true,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Make the freshly-installed version active.
|
|
117
|
+
setActiveVersion(name, version, { scope, cwd: opts.cwd });
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
name,
|
|
121
|
+
version,
|
|
122
|
+
scope,
|
|
123
|
+
dir: dest,
|
|
124
|
+
warnings: manifest.warnings,
|
|
125
|
+
signatureVerified: verification?.signatureVerified === true,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Install from a source string:
|
|
131
|
+
* - a local directory → copied in directly
|
|
132
|
+
* - a git URL (https://…, git@…, ….git, file://…) → shallow-cloned then installed
|
|
133
|
+
* - GitHub shorthand `owner/repo` → https://github.com/owner/repo.git
|
|
134
|
+
* An optional `#ref` (branch / tag / commit) pins the checkout.
|
|
135
|
+
*/
|
|
136
|
+
export function installFromSource(source, opts = {}) {
|
|
137
|
+
return _withMaterializedSource(source, (dir, info) => {
|
|
138
|
+
const res = installFromDirectory(dir, opts);
|
|
139
|
+
return info ? { ...res, source: info.url, ref: info.ref || null } : res;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Materialize a source string into a local directory (cloning a git source into
|
|
145
|
+
* a temp dir), invoke `fn(dir, gitInfo|null)`, then clean up any temp checkout.
|
|
146
|
+
* Single fetch shared by installFromSource + updatePlugin.
|
|
147
|
+
*/
|
|
148
|
+
function _withMaterializedSource(source, fn) {
|
|
149
|
+
const raw = String(source || "");
|
|
150
|
+
const asDir = path.resolve(raw);
|
|
151
|
+
if (_deps.existsSync(asDir) && _deps.lstatSync(asDir).isDirectory()) {
|
|
152
|
+
return fn(asDir, null);
|
|
153
|
+
}
|
|
154
|
+
const git = parseGitSource(raw);
|
|
155
|
+
if (git) {
|
|
156
|
+
const cloned = fetchGitRepo(git.url, git.ref);
|
|
157
|
+
try {
|
|
158
|
+
return fn(cloned, git);
|
|
159
|
+
} finally {
|
|
160
|
+
try {
|
|
161
|
+
_deps.rmSync(path.dirname(cloned), { recursive: true, force: true });
|
|
162
|
+
} catch {
|
|
163
|
+
/* temp cleanup is best-effort */
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
throw new Error(
|
|
168
|
+
`source not found as a local directory or git URL: ${source}`,
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Update an installed plugin from a source (local dir or git). Fetches the
|
|
174
|
+
* source ONCE, reads its name+version, and:
|
|
175
|
+
* - a NEW version → installs the new immutable version dir + repoints
|
|
176
|
+
* `.active` (the old version stays on disk for rollback via `cc plugin use`);
|
|
177
|
+
* - the SAME version → no-op unless `--force` reinstalls it.
|
|
178
|
+
* Returns { name, version, previousVersion, updated, reinstalled }.
|
|
179
|
+
*/
|
|
180
|
+
export function updatePlugin(source, opts = {}) {
|
|
181
|
+
const scope = opts.scope || "user";
|
|
182
|
+
return _withMaterializedSource(source, (dir, info) => {
|
|
183
|
+
const manifest = parsePluginManifest(dir);
|
|
184
|
+
if (!manifest.ok) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`plugin manifest is invalid:\n - ${manifest.errors.join("\n - ")}`,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
const { name, version } = manifest.metadata;
|
|
190
|
+
const previousVersion = getActiveVersion(name, { scope, cwd: opts.cwd });
|
|
191
|
+
const dest = pluginVersionDir(scope, name, version, { cwd: opts.cwd });
|
|
192
|
+
const sameVersionExists = _deps.existsSync(dest);
|
|
193
|
+
|
|
194
|
+
if (sameVersionExists && !opts.force) {
|
|
195
|
+
// Already at this version — make sure it's the active one, but don't
|
|
196
|
+
// reinstall an immutable dir.
|
|
197
|
+
if (previousVersion !== version) {
|
|
198
|
+
setActiveVersion(name, version, { scope, cwd: opts.cwd });
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
name,
|
|
202
|
+
version,
|
|
203
|
+
previousVersion,
|
|
204
|
+
updated: previousVersion !== version,
|
|
205
|
+
reinstalled: false,
|
|
206
|
+
source: info ? info.url : null,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const res = installFromDirectory(dir, { ...opts, scope, force: true });
|
|
211
|
+
return {
|
|
212
|
+
...res,
|
|
213
|
+
previousVersion,
|
|
214
|
+
updated: previousVersion !== version,
|
|
215
|
+
reinstalled: sameVersionExists,
|
|
216
|
+
source: info ? info.url : null,
|
|
217
|
+
ref: info ? info.ref || null : null,
|
|
218
|
+
};
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Classify a source string into a git URL (+ optional ref), or null when it is
|
|
224
|
+
* not remote-looking. `owner/repo` expands to a GitHub HTTPS URL.
|
|
225
|
+
*/
|
|
226
|
+
export function parseGitSource(raw) {
|
|
227
|
+
const [loc, ref] = String(raw || "").split("#");
|
|
228
|
+
if (!loc) return null;
|
|
229
|
+
if (
|
|
230
|
+
/^(https?|git|ssh|file):\/\//.test(loc) ||
|
|
231
|
+
loc.endsWith(".git") ||
|
|
232
|
+
/^git@/.test(loc)
|
|
233
|
+
) {
|
|
234
|
+
return { url: loc, ref: ref || null };
|
|
235
|
+
}
|
|
236
|
+
if (/^[\w.-]+\/[\w.-]+$/.test(loc)) {
|
|
237
|
+
return { url: `https://github.com/${loc}.git`, ref: ref || null };
|
|
238
|
+
}
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Shallow-clone `url` (optionally at `ref`) into a fresh temp dir and return the
|
|
244
|
+
* checkout path. Uses `git` via spawn WITHOUT a shell (url/ref are argv, not a
|
|
245
|
+
* command line — no injection). Caller removes the temp dir's parent.
|
|
246
|
+
*/
|
|
247
|
+
export function fetchGitRepo(url, ref) {
|
|
248
|
+
const base = _deps.mkdtempSync(path.join(os.tmpdir(), "cc-plugin-git-"));
|
|
249
|
+
const dir = path.join(base, "repo");
|
|
250
|
+
const run = (args) =>
|
|
251
|
+
_deps.spawnSync("git", args, {
|
|
252
|
+
encoding: "utf8",
|
|
253
|
+
timeout: 120000,
|
|
254
|
+
windowsHide: true,
|
|
255
|
+
shell: false,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
const cloneArgs = ["clone", "--depth", "1"];
|
|
259
|
+
if (ref) cloneArgs.push("--branch", ref);
|
|
260
|
+
cloneArgs.push(url, dir);
|
|
261
|
+
let res = run(cloneArgs);
|
|
262
|
+
if (res.error && res.error.code === "ENOENT") {
|
|
263
|
+
throw new Error("git is not installed (needed to fetch a remote plugin)");
|
|
264
|
+
}
|
|
265
|
+
if (res.status !== 0) {
|
|
266
|
+
// A commit SHA can't be used with --branch/--depth; retry with a full clone
|
|
267
|
+
// then checkout the ref explicitly.
|
|
268
|
+
if (ref) {
|
|
269
|
+
try {
|
|
270
|
+
_deps.rmSync(dir, { recursive: true, force: true });
|
|
271
|
+
} catch {
|
|
272
|
+
/* ignore */
|
|
273
|
+
}
|
|
274
|
+
const full = run(["clone", url, dir]);
|
|
275
|
+
if (!full.error && full.status === 0) {
|
|
276
|
+
const co = run(["-C", dir, "checkout", ref]);
|
|
277
|
+
if (co.status === 0) return dir;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
const reason = (res.stderr || "").trim() || `git exited ${res.status}`;
|
|
281
|
+
throw new Error(`git clone failed for ${url}: ${reason}`);
|
|
282
|
+
}
|
|
283
|
+
return dir;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* List installed plugins (active version per name) across scopes. Uses
|
|
288
|
+
* `skipPolicy` so the ADMIN view shows every plugin on disk — including one an
|
|
289
|
+
* org managed policy blocks from LOADING — otherwise a denied plugin would be
|
|
290
|
+
* invisible and impossible to inspect / uninstall / un-deny.
|
|
291
|
+
*/
|
|
292
|
+
export function listInstalled(opts = {}) {
|
|
293
|
+
return discoverPlugins({
|
|
294
|
+
cwd: opts.cwd,
|
|
295
|
+
scopes: opts.scopes,
|
|
296
|
+
skipPolicy: true,
|
|
297
|
+
}).map((p) => ({
|
|
298
|
+
name: p.name,
|
|
299
|
+
version: p.version,
|
|
300
|
+
scope: p.scope,
|
|
301
|
+
dir: p.root,
|
|
302
|
+
ok: p.manifest?.ok === true,
|
|
303
|
+
}));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Uninstall a plugin. Without `version`, removes the whole plugin (all versions);
|
|
308
|
+
* with `version`, removes just that one and repoints `.active` if needed.
|
|
309
|
+
* @returns {{ removed: string[] }}
|
|
310
|
+
*/
|
|
311
|
+
export function uninstall(name, opts = {}) {
|
|
312
|
+
const scope = opts.scope || "user";
|
|
313
|
+
const cwd = opts.cwd;
|
|
314
|
+
const removed = [];
|
|
315
|
+
|
|
316
|
+
if (opts.version) {
|
|
317
|
+
const dir = pluginVersionDir(scope, name, opts.version, { cwd });
|
|
318
|
+
if (!_deps.existsSync(dir)) {
|
|
319
|
+
throw new Error(
|
|
320
|
+
`${name}@${opts.version} is not installed at ${scope} scope`,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
// Capture the active version BEFORE removing, so we only repoint `.active`
|
|
324
|
+
// when the version we removed WAS the active one. Removing a NON-active
|
|
325
|
+
// version (e.g. cleaning up a newer version after rolling back to an older
|
|
326
|
+
// pinned one) must not silently change which version is active — the old
|
|
327
|
+
// code always rewrote `.active` to the newest remaining, so uninstalling an
|
|
328
|
+
// unrelated version could bump the user's pinned choice.
|
|
329
|
+
const removedWasActive =
|
|
330
|
+
getActiveVersion(name, { scope, cwd }) === opts.version;
|
|
331
|
+
_deps.rmSync(dir, { recursive: true, force: true });
|
|
332
|
+
removed.push(opts.version);
|
|
333
|
+
// Repoint .active to the newest remaining version, or clear it.
|
|
334
|
+
const remaining = listInstalledVersions(scope, name, { cwd });
|
|
335
|
+
const activeFile = path.join(
|
|
336
|
+
pluginNameDir(scope, name, { cwd }),
|
|
337
|
+
".active",
|
|
338
|
+
);
|
|
339
|
+
if (remaining.length === 0) {
|
|
340
|
+
_deps.rmSync(pluginNameDir(scope, name, { cwd }), {
|
|
341
|
+
recursive: true,
|
|
342
|
+
force: true,
|
|
343
|
+
});
|
|
344
|
+
} else if (removedWasActive && _deps.existsSync(activeFile)) {
|
|
345
|
+
_deps.writeFileSync(activeFile, remaining[0], "utf8");
|
|
346
|
+
}
|
|
347
|
+
return { removed };
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const nameDir = pluginNameDir(scope, name, { cwd });
|
|
351
|
+
if (!_deps.existsSync(nameDir)) {
|
|
352
|
+
throw new Error(`${name} is not installed at ${scope} scope`);
|
|
353
|
+
}
|
|
354
|
+
removed.push(...listInstalledVersions(scope, name, { cwd }));
|
|
355
|
+
_deps.rmSync(nameDir, { recursive: true, force: true });
|
|
356
|
+
return { removed };
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/** Pin a plugin's active version (rollback / switch). */
|
|
360
|
+
export function setActiveVersion(name, version, opts = {}) {
|
|
361
|
+
const scope = opts.scope || "user";
|
|
362
|
+
const cwd = opts.cwd;
|
|
363
|
+
const versionDir = pluginVersionDir(scope, name, version, { cwd });
|
|
364
|
+
if (!_deps.existsSync(versionDir)) {
|
|
365
|
+
throw new Error(`${name}@${version} is not installed at ${scope} scope`);
|
|
366
|
+
}
|
|
367
|
+
const activeFile = path.join(pluginNameDir(scope, name, { cwd }), ".active");
|
|
368
|
+
_deps.writeFileSync(activeFile, String(version), "utf8");
|
|
369
|
+
return { name, version, scope, active: version };
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/** Which version is active for a plugin at a scope (or null). */
|
|
373
|
+
export function getActiveVersion(name, opts = {}) {
|
|
374
|
+
return activeVersion(opts.scope || "user", name, { cwd: opts.cwd });
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ── guarded recursive copy ────────────────────────────────────────────────
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Copy `src` → `dst`, refusing to write outside `root` and skipping symlinks
|
|
381
|
+
* (which could later resolve outside the plugin sandbox). Directories recurse.
|
|
382
|
+
*/
|
|
383
|
+
function copyDirGuarded(src, dst, root) {
|
|
384
|
+
for (const entry of _deps.readdirSync(src, { withFileTypes: true })) {
|
|
385
|
+
const from = path.join(src, entry.name);
|
|
386
|
+
const to = path.join(dst, entry.name);
|
|
387
|
+
if (!isWithin(root, to)) continue; // never escape the version dir
|
|
388
|
+
if (entry.isSymbolicLink()) continue; // do not copy symlinks
|
|
389
|
+
if (entry.isDirectory()) {
|
|
390
|
+
_deps.mkdirSync(to, { recursive: true });
|
|
391
|
+
copyDirGuarded(from, to, root);
|
|
392
|
+
} else if (entry.isFile()) {
|
|
393
|
+
_deps.copyFileSync(from, to);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply installed plugins' `.lsp.json` language-server contributions to the LSP
|
|
3
|
+
* registry (Phase 3.2 — first plugin component actually wired to the agent).
|
|
4
|
+
*
|
|
5
|
+
* A plugin declares extra language servers via `.lsp.json`; this bridges those
|
|
6
|
+
* declarations into `lsp-server-registry.registerLanguageServer`, so the Phase 2
|
|
7
|
+
* `code_intelligence` agent tool and `cc code-intel` command transparently gain
|
|
8
|
+
* definition/references/diagnostics for the plugin's language — no core change
|
|
9
|
+
* per new language.
|
|
10
|
+
*
|
|
11
|
+
* Idempotent + memoized per project root: the first LSP query (agent or CLI)
|
|
12
|
+
* triggers a one-time scan of the user/project/local plugin scopes.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import path from "path";
|
|
16
|
+
import { discoverPlugins } from "./scopes.js";
|
|
17
|
+
import { registerLanguageServer } from "../lsp/lsp-server-registry.js";
|
|
18
|
+
import { partitionByTrust, warnUntrustedOnce } from "./trust.js";
|
|
19
|
+
|
|
20
|
+
const _loadedRoots = new Set();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Register every installed plugin's LSP servers for `cwd` (once per root).
|
|
24
|
+
* Never throws — a broken plugin manifest must not break code navigation.
|
|
25
|
+
*
|
|
26
|
+
* @param {object} [opts] { cwd, scopes, force }
|
|
27
|
+
* @returns {{ registered: Array<{plugin, languageId, id}> }}
|
|
28
|
+
*/
|
|
29
|
+
export function ensurePluginLspServers(opts = {}) {
|
|
30
|
+
const cwd = path.resolve(opts.cwd || process.cwd());
|
|
31
|
+
if (_loadedRoots.has(cwd) && !opts.force) return { registered: [] };
|
|
32
|
+
_loadedRoots.add(cwd);
|
|
33
|
+
|
|
34
|
+
const registered = [];
|
|
35
|
+
let plugins = [];
|
|
36
|
+
try {
|
|
37
|
+
plugins = discoverPlugins({ cwd, scopes: opts.scopes });
|
|
38
|
+
} catch {
|
|
39
|
+
return { registered };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// An LSP server spawns a binary — gate it behind trust. Untrusted project
|
|
43
|
+
// plugins (e.g. from a cloned repo) don't get to launch processes silently.
|
|
44
|
+
const { trusted, skipped } = partitionByTrust(plugins);
|
|
45
|
+
warnUntrustedOnce(
|
|
46
|
+
skipped
|
|
47
|
+
.filter((p) => (p.manifest?.components?.lsp || []).length > 0)
|
|
48
|
+
.map((p) => p.name),
|
|
49
|
+
"language servers",
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
for (const p of trusted) {
|
|
53
|
+
const servers = p.manifest?.components?.lsp || [];
|
|
54
|
+
for (const s of servers) {
|
|
55
|
+
try {
|
|
56
|
+
registerLanguageServer({
|
|
57
|
+
languageId: s.languageId,
|
|
58
|
+
command: s.command,
|
|
59
|
+
args: s.args,
|
|
60
|
+
extensions: s.extensions,
|
|
61
|
+
id: s.id,
|
|
62
|
+
});
|
|
63
|
+
registered.push({ plugin: p.name, languageId: s.languageId, id: s.id });
|
|
64
|
+
} catch {
|
|
65
|
+
// skip a malformed server entry; other plugins still load
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return { registered };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Test hook: forget which roots have been scanned so a re-scan can run. */
|
|
73
|
+
export function _resetPluginLspLoadState() {
|
|
74
|
+
_loadedRoots.clear();
|
|
75
|
+
}
|