@google/gemini-cli 0.64.0-preview.0 → 0.64.0-preview.1
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/bundle/{chunk-EDVFNWRG.js → chunk-2XMCTNPW.js} +1 -1
- package/bundle/{chunk-HN74ORTP.js → chunk-46DG3MEK.js} +15 -3
- package/bundle/{chunk-UFQDAROY.js → chunk-4TPFLAND.js} +1 -1
- package/bundle/{chunk-A4TO2DY2.js → chunk-627EICDK.js} +8258 -14927
- package/bundle/{chunk-EDYPRCAA.js → chunk-6JF3XGX6.js} +2 -2
- package/bundle/{chunk-SDWOC67Z.js → chunk-7AV6KELE.js} +1 -1
- package/bundle/{chunk-EBP6K2WG.js → chunk-7FPYEHDV.js} +25 -9
- package/bundle/{chunk-U76XPSKR.js → chunk-7OAPTXNW.js} +89 -60
- package/bundle/{chunk-EFX5XL6M.js → chunk-BONG2QK5.js} +2 -2
- package/bundle/{chunk-VBVCLWLA.js → chunk-BRVQMVD5.js} +2 -2
- package/bundle/{chunk-2NQXIWQK.js → chunk-BSE7BCTQ.js} +15 -3
- package/bundle/chunk-BYVRH4VZ.js +103137 -0
- package/bundle/{chunk-HSZIYPL6.js → chunk-EE4FVMPM.js} +3 -3
- package/bundle/{chunk-QUCRASYB.js → chunk-GWH2CDNQ.js} +1 -1
- package/bundle/{chunk-NX7TO2DU.js → chunk-H2WBGLUF.js} +1 -1
- package/bundle/{chunk-Y2HXXBXI.js → chunk-J7KGQZGT.js} +1 -1
- package/bundle/{chunk-UBGF6JU5.js → chunk-JLBO43LX.js} +1 -1
- package/bundle/{chunk-ZPLFLZQA.js → chunk-L3JNREL2.js} +21 -7
- package/bundle/{chunk-ZQW7OGUO.js → chunk-MN5WGELB.js} +426 -91
- package/bundle/{chunk-6OFXOGEG.js → chunk-NTBZBCDY.js} +456 -94
- package/bundle/{chunk-ZOHM7BPT.js → chunk-ONZZ4MZP.js} +1 -1
- package/bundle/chunk-POXVKWMH.js +17519 -0
- package/bundle/{chunk-MLSLNORV.js → chunk-R7OEYEVK.js} +3 -3
- package/bundle/{chunk-KCCVXZ52.js → chunk-RIRMXE4G.js} +25 -9
- package/bundle/{chunk-2VN53SWW.js → chunk-RQB6UOWL.js} +9 -8
- package/bundle/{chunk-VJYKQD5D.js → chunk-SQZOWFWU.js} +3 -3
- package/bundle/chunk-T7UXARRX.js +401531 -0
- package/bundle/chunk-TDYDNMXH.js +425 -0
- package/bundle/chunk-TVJ4WAFU.js +512 -0
- package/bundle/chunk-XNLASMX4.js +154 -0
- package/bundle/chunk-Y3EQFIOM.js +118 -0
- package/bundle/chunk-YKGBOB2S.js +1571 -0
- package/bundle/{cleanup-GGCB2LVD.js → cleanup-5HA3CDPH.js} +2 -2
- package/bundle/{cleanup-JRDG3OTL.js → cleanup-LXXTR2OE.js} +2 -2
- package/bundle/{cleanup-SSW6IXTR.js → cleanup-RM72YALN.js} +2 -2
- package/bundle/cleanup-TBTZ6WZD.js +32 -0
- package/bundle/{core-IUIZE6JW.js → core-NBQGNNOM.js} +11 -1
- package/bundle/{devtoolsService-3SADPKKB.js → devtoolsService-BUAVC3ZD.js} +2 -2
- package/bundle/{devtoolsService-XZCKFZP5.js → devtoolsService-DCRIOTR4.js} +2 -2
- package/bundle/{devtoolsService-MF6JKRUV.js → devtoolsService-PXS65V3Y.js} +4 -3
- package/bundle/devtoolsService-ZHFOHPIS.js +4359 -0
- package/bundle/{dist-7L3BRW6V.js → dist-24APVFHT.js} +11 -1
- package/bundle/{core-6HRWFQZW.js → dist-EOOSNLUQ.js} +11 -1
- package/bundle/dist-YP3VMVL6.js +2262 -0
- package/bundle/docs/tools/mcp-server.md +41 -12
- package/bundle/{gemini-JPMMQ3KA.js → gemini-LHZDQRUM.js} +13 -13
- package/bundle/{gemini-ZMMDUAQJ.js → gemini-Q4LI2KHU.js} +214 -198
- package/bundle/gemini-QM6PZXIH.js +17934 -0
- package/bundle/{gemini-QOQNG5VY.js → gemini-UEMV4Y7B.js} +13 -13
- package/bundle/gemini.js +7 -7
- package/bundle/{interactiveCli-R3P4A3FC.js → interactiveCli-HMZ5ZWK4.js} +9 -20
- package/bundle/{interactiveCli-UDWGRVJL.js → interactiveCli-IQQYS4AV.js} +9 -20
- package/bundle/{interactiveCli-3I4TG5SK.js → interactiveCli-QCNSW3M7.js} +313 -305
- package/bundle/interactiveCli-QXZXFSNY.js +34968 -0
- package/bundle/{liteRtServerManager-OVPUSK2T.js → liteRtServerManager-2I4N5IEZ.js} +4 -4
- package/bundle/{liteRtServerManager-RAV63AGE.js → liteRtServerManager-3IZ2LKBD.js} +4 -4
- package/bundle/{liteRtServerManager-4MWCEVVM.js → liteRtServerManager-RABYR6TB.js} +4 -4
- package/bundle/liteRtServerManager-T3MOB7VG.js +65 -0
- package/bundle/{oauth2-provider-FVTRRJZR.js → oauth2-provider-I3CU23H3.js} +1 -1
- package/bundle/{oauth2-provider-EWOA64PR.js → oauth2-provider-INBLO6HF.js} +38 -72
- package/bundle/oauth2-provider-UZV2BJA3.js +235 -0
- package/bundle/{oauth2-provider-XFP63FGJ.js → oauth2-provider-XFPEOXNY.js} +1 -1
- package/bundle/{start-DJAIXPPY.js → start-4UWH3BI7.js} +6 -6
- package/bundle/{start-VQQ2Q5KT.js → start-CQTZWDLV.js} +6 -6
- package/bundle/{start-5O7TBK5L.js → start-D6DJS7SZ.js} +6 -6
- package/bundle/start-IXFELTCY.js +18 -0
- package/package.json +1 -1
|
@@ -283529,7 +283529,7 @@ function isValidToolName(name3, options = {}) {
|
|
|
283529
283529
|
}
|
|
283530
283530
|
|
|
283531
283531
|
// packages/core/dist/src/generated/git-commit.js
|
|
283532
|
-
var GIT_COMMIT_INFO = "
|
|
283532
|
+
var GIT_COMMIT_INFO = "581fdbbfa";
|
|
283533
283533
|
var CLI_VERSION = "0.64.0-preview.0";
|
|
283534
283534
|
|
|
283535
283535
|
// packages/core/dist/src/ide/detect-ide.js
|
|
@@ -307310,7 +307310,7 @@ function getVersion() {
|
|
|
307310
307310
|
}
|
|
307311
307311
|
versionPromise = (async () => {
|
|
307312
307312
|
const pkgJson = await getPackageJson(__dirname4);
|
|
307313
|
-
return "0.64.0-preview.
|
|
307313
|
+
return "0.64.0-preview.1";
|
|
307314
307314
|
})();
|
|
307315
307315
|
return versionPromise;
|
|
307316
307316
|
}
|
|
@@ -309438,6 +309438,142 @@ var BENIGN_SUBCOMMAND_TOKENS = /* @__PURE__ */ new Set([
|
|
|
309438
309438
|
"restart",
|
|
309439
309439
|
"status"
|
|
309440
309440
|
]);
|
|
309441
|
+
var SAFE_SHORT_FLAGS = /* @__PURE__ */ new Set([
|
|
309442
|
+
"-a",
|
|
309443
|
+
"-A",
|
|
309444
|
+
"-b",
|
|
309445
|
+
"-B",
|
|
309446
|
+
"-C",
|
|
309447
|
+
"-d",
|
|
309448
|
+
"-D",
|
|
309449
|
+
"-E",
|
|
309450
|
+
"-F",
|
|
309451
|
+
"-g",
|
|
309452
|
+
"-G",
|
|
309453
|
+
"-h",
|
|
309454
|
+
"-H",
|
|
309455
|
+
"-i",
|
|
309456
|
+
"-I",
|
|
309457
|
+
"-l",
|
|
309458
|
+
"-L",
|
|
309459
|
+
"-m",
|
|
309460
|
+
"-n",
|
|
309461
|
+
"-N",
|
|
309462
|
+
"-p",
|
|
309463
|
+
"-P",
|
|
309464
|
+
"-q",
|
|
309465
|
+
"-r",
|
|
309466
|
+
"-R",
|
|
309467
|
+
"-s",
|
|
309468
|
+
"-S",
|
|
309469
|
+
"-t",
|
|
309470
|
+
"-T",
|
|
309471
|
+
"-u",
|
|
309472
|
+
"-U",
|
|
309473
|
+
"-v",
|
|
309474
|
+
"-V",
|
|
309475
|
+
"-w",
|
|
309476
|
+
"-W",
|
|
309477
|
+
"-x",
|
|
309478
|
+
"-z",
|
|
309479
|
+
"-1",
|
|
309480
|
+
// Common combined POSIX inspection flags (ls, grep, ps, git)
|
|
309481
|
+
"-la",
|
|
309482
|
+
"-al",
|
|
309483
|
+
"-ld",
|
|
309484
|
+
"-dl",
|
|
309485
|
+
"-lh",
|
|
309486
|
+
"-hl",
|
|
309487
|
+
"-lah",
|
|
309488
|
+
"-alh",
|
|
309489
|
+
"-lrt",
|
|
309490
|
+
"-ltr",
|
|
309491
|
+
"-rn",
|
|
309492
|
+
"-nr",
|
|
309493
|
+
"-ri",
|
|
309494
|
+
"-ir",
|
|
309495
|
+
"-rni",
|
|
309496
|
+
"-rin",
|
|
309497
|
+
"-ni",
|
|
309498
|
+
"-in",
|
|
309499
|
+
"-ef",
|
|
309500
|
+
"-aux"
|
|
309501
|
+
]);
|
|
309502
|
+
var SAFE_LONG_FLAGS = /* @__PURE__ */ new Set([
|
|
309503
|
+
"--all",
|
|
309504
|
+
"--oneline",
|
|
309505
|
+
"--stat",
|
|
309506
|
+
"--numstat",
|
|
309507
|
+
"--shortstat",
|
|
309508
|
+
"--name-only",
|
|
309509
|
+
"--name-status",
|
|
309510
|
+
"--graph",
|
|
309511
|
+
"--decorate",
|
|
309512
|
+
"--no-pager",
|
|
309513
|
+
"--color",
|
|
309514
|
+
"--no-color",
|
|
309515
|
+
"--grep",
|
|
309516
|
+
"--author",
|
|
309517
|
+
"--since",
|
|
309518
|
+
"--until",
|
|
309519
|
+
"--before",
|
|
309520
|
+
"--after",
|
|
309521
|
+
"--pretty",
|
|
309522
|
+
"--format",
|
|
309523
|
+
"--abbrev-commit",
|
|
309524
|
+
"--max-count",
|
|
309525
|
+
"--cached",
|
|
309526
|
+
"--staged",
|
|
309527
|
+
"--short",
|
|
309528
|
+
"--branch",
|
|
309529
|
+
"--porcelain",
|
|
309530
|
+
"--help",
|
|
309531
|
+
"--version",
|
|
309532
|
+
"--quiet",
|
|
309533
|
+
"--verbose",
|
|
309534
|
+
"--dry-run",
|
|
309535
|
+
"--ignore-case",
|
|
309536
|
+
"--line-number",
|
|
309537
|
+
"--recursive",
|
|
309538
|
+
"--extended-regexp",
|
|
309539
|
+
"--fixed-strings",
|
|
309540
|
+
"--files-with-matches",
|
|
309541
|
+
"--count",
|
|
309542
|
+
"--context",
|
|
309543
|
+
"--before-context",
|
|
309544
|
+
"--after-context"
|
|
309545
|
+
]);
|
|
309546
|
+
var HIGH_RISK_VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
309547
|
+
"-c",
|
|
309548
|
+
"-e",
|
|
309549
|
+
"--eval",
|
|
309550
|
+
"--exec",
|
|
309551
|
+
"-exec",
|
|
309552
|
+
"-execdir",
|
|
309553
|
+
"--run_under",
|
|
309554
|
+
"--test_strategy",
|
|
309555
|
+
"--test_arg",
|
|
309556
|
+
"--test_env",
|
|
309557
|
+
"--action_env",
|
|
309558
|
+
"--jvmopt",
|
|
309559
|
+
"--host_jvm_args",
|
|
309560
|
+
"--wrapper_script_flag",
|
|
309561
|
+
"--upload-pack",
|
|
309562
|
+
"--receive-pack",
|
|
309563
|
+
"--require",
|
|
309564
|
+
"--import",
|
|
309565
|
+
"--loader"
|
|
309566
|
+
]);
|
|
309567
|
+
var FILE_MODE_STRING_REGEX = /^[dcbpsl-][rwxstST-]{9}[+@.]?$/i;
|
|
309568
|
+
var BARE_DASHES_REGEX = /^--+$/;
|
|
309569
|
+
var BARE_SHELL_VARIABLE_REGEX = /^\$(?:[a-zA-Z_][a-zA-Z0-9_]*|\{[a-zA-Z_][a-zA-Z0-9_]*\})$/;
|
|
309570
|
+
function isHighRiskPatternToken(token2) {
|
|
309571
|
+
return token2.startsWith("http://") || token2.startsWith("https://") || token2.startsWith("/") || token2.startsWith("\\") || token2.startsWith("./") || token2.startsWith("../") || /^[a-zA-Z]:[\\/]/.test(token2) || /\.(sh|bash|zsh|ps1|bat|cmd|exe)$/i.test(token2);
|
|
309572
|
+
}
|
|
309573
|
+
function hasUntrustedSubstring(untrustedContext, value) {
|
|
309574
|
+
const normalized2 = value.toLowerCase().replace(/\\/g, "/");
|
|
309575
|
+
return untrustedContext.untrustedTexts.some((text) => text.toLowerCase().includes(normalized2));
|
|
309576
|
+
}
|
|
309441
309577
|
function extractUntrustedContext(history) {
|
|
309442
309578
|
const untrustedTexts = [];
|
|
309443
309579
|
const untrustedTokens = /* @__PURE__ */ new Set();
|
|
@@ -309468,35 +309604,19 @@ function extractUntrustedContext(history) {
|
|
|
309468
309604
|
if (untrustedContent) {
|
|
309469
309605
|
const normalizedContent = untrustedContent.replace(/\\/g, "/");
|
|
309470
309606
|
untrustedTexts.push(normalizedContent);
|
|
309471
|
-
const
|
|
309607
|
+
const contentWithoutShellMetadata = normalizedContent.replace(/^\s*Output:\s*(\(empty\))?\s*/i, "").replace(/\n(?:Exit Code|Signal|Background PIDs|Process Group PGID):.*$/gim, "");
|
|
309608
|
+
const tokens = contentWithoutShellMetadata.split(/[\s,`"';()|&[\]{}<>]+/).map((t2) => t2.trim()).filter((t2) => t2.length > 1).filter((t2) => !BARE_DASHES_REGEX.test(t2)).filter((t2) => !FILE_MODE_STRING_REGEX.test(t2)).filter((t2) => !BENIGN_SUBCOMMAND_TOKENS.has(t2.toLowerCase())).filter((t2) => !SAFE_SHORT_FLAGS.has(t2)).filter((t2) => !SAFE_LONG_FLAGS.has(t2.toLowerCase()));
|
|
309472
309609
|
for (const token2 of tokens) {
|
|
309473
|
-
const
|
|
309474
|
-
|
|
309475
|
-
|
|
309476
|
-
|
|
309477
|
-
|
|
309478
|
-
untrustedTokens.add(lowerToken.substring(1));
|
|
309479
|
-
}
|
|
309480
|
-
if (lowerToken.includes("=")) {
|
|
309481
|
-
const eqParts = lowerToken.split("=");
|
|
309610
|
+
const isShortFlag = token2.startsWith("-") && !token2.startsWith("--");
|
|
309611
|
+
const tokenToStore = isShortFlag ? token2 : token2.toLowerCase();
|
|
309612
|
+
untrustedTokens.add(tokenToStore);
|
|
309613
|
+
if (token2.includes("=")) {
|
|
309614
|
+
const eqParts = token2.split("=");
|
|
309482
309615
|
for (const eqPart of eqParts) {
|
|
309483
309616
|
const trimmedPart = eqPart.trim();
|
|
309484
|
-
if (trimmedPart.length > 1) {
|
|
309485
|
-
|
|
309486
|
-
|
|
309487
|
-
untrustedTokens.add(trimmedPart.substring(2));
|
|
309488
|
-
} else if (trimmedPart.startsWith("-")) {
|
|
309489
|
-
untrustedTokens.add(trimmedPart.substring(1));
|
|
309490
|
-
}
|
|
309491
|
-
}
|
|
309492
|
-
}
|
|
309493
|
-
}
|
|
309494
|
-
if (lowerToken.includes("/")) {
|
|
309495
|
-
const pathParts = lowerToken.split("/");
|
|
309496
|
-
for (const part2 of pathParts) {
|
|
309497
|
-
const trimmedPart = part2.trim();
|
|
309498
|
-
if (trimmedPart.length > 1) {
|
|
309499
|
-
untrustedTokens.add(trimmedPart);
|
|
309617
|
+
if (trimmedPart.length > 1 && !BARE_DASHES_REGEX.test(trimmedPart) && !SAFE_SHORT_FLAGS.has(trimmedPart) && !SAFE_LONG_FLAGS.has(trimmedPart.toLowerCase())) {
|
|
309618
|
+
const isPartShortFlag = trimmedPart.startsWith("-") && !trimmedPart.startsWith("--");
|
|
309619
|
+
untrustedTokens.add(isPartShortFlag ? trimmedPart : trimmedPart.toLowerCase());
|
|
309500
309620
|
}
|
|
309501
309621
|
}
|
|
309502
309622
|
}
|
|
@@ -309515,7 +309635,7 @@ function findUntrustedFlags(command, untrustedContext) {
|
|
|
309515
309635
|
let parsed;
|
|
309516
309636
|
try {
|
|
309517
309637
|
const normalizedCommand = process.platform === "win32" ? command.replace(/\\(?!")/g, "/") : command;
|
|
309518
|
-
parsed = (0, import_shell_quote5.parse)(normalizedCommand);
|
|
309638
|
+
parsed = (0, import_shell_quote5.parse)(normalizedCommand, (key) => `$${key}`);
|
|
309519
309639
|
} catch {
|
|
309520
309640
|
parsed = command.trim().split(/\s+/);
|
|
309521
309641
|
}
|
|
@@ -309538,45 +309658,57 @@ function findUntrustedFlags(command, untrustedContext) {
|
|
|
309538
309658
|
const token2 = rawTokens[i3];
|
|
309539
309659
|
const lowerToken = token2.toLowerCase();
|
|
309540
309660
|
if (token2.startsWith("-")) {
|
|
309661
|
+
if (/^--?$/.test(token2)) {
|
|
309662
|
+
continue;
|
|
309663
|
+
}
|
|
309664
|
+
let rawFlagName = token2;
|
|
309541
309665
|
let flagToCheck = lowerToken;
|
|
309666
|
+
let rawValToCheck;
|
|
309542
309667
|
let valToCheck;
|
|
309543
309668
|
if (token2.includes("=")) {
|
|
309544
|
-
const eqIdx =
|
|
309669
|
+
const eqIdx = token2.indexOf("=");
|
|
309670
|
+
rawFlagName = token2.substring(0, eqIdx);
|
|
309545
309671
|
flagToCheck = lowerToken.substring(0, eqIdx);
|
|
309672
|
+
rawValToCheck = token2.substring(eqIdx + 1);
|
|
309546
309673
|
valToCheck = lowerToken.substring(eqIdx + 1);
|
|
309547
309674
|
}
|
|
309548
|
-
|
|
309675
|
+
const isSafeFlag = SAFE_SHORT_FLAGS.has(rawFlagName) || SAFE_LONG_FLAGS.has(flagToCheck);
|
|
309676
|
+
const isHighRiskFlag = HIGH_RISK_VALUE_FLAGS.has(rawFlagName) || rawFlagName.startsWith("--") && HIGH_RISK_VALUE_FLAGS.has(flagToCheck);
|
|
309677
|
+
const isShortFlag = rawFlagName.startsWith("-") && !rawFlagName.startsWith("--");
|
|
309678
|
+
const tokenToLookup = isShortFlag ? rawFlagName : lowerToken;
|
|
309679
|
+
const flagToLookup = isShortFlag ? rawFlagName : flagToCheck;
|
|
309680
|
+
if (!isSafeFlag && (untrustedContext.untrustedTokens.has(tokenToLookup) || untrustedContext.untrustedTokens.has(flagToLookup))) {
|
|
309549
309681
|
detected.add(token2);
|
|
309550
|
-
|
|
309682
|
+
if (token2.includes("=") || !isHighRiskFlag) {
|
|
309683
|
+
continue;
|
|
309684
|
+
}
|
|
309551
309685
|
}
|
|
309552
|
-
if (valToCheck &&
|
|
309553
|
-
|
|
309554
|
-
|
|
309686
|
+
if (valToCheck && rawValToCheck) {
|
|
309687
|
+
const isValUntrusted = untrustedContext.untrustedTokens.has(valToCheck) && (isHighRiskFlag || !isSafeFlag && isHighRiskPatternToken(rawValToCheck));
|
|
309688
|
+
const isHighRiskValSubstring = (!isSafeFlag || isHighRiskFlag) && isHighRiskPatternToken(rawValToCheck) && hasUntrustedSubstring(untrustedContext, valToCheck);
|
|
309689
|
+
if (isValUntrusted || isHighRiskValSubstring) {
|
|
309690
|
+
detected.add(token2);
|
|
309691
|
+
continue;
|
|
309692
|
+
}
|
|
309555
309693
|
}
|
|
309556
|
-
|
|
309557
|
-
|
|
309558
|
-
|
|
309559
|
-
|
|
309694
|
+
if (!token2.includes("=") && isHighRiskFlag) {
|
|
309695
|
+
const nextToken = rawTokens[i3 + 1];
|
|
309696
|
+
if (nextToken && !nextToken.startsWith("-") && !BARE_SHELL_VARIABLE_REGEX.test(nextToken) && !BENIGN_SUBCOMMAND_TOKENS.has(nextToken.toLowerCase()) && (untrustedContext.untrustedTokens.has(nextToken.toLowerCase()) || isHighRiskPatternToken(nextToken) && hasUntrustedSubstring(untrustedContext, nextToken))) {
|
|
309697
|
+
detected.add(token2);
|
|
309698
|
+
detected.add(nextToken);
|
|
309699
|
+
}
|
|
309560
309700
|
}
|
|
309561
309701
|
} else {
|
|
309562
|
-
if (token2.length <= 1) {
|
|
309702
|
+
if (token2.length <= 1 || BARE_SHELL_VARIABLE_REGEX.test(token2)) {
|
|
309563
309703
|
continue;
|
|
309564
309704
|
}
|
|
309565
|
-
|
|
309566
|
-
const isHighRiskPattern = token2.startsWith("http://") || token2.startsWith("https://") || token2.startsWith("/") || token2.startsWith("\\") || /^[a-zA-Z]:[\\/]/.test(token2);
|
|
309567
|
-
if (isSensitiveWord) {
|
|
309705
|
+
if (isHighRiskPatternToken(token2)) {
|
|
309568
309706
|
if (untrustedContext.untrustedTokens.has(lowerToken)) {
|
|
309569
309707
|
detected.add(token2);
|
|
309570
309708
|
continue;
|
|
309571
309709
|
}
|
|
309572
|
-
if (
|
|
309573
|
-
|
|
309574
|
-
for (const text of untrustedContext.untrustedTexts) {
|
|
309575
|
-
if (text.toLowerCase().includes(normalizedLowerToken)) {
|
|
309576
|
-
detected.add(token2);
|
|
309577
|
-
break;
|
|
309578
|
-
}
|
|
309579
|
-
}
|
|
309710
|
+
if (hasUntrustedSubstring(untrustedContext, lowerToken)) {
|
|
309711
|
+
detected.add(token2);
|
|
309580
309712
|
}
|
|
309581
309713
|
}
|
|
309582
309714
|
}
|
|
@@ -332836,6 +332968,9 @@ function scrubPart(part) {
|
|
|
332836
332968
|
if (part.functionResponse.id) {
|
|
332837
332969
|
scrubbedResp["id"] = part.functionResponse.id;
|
|
332838
332970
|
}
|
|
332971
|
+
if ("parts" in part.functionResponse && Array.isArray(part.functionResponse.parts)) {
|
|
332972
|
+
scrubbedResp["parts"] = part.functionResponse.parts.map(scrubPart);
|
|
332973
|
+
}
|
|
332839
332974
|
scrubbed["functionResponse"] = scrubbedResp;
|
|
332840
332975
|
}
|
|
332841
332976
|
if ("fileData" in part) {
|
|
@@ -332866,6 +333001,8 @@ var MID_STREAM_RETRY_OPTIONS = {
|
|
|
332866
333001
|
};
|
|
332867
333002
|
var SYNTHETIC_THOUGHT_SIGNATURE2 = "skip_thought_signature_validator";
|
|
332868
333003
|
var INTERRUPTED_RESPONSE_PLACEHOLDER = "[The previous response was interrupted before it completed.]";
|
|
333004
|
+
var INTERRUPTED_TOOL_RESPONSE_ERROR = "Response was lost or interrupted.";
|
|
333005
|
+
var CONTINUE_PROMPT_TEXT = "Please continue.";
|
|
332869
333006
|
function isIndexedPart(part) {
|
|
332870
333007
|
return "callIndex" in part;
|
|
332871
333008
|
}
|
|
@@ -333107,6 +333244,7 @@ var GeminiChat = class {
|
|
|
333107
333244
|
let userContent = createUserContent(message);
|
|
333108
333245
|
const isOriginalFunctionResponse = isFunctionResponse(userContent);
|
|
333109
333246
|
if (!isOriginalFunctionResponse) {
|
|
333247
|
+
this.closeUnansweredToolCallsTurn();
|
|
333110
333248
|
this.closeUnansweredToolResponseTurn();
|
|
333111
333249
|
}
|
|
333112
333250
|
const { model } = this.context.config.modelConfigService.getResolvedConfig(modelConfigKey);
|
|
@@ -333133,7 +333271,7 @@ var GeminiChat = class {
|
|
|
333133
333271
|
} else {
|
|
333134
333272
|
const history = this.agentHistory.get();
|
|
333135
333273
|
const lastTurn = history[history.length - 1];
|
|
333136
|
-
if (!lastTurn || partListUnionToString(lastTurn.content.parts || []) !== userMessageContent) {
|
|
333274
|
+
if (!lastTurn || lastTurn.content.role !== "user" || partListUnionToString(lastTurn.content.parts || []) !== userMessageContent) {
|
|
333137
333275
|
const id = this.chatRecordingService.recordMessage({
|
|
333138
333276
|
model,
|
|
333139
333277
|
type: "user",
|
|
@@ -333181,11 +333319,12 @@ var GeminiChat = class {
|
|
|
333181
333319
|
} else {
|
|
333182
333320
|
const history = this.agentHistory.get();
|
|
333183
333321
|
const lastTurn = history[history.length - 1];
|
|
333184
|
-
if (!lastTurn || partListUnionToString(lastTurn.content.parts || []) !== partListUnionToString(userContent.parts || [])) {
|
|
333322
|
+
if (!lastTurn || lastTurn.content.role !== "user" || partListUnionToString(lastTurn.content.parts || []) !== partListUnionToString(userContent.parts || [])) {
|
|
333185
333323
|
this.agentHistory.push({ id, content: userContent });
|
|
333186
333324
|
}
|
|
333187
333325
|
}
|
|
333188
333326
|
}
|
|
333327
|
+
this.replaceEmptyTrailingUserTurn();
|
|
333189
333328
|
const requestHistory = this.getHistoryTurns(true);
|
|
333190
333329
|
const streamWithRetries = async function* () {
|
|
333191
333330
|
let isSuccess = false;
|
|
@@ -333297,23 +333436,77 @@ var GeminiChat = class {
|
|
|
333297
333436
|
return streamWithRetries.call(this);
|
|
333298
333437
|
}
|
|
333299
333438
|
/**
|
|
333300
|
-
* Appends a
|
|
333301
|
-
*
|
|
333439
|
+
* Appends a dedicated synthetic user turn with matching functionResponse
|
|
333440
|
+
* parts when history ends with an unclosed model functionCall. The
|
|
333441
|
+
* subsequent user prompt is then recorded as a clean turn of its own (after
|
|
333442
|
+
* `closeUnansweredToolResponseTurn` adds the closing model turn).
|
|
333302
333443
|
*/
|
|
333303
|
-
|
|
333444
|
+
closeUnansweredToolCallsTurn() {
|
|
333304
333445
|
const turns = this.agentHistory.get();
|
|
333305
333446
|
const last2 = turns[turns.length - 1];
|
|
333306
|
-
if (last2?.content.role !== "
|
|
333447
|
+
if (last2?.content.role !== "model") {
|
|
333307
333448
|
return;
|
|
333308
333449
|
}
|
|
333450
|
+
const missingResponses = buildInterruptedToolResponseParts(last2.content.parts ?? []);
|
|
333451
|
+
if (missingResponses.length === 0) {
|
|
333452
|
+
return;
|
|
333453
|
+
}
|
|
333454
|
+
const id = this.chatRecordingService.recordSyntheticMessage("user", missingResponses);
|
|
333309
333455
|
this.agentHistory.push({
|
|
333310
|
-
id
|
|
333311
|
-
content: {
|
|
333312
|
-
role: "model",
|
|
333313
|
-
parts: [{ text: INTERRUPTED_RESPONSE_PLACEHOLDER }]
|
|
333314
|
-
}
|
|
333456
|
+
id,
|
|
333457
|
+
content: { role: "user", parts: missingResponses }
|
|
333315
333458
|
});
|
|
333316
333459
|
}
|
|
333460
|
+
/**
|
|
333461
|
+
* Replaces the parts of a trailing user turn that carries no content (e.g.
|
|
333462
|
+
* only empty text parts) with a continuation prompt, keeping the in-memory
|
|
333463
|
+
* history and the session log in sync. Runs once per send so that the
|
|
333464
|
+
* persisted history never keeps an empty user turn between model turns.
|
|
333465
|
+
*/
|
|
333466
|
+
replaceEmptyTrailingUserTurn() {
|
|
333467
|
+
const turns = this.agentHistory.get();
|
|
333468
|
+
const last2 = turns[turns.length - 1];
|
|
333469
|
+
if (last2?.content.role !== "user" || hasNonEmptyParts(last2.content)) {
|
|
333470
|
+
return;
|
|
333471
|
+
}
|
|
333472
|
+
this.agentHistory.set([
|
|
333473
|
+
...turns.slice(0, -1),
|
|
333474
|
+
{
|
|
333475
|
+
id: last2.id,
|
|
333476
|
+
content: { ...last2.content, parts: [{ text: CONTINUE_PROMPT_TEXT }] }
|
|
333477
|
+
}
|
|
333478
|
+
]);
|
|
333479
|
+
this.chatRecordingService.updateMessagesFromHistory(this.agentHistory.get());
|
|
333480
|
+
}
|
|
333481
|
+
/**
|
|
333482
|
+
* Appends a closing model turn when history ends with an unanswered tool
|
|
333483
|
+
* response, so the next user message stays a turn of its own.
|
|
333484
|
+
*/
|
|
333485
|
+
closeUnansweredToolResponseTurn() {
|
|
333486
|
+
const turns = this.agentHistory.get();
|
|
333487
|
+
let targetTurn = turns[turns.length - 1];
|
|
333488
|
+
let hadEmptyTrailingModelTurn = false;
|
|
333489
|
+
if (targetTurn?.content.role === "model" && (!targetTurn.content.parts || targetTurn.content.parts.length === 0)) {
|
|
333490
|
+
hadEmptyTrailingModelTurn = true;
|
|
333491
|
+
targetTurn = turns[turns.length - 2];
|
|
333492
|
+
}
|
|
333493
|
+
if (targetTurn?.content.role !== "user" || !targetTurn.content.parts?.some((part) => !!part.functionResponse)) {
|
|
333494
|
+
return;
|
|
333495
|
+
}
|
|
333496
|
+
if (hadEmptyTrailingModelTurn) {
|
|
333497
|
+
const lastTurn = turns[turns.length - 1];
|
|
333498
|
+
lastTurn.content.parts = [{ text: INTERRUPTED_RESPONSE_PLACEHOLDER }];
|
|
333499
|
+
this.chatRecordingService.updateMessagesFromHistory(turns);
|
|
333500
|
+
} else {
|
|
333501
|
+
this.agentHistory.push({
|
|
333502
|
+
id: randomUUID6(),
|
|
333503
|
+
content: {
|
|
333504
|
+
role: "model",
|
|
333505
|
+
parts: [{ text: INTERRUPTED_RESPONSE_PLACEHOLDER }]
|
|
333506
|
+
}
|
|
333507
|
+
});
|
|
333508
|
+
}
|
|
333509
|
+
}
|
|
333317
333510
|
extractBinaryInjections(parts2) {
|
|
333318
333511
|
const binaryParts = [];
|
|
333319
333512
|
if (parts2) {
|
|
@@ -333430,10 +333623,14 @@ var GeminiChat = class {
|
|
|
333430
333623
|
if (this.onModelChanged) {
|
|
333431
333624
|
this.tools = await this.onModelChanged(modelToUse);
|
|
333432
333625
|
}
|
|
333626
|
+
const normalizedContents = ensureTerminalUserTurn(contentsToUse);
|
|
333627
|
+
if (normalizedContents !== contentsToUse) {
|
|
333628
|
+
debugLogger.warn("Final contents do not end with a valid user turn. Normalizing contents to satisfy Gemini API invariant.");
|
|
333629
|
+
}
|
|
333433
333630
|
lastModelToUse = modelToUse;
|
|
333434
333631
|
lastConfig = config2;
|
|
333435
|
-
lastContentsToUse =
|
|
333436
|
-
const finalContents = stripToolCallIdPrefixes(
|
|
333632
|
+
lastContentsToUse = normalizedContents;
|
|
333633
|
+
const finalContents = stripToolCallIdPrefixes(normalizedContents);
|
|
333437
333634
|
return this.context.config.getContentGenerator().generateContentStream({
|
|
333438
333635
|
model: modelToUse,
|
|
333439
333636
|
contents: finalContents,
|
|
@@ -333531,6 +333728,25 @@ var GeminiChat = class {
|
|
|
333531
333728
|
}
|
|
333532
333729
|
ensureStableToolIds(this.agentHistory.get());
|
|
333533
333730
|
}
|
|
333731
|
+
/**
|
|
333732
|
+
* Removes the trailing model turn when it holds function calls that were
|
|
333733
|
+
* never answered (e.g. every call in the batch was declined). Earlier
|
|
333734
|
+
* completed tool rounds and the originating user prompt are kept, and the
|
|
333735
|
+
* durable IDs of the remaining turns are preserved.
|
|
333736
|
+
*
|
|
333737
|
+
* @returns true when a turn was removed.
|
|
333738
|
+
*/
|
|
333739
|
+
discardTrailingUnansweredToolCallTurn() {
|
|
333740
|
+
const turns = this.agentHistory.get();
|
|
333741
|
+
const last2 = turns[turns.length - 1];
|
|
333742
|
+
if (last2?.content.role !== "model" || !last2.content.parts?.some((part) => !!part.functionCall)) {
|
|
333743
|
+
return false;
|
|
333744
|
+
}
|
|
333745
|
+
this.agentHistory.rollback(turns.length - 1);
|
|
333746
|
+
this.lastPromptTokenCount = estimateTokenCountSync(this.agentHistory.flatMap((c4) => c4.content.parts || []));
|
|
333747
|
+
this.chatRecordingService.updateMessagesFromHistory(this.agentHistory.get());
|
|
333748
|
+
return true;
|
|
333749
|
+
}
|
|
333534
333750
|
setHistory(history) {
|
|
333535
333751
|
const wrappedHistory = history.map((item) => {
|
|
333536
333752
|
if ("id" in item && "content" in item) {
|
|
@@ -333884,8 +334100,41 @@ function isSchemaDepthError(errorMessage) {
|
|
|
333884
334100
|
function isInvalidArgumentError(errorMessage) {
|
|
333885
334101
|
return errorMessage.includes("Request contains an invalid argument");
|
|
333886
334102
|
}
|
|
334103
|
+
function isEmptyTextPart(part) {
|
|
334104
|
+
if (part.text !== "") {
|
|
334105
|
+
return false;
|
|
334106
|
+
}
|
|
334107
|
+
return !Object.keys(part).some((key) => key !== "text" && key !== "thought" && key !== "callIndex");
|
|
334108
|
+
}
|
|
334109
|
+
function hasNonEmptyParts(content) {
|
|
334110
|
+
return (content.parts ?? []).some((part) => !isEmptyTextPart(part));
|
|
334111
|
+
}
|
|
334112
|
+
function buildInterruptedToolResponseParts(parts2) {
|
|
334113
|
+
return parts2.filter((part) => !!part?.functionCall).map((part) => ({
|
|
334114
|
+
functionResponse: {
|
|
334115
|
+
name: part.functionCall.name?.trim() || "generic_tool",
|
|
334116
|
+
id: part.functionCall.id,
|
|
334117
|
+
response: { error: INTERRUPTED_TOOL_RESPONSE_ERROR }
|
|
334118
|
+
}
|
|
334119
|
+
}));
|
|
334120
|
+
}
|
|
334121
|
+
function ensureTerminalUserTurn(contents) {
|
|
334122
|
+
const last2 = contents.at(-1);
|
|
334123
|
+
if (last2?.role === "user" && hasNonEmptyParts(last2)) {
|
|
334124
|
+
return contents;
|
|
334125
|
+
}
|
|
334126
|
+
if (last2?.role === "user") {
|
|
334127
|
+
return [
|
|
334128
|
+
...contents.slice(0, -1),
|
|
334129
|
+
{ ...last2, parts: [{ text: CONTINUE_PROMPT_TEXT }] }
|
|
334130
|
+
];
|
|
334131
|
+
}
|
|
334132
|
+
const missingResponses = buildInterruptedToolResponseParts(last2?.parts ?? []);
|
|
334133
|
+
const parts2 = missingResponses.length > 0 ? missingResponses : [{ text: CONTINUE_PROMPT_TEXT }];
|
|
334134
|
+
return [...contents, { role: "user", parts: parts2 }];
|
|
334135
|
+
}
|
|
333887
334136
|
function stripToolCallIdPrefixes(contents) {
|
|
333888
|
-
|
|
334137
|
+
const stripped = contents.map((content) => {
|
|
333889
334138
|
const parts2 = (content.parts || []).map((part) => {
|
|
333890
334139
|
const newPart = { ...part };
|
|
333891
334140
|
if (newPart.functionCall) {
|
|
@@ -333893,8 +334142,7 @@ function stripToolCallIdPrefixes(contents) {
|
|
|
333893
334142
|
const name3 = fc.name?.trim() || "generic_tool";
|
|
333894
334143
|
if (fc.id && fc.id.startsWith(`${name3}__`)) {
|
|
333895
334144
|
newPart.functionCall = {
|
|
333896
|
-
|
|
333897
|
-
args: fc.args,
|
|
334145
|
+
...fc,
|
|
333898
334146
|
id: fc.id.substring(name3.length + 2)
|
|
333899
334147
|
};
|
|
333900
334148
|
}
|
|
@@ -333904,8 +334152,9 @@ function stripToolCallIdPrefixes(contents) {
|
|
|
333904
334152
|
const name3 = fr.name?.trim() || "generic_tool";
|
|
333905
334153
|
if (fr.id && fr.id.startsWith(`${name3}__`)) {
|
|
333906
334154
|
newPart.functionResponse = {
|
|
333907
|
-
|
|
333908
|
-
|
|
334155
|
+
// History parts are plain JSON objects, not class instances.
|
|
334156
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-spread
|
|
334157
|
+
...fr,
|
|
333909
334158
|
id: fr.id.substring(name3.length + 2)
|
|
333910
334159
|
};
|
|
333911
334160
|
}
|
|
@@ -333915,18 +334164,30 @@ function stripToolCallIdPrefixes(contents) {
|
|
|
333915
334164
|
delete newPart.text;
|
|
333916
334165
|
}
|
|
333917
334166
|
return newPart;
|
|
333918
|
-
}).filter((part) =>
|
|
333919
|
-
const hasOtherKeys = Object.keys(part).some((key) => key !== "text" && key !== "thought" && key !== "callIndex");
|
|
333920
|
-
if (part.text !== void 0 && part.text === "" && !hasOtherKeys) {
|
|
333921
|
-
return false;
|
|
333922
|
-
}
|
|
333923
|
-
return true;
|
|
333924
|
-
});
|
|
334167
|
+
}).filter((part) => !isEmptyTextPart(part));
|
|
333925
334168
|
return {
|
|
333926
334169
|
...content,
|
|
333927
334170
|
parts: parts2
|
|
333928
334171
|
};
|
|
333929
|
-
});
|
|
334172
|
+
}).filter((content) => content.parts.length > 0);
|
|
334173
|
+
return coalesceConsecutiveContents(stripped);
|
|
334174
|
+
}
|
|
334175
|
+
function coalesceConsecutiveContents(contents) {
|
|
334176
|
+
const result2 = [];
|
|
334177
|
+
for (const item of contents) {
|
|
334178
|
+
const lastIdx = result2.length - 1;
|
|
334179
|
+
const last2 = result2[lastIdx];
|
|
334180
|
+
if (last2 && last2.role && last2.role === item.role) {
|
|
334181
|
+
const hasParts = last2.parts || item.parts;
|
|
334182
|
+
result2[lastIdx] = {
|
|
334183
|
+
...last2,
|
|
334184
|
+
parts: hasParts ? [...last2.parts || [], ...item.parts || []] : void 0
|
|
334185
|
+
};
|
|
334186
|
+
} else {
|
|
334187
|
+
result2.push({ ...item });
|
|
334188
|
+
}
|
|
334189
|
+
}
|
|
334190
|
+
return result2;
|
|
333930
334191
|
}
|
|
333931
334192
|
function coalesceConsecutiveRoles(history) {
|
|
333932
334193
|
const result2 = [];
|
|
@@ -341235,7 +341496,13 @@ var OAuthUtils = class {
|
|
|
341235
341496
|
issuer: metadata2.issuer,
|
|
341236
341497
|
tokenUrl: metadata2.token_endpoint,
|
|
341237
341498
|
scopes: metadata2.scopes_supported || [],
|
|
341238
|
-
registrationUrl: metadata2.registration_endpoint
|
|
341499
|
+
registrationUrl: metadata2.registration_endpoint,
|
|
341500
|
+
// RFC 9207 Section 3: the flag defaults to false when omitted. Discovered
|
|
341501
|
+
// configurations therefore always carry an explicit boolean, which lets
|
|
341502
|
+
// the callback policy distinguish them from an explicitly configured issuer.
|
|
341503
|
+
// Only a literal boolean `true` enables the flag, so loosely typed values
|
|
341504
|
+
// returned by some servers (e.g. "false" or "0") are not coerced to true.
|
|
341505
|
+
authorizationResponseIssParameterSupported: metadata2.authorization_response_iss_parameter_supported === true
|
|
341239
341506
|
};
|
|
341240
341507
|
}
|
|
341241
341508
|
/**
|
|
@@ -341559,7 +341826,7 @@ var A2AAuthProviderFactory = class _A2AAuthProviderFactory {
|
|
|
341559
341826
|
return provider;
|
|
341560
341827
|
}
|
|
341561
341828
|
case "oauth2": {
|
|
341562
|
-
const { OAuth2AuthProvider } = await import("./oauth2-provider-
|
|
341829
|
+
const { OAuth2AuthProvider } = await import("./oauth2-provider-I3CU23H3.js");
|
|
341563
341830
|
const provider = new OAuth2AuthProvider(authConfig, options.agentName ?? "unknown", agentCard, options.agentCardUrl);
|
|
341564
341831
|
await provider.initialize();
|
|
341565
341832
|
return provider;
|
|
@@ -347707,6 +347974,21 @@ var GeminiClient = class {
|
|
|
347707
347974
|
this.updateTelemetryTokenCount();
|
|
347708
347975
|
this.forceFullIdeContext = true;
|
|
347709
347976
|
}
|
|
347977
|
+
/**
|
|
347978
|
+
* Removes the trailing model turn when it only holds unanswered function
|
|
347979
|
+
* calls. See {@link GeminiChat.discardTrailingUnansweredToolCallTurn}.
|
|
347980
|
+
* Returns false without side effects when the chat is not initialized.
|
|
347981
|
+
*/
|
|
347982
|
+
discardTrailingUnansweredToolCallTurn() {
|
|
347983
|
+
if (!this.isInitialized()) {
|
|
347984
|
+
return false;
|
|
347985
|
+
}
|
|
347986
|
+
const removed = this.getChat().discardTrailingUnansweredToolCallTurn();
|
|
347987
|
+
if (removed) {
|
|
347988
|
+
this.updateTelemetryTokenCount();
|
|
347989
|
+
}
|
|
347990
|
+
return removed;
|
|
347991
|
+
}
|
|
347710
347992
|
lastUsedModelId;
|
|
347711
347993
|
async setTools(modelId) {
|
|
347712
347994
|
if (!this.chat) {
|
|
@@ -363984,7 +364266,7 @@ var PolicyEngine = class {
|
|
|
363984
364266
|
}
|
|
363985
364267
|
return decision;
|
|
363986
364268
|
}
|
|
363987
|
-
async checkShellCommand(toolName, command, ruleDecision, serverName, dir_path, allowRedirection, rule, toolAnnotations, subagent) {
|
|
364269
|
+
async checkShellCommand(toolName, command, ruleDecision, serverName, dir_path, allowRedirection, rule, toolAnnotations, subagent, hasTopLevelHeuristicDowngrade = false) {
|
|
363988
364270
|
if (!command) {
|
|
363989
364271
|
return {
|
|
363990
364272
|
decision: ruleDecision,
|
|
@@ -364020,13 +364302,17 @@ var PolicyEngine = class {
|
|
|
364020
364302
|
}
|
|
364021
364303
|
let aggregateDecision = ruleDecision;
|
|
364022
364304
|
let responsibleRule = rule && ruleDecision === rule.decision ? rule : void 0;
|
|
364023
|
-
|
|
364305
|
+
const hasTopLevelRedirectionDowngrade = this.shouldDowngradeForRedirection(command, allowRedirection, rule);
|
|
364306
|
+
if (hasTopLevelRedirectionDowngrade) {
|
|
364024
364307
|
if (aggregateDecision === PolicyDecision.ALLOW) {
|
|
364025
364308
|
debugLogger.debug(`[PolicyEngine.check] Downgrading ALLOW to ASK_USER for redirected command: ${command}`);
|
|
364026
364309
|
aggregateDecision = PolicyDecision.ASK_USER;
|
|
364027
364310
|
responsibleRule = void 0;
|
|
364028
364311
|
}
|
|
364029
364312
|
}
|
|
364313
|
+
let evaluatedSubCommands = 0;
|
|
364314
|
+
let allSubCommandsExplicitlyAllowed = true;
|
|
364315
|
+
let lastAllowedSubRule;
|
|
364030
364316
|
for (const detail of subCommands) {
|
|
364031
364317
|
if (REDIRECTION_NAMES.has(detail.name)) {
|
|
364032
364318
|
continue;
|
|
@@ -364035,23 +364321,31 @@ var PolicyEngine = class {
|
|
|
364035
364321
|
const isAtomic = subCmd === command || detail.startIndex === 0 && detail.text.length === command.length;
|
|
364036
364322
|
const stripped = stripShellWrapper(subCmd);
|
|
364037
364323
|
if (stripped !== subCmd) {
|
|
364324
|
+
evaluatedSubCommands++;
|
|
364038
364325
|
const wrapperResult = await this.check({ name: toolName, args: { command: stripped, dir_path } }, serverName, toolAnnotations, subagent, true);
|
|
364039
364326
|
if (wrapperResult.decision === PolicyDecision.DENY)
|
|
364040
364327
|
return wrapperResult;
|
|
364041
364328
|
if (wrapperResult.decision === PolicyDecision.ASK_USER) {
|
|
364329
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
364042
364330
|
if (aggregateDecision === PolicyDecision.ALLOW) {
|
|
364043
364331
|
responsibleRule = wrapperResult.rule;
|
|
364044
364332
|
} else {
|
|
364045
364333
|
responsibleRule ??= wrapperResult.rule;
|
|
364046
364334
|
}
|
|
364047
364335
|
aggregateDecision = PolicyDecision.ASK_USER;
|
|
364336
|
+
} else if (wrapperResult.decision === PolicyDecision.ALLOW && wrapperResult.rule?.decision === PolicyDecision.ALLOW && Boolean(wrapperResult.rule?.argsPattern)) {
|
|
364337
|
+
lastAllowedSubRule = wrapperResult.rule;
|
|
364338
|
+
} else {
|
|
364339
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
364048
364340
|
}
|
|
364049
364341
|
}
|
|
364050
364342
|
if (!isAtomic) {
|
|
364343
|
+
evaluatedSubCommands++;
|
|
364051
364344
|
const subResult = await this.check({ name: toolName, args: { command: subCmd, dir_path } }, serverName, toolAnnotations, subagent, true);
|
|
364052
364345
|
if (subResult.decision === PolicyDecision.DENY)
|
|
364053
364346
|
return subResult;
|
|
364054
364347
|
if (subResult.decision === PolicyDecision.ASK_USER) {
|
|
364348
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
364055
364349
|
if (aggregateDecision === PolicyDecision.ALLOW) {
|
|
364056
364350
|
responsibleRule = subResult.rule;
|
|
364057
364351
|
} else {
|
|
@@ -364060,13 +364354,31 @@ var PolicyEngine = class {
|
|
|
364060
364354
|
aggregateDecision = PolicyDecision.ASK_USER;
|
|
364061
364355
|
}
|
|
364062
364356
|
if (subResult.decision === PolicyDecision.ALLOW && this.shouldDowngradeForRedirection(subCmd, subResult.rule?.allowRedirection ?? allowRedirection, subResult.rule)) {
|
|
364357
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
364063
364358
|
if (aggregateDecision === PolicyDecision.ALLOW) {
|
|
364064
364359
|
aggregateDecision = PolicyDecision.ASK_USER;
|
|
364065
364360
|
responsibleRule = void 0;
|
|
364066
364361
|
}
|
|
364362
|
+
} else if (subResult.decision === PolicyDecision.ALLOW && subResult.rule?.decision === PolicyDecision.ALLOW && Boolean(subResult.rule?.argsPattern)) {
|
|
364363
|
+
lastAllowedSubRule = subResult.rule;
|
|
364364
|
+
} else {
|
|
364365
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
364067
364366
|
}
|
|
364367
|
+
} else if (stripped === subCmd) {
|
|
364368
|
+
allSubCommandsExplicitlyAllowed = false;
|
|
364068
364369
|
}
|
|
364069
364370
|
}
|
|
364371
|
+
const workspace = typeof this.sandboxManager.getWorkspace === "function" ? this.sandboxManager.getWorkspace() : process.cwd();
|
|
364372
|
+
const effectiveCwd = dir_path ? path83.resolve(workspace, dir_path) : workspace;
|
|
364373
|
+
const isOutsideWorkspace = effectiveCwd !== workspace && !isSubpath(workspace, effectiveCwd) && this.approvalMode !== ApprovalMode.YOLO;
|
|
364374
|
+
const parsedObjArgs = (0, import_shell_quote7.parse)(command);
|
|
364375
|
+
const parsedArgs = parsedObjArgs.map(extractStringFromParseEntry);
|
|
364376
|
+
const isUntrustedGit = containsGitCommand(parsedArgs) && !this.isTrustedFolder();
|
|
364377
|
+
const isDangerous = this.approvalMode !== ApprovalMode.YOLO && this.sandboxManager.isDangerousCommand(parsedArgs, effectiveCwd);
|
|
364378
|
+
if (aggregateDecision === PolicyDecision.ASK_USER && !rule?.argsPattern && !hasTopLevelRedirectionDowngrade && !hasTopLevelHeuristicDowngrade && !isOutsideWorkspace && !isUntrustedGit && !isDangerous && evaluatedSubCommands > 0 && allSubCommandsExplicitlyAllowed) {
|
|
364379
|
+
aggregateDecision = PolicyDecision.ALLOW;
|
|
364380
|
+
responsibleRule = lastAllowedSubRule;
|
|
364381
|
+
}
|
|
364070
364382
|
return {
|
|
364071
364383
|
decision: aggregateDecision,
|
|
364072
364384
|
rule: aggregateDecision === ruleDecision ? rule : responsibleRule
|
|
@@ -364124,11 +364436,16 @@ var PolicyEngine = class {
|
|
|
364124
364436
|
if (match2) {
|
|
364125
364437
|
debugLogger.debug(`[PolicyEngine.check] MATCHED rule: toolName=${rule.toolName}, decision=${rule.decision}, priority=${rule.priority}, argsPattern=${rule.argsPattern?.source || "none"}`);
|
|
364126
364438
|
let ruleDecision = rule.decision;
|
|
364439
|
+
let hasTopLevelHeuristicDowngrade = false;
|
|
364127
364440
|
if (!skipHeuristics && isShellCommand && command && !("commandPrefix" in rule) && !rule.argsPattern) {
|
|
364441
|
+
const prevDecision = ruleDecision;
|
|
364128
364442
|
ruleDecision = await this.applyShellHeuristics(command, ruleDecision, shellDirPath);
|
|
364443
|
+
if (prevDecision === PolicyDecision.ALLOW && ruleDecision === PolicyDecision.ASK_USER) {
|
|
364444
|
+
hasTopLevelHeuristicDowngrade = true;
|
|
364445
|
+
}
|
|
364129
364446
|
}
|
|
364130
364447
|
if (isShellCommand && toolName) {
|
|
364131
|
-
const shellResult = await this.checkShellCommand(toolName, command, ruleDecision, serverName, shellDirPath, rule.allowRedirection, rule, toolAnnotations, subagent);
|
|
364448
|
+
const shellResult = await this.checkShellCommand(toolName, command, ruleDecision, serverName, shellDirPath, rule.allowRedirection, rule, toolAnnotations, subagent, hasTopLevelHeuristicDowngrade);
|
|
364132
364449
|
decision = shellResult.decision;
|
|
364133
364450
|
matchedRule = shellResult.rule;
|
|
364134
364451
|
break;
|
|
@@ -364147,10 +364464,15 @@ var PolicyEngine = class {
|
|
|
364147
364464
|
debugLogger.debug(`[PolicyEngine.check] NO MATCH - using default decision: ${this.defaultDecision}`);
|
|
364148
364465
|
if (toolName && SHELL_TOOL_NAMES.includes(toolName)) {
|
|
364149
364466
|
let heuristicDecision = this.defaultDecision;
|
|
364467
|
+
let hasTopLevelHeuristicDowngrade = false;
|
|
364150
364468
|
if (!skipHeuristics && command) {
|
|
364469
|
+
const prevDecision = heuristicDecision;
|
|
364151
364470
|
heuristicDecision = await this.applyShellHeuristics(command, heuristicDecision, shellDirPath);
|
|
364471
|
+
if (prevDecision === PolicyDecision.ALLOW && heuristicDecision === PolicyDecision.ASK_USER) {
|
|
364472
|
+
hasTopLevelHeuristicDowngrade = true;
|
|
364473
|
+
}
|
|
364152
364474
|
}
|
|
364153
|
-
const shellResult = await this.checkShellCommand(toolName, command, heuristicDecision, serverName, shellDirPath, false, void 0, toolAnnotations, subagent);
|
|
364475
|
+
const shellResult = await this.checkShellCommand(toolName, command, heuristicDecision, serverName, shellDirPath, false, void 0, toolAnnotations, subagent, hasTopLevelHeuristicDowngrade);
|
|
364154
364476
|
decision = shellResult.decision;
|
|
364155
364477
|
matchedRule = shellResult.rule;
|
|
364156
364478
|
} else {
|
|
@@ -369889,7 +370211,7 @@ function areIssuersEqual(issuerA, issuerB) {
|
|
|
369889
370211
|
}
|
|
369890
370212
|
return normA === normB;
|
|
369891
370213
|
}
|
|
369892
|
-
function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
370214
|
+
function startCallbackServer(expectedState, port, expectedIssuer, requireIssInResponse) {
|
|
369893
370215
|
let portResolve;
|
|
369894
370216
|
let portReject;
|
|
369895
370217
|
const portPromise = new Promise((resolve29, reject) => {
|
|
@@ -369943,8 +370265,9 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
369943
370265
|
return;
|
|
369944
370266
|
}
|
|
369945
370267
|
if (expectedIssuer) {
|
|
369946
|
-
|
|
369947
|
-
|
|
370268
|
+
const requireIss = requireIssInResponse ?? true;
|
|
370269
|
+
if (requireIss && !iss) {
|
|
370270
|
+
debugLogger.error('OAuth callback rejected: Missing required "iss" parameter for the expected authorization server (RFC 9207).');
|
|
369948
370271
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
369949
370272
|
res.end(`
|
|
369950
370273
|
<html>
|
|
@@ -369959,7 +370282,7 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
369959
370282
|
reject(new Error('Missing "iss" parameter in authorization response per RFC 9207'));
|
|
369960
370283
|
return;
|
|
369961
370284
|
}
|
|
369962
|
-
if (!areIssuersEqual(iss, expectedIssuer)) {
|
|
370285
|
+
if (iss && !areIssuersEqual(iss, expectedIssuer)) {
|
|
369963
370286
|
debugLogger.error("OAuth callback rejected: Issuer mismatch between authorization response and expected authorization server. Possible IdP mix-up attack (RFC 9207).");
|
|
369964
370287
|
res.writeHead(400, { "Content-Type": "text/html" });
|
|
369965
370288
|
res.end(`
|
|
@@ -369975,7 +370298,9 @@ function startCallbackServer(expectedState, port, expectedIssuer) {
|
|
|
369975
370298
|
reject(new Error("Issuer mismatch in authorization response - possible OAuth mix-up attack"));
|
|
369976
370299
|
return;
|
|
369977
370300
|
}
|
|
369978
|
-
|
|
370301
|
+
if (iss) {
|
|
370302
|
+
debugLogger.debug("\u2713 OAuth callback issuer validated successfully.");
|
|
370303
|
+
}
|
|
369979
370304
|
} else if (iss) {
|
|
369980
370305
|
debugLogger.debug('OAuth callback received "iss" parameter (no expected issuer was configured).');
|
|
369981
370306
|
}
|
|
@@ -370379,6 +370704,7 @@ var MCPOAuthProvider = class {
|
|
|
370379
370704
|
issuer: discoveredConfig.issuer,
|
|
370380
370705
|
tokenUrl: discoveredConfig.tokenUrl,
|
|
370381
370706
|
scopes: config2.scopes || discoveredConfig.scopes || [],
|
|
370707
|
+
authorizationResponseIssParameterSupported: config2.authorizationResponseIssParameterSupported ?? discoveredConfig.authorizationResponseIssParameterSupported,
|
|
370382
370708
|
// Preserve existing client credentials
|
|
370383
370709
|
clientId: config2.clientId,
|
|
370384
370710
|
clientSecret: config2.clientSecret
|
|
@@ -370402,6 +370728,7 @@ var MCPOAuthProvider = class {
|
|
|
370402
370728
|
issuer: discoveredConfig.issuer,
|
|
370403
370729
|
scopes: config2.scopes || discoveredConfig.scopes || [],
|
|
370404
370730
|
registrationUrl: discoveredConfig.registrationUrl,
|
|
370731
|
+
authorizationResponseIssParameterSupported: config2.authorizationResponseIssParameterSupported ?? discoveredConfig.authorizationResponseIssParameterSupported,
|
|
370405
370732
|
// Preserve existing client credentials
|
|
370406
370733
|
clientId: config2.clientId,
|
|
370407
370734
|
clientSecret: config2.clientSecret
|
|
@@ -370414,7 +370741,8 @@ var MCPOAuthProvider = class {
|
|
|
370414
370741
|
const pkceParams = generatePKCEParams();
|
|
370415
370742
|
const preferredPort = getPortFromUrl(config2.redirectUri);
|
|
370416
370743
|
debugLogger.debug(`Starting callback server for "${serverName}" (expected issuer: ${config2.issuer || "none"})...`);
|
|
370417
|
-
const
|
|
370744
|
+
const requireIssInResponse = config2.authorizationResponseIssParameterSupported ?? Boolean(config2.issuer);
|
|
370745
|
+
const callbackServer = startCallbackServer(pkceParams.state, preferredPort, config2.issuer, requireIssInResponse);
|
|
370418
370746
|
const redirectPort = await callbackServer.port;
|
|
370419
370747
|
debugLogger.debug(`Callback server listening on port ${redirectPort}`);
|
|
370420
370748
|
if (!config2.clientId) {
|
|
@@ -371163,7 +371491,8 @@ async function handleAutomaticOAuth(mcpServerName, mcpServerConfig, wwwAuthentic
|
|
|
371163
371491
|
authorizationUrl: oauthConfig.authorizationUrl,
|
|
371164
371492
|
issuer: oauthConfig.issuer,
|
|
371165
371493
|
tokenUrl: oauthConfig.tokenUrl,
|
|
371166
|
-
scopes: oauthConfig.scopes || []
|
|
371494
|
+
scopes: oauthConfig.scopes || [],
|
|
371495
|
+
authorizationResponseIssParameterSupported: mcpServerConfig.oauth?.authorizationResponseIssParameterSupported ?? oauthConfig.authorizationResponseIssParameterSupported
|
|
371167
371496
|
};
|
|
371168
371497
|
debugLogger.log(`Starting OAuth authentication for server '${mcpServerName}'...`);
|
|
371169
371498
|
const authProvider = new MCPOAuthProvider(new MCPOAuthTokenStorage());
|
|
@@ -371707,7 +372036,8 @@ async function connectToMcpServer(clientVersion, mcpServerName, mcpServerConfig,
|
|
|
371707
372036
|
authorizationUrl: oauthConfig.authorizationUrl,
|
|
371708
372037
|
issuer: oauthConfig.issuer,
|
|
371709
372038
|
tokenUrl: oauthConfig.tokenUrl,
|
|
371710
|
-
scopes: oauthConfig.scopes || []
|
|
372039
|
+
scopes: oauthConfig.scopes || [],
|
|
372040
|
+
authorizationResponseIssParameterSupported: mcpServerConfig.oauth?.authorizationResponseIssParameterSupported ?? oauthConfig.authorizationResponseIssParameterSupported
|
|
371711
372041
|
};
|
|
371712
372042
|
const authServerUrl = mcpServerConfig.httpUrl || mcpServerConfig.url;
|
|
371713
372043
|
debugLogger.log(`Starting OAuth authentication for server '${mcpServerName}'...`);
|
|
@@ -400210,6 +400540,8 @@ export {
|
|
|
400210
400540
|
StreamEventType,
|
|
400211
400541
|
SYNTHETIC_THOUGHT_SIGNATURE2 as SYNTHETIC_THOUGHT_SIGNATURE,
|
|
400212
400542
|
INTERRUPTED_RESPONSE_PLACEHOLDER,
|
|
400543
|
+
INTERRUPTED_TOOL_RESPONSE_ERROR,
|
|
400544
|
+
CONTINUE_PROMPT_TEXT,
|
|
400213
400545
|
isValidNonThoughtTextPart,
|
|
400214
400546
|
THINKING_ONLY_NUDGE_MESSAGE,
|
|
400215
400547
|
NO_RESPONSE_TEXT_NUDGE_MESSAGE,
|
|
@@ -400220,7 +400552,10 @@ export {
|
|
|
400220
400552
|
GeminiChat,
|
|
400221
400553
|
isSchemaDepthError,
|
|
400222
400554
|
isInvalidArgumentError,
|
|
400555
|
+
buildInterruptedToolResponseParts,
|
|
400556
|
+
ensureTerminalUserTurn,
|
|
400223
400557
|
stripToolCallIdPrefixes,
|
|
400558
|
+
coalesceConsecutiveContents,
|
|
400224
400559
|
coalesceConsecutiveRoles,
|
|
400225
400560
|
stripThoughts2 as stripThoughts,
|
|
400226
400561
|
populateToolDisplay,
|