chainlesschain 0.165.6 → 0.165.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-vfoDb6HZ.js → AIOps-DxwjrnEA.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Cm5f7p93.js → ActionButton-JdbYowzn.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-yRuvgWxa.js → Analytics-C06GCahv.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BROsC4h1.js → AppLayout-BUVEEyi1.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-CimHApb1.js → Artifacts-D_ORzkJd.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DI8kr8zI.js → Audit-8o_Y5ejG.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DSLzKy-n.js → BackgroundAgents-DrkHd5VU.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DkH_n2r1.js → Backup-CKBZCX11.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CKSrUoRA.js → BaseInput-C8HkI399.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-ClwfMXUS.js → Chat-zb2H2Wux.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CjMaqfL7.js → ChatBubbleRenderer-BDcNpU_F.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BYTehcQG.js → Checkbox-MwPtQmNz.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B8AMcp6J.js → Codegen-3p5QCkFK.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BNSogPo3.js → Col-BPLlhn52.js} +1 -1
- package/src/assets/web-panel/assets/{Community-JxPvGb8O.js → Community-C-3dBNOM.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DF7bFAgE.js → Compact-BUcy-F_b.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Bvhqnwrq.js → Compliance-CI8NxT8m.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BDS0CJvM.js → Cowork-DaDEBS-Q.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DqvRfxoQ.js → Cron-BSv9HXu5.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CDcIvnqS.js → Crosschain-yuiKlJmv.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D7jaUxU3.js → DID-D6LfldB0.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B5A18wEV.js → Dashboard-CBhLqG61.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-_6IVkGag.js → Dropdown-BG8pIl3O.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C9PeiKCG.js → EmailListRenderer-CY92VIE6.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DXjuEHrX.js → FamilyGuardDashboard-1Q_ehauM.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B4IAR9zv.js → Federation-D3XirJIU.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CxQeSNx1.js → FormItemContext-DfI9UuGZ.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-B8GS-Y3N.js → GenericCardRenderer-IeCZk2m7.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BS8SouUX.js → Git-DzK4IJAZ.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Dq9aYb5Q.js → Governance-BHf5KfmQ.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BrCEe9AJ.js → Inference-BmaxSALS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DybOpiY2.js → KnowledgeGraph-BgePFLA9.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DBpzbRfx.js → Logs-nqgxpOc4.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-xkX6izBt.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Cc7CCSCu.js → Marketplace-Bu8to-86.js} +1 -1
- package/src/assets/web-panel/assets/McpTools-BFWTzEk0.js +4 -0
- package/src/assets/web-panel/assets/{Memory-KCqlp9ol.js → Memory-B026G2GA.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Bys84ySN.js → MobileBridge-CM2Eeg6I.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-B-6qU-je.js → MobileProjects-B79Ob3hy.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BgY-fvCq.js → Mtc-CxevSZuV.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-B8pCmqQJ.js → MtcAudit-X396cPEX.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BbOmYutA.js → Multisig-HWIB_aZ1.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BocLQz_M.js → NLProgramming-gnYD1Xwy.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CSwbxEop.js → Notes-Dn2Gf_J1.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CqFNSYG3.js → NotificationSettings-BRKBQ5rq.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-C6gMfAk7.js → OrderTableRenderer-Dy___Cgo.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-QrDXVdMJ.js → Organization-cqfccxnt.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Cxntotjt.js → Overflow-CSX4FHN3.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CIdBOwNq.js → P2P-Bwa4aghp.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CT5aP8rD.js → PdhVaultBrowser-Dhszyjig.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-DH7OM8XU.js → Permissions-CXzTyk6e.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CnJqbWce.js → PersonalDataHub-CFCAAJbb.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-5C3HG1kH.js → Pipeline-BPJbx6xt.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B4yIp7xK.js → Privacy-BbiXvEHz.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BMvt-2M0.js → ProjectInit-B-s7-wSD.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CvSTEMRG.js → ProjectSettings-Dyug206y.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BKBJxEek.js → Projects-BtAI5Fwo.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BdwUqFWN.js → Providers-JpIPmz6N.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DtnCKlTm.js → QrScannerModal-CZdoN64A.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-sTbgwyNr.js → QuickAsk-BwvnoRIT.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Bzr14gSb.js → Recommend-ASMlMQrD.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C_TF5IaJ.js → RemoteSession-BiJzKFKi.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-GCAM4H2K.js → Reputation-C80TWLIO.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Dir0r6OQ.js → Row-C1VNmjmX.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CpGnlecX.js → RssFeed-T2MyGUlG.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DMMamC6u.js → Search-DXM6O83L.js} +1 -1
- package/src/assets/web-panel/assets/{Security-yqay5yG-.js → Security-nv69kU7W.js} +3 -3
- package/src/assets/web-panel/assets/{Services-C5i2wh9G.js → Services-AyHWe7Qj.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-vUqk35yj.js → Skeleton-D6PWLxFI.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DzcSkhot.js → Skills-BqVeOmNQ.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CB6qbYNr.js → Sla-BegIPl9M.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BHUI7cox.js → SpeechSettings-CKJn3xk-.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-D-RrsxTJ.js → SyncSettings-Th4cnAMl.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DFxdOJiq.js → Tasks-BuKfBroh.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-SKAob_Aq.js → Templates-CMuWN8Ac.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BPfsfHQ-.js → Tenant-C4je8E8Q.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-8iw7FpUf.js → Terminal-agJESOcO.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-C4Gjj5Su.js → TimelineRenderer-D2qDuVZ_.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-COYhN18e.js → Tokens-Cvmn99rH.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-B-JzXcf6.js → Trigger-D_QYIHH8.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BJ5bg0nI.js → Trust-BmzvQLnX.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BG_ByRMf.js → UkeySign-D_LopHwH.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-B3kOnSiU.js → VideoEditing-DoWl3PhQ.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CcoGFnK7.js → Wallet-5NYcAkxe.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DdT8vRC_.js → WebAuthn-B-_Q3ewp.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CZu3M9N8.js → WorkflowEditor-CHET-gi2.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DxJt3Qba.js → chat-C6nvb-n6.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DdYfwJaB.js → colors-CTDE9LTX.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BG3SUzwj.js → compact-item-KnemdF8D.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-By51z2-1.js → createContext-DUJR3Uek.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-1DqLH1KX.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-B0apZ3KJ.js → hasIn-CFNTaby8.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZxtP8jG7.js → index-65HO56Bv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Da_WBdLX.js → index-B8RtbSkV.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBPf3TpM.js → index-BHqSqnW7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BP94CrBV.js → index-BTetEUWd.js} +1 -1
- package/src/assets/web-panel/assets/{index-p1_8SbI1.js → index-BXWg1crv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWF8_mkx.js → index-BdiC4LOs.js} +1 -1
- package/src/assets/web-panel/assets/index-BhJtcPWo.js +1 -0
- package/src/assets/web-panel/assets/{index-SQqOlR3d.js → index-BuizJo2E.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpjZhgNd.js → index-BwZM1rod.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzmQElZy.js → index-C96N9xeL.js} +1 -1
- package/src/assets/web-panel/assets/{index-bP_VlDb4.js → index-CHfUdnJH.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZFbps9po.js → index-CKvBF3Ov.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaIz0NAW.js → index-CSD9_I2_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BewKYrX9.js → index-Cc7dbl_p.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNIxXMmN.js → index-CcF0D7UZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Q2SCX-MI.js → index-Ceu92a8D.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE76D-kA.js → index-CnLpuTAU.js} +1 -1
- package/src/assets/web-panel/assets/index-Cq8MWPDT.js +1 -0
- package/src/assets/web-panel/assets/{index-BkvcEo4p.js → index-CquKnw5r.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cp6e-hGw.js → index-CyEtHvEE.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLIbGOLX.js → index-DF-fcTvQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCn8IcxV.js → index-DF1Y0Vuw.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bissefox.js → index-DJyPeBBk.js} +3 -3
- package/src/assets/web-panel/assets/{index-BZ_0qm4g.js → index-DP-PbO11.js} +1 -1
- package/src/assets/web-panel/assets/{index-kf57LJ93.js → index-DZgCRMxk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYINoRLK.js → index-DfJzS3Qa.js} +1 -1
- package/src/assets/web-panel/assets/{index-3jWkIu5j.js → index-DqPpJkte.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5rLiEo0.js → index-DzReoLyh.js} +1 -1
- package/src/assets/web-panel/assets/{index-CW93tZDv.js → index-JGTiDeOW.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1C9i79A.js → index-NUR0If7O.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAhHirVH.js → index-NtAcnJYW.js} +1 -1
- package/src/assets/web-panel/assets/{index-RD6O-0C6.js → index-OmuhFYKE.js} +1 -1
- package/src/assets/web-panel/assets/{index-oxRrmFO9.js → index-Wlc7o_C8.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3rWuPMW.js → index-bxTPfdri.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIrJfqO4.js → index-k6uorYmf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfWYsB9t.js → index-ox6mIwE2.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bos5_aMV.js → index-rVDD7AAR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWEuZWCK.js → index-u0h6QqVV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dz49VOyQ.js → index-v-mtxmWH.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BWJktcg8.js → initDefaultProps-qEt8dI-t.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BEXBzUFV.js → motion-DetKPWy-.js} +1 -1
- package/src/assets/web-panel/assets/{move-BUKwn2sx.js → move-BeNYeDV2.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-FTI7btqQ.js → mtc-parser-C0q0MK_T.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CsLtSPH3.js → omit-DLKkrKpE.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DWZxsT_S.js → pickAttrs-Bw1tWsY8.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Bcfs43CX.js → placementArrow-DeesBLbd.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-a9bcC1p-.js → responsiveObserve-bqLhxHhn.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BDTzgOXN.js → slide-DGCXRoQm.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Iq1j_HUg.js → statusUtils-H-re3Egl.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DAZEYxeh.js → styleChecker-BXg4qGX_.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DVkjyDrh.js → useFlexGapSupport-CKLb2KA6.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-wXTpNTHt.js → useFs-CTAhHeyw.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CtQM_aZr.js → usePersonalDataHub-BQ4pDh5g.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-hjEoG85v.js → vnode-jrSK6j4j.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BHVpyKg_.js → zoom-fOQE24pw.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/commands/agent.js +91 -60
- package/src/commands/git.js +39 -0
- package/src/commands/plugin.js +17 -2
- package/src/commands/session-group.js +131 -0
- package/src/commands/session-location.js +48 -0
- package/src/commands/session.js +11 -0
- package/src/commands/sync-providers.js +4 -1
- package/src/commands/update.js +1 -0
- package/src/data/changelog.json +40 -1
- package/src/gateways/ws/mcp-topic-handlers.js +167 -0
- package/src/gateways/ws/ws-agent-handler.js +20 -12
- package/src/harness/jsonl-session-store.js +279 -37
- package/src/harness/mcp-client.js +701 -91
- package/src/harness/session-index.js +15 -4
- package/src/lib/agent-network.js +166 -29
- package/src/lib/agent-router.js +62 -6
- package/src/lib/agent-sandbox.js +7 -1
- package/src/lib/agent-worktree.js +8 -1
- package/src/lib/auto-mode-safety-classifier.js +3 -17
- package/src/lib/background-agent-keeper-protocol.js +26 -6
- package/src/lib/background-agent-supervisor.js +17 -1
- package/src/lib/browser-evidence.js +1405 -0
- package/src/lib/chrome-connector.js +465 -79
- package/src/lib/claude-code-bridge.js +159 -54
- package/src/lib/claude-project-auto-memory.js +481 -0
- package/src/lib/claude-project-storage-layout.js +104 -0
- package/src/lib/cloud/cloud-client.js +40 -0
- package/src/lib/cowork-workflow.js +69 -6
- package/src/lib/execution-location-local-supervisor.mjs +226 -0
- package/src/lib/execution-location-runner-lifecycle.js +991 -0
- package/src/lib/execution-location-target-preflight.js +333 -0
- package/src/lib/execution-location-target.js +783 -13
- package/src/lib/external-agent-adapters.js +269 -0
- package/src/lib/file-lines.js +6 -1
- package/src/lib/gateway-client-resilience.js +571 -0
- package/src/lib/gitlab-mr-worktree.js +176 -0
- package/src/lib/hooks-v2-producers.js +119 -15
- package/src/lib/hooks-v2-workspace-context.js +44 -1
- package/src/lib/host-resource-budget.js +295 -0
- package/src/lib/ide-context.js +15 -2
- package/src/lib/ipfs-storage.js +127 -25
- package/src/lib/llm-config-defaults.js +43 -0
- package/src/lib/mcp-lifecycle-authority.js +887 -0
- package/src/lib/mcp-oauth.js +101 -20
- package/src/lib/mcp-tls.js +103 -3
- package/src/lib/orchestrator.js +47 -0
- package/src/lib/paths.js +260 -32
- package/src/lib/permission-request.js +48 -0
- package/src/lib/plugin-runtime/bin.js +3 -1
- package/src/lib/plugin-runtime/hooks.js +3 -1
- package/src/lib/plugin-runtime/install.js +117 -1
- package/src/lib/plugin-runtime/lsp.js +4 -4
- package/src/lib/plugin-runtime/marketplace-archive-source.js +40 -5
- package/src/lib/plugin-runtime/marketplace-catalog.js +13 -2
- package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
- package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
- package/src/lib/plugin-runtime/marketplace-source-adapter.js +33 -8
- package/src/lib/plugin-runtime/mcp.js +3 -1
- package/src/lib/plugin-runtime/monitors.js +3 -1
- package/src/lib/plugin-runtime/remote-source.js +151 -6
- package/src/lib/plugin-runtime/settings.js +3 -1
- package/src/lib/plugin-runtime/trust.js +274 -13
- package/src/lib/process-execution-broker/credential-agent.js +210 -41
- package/src/lib/process-execution-broker/index.js +15 -1
- package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
- package/src/lib/project-mcp-trust.js +165 -10
- package/src/lib/resume-session.js +9 -6
- package/src/lib/session-core-singletons.js +26 -11
- package/src/lib/session-host-lease.js +52 -16
- package/src/lib/session-lifecycle-scope.js +153 -0
- package/src/lib/session-message-fabric.js +168 -21
- package/src/lib/session-projection.js +244 -4
- package/src/lib/session-store-guard.js +3 -1
- package/src/lib/session-workbench-store.js +466 -0
- package/src/lib/shell-approval.js +7 -5
- package/src/lib/spellcheck.js +211 -0
- package/src/lib/sub-agent-context.js +9 -9
- package/src/lib/sync-cli-db.js +485 -129
- package/src/lib/sync-credentials.js +31 -20
- package/src/lib/web-fetch.js +112 -40
- package/src/lib/web-search.js +127 -61
- package/src/lib/workflow-engine.js +42 -11
- package/src/lib/workspace-trust.js +793 -0
- package/src/repl/agent-repl.js +124 -5
- package/src/repl/permission-prompt.js +10 -12
- package/src/runtime/agent-core.js +311 -18
- package/src/runtime/agent-runtime.js +12 -1
- package/src/runtime/bootstrap.js +37 -13
- package/src/runtime/coding-agent-contract-shared.cjs +11 -4
- package/src/runtime/headless-runner.js +234 -36
- package/src/runtime/headless-stream.js +181 -6
- package/src/runtime/mcp-config.js +298 -8
- package/src/runtime/policies/agent-policy.js +8 -0
- package/src/runtime/status-diagnostics-lite.js +9 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-CFyt8iUd.js +0 -1
- package/src/assets/web-panel/assets/McpTools-DFaIhOfu.js +0 -7
- package/src/assets/web-panel/assets/devWarning-DorRZcI9.js +0 -1
- package/src/assets/web-panel/assets/index-BETiL0a3.js +0 -1
- package/src/assets/web-panel/assets/index-BhAVHuW8.js +0 -1
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
sameInteractionBinding,
|
|
28
28
|
} from "../lib/interaction-binding.js";
|
|
29
29
|
import {
|
|
30
|
+
addHooksV2EventObserver,
|
|
30
31
|
emitHooksV2Event,
|
|
31
32
|
executeHooksV2Event,
|
|
32
33
|
resolvePromptExpansion,
|
|
@@ -42,6 +43,7 @@ import { composeSystemPrompt } from "./system-prompt.js";
|
|
|
42
43
|
import { collapseConsecutiveMessagesInPlace } from "./message-roles.js";
|
|
43
44
|
import { sanitizeToolPairs } from "../harness/prompt-compressor.js";
|
|
44
45
|
import { compactConversationWithProvider } from "../harness/provider-backed-compaction.js";
|
|
46
|
+
import { HostResourceBudget } from "../lib/host-resource-budget.js";
|
|
45
47
|
import { projectCanonicalResumeMessages } from "../lib/session-message-provenance.js";
|
|
46
48
|
import { isAbortError } from "../lib/abort-utils.js";
|
|
47
49
|
import { expandFileRefsAsync } from "./file-ref-expander.js";
|
|
@@ -65,6 +67,7 @@ import {
|
|
|
65
67
|
resolveAgentMcp,
|
|
66
68
|
resolvePermissionPromptTool,
|
|
67
69
|
makePermissionPromptConfirmer,
|
|
70
|
+
readHeadlessMcpConfigErrors,
|
|
68
71
|
} from "./mcp-config.js";
|
|
69
72
|
import { maybeApplyToolSearch } from "./mcp-tool-search.js";
|
|
70
73
|
import {
|
|
@@ -398,6 +401,9 @@ export function planSnapshot(pm) {
|
|
|
398
401
|
const MAX_PLAN_REVIEW_SNAPSHOT_CHARS = 24000;
|
|
399
402
|
const MAX_PLAN_REVIEW_COMMENTS = 64;
|
|
400
403
|
const MAX_PLAN_REVIEW_COMMENT_CHARS = 2000;
|
|
404
|
+
const HOST_EVENT_BACKLOG_CODE = "CC_HOST_EVENT_BACKLOG_EXHAUSTED";
|
|
405
|
+
const HOST_EVENT_BACKLOG_ERROR =
|
|
406
|
+
"CC_HOST_EVENT_BACKLOG_EXHAUSTED: event backlog limit reached";
|
|
401
407
|
|
|
402
408
|
function boundedReviewString(value, limit) {
|
|
403
409
|
return String(value == null ? "" : value).slice(0, limit);
|
|
@@ -1463,6 +1469,11 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
1463
1469
|
deps[STREAM_SESSION_ID] ||
|
|
1464
1470
|
options.sessionId ||
|
|
1465
1471
|
`headless-stream-${Date.now()}-${process.pid}`;
|
|
1472
|
+
// The input stream may drive many turns. Allocate once at the stream-run
|
|
1473
|
+
// boundary so every turn (and its nested agents) shares cache/backlog limits.
|
|
1474
|
+
// SessionResourceBudget remains separately leased by executeTool.
|
|
1475
|
+
const hostResourceBudget =
|
|
1476
|
+
options.hostResourceBudget || new HostResourceBudget();
|
|
1466
1477
|
const persist =
|
|
1467
1478
|
(Boolean(options.sessionId) || options.observabilityScope != null) &&
|
|
1468
1479
|
options.ephemeral !== true;
|
|
@@ -1483,6 +1494,10 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
1483
1494
|
fieldGate,
|
|
1484
1495
|
});
|
|
1485
1496
|
const emit = streamCoalescer.emit;
|
|
1497
|
+
const removeHookObserver =
|
|
1498
|
+
options.includeHookEvents === true
|
|
1499
|
+
? addHooksV2EventObserver(sessionId, (event) => emit(event))
|
|
1500
|
+
: null;
|
|
1486
1501
|
streamCleanup.setOutputCleanup(() => streamCoalescer.flush?.());
|
|
1487
1502
|
|
|
1488
1503
|
const hasInjectedSessionStore =
|
|
@@ -2484,6 +2499,20 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
2484
2499
|
let sanitizeRolesNextTurn =
|
|
2485
2500
|
resumedMessages > 0 && messages[messages.length - 1]?.role === "user";
|
|
2486
2501
|
|
|
2502
|
+
// `system:init` intentionally precedes MCP connection so stream consumers
|
|
2503
|
+
// receive their manifest promptly. Validation itself is local and side-effect
|
|
2504
|
+
// free, so preflight just its bounded, redacted projection here; the normal
|
|
2505
|
+
// resolver below remains authoritative for parsing and connection.
|
|
2506
|
+
let initialMcpServerErrors = [];
|
|
2507
|
+
if (options.mcpConfig) {
|
|
2508
|
+
try {
|
|
2509
|
+
initialMcpServerErrors = readHeadlessMcpConfigErrors(options.mcpConfig);
|
|
2510
|
+
} catch {
|
|
2511
|
+
// The normal resolver reports unreadable/malformed files as its existing
|
|
2512
|
+
// config error result. Never place filesystem/parser details in init.
|
|
2513
|
+
}
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2487
2516
|
emit({
|
|
2488
2517
|
type: "system",
|
|
2489
2518
|
subtype: "init",
|
|
@@ -2512,6 +2541,9 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
2512
2541
|
mcp: Boolean(options.mcpConfig) || options.useRegisteredMcp !== false,
|
|
2513
2542
|
enabledToolNames,
|
|
2514
2543
|
}),
|
|
2544
|
+
...(initialMcpServerErrors.length > 0
|
|
2545
|
+
? { mcp_server_errors: initialMcpServerErrors }
|
|
2546
|
+
: {}),
|
|
2515
2547
|
slash_commands: [...SESSION_SLASH_COMMANDS],
|
|
2516
2548
|
input_format: "stream-json",
|
|
2517
2549
|
additional_directories: additionalDirectories,
|
|
@@ -2591,6 +2623,7 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
2591
2623
|
},
|
|
2592
2624
|
{
|
|
2593
2625
|
writeErr,
|
|
2626
|
+
mcpConfigWarnings: false,
|
|
2594
2627
|
loadMcpConfig: deps.loadMcpConfig,
|
|
2595
2628
|
loadRegisteredMcp: deps.loadRegisteredMcp,
|
|
2596
2629
|
loadIdeMcp: deps.loadIdeMcp,
|
|
@@ -2836,6 +2869,78 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
2836
2869
|
}
|
|
2837
2870
|
}
|
|
2838
2871
|
|
|
2872
|
+
const streamInteraction = {};
|
|
2873
|
+
if (interactiveQuestions) streamInteraction.askUser = interactionAskUser;
|
|
2874
|
+
if (options.includeHookEvents === true) {
|
|
2875
|
+
streamInteraction.emit = (kind, payload = {}) => {
|
|
2876
|
+
const subAgentId =
|
|
2877
|
+
typeof payload.subAgentId === "string" && payload.subAgentId.trim()
|
|
2878
|
+
? payload.subAgentId.slice(0, 160)
|
|
2879
|
+
: null;
|
|
2880
|
+
if (!subAgentId) return;
|
|
2881
|
+
const base = {
|
|
2882
|
+
schema_version: 1,
|
|
2883
|
+
subagent_id: subAgentId,
|
|
2884
|
+
parent_id:
|
|
2885
|
+
typeof payload.parentSessionId === "string" &&
|
|
2886
|
+
payload.parentSessionId.trim()
|
|
2887
|
+
? payload.parentSessionId.slice(0, 160)
|
|
2888
|
+
: sessionId,
|
|
2889
|
+
...(typeof payload.role === "string" && payload.role.trim()
|
|
2890
|
+
? { role: payload.role.trim().slice(0, 96) }
|
|
2891
|
+
: {}),
|
|
2892
|
+
};
|
|
2893
|
+
if (kind === "sub-agent.started") {
|
|
2894
|
+
emit({
|
|
2895
|
+
type: "subagent_started",
|
|
2896
|
+
...base,
|
|
2897
|
+
background: payload.background === true,
|
|
2898
|
+
});
|
|
2899
|
+
} else if (
|
|
2900
|
+
kind === "sub-agent.completed" ||
|
|
2901
|
+
kind === "sub-agent.failed"
|
|
2902
|
+
) {
|
|
2903
|
+
emit({
|
|
2904
|
+
type: "subagent_completed",
|
|
2905
|
+
...base,
|
|
2906
|
+
status: kind === "sub-agent.failed" ? "failed" : "completed",
|
|
2907
|
+
background: payload.background === true,
|
|
2908
|
+
...(Number.isFinite(payload.iterationCount)
|
|
2909
|
+
? {
|
|
2910
|
+
iteration_count: Math.max(
|
|
2911
|
+
0,
|
|
2912
|
+
Math.floor(payload.iterationCount),
|
|
2913
|
+
),
|
|
2914
|
+
}
|
|
2915
|
+
: {}),
|
|
2916
|
+
});
|
|
2917
|
+
} else if (kind === "sub-agent.progress") {
|
|
2918
|
+
emit({
|
|
2919
|
+
type: "subagent_progress",
|
|
2920
|
+
...base,
|
|
2921
|
+
event_type:
|
|
2922
|
+
typeof payload.event_type === "string"
|
|
2923
|
+
? payload.event_type.slice(0, 96)
|
|
2924
|
+
: "unknown",
|
|
2925
|
+
...(typeof payload.tool === "string" && payload.tool
|
|
2926
|
+
? { tool: payload.tool.slice(0, 128) }
|
|
2927
|
+
: {}),
|
|
2928
|
+
...(Number.isFinite(payload.iteration_count)
|
|
2929
|
+
? {
|
|
2930
|
+
iteration_count: Math.max(
|
|
2931
|
+
0,
|
|
2932
|
+
Math.floor(payload.iteration_count),
|
|
2933
|
+
),
|
|
2934
|
+
}
|
|
2935
|
+
: {}),
|
|
2936
|
+
...(Number.isFinite(payload.token_count)
|
|
2937
|
+
? { token_count: Math.max(0, Math.floor(payload.token_count)) }
|
|
2938
|
+
: {}),
|
|
2939
|
+
});
|
|
2940
|
+
}
|
|
2941
|
+
};
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2839
2944
|
const loopOptionsBase = {
|
|
2840
2945
|
model,
|
|
2841
2946
|
provider,
|
|
@@ -2849,6 +2954,7 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
2849
2954
|
additionalDirectories,
|
|
2850
2955
|
sessionId,
|
|
2851
2956
|
sessionBudget: options.sessionBudget || null,
|
|
2957
|
+
hostResourceBudget,
|
|
2852
2958
|
sessionHostSnapshot: canonicalResume?.snapshot || null,
|
|
2853
2959
|
// Auto-checkpoint (Claude-Code parity): snapshot the work tree before each
|
|
2854
2960
|
// mutating tool so a stream consumer (e.g. the IDE chat panel) can rewind.
|
|
@@ -2877,9 +2983,8 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
2877
2983
|
// ask_user_question round-trip (opt-in via CC_INTERACTIVE_QUESTIONS): give
|
|
2878
2984
|
// the tool handler an askUser that emits question_request + blocks on stdin.
|
|
2879
2985
|
// Absent → agent-core returns user_not_reachable (graceful proceed).
|
|
2880
|
-
interaction:
|
|
2881
|
-
?
|
|
2882
|
-
: undefined,
|
|
2986
|
+
interaction:
|
|
2987
|
+
Object.keys(streamInteraction).length > 0 ? streamInteraction : undefined,
|
|
2883
2988
|
prepareCall: goalPrepareCallFn,
|
|
2884
2989
|
// --mcp-config wiring (tool defs + dispatch map + live client).
|
|
2885
2990
|
mcpClient: mcp?.mcpClient || null,
|
|
@@ -3081,13 +3186,43 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
3081
3186
|
// Stop / Claude-Code Esc parity) instead of waiting in line behind it.
|
|
3082
3187
|
// Normal events queue for the serial turn loop below; interrupts act on the
|
|
3083
3188
|
// live per-turn AbortController and are never queued.
|
|
3189
|
+
// A normal input can contain arbitrary user data, so retain it only while it
|
|
3190
|
+
// is waiting for the serial turn loop. Interrupts/approvals/answers remain
|
|
3191
|
+
// out-of-band controls and never consume a queue slot.
|
|
3084
3192
|
const queue = [];
|
|
3085
3193
|
let wakeQueue = null;
|
|
3086
3194
|
let inputDone = false;
|
|
3087
3195
|
let currentAbort = null;
|
|
3196
|
+
let inputBacklogFailure = false;
|
|
3088
3197
|
let slashRequestSeq = 0;
|
|
3089
3198
|
const inputLines = readJsonLines(input);
|
|
3090
|
-
|
|
3199
|
+
const releaseQueuedInputEvents = () => {
|
|
3200
|
+
while (queue.length > 0) {
|
|
3201
|
+
const queued = queue.shift();
|
|
3202
|
+
try {
|
|
3203
|
+
queued?.lease?.release?.();
|
|
3204
|
+
} catch {
|
|
3205
|
+
// Drain every opaque slot even when an injected test authority has a
|
|
3206
|
+
// faulty disposer. Its payload is deliberately never inspected here.
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
};
|
|
3210
|
+
const failInputEventBacklog = () => {
|
|
3211
|
+
if (inputBacklogFailure) return;
|
|
3212
|
+
inputBacklogFailure = true;
|
|
3213
|
+
releaseQueuedInputEvents();
|
|
3214
|
+
// A flood can happen while a model turn is running. Abort that turn before
|
|
3215
|
+
// surfacing the stable host diagnostic; otherwise it could continue to do
|
|
3216
|
+
// paid/tool work after the host has refused its input backlog.
|
|
3217
|
+
currentAbort?.abort();
|
|
3218
|
+
streamCleanup.setReason("host_event_backlog_exhausted");
|
|
3219
|
+
streamCleanup.requestStop();
|
|
3220
|
+
wakeQueue?.();
|
|
3221
|
+
};
|
|
3222
|
+
streamCleanup.setInputCancel(() => {
|
|
3223
|
+
releaseQueuedInputEvents();
|
|
3224
|
+
return inputLines.return?.();
|
|
3225
|
+
});
|
|
3091
3226
|
(async () => {
|
|
3092
3227
|
try {
|
|
3093
3228
|
for await (const line of inputLines) {
|
|
@@ -3157,7 +3292,26 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
3157
3292
|
);
|
|
3158
3293
|
continue;
|
|
3159
3294
|
}
|
|
3160
|
-
|
|
3295
|
+
try {
|
|
3296
|
+
if (typeof hostResourceBudget?.admitEvent !== "function") {
|
|
3297
|
+
throw new TypeError(
|
|
3298
|
+
"host resource budget does not provide admitEvent()",
|
|
3299
|
+
);
|
|
3300
|
+
}
|
|
3301
|
+
const lease = hostResourceBudget.admitEvent();
|
|
3302
|
+
if (!lease || typeof lease.release !== "function") {
|
|
3303
|
+
throw new TypeError(
|
|
3304
|
+
"host resource budget event admission is invalid",
|
|
3305
|
+
);
|
|
3306
|
+
}
|
|
3307
|
+
queue.push({ parsed, lease });
|
|
3308
|
+
} catch {
|
|
3309
|
+
// Refuse the whole input stream rather than dropping one unbounded
|
|
3310
|
+
// event and then accepting more. The externally-visible error below
|
|
3311
|
+
// is fixed and contains none of the rejected line's content.
|
|
3312
|
+
failInputEventBacklog();
|
|
3313
|
+
break;
|
|
3314
|
+
}
|
|
3161
3315
|
if (wakeQueue) wakeQueue();
|
|
3162
3316
|
}
|
|
3163
3317
|
} catch {
|
|
@@ -3177,7 +3331,15 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
3177
3331
|
})();
|
|
3178
3332
|
const nextEvent = async () => {
|
|
3179
3333
|
for (;;) {
|
|
3180
|
-
if (queue.length > 0)
|
|
3334
|
+
if (queue.length > 0) {
|
|
3335
|
+
const queued = queue.shift();
|
|
3336
|
+
try {
|
|
3337
|
+
return queued.parsed;
|
|
3338
|
+
} finally {
|
|
3339
|
+
// The serial loop now owns the event; it is no longer backlog.
|
|
3340
|
+
queued.lease.release();
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3181
3343
|
if (inputDone || options.signal?.aborted) return null;
|
|
3182
3344
|
await new Promise((r) => {
|
|
3183
3345
|
let settled = false;
|
|
@@ -3198,6 +3360,18 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
3198
3360
|
for (;;) {
|
|
3199
3361
|
await deps.outputFlow?.wait?.();
|
|
3200
3362
|
const parsed = await nextEvent();
|
|
3363
|
+
if (inputBacklogFailure) {
|
|
3364
|
+
emit({
|
|
3365
|
+
type: "result",
|
|
3366
|
+
subtype: "error_host_resource_budget",
|
|
3367
|
+
is_error: true,
|
|
3368
|
+
code: HOST_EVENT_BACKLOG_CODE,
|
|
3369
|
+
error: HOST_EVENT_BACKLOG_ERROR,
|
|
3370
|
+
session_id: sessionId,
|
|
3371
|
+
});
|
|
3372
|
+
sawError = true;
|
|
3373
|
+
break;
|
|
3374
|
+
}
|
|
3201
3375
|
if (parsed == null) break; // stdin closed
|
|
3202
3376
|
sessionHostLease?.assert?.();
|
|
3203
3377
|
if (turnBindingPersistenceError) {
|
|
@@ -4309,6 +4483,7 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
4309
4483
|
: "completed",
|
|
4310
4484
|
);
|
|
4311
4485
|
await streamCleanup.cleanup();
|
|
4486
|
+
removeHookObserver?.();
|
|
4312
4487
|
|
|
4313
4488
|
if (!pipeState.closed) {
|
|
4314
4489
|
emit({ type: "system", subtype: "end", session_id: sessionId, turns });
|
|
@@ -51,7 +51,15 @@ import {
|
|
|
51
51
|
normalizeMcpSandboxPolicy,
|
|
52
52
|
readMcpStdioCwd,
|
|
53
53
|
} from "../lib/mcp-sandbox-policy.js";
|
|
54
|
-
import {
|
|
54
|
+
import {
|
|
55
|
+
MCP_TLS_MANAGED_SOURCE_REQUIRED_CODE,
|
|
56
|
+
MCP_TLS_MANAGED_SOURCE_REQUIRED_MESSAGE,
|
|
57
|
+
provisionManagedMcpTlsConfig,
|
|
58
|
+
} from "../lib/mcp-tls.js";
|
|
59
|
+
import {
|
|
60
|
+
McpLifecycleAuthority,
|
|
61
|
+
defaultMcpLifecycleAuthorityPath,
|
|
62
|
+
} from "../lib/mcp-lifecycle-authority.js";
|
|
55
63
|
|
|
56
64
|
function invalidSandboxPolicy(message) {
|
|
57
65
|
const error = new TypeError(message);
|
|
@@ -135,12 +143,203 @@ function headersHelperField(value) {
|
|
|
135
143
|
: {};
|
|
136
144
|
}
|
|
137
145
|
|
|
146
|
+
const MCP_CONFIG_ERROR_TYPES = new Set([
|
|
147
|
+
"invalid_config",
|
|
148
|
+
"invalid_name",
|
|
149
|
+
"unknown_type",
|
|
150
|
+
"url_missing_type",
|
|
151
|
+
"reserved_name",
|
|
152
|
+
]);
|
|
153
|
+
|
|
154
|
+
const MCP_CONFIG_TRANSPORT_TYPES = new Set([
|
|
155
|
+
"stdio",
|
|
156
|
+
"http",
|
|
157
|
+
"https",
|
|
158
|
+
"sse",
|
|
159
|
+
"ws",
|
|
160
|
+
"wss",
|
|
161
|
+
]);
|
|
162
|
+
|
|
163
|
+
function mcpConfigError(name, type, message) {
|
|
164
|
+
return {
|
|
165
|
+
// The entry name is intentionally retained: callers need to associate a
|
|
166
|
+
// skipped config with the declaration that supplied it. Keep its size
|
|
167
|
+
// bounded, while all other fields are fixed host-owned strings.
|
|
168
|
+
name: String(name || "<unnamed>").slice(0, 256),
|
|
169
|
+
type: MCP_CONFIG_ERROR_TYPES.has(type) ? type : "invalid_config",
|
|
170
|
+
message,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function mcpConfigEntries(raw) {
|
|
175
|
+
const block =
|
|
176
|
+
raw && typeof raw === "object" && !Array.isArray(raw)
|
|
177
|
+
? raw.mcpServers || raw.servers || raw
|
|
178
|
+
: null;
|
|
179
|
+
return block && typeof block === "object" && !Array.isArray(block)
|
|
180
|
+
? Object.entries(block)
|
|
181
|
+
: [];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function mcpConfigEntryError(name, config) {
|
|
185
|
+
if (!name || typeof name !== "string" || name.trim().length === 0) {
|
|
186
|
+
return mcpConfigError(
|
|
187
|
+
name,
|
|
188
|
+
"invalid_name",
|
|
189
|
+
"MCP server name must be a non-empty string.",
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
193
|
+
return mcpConfigError(
|
|
194
|
+
name,
|
|
195
|
+
"invalid_config",
|
|
196
|
+
"MCP server configuration must be an object.",
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const configuredType =
|
|
201
|
+
typeof config.type === "string" && config.type.trim()
|
|
202
|
+
? config.type.trim().toLowerCase()
|
|
203
|
+
: typeof config.transport === "string" && config.transport.trim()
|
|
204
|
+
? config.transport.trim().toLowerCase()
|
|
205
|
+
: null;
|
|
206
|
+
if (configuredType && !MCP_CONFIG_TRANSPORT_TYPES.has(configuredType)) {
|
|
207
|
+
return mcpConfigError(
|
|
208
|
+
name,
|
|
209
|
+
"unknown_type",
|
|
210
|
+
"MCP server transport type is not supported.",
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const hasCommand =
|
|
215
|
+
typeof config.command === "string" && config.command.trim().length > 0;
|
|
216
|
+
const hasUrl = typeof config.url === "string" && config.url.trim().length > 0;
|
|
217
|
+
if (hasCommand && hasUrl) {
|
|
218
|
+
return mcpConfigError(
|
|
219
|
+
name,
|
|
220
|
+
"invalid_config",
|
|
221
|
+
"MCP server configuration must specify one transport endpoint.",
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
if (
|
|
225
|
+
configuredType === "stdio" &&
|
|
226
|
+
!hasCommand &&
|
|
227
|
+
config.disabled !== true &&
|
|
228
|
+
config.enabled !== false
|
|
229
|
+
) {
|
|
230
|
+
return mcpConfigError(
|
|
231
|
+
name,
|
|
232
|
+
"invalid_config",
|
|
233
|
+
"Stdio MCP server configuration requires a command.",
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
if (
|
|
237
|
+
configuredType &&
|
|
238
|
+
configuredType !== "stdio" &&
|
|
239
|
+
!hasUrl &&
|
|
240
|
+
config.disabled !== true &&
|
|
241
|
+
config.enabled !== false
|
|
242
|
+
) {
|
|
243
|
+
return mcpConfigError(
|
|
244
|
+
name,
|
|
245
|
+
"invalid_config",
|
|
246
|
+
"Remote MCP server configuration requires a URL.",
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
if (
|
|
250
|
+
!hasCommand &&
|
|
251
|
+
!hasUrl &&
|
|
252
|
+
config.disabled !== true &&
|
|
253
|
+
config.enabled !== false
|
|
254
|
+
) {
|
|
255
|
+
return mcpConfigError(
|
|
256
|
+
name,
|
|
257
|
+
"invalid_config",
|
|
258
|
+
"MCP server configuration requires a command or URL.",
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Validate one explicit `--mcp-config` document without connecting to any
|
|
266
|
+
* server. Invalid entries are independently skipped; the fixed diagnostic
|
|
267
|
+
* shape is safe to expose in headless `system:init` output.
|
|
268
|
+
*
|
|
269
|
+
* This intentionally retains ChainlessChain's legacy URL inference when no
|
|
270
|
+
* `type`/`transport` is given. Explicit, unknown transport types are rejected
|
|
271
|
+
* before any DNS, process spawn, or transport construction.
|
|
272
|
+
*/
|
|
273
|
+
export function parseHeadlessMcpConfig(raw) {
|
|
274
|
+
const servers = {};
|
|
275
|
+
const errors = [];
|
|
276
|
+
for (const [name, config] of mcpConfigEntries(raw)) {
|
|
277
|
+
const entryError = mcpConfigEntryError(name, config);
|
|
278
|
+
if (entryError) {
|
|
279
|
+
errors.push(entryError);
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
// Claude-style config calls the field `type`; the established cc shape
|
|
284
|
+
// calls it `transport`. Preserve an explicit transport when both exist.
|
|
285
|
+
const normalizedConfig =
|
|
286
|
+
config.transport == null && typeof config.type === "string"
|
|
287
|
+
? { ...config, transport: config.type }
|
|
288
|
+
: config;
|
|
289
|
+
const parsed = parseMcpServers({
|
|
290
|
+
mcpServers: { [name]: normalizedConfig },
|
|
291
|
+
});
|
|
292
|
+
if (!parsed[name]) {
|
|
293
|
+
errors.push(
|
|
294
|
+
mcpConfigError(
|
|
295
|
+
name,
|
|
296
|
+
"invalid_config",
|
|
297
|
+
"MCP server configuration is invalid.",
|
|
298
|
+
),
|
|
299
|
+
);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
servers[name] = parsed[name];
|
|
303
|
+
} catch (error) {
|
|
304
|
+
if (error?.code === MCP_SANDBOX_POLICY_INVALID_CODE) {
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
307
|
+
// Non-authority config parsers can still reject malformed nested values.
|
|
308
|
+
// Do not reflect their raw message into NDJSON because it may contain a
|
|
309
|
+
// filesystem path or user-supplied secret.
|
|
310
|
+
errors.push(
|
|
311
|
+
mcpConfigError(
|
|
312
|
+
name,
|
|
313
|
+
"invalid_config",
|
|
314
|
+
"MCP server configuration is invalid.",
|
|
315
|
+
),
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return { servers, errors };
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** Read just the safe validation projection for a `--mcp-config` file. */
|
|
323
|
+
export function readHeadlessMcpConfigErrors(filePath, deps = {}) {
|
|
324
|
+
const readFile = deps.readFile || ((p) => fs.readFileSync(p, "utf-8"));
|
|
325
|
+
const raw = JSON.parse(readFile(filePath));
|
|
326
|
+
return parseHeadlessMcpConfig(raw).errors;
|
|
327
|
+
}
|
|
328
|
+
|
|
138
329
|
/**
|
|
139
330
|
* Normalize a parsed config object into a `{ name: serverConfig }` map.
|
|
140
331
|
* Accepts the Claude-Code shape `{ "mcpServers": { ... } }`, the bundle shape
|
|
141
332
|
* `{ "servers": { ... } }`, or a bare `{ name: cfg }` map.
|
|
142
333
|
*/
|
|
143
|
-
|
|
334
|
+
function unmanagedMcpTlsConfigError() {
|
|
335
|
+
// Configuration parsing errors are surfaced in headless diagnostics. Keep
|
|
336
|
+
// this entirely host-owned: do not disclose source paths or any TLS field.
|
|
337
|
+
const error = new Error(MCP_TLS_MANAGED_SOURCE_REQUIRED_MESSAGE);
|
|
338
|
+
error.code = MCP_TLS_MANAGED_SOURCE_REQUIRED_CODE;
|
|
339
|
+
return error;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function parseMcpServersForSource(raw, { provisionManagedTls = false } = {}) {
|
|
144
343
|
const block =
|
|
145
344
|
(raw && typeof raw === "object" && (raw.mcpServers || raw.servers)) ||
|
|
146
345
|
raw ||
|
|
@@ -208,22 +407,50 @@ export function parseMcpServers(raw) {
|
|
|
208
407
|
...(Number.isFinite(cfg.maxToolResultNodes)
|
|
209
408
|
? { maxToolResultNodes: cfg.maxToolResultNodes }
|
|
210
409
|
: {}),
|
|
410
|
+
...(Number.isFinite(cfg.toolIdleTimeoutMs)
|
|
411
|
+
? { toolIdleTimeoutMs: cfg.toolIdleTimeoutMs }
|
|
412
|
+
: {}),
|
|
413
|
+
...(cfg.discoveryCache === true ||
|
|
414
|
+
(cfg.discoveryCache && typeof cfg.discoveryCache === "object")
|
|
415
|
+
? { discoveryCache: cfg.discoveryCache }
|
|
416
|
+
: {}),
|
|
211
417
|
...headersHelperField(cfg.headersHelper),
|
|
212
418
|
...(cfg.configScope ? { configScope: cfg.configScope } : {}),
|
|
213
419
|
...(cfg.configSource ? { configSource: cfg.configSource } : {}),
|
|
214
|
-
...(cfg.tls != null
|
|
420
|
+
...(cfg.tls != null
|
|
421
|
+
? provisionManagedTls
|
|
422
|
+
? { tls: provisionManagedMcpTlsConfig(cfg.tls) }
|
|
423
|
+
: (() => {
|
|
424
|
+
throw unmanagedMcpTlsConfigError();
|
|
425
|
+
})()
|
|
426
|
+
: {}),
|
|
427
|
+
...(cfg.disabled === true || cfg.enabled === false
|
|
428
|
+
? { disabled: true }
|
|
429
|
+
: {}),
|
|
215
430
|
};
|
|
216
431
|
}
|
|
217
432
|
return out;
|
|
218
433
|
}
|
|
219
434
|
|
|
435
|
+
/**
|
|
436
|
+
* Parse an unprivileged MCP configuration source. TLS material is deliberately
|
|
437
|
+
* rejected here; only `loadManagedMcp` invokes the source-specific parser that
|
|
438
|
+
* can mint the opaque managed TLS provenance.
|
|
439
|
+
*/
|
|
440
|
+
export function parseMcpServers(raw) {
|
|
441
|
+
return parseMcpServersForSource(raw);
|
|
442
|
+
}
|
|
443
|
+
|
|
220
444
|
/** Load organization-provisioned MCP servers as the highest-precedence layer. */
|
|
221
445
|
export async function loadManagedMcp(settings, deps = {}) {
|
|
222
446
|
const block = settings?.managedMcpServers || settings?.mcpServers;
|
|
223
447
|
if (!block || typeof block !== "object" || Array.isArray(block)) {
|
|
224
448
|
return deps.into || null;
|
|
225
449
|
}
|
|
226
|
-
const servers =
|
|
450
|
+
const servers = parseMcpServersForSource(
|
|
451
|
+
{ mcpServers: block },
|
|
452
|
+
{ provisionManagedTls: true },
|
|
453
|
+
);
|
|
227
454
|
const nameReservations = mcpServerNameReservations(deps);
|
|
228
455
|
for (const config of Object.values(servers)) {
|
|
229
456
|
config.configScope = "managed";
|
|
@@ -339,11 +566,30 @@ export function mcpAuthHint(url, errMessage) {
|
|
|
339
566
|
*/
|
|
340
567
|
export async function setupMcpFromConfig(servers, deps = {}) {
|
|
341
568
|
const writeErr = deps.writeErr || (() => {});
|
|
569
|
+
const mcpLifecycleAuthority =
|
|
570
|
+
deps.mcpLifecycleAuthority || new McpLifecycleAuthority();
|
|
342
571
|
const createClient =
|
|
343
572
|
deps.createClient ||
|
|
344
573
|
(() =>
|
|
345
|
-
new MCPClient({
|
|
574
|
+
new MCPClient({
|
|
575
|
+
eventRuntimeStore: deps.eventRuntimeStore || null,
|
|
576
|
+
lifecycleAuthority: mcpLifecycleAuthority,
|
|
577
|
+
sessionId: deps.sessionId,
|
|
578
|
+
}));
|
|
346
579
|
servers = filterMcpServersByPolicy(servers, deps.mcpPolicy, writeErr);
|
|
580
|
+
const enabledServers = {};
|
|
581
|
+
for (const [name, config] of Object.entries(servers)) {
|
|
582
|
+
if (config?.disabled === true || config?.enabled === false) {
|
|
583
|
+
mcpLifecycleAuthority.markDisabled({
|
|
584
|
+
name,
|
|
585
|
+
sessionId: deps.sessionId || "default",
|
|
586
|
+
config,
|
|
587
|
+
});
|
|
588
|
+
} else {
|
|
589
|
+
enabledServers[name] = config;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
servers = enabledServers;
|
|
347
593
|
const nameReservations = mcpServerNameReservations(deps);
|
|
348
594
|
const previouslyReservedNames = new Set(nameReservations);
|
|
349
595
|
|
|
@@ -373,6 +619,29 @@ export async function setupMcpFromConfig(servers, deps = {}) {
|
|
|
373
619
|
result.resourceTemplates = [];
|
|
374
620
|
}
|
|
375
621
|
if (!Array.isArray(result.prompts)) result.prompts = [];
|
|
622
|
+
if (!Array.isArray(result.mcpServerErrors)) {
|
|
623
|
+
result.mcpServerErrors = [];
|
|
624
|
+
}
|
|
625
|
+
if (Array.isArray(deps.mcpServerErrors)) {
|
|
626
|
+
for (const error of deps.mcpServerErrors) {
|
|
627
|
+
if (!error || typeof error !== "object") continue;
|
|
628
|
+
const normalized = mcpConfigError(
|
|
629
|
+
error.name,
|
|
630
|
+
error.type,
|
|
631
|
+
error.message || "MCP server configuration is invalid.",
|
|
632
|
+
);
|
|
633
|
+
if (
|
|
634
|
+
!result.mcpServerErrors.some(
|
|
635
|
+
(current) =>
|
|
636
|
+
current.name === normalized.name &&
|
|
637
|
+
current.type === normalized.type &&
|
|
638
|
+
current.message === normalized.message,
|
|
639
|
+
)
|
|
640
|
+
) {
|
|
641
|
+
result.mcpServerErrors.push(normalized);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
376
645
|
// Per-server usage instructions from the MCP initialize response (surfaced
|
|
377
646
|
// by tool search; absent for servers that send none).
|
|
378
647
|
if (
|
|
@@ -779,20 +1048,31 @@ export async function loadMcpConfig(filePath, deps = {}) {
|
|
|
779
1048
|
`--mcp-config: cannot read/parse "${filePath}": ${err.message}`,
|
|
780
1049
|
);
|
|
781
1050
|
}
|
|
782
|
-
const servers =
|
|
783
|
-
if (Object.keys(servers).length === 0) {
|
|
1051
|
+
const { servers, errors } = parseHeadlessMcpConfig(raw);
|
|
1052
|
+
if (Object.keys(servers).length === 0 && errors.length === 0) {
|
|
784
1053
|
throw new Error(
|
|
785
1054
|
`--mcp-config: no servers found in "${filePath}" ` +
|
|
786
1055
|
`(expected {"mcpServers": {"name": {"command": "..."}}}).`,
|
|
787
1056
|
);
|
|
788
1057
|
}
|
|
1058
|
+
if (errors.length > 0 && deps.mcpConfigWarnings !== false) {
|
|
1059
|
+
const count = errors.length;
|
|
1060
|
+
const noun = count === 1 ? "server" : "servers";
|
|
1061
|
+
deps.writeErr?.(
|
|
1062
|
+
`Warning: ${count} MCP ${noun} skipped due to invalid config:\n` +
|
|
1063
|
+
errors.map((error) => ` ${error.name}: ${error.message}\n`).join(""),
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
789
1066
|
authorizeStdioServers(
|
|
790
1067
|
servers,
|
|
791
1068
|
"explicit-config",
|
|
792
1069
|
() => path.resolve(filePath),
|
|
793
1070
|
{ failFast: true },
|
|
794
1071
|
);
|
|
795
|
-
return setupMcpFromConfig(servers,
|
|
1072
|
+
return setupMcpFromConfig(servers, {
|
|
1073
|
+
...deps,
|
|
1074
|
+
mcpServerErrors: errors,
|
|
1075
|
+
});
|
|
796
1076
|
}
|
|
797
1077
|
|
|
798
1078
|
/**
|
|
@@ -1317,6 +1597,15 @@ export async function resolveAgentMcp(args = {}, deps = {}) {
|
|
|
1317
1597
|
(runtimeEnv.CC_EVENT_RUNTIME_DURABLE === "1"
|
|
1318
1598
|
? new EventRuntimeStore()
|
|
1319
1599
|
: null);
|
|
1600
|
+
const mcpLifecycleAuthority =
|
|
1601
|
+
deps.mcpLifecycleAuthority ||
|
|
1602
|
+
args.mcpLifecycleAuthority ||
|
|
1603
|
+
new McpLifecycleAuthority({
|
|
1604
|
+
statePath:
|
|
1605
|
+
deps.mcpLifecycleStatePath ||
|
|
1606
|
+
args.mcpLifecycleStatePath ||
|
|
1607
|
+
defaultMcpLifecycleAuthorityPath(),
|
|
1608
|
+
});
|
|
1320
1609
|
const serverNameReservations =
|
|
1321
1610
|
deps.mcpServerNameReservations instanceof Set
|
|
1322
1611
|
? deps.mcpServerNameReservations
|
|
@@ -1341,6 +1630,7 @@ export async function resolveAgentMcp(args = {}, deps = {}) {
|
|
|
1341
1630
|
cwd: args.cwd || deps.cwd || process.cwd(),
|
|
1342
1631
|
...(args.sessionId != null ? { sessionId: args.sessionId } : {}),
|
|
1343
1632
|
...(eventRuntimeStore ? { eventRuntimeStore } : {}),
|
|
1633
|
+
mcpLifecycleAuthority,
|
|
1344
1634
|
mcpPolicy,
|
|
1345
1635
|
mcpServerNameReservations: serverNameReservations,
|
|
1346
1636
|
};
|