chainlesschain 0.166.103 → 0.166.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-BLrXpdnP.js → AIOps-Bah3HREy.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-C0xy9uFy.js → ActionButton-DY2aeZMc.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C6EephQP.js → Analytics-BFly8Xaa.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-ZCXdOD9y.js → AppLayout-dp0Zz-JM.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-D4MfZ-pl.js → Artifacts-DcIg09ai.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BQ8c3bBu.js → Audit-DkN-lsjZ.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BOA7_ljM.js → BackgroundAgents-BjzgusLx.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-60uiQjGT.js → Backup-CU8S6qu9.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BDvEbGs_.js → BaseInput-B1pC2gjL.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-B3IkAuFQ.js → Chat-B6xFp6gD.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DxNCLZ_X.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-njGbfJWq.js → Checkbox-QHw7Vc4U.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CF7DtdxC.js → Codegen-gdecsfjg.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C_3Zix40.js → Col-B0_JmAmc.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CzU-ZC2d.js → Community-DRCcP5xR.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BgeqsPRh.js → Compact-DZtoGzhX.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-6l7cwiqp.js → Compliance-BfNTvEnT.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-D4s905fI.js → Cowork-CDXTLm84.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-CGTYSxRS.js → Cron-Big35CbN.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BnSo-Yt3.js → Crosschain-C8ArrAVr.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Dm4vk2X1.js → DID-D_77BI2O.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-D7H-PZ_N.js → Dashboard-D2SxTzEp.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-COslkgxn.js → Dropdown-mR1-b9ud.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CJWEetmk.js → EmailListRenderer-DPl7TE1c.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-BbzebAWe.js → EvolutionSettings-BxRYLRSH.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BsoTOXwk.js → FamilyGuardDashboard-rnGtXJ5Z.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Ck5kM_5H.js → Federation-BpxenYK8.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-gShxCqtF.js → FormItemContext-Cz1kDf6l.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DarN1G-z.js → GenericCardRenderer-CGV3KN6U.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CJfpLyP5.js → Git-CIRP4UTx.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CVcJmpQz.js → Governance-DX4r8Vmt.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-ComU_ig8.js → Inference-DQKk02Hl.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-35hprFJy.js → KnowledgeGraph-DdD6J-By.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BQDqBTz0.js → Logs-DA2w-1_m.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BpdGAVCC.js → MarkdownRenderer-C9aSGETh.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-B9O9OKnn.js → Marketplace-BsJ6_6KW.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-VMKxA4Wc.js → McpTools-_6k30z6u.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CcBbf3Bc.js → Memory-C0_dYY0A.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-D7myz46N.js → MobileBridge-CCTnVqiC.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Da5KBXyx.js → MobileProjects-RZdxDSwC.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-x3NPZfuL.js → Mtc-D4Ys8lvX.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-CwnzptEC.js → MtcAudit-BKTC--a2.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-CCAxf4Ye.js → Multisig-CGR1qOe1.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CptHKz-Q.js → NLProgramming-hKKD4qWb.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-0uEp4DCJ.js → Notes-pCn7Ec40.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DthvrOLd.js → NotificationSettings-B9eEJXEs.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CmJuhaT2.js +1 -0
- package/src/assets/web-panel/assets/{Organization-BWf2tmQQ.js → Organization-CcQbrnwW.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BbvAtEth.js → Overflow-HmD4Mn72.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-zBo6enit.js → P2P-B7LIgx5H.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-D_LMQ4A4.js → PdhVaultBrowser-CXiHnBfX.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-C1ucb2ck.js → Permissions-CQRI3y_l.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Bz64RddJ.js → PersonalDataHub-1EeHmsy5.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DXJt3y3_.js → Pipeline-BFyoIdn8.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DiZ8b_ut.js → Privacy-BxWthXMF.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DfLKKrJ4.js → ProjectInit-DfigBilu.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Ct6kJuIY.js → ProjectSettings-CFmIcVc-.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BBUMlZ3m.js → Projects-CR7H59v3.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DYVQPHvc.js → Providers-2ulom-76.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-23Il7iPp.js → QrScannerModal-BwhO07b_.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-WgOZKrv1.js → QuickAsk-_Wg34OwF.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CRIka6xT.js → Recommend-D_jq6Svg.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DOy3GjVZ.js → RemoteSession-BlzvEfsa.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BXyi6xeR.js → Reputation-9CTXHfL4.js} +1 -1
- package/src/assets/web-panel/assets/{Row-CoMxuIcR.js → Row-DlCYCN-t.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-87hPkoM6.js → RssFeed-BvlInFCH.js} +3 -3
- package/src/assets/web-panel/assets/{Search-B1EqFCO4.js → Search-CfaUzKuL.js} +1 -1
- package/src/assets/web-panel/assets/{Security-HcC41eGs.js → Security-bAWgLyve.js} +3 -3
- package/src/assets/web-panel/assets/{Services-BqLwmvCM.js → Services-C4LOGACW.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CIMmjW4r.js → Skeleton-Dd0Uwh3_.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CgurezJU.js → Skills-ZYF1kYCU.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CJuRuqPE.js → Sla-DpsmIaEo.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BUwsbd1o.js → SpeechSettings-BBXoJ4yc.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-qo04TOX-.js → SyncSettings-SOnROi2Y.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-HFA_ZlDk.js +1 -0
- package/src/assets/web-panel/assets/{Templates-D1PTczPW.js → Templates-fsK-RCEc.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Bi0FkEPR.js → Tenant-CuqYxamb.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DfSt3bIF.js → Terminal-GKlI2R5F.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-B7bIVs4R.js → TimelineRenderer-DMDMHLeY.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-B6w5XrMb.js → Tokens-BoV60rh3.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-XXVSDWiF.js → Trigger-CE344-Ws.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DYvlgcK-.js → Trust-DENwgkVc.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-XyYwJMBM.js → UkeySign-FrcM7yfm.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C47WbtHH.js → VideoEditing-DAY9WaC2.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CYfqTj_C.js → Wallet-BuUR5i82.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-3AduFn1l.js → WebAuthn-nfSQuq85.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-DHYEHjMJ.js → WorkflowEditor-DHhPOp9l.js} +1 -1
- package/src/assets/web-panel/assets/{chat-AeehErSw.js → chat-C4nsLzYy.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DKXJ8paX.js → colors-BwXH0Wjn.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BOlCiomD.js → compact-item-uApFG30S.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BAP6U85b.js → createContext-BpyYs4fe.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Bk6HGn3N.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BLmeL1Xe.js → hasIn-MXCLi00p.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdNSmvog.js → index-1LxX2IwJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dv8-g1pY.js → index-61CBBrHE.js} +1 -1
- package/src/assets/web-panel/assets/{index-ClpwxOXo.js → index-B0P1Z_oa.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgtaOzMo.js → index-B7jojVc7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRcJlKSa.js → index-BEGMfaOo.js} +1 -1
- package/src/assets/web-panel/assets/{index-wyKpTsGM.js → index-BOhjapd5.js} +1 -1
- package/src/assets/web-panel/assets/{index-BuUwKmEI.js → index-BaBwXpAp.js} +1 -1
- package/src/assets/web-panel/assets/index-Bb1LPYdi.js +1 -0
- package/src/assets/web-panel/assets/{index-Co7pjF53.js → index-Btv--Nnt.js} +1 -1
- package/src/assets/web-panel/assets/index-C-FsTuFG.js +1 -0
- package/src/assets/web-panel/assets/{index-CFKzWIo8.js → index-CF0bUOP4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaHhfpBi.js → index-CNjUPfJP.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZMbXl5lo.js → index-CRmNdEk_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTnp4Nt3.js → index-C_oOpXhP.js} +1 -1
- package/src/assets/web-panel/assets/{index-OLKhib9T.js → index-ChUTKrOq.js} +1 -1
- package/src/assets/web-panel/assets/{index-T28naovw.js → index-CiIpIYhs.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bpx54vfs.js → index-CwVvk2i7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAS2QqLn.js → index-D3_tj06B.js} +1 -1
- package/src/assets/web-panel/assets/{index-CRa4pAaM.js → index-DE4W4vLO.js} +3 -3
- package/src/assets/web-panel/assets/{index-BSOenF5s.js → index-DLxKx5_J.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE7cbDDe.js → index-DTXi_gQh.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWYqOI1A.js → index-Daco83me.js} +1 -1
- package/src/assets/web-panel/assets/{index-DQLQuwpA.js → index-DffWVpZv.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiqeF0Pf.js → index-Dkncxel3.js} +1 -1
- package/src/assets/web-panel/assets/{index-IlzfIRNh.js → index-Dn12gJJU.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bn54FU3i.js → index-Dt-nq2eF.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bt-FCVzh.js → index-Du01X9N9.js} +1 -1
- package/src/assets/web-panel/assets/{index-EKNODw4P.js → index-DucLR6YX.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5AKY6bJ.js → index-Gz2rGWef.js} +1 -1
- package/src/assets/web-panel/assets/{index-C8qi53Ki.js → index-IvgszJ3C.js} +1 -1
- package/src/assets/web-panel/assets/{index-urPvyUVk.js → index-S80LLjdx.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bs2O3f81.js → index-WKbnwbKa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpZqbc4w.js → index-XHBXtvqp.js} +1 -1
- package/src/assets/web-panel/assets/{index-De2fPxdb.js → index-nn22NSDK.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0IjlB9m.js → index-pCIAE2yS.js} +1 -1
- package/src/assets/web-panel/assets/{index-PEe9OWEQ.js → index-pRpMLhMt.js} +1 -1
- package/src/assets/web-panel/assets/{index-FPXLIXoy.js → index-pgHGBAoF.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhcpWl5z.js → index-ugIUt5TL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsQ38fVY.js → index-xLGf7f9K.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CDWa1rnn.js → initDefaultProps-C58CkKEo.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CX2Cnsd5.js → motion-BLWPO2NV.js} +1 -1
- package/src/assets/web-panel/assets/{move-Bfe1NcEF.js → move-BgrFMwYp.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DbdqleHE.js → mtc-parser-Cq2AuGzl.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CE2K7NVv.js → omit-Bb-9L7if.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-y_bZgxWG.js → pickAttrs-vLmOxYr1.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BOHR4zwr.js → placementArrow-BNySU_dJ.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B8Jwq05-.js → responsiveObserve-xnbwagnm.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BD7RJ3Kn.js → slide-BccbY5Cn.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BuxDJeDx.js → statusUtils-DOp9d2-w.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DgYQ2Q0o.js → styleChecker-Bu1w6ho9.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DAHF0Fwi.js → useFlexGapSupport-ZsUOrVdL.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-D4kDyLFp.js → useFs-C0zpzKtO.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BHtSxW4A.js → usePersonalDataHub-DO1OdgXK.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CHKtdqW0.js → vnode-jTIRyhR5.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CIZAMma9.js → zoom-DKvS7-Qs.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +56 -20
- package/src/commands/batch.js +17 -12
- package/src/commands/eval.js +24 -8
- package/src/data/changelog.json +13 -0
- package/src/harness/mcp-client.js +187 -26
- package/src/lib/background-session-transport.js +21 -5
- package/src/lib/decision-layer/runtime.js +180 -10
- package/src/lib/direct-model-usage.js +34 -0
- package/src/lib/evolution/agent-evolution-ingress.js +63 -7
- package/src/lib/evolution/evolution-evidence-artifact-adapter.js +10 -0
- package/src/lib/evolution/evolution-evidence-projector.js +46 -7
- package/src/lib/evolution/skill-decision-projection.js +211 -0
- package/src/lib/evolution/skill-retrieval-revocation-authority.js +17 -2
- package/src/lib/skill-loader.js +16 -0
- package/src/repl/agent-repl.js +86 -7
- package/src/runtime/agent-core.js +111 -13
- package/src/runtime/headless-runner.js +212 -22
- package/src/runtime/headless-stream.js +189 -25
- package/src/runtime/mcp-config.js +26 -17
- package/src/runtime/mcp-tool-search.js +44 -14
- package/src/assets/web-panel/assets/ChatBubbleRenderer-n6BVStHf.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CxXuPzZg.js +0 -1
- package/src/assets/web-panel/assets/Tasks-QEFENVsp.js +0 -1
- package/src/assets/web-panel/assets/devWarning-rGldFhxo.js +0 -1
- package/src/assets/web-panel/assets/index-Cw-lfvvV.js +0 -1
- package/src/assets/web-panel/assets/index-QBXRSyoZ.js +0 -1
|
@@ -744,6 +744,51 @@ function mcpTransportError(code, message, details = {}) {
|
|
|
744
744
|
return error;
|
|
745
745
|
}
|
|
746
746
|
|
|
747
|
+
function pendingToolFailure(error, entry, method, dispatched) {
|
|
748
|
+
const httpStatus = safeRpcProperty(error, "status");
|
|
749
|
+
if (
|
|
750
|
+
method !== "tools/call" ||
|
|
751
|
+
!dispatched ||
|
|
752
|
+
isMcpRpcError(error) ||
|
|
753
|
+
safeRpcProperty(error, "outcomeUnknown") != null ||
|
|
754
|
+
(safeRpcProperty(error, "code") === "CC_MCP_HTTP_STATUS" &&
|
|
755
|
+
(httpStatus === 401 || httpStatus === 403 || httpStatus === 404))
|
|
756
|
+
) {
|
|
757
|
+
return error;
|
|
758
|
+
}
|
|
759
|
+
const originalCode = safeRpcProperty(error, "code");
|
|
760
|
+
if (
|
|
761
|
+
typeof originalCode === "string" &&
|
|
762
|
+
originalCode.startsWith("CC_MCP_") &&
|
|
763
|
+
!isProxy(error) &&
|
|
764
|
+
error instanceof Error
|
|
765
|
+
) {
|
|
766
|
+
try {
|
|
767
|
+
error.dispatched = true;
|
|
768
|
+
error.outcomeUnknown = true;
|
|
769
|
+
return error;
|
|
770
|
+
} catch {
|
|
771
|
+
// A frozen host error still needs a public uncertainty marker.
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
const message = safeRpcErrorText(error) || "MCP tool request failed";
|
|
775
|
+
return mcpTransportError(
|
|
776
|
+
typeof originalCode === "string" && originalCode.startsWith("CC_MCP_")
|
|
777
|
+
? originalCode
|
|
778
|
+
: "CC_MCP_TOOL_OUTCOME_UNKNOWN",
|
|
779
|
+
`${message}; tool outcome is unknown and was not replayed`,
|
|
780
|
+
{
|
|
781
|
+
transport: entry?.transportKind,
|
|
782
|
+
url: entry?.config?.url,
|
|
783
|
+
status: httpStatus,
|
|
784
|
+
closeCode: safeRpcProperty(error, "closeCode"),
|
|
785
|
+
limitBytes: safeRpcProperty(error, "limitBytes"),
|
|
786
|
+
dispatched: true,
|
|
787
|
+
outcomeUnknown: true,
|
|
788
|
+
},
|
|
789
|
+
);
|
|
790
|
+
}
|
|
791
|
+
|
|
747
792
|
function dispatchMcpToolRequest(options, metadata, dispatch) {
|
|
748
793
|
const admission = options?.dispatchAdmission ?? null;
|
|
749
794
|
if (metadata.method !== "tools/call" || admission === null) {
|
|
@@ -916,8 +961,8 @@ function mcpInboundBudgetError(serverName, entry, budget) {
|
|
|
916
961
|
function mcpJsonBudgetError(serverName, entry, budget) {
|
|
917
962
|
const dispatched = Boolean(
|
|
918
963
|
(entry?._pending instanceof Map && entry._pending.size > 0) ||
|
|
919
|
-
|
|
920
|
-
|
|
964
|
+
(entry?._httpRequestControllers instanceof Set &&
|
|
965
|
+
entry._httpRequestControllers.size > 0),
|
|
921
966
|
);
|
|
922
967
|
if (budget === "depth") {
|
|
923
968
|
const limitDepth = mcpJsonDepthLimit(entry?.config?.maxJsonDepth);
|
|
@@ -956,6 +1001,15 @@ function mcpSseEventTimeoutError(timeoutMs) {
|
|
|
956
1001
|
return error;
|
|
957
1002
|
}
|
|
958
1003
|
|
|
1004
|
+
function mcpSseHeaderTimeoutError(timeoutMs) {
|
|
1005
|
+
const error = new Error(
|
|
1006
|
+
`MCP HTTP message stream headers exceeded the ${timeoutMs}ms host deadline`,
|
|
1007
|
+
);
|
|
1008
|
+
error.code = "CC_MCP_SSE_HEADER_TIMEOUT";
|
|
1009
|
+
error.timeoutMs = timeoutMs;
|
|
1010
|
+
return error;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
959
1013
|
function mcpHttpResponseTimeoutError(
|
|
960
1014
|
serverName,
|
|
961
1015
|
entry,
|
|
@@ -999,6 +1053,7 @@ const MCP_NON_RETRYABLE_PROTOCOL_ERROR_CODES = new Set([
|
|
|
999
1053
|
"CC_MCP_HTTP_RESPONSE_TIMEOUT",
|
|
1000
1054
|
"CC_MCP_HTTP_DISCARD_TIMEOUT",
|
|
1001
1055
|
"CC_MCP_SSE_EVENT_TIMEOUT",
|
|
1056
|
+
"CC_MCP_SSE_HEADER_TIMEOUT",
|
|
1002
1057
|
"CC_MCP_INBOUND_RATE_EXCEEDED",
|
|
1003
1058
|
"CC_MCP_INBOUND_TRAFFIC_EXCEEDED",
|
|
1004
1059
|
"CC_MCP_JSON_DEPTH_EXCEEDED",
|
|
@@ -1009,6 +1064,8 @@ const MCP_NON_RETRYABLE_PROTOCOL_ERROR_CODES = new Set([
|
|
|
1009
1064
|
"CC_MCP_RPC_ERROR_INVALID",
|
|
1010
1065
|
"CC_MCP_RPC_RESPONSE_INVALID",
|
|
1011
1066
|
"CC_MCP_RPC_MESSAGE_INVALID",
|
|
1067
|
+
"CC_MCP_TOOL_CATALOG_STALE",
|
|
1068
|
+
"CC_MCP_TOOL_NOT_ADVERTISED",
|
|
1012
1069
|
]);
|
|
1013
1070
|
|
|
1014
1071
|
function isMcpNonRetryableProtocolError(error) {
|
|
@@ -1422,6 +1479,7 @@ export class MCPClient extends EventEmitter {
|
|
|
1422
1479
|
this._toolMetadataBytes = 0;
|
|
1423
1480
|
this._nextId = 1;
|
|
1424
1481
|
this._reconnectors = new Map(); // name → async () => config|null
|
|
1482
|
+
this._unknownOutcomeRecovery = new Set(); // reconnect only for future explicit calls
|
|
1425
1483
|
this._reconnecting = new Map(); // name → in-flight reconnect promise
|
|
1426
1484
|
// progressToken → reset-idle callback for in-flight tools/call requests.
|
|
1427
1485
|
// Tokens are generated by this client and are removed on every terminal
|
|
@@ -2162,15 +2220,25 @@ export class MCPClient extends EventEmitter {
|
|
|
2162
2220
|
* Register a reconnector for a server: an async function that returns a
|
|
2163
2221
|
* FRESH connection config (or null when the server can't be found anymore).
|
|
2164
2222
|
* When a `callTool` on that server fails with a connection-shaped error,
|
|
2165
|
-
* the client re-resolves the config
|
|
2223
|
+
* the client re-resolves the config. An opt-in bridge may also reconnect
|
|
2224
|
+
* after an unknown tool outcome, without replaying that call.
|
|
2166
2225
|
*
|
|
2167
2226
|
* Used by the IDE bridge: a window reload / extension update restarts the
|
|
2168
2227
|
* editor's MCP server on a new port with a new token, so the original
|
|
2169
2228
|
* config is permanently dead but a lockfile re-scan finds the new one.
|
|
2170
2229
|
*/
|
|
2171
|
-
setReconnector(name, fn) {
|
|
2172
|
-
if (typeof fn === "function")
|
|
2173
|
-
|
|
2230
|
+
setReconnector(name, fn, options = {}) {
|
|
2231
|
+
if (typeof fn === "function") {
|
|
2232
|
+
this._reconnectors.set(name, fn);
|
|
2233
|
+
if (options.recoverUnknownOutcome === true) {
|
|
2234
|
+
this._unknownOutcomeRecovery.add(name);
|
|
2235
|
+
} else {
|
|
2236
|
+
this._unknownOutcomeRecovery.delete(name);
|
|
2237
|
+
}
|
|
2238
|
+
} else {
|
|
2239
|
+
this._reconnectors.delete(name);
|
|
2240
|
+
this._unknownOutcomeRecovery.delete(name);
|
|
2241
|
+
}
|
|
2174
2242
|
}
|
|
2175
2243
|
|
|
2176
2244
|
/** Return the opaque host authority used to resolve policy-bearing MCP cwd. */
|
|
@@ -3057,6 +3125,7 @@ export class MCPClient extends EventEmitter {
|
|
|
3057
3125
|
this._replaceToolInventory(name, entry, toolsResult?.tools || []);
|
|
3058
3126
|
} catch (err) {
|
|
3059
3127
|
if (isMcpFatalDiscoveryError(err)) throw err;
|
|
3128
|
+
entry._toolInventoryReady = true;
|
|
3060
3129
|
if (advertisesTools) {
|
|
3061
3130
|
toolsDiscoveryFailed = true;
|
|
3062
3131
|
entry.toolsError = err?.message || String(err);
|
|
@@ -3464,6 +3533,7 @@ export class MCPClient extends EventEmitter {
|
|
|
3464
3533
|
clientBytesUsed,
|
|
3465
3534
|
});
|
|
3466
3535
|
entry.tools = admitted.tools;
|
|
3536
|
+
entry._toolInventoryReady = true;
|
|
3467
3537
|
entry._toolMetadataBytes = admitted.metadataBytes;
|
|
3468
3538
|
this._toolMetadataBytes = clientBytesUsed + admitted.metadataBytes;
|
|
3469
3539
|
return entry.tools;
|
|
@@ -3525,9 +3595,9 @@ export class MCPClient extends EventEmitter {
|
|
|
3525
3595
|
* Call a tool on a specific server. If the server has a registered
|
|
3526
3596
|
* reconnector and the call fails with a connection-shaped error (server
|
|
3527
3597
|
* restarted / token rotated / entry dropped), re-resolve the config,
|
|
3528
|
-
* reconnect, and retry
|
|
3529
|
-
*
|
|
3530
|
-
*
|
|
3598
|
+
* reconnect, and retry a call only when its outcome is known not to have
|
|
3599
|
+
* occurred. An already-dispatched tool with an unknown outcome may refresh
|
|
3600
|
+
* the connection for a later explicit call, but is never replayed here.
|
|
3531
3601
|
* @param {string} serverName - Server name
|
|
3532
3602
|
* @param {string} toolName - Tool name
|
|
3533
3603
|
* @param {object} args - Tool arguments
|
|
@@ -3589,7 +3659,28 @@ export class MCPClient extends EventEmitter {
|
|
|
3589
3659
|
// Retry exactly once after every out-of-band flow reports completion.
|
|
3590
3660
|
return this._callToolOnce(serverName, toolName, args, options);
|
|
3591
3661
|
}
|
|
3592
|
-
if (safeRpcProperty(err, "outcomeUnknown") === true)
|
|
3662
|
+
if (safeRpcProperty(err, "outcomeUnknown") === true) {
|
|
3663
|
+
if (
|
|
3664
|
+
!options?.signal?.aborted &&
|
|
3665
|
+
isLikelyConnectionError(err) &&
|
|
3666
|
+
this._unknownOutcomeRecovery.has(serverName)
|
|
3667
|
+
) {
|
|
3668
|
+
const current = this.servers.get(serverName);
|
|
3669
|
+
const recovered =
|
|
3670
|
+
current && current !== attemptedEntry
|
|
3671
|
+
? current.state === ServerState.CONNECTED
|
|
3672
|
+
: await this._tryReconnect(serverName, {
|
|
3673
|
+
connectAuthRetryUsed: true,
|
|
3674
|
+
expectedEntry: attemptedEntry,
|
|
3675
|
+
});
|
|
3676
|
+
try {
|
|
3677
|
+
err.connectionRecovered = Boolean(recovered);
|
|
3678
|
+
} catch {
|
|
3679
|
+
// A frozen error still retains its original unknown-outcome marker.
|
|
3680
|
+
}
|
|
3681
|
+
}
|
|
3682
|
+
throw err;
|
|
3683
|
+
}
|
|
3593
3684
|
if (
|
|
3594
3685
|
!this._reconnectors.has(serverName) &&
|
|
3595
3686
|
!this.servers.get(serverName)?.config?.headersHelper
|
|
@@ -3704,6 +3795,23 @@ export class MCPClient extends EventEmitter {
|
|
|
3704
3795
|
if (entry.state !== ServerState.CONNECTED) {
|
|
3705
3796
|
throw new Error(`Server "${serverName}" is not connected`);
|
|
3706
3797
|
}
|
|
3798
|
+
if (entry._toolInventoryDirty) {
|
|
3799
|
+
throw mcpTransportError(
|
|
3800
|
+
"CC_MCP_TOOL_CATALOG_STALE",
|
|
3801
|
+
`MCP tool catalog for server "${serverName}" is refreshing; retry after it settles`,
|
|
3802
|
+
{ transport: entry.transportKind, dispatched: false },
|
|
3803
|
+
);
|
|
3804
|
+
}
|
|
3805
|
+
if (
|
|
3806
|
+
entry._toolInventoryReady &&
|
|
3807
|
+
!entry.tools.some((tool) => tool.name === toolName)
|
|
3808
|
+
) {
|
|
3809
|
+
throw mcpTransportError(
|
|
3810
|
+
"CC_MCP_TOOL_NOT_ADVERTISED",
|
|
3811
|
+
`MCP tool "${toolName}" is not advertised by server "${serverName}"`,
|
|
3812
|
+
{ transport: entry.transportKind, dispatched: false },
|
|
3813
|
+
);
|
|
3814
|
+
}
|
|
3707
3815
|
|
|
3708
3816
|
const timeoutMs = mcpToolIdleTimeoutMs(entry.config, options);
|
|
3709
3817
|
const progressToken = `cc:${randomUUID()}`;
|
|
@@ -4137,7 +4245,8 @@ export class MCPClient extends EventEmitter {
|
|
|
4137
4245
|
};
|
|
4138
4246
|
const pending = {
|
|
4139
4247
|
resolve: (value) => settle(resolve, value),
|
|
4140
|
-
reject: (error) =>
|
|
4248
|
+
reject: (error) =>
|
|
4249
|
+
settle(reject, pendingToolFailure(error, entry, method, dispatched)),
|
|
4141
4250
|
};
|
|
4142
4251
|
entry._pending.set(id, pending);
|
|
4143
4252
|
|
|
@@ -4184,7 +4293,7 @@ export class MCPClient extends EventEmitter {
|
|
|
4184
4293
|
if (!longRunning && timeoutMs > 0) {
|
|
4185
4294
|
timeout = setTimeout(() => {
|
|
4186
4295
|
const timeoutError = new Error(`Request timeout: ${method}`);
|
|
4187
|
-
if (!
|
|
4296
|
+
if (!pending.reject(timeoutError)) return;
|
|
4188
4297
|
this._sendRequestCancellation(
|
|
4189
4298
|
serverName,
|
|
4190
4299
|
method,
|
|
@@ -4276,7 +4385,8 @@ export class MCPClient extends EventEmitter {
|
|
|
4276
4385
|
};
|
|
4277
4386
|
const pending = {
|
|
4278
4387
|
resolve: (value) => settle(resolve, value),
|
|
4279
|
-
reject: (error) =>
|
|
4388
|
+
reject: (error) =>
|
|
4389
|
+
settle(reject, pendingToolFailure(error, entry, method, dispatched)),
|
|
4280
4390
|
};
|
|
4281
4391
|
entry._pending.set(id, pending);
|
|
4282
4392
|
|
|
@@ -4314,7 +4424,7 @@ export class MCPClient extends EventEmitter {
|
|
|
4314
4424
|
`Request timeout: ${method} (WebSocket, no response in ${timeoutMs}ms)`,
|
|
4315
4425
|
{ transport: entry.transportKind, url: entry.config?.url },
|
|
4316
4426
|
);
|
|
4317
|
-
if (!
|
|
4427
|
+
if (!pending.reject(timeoutError)) return;
|
|
4318
4428
|
this._sendRequestCancellation(
|
|
4319
4429
|
serverName,
|
|
4320
4430
|
method,
|
|
@@ -4472,7 +4582,10 @@ export class MCPClient extends EventEmitter {
|
|
|
4472
4582
|
? { dispatcher: entry._httpDispatcher }
|
|
4473
4583
|
: {}),
|
|
4474
4584
|
}),
|
|
4475
|
-
|
|
4585
|
+
{
|
|
4586
|
+
controller: stream.controller,
|
|
4587
|
+
timeoutMs: _sseEventTimeout(entry.config?.requestTimeoutMs),
|
|
4588
|
+
},
|
|
4476
4589
|
);
|
|
4477
4590
|
if (response.status === 405) {
|
|
4478
4591
|
_cancelHttpResponseBody(response);
|
|
@@ -4547,6 +4660,7 @@ export class MCPClient extends EventEmitter {
|
|
|
4547
4660
|
return;
|
|
4548
4661
|
}
|
|
4549
4662
|
if (error?.code === "CC_MCP_SSE_EVENT_TIMEOUT") return;
|
|
4663
|
+
if (error?.code === "CC_MCP_SSE_HEADER_TIMEOUT") return;
|
|
4550
4664
|
if (error?.code === "CC_MCP_INBOUND_RATE_EXCEEDED") return;
|
|
4551
4665
|
if (error?.code === "CC_MCP_INBOUND_TRAFFIC_EXCEEDED") return;
|
|
4552
4666
|
if (error?.code === "CC_MCP_JSON_DEPTH_EXCEEDED") return;
|
|
@@ -4853,10 +4967,15 @@ export class MCPClient extends EventEmitter {
|
|
|
4853
4967
|
throwIfAborted();
|
|
4854
4968
|
} catch (abortError) {
|
|
4855
4969
|
settleLifecycle("failed-closed");
|
|
4856
|
-
throw
|
|
4970
|
+
throw pendingToolFailure(
|
|
4971
|
+
abortError,
|
|
4972
|
+
entry,
|
|
4973
|
+
method,
|
|
4974
|
+
request?.dispatched,
|
|
4975
|
+
);
|
|
4857
4976
|
}
|
|
4858
4977
|
settleLifecycle("failed-closed");
|
|
4859
|
-
throw err;
|
|
4978
|
+
throw pendingToolFailure(err, entry, method, request?.dispatched);
|
|
4860
4979
|
} finally {
|
|
4861
4980
|
if (timer) clearTimeout(timer);
|
|
4862
4981
|
if (responseTimer) clearTimeout(responseTimer);
|
|
@@ -5272,15 +5391,22 @@ export class MCPClient extends EventEmitter {
|
|
|
5272
5391
|
async _refreshServerList(serverName, kind) {
|
|
5273
5392
|
const entry = this.servers.get(serverName);
|
|
5274
5393
|
if (!entry) return;
|
|
5394
|
+
if (kind === "tools") {
|
|
5395
|
+
entry._toolInventoryDirty = true;
|
|
5396
|
+
}
|
|
5275
5397
|
const flags = (entry._listRefresh = entry._listRefresh || {});
|
|
5276
5398
|
if (flags[`${kind}Running`]) {
|
|
5277
5399
|
flags[`${kind}Dirty`] = true;
|
|
5278
5400
|
return;
|
|
5279
5401
|
}
|
|
5280
5402
|
flags[`${kind}Running`] = true;
|
|
5403
|
+
let refreshed = false;
|
|
5404
|
+
let toolCount = 0;
|
|
5281
5405
|
try {
|
|
5282
5406
|
do {
|
|
5407
|
+
if (this.servers.get(serverName) !== entry) return;
|
|
5283
5408
|
flags[`${kind}Dirty`] = false;
|
|
5409
|
+
refreshed = false;
|
|
5284
5410
|
try {
|
|
5285
5411
|
const method =
|
|
5286
5412
|
kind === "tools"
|
|
@@ -5289,6 +5415,10 @@ export class MCPClient extends EventEmitter {
|
|
|
5289
5415
|
? "resources/templates/list"
|
|
5290
5416
|
: "resources/list";
|
|
5291
5417
|
const result = await this._sendRequest(serverName, method, {});
|
|
5418
|
+
// A reconnect can replace this entry while the old list request is
|
|
5419
|
+
// pending. Never let its late result mutate the replacement's global
|
|
5420
|
+
// metadata budget or publish a stale inventory event.
|
|
5421
|
+
if (this.servers.get(serverName) !== entry) return;
|
|
5292
5422
|
const list =
|
|
5293
5423
|
(kind === "tools"
|
|
5294
5424
|
? result?.tools
|
|
@@ -5298,14 +5428,17 @@ export class MCPClient extends EventEmitter {
|
|
|
5298
5428
|
if (kind === "tools") {
|
|
5299
5429
|
this._replaceToolInventory(serverName, entry, list);
|
|
5300
5430
|
entry.toolsError = null;
|
|
5431
|
+
toolCount = list.length;
|
|
5301
5432
|
} else {
|
|
5302
5433
|
entry[kind] = list;
|
|
5434
|
+
this.emit(`${kind}-changed`, {
|
|
5435
|
+
server: serverName,
|
|
5436
|
+
count: list.length,
|
|
5437
|
+
});
|
|
5303
5438
|
}
|
|
5304
|
-
|
|
5305
|
-
server: serverName,
|
|
5306
|
-
count: list.length,
|
|
5307
|
-
});
|
|
5439
|
+
refreshed = true;
|
|
5308
5440
|
} catch (error) {
|
|
5441
|
+
if (this.servers.get(serverName) !== entry) return;
|
|
5309
5442
|
if (kind === "tools" && isMcpToolMetadataError(error)) {
|
|
5310
5443
|
entry.toolsError = error.message;
|
|
5311
5444
|
this.emit("server-error", {
|
|
@@ -5331,6 +5464,19 @@ export class MCPClient extends EventEmitter {
|
|
|
5331
5464
|
} while (flags[`${kind}Dirty`]);
|
|
5332
5465
|
} finally {
|
|
5333
5466
|
flags[`${kind}Running`] = false;
|
|
5467
|
+
if (
|
|
5468
|
+
kind === "tools" &&
|
|
5469
|
+
refreshed &&
|
|
5470
|
+
this.servers.get(serverName) === entry
|
|
5471
|
+
) {
|
|
5472
|
+
// Event listeners may call a newly advertised tool immediately.
|
|
5473
|
+
entry._toolInventoryDirty = false;
|
|
5474
|
+
try {
|
|
5475
|
+
this.emit("tools-changed", { server: serverName, count: toolCount });
|
|
5476
|
+
} catch {
|
|
5477
|
+
// An observer cannot make a successfully refreshed catalog stale.
|
|
5478
|
+
}
|
|
5479
|
+
}
|
|
5334
5480
|
}
|
|
5335
5481
|
}
|
|
5336
5482
|
|
|
@@ -5601,9 +5747,12 @@ function _readHttpReaderChunk(reader, signal) {
|
|
|
5601
5747
|
});
|
|
5602
5748
|
}
|
|
5603
5749
|
|
|
5604
|
-
function _waitForHttpMessageStreamResponse(
|
|
5605
|
-
|
|
5606
|
-
|
|
5750
|
+
function _waitForHttpMessageStreamResponse(
|
|
5751
|
+
responsePromise,
|
|
5752
|
+
{ controller, timeoutMs } = {},
|
|
5753
|
+
) {
|
|
5754
|
+
const signal = controller?.signal;
|
|
5755
|
+
if (signal?.aborted) {
|
|
5607
5756
|
Promise.resolve(responsePromise).then(
|
|
5608
5757
|
(response) => _cancelHttpResponseBody(response),
|
|
5609
5758
|
() => {},
|
|
@@ -5613,7 +5762,11 @@ function _waitForHttpMessageStreamResponse(responsePromise, signal) {
|
|
|
5613
5762
|
return new Promise((resolve, reject) => {
|
|
5614
5763
|
let settled = false;
|
|
5615
5764
|
let aborted = false;
|
|
5616
|
-
|
|
5765
|
+
let timer;
|
|
5766
|
+
const cleanup = () => {
|
|
5767
|
+
clearTimeout(timer);
|
|
5768
|
+
signal?.removeEventListener?.("abort", onAbort);
|
|
5769
|
+
};
|
|
5617
5770
|
const finish = (settler, value) => {
|
|
5618
5771
|
if (settled) return false;
|
|
5619
5772
|
settled = true;
|
|
@@ -5625,7 +5778,15 @@ function _waitForHttpMessageStreamResponse(responsePromise, signal) {
|
|
|
5625
5778
|
aborted = true;
|
|
5626
5779
|
finish(reject, _httpReadAbortedError());
|
|
5627
5780
|
};
|
|
5628
|
-
|
|
5781
|
+
if (Number.isFinite(timeoutMs) && timeoutMs > 0) {
|
|
5782
|
+
timer = setTimeout(() => {
|
|
5783
|
+
aborted = true;
|
|
5784
|
+
if (finish(reject, mcpSseHeaderTimeoutError(timeoutMs))) {
|
|
5785
|
+
controller?.abort();
|
|
5786
|
+
}
|
|
5787
|
+
}, timeoutMs);
|
|
5788
|
+
}
|
|
5789
|
+
signal?.addEventListener?.("abort", onAbort, { once: true });
|
|
5629
5790
|
Promise.resolve(responsePromise).then(
|
|
5630
5791
|
(response) => {
|
|
5631
5792
|
if (!finish(resolve, response) && aborted) {
|
|
@@ -50,17 +50,28 @@ export function transportPipePath(id, dir, options = {}) {
|
|
|
50
50
|
*/
|
|
51
51
|
export function createNdjsonReader(onMessage, onError = () => {}) {
|
|
52
52
|
let carry = "";
|
|
53
|
+
let droppingOversizedLine = false;
|
|
54
|
+
const decoder = new TextDecoder("utf-8");
|
|
53
55
|
return (chunk) => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
let text =
|
|
57
|
+
typeof chunk === "string"
|
|
58
|
+
? chunk
|
|
59
|
+
: decoder.decode(chunk, { stream: true });
|
|
60
|
+
if (droppingOversizedLine) {
|
|
61
|
+
const end = text.indexOf("\n");
|
|
62
|
+
if (end < 0) return;
|
|
63
|
+
droppingOversizedLine = false;
|
|
64
|
+
text = text.slice(end + 1);
|
|
59
65
|
}
|
|
66
|
+
carry += text;
|
|
60
67
|
let index;
|
|
61
68
|
while ((index = carry.indexOf("\n")) !== -1) {
|
|
62
69
|
const line = carry.slice(0, index).replace(/\r$/, "");
|
|
63
70
|
carry = carry.slice(index + 1);
|
|
71
|
+
if (Buffer.byteLength(line, "utf8") > MAX_LINE_BYTES) {
|
|
72
|
+
onError(new Error("line too long"));
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
64
75
|
if (!line.trim()) continue;
|
|
65
76
|
let message;
|
|
66
77
|
try {
|
|
@@ -71,6 +82,11 @@ export function createNdjsonReader(onMessage, onError = () => {}) {
|
|
|
71
82
|
}
|
|
72
83
|
onMessage(message);
|
|
73
84
|
}
|
|
85
|
+
if (Buffer.byteLength(carry, "utf8") > MAX_LINE_BYTES) {
|
|
86
|
+
carry = "";
|
|
87
|
+
droppingOversizedLine = true;
|
|
88
|
+
onError(new Error("line too long"));
|
|
89
|
+
}
|
|
74
90
|
};
|
|
75
91
|
}
|
|
76
92
|
|