chainlesschain 0.162.149 → 0.162.151
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +3 -2
- package/src/assets/web-panel/assets/{AIOps-BJif14yR.js → AIOps-DuEOzebi.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CXek6gJY.js → ActionButton-C6GiJa5H.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BgQhdAJi.js → Analytics-BBIiL_pO.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DTYl5NtR.js → AppLayout-CuI2gZRy.js} +3 -3
- package/src/assets/web-panel/assets/{Audit-BzATQAeR.js → Audit-CbUjfr-K.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BzdPEQhL.js → Backup-CsSW9ljf.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BM0KVh8E.js → BaseInput-kM3rLe7F.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-D7fHXHkz.js → Chat-kfE51YN3.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Wm34RR-b.js → ChatBubbleRenderer-Bg2FTW6A.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-CAiSQ9vO.js → Checkbox-jYb1uj-M.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Df40CrEe.js → Codegen-X9XiD5Lj.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DIT2fNFU.js → Col-BfbHu1xI.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CSTIbW2k.js → Community-c4oJMFS-.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DtqXZZUi.js → Compact-BFmnZpH7.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CUtzw6o7.js → Compliance-s9shVHBS.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CezmlnmU.js → Cowork-C5da--TC.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-P4BITarg.js → Cron-9kNbyNE4.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BRRiYwvq.js → Crosschain-C1k3NJD4.js} +1 -1
- package/src/assets/web-panel/assets/{DID-L5ijB9i4.js → DID-DkheEvNK.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CFxro4ob.js → Dashboard-C3FuSGmJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BmAFCQ71.js → Dropdown-CAV6FMFD.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DJBCEuon.js → EmailListRenderer-Cc-Ulc4l.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-z4oLq6eT.js → FamilyGuardDashboard-8CitHEtv.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DsVCpHMF.js → Federation-DFSZ5KDt.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DP3bP5th.js → FormItemContext-CEWCtnG2.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BAXP2Gc6.js → GenericCardRenderer-CwRzNzmX.js} +1 -1
- package/src/assets/web-panel/assets/{Git-I3g_bAw9.js → Git-0rgDM7cJ.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-jHS5-ioS.js → Governance-CfBKtK9F.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CPL7sfx9.js → Inference-CzcUVvud.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Jf236h4C.js → KnowledgeGraph-Dwc4YL4A.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Cm2tcSKg.js → Logs-DgFPwR2F.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-CZK82rhi.js → Marketplace-DnpPTbGU.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CZCeji7a.js → McpTools-DRxxINyW.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-3l2KVS9k.js → Memory-OhmW_6Z3.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-VYdpoLh6.js → MobileBridge-DkTW-RK5.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-CiB9cmm1.js → MobileProjects-DpCGV_lI.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-wCFZbBuL.js → Mtc--vmkL0AS.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-1a3THIyG.js → MtcAudit-DGoFWjD4.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-DMzLB2hG.js → Multisig-B4kWgq95.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-D9wZbf6l.js → NLProgramming-YQwvommE.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-hrFe2ZM-.js → Notes-CgjtUADJ.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CHGX5Jwm.js → NotificationSettings-6JDrpBG5.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-PM6IlxjO.js +1 -0
- package/src/assets/web-panel/assets/{Organization-By7FkhtY.js → Organization-8McOT_OF.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow--khGSzJn.js → Overflow-DAZpSCGc.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CAG9dH35.js → P2P-B7l2ZWLy.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-B3SQZmK9.js → PdhVaultBrowser-W1Ud-NAL.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-D35ec6JA.js → Permissions-Czm_w9u_.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CxBF7hW_.js → PersonalDataHub-B4F0_ZVM.js} +2 -2
- package/src/assets/web-panel/assets/{Pipeline-s6EtOO1s.js → Pipeline-B37aFiWv.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BbJYmWmO.js → Privacy-94KBnRrD.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-VGQq1jMT.js → ProjectInit-B5h8_dlh.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-B1ew3Teh.js → ProjectSettings-lmeI3Lpm.js} +2 -2
- package/src/assets/web-panel/assets/Projects-D5AYOasl.js +1 -0
- package/src/assets/web-panel/assets/{Providers-mrO47FIK.js → Providers-B3cNWwJg.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-IJF2mHyw.js → QrScannerModal-CHRvOw1R.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CU0wN_Z0.js → QuickAsk-D1JMgFEd.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DhN37R6G.js → Recommend-EYWGR79p.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-D_xOX_hu.js → RemoteSession-BAMC2pJt.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-D_Ssv7uH.js → Reputation-X2Hk1XG_.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Kx5dKxX7.js → Row-Eq98LRtU.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BlGwqZkY.js → RssFeed-i76s6z_o.js} +2 -2
- package/src/assets/web-panel/assets/{Search-hLFQzxpb.js → Search-D_Es7CAI.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DMlvsVt4.js → Security-kayD2e94.js} +3 -3
- package/src/assets/web-panel/assets/{Services-Bd0Qsj2m.js → Services-Ctsm6ul8.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DFclq9X3.js → Skeleton-CRNYlfdf.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BNtln2qY.js → Skills-DkZYpF4-.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-Dch5H19G.js → Sla-DXkoBcOP.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-2UfQcU1g.js → SpeechSettings-DXi_GI1d.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CD9YQr4i.js → SyncSettings-rNKpfomn.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BNu-7MzI.js → Tasks-XF4uPtG-.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D1n9CaIR.js → Templates-i0Hzfeyu.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DenL3iBW.js → Tenant-sMpHAi27.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-BoZvaYAl.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-D87IfukO.js → TimelineRenderer-yuC6K7Rf.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BkiZc8E3.js → Tokens-B8O8i0s6.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BNRSytGN.js → Trigger-Bv6yrlCr.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-Bwbd4X2m.js → Trust-C4mW95Ev.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B8O2bs0o.js → UkeySign-DV6yKaHn.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C2fL8zmH.js → VideoEditing-UI479-sD.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BORYDdE1.js → Wallet-M5oV9EVP.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-C0V5S2FM.js → WebAuthn-DDyDHPDR.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-2dR0fcHL.js → WorkflowEditor-RoBv4rqk.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BmuAFAn8.js → chat-Cw1mE5LS.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CN3smMcK.js → colors-BFP62Gwf.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DCnxb4kW.js → compact-item-17HL6pyC.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-vlR43pHn.js → createContext-D55X4fZX.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CqbHYuRc.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D04tHYFd.js → hasIn-D3E5mNsP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbVsQBOH.js → index--44J50mc.js} +1 -1
- package/src/assets/web-panel/assets/{index-TslMTwNy.js → index-ASPYTzMK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTOCnIQ7.js → index-BC6zxOlU.js} +1 -1
- package/src/assets/web-panel/assets/{index-ljuBiQW9.js → index-BEa1RW4c.js} +1 -1
- package/src/assets/web-panel/assets/{index-jzR7Ujuw.js → index-BQmZg5si.js} +1 -1
- package/src/assets/web-panel/assets/{index-BudvKQfG.js → index-BY_xZ2jy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CP9m9Ggr.js → index-BgN5G5vF.js} +3 -3
- package/src/assets/web-panel/assets/{index-Cr-A0FYJ.js → index-BnGpft-Z.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5LZVZ0L.js → index-Bq83UBDr.js} +1 -1
- package/src/assets/web-panel/assets/{index-ToUh2b1-.js → index-Bzpp2z2S.js} +1 -1
- package/src/assets/web-panel/assets/{index-DbADHwhr.js → index-CFYGn88j.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClhAHDK3.js → index-CGyTos4p.js} +1 -1
- package/src/assets/web-panel/assets/index-CKBI1U5K.js +1 -0
- package/src/assets/web-panel/assets/{index-C-6NO5il.js → index-CLEzsZ8A.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8vwp4qp.js → index-CR9rNUvi.js} +1 -1
- package/src/assets/web-panel/assets/{index-_FIkN3jd.js → index-CW6LLoJO.js} +1 -1
- package/src/assets/web-panel/assets/{index-D65_XseV.js → index-C_MfcrLf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnXebZLL.js → index-Cdvk2_2q.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_n8_vfI.js → index-CjCwi7we.js} +1 -1
- package/src/assets/web-panel/assets/index-CkLp6DTO.js +1 -0
- package/src/assets/web-panel/assets/{index-DDwLgQY9.js → index-CvCFKojj.js} +1 -1
- package/src/assets/web-panel/assets/{index-430S68MN.js → index-D4LHSde4.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXRg8GFQ.js → index-DCLu84x-.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTtRscUa.js → index-DD_qGBrt.js} +1 -1
- package/src/assets/web-panel/assets/{index-BasvsWDM.js → index-DIRvdwBX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BeGDEXFs.js → index-DOjA8bvj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CsAsCPJ6.js → index-Da27u6j0.js} +1 -1
- package/src/assets/web-panel/assets/{index-D28DeAAB.js → index-DkBVYlE4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CngCC8hC.js → index-DtAnPBWP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B78xL3s2.js → index-DzG7mkgW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIpY0qM5.js → index-H9_X1Cg_.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5Sxb1sE.js → index-ITeEHb8L.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTPEZTk1.js → index-KtLJXn4s.js} +1 -1
- package/src/assets/web-panel/assets/{index-hpvvtAZ3.js → index-RYZgFIwo.js} +1 -1
- package/src/assets/web-panel/assets/{index-HhNjnCfe.js → index-gAVxDiTZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTWg-18U.js → index-paVubXzn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqhASEL4.js → index-tUH_6bdJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYAtmqiv.js → index-tVRPgYGr.js} +1 -1
- package/src/assets/web-panel/assets/{index-0DnaZGkC.js → index-uSsiwgZ2.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C3wUb4je.js → initDefaultProps-Ckp7xVZS.js} +1 -1
- package/src/assets/web-panel/assets/{motion-D-jYFUNA.js → motion-DUZgCpn6.js} +1 -1
- package/src/assets/web-panel/assets/{move-tqb8nwJ2.js → move-B2rttglH.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DSOjMJMz.js → mtc-parser-BYWcLTuN.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CJ7VimIW.js → omit-DhHqKeFx.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-qXiG1iT3.js → pickAttrs-ANpJaWMO.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CkGBcy1Z.js → placementArrow-CfZWe7CA.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-D3WvTlLO.js → responsiveObserve-D7Xz2y-R.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BEE2ftge.js → slide-DekqCBY9.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-CsfBpxiG.js → statusUtils-BET6XU7h.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-xPrIiJPI.js → styleChecker-qHmJjV62.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C5Yd-SCR.js → useFlexGapSupport-BoMCTNyu.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-D_MDS8HI.js → useFs-TdW-NgFC.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BqJh-usA.js → usePersonalDataHub-Dyox7wCu.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-chm_p-gz.js → vnode-XUn5S8CP.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-3-YDNz0Z.js → zoom-Ls77i8hn.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-manifest.json +8 -1
- package/src/commands/a2a.js +19 -4
- package/src/commands/activitypub.js +20 -3
- package/src/commands/agent.js +27 -5
- package/src/commands/audit.js +40 -24
- package/src/commands/changelog.js +148 -0
- package/src/commands/codeintel.js +68 -0
- package/src/commands/collab.js +15 -2
- package/src/commands/compliance.js +5 -0
- package/src/commands/config.js +4 -1
- package/src/commands/dao.js +86 -14
- package/src/commands/dev.js +2 -0
- package/src/commands/did.js +7 -1
- package/src/commands/dlp.js +23 -1
- package/src/commands/economy.js +29 -3
- package/src/commands/eval.js +7 -0
- package/src/commands/evomap.js +26 -0
- package/src/commands/governance.js +17 -3
- package/src/commands/hardening.js +18 -0
- package/src/commands/incentive.js +5 -0
- package/src/commands/init.js +46 -2
- package/src/commands/kg.js +4 -0
- package/src/commands/loop.js +6 -1
- package/src/commands/lowcode.js +15 -2
- package/src/commands/marketplace.js +40 -6
- package/src/commands/matrix.js +20 -1
- package/src/commands/memory.js +4 -1
- package/src/commands/mtc.js +7 -1
- package/src/commands/nostr.js +31 -4
- package/src/commands/note.js +7 -4
- package/src/commands/plugin.js +125 -5
- package/src/commands/pqc.js +5 -0
- package/src/commands/reputation.js +10 -1
- package/src/commands/scim.js +6 -0
- package/src/commands/session.js +32 -10
- package/src/commands/siem.js +11 -0
- package/src/commands/sla.js +18 -3
- package/src/commands/social.js +38 -5
- package/src/commands/sso.js +10 -2
- package/src/commands/stress.js +23 -4
- package/src/commands/team.js +9 -2
- package/src/commands/tech.js +2 -0
- package/src/commands/tenant.js +10 -1
- package/src/commands/terraform.js +6 -0
- package/src/commands/update.js +1 -1
- package/src/commands/zkp.js +20 -0
- package/src/data/changelog.json +189 -0
- package/src/gateways/ws/message-dispatcher.js +5 -2
- package/src/gateways/ws/remote-session-protocol.js +110 -42
- package/src/harness/jsonl-session-store.js +12 -5
- package/src/harness/plugin-manager.js +16 -4
- package/src/harness/remote-command-ledger.js +46 -15
- package/src/harness/worktree-isolator.js +16 -6
- package/src/index.js +2 -0
- package/src/lib/__tests__/logger.test.js +5 -2
- package/src/lib/a2a-protocol.js +25 -1
- package/src/lib/activitypub-bridge.js +61 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-economy.js +262 -29
- package/src/lib/agent-network.js +7 -1
- package/src/lib/agent-team/team-runner.js +25 -9
- package/src/lib/agent-team/team-worktree.js +36 -4
- package/src/lib/async-hook-supervisor.cjs +102 -16
- package/src/lib/audit-logger.js +7 -6
- package/src/lib/autonomous-developer.js +60 -0
- package/src/lib/changelog.js +252 -0
- package/src/lib/chat-core.js +17 -4
- package/src/lib/collaboration-governance.js +56 -0
- package/src/lib/community-governance.js +68 -0
- package/src/lib/compliance-manager.js +63 -0
- package/src/lib/cross-chain.js +5 -0
- package/src/lib/dao-governance.js +151 -2
- package/src/lib/did-manager.js +23 -10
- package/src/lib/dlp-engine.js +70 -0
- package/src/lib/eval/runner.js +89 -1
- package/src/lib/eval/tasks.js +170 -0
- package/src/lib/eval/trend.js +16 -1
- package/src/lib/evolution-system.js +92 -0
- package/src/lib/evomap-federation.js +55 -0
- package/src/lib/evomap-governance.js +94 -0
- package/src/lib/fatal-handler.js +17 -1
- package/src/lib/hardening-manager.js +73 -0
- package/src/lib/hierarchical-memory.js +14 -8
- package/src/lib/knowledge-exporter.js +8 -2
- package/src/lib/knowledge-graph.js +79 -0
- package/src/lib/llm-providers.js +23 -14
- package/src/lib/logger.js +4 -1
- package/src/lib/lsp/__tests__/benchmark.test.js +88 -0
- package/src/lib/lsp/__tests__/lsp-client.test.js +11 -0
- package/src/lib/lsp/__tests__/lsp-manager.test.js +69 -0
- package/src/lib/lsp/benchmark.js +257 -0
- package/src/lib/lsp/lsp-client.js +30 -9
- package/src/lib/lsp/lsp-manager.js +54 -2
- package/src/lib/lsp/lsp-server-registry.js +15 -4
- package/src/lib/matrix-bridge.js +84 -0
- package/src/lib/memory-manager.js +5 -3
- package/src/lib/nostr-bridge.js +53 -0
- package/src/lib/permission-engine.js +22 -4
- package/src/lib/plugin-runtime/__tests__/remote-source.test.js +256 -0
- package/src/lib/plugin-runtime/hooks.js +20 -4
- package/src/lib/plugin-runtime/install.js +9 -1
- package/src/lib/plugin-runtime/monitors.js +20 -4
- package/src/lib/plugin-runtime/policy.js +9 -1
- package/src/lib/plugin-runtime/remote-source.js +240 -0
- package/src/lib/plugin-runtime/signature.js +16 -0
- package/src/lib/pqc-manager.js +64 -0
- package/src/lib/reputation-optimizer.js +101 -0
- package/src/lib/sandbox-egress-proxy.js +195 -59
- package/src/lib/sandbox-fs-policy.js +112 -0
- package/src/lib/sandbox-network-policy.js +44 -5
- package/src/lib/sandbox-v2.js +14 -14
- package/src/lib/scim-manager.js +36 -0
- package/src/lib/session-manager.js +5 -2
- package/src/lib/settings-hooks.cjs +1 -0
- package/src/lib/siem-exporter.js +45 -0
- package/src/lib/skill-loader.js +20 -2
- package/src/lib/skill-marketplace.js +83 -0
- package/src/lib/sla-manager.js +88 -0
- package/src/lib/social-manager.js +74 -0
- package/src/lib/stress-tester.js +65 -0
- package/src/lib/tech-learning-engine.js +75 -0
- package/src/lib/telemetry/span-recorder.js +12 -1
- package/src/lib/tenant-saas.js +107 -0
- package/src/lib/terraform-manager.js +67 -0
- package/src/lib/token-incentive.js +180 -29
- package/src/lib/wallet-manager.js +81 -35
- package/src/lib/zkp-engine.js +87 -0
- package/src/repl/agent-repl.js +17 -2
- package/src/runtime/__tests__/auto-pin.test.js +104 -0
- package/src/runtime/agent-core.js +241 -68
- package/src/runtime/auto-pin.js +117 -0
- package/src/runtime/headless-runner.js +35 -0
- package/src/assets/web-panel/assets/OrderTableRenderer-CRIFE2Tj.js +0 -1
- package/src/assets/web-panel/assets/Projects-CGcNIs_g.js +0 -1
- package/src/assets/web-panel/assets/Terminal-ZzU0Io1Y.js +0 -3
- package/src/assets/web-panel/assets/devWarning-DxwmsL4j.js +0 -1
- package/src/assets/web-panel/assets/index-Cg2ldRfU.js +0 -1
- package/src/assets/web-panel/assets/index-Dwzo-dtJ.js +0 -1
package/src/repl/agent-repl.js
CHANGED
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
PromptCompressor,
|
|
65
65
|
getContextWindow,
|
|
66
66
|
} from "../harness/prompt-compressor.js";
|
|
67
|
+
import { buildAutoPinPredicate } from "../runtime/auto-pin.js";
|
|
67
68
|
import { feature } from "../lib/feature-flags.js";
|
|
68
69
|
import { recordCompressionMetric } from "../lib/compression-telemetry.js";
|
|
69
70
|
import {
|
|
@@ -416,10 +417,15 @@ export async function startAgentRepl(options = {}) {
|
|
|
416
417
|
// Unset → agent-core's 180s default (matches cc chat/ask). Set to 0 to
|
|
417
418
|
// disable. Left undefined here means "use the default".
|
|
418
419
|
let _streamStallTimeoutMs;
|
|
420
|
+
// Auto-pin (OPT-IN, off by default): when set, compaction pins the original
|
|
421
|
+
// task. Resolved from config `context.autoPin` or CC_AUTO_PIN=1; falsy → the
|
|
422
|
+
// compress calls below pass no pin predicate (byte-identical default).
|
|
423
|
+
let _autoPinOpt;
|
|
419
424
|
try {
|
|
420
425
|
const { loadConfig } = await import("../lib/config-manager.js");
|
|
421
426
|
const _cfg = loadConfig();
|
|
422
427
|
_visionModel = _cfg?.llm?.visionModel || undefined;
|
|
428
|
+
_autoPinOpt = _cfg?.context?.autoPin;
|
|
423
429
|
const raw = _cfg?.llm?.streamStallTimeoutMs;
|
|
424
430
|
const t = Number(raw);
|
|
425
431
|
// Accept 0 (explicit disable) — only ignore absent/invalid values.
|
|
@@ -477,6 +483,15 @@ export async function startAgentRepl(options = {}) {
|
|
|
477
483
|
if (feature("PROMPT_COMPRESSOR")) {
|
|
478
484
|
_compressor = new PromptCompressor({ model, provider });
|
|
479
485
|
}
|
|
486
|
+
if (process.env.CC_AUTO_PIN === "1") _autoPinOpt = _autoPinOpt || true;
|
|
487
|
+
// Compaction options shared by /compact + auto-compact. Adds the opt-in
|
|
488
|
+
// pin predicate only when auto-pin is enabled; otherwise byte-identical.
|
|
489
|
+
const _compactOpts = (msgs) => {
|
|
490
|
+
const base = { preserveToolPairs: true };
|
|
491
|
+
if (!_autoPinOpt) return base;
|
|
492
|
+
const isPinned = buildAutoPinPredicate(msgs, _autoPinOpt);
|
|
493
|
+
return isPinned ? { ...base, isPinned } : base;
|
|
494
|
+
};
|
|
480
495
|
|
|
481
496
|
// Initialize permanent memory
|
|
482
497
|
let permanentMemory = null;
|
|
@@ -2533,7 +2548,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
2533
2548
|
if (_compressor && messages.length > 3) {
|
|
2534
2549
|
const { messages: compacted, stats } = await _compressor.compress(
|
|
2535
2550
|
messages,
|
|
2536
|
-
|
|
2551
|
+
_compactOpts(messages),
|
|
2537
2552
|
);
|
|
2538
2553
|
messages.length = 0;
|
|
2539
2554
|
messages.push(...compacted);
|
|
@@ -4460,7 +4475,7 @@ export async function startAgentRepl(options = {}) {
|
|
|
4460
4475
|
try {
|
|
4461
4476
|
const { messages: compacted, stats } = await _compressor.compress(
|
|
4462
4477
|
messages,
|
|
4463
|
-
|
|
4478
|
+
_compactOpts(messages),
|
|
4464
4479
|
);
|
|
4465
4480
|
messages.length = 0;
|
|
4466
4481
|
messages.push(...compacted);
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* auto-pin policy tests — the OPT-IN compaction pin policy. Verifies it is off
|
|
3
|
+
* by default (returns null → caller passes no predicate → byte-identical), and
|
|
4
|
+
* when enabled pins the original task (first user turn) plus explicit pins,
|
|
5
|
+
* honoring the token cap.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect } from "vitest";
|
|
9
|
+
import {
|
|
10
|
+
resolveAutoPinConfig,
|
|
11
|
+
buildAutoPinPredicate,
|
|
12
|
+
describeAutoPin,
|
|
13
|
+
} from "../auto-pin.js";
|
|
14
|
+
|
|
15
|
+
const MSGS = [
|
|
16
|
+
{ role: "system", content: "you are a coding agent" },
|
|
17
|
+
{ role: "user", content: "Refactor the auth module to use async/await" },
|
|
18
|
+
{ role: "assistant", content: "ok, reading files" },
|
|
19
|
+
{ role: "user", content: "also add tests" },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
describe("resolveAutoPinConfig", () => {
|
|
23
|
+
it("returns null when off (falsy)", () => {
|
|
24
|
+
expect(resolveAutoPinConfig(undefined)).toBeNull();
|
|
25
|
+
expect(resolveAutoPinConfig(false)).toBeNull();
|
|
26
|
+
expect(resolveAutoPinConfig(0)).toBeNull();
|
|
27
|
+
});
|
|
28
|
+
it("defaults firstUserGoal on when enabled with true", () => {
|
|
29
|
+
expect(resolveAutoPinConfig(true)).toMatchObject({ firstUserGoal: true });
|
|
30
|
+
});
|
|
31
|
+
it("accepts an object and can disable firstUserGoal", () => {
|
|
32
|
+
expect(resolveAutoPinConfig({ firstUserGoal: false })).toMatchObject({
|
|
33
|
+
firstUserGoal: false,
|
|
34
|
+
});
|
|
35
|
+
expect(resolveAutoPinConfig({ maxPinTokens: 50 }).maxPinTokens).toBe(50);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe("buildAutoPinPredicate", () => {
|
|
40
|
+
it("returns null when auto-pin is off (→ default compaction, byte-identical)", () => {
|
|
41
|
+
expect(buildAutoPinPredicate(MSGS, false)).toBeNull();
|
|
42
|
+
expect(buildAutoPinPredicate(MSGS, undefined)).toBeNull();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("pins the first user turn (the original task) when enabled", () => {
|
|
46
|
+
const isPinned = buildAutoPinPredicate(MSGS, true);
|
|
47
|
+
expect(isPinned(MSGS[1])).toBe(true); // first user
|
|
48
|
+
expect(isPinned(MSGS[3])).toBe(false); // second user NOT pinned
|
|
49
|
+
expect(isPinned(MSGS[0])).toBe(false); // system not pinned
|
|
50
|
+
expect(isPinned(MSGS[2])).toBe(false); // assistant not pinned
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("always honors explicit pins on top of the policy", () => {
|
|
54
|
+
const msgs = [
|
|
55
|
+
...MSGS,
|
|
56
|
+
{ role: "assistant", content: "important decision", pinned: true },
|
|
57
|
+
{ role: "assistant", content: "legacy marker", _pin: true },
|
|
58
|
+
];
|
|
59
|
+
const isPinned = buildAutoPinPredicate(msgs, true);
|
|
60
|
+
expect(isPinned(msgs[4])).toBe(true); // pinned:true
|
|
61
|
+
expect(isPinned(msgs[5])).toBe(true); // _pin
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("honors explicit pins even with firstUserGoal disabled", () => {
|
|
65
|
+
const msgs = [
|
|
66
|
+
MSGS[0],
|
|
67
|
+
MSGS[1],
|
|
68
|
+
{ role: "user", content: "x", pinned: true },
|
|
69
|
+
];
|
|
70
|
+
const isPinned = buildAutoPinPredicate(msgs, { firstUserGoal: false });
|
|
71
|
+
expect(isPinned(msgs[1])).toBe(false); // first user NOT auto-pinned
|
|
72
|
+
expect(isPinned(msgs[2])).toBe(true); // explicit pin still honored
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("skips a first user turn that exceeds the token cap", () => {
|
|
76
|
+
const big = { role: "user", content: "x".repeat(10_000) }; // ~2500 tokens
|
|
77
|
+
const msgs = [MSGS[0], big, MSGS[2]];
|
|
78
|
+
const isPinned = buildAutoPinPredicate(msgs, { maxPinTokens: 100 });
|
|
79
|
+
expect(isPinned(big)).toBe(false); // too big to pin
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("matches by identity, not by value (compaction filters the same array)", () => {
|
|
83
|
+
const isPinned = buildAutoPinPredicate(MSGS, true);
|
|
84
|
+
const clone = { ...MSGS[1] }; // same content, different object
|
|
85
|
+
expect(isPinned(clone)).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe("describeAutoPin", () => {
|
|
90
|
+
it("reports disabled when off", () => {
|
|
91
|
+
expect(describeAutoPin(MSGS, false)).toEqual({
|
|
92
|
+
enabled: false,
|
|
93
|
+
reasons: [],
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
it("explains the original-task pin", () => {
|
|
97
|
+
const d = describeAutoPin(MSGS, true);
|
|
98
|
+
expect(d.enabled).toBe(true);
|
|
99
|
+
expect(d.reasons.some((r) => r.why.includes("original task"))).toBe(true);
|
|
100
|
+
expect(d.reasons[d.reasons.length - 1].preview).toContain(
|
|
101
|
+
"Refactor the auth",
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -221,6 +221,77 @@ export function killAllBackgroundShellTasks() {
|
|
|
221
221
|
return killed;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
// SYNCHRONOUS whole-tree kill for use inside a process 'exit' / signal handler,
|
|
225
|
+
// where only synchronous work runs to completion (the async `spawn`/`taskkill`
|
|
226
|
+
// in _killTask would be cut off the instant the process terminates, leaving the
|
|
227
|
+
// grandchild orphaned). POSIX signals the process group with SIGKILL; Windows
|
|
228
|
+
// uses spawnSync taskkill /T so the shell's children die too.
|
|
229
|
+
function _killTaskSync(task) {
|
|
230
|
+
const child = task?.child;
|
|
231
|
+
if (!child || child.killed || task?.status !== "running") return false;
|
|
232
|
+
try {
|
|
233
|
+
if (process.platform === "win32") {
|
|
234
|
+
if (child.pid) {
|
|
235
|
+
spawnSync("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
236
|
+
windowsHide: true,
|
|
237
|
+
});
|
|
238
|
+
} else {
|
|
239
|
+
child.kill();
|
|
240
|
+
}
|
|
241
|
+
} else if (child.pid) {
|
|
242
|
+
// Negative pid → whole process group (requires the detached spawn above).
|
|
243
|
+
try {
|
|
244
|
+
process.kill(-child.pid, "SIGKILL");
|
|
245
|
+
} catch (_err) {
|
|
246
|
+
child.kill("SIGKILL");
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
child.kill("SIGKILL");
|
|
250
|
+
}
|
|
251
|
+
return true;
|
|
252
|
+
} catch (_err) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Synchronously kill every still-running background shell task. Safe to call
|
|
259
|
+
* from a process 'exit' or signal handler (uses spawnSync/process.kill, not the
|
|
260
|
+
* async spawn path which a terminating process would cut off). This is the
|
|
261
|
+
* orphan-reclaim net for the paths the normal `finally` reaper can't cover: a
|
|
262
|
+
* Ctrl-C / SIGTERM unwinds no `finally`, so without it a backgrounded dev server
|
|
263
|
+
* outlives a killed `cc agent -p`.
|
|
264
|
+
* @returns {number} count of tasks signalled
|
|
265
|
+
*/
|
|
266
|
+
export function killAllBackgroundShellTasksSync() {
|
|
267
|
+
let killed = 0;
|
|
268
|
+
for (const task of _backgroundShellTasks.values()) {
|
|
269
|
+
if (_killTaskSync(task)) {
|
|
270
|
+
killed += 1;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return killed;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Install a one-time process 'exit' net that synchronously reaps background
|
|
277
|
+
// shell tasks. `finally` blocks (headless/REPL) already reap on normal
|
|
278
|
+
// completion, but an explicit process.exit() elsewhere (serve shutdown, the
|
|
279
|
+
// headless signal handler that converts Ctrl-C → exit) would otherwise leave a
|
|
280
|
+
// backgrounded command orphaned. Installed lazily on the first background task,
|
|
281
|
+
// so a process that never backgrounds anything pays nothing.
|
|
282
|
+
let _bgExitReaperHooked = false;
|
|
283
|
+
function _ensureBgExitReaper() {
|
|
284
|
+
if (_bgExitReaperHooked) return;
|
|
285
|
+
_bgExitReaperHooked = true;
|
|
286
|
+
process.once("exit", () => {
|
|
287
|
+
try {
|
|
288
|
+
killAllBackgroundShellTasksSync();
|
|
289
|
+
} catch {
|
|
290
|
+
/* best-effort teardown on exit */
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
224
295
|
// Idle-reap tuning (Claude-Code 2.1.193 "automatic memory-pressure reaping for
|
|
225
296
|
// idle background shell commands"). A running task is a reap candidate when it
|
|
226
297
|
// has produced no output for BG_IDLE_REAP_MS AND the system is under memory
|
|
@@ -324,16 +395,12 @@ async function runSettingsPreToolUseHooks(name, args, context, cwd) {
|
|
|
324
395
|
ideResult: ide.result,
|
|
325
396
|
};
|
|
326
397
|
}
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
rule: `hook:${outcome.hook}`,
|
|
334
|
-
reason: outcome.reason || "a PreToolUse hook requests confirmation",
|
|
335
|
-
})
|
|
336
|
-
: false;
|
|
398
|
+
const ok = await requestInteractivePermission(name, args, context, cwd, {
|
|
399
|
+
tool: name,
|
|
400
|
+
args,
|
|
401
|
+
rule: `hook:${outcome.hook}`,
|
|
402
|
+
reason: outcome.reason || "a PreToolUse hook requests confirmation",
|
|
403
|
+
});
|
|
337
404
|
return ok
|
|
338
405
|
? { blocked: false }
|
|
339
406
|
: {
|
|
@@ -345,6 +412,87 @@ async function runSettingsPreToolUseHooks(name, args, context, cwd) {
|
|
|
345
412
|
return { blocked: false };
|
|
346
413
|
}
|
|
347
414
|
|
|
415
|
+
/**
|
|
416
|
+
* Run settings.json `PermissionRequest` hooks (Claude-Code parity). Fires at the
|
|
417
|
+
* exact moment a tool call would prompt the user for approval — BEFORE the
|
|
418
|
+
* prompt — so a policy hook can auto-approve (`allow`/`approve`), auto-reject
|
|
419
|
+
* (`deny`/`block`), or defer (`ask` / no decision) to the normal prompt.
|
|
420
|
+
* Returns `{ decision: "allow" | "deny" | null }`. No matching hook (or no
|
|
421
|
+
* `settingsHooks`) → `{ decision: null }` and the caller prompts exactly as
|
|
422
|
+
* before (default behaviour is byte-for-byte unchanged).
|
|
423
|
+
* @returns {{decision:("allow"|"deny"|null), reason?:string, hook?:string}}
|
|
424
|
+
*/
|
|
425
|
+
function runSettingsPermissionRequestHooks(name, args, context, cwd, reason) {
|
|
426
|
+
const matched = collectHooks(
|
|
427
|
+
context.settingsHooks,
|
|
428
|
+
"PermissionRequest",
|
|
429
|
+
name,
|
|
430
|
+
);
|
|
431
|
+
if (!matched || matched.length === 0) return { decision: null };
|
|
432
|
+
const payload = {
|
|
433
|
+
hook_event_name: "PermissionRequest",
|
|
434
|
+
tool_name: umbrellaFor(name),
|
|
435
|
+
raw_tool_name: name,
|
|
436
|
+
tool_input: args,
|
|
437
|
+
permission_reason: reason || null,
|
|
438
|
+
cwd,
|
|
439
|
+
session_id: context.sessionId || null,
|
|
440
|
+
};
|
|
441
|
+
const outcome = runCommandHooks(matched, payload, {
|
|
442
|
+
cwd,
|
|
443
|
+
event: "PermissionRequest",
|
|
444
|
+
});
|
|
445
|
+
// Precedence: deny > ask > allow > defer. The runner normalizes deny/block →
|
|
446
|
+
// "block" and short-circuits block/ask, but it COLLAPSES an "allow" into the
|
|
447
|
+
// aggregate "continue" (it only short-circuits block/ask) — so an explicit
|
|
448
|
+
// auto-approve must be recovered from the per-hook `results`. A deny or ask
|
|
449
|
+
// by any hook still wins over an allow (safety: never let an allow override a
|
|
450
|
+
// gate that another hook wanted to block or prompt for).
|
|
451
|
+
if (outcome.decision === "block") {
|
|
452
|
+
return { decision: "deny", reason: outcome.reason, hook: outcome.hook };
|
|
453
|
+
}
|
|
454
|
+
if (outcome.decision === "ask") {
|
|
455
|
+
return { decision: null }; // a hook asked → defer to the confirmer
|
|
456
|
+
}
|
|
457
|
+
const allowHook =
|
|
458
|
+
outcome.decision === "allow"
|
|
459
|
+
? { command: outcome.hook }
|
|
460
|
+
: (outcome.results || []).find((r) => r && r.decision === "allow");
|
|
461
|
+
if (allowHook) {
|
|
462
|
+
return { decision: "allow", hook: allowHook.command || null };
|
|
463
|
+
}
|
|
464
|
+
return { decision: null }; // no actionable decision → defer to the confirmer
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Resolve an interactive permission gate. Gives `PermissionRequest` hooks first
|
|
469
|
+
* say (auto-allow → true without prompting, auto-deny → false without
|
|
470
|
+
* prompting), then falls back to the injected confirmer with the identical
|
|
471
|
+
* arguments the call site would have passed. When no `PermissionRequest` hook
|
|
472
|
+
* matches this is byte-for-byte the previous `confirm(confirmArgs)` call, so
|
|
473
|
+
* every existing permission gate keeps its exact behaviour absent a hook.
|
|
474
|
+
* @returns {Promise<boolean>}
|
|
475
|
+
*/
|
|
476
|
+
async function requestInteractivePermission(
|
|
477
|
+
name,
|
|
478
|
+
args,
|
|
479
|
+
context,
|
|
480
|
+
cwd,
|
|
481
|
+
confirmArgs,
|
|
482
|
+
) {
|
|
483
|
+
const verdict = runSettingsPermissionRequestHooks(
|
|
484
|
+
name,
|
|
485
|
+
args,
|
|
486
|
+
context,
|
|
487
|
+
cwd,
|
|
488
|
+
confirmArgs?.reason,
|
|
489
|
+
);
|
|
490
|
+
if (verdict.decision === "allow") return true;
|
|
491
|
+
if (verdict.decision === "deny") return false;
|
|
492
|
+
const confirm = context.permissionConfirm || context.shellConfirm || null;
|
|
493
|
+
return typeof confirm === "function" ? await confirm(confirmArgs) : false;
|
|
494
|
+
}
|
|
495
|
+
|
|
348
496
|
// ─── Tool definitions ────────────────────────────────────────────────────
|
|
349
497
|
|
|
350
498
|
export const AGENT_TOOLS = getCodingAgentFunctionToolDefinitions();
|
|
@@ -1082,16 +1230,12 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1082
1230
|
source: "settings rule",
|
|
1083
1231
|
});
|
|
1084
1232
|
if (ide) return ide.result;
|
|
1085
|
-
const
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
rule: settingsVerdict.rule,
|
|
1092
|
-
reason: `settings rule ${settingsVerdict.rule} requires confirmation`,
|
|
1093
|
-
})
|
|
1094
|
-
: false;
|
|
1233
|
+
const ok = await requestInteractivePermission(name, args, context, cwd, {
|
|
1234
|
+
tool: name,
|
|
1235
|
+
args,
|
|
1236
|
+
rule: settingsVerdict.rule,
|
|
1237
|
+
reason: `settings rule ${settingsVerdict.rule} requires confirmation`,
|
|
1238
|
+
});
|
|
1095
1239
|
if (!ok) {
|
|
1096
1240
|
return {
|
|
1097
1241
|
error: `[Permission] Tool "${name}" requires confirmation (settings rule: ${settingsVerdict.rule}) but this run is non-interactive — denied. Do not retry; tell the user this action needs their approval.`,
|
|
@@ -1123,16 +1267,12 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1123
1267
|
await import("../lib/sensitive-file-guard.js");
|
|
1124
1268
|
const sensReason = sensitiveFileReason(args.path);
|
|
1125
1269
|
if (sensReason) {
|
|
1126
|
-
const
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
rule: null,
|
|
1133
|
-
reason: `sensitive file: ${sensReason}`,
|
|
1134
|
-
})
|
|
1135
|
-
: false;
|
|
1270
|
+
const ok = await requestInteractivePermission(name, args, context, cwd, {
|
|
1271
|
+
tool: name,
|
|
1272
|
+
args,
|
|
1273
|
+
rule: null,
|
|
1274
|
+
reason: `sensitive file: ${sensReason}`,
|
|
1275
|
+
});
|
|
1136
1276
|
if (!ok) {
|
|
1137
1277
|
return {
|
|
1138
1278
|
error: `[Sensitive File] Writing "${args.path}" requires confirmation (${sensReason}) — denied. Add a settings allow rule to pre-authorize.`,
|
|
@@ -1155,16 +1295,12 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1155
1295
|
!planManager.isActive() &&
|
|
1156
1296
|
isDangerousGitCommand(args?.command)
|
|
1157
1297
|
) {
|
|
1158
|
-
const
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
rule: null,
|
|
1165
|
-
reason: `destructive git command: git ${normalizeGitCommand(args.command)}`,
|
|
1166
|
-
})
|
|
1167
|
-
: false;
|
|
1298
|
+
const ok = await requestInteractivePermission(name, args, context, cwd, {
|
|
1299
|
+
tool: name,
|
|
1300
|
+
args,
|
|
1301
|
+
rule: null,
|
|
1302
|
+
reason: `destructive git command: git ${normalizeGitCommand(args.command)}`,
|
|
1303
|
+
});
|
|
1168
1304
|
if (!ok) {
|
|
1169
1305
|
return {
|
|
1170
1306
|
error: `[Destructive Git] "git ${normalizeGitCommand(args.command)}" discards work irrecoverably and requires confirmation — denied. Add a settings allow rule to pre-authorize.`,
|
|
@@ -1199,17 +1335,18 @@ export async function executeTool(name, args, context = {}) {
|
|
|
1199
1335
|
credReason = hit ? hit.reason : null;
|
|
1200
1336
|
}
|
|
1201
1337
|
if (credReason) {
|
|
1202
|
-
const
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1338
|
+
const ok = await requestInteractivePermission(
|
|
1339
|
+
name,
|
|
1340
|
+
args,
|
|
1341
|
+
context,
|
|
1342
|
+
cwd,
|
|
1343
|
+
{
|
|
1344
|
+
tool: name,
|
|
1345
|
+
args,
|
|
1346
|
+
rule: null,
|
|
1347
|
+
reason: `credential access: ${credReason}`,
|
|
1348
|
+
},
|
|
1349
|
+
);
|
|
1213
1350
|
if (!ok) {
|
|
1214
1351
|
const what =
|
|
1215
1352
|
name === "read_file" ? `Reading "${args.path}"` : "This command";
|
|
@@ -1774,28 +1911,41 @@ const _codeIntelPool = new Map(); // root -> { ci, idleTimer }
|
|
|
1774
1911
|
const CODE_INTEL_IDLE_MS = 60_000;
|
|
1775
1912
|
let _codeIntelExitHooked = false;
|
|
1776
1913
|
|
|
1777
|
-
async function _getSharedCodeIntel(cwd) {
|
|
1914
|
+
export async function _getSharedCodeIntel(cwd) {
|
|
1778
1915
|
const root = path.resolve(cwd || process.cwd());
|
|
1779
1916
|
let entry = _codeIntelPool.get(root);
|
|
1780
1917
|
if (!entry) {
|
|
1781
1918
|
const { CodeIntelligence } =
|
|
1782
1919
|
await import("../lib/lsp/code-intelligence.js");
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1920
|
+
// Re-check AFTER the await: two concurrent callers (the parallel read-only
|
|
1921
|
+
// batch runs several `code_intelligence` calls at once) both observed an
|
|
1922
|
+
// empty pool before this `await import`, so without this guard both would
|
|
1923
|
+
// construct a CodeIntelligence — each spawning its own language server — and
|
|
1924
|
+
// the second `set` would orphan the first (leaked server process) while its
|
|
1925
|
+
// stale idle-timer, still bound to `root`, later evicts the wrong (warm,
|
|
1926
|
+
// in-use) entry. This is exactly the orphaned-server/dangling-timer trap the
|
|
1927
|
+
// pool exists to prevent. Construction below has NO further await, so once
|
|
1928
|
+
// one continuation wins the re-check the other reuses its entry — the window
|
|
1929
|
+
// is fully closed.
|
|
1930
|
+
entry = _codeIntelPool.get(root);
|
|
1931
|
+
if (!entry) {
|
|
1932
|
+
entry = {
|
|
1933
|
+
ci: new CodeIntelligence({ projectRoot: root, coldStart: true }),
|
|
1934
|
+
idleTimer: null,
|
|
1935
|
+
};
|
|
1936
|
+
_codeIntelPool.set(root, entry);
|
|
1937
|
+
if (!_codeIntelExitHooked) {
|
|
1938
|
+
_codeIntelExitHooked = true;
|
|
1939
|
+
process.once("exit", () => {
|
|
1940
|
+
for (const e of _codeIntelPool.values()) {
|
|
1941
|
+
try {
|
|
1942
|
+
e.ci.dispose();
|
|
1943
|
+
} catch {
|
|
1944
|
+
/* best-effort teardown on exit */
|
|
1945
|
+
}
|
|
1796
1946
|
}
|
|
1797
|
-
}
|
|
1798
|
-
}
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1799
1949
|
}
|
|
1800
1950
|
}
|
|
1801
1951
|
if (entry.idleTimer) clearTimeout(entry.idleTimer);
|
|
@@ -2327,6 +2477,9 @@ async function executeToolInner(
|
|
|
2327
2477
|
task.endedAt = new Date().toISOString();
|
|
2328
2478
|
}
|
|
2329
2479
|
_backgroundShellTasks.set(id, task);
|
|
2480
|
+
// Arm the process-exit net so a Ctrl-C / hard exit can't orphan this
|
|
2481
|
+
// task (the normal `finally` reaper is bypassed by signals).
|
|
2482
|
+
_ensureBgExitReaper();
|
|
2330
2483
|
return attachDescriptor(
|
|
2331
2484
|
{
|
|
2332
2485
|
background: true,
|
|
@@ -2463,6 +2616,14 @@ async function executeToolInner(
|
|
|
2463
2616
|
return attachDescriptor(
|
|
2464
2617
|
{
|
|
2465
2618
|
error: err.message.substring(0, 2000),
|
|
2619
|
+
// Surface stdout too: a failing command (test runner / linter /
|
|
2620
|
+
// build) usually prints WHAT failed to stdout and only the summary
|
|
2621
|
+
// to stderr, so dropping it on non-zero exit blinds the agent to the
|
|
2622
|
+
// actual failure. Only attach it when there IS output (a timeout with
|
|
2623
|
+
// no output keeps the field absent), mirroring the success path.
|
|
2624
|
+
...(err.stdout
|
|
2625
|
+
? { stdout: String(err.stdout).substring(0, 30000) }
|
|
2626
|
+
: {}),
|
|
2466
2627
|
stderr: (err.stderr || "").substring(0, 2000),
|
|
2467
2628
|
exitCode: err.status,
|
|
2468
2629
|
shellCommandPolicy: shellPolicy,
|
|
@@ -5440,10 +5601,22 @@ export async function* agentLoop(messages, options) {
|
|
|
5440
5601
|
reason: preCompactReason,
|
|
5441
5602
|
};
|
|
5442
5603
|
}
|
|
5604
|
+
// Auto-pin (OPT-IN): when enabled, the original task (first user turn)
|
|
5605
|
+
// is pinned so compaction can't drop it. Off by default → no predicate
|
|
5606
|
+
// is passed and compaction is byte-identical to before.
|
|
5607
|
+
let pinOpts = {};
|
|
5608
|
+
if (options.autoPin) {
|
|
5609
|
+
const { buildAutoPinPredicate } = await import("./auto-pin.js");
|
|
5610
|
+
const isPinned = buildAutoPinPredicate(messages, options.autoPin);
|
|
5611
|
+
if (isPinned) pinOpts = { isPinned };
|
|
5612
|
+
}
|
|
5443
5613
|
const { messages: compacted, stats } =
|
|
5444
5614
|
!needFull || preCompactBlocked
|
|
5445
5615
|
? { messages, stats: { saved: 0 } }
|
|
5446
|
-
: await compactor.compress(messages, {
|
|
5616
|
+
: await compactor.compress(messages, {
|
|
5617
|
+
preserveToolPairs: true,
|
|
5618
|
+
...pinOpts,
|
|
5619
|
+
});
|
|
5447
5620
|
if (stats.saved > 0 && compacted.length < messages.length) {
|
|
5448
5621
|
messages.splice(0, messages.length, ...compacted);
|
|
5449
5622
|
// Persist the compaction so a later --resume rebuilds from the
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-pin policy for compaction (OPT-IN).
|
|
3
|
+
*
|
|
4
|
+
* Phase 7.7 gave the compressor a deterministic pin mechanism: a message the
|
|
5
|
+
* predicate marks is pulled out before any strategy and re-inserted verbatim,
|
|
6
|
+
* so it survives compaction no matter what the (non-deterministic) LLM summary
|
|
7
|
+
* drops. What was deliberately left unbuilt is the *policy* — deciding WHICH
|
|
8
|
+
* messages to auto-pin — because auto-pinning reorders the hot agent loop's
|
|
9
|
+
* context and is a product-UX call.
|
|
10
|
+
*
|
|
11
|
+
* This module supplies that policy, but strictly opt-in: it only ever produces
|
|
12
|
+
* a predicate when the caller explicitly enables auto-pin. When disabled it
|
|
13
|
+
* returns null and the caller passes NO predicate, so the compressor falls back
|
|
14
|
+
* to its default (pin only messages already tagged `pinned:true`) and behaviour
|
|
15
|
+
* is byte-identical to before.
|
|
16
|
+
*
|
|
17
|
+
* Default policy when enabled: pin the ORIGINAL TASK — the first user turn —
|
|
18
|
+
* because that is the single fact most likely to scroll out of the recent
|
|
19
|
+
* window yet most important to keep (the coding agent's goal). Explicit
|
|
20
|
+
* `pinned:true` messages are always honored on top of it. A token cap keeps a
|
|
21
|
+
* pathologically large first turn from itself blowing the budget.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const DEFAULT_MAX_PIN_TOKENS = 2000;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Normalize the opt-in value into a config object, or null when auto-pin is off.
|
|
28
|
+
* Accepts: falsy (off), `true` (defaults on), or a config object
|
|
29
|
+
* `{ firstUserGoal?, maxPinTokens? }`.
|
|
30
|
+
*/
|
|
31
|
+
export function resolveAutoPinConfig(opt) {
|
|
32
|
+
if (!opt) return null;
|
|
33
|
+
const cfg = typeof opt === "object" ? opt : {};
|
|
34
|
+
return {
|
|
35
|
+
firstUserGoal: cfg.firstUserGoal !== false, // default true when enabled
|
|
36
|
+
maxPinTokens: Number.isFinite(cfg.maxPinTokens)
|
|
37
|
+
? cfg.maxPinTokens
|
|
38
|
+
: DEFAULT_MAX_PIN_TOKENS,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Coarse char/4 token estimate — matches the compressor's own heuristic. */
|
|
43
|
+
function estimateTokens(text) {
|
|
44
|
+
return Math.ceil(String(text || "").length / 4);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function contentString(m) {
|
|
48
|
+
if (!m) return "";
|
|
49
|
+
return typeof m.content === "string"
|
|
50
|
+
? m.content
|
|
51
|
+
: JSON.stringify(m.content || "");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Build an `isPinned(message)` predicate for `compress({ isPinned })`, or null
|
|
56
|
+
* when auto-pin is disabled (caller then passes no predicate → default).
|
|
57
|
+
*
|
|
58
|
+
* The predicate combines explicit pins (`pinned:true`/`_pin`) with the policy's
|
|
59
|
+
* auto-selected messages, matched by identity against `messages` (compress
|
|
60
|
+
* filters the same array, so identity is stable).
|
|
61
|
+
*/
|
|
62
|
+
export function buildAutoPinPredicate(messages, opt) {
|
|
63
|
+
const cfg = resolveAutoPinConfig(opt);
|
|
64
|
+
if (!cfg) return null;
|
|
65
|
+
if (!Array.isArray(messages)) {
|
|
66
|
+
return (m) => !!m && (m.pinned === true || m._pin === true);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const auto = new Set();
|
|
70
|
+
if (cfg.firstUserGoal) {
|
|
71
|
+
const firstUser = messages.find((m) => m && m.role === "user");
|
|
72
|
+
// Skip a first turn that is itself huge — pinning it would defeat the point
|
|
73
|
+
// (it would dominate the very budget compaction is trying to reclaim).
|
|
74
|
+
if (
|
|
75
|
+
firstUser &&
|
|
76
|
+
estimateTokens(contentString(firstUser)) <= cfg.maxPinTokens
|
|
77
|
+
) {
|
|
78
|
+
auto.add(firstUser);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return (m) => !!m && (m.pinned === true || m._pin === true || auto.has(m));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Explain what the policy would pin for `messages` (for `--dry-run` / logging).
|
|
87
|
+
* Returns `{ enabled, reasons: [{ role, preview, why }] }`.
|
|
88
|
+
*/
|
|
89
|
+
export function describeAutoPin(messages, opt) {
|
|
90
|
+
const cfg = resolveAutoPinConfig(opt);
|
|
91
|
+
if (!cfg) return { enabled: false, reasons: [] };
|
|
92
|
+
const reasons = [];
|
|
93
|
+
const list = Array.isArray(messages) ? messages : [];
|
|
94
|
+
for (const m of list) {
|
|
95
|
+
if (m && (m.pinned === true || m._pin === true)) {
|
|
96
|
+
reasons.push({ role: m.role, preview: preview(m), why: "explicit pin" });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (cfg.firstUserGoal) {
|
|
100
|
+
const firstUser = list.find((m) => m && m.role === "user");
|
|
101
|
+
if (
|
|
102
|
+
firstUser &&
|
|
103
|
+
estimateTokens(contentString(firstUser)) <= cfg.maxPinTokens
|
|
104
|
+
) {
|
|
105
|
+
reasons.push({
|
|
106
|
+
role: "user",
|
|
107
|
+
preview: preview(firstUser),
|
|
108
|
+
why: "original task (first user turn)",
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return { enabled: true, reasons };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function preview(m) {
|
|
116
|
+
return contentString(m).replace(/\s+/g, " ").slice(0, 80);
|
|
117
|
+
}
|