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,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TeamBudget (Phase 4 — Agent Team) — a team-wide spend cap across four
|
|
3
|
+
* independent dimensions, consulted by TeamRunner BEFORE it hands a teammate a
|
|
4
|
+
* new task so a runaway graph is bounded and a resumed session keeps counting
|
|
5
|
+
* from where it left off (Phase 4 acceptance "支持 token、时间、并发数和费用预算"
|
|
6
|
+
* + "团队会话恢复后…预算保持一致").
|
|
7
|
+
*
|
|
8
|
+
* - maxTasks total task EXECUTIONS across all teammates (task-count cap)
|
|
9
|
+
* - maxTokens total (input+output) LLM tokens folded from task results
|
|
10
|
+
* - maxUsd total estimated USD spend — delegated to the audited CostBudget
|
|
11
|
+
* (same pricing/cache-token rules as `--max-budget-usd`)
|
|
12
|
+
* - maxWallMs wall-clock since the first task started (time cap)
|
|
13
|
+
*
|
|
14
|
+
* Because a task's cost is only known once it returns, the team may overshoot a
|
|
15
|
+
* token/USD cap by at most one task — like CostBudget, it never STARTS a task
|
|
16
|
+
* once already over. A dimension left null is simply inactive. The clock is
|
|
17
|
+
* injected so the wall-clock cap is deterministic in tests, and snapshot/restore
|
|
18
|
+
* carries the running totals so `cc team run --resume` doesn't reset the budget.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { CostBudget } from "../cost-budget.js";
|
|
22
|
+
|
|
23
|
+
const pos = (n) => {
|
|
24
|
+
const v = Number(n);
|
|
25
|
+
return Number.isFinite(v) && v > 0 ? v : null;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export class TeamBudget {
|
|
29
|
+
constructor({
|
|
30
|
+
maxTasks = null,
|
|
31
|
+
maxTokens = null,
|
|
32
|
+
maxUsd = null,
|
|
33
|
+
maxWallMs = null,
|
|
34
|
+
table = undefined,
|
|
35
|
+
now = () => Date.now(),
|
|
36
|
+
} = {}) {
|
|
37
|
+
this._now = typeof now === "function" ? now : () => now;
|
|
38
|
+
this.maxTasks = pos(maxTasks);
|
|
39
|
+
this.maxTokens = pos(maxTokens);
|
|
40
|
+
this.maxWallMs = pos(maxWallMs);
|
|
41
|
+
this.cost = new CostBudget({ limitUsd: maxUsd, table });
|
|
42
|
+
this.tasks = 0;
|
|
43
|
+
this.tokens = 0;
|
|
44
|
+
this.startedAt = null; // set on the first recorded task
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Any dimension active? (an all-null budget never stops anything). */
|
|
48
|
+
enabled() {
|
|
49
|
+
return (
|
|
50
|
+
this.maxTasks != null ||
|
|
51
|
+
this.maxTokens != null ||
|
|
52
|
+
this.maxWallMs != null ||
|
|
53
|
+
this.cost.enabled()
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Begin the wall-clock window (idempotent — first call wins). */
|
|
58
|
+
start(now = this._now()) {
|
|
59
|
+
if (this.startedAt == null) this.startedAt = now;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Fold one settled task into the running totals. `usage` (an LLM token-usage
|
|
65
|
+
* event) is optional — a plain `--exec` shell task carries none, so only the
|
|
66
|
+
* task-count / wall-clock dimensions move for it.
|
|
67
|
+
* @returns {this}
|
|
68
|
+
*/
|
|
69
|
+
record({ usage = null, provider, model } = {}, now = this._now()) {
|
|
70
|
+
this.start(now);
|
|
71
|
+
this.tasks += 1;
|
|
72
|
+
if (usage) {
|
|
73
|
+
this.tokens +=
|
|
74
|
+
(Number(usage.input_tokens) || 0) + (Number(usage.output_tokens) || 0);
|
|
75
|
+
this.cost.add({ provider, model, usage });
|
|
76
|
+
}
|
|
77
|
+
return this;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Which cap (if any) is now reached — checked BEFORE starting a new task.
|
|
82
|
+
* @returns {null|"max-tasks"|"max-tokens"|"max-usd"|"max-wall-ms"}
|
|
83
|
+
*/
|
|
84
|
+
reason(now = this._now()) {
|
|
85
|
+
if (this.maxTasks != null && this.tasks >= this.maxTasks) {
|
|
86
|
+
return "max-tasks";
|
|
87
|
+
}
|
|
88
|
+
if (this.maxTokens != null && this.tokens >= this.maxTokens) {
|
|
89
|
+
return "max-tokens";
|
|
90
|
+
}
|
|
91
|
+
if (this.cost.exceeded()) return "max-usd";
|
|
92
|
+
if (
|
|
93
|
+
this.maxWallMs != null &&
|
|
94
|
+
this.startedAt != null &&
|
|
95
|
+
now - this.startedAt >= this.maxWallMs
|
|
96
|
+
) {
|
|
97
|
+
return "max-wall-ms";
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** True once any active cap has been reached. */
|
|
103
|
+
shouldStop(now = this._now()) {
|
|
104
|
+
return this.reason(now) != null;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
status(now = this._now()) {
|
|
108
|
+
return {
|
|
109
|
+
tasks: this.tasks,
|
|
110
|
+
maxTasks: this.maxTasks,
|
|
111
|
+
tokens: this.tokens,
|
|
112
|
+
maxTokens: this.maxTokens,
|
|
113
|
+
spentUsd: this.cost.spentUsd,
|
|
114
|
+
maxUsd: this.cost.limitUsd,
|
|
115
|
+
elapsedMs: this.startedAt == null ? 0 : now - this.startedAt,
|
|
116
|
+
maxWallMs: this.maxWallMs,
|
|
117
|
+
reason: this.reason(now),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
snapshot() {
|
|
122
|
+
return {
|
|
123
|
+
limits: {
|
|
124
|
+
maxTasks: this.maxTasks,
|
|
125
|
+
maxTokens: this.maxTokens,
|
|
126
|
+
maxUsd: this.cost.limitUsd,
|
|
127
|
+
maxWallMs: this.maxWallMs,
|
|
128
|
+
},
|
|
129
|
+
totals: {
|
|
130
|
+
tasks: this.tasks,
|
|
131
|
+
tokens: this.tokens,
|
|
132
|
+
spentUsd: this.cost.spentUsd,
|
|
133
|
+
startedAt: this.startedAt,
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Restore running totals + caps from a snapshot. `overrides` lets the current
|
|
140
|
+
* CLI invocation RAISE/lower a cap on resume — a provided (non-nullish) value
|
|
141
|
+
* wins over the snapshot's; an omitted one keeps the prior cap (so a resume
|
|
142
|
+
* with no flags can't silently drop a safety cap).
|
|
143
|
+
*/
|
|
144
|
+
static restore(snap, { now = () => Date.now(), table, overrides = {} } = {}) {
|
|
145
|
+
const pick = (o, s) => (o == null ? s : o);
|
|
146
|
+
const b = new TeamBudget({
|
|
147
|
+
maxTasks: pick(overrides.maxTasks, snap?.limits?.maxTasks),
|
|
148
|
+
maxTokens: pick(overrides.maxTokens, snap?.limits?.maxTokens),
|
|
149
|
+
maxUsd: pick(overrides.maxUsd, snap?.limits?.maxUsd),
|
|
150
|
+
maxWallMs: pick(overrides.maxWallMs, snap?.limits?.maxWallMs),
|
|
151
|
+
table,
|
|
152
|
+
now,
|
|
153
|
+
});
|
|
154
|
+
b.tasks = Number(snap?.totals?.tasks) || 0;
|
|
155
|
+
b.tokens = Number(snap?.totals?.tokens) || 0;
|
|
156
|
+
// Preserve prior USD spend so the cap keeps counting across a resume.
|
|
157
|
+
const spent = Number(snap?.totals?.spentUsd);
|
|
158
|
+
b.cost.spentUsd = Number.isFinite(spent) && spent >= 0 ? spent : 0;
|
|
159
|
+
if (b.cost.spentUsd > 0) b.cost.priced = true;
|
|
160
|
+
// A time cap must NOT keep counting wall-clock across a crash gap (the
|
|
161
|
+
// process was down); restart the window on the next recorded task.
|
|
162
|
+
b.startedAt = null;
|
|
163
|
+
return b;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TeamMailbox (Phase 4 — Agent Team) — directed + broadcast messaging between
|
|
3
|
+
* teammates so a coordinating agent can hand off context, flag a finding, or ask
|
|
4
|
+
* a peer to redo work (Phase 4 work-item "支持 Agent 间直接消息和定向通知",
|
|
5
|
+
* acceptance "团队会话恢复后…消息…保持一致").
|
|
6
|
+
*
|
|
7
|
+
* A message is addressed to a specific recipient (`to`) or broadcast (`to:"*"`).
|
|
8
|
+
* `drain(recipient)` returns that recipient's undelivered messages (direct +
|
|
9
|
+
* broadcasts it hasn't seen) and marks them delivered FOR THAT RECIPIENT — a
|
|
10
|
+
* broadcast is delivered independently to each teammate, so two teammates each
|
|
11
|
+
* receive it exactly once. Delivery cursors + the log are in the snapshot, so a
|
|
12
|
+
* resumed session re-delivers only what a teammate hadn't yet drained.
|
|
13
|
+
*
|
|
14
|
+
* Pure + deterministic: ids come from a monotonic counter (not a clock) and the
|
|
15
|
+
* clock is injected only for timestamps, so ordering is stable in tests.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export class TeamMailbox {
|
|
19
|
+
constructor({ now = () => Date.now() } = {}) {
|
|
20
|
+
this._now = typeof now === "function" ? now : () => now;
|
|
21
|
+
this._log = []; // ordered [{ id, from, to, subject, body, ts }]
|
|
22
|
+
this._seq = 0; // monotonic message id source
|
|
23
|
+
this._delivered = new Map(); // recipient → highest message id already drained
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Post a message. `to` is a teammate id or "*" (broadcast). Returns the stored
|
|
28
|
+
* message (with its assigned id).
|
|
29
|
+
*/
|
|
30
|
+
send({ from = null, to, subject = null, body = null } = {}) {
|
|
31
|
+
if (!to || typeof to !== "string") {
|
|
32
|
+
throw new Error("TeamMailbox.send: `to` recipient (or '*') is required");
|
|
33
|
+
}
|
|
34
|
+
const msg = {
|
|
35
|
+
id: ++this._seq,
|
|
36
|
+
from,
|
|
37
|
+
to,
|
|
38
|
+
subject,
|
|
39
|
+
body,
|
|
40
|
+
ts: this._now(),
|
|
41
|
+
};
|
|
42
|
+
this._log.push(msg);
|
|
43
|
+
return { ...msg };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
_isFor(msg, recipient) {
|
|
47
|
+
return msg.to === recipient || msg.to === "*";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Peek at a recipient's undelivered messages WITHOUT marking them delivered. */
|
|
51
|
+
peek(recipient) {
|
|
52
|
+
const cursor = this._delivered.get(recipient) || 0;
|
|
53
|
+
return this._log
|
|
54
|
+
.filter(
|
|
55
|
+
(m) =>
|
|
56
|
+
m.id > cursor && m.from !== recipient && this._isFor(m, recipient),
|
|
57
|
+
)
|
|
58
|
+
.map((m) => ({ ...m }));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Return a recipient's undelivered messages and advance its delivery cursor so
|
|
63
|
+
* they are not returned again. A teammate never receives its own broadcast.
|
|
64
|
+
*/
|
|
65
|
+
drain(recipient) {
|
|
66
|
+
const pending = this.peek(recipient);
|
|
67
|
+
if (pending.length > 0) {
|
|
68
|
+
const highest = pending[pending.length - 1].id;
|
|
69
|
+
const cursor = this._delivered.get(recipient) || 0;
|
|
70
|
+
this._delivered.set(recipient, Math.max(cursor, highest));
|
|
71
|
+
}
|
|
72
|
+
return pending;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** How many messages a recipient has yet to drain. */
|
|
76
|
+
pendingCount(recipient) {
|
|
77
|
+
return this.peek(recipient).length;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** The full ordered message log (for a status panel / audit). */
|
|
81
|
+
log() {
|
|
82
|
+
return this._log.map((m) => ({ ...m }));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
size() {
|
|
86
|
+
return this._log.length;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
snapshot() {
|
|
90
|
+
return {
|
|
91
|
+
log: this._log.map((m) => ({ ...m })),
|
|
92
|
+
seq: this._seq,
|
|
93
|
+
delivered: Array.from(this._delivered.entries()),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static restore(snap, { now = () => Date.now() } = {}) {
|
|
98
|
+
const mb = new TeamMailbox({ now });
|
|
99
|
+
mb._log = Array.isArray(snap?.log) ? snap.log.map((m) => ({ ...m })) : [];
|
|
100
|
+
mb._seq =
|
|
101
|
+
Number(snap?.seq) ||
|
|
102
|
+
mb._log.reduce((max, m) => Math.max(max, m.id || 0), 0);
|
|
103
|
+
mb._delivered = new Map(snap?.delivered || []);
|
|
104
|
+
return mb;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TeamRunner (Phase 4 — Agent Team) — drives a TaskLeaseRegistry with N
|
|
3
|
+
* concurrent teammates, each looping: pick a claimable task → acquire its
|
|
4
|
+
* EXCLUSIVE lease → run it → complete (or fail → retry/cancel). The registry's
|
|
5
|
+
* lease + dependency DAG guarantees the two things a plain worker pool can't:
|
|
6
|
+
* - a task is run by AT MOST ONE teammate at a time (exclusive lease), so no
|
|
7
|
+
* duplicate work even with M teammates racing for the same task;
|
|
8
|
+
* - a task only starts once its dependencies are COMPLETED (DAG gating), and a
|
|
9
|
+
* task whose dependency was CANCELLED never runs (stays blocked).
|
|
10
|
+
*
|
|
11
|
+
* `runTask` is injected so the whole orchestration is unit-testable offline; in
|
|
12
|
+
* production it's wired to a real agent turn (SubAgentContext.run in a
|
|
13
|
+
* per-teammate worktree). Events are emitted for a machine-readable stream /
|
|
14
|
+
* status panel. A total-time / total-task budget bounds a runaway graph.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export class TeamRunner {
|
|
18
|
+
/**
|
|
19
|
+
* @param {TaskLeaseRegistry} registry
|
|
20
|
+
* @param {object} opts
|
|
21
|
+
* runTask async ({key, task, holder, renew}) => any (throw = task failed)
|
|
22
|
+
* teammates number of concurrent workers (default 2)
|
|
23
|
+
* ttlMs lease TTL per acquisition
|
|
24
|
+
* onEvent (evt) => void {type, ...}
|
|
25
|
+
* maxTasks safety cap on total task executions (default 1000)
|
|
26
|
+
* now () => ms (for deadline math; defaults to registry clock)
|
|
27
|
+
*/
|
|
28
|
+
constructor(registry, opts = {}) {
|
|
29
|
+
this.registry = registry;
|
|
30
|
+
this.runTask = opts.runTask;
|
|
31
|
+
this.teammates = opts.teammates > 0 ? Math.floor(opts.teammates) : 2;
|
|
32
|
+
this.ttlMs = opts.ttlMs;
|
|
33
|
+
this.onEvent = typeof opts.onEvent === "function" ? opts.onEvent : () => {};
|
|
34
|
+
this.maxTasks = opts.maxTasks > 0 ? opts.maxTasks : 1000;
|
|
35
|
+
this._now = opts.now || registry._now || (() => Date.now());
|
|
36
|
+
// Team-wide token/USD/time/task budget (null → unbounded). Consulted before
|
|
37
|
+
// every claim; folded after every settled task.
|
|
38
|
+
this.budget = opts.budget || null;
|
|
39
|
+
// Directed/broadcast messaging between teammates (null → disabled).
|
|
40
|
+
this.mailbox = opts.mailbox || null;
|
|
41
|
+
this._executions = 0;
|
|
42
|
+
this._inFlight = 0;
|
|
43
|
+
this._maxInFlight = 0;
|
|
44
|
+
this._members = new Map(); // holder → lifecycle record
|
|
45
|
+
this._budgetStopped = false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
_emit(type, extra) {
|
|
49
|
+
try {
|
|
50
|
+
this.onEvent({ type, ts: this._now(), ...extra });
|
|
51
|
+
} catch {
|
|
52
|
+
/* event sink is best-effort */
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Track a teammate's lifecycle state (idle / running / failed / shutdown) and
|
|
58
|
+
* emit a `teammate:state` event on every transition. `lost` is set on resume
|
|
59
|
+
* by the caller for a teammate whose lease was reclaimed after a crash.
|
|
60
|
+
*/
|
|
61
|
+
_setState(holder, state, extra = {}) {
|
|
62
|
+
let m = this._members.get(holder);
|
|
63
|
+
if (!m) {
|
|
64
|
+
m = { holder, state: null, completed: 0, failed: 0, lastError: null };
|
|
65
|
+
this._members.set(holder, m);
|
|
66
|
+
}
|
|
67
|
+
if (state === "completed-task") {
|
|
68
|
+
m.completed += 1;
|
|
69
|
+
return m;
|
|
70
|
+
}
|
|
71
|
+
if (state === "failed-task") {
|
|
72
|
+
m.failed += 1;
|
|
73
|
+
m.lastError = extra.error || null;
|
|
74
|
+
return m;
|
|
75
|
+
}
|
|
76
|
+
if (m.state === state) return m; // no transition
|
|
77
|
+
m.state = state;
|
|
78
|
+
this._emit("teammate:state", { holder, state, ...extra });
|
|
79
|
+
return m;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Snapshot of every teammate's lifecycle (for a status panel / resume). */
|
|
83
|
+
members() {
|
|
84
|
+
return Array.from(this._members.values()).map((m) => ({ ...m }));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Restore prior-run member records (e.g. before a --resume run). */
|
|
88
|
+
seedMembers(records = []) {
|
|
89
|
+
for (const r of records) {
|
|
90
|
+
if (r && r.holder) this._members.set(r.holder, { ...r });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Run the graph to completion (all tasks terminal) or until no teammate can
|
|
96
|
+
* make progress (everything remaining is blocked/leased). Returns a summary.
|
|
97
|
+
*/
|
|
98
|
+
async run() {
|
|
99
|
+
if (typeof this.runTask !== "function") {
|
|
100
|
+
throw new Error("TeamRunner: opts.runTask is required");
|
|
101
|
+
}
|
|
102
|
+
this._emit("run:start", {
|
|
103
|
+
teammates: this.teammates,
|
|
104
|
+
tasks: this.registry.list().length,
|
|
105
|
+
});
|
|
106
|
+
if (this.budget) this.budget.start();
|
|
107
|
+
const workers = [];
|
|
108
|
+
for (let i = 0; i < this.teammates; i++) {
|
|
109
|
+
const holder = `teammate-${i + 1}`;
|
|
110
|
+
this._setState(holder, "idle");
|
|
111
|
+
workers.push(this._worker(holder));
|
|
112
|
+
}
|
|
113
|
+
await Promise.all(workers);
|
|
114
|
+
const stats = this.registry.stats();
|
|
115
|
+
const summary = {
|
|
116
|
+
done: this.registry.allDone(),
|
|
117
|
+
executions: this._executions,
|
|
118
|
+
maxConcurrent: this._maxInFlight,
|
|
119
|
+
budgetStopped: this._budgetStopped,
|
|
120
|
+
budgetReason: this.budget ? this.budget.reason() : null,
|
|
121
|
+
members: this.members(),
|
|
122
|
+
messages: this.mailbox ? this.mailbox.size() : 0,
|
|
123
|
+
stats,
|
|
124
|
+
};
|
|
125
|
+
this._emit("run:end", summary);
|
|
126
|
+
return summary;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async _worker(holder) {
|
|
130
|
+
// Each teammate keeps taking claimable work until none is left FOR IT. A
|
|
131
|
+
// task blocked only by a peer's in-flight lease will free up (complete) or
|
|
132
|
+
// its dep will finish — so a worker that finds nothing claimable yields and
|
|
133
|
+
// re-checks while any work is still in flight.
|
|
134
|
+
for (;;) {
|
|
135
|
+
if (this._executions >= this.maxTasks) {
|
|
136
|
+
this._emit("run:budget-exhausted", { maxTasks: this.maxTasks });
|
|
137
|
+
this._setState(holder, "shutdown", { reason: "max-tasks" });
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// Team budget (token/USD/time/task) — stop CLAIMING once any cap is hit so
|
|
141
|
+
// the team overshoots by at most the tasks already in flight.
|
|
142
|
+
if (this.budget && this.budget.shouldStop()) {
|
|
143
|
+
const reason = this.budget.reason();
|
|
144
|
+
if (!this._budgetStopped) {
|
|
145
|
+
this._budgetStopped = true;
|
|
146
|
+
this._emit("run:budget-exhausted", { reason });
|
|
147
|
+
}
|
|
148
|
+
this._setState(holder, "shutdown", { reason });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const key = this._nextFor(holder);
|
|
152
|
+
if (!key) {
|
|
153
|
+
// Nothing to claim right now. If peers are still working, wait and
|
|
154
|
+
// retry (their completions may unblock a dependent). Otherwise we're done.
|
|
155
|
+
if (this._inFlight > 0) {
|
|
156
|
+
this._setState(holder, "idle");
|
|
157
|
+
await this._tick();
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
this._setState(holder, "shutdown", { reason: "no-more-work" });
|
|
161
|
+
return; // no claimable + nothing in flight → this worker is finished
|
|
162
|
+
}
|
|
163
|
+
const acq = this.registry.acquire(key, { holder, ttlMs: this.ttlMs });
|
|
164
|
+
if (!acq.ok) {
|
|
165
|
+
// Lost the race to a peer (or it just got blocked) — try another.
|
|
166
|
+
this._setState(holder, "idle");
|
|
167
|
+
await this._tick();
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
await this._execute(holder, key, acq.lease);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Pick a claimable task key for this holder (highest priority first). */
|
|
175
|
+
_nextFor() {
|
|
176
|
+
const claimable = this.registry.claimable();
|
|
177
|
+
if (claimable.length === 0) return null;
|
|
178
|
+
// Stable: prefer higher priority, else insertion order (claimable order).
|
|
179
|
+
const rank = { high: 0, normal: 1, low: 2 };
|
|
180
|
+
let best = null;
|
|
181
|
+
let bestScore = Infinity;
|
|
182
|
+
for (const key of claimable) {
|
|
183
|
+
const t = this.registry.getTask(key);
|
|
184
|
+
const score = rank[t?.priority] ?? 1;
|
|
185
|
+
if (score < bestScore) {
|
|
186
|
+
bestScore = score;
|
|
187
|
+
best = key;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return best;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async _execute(holder, key, lease) {
|
|
194
|
+
const task = this.registry.getTask(key);
|
|
195
|
+
this._executions++;
|
|
196
|
+
this._inFlight++;
|
|
197
|
+
this._maxInFlight = Math.max(this._maxInFlight, this._inFlight);
|
|
198
|
+
this._setState(holder, "running", { key });
|
|
199
|
+
this._emit("task:claimed", { key, holder, attempts: task.attempts });
|
|
200
|
+
const renew = () => this.registry.renew(key, { holder, ttlMs: this.ttlMs });
|
|
201
|
+
// A teammate-scoped messaging handle: post to a peer / broadcast, and read
|
|
202
|
+
// its own inbox (direct messages + unseen broadcasts).
|
|
203
|
+
const inbox = this.mailbox ? this.mailbox.drain(holder) : [];
|
|
204
|
+
const sendMessage = (to, body, subject = null) =>
|
|
205
|
+
this.mailbox
|
|
206
|
+
? this.mailbox.send({ from: holder, to, subject, body })
|
|
207
|
+
: null;
|
|
208
|
+
const startedAt = this._now();
|
|
209
|
+
try {
|
|
210
|
+
const result = await this.runTask({
|
|
211
|
+
key,
|
|
212
|
+
task,
|
|
213
|
+
holder,
|
|
214
|
+
renew,
|
|
215
|
+
inbox,
|
|
216
|
+
sendMessage,
|
|
217
|
+
mailbox: this.mailbox,
|
|
218
|
+
budget: this.budget,
|
|
219
|
+
});
|
|
220
|
+
const done = this.registry.complete(key, { holder, result });
|
|
221
|
+
// Fold usage/cost into the team budget regardless — the task DID execute
|
|
222
|
+
// and consumed resources. `--exec` shell tasks carry no usage → only the
|
|
223
|
+
// task-count / wall-clock dimensions move.
|
|
224
|
+
if (this.budget) {
|
|
225
|
+
this.budget.record(
|
|
226
|
+
{
|
|
227
|
+
usage: result?.usage || null,
|
|
228
|
+
provider: result?.provider,
|
|
229
|
+
model: result?.model,
|
|
230
|
+
},
|
|
231
|
+
this._now(),
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
if (done.ok) {
|
|
235
|
+
this._setState(holder, "completed-task");
|
|
236
|
+
this._emit("task:completed", {
|
|
237
|
+
key,
|
|
238
|
+
holder,
|
|
239
|
+
ms: this._now() - startedAt,
|
|
240
|
+
});
|
|
241
|
+
} else {
|
|
242
|
+
// The registry REJECTED the completion — the lease expired mid-run (the
|
|
243
|
+
// task outran its TTL without renewing), so a peer may already own it.
|
|
244
|
+
// Reporting `task:completed` + bumping the completed counter here would
|
|
245
|
+
// be a phantom success (the registry has no record of it, and the task
|
|
246
|
+
// will be reclaimed and re-run). Surface the discard honestly instead so
|
|
247
|
+
// the event stream and per-teammate stats stay truthful.
|
|
248
|
+
this._emit("task:completion-discarded", {
|
|
249
|
+
key,
|
|
250
|
+
holder,
|
|
251
|
+
reason: done.reason,
|
|
252
|
+
ms: this._now() - startedAt,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
} catch (err) {
|
|
256
|
+
// A failed task still consumed a task-count slot (and any wall-clock) — fold
|
|
257
|
+
// it so a doomed retry loop can't dodge the budget.
|
|
258
|
+
if (this.budget) this.budget.record({ usage: null }, this._now());
|
|
259
|
+
const outcome = this.registry.fail(key, {
|
|
260
|
+
holder,
|
|
261
|
+
error: err?.message || String(err),
|
|
262
|
+
});
|
|
263
|
+
this._setState(holder, "failed-task", {
|
|
264
|
+
error: err?.message || String(err),
|
|
265
|
+
});
|
|
266
|
+
this._emit("task:failed", {
|
|
267
|
+
key,
|
|
268
|
+
holder,
|
|
269
|
+
error: err?.message || String(err),
|
|
270
|
+
retry: outcome?.retry === true,
|
|
271
|
+
attempts: outcome?.attempts,
|
|
272
|
+
});
|
|
273
|
+
} finally {
|
|
274
|
+
this._inFlight--;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** Yield to the event loop so peer completions land before re-checking. */
|
|
279
|
+
_tick() {
|
|
280
|
+
return new Promise((resolve) => setTimeout(resolve, 0));
|
|
281
|
+
}
|
|
282
|
+
}
|