@google/gemini-cli 0.62.0-preview.0 → 0.63.0-nightly.20260928.g2fe7c2d3f

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.
Files changed (69) hide show
  1. package/bundle/{chunk-VNI6B2SC.js → chunk-2AXHER6I.js} +1 -1
  2. package/bundle/{chunk-7P7I4GYC.js → chunk-4PBNRKYJ.js} +1 -1
  3. package/bundle/{chunk-UDX2JG4X.js → chunk-4SQTLFVK.js} +45 -11
  4. package/bundle/{chunk-ZOLMIYBF.js → chunk-5G7FE6LZ.js} +109 -62
  5. package/bundle/{chunk-UCTTKDYX.js → chunk-7ZCWMSGJ.js} +1 -1
  6. package/bundle/{chunk-7LRWECUM.js → chunk-B3EF23HT.js} +612 -158
  7. package/bundle/{chunk-4B6A2PDH.js → chunk-BRTA6WWG.js} +9 -8
  8. package/bundle/{chunk-IP26BEPK.js → chunk-C2KZGMGL.js} +1 -1
  9. package/bundle/{chunk-67JFSAOI.js → chunk-DEI3TS7C.js} +8 -5
  10. package/bundle/{chunk-QE6MNPCN.js → chunk-EATZTV2L.js} +45 -11
  11. package/bundle/chunk-EORMOPQX.js +17368 -0
  12. package/bundle/{chunk-YHJCOL52.js → chunk-ERMD62K5.js} +8372 -14832
  13. package/bundle/chunk-EYGY6SJV.js +512 -0
  14. package/bundle/{chunk-FX7H3YXM.js → chunk-I5ZBUXWS.js} +1 -1
  15. package/bundle/{chunk-X3MDVQ2M.js → chunk-I7XQQVIO.js} +1 -1
  16. package/bundle/{chunk-IZ7EEAUQ.js → chunk-KCZCDPS2.js} +2 -2
  17. package/bundle/{chunk-2MIF7TLR.js → chunk-KRI5JA76.js} +680 -165
  18. package/bundle/{chunk-DSHGGNYE.js → chunk-KSWUQTWU.js} +3 -3
  19. package/bundle/chunk-LNPKSDNP.js +102951 -0
  20. package/bundle/{chunk-RQBLUWGO.js → chunk-PAIQESPE.js} +3 -3
  21. package/bundle/{chunk-LXVOSY26.js → chunk-PGIM2K4Q.js} +1 -1
  22. package/bundle/{chunk-HCJU65X4.js → chunk-QX7M3XMQ.js} +3 -3
  23. package/bundle/{chunk-KYWRBXUN.js → chunk-QYTRARRL.js} +2 -2
  24. package/bundle/{chunk-4SYYS7FT.js → chunk-RFR5KZGU.js} +1 -1
  25. package/bundle/{chunk-UVWRONOW.js → chunk-SJFSOFYJ.js} +2 -2
  26. package/bundle/chunk-SZK5XAFL.js +398 -0
  27. package/bundle/chunk-TXWIPUPY.js +400484 -0
  28. package/bundle/{chunk-ZNLZV6KB.js → chunk-UOXIYBXB.js} +1 -1
  29. package/bundle/chunk-VAGYZO4R.js +1571 -0
  30. package/bundle/chunk-VNGBTT2C.js +154 -0
  31. package/bundle/chunk-YZPLV23A.js +118 -0
  32. package/bundle/{chunk-ZXPUBJYD.js → chunk-ZAM747AR.js} +1 -1
  33. package/bundle/{cleanup-FHA2KSXH.js → cleanup-5PD3O5L7.js} +2 -2
  34. package/bundle/{cleanup-HY2KJG6D.js → cleanup-6IDD7Q3X.js} +2 -2
  35. package/bundle/{cleanup-UNKT2DM4.js → cleanup-7UL3PRLF.js} +2 -2
  36. package/bundle/cleanup-UTIIPF3A.js +32 -0
  37. package/bundle/{core-FGYHAZ6H.js → core-IIFMZU4H.js} +11 -1
  38. package/bundle/{devtoolsService-WDMSDVS7.js → devtoolsService-67KG4JD7.js} +2 -2
  39. package/bundle/{devtoolsService-FYN3P465.js → devtoolsService-A7VWEFDQ.js} +4 -3
  40. package/bundle/{devtoolsService-2RNXWTDT.js → devtoolsService-AK7UU2FI.js} +2 -2
  41. package/bundle/devtoolsService-REQSIEPU.js +4359 -0
  42. package/bundle/{dist-42YIZWSU.js → dist-5HHK4577.js} +11 -1
  43. package/bundle/{core-CYZFUAYU.js → dist-I74UZ4GA.js} +11 -1
  44. package/bundle/dist-QMOHSH2B.js +2248 -0
  45. package/bundle/docs/changelogs/index.md +16 -0
  46. package/bundle/docs/changelogs/latest.md +34 -55
  47. package/bundle/docs/changelogs/preview.md +65 -29
  48. package/bundle/{gemini-H6C5T6NZ.js → gemini-I47O5YI2.js} +21 -21
  49. package/bundle/{gemini-5VI65FOO.js → gemini-OFIYPHV5.js} +221 -205
  50. package/bundle/{gemini-DRDYGTKK.js → gemini-PGIEQLQD.js} +21 -21
  51. package/bundle/gemini-PLPMSDXJ.js +17863 -0
  52. package/bundle/gemini.js +7 -7
  53. package/bundle/{interactiveCli-TLTKI2C4.js → interactiveCli-CJEDKYUL.js} +31 -14
  54. package/bundle/{interactiveCli-SOVSAZ32.js → interactiveCli-JF6LE6RN.js} +334 -298
  55. package/bundle/{interactiveCli-KSL5ASTL.js → interactiveCli-JLFFVRVY.js} +31 -14
  56. package/bundle/interactiveCli-OG4JE4CU.js +34907 -0
  57. package/bundle/{liteRtServerManager-KO56TKLF.js → liteRtServerManager-4LVWWKUV.js} +4 -4
  58. package/bundle/{liteRtServerManager-T2GG72NW.js → liteRtServerManager-DVDNFJNH.js} +4 -4
  59. package/bundle/{liteRtServerManager-2CCV35OQ.js → liteRtServerManager-G4WG2Q45.js} +4 -4
  60. package/bundle/liteRtServerManager-MZO6JMNV.js +65 -0
  61. package/bundle/{oauth2-provider-TBQ7JUDB.js → oauth2-provider-CEQ4PAUC.js} +1 -1
  62. package/bundle/{oauth2-provider-BSRUMVCL.js → oauth2-provider-IBKEWCFT.js} +38 -72
  63. package/bundle/{oauth2-provider-UY26FDAA.js → oauth2-provider-KPLVYPVA.js} +1 -1
  64. package/bundle/oauth2-provider-UHJTSOLD.js +235 -0
  65. package/bundle/{start-NGSQCGCK.js → start-2A3VVOAH.js} +6 -6
  66. package/bundle/{start-RUS2QGZK.js → start-6PINHVUA.js} +6 -6
  67. package/bundle/{start-GCXJMSER.js → start-BZAGKSC2.js} +6 -6
  68. package/bundle/start-ZRUVAD7P.js +18 -0
  69. package/package.json +1 -1
@@ -252404,16 +252404,23 @@ function trimTrailingSpacesAndDots(str2) {
252404
252404
  return str2.slice(0, end + 1);
252405
252405
  }
252406
252406
  var GIT_SFN_REGEX = /^(git|gi[0-9a-f]{4})~\d+$/;
252407
- var ENV_SFN_REGEX = /^(env|en[0-9a-f]{4})~\d+$/;
252407
+ var ENV_SFN_REGEX = /^(env|en[0-9a-f]{4})~\d+(\..+)?$/i;
252408
252408
  var NODE_MODULES_SFN_REGEX = /^(node_m|no[0-9a-f]{4})~\d+$/;
252409
252409
  var GHA_CREDS_SFN_REGEX = /^(gha-cr|gh[0-9a-f]{4})~\d+\.jso(n)?$/;
252410
+ var SAFE_ENV_TEMPLATES = /* @__PURE__ */ new Set([
252411
+ ".env.example",
252412
+ ".env.sample",
252413
+ ".env.template",
252414
+ ".env.dist"
252415
+ ]);
252410
252416
  function hasBlockedPathSegment(p) {
252411
252417
  const segments = p.split(/[/\\]/);
252412
252418
  for (const segment of segments) {
252413
252419
  const clean = trimTrailingSpacesAndDots(
252414
252420
  segment.split(":")[0]
252415
252421
  ).toLowerCase();
252416
- if (clean === ".git" || clean === ".env" || clean === "node_modules" || GIT_SFN_REGEX.test(clean) || ENV_SFN_REGEX.test(clean) || NODE_MODULES_SFN_REGEX.test(clean)) {
252422
+ const isEnvFile = clean === ".env" || clean.startsWith(".env.") && !SAFE_ENV_TEMPLATES.has(clean);
252423
+ if (clean === ".git" || isEnvFile || clean === "node_modules" || GIT_SFN_REGEX.test(clean) || ENV_SFN_REGEX.test(clean) || NODE_MODULES_SFN_REGEX.test(clean)) {
252417
252424
  return true;
252418
252425
  }
252419
252426
  if (clean.startsWith("gha-creds-") && clean.endsWith(".json") || GHA_CREDS_SFN_REGEX.test(clean)) {
@@ -253766,6 +253773,7 @@ var REFERENCE_CONTENT_END = "--- End of content ---";
253766
253773
  var DEFAULT_MAX_LINES_TEXT_FILE = 2e3;
253767
253774
  var MAX_LINE_LENGTH_TEXT_FILE = 2e3;
253768
253775
  var MAX_FILE_SIZE_MB = 20;
253776
+ var MAX_STORED_TOOL_OUTPUT_BYTES = 64 * 1024;
253769
253777
  var EMPTY_RESPONSE_COMPRESS_SUGGESTION = "The model returned an empty text response. If your context window is near capacity, try using /compress.";
253770
253778
  var THINKING_ONLY_COMPRESS_SUGGESTION = "The model returned reasoning thoughts but no final response text. If your context window is near capacity, try using /compress.";
253771
253779
  var MAX_TOKENS_EXCEEDED_SUGGESTION = "Model response was truncated because it exceeded the token limit. Try using /compress to free up context space.";
@@ -253847,8 +253855,43 @@ function decodeUTF32(buf, littleEndian) {
253847
253855
  }
253848
253856
  return out2;
253849
253857
  }
253850
- async function readFileWithEncoding(filePath) {
253851
- const full = await fs7.promises.readFile(filePath);
253858
+ async function readSecureFileBuffer(filePath, expectedStats) {
253859
+ const initialStats = expectedStats ?? await fs7.promises.stat(filePath);
253860
+ let fileHandle;
253861
+ try {
253862
+ if (typeof fs7.promises.open === "function") {
253863
+ try {
253864
+ fileHandle = await fs7.promises.open(filePath, "r");
253865
+ } catch {
253866
+ }
253867
+ if (fileHandle && typeof fileHandle.stat === "function") {
253868
+ const handleStats = await fileHandle.stat();
253869
+ if (initialStats.dev !== void 0 && initialStats.ino !== void 0 && handleStats && handleStats.dev !== void 0 && handleStats.ino !== void 0 && (initialStats.dev !== handleStats.dev || initialStats.ino !== handleStats.ino)) {
253870
+ throw new Error(
253871
+ `File device or inode changed during read: ${filePath}`
253872
+ );
253873
+ }
253874
+ }
253875
+ }
253876
+ const contentBuffer = fileHandle ? await fileHandle.readFile() : await fs7.promises.readFile(filePath);
253877
+ let postStats;
253878
+ try {
253879
+ postStats = await fs7.promises.stat(filePath);
253880
+ } catch {
253881
+ }
253882
+ if (postStats && initialStats.dev !== void 0 && initialStats.ino !== void 0 && postStats.dev !== void 0 && postStats.ino !== void 0 && (initialStats.dev !== postStats.dev || initialStats.ino !== postStats.ino)) {
253883
+ throw new Error(`File device or inode changed during read: ${filePath}`);
253884
+ }
253885
+ return contentBuffer;
253886
+ } finally {
253887
+ if (fileHandle) {
253888
+ await fileHandle.close().catch(() => {
253889
+ });
253890
+ }
253891
+ }
253892
+ }
253893
+ async function readFileWithEncoding(filePath, expectedStats) {
253894
+ const full = await readSecureFileBuffer(filePath, expectedStats);
253852
253895
  if (full.length === 0) return "";
253853
253896
  const bom = detectBOM(full);
253854
253897
  if (!bom) {
@@ -254085,14 +254128,14 @@ async function processSingleFileContent(filePath, rootDirectory, _fileSystemServ
254085
254128
  returnDisplay: `Skipped large SVG file (>1MB): ${relativePathForDisplay}`
254086
254129
  };
254087
254130
  }
254088
- const content = await readFileWithEncoding(filePath);
254131
+ const content = await readFileWithEncoding(filePath, stats);
254089
254132
  return {
254090
254133
  llmContent: content,
254091
254134
  returnDisplay: `Read SVG as text: ${relativePathForDisplay}`
254092
254135
  };
254093
254136
  }
254094
254137
  case "text": {
254095
- const content = await readFileWithEncoding(filePath);
254138
+ const content = await readFileWithEncoding(filePath, stats);
254096
254139
  const lines = content.split(/\r?\n/);
254097
254140
  const originalLineCount = lines.length;
254098
254141
  let sliceStart = 0;
@@ -254145,7 +254188,7 @@ async function processSingleFileContent(filePath, rootDirectory, _fileSystemServ
254145
254188
  errorType: "read_content_failure" /* READ_CONTENT_FAILURE */
254146
254189
  };
254147
254190
  }
254148
- const contentBuffer = await fs7.promises.readFile(filePath);
254191
+ const contentBuffer = await readSecureFileBuffer(filePath, stats);
254149
254192
  const base64Data = contentBuffer.toString("base64");
254150
254193
  return {
254151
254194
  llmContent: {
@@ -254161,7 +254204,7 @@ async function processSingleFileContent(filePath, rootDirectory, _fileSystemServ
254161
254204
  case "pdf":
254162
254205
  case "video": {
254163
254206
  const mimeType = getSpecificMimeType(filePath) ?? "application/octet-stream";
254164
- const contentBuffer = await fs7.promises.readFile(filePath);
254207
+ const contentBuffer = await readSecureFileBuffer(filePath, stats);
254165
254208
  const base64Data = contentBuffer.toString("base64");
254166
254209
  return {
254167
254210
  llmContent: {
@@ -283717,8 +283760,8 @@ function isValidToolName(name3, options = {}) {
283717
283760
  }
283718
283761
 
283719
283762
  // packages/core/src/generated/git-commit.ts
283720
- var GIT_COMMIT_INFO = "f50ba8608";
283721
- var CLI_VERSION = "0.62.0-preview.0";
283763
+ var GIT_COMMIT_INFO = "2fe7c2d3f";
283764
+ var CLI_VERSION = "0.63.0-nightly.20260923.gf50ba8608";
283722
283765
 
283723
283766
  // packages/core/src/ide/detect-ide.ts
283724
283767
  var IDE_DEFINITIONS = {
@@ -286760,10 +286803,12 @@ var ChatRecordingService = class {
286760
286803
  if (this.kind === "subagent") {
286761
286804
  filename = `${safeSessionId}.jsonl`;
286762
286805
  } else {
286763
- filename = `${SESSION_FILE_PREFIX}${timestamp2}-${safeSessionId.slice(
286764
- 0,
286765
- 8
286766
- )}.jsonl`;
286806
+ const shortId = safeSessionId.slice(0, 8);
286807
+ filename = `${SESSION_FILE_PREFIX}${timestamp2}-${shortId}.jsonl`;
286808
+ let collisionIndex = 1;
286809
+ while (fs32.existsSync(path29.join(chatsDir, filename))) {
286810
+ filename = `${SESSION_FILE_PREFIX}${timestamp2}-${collisionIndex++}-${shortId}.jsonl`;
286811
+ }
286767
286812
  }
286768
286813
  this.conversationFile = path29.join(chatsDir, filename);
286769
286814
  const directories = this.kind === "subagent" ? [
@@ -307338,7 +307383,7 @@ function getVersion() {
307338
307383
  }
307339
307384
  versionPromise = (async () => {
307340
307385
  const pkgJson = await getPackageJson(__dirname4);
307341
- return "0.62.0-preview.0";
307386
+ return "0.63.0-nightly.20260923.gf50ba8608";
307342
307387
  })();
307343
307388
  return versionPromise;
307344
307389
  }
@@ -314969,10 +315014,11 @@ function getSafeGitEnv(baseEnv = process.env) {
314969
315014
  }
314970
315015
  return {
314971
315016
  ...cleanedEnv,
315017
+ GIT_TERMINAL_PROMPT: "0",
314972
315018
  GIT_CONFIG_GLOBAL: devNullPath,
314973
315019
  GIT_CONFIG_SYSTEM: devNullPath,
314974
315020
  GIT_CONFIG_NOSYSTEM: "1",
314975
- GIT_CONFIG_COUNT: "8",
315021
+ GIT_CONFIG_COUNT: "7",
314976
315022
  GIT_CONFIG_KEY_0: "credential.helper",
314977
315023
  GIT_CONFIG_VALUE_0: "",
314978
315024
  GIT_CONFIG_KEY_1: "core.fsmonitor",
@@ -314986,9 +315032,7 @@ function getSafeGitEnv(baseEnv = process.env) {
314986
315032
  GIT_CONFIG_KEY_5: "core.editor",
314987
315033
  GIT_CONFIG_VALUE_5: "",
314988
315034
  GIT_CONFIG_KEY_6: "sequence.editor",
314989
- GIT_CONFIG_VALUE_6: "",
314990
- GIT_CONFIG_KEY_7: "diff.external",
314991
- GIT_CONFIG_VALUE_7: ""
315035
+ GIT_CONFIG_VALUE_6: ""
314992
315036
  };
314993
315037
  }
314994
315038
  async function getAbsoluteGitDir(cwd) {
@@ -315309,8 +315353,23 @@ var ReadFileToolInvocation = class extends BaseToolInvocation {
315309
315353
  };
315310
315354
  }
315311
315355
  async execute(_options) {
315356
+ const sanitizedPath = resolveDefensiveToolPath(
315357
+ this.params.file_path,
315358
+ this.config.getTargetDir()
315359
+ );
315360
+ let targetPathToRead = this.resolvedPath;
315361
+ try {
315362
+ targetPathToRead = resolveToRealPath(
315363
+ path52.resolve(this.config.getTargetDir(), sanitizedPath)
315364
+ );
315365
+ } catch {
315366
+ targetPathToRead = path52.resolve(
315367
+ this.config.getTargetDir(),
315368
+ sanitizedPath
315369
+ );
315370
+ }
315312
315371
  const validationError = this.config.validatePathAccess(
315313
- this.resolvedPath,
315372
+ targetPathToRead,
315314
315373
  "read"
315315
315374
  );
315316
315375
  if (validationError) {
@@ -315324,7 +315383,7 @@ var ReadFileToolInvocation = class extends BaseToolInvocation {
315324
315383
  };
315325
315384
  }
315326
315385
  const result2 = await processSingleFileContent(
315327
- this.resolvedPath,
315386
+ targetPathToRead,
315328
315387
  this.config.getTargetDir(),
315329
315388
  this.config.getFileSystemService(),
315330
315389
  this.params.start_line,
@@ -315355,9 +315414,9 @@ ${result2.llmContent}`;
315355
315414
  llmContent = result2.llmContent || "";
315356
315415
  }
315357
315416
  const lines = typeof result2.llmContent === "string" ? result2.llmContent.split("\n").length : void 0;
315358
- const mimetype = getSpecificMimeType(this.resolvedPath);
315417
+ const mimetype = getSpecificMimeType(targetPathToRead);
315359
315418
  const programming_language = getProgrammingLanguage({
315360
- file_path: this.resolvedPath
315419
+ file_path: targetPathToRead
315361
315420
  });
315362
315421
  logFileOperation(
315363
315422
  this.config,
@@ -315366,11 +315425,11 @@ ${result2.llmContent}`;
315366
315425
  "read" /* READ */,
315367
315426
  lines,
315368
315427
  mimetype,
315369
- path52.extname(this.resolvedPath),
315428
+ path52.extname(targetPathToRead),
315370
315429
  programming_language
315371
315430
  )
315372
315431
  );
315373
- const jitContext = await discoverJitContext(this.config, this.resolvedPath);
315432
+ const jitContext = await discoverJitContext(this.config, targetPathToRead);
315374
315433
  if (jitContext) {
315375
315434
  if (typeof llmContent === "string") {
315376
315435
  llmContent = appendJitContext(llmContent, jitContext);
@@ -315564,7 +315623,7 @@ var ReadMcpResourceToolInvocation = class extends BaseToolInvocation {
315564
315623
  }
315565
315624
  }
315566
315625
  return {
315567
- llmContent: contentText || "No content returned from resource.",
315626
+ llmContent: contentText ? wrapUntrusted(contentText) : "No content returned from resource.",
315568
315627
  returnDisplay: this.resource ? `Successfully read resource "${this.resource.name}" from server "${this.resource.serverName}"` : `Successfully read resource: ${uri}`
315569
315628
  };
315570
315629
  } catch (e2) {
@@ -315651,7 +315710,7 @@ var ListMcpResourcesToolInvocation = class extends BaseToolInvocation {
315651
315710
  content += "\n";
315652
315711
  }
315653
315712
  return {
315654
- llmContent: content,
315713
+ llmContent: wrapUntrusted(content),
315655
315714
  returnDisplay: `Listed ${resources.length} resources.`
315656
315715
  };
315657
315716
  }
@@ -324320,7 +324379,7 @@ var ActivateSkillTool = class _ActivateSkillTool extends BaseDeclarativeTool {
324320
324379
  };
324321
324380
 
324322
324381
  // packages/core/src/tools/shell.ts
324323
- import fsPromises9 from "node:fs/promises";
324382
+ import fsPromises10 from "node:fs/promises";
324324
324383
  import fs51 from "node:fs";
324325
324384
  import path61 from "node:path";
324326
324385
  import os32 from "node:os";
@@ -324388,6 +324447,7 @@ import { spawn as cpSpawn } from "node:child_process";
324388
324447
  import { TextDecoder as TextDecoder2 } from "node:util";
324389
324448
  import os30 from "node:os";
324390
324449
  import fs49, { mkdirSync as mkdirSync4 } from "node:fs";
324450
+ import fsPromises9 from "node:fs/promises";
324391
324451
  import path59 from "node:path";
324392
324452
  var import_headless3 = __toESM(require_xterm_headless(), 1);
324393
324453
 
@@ -325438,6 +325498,7 @@ var ShellExecutionService = class _ShellExecutionService {
325438
325498
  static activeChildProcesses = /* @__PURE__ */ new Map();
325439
325499
  static backgroundLogPids = /* @__PURE__ */ new Set();
325440
325500
  static backgroundLogStreams = /* @__PURE__ */ new Map();
325501
+ static backgroundTempDirs = /* @__PURE__ */ new Map();
325441
325502
  static backgroundProcessHistory = /* @__PURE__ */ new Map();
325442
325503
  static getLogDir() {
325443
325504
  return path59.join(Storage.getGlobalTempDir(), "background-processes");
@@ -325464,6 +325525,10 @@ ${truncated}`;
325464
325525
  }
325465
325526
  }
325466
325527
  static async cleanupLogStream(pid) {
325528
+ const tempDir = this.backgroundTempDirs.get(pid);
325529
+ this.backgroundTempDirs.delete(pid);
325530
+ const rmPromise = tempDir ? fsPromises9.rm(tempDir, { recursive: true, force: true }).catch(() => {
325531
+ }) : Promise.resolve();
325467
325532
  const stream2 = this.backgroundLogStreams.get(pid);
325468
325533
  if (stream2) {
325469
325534
  await new Promise((resolve29) => {
@@ -325472,6 +325537,7 @@ ${truncated}`;
325472
325537
  this.backgroundLogStreams.delete(pid);
325473
325538
  }
325474
325539
  this.backgroundLogPids.delete(pid);
325540
+ await rmPromise;
325475
325541
  }
325476
325542
  /**
325477
325543
  * Executes a shell command using `node-pty`, capturing all output and lifecycle events.
@@ -325588,8 +325654,7 @@ ${truncated}`;
325588
325654
  ["core.sshCommand", ""],
325589
325655
  ["core.pager", "cat"],
325590
325656
  ["core.editor", ""],
325591
- ["sequence.editor", ""],
325592
- ["diff.external", ""]
325657
+ ["sequence.editor", ""]
325593
325658
  ];
325594
325659
  for (const [overrideKey, overrideVal] of defaultGitOverrides) {
325595
325660
  const keyVar = `GIT_CONFIG_KEY_${gitConfigCount}`;
@@ -325667,6 +325732,33 @@ ${truncated}`;
325667
325732
  }
325668
325733
  }
325669
325734
  }
325735
+ if (child.stdout) {
325736
+ child.stdout.removeAllListeners();
325737
+ try {
325738
+ child.stdout.destroy();
325739
+ } catch {
325740
+ }
325741
+ }
325742
+ if (child.stderr) {
325743
+ child.stderr.removeAllListeners();
325744
+ try {
325745
+ child.stderr.destroy();
325746
+ } catch {
325747
+ }
325748
+ }
325749
+ const stdin = child.stdin;
325750
+ if (stdin) {
325751
+ stdin.removeAllListeners();
325752
+ try {
325753
+ stdin.destroy();
325754
+ } catch {
325755
+ }
325756
+ }
325757
+ child.removeAllListeners("error");
325758
+ child.removeAllListeners("close");
325759
+ state.sniffChunks.length = 0;
325760
+ stdoutDecoder = null;
325761
+ stderrDecoder = null;
325670
325762
  return;
325671
325763
  };
325672
325764
  var cleanup = cleanup2;
@@ -325705,7 +325797,8 @@ ${truncated}`;
325705
325797
  process: child,
325706
325798
  state,
325707
325799
  command: shellExecutionConfig.originalCommand ?? commandToExecute,
325708
- sessionId: shellExecutionConfig.sessionId
325800
+ sessionId: shellExecutionConfig.sessionId,
325801
+ tempDir: shellExecutionConfig.tempDir
325709
325802
  });
325710
325803
  }
325711
325804
  const lifecycleHandle = child.pid ? ExecutionLifecycleService.attachExecution(child.pid, {
@@ -325821,6 +325914,7 @@ ${truncated}`;
325821
325914
  cleanup2();
325822
325915
  cmdCleanup?.();
325823
325916
  let combinedOutput = state.output;
325917
+ state.output = "";
325824
325918
  if (state.truncated) {
325825
325919
  const truncationMessage = `
325826
325920
  [GEMINI_CLI_WARNING: Output truncated. The buffer is limited to ${MAX_CHILD_PROCESS_BUFFER_SIZE / (1024 * 1024)}MB.]`;
@@ -325856,9 +325950,8 @@ ${truncated}`;
325856
325950
  historyItem.endTime = Date.now();
325857
325951
  }
325858
325952
  onOutputEvent(event);
325859
- _ShellExecutionService.cleanupLogStream(pid).then(() => {
325860
- _ShellExecutionService.activeChildProcesses.delete(pid);
325861
- });
325953
+ _ShellExecutionService.activeChildProcesses.delete(pid);
325954
+ _ShellExecutionService.cleanupLogStream(pid);
325862
325955
  ExecutionLifecycleService.completeWithResult(pid, resultPayload);
325863
325956
  } else {
325864
325957
  resolveWithoutPid?.(resultPayload);
@@ -326078,7 +326171,8 @@ ${truncated}`;
326078
326171
  maxSerializedLines: shellExecutionConfig.maxSerializedLines,
326079
326172
  command: shellExecutionConfig.originalCommand ?? commandToExecute,
326080
326173
  sessionId: shellExecutionConfig.sessionId,
326081
- cancelRender
326174
+ cancelRender,
326175
+ tempDir: shellExecutionConfig.tempDir
326082
326176
  });
326083
326177
  const result2 = ExecutionLifecycleService.attachExecution(assignedPid, {
326084
326178
  executionMethod: ptyInfo?.name ?? "node-pty",
@@ -326537,18 +326631,32 @@ ${truncated}`;
326537
326631
  * This resolves the execution promise but keeps the PTY active.
326538
326632
  *
326539
326633
  * @param pid The process ID of the target PTY.
326634
+ * @param sessionId Optional session ID for process history tracking.
326635
+ * @param command Optional command string for display.
326636
+ * @param tempDir Optional temporary directory path owned by this execution to clean up on exit.
326540
326637
  */
326541
- static background(pid, sessionId, command) {
326542
- if (this.backgroundLogPids.has(pid)) {
326543
- return;
326544
- }
326638
+ static background(pid, sessionId, command, tempDir) {
326545
326639
  const activePty = this.activePtys.get(pid);
326546
326640
  const activeChild = this.activeChildProcesses.get(pid);
326641
+ const resolvedTempDir = tempDir ?? activePty?.tempDir ?? activeChild?.tempDir;
326547
326642
  const resolvedSessionId = sessionId ?? activePty?.sessionId ?? activeChild?.sessionId;
326548
326643
  const resolvedCommand = command ?? activePty?.command ?? activeChild?.command ?? "unknown command";
326549
326644
  if (!resolvedSessionId) {
326550
326645
  throw new Error("Session ID is required for background operations");
326551
326646
  }
326647
+ if (!activePty && !activeChild) {
326648
+ if (resolvedTempDir) {
326649
+ fsPromises9.rm(resolvedTempDir, { recursive: true, force: true }).catch(() => {
326650
+ });
326651
+ }
326652
+ return;
326653
+ }
326654
+ if (resolvedTempDir) {
326655
+ this.backgroundTempDirs.set(pid, resolvedTempDir);
326656
+ }
326657
+ if (this.backgroundLogPids.has(pid)) {
326658
+ return;
326659
+ }
326552
326660
  const MAX_BACKGROUND_PROCESS_HISTORY_SIZE = 100;
326553
326661
  const history = this.backgroundProcessHistory.get(resolvedSessionId) ?? /* @__PURE__ */ new Map();
326554
326662
  if (history.size >= MAX_BACKGROUND_PROCESS_HISTORY_SIZE) {
@@ -326560,7 +326668,8 @@ ${truncated}`;
326560
326668
  history.set(pid, {
326561
326669
  command: resolvedCommand,
326562
326670
  status: "running",
326563
- startTime: Date.now()
326671
+ startTime: Date.now(),
326672
+ ...resolvedTempDir ? { tempDir: resolvedTempDir } : {}
326564
326673
  });
326565
326674
  this.backgroundProcessHistory.set(resolvedSessionId, history);
326566
326675
  const logPath = this.getLogFilePath(pid);
@@ -326708,8 +326817,15 @@ ${truncated}`;
326708
326817
  } catch {
326709
326818
  }
326710
326819
  }
326820
+ for (const tempDir of this.backgroundTempDirs.values()) {
326821
+ try {
326822
+ fs49.rmSync(tempDir, { recursive: true, force: true });
326823
+ } catch {
326824
+ }
326825
+ }
326711
326826
  this.backgroundLogPids.clear();
326712
326827
  this.backgroundLogStreams.clear();
326828
+ this.backgroundTempDirs.clear();
326713
326829
  this.backgroundProcessHistory.clear();
326714
326830
  }
326715
326831
  };
@@ -327003,15 +327119,19 @@ exit $__code`;
327003
327119
  getExplanation() {
327004
327120
  return this.getContextualDetails().trim();
327005
327121
  }
327122
+ hasTaintedOrBuildFileRisk() {
327123
+ const command = stripShellWrapper(this.params.command);
327124
+ const history = this.getHistory();
327125
+ const untrustedContext = extractUntrustedContext(history);
327126
+ const untrustedFlags = findUntrustedFlags(command, untrustedContext);
327127
+ const modifiedBuildFiles = getModifiedBuildFiles(this.context.config);
327128
+ const isBuildCmd = isBuildOrTestCommand(command);
327129
+ return untrustedFlags.length > 0 || isBuildCmd && modifiedBuildFiles.length > 0;
327130
+ }
327006
327131
  getPolicyUpdateOptions(outcome) {
327007
327132
  if (outcome === "proceed_always_and_save" /* ProceedAlwaysAndSave */ || outcome === "proceed_always" /* ProceedAlways */) {
327008
327133
  const command = stripShellWrapper(this.params.command);
327009
- const history = this.getHistory();
327010
- const untrustedContext = extractUntrustedContext(history);
327011
- const untrustedFlags = findUntrustedFlags(command, untrustedContext);
327012
- const modifiedBuildFiles = getModifiedBuildFiles(this.context.config);
327013
- const isBuildCmd = isBuildOrTestCommand(command);
327014
- if (untrustedFlags.length > 0 || isBuildCmd && modifiedBuildFiles.length > 0) {
327134
+ if (this.hasTaintedOrBuildFileRisk()) {
327015
327135
  return void 0;
327016
327136
  }
327017
327137
  const rootCommands = [...new Set(getCommandRoots(command))];
@@ -327027,24 +327147,18 @@ exit $__code`;
327027
327147
  if (forcedDecision === "deny") {
327028
327148
  return super.shouldConfirmExecute(abortSignal, forcedDecision);
327029
327149
  }
327030
- const command = stripShellWrapper(this.params.command);
327031
- const history = this.getHistory();
327032
- const untrustedContext = extractUntrustedContext(history);
327033
- const untrustedFlags = findUntrustedFlags(command, untrustedContext);
327034
- const modifiedBuildFiles = getModifiedBuildFiles(this.context.config);
327035
- const isBuildCmd = isBuildOrTestCommand(command);
327036
- if (untrustedFlags.length > 0 || isBuildCmd && modifiedBuildFiles.length > 0) {
327150
+ if (this.hasTaintedOrBuildFileRisk()) {
327037
327151
  return this.getConfirmationDetails(abortSignal);
327038
327152
  }
327039
- if (this.context.config.getApprovalMode() === "yolo" /* YOLO */) {
327153
+ if (this.context.config.getApprovalMode() === "yolo" /* YOLO */ && forcedDecision !== "ask_user") {
327040
327154
  return super.shouldConfirmExecute(abortSignal, forcedDecision);
327041
327155
  }
327042
327156
  if (this.params[PARAM_ADDITIONAL_PERMISSIONS]) {
327043
327157
  return this.getConfirmationDetails(abortSignal);
327044
327158
  }
327045
327159
  if (this.context.config.getSandboxEnabled()) {
327046
- const command2 = stripShellWrapper(this.params.command);
327047
- const rootCommands = getCommandRoots(command2);
327160
+ const command = stripShellWrapper(this.params.command);
327161
+ const rootCommands = getCommandRoots(command);
327048
327162
  const rawRootCommand = rootCommands[0];
327049
327163
  if (rawRootCommand) {
327050
327164
  const rootCommand = normalizeCommand(rawRootCommand);
@@ -327057,7 +327171,7 @@ exit $__code`;
327057
327171
  );
327058
327172
  const hasNetwork = modeConfig.network || approved.network;
327059
327173
  const missingNetwork = !!proactive.network && !hasNetwork;
327060
- const parsed = parseCommandDetails(command2);
327174
+ const parsed = parseCommandDetails(command);
327061
327175
  const subCommand = parsed?.details[0]?.args?.[0];
327062
327176
  const needsNetwork = isNetworkReliantCommand(rootCommand, subCommand);
327063
327177
  if (needsNetwork) {
@@ -327196,6 +327310,7 @@ exit $__code`;
327196
327310
  const isWindows3 = os32.platform() === "win32";
327197
327311
  let tempFilePath = "";
327198
327312
  let tempDir = "";
327313
+ let isBackgrounded = false;
327199
327314
  const timeoutMs = this.context.config.getShellToolInactivityTimeout();
327200
327315
  const timeoutController = new AbortController();
327201
327316
  let timeoutTimer;
@@ -327351,7 +327466,8 @@ exit $__code`;
327351
327466
  }
327352
327467
  },
327353
327468
  backgroundCompletionBehavior: this.context.config.getShellBackgroundCompletionBehavior(),
327354
- originalCommand: strippedCommand
327469
+ originalCommand: strippedCommand,
327470
+ tempDir
327355
327471
  }
327356
327472
  );
327357
327473
  if (pid) {
@@ -327366,11 +327482,20 @@ exit $__code`;
327366
327482
  () => {
327367
327483
  promotionTimer = null;
327368
327484
  if (!completed) {
327369
- ShellExecutionService.background(
327370
- pid,
327371
- sessionId,
327372
- strippedCommand
327373
- );
327485
+ try {
327486
+ ShellExecutionService.background(
327487
+ pid,
327488
+ sessionId,
327489
+ strippedCommand,
327490
+ tempDir
327491
+ );
327492
+ isBackgrounded = true;
327493
+ } catch (err2) {
327494
+ debugLogger.error(
327495
+ "Failed to background shell execution:",
327496
+ err2
327497
+ );
327498
+ }
327374
327499
  }
327375
327500
  },
327376
327501
  delay3
@@ -327409,20 +327534,22 @@ ${cumulativeOutput}`,
327409
327534
  }
327410
327535
  }
327411
327536
  const result2 = await resultPromise;
327412
- if (!result2.backgrounded) {
327537
+ if (result2.backgrounded) {
327538
+ isBackgrounded = true;
327539
+ } else {
327413
327540
  flushOutput();
327414
327541
  }
327415
327542
  const backgroundPIDs = [];
327416
327543
  if (os32.platform() !== "win32") {
327417
327544
  let tempFileExists = false;
327418
327545
  try {
327419
- await fsPromises9.access(tempFilePath);
327546
+ await fsPromises10.access(tempFilePath);
327420
327547
  tempFileExists = true;
327421
327548
  } catch {
327422
327549
  tempFileExists = false;
327423
327550
  }
327424
327551
  if (tempFileExists) {
327425
- const backgroundPIDContent = await fsPromises9.readFile(
327552
+ const backgroundPIDContent = await fsPromises10.readFile(
327426
327553
  tempFilePath,
327427
327554
  "utf8"
327428
327555
  );
@@ -327667,16 +327794,16 @@ ${result2.output}`;
327667
327794
  }
327668
327795
  signal.removeEventListener("abort", onAbort);
327669
327796
  timeoutController.signal.removeEventListener("abort", onAbort);
327670
- if (!this.params.is_background) {
327797
+ if (!isBackgrounded) {
327671
327798
  if (tempFilePath) {
327672
327799
  try {
327673
- await fsPromises9.unlink(tempFilePath);
327800
+ await fsPromises10.unlink(tempFilePath);
327674
327801
  } catch {
327675
327802
  }
327676
327803
  }
327677
327804
  if (tempDir) {
327678
327805
  try {
327679
- await fsPromises9.rm(tempDir, { recursive: true, force: true });
327806
+ await fsPromises10.rm(tempDir, { recursive: true, force: true });
327680
327807
  } catch {
327681
327808
  }
327682
327809
  }
@@ -333787,7 +333914,7 @@ var WebSearchToolInvocation = class extends BaseToolInvocation {
333787
333914
  return {
333788
333915
  llmContent: `Web search results for "${this.params.query}":
333789
333916
 
333790
- ${modifiedResponseText}`,
333917
+ ${wrapUntrusted(modifiedResponseText)}`,
333791
333918
  returnDisplay: `Search results for "${this.params.query}" returned.`,
333792
333919
  sources
333793
333920
  };
@@ -338493,6 +338620,133 @@ var PreCompressTrigger = /* @__PURE__ */ ((PreCompressTrigger2) => {
338493
338620
 
338494
338621
  // packages/core/src/context/chatCompressionService.ts
338495
338622
  var DEFAULT_COMPRESSION_TOKEN_THRESHOLD = 0.5;
338623
+ var RECENT_TURNS_PROTECTED = 3;
338624
+ var RETRIEVAL_TOOL_NAMES_EXEMPT_FROM_COLLAPSE = /* @__PURE__ */ new Set([
338625
+ "read_file",
338626
+ "read_many_files",
338627
+ "get_internal_docs",
338628
+ "read_mcp_resource",
338629
+ "grep",
338630
+ "rip_grep",
338631
+ "glob",
338632
+ "search_file_content",
338633
+ "find_files"
338634
+ ]);
338635
+ function isExemptRetrievalTool(toolName, exemptTools = RETRIEVAL_TOOL_NAMES_EXEMPT_FROM_COLLAPSE) {
338636
+ if (!toolName) {
338637
+ return false;
338638
+ }
338639
+ const normalized2 = toolName.toLowerCase();
338640
+ if (exemptTools.has(normalized2)) {
338641
+ return true;
338642
+ }
338643
+ return normalized2.endsWith("read_file") || normalized2.endsWith("read_files") || normalized2.endsWith("read_many_files") || normalized2.endsWith("read_resource");
338644
+ }
338645
+ var COLLAPSED_FUNCTION_RESPONSE_MAX_BYTES = 2048;
338646
+ var defaultGraphemeSegmenter = new Intl.Segmenter(void 0, {
338647
+ granularity: "grapheme"
338648
+ });
338649
+ function collapseOlderFunctionResponses(history, maxBytesPerOldResponse = COLLAPSED_FUNCTION_RESPONSE_MAX_BYTES, segmenter2 = defaultGraphemeSegmenter, protectedTurns = RECENT_TURNS_PROTECTED, exemptTools = RETRIEVAL_TOOL_NAMES_EXEMPT_FROM_COLLAPSE) {
338650
+ const toolIndices = [];
338651
+ for (let i3 = 0; i3 < history.length; i3++) {
338652
+ if (history[i3].role === "user" && history[i3].parts?.some((p) => !!p.functionResponse)) {
338653
+ toolIndices.push(i3);
338654
+ }
338655
+ }
338656
+ if (toolIndices.length <= protectedTurns) {
338657
+ return history;
338658
+ }
338659
+ const cutoffToolIndex = toolIndices[toolIndices.length - protectedTurns];
338660
+ const collapseString = (str2) => {
338661
+ const totalBytes = Buffer.byteLength(str2, "utf8");
338662
+ if (totalBytes <= maxBytesPerOldResponse) {
338663
+ return str2;
338664
+ }
338665
+ const previewBytes = maxBytesPerOldResponse;
338666
+ let preview = "";
338667
+ let currentBytes = 0;
338668
+ for (const { segment } of segmenter2.segment(str2)) {
338669
+ const segmentBytes = Buffer.byteLength(segment, "utf8");
338670
+ if (currentBytes + segmentBytes > previewBytes) {
338671
+ break;
338672
+ }
338673
+ preview += segment;
338674
+ currentBytes += segmentBytes;
338675
+ }
338676
+ const omittedBytes = totalBytes - currentBytes;
338677
+ return `${preview}
338678
+ ... [Tool output collapsed from previous turn: ${omittedBytes} bytes omitted to conserve memory] ...`;
338679
+ };
338680
+ const collapseValue = (val) => {
338681
+ if (typeof val === "string") {
338682
+ return collapseString(val);
338683
+ }
338684
+ if (Array.isArray(val)) {
338685
+ let arrayModified = false;
338686
+ const newVal = val.map((item) => {
338687
+ const collapsed = collapseValue(item);
338688
+ if (collapsed !== item) {
338689
+ arrayModified = true;
338690
+ }
338691
+ return collapsed;
338692
+ });
338693
+ return arrayModified ? newVal : val;
338694
+ }
338695
+ if (typeof val === "object" && val !== null) {
338696
+ const proto = Object.getPrototypeOf(val);
338697
+ if (proto !== Object.prototype && proto !== null) {
338698
+ return val;
338699
+ }
338700
+ let objModified = false;
338701
+ const copy = {};
338702
+ for (const [k, v] of Object.entries(val)) {
338703
+ const collapsed = collapseValue(v);
338704
+ if (collapsed !== v) {
338705
+ objModified = true;
338706
+ }
338707
+ copy[k] = collapsed;
338708
+ }
338709
+ return objModified ? copy : val;
338710
+ }
338711
+ return val;
338712
+ };
338713
+ let modified = false;
338714
+ const newHistory = history.map((content, idx) => {
338715
+ if (idx >= cutoffToolIndex || content.role !== "user" || !content.parts) {
338716
+ return content;
338717
+ }
338718
+ let partsModified = false;
338719
+ const newParts = content.parts.map((part) => {
338720
+ if (!part.functionResponse?.response) {
338721
+ return part;
338722
+ }
338723
+ if (isExemptRetrievalTool(part.functionResponse.name, exemptTools)) {
338724
+ return part;
338725
+ }
338726
+ const resp = part.functionResponse.response;
338727
+ const newResp = collapseValue(resp);
338728
+ if (newResp !== resp) {
338729
+ partsModified = true;
338730
+ return {
338731
+ ...part,
338732
+ functionResponse: {
338733
+ // eslint-disable-next-line @typescript-eslint/no-misused-spread
338734
+ ...part.functionResponse,
338735
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
338736
+ response: newResp
338737
+ }
338738
+ };
338739
+ }
338740
+ return part;
338741
+ });
338742
+ if (partsModified) {
338743
+ modified = true;
338744
+ return { ...content, parts: newParts };
338745
+ }
338746
+ return content;
338747
+ });
338748
+ return modified ? newHistory : history;
338749
+ }
338496
338750
  var COMPRESSION_PRESERVE_THRESHOLD = 0.3;
338497
338751
  var COMPRESSION_FUNCTION_RESPONSE_TOKEN_BUDGET = 5e4;
338498
338752
  function findCompressSplitPoint(contents, fraction) {
@@ -338630,10 +338884,12 @@ var ChatCompressionService = class {
338630
338884
  }
338631
338885
  const trigger = force ? "manual" /* Manual */ : "auto" /* Auto */;
338632
338886
  await config2.getHookSystem()?.firePreCompressEvent(trigger);
338633
- const originalTokenCount = chat.getLastPromptTokenCount();
338887
+ const lastPromptTokenCount = chat.getLastPromptTokenCount();
338888
+ const originalTokenCount = lastPromptTokenCount > 0 ? lastPromptTokenCount : estimateTokenCountSync(curatedHistory.flatMap((c4) => c4.parts || []));
338634
338889
  if (!force) {
338635
338890
  const threshold = await config2.getCompressionThreshold() ?? DEFAULT_COMPRESSION_TOKEN_THRESHOLD;
338636
- if (originalTokenCount < threshold * tokenLimit(model)) {
338891
+ const isOverModelThreshold = originalTokenCount >= threshold * tokenLimit(model);
338892
+ if (!isOverModelThreshold) {
338637
338893
  return {
338638
338894
  newHistory: null,
338639
338895
  info: {
@@ -338795,6 +339051,8 @@ First, reason in your scratchpad. Then, generate the updated <state_snapshot>.`
338795
339051
  }
338796
339052
  };
338797
339053
  } else {
339054
+ historyToCompressTruncated.length = 0;
339055
+ originalHistoryToCompress.length = 0;
338798
339056
  return {
338799
339057
  newHistory: extraHistory,
338800
339058
  info: {
@@ -338807,6 +339065,173 @@ First, reason in your scratchpad. Then, generate the updated <state_snapshot>.`
338807
339065
  }
338808
339066
  };
338809
339067
 
339068
+ // packages/core/src/utils/tool-utils.ts
339069
+ var import_fast_levenshtein2 = __toESM(require_levenshtein(), 1);
339070
+ function isToolCallResponseInfo(data) {
339071
+ return typeof data === "object" && data !== null && "callId" in data && "responseParts" in data;
339072
+ }
339073
+ function getToolSuggestion(unknownToolName, allToolNames, topN = 3) {
339074
+ const matches = allToolNames.map((toolName) => ({
339075
+ name: toolName,
339076
+ distance: import_fast_levenshtein2.default.get(unknownToolName, toolName)
339077
+ }));
339078
+ matches.sort((a2, b) => a2.distance - b.distance);
339079
+ const topNResults = matches.slice(0, topN);
339080
+ if (topNResults.length === 0) {
339081
+ return "";
339082
+ }
339083
+ const suggestedNames = topNResults.map((match2) => `"${match2.name}"`).join(", ");
339084
+ if (topNResults.length > 1) {
339085
+ return ` Did you mean one of: ${suggestedNames}?`;
339086
+ } else {
339087
+ return ` Did you mean ${suggestedNames}?`;
339088
+ }
339089
+ }
339090
+ function doesToolInvocationMatch(toolOrToolName, invocation, patterns) {
339091
+ let toolNames;
339092
+ if (isTool(toolOrToolName)) {
339093
+ toolNames = [toolOrToolName.name, toolOrToolName.constructor.name];
339094
+ } else {
339095
+ toolNames = [toolOrToolName];
339096
+ }
339097
+ if (toolNames.some((name3) => SHELL_TOOL_NAMES.includes(name3))) {
339098
+ toolNames = [.../* @__PURE__ */ new Set([...toolNames, ...SHELL_TOOL_NAMES])];
339099
+ }
339100
+ for (const pattern of patterns) {
339101
+ const openParen = pattern.indexOf("(");
339102
+ if (openParen === -1) {
339103
+ if (toolNames.includes(pattern)) {
339104
+ return true;
339105
+ }
339106
+ continue;
339107
+ }
339108
+ const patternToolName = pattern.substring(0, openParen);
339109
+ if (!toolNames.includes(patternToolName)) {
339110
+ continue;
339111
+ }
339112
+ if (!pattern.endsWith(")")) {
339113
+ continue;
339114
+ }
339115
+ const argPattern = pattern.substring(openParen + 1, pattern.length - 1);
339116
+ let command;
339117
+ if (typeof invocation === "string") {
339118
+ command = invocation;
339119
+ } else {
339120
+ if (!("command" in invocation.params)) {
339121
+ continue;
339122
+ }
339123
+ command = String(invocation.params.command);
339124
+ }
339125
+ if (toolNames.some((name3) => SHELL_TOOL_NAMES.includes(name3))) {
339126
+ if (command === argPattern || command.startsWith(argPattern + " ")) {
339127
+ return true;
339128
+ }
339129
+ }
339130
+ }
339131
+ return false;
339132
+ }
339133
+ var segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
339134
+ function truncateToolOutput(text, maxBytes = MAX_STORED_TOOL_OUTPUT_BYTES, savedFilePath) {
339135
+ if (Buffer.byteLength(text, "utf8") <= maxBytes) {
339136
+ return text;
339137
+ }
339138
+ const suffix = savedFilePath ? `
339139
+ ... [Tool output truncated to conserve memory. For full output see: ${savedFilePath}]` : "\n... [Tool output truncated to conserve memory]";
339140
+ const targetBytes = Math.max(0, maxBytes - Buffer.byteLength(suffix, "utf8"));
339141
+ let accumulatedBytes = 0;
339142
+ let truncatedText = "";
339143
+ for (const { segment } of segmenter.segment(text)) {
339144
+ const segmentBytes = Buffer.byteLength(segment, "utf8");
339145
+ if (accumulatedBytes + segmentBytes > targetBytes) {
339146
+ break;
339147
+ }
339148
+ accumulatedBytes += segmentBytes;
339149
+ truncatedText += segment;
339150
+ }
339151
+ return truncatedText + suffix;
339152
+ }
339153
+ function truncateFunctionResponsePart(part, maxBytes = MAX_STORED_TOOL_OUTPUT_BYTES, savedFilePath) {
339154
+ if (part.text && Buffer.byteLength(part.text, "utf8") > maxBytes) {
339155
+ return {
339156
+ ...part,
339157
+ text: truncateToolOutput(part.text, maxBytes, savedFilePath)
339158
+ };
339159
+ }
339160
+ if (!part.functionResponse?.response) {
339161
+ return part;
339162
+ }
339163
+ const resp = part.functionResponse.response;
339164
+ if (typeof resp === "string") {
339165
+ if (Buffer.byteLength(resp, "utf8") > maxBytes) {
339166
+ return {
339167
+ ...part,
339168
+ functionResponse: {
339169
+ // eslint-disable-next-line @typescript-eslint/no-misused-spread
339170
+ ...part.functionResponse,
339171
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
339172
+ response: truncateToolOutput(
339173
+ resp,
339174
+ maxBytes,
339175
+ savedFilePath
339176
+ )
339177
+ }
339178
+ };
339179
+ }
339180
+ return part;
339181
+ }
339182
+ if (typeof resp === "object" && resp !== null) {
339183
+ const truncateValue = (val) => {
339184
+ if (typeof val === "string") {
339185
+ if (Buffer.byteLength(val, "utf8") > maxBytes) {
339186
+ return truncateToolOutput(val, maxBytes, savedFilePath);
339187
+ }
339188
+ return val;
339189
+ }
339190
+ if (Array.isArray(val)) {
339191
+ let arrayModified = false;
339192
+ const newVal = val.map((item) => {
339193
+ const truncated = truncateValue(item);
339194
+ if (truncated !== item) {
339195
+ arrayModified = true;
339196
+ }
339197
+ return truncated;
339198
+ });
339199
+ return arrayModified ? newVal : val;
339200
+ }
339201
+ if (typeof val === "object" && val !== null) {
339202
+ const proto = Object.getPrototypeOf(val);
339203
+ if (proto !== Object.prototype && proto !== null) {
339204
+ return val;
339205
+ }
339206
+ let objModified = false;
339207
+ const copy = {};
339208
+ for (const [k, v] of Object.entries(val)) {
339209
+ const truncated = truncateValue(v);
339210
+ if (truncated !== v) {
339211
+ objModified = true;
339212
+ }
339213
+ copy[k] = truncated;
339214
+ }
339215
+ return objModified ? copy : val;
339216
+ }
339217
+ return val;
339218
+ };
339219
+ const newResp = truncateValue(resp);
339220
+ if (newResp !== resp) {
339221
+ return {
339222
+ ...part,
339223
+ functionResponse: {
339224
+ // eslint-disable-next-line @typescript-eslint/no-misused-spread
339225
+ ...part.functionResponse,
339226
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
339227
+ response: newResp
339228
+ }
339229
+ };
339230
+ }
339231
+ }
339232
+ return part;
339233
+ }
339234
+
338810
339235
  // packages/core/src/agents/types.ts
338811
339236
  var AgentTerminateMode = /* @__PURE__ */ ((AgentTerminateMode2) => {
338812
339237
  AgentTerminateMode2["ERROR"] = "ERROR";
@@ -343369,7 +343794,7 @@ var A2AAuthProviderFactory = class _A2AAuthProviderFactory {
343369
343794
  return provider;
343370
343795
  }
343371
343796
  case "oauth2": {
343372
- const { OAuth2AuthProvider } = await import("./oauth2-provider-UY26FDAA.js");
343797
+ const { OAuth2AuthProvider } = await import("./oauth2-provider-KPLVYPVA.js");
343373
343798
  const provider = new OAuth2AuthProvider(
343374
343799
  authConfig,
343375
343800
  options.agentName ?? "unknown",
@@ -344616,72 +345041,6 @@ function getToolCallContext() {
344616
345041
  return toolCallContext.getStore();
344617
345042
  }
344618
345043
 
344619
- // packages/core/src/utils/tool-utils.ts
344620
- var import_fast_levenshtein2 = __toESM(require_levenshtein(), 1);
344621
- function isToolCallResponseInfo(data) {
344622
- return typeof data === "object" && data !== null && "callId" in data && "responseParts" in data;
344623
- }
344624
- function getToolSuggestion(unknownToolName, allToolNames, topN = 3) {
344625
- const matches = allToolNames.map((toolName) => ({
344626
- name: toolName,
344627
- distance: import_fast_levenshtein2.default.get(unknownToolName, toolName)
344628
- }));
344629
- matches.sort((a2, b) => a2.distance - b.distance);
344630
- const topNResults = matches.slice(0, topN);
344631
- if (topNResults.length === 0) {
344632
- return "";
344633
- }
344634
- const suggestedNames = topNResults.map((match2) => `"${match2.name}"`).join(", ");
344635
- if (topNResults.length > 1) {
344636
- return ` Did you mean one of: ${suggestedNames}?`;
344637
- } else {
344638
- return ` Did you mean ${suggestedNames}?`;
344639
- }
344640
- }
344641
- function doesToolInvocationMatch(toolOrToolName, invocation, patterns) {
344642
- let toolNames;
344643
- if (isTool(toolOrToolName)) {
344644
- toolNames = [toolOrToolName.name, toolOrToolName.constructor.name];
344645
- } else {
344646
- toolNames = [toolOrToolName];
344647
- }
344648
- if (toolNames.some((name3) => SHELL_TOOL_NAMES.includes(name3))) {
344649
- toolNames = [.../* @__PURE__ */ new Set([...toolNames, ...SHELL_TOOL_NAMES])];
344650
- }
344651
- for (const pattern of patterns) {
344652
- const openParen = pattern.indexOf("(");
344653
- if (openParen === -1) {
344654
- if (toolNames.includes(pattern)) {
344655
- return true;
344656
- }
344657
- continue;
344658
- }
344659
- const patternToolName = pattern.substring(0, openParen);
344660
- if (!toolNames.includes(patternToolName)) {
344661
- continue;
344662
- }
344663
- if (!pattern.endsWith(")")) {
344664
- continue;
344665
- }
344666
- const argPattern = pattern.substring(openParen + 1, pattern.length - 1);
344667
- let command;
344668
- if (typeof invocation === "string") {
344669
- command = invocation;
344670
- } else {
344671
- if (!("command" in invocation.params)) {
344672
- continue;
344673
- }
344674
- command = String(invocation.params.command);
344675
- }
344676
- if (toolNames.some((name3) => SHELL_TOOL_NAMES.includes(name3))) {
344677
- if (command === argPattern || command.startsWith(argPattern + " ")) {
344678
- return true;
344679
- }
344680
- }
344681
- }
344682
- return false;
344683
- }
344684
-
344685
345044
  // packages/core/src/scheduler/state-manager.ts
344686
345045
  var SchedulerStateManager = class {
344687
345046
  constructor(messageBus, schedulerId = ROOT_SCHEDULER_ID, onTerminalCall) {
@@ -346573,7 +346932,7 @@ ${summary}
346573
346932
 
346574
346933
  // packages/core/src/context/toolOutputMaskingService.ts
346575
346934
  import path68 from "node:path";
346576
- import * as fsPromises10 from "node:fs/promises";
346935
+ import * as fsPromises11 from "node:fs/promises";
346577
346936
  var DEFAULT_TOOL_PROTECTION_THRESHOLD = 5e4;
346578
346937
  var DEFAULT_MIN_PRUNABLE_TOKENS_THRESHOLD = 3e4;
346579
346938
  var DEFAULT_PROTECT_LATEST_TURN = true;
@@ -346654,7 +347013,7 @@ var ToolOutputMaskingService = class {
346654
347013
  const safeSessionId = sanitizeFilenamePart(sessionId);
346655
347014
  toolOutputsDir = path68.join(toolOutputsDir, `session-${safeSessionId}`);
346656
347015
  }
346657
- await fsPromises10.mkdir(toolOutputsDir, { recursive: true });
347016
+ await fsPromises11.mkdir(toolOutputsDir, { recursive: true });
346658
347017
  for (const item of prunableParts) {
346659
347018
  const { contentIndex, partIndex, content, tokens } = item;
346660
347019
  const contentRecord = newHistory[contentIndex];
@@ -346666,7 +347025,7 @@ var ToolOutputMaskingService = class {
346666
347025
  const safeCallId = sanitizeFilenamePart(callId).toLowerCase();
346667
347026
  const fileName = `${safeToolName}_${safeCallId}_${Math.random().toString(36).substring(7)}.txt`;
346668
347027
  const filePath = path68.join(toolOutputsDir, fileName);
346669
- await fsPromises10.writeFile(filePath, content, "utf-8");
347028
+ await fsPromises11.writeFile(filePath, content, "utf-8");
346670
347029
  const originalResponse = (
346671
347030
  // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
346672
347031
  part.functionResponse.response || {}
@@ -350239,6 +350598,15 @@ var GeminiClient = class {
350239
350598
  );
350240
350599
  }
350241
350600
  async resumeChat(history, resumedSessionData) {
350601
+ if (resumedSessionData?.filePath) {
350602
+ const previousRecordingService = this.chat?.getChatRecordingService?.();
350603
+ if (previousRecordingService && previousRecordingService.getConversationFilePath?.() !== resumedSessionData.filePath) {
350604
+ try {
350605
+ await previousRecordingService.deleteCurrentSessionIfNotResumableAsync?.();
350606
+ } catch {
350607
+ }
350608
+ }
350609
+ }
350242
350610
  this.chat = await this.startChat(history, resumedSessionData);
350243
350611
  this.updateTelemetryTokenCount();
350244
350612
  }
@@ -351311,7 +351679,7 @@ var ToolExecutor = class {
351311
351679
  this.context.promptId
351312
351680
  );
351313
351681
  outputFile = savedPath;
351314
- const truncatedContent = formatTruncatedToolOutput(
351682
+ let truncatedContent = formatTruncatedToolOutput(
351315
351683
  content,
351316
351684
  outputFile,
351317
351685
  threshold
@@ -351325,6 +351693,12 @@ var ToolExecutor = class {
351325
351693
  threshold
351326
351694
  })
351327
351695
  );
351696
+ if (typeof truncatedContent === "string" && Buffer.byteLength(truncatedContent, "utf8") > MAX_STORED_TOOL_OUTPUT_BYTES) {
351697
+ truncatedContent = truncateToolOutput(
351698
+ truncatedContent,
351699
+ MAX_STORED_TOOL_OUTPUT_BYTES
351700
+ );
351701
+ }
351328
351702
  return { truncatedContent, outputFile };
351329
351703
  }
351330
351704
  } else if (Array.isArray(content) && content.length === 1 && "tool" in call && call.tool instanceof DiscoveredMCPTool) {
@@ -351342,11 +351716,17 @@ var ToolExecutor = class {
351342
351716
  this.context.promptId
351343
351717
  );
351344
351718
  outputFile = savedPath;
351345
- const truncatedText = formatTruncatedToolOutput(
351719
+ let truncatedText = formatTruncatedToolOutput(
351346
351720
  textContent2,
351347
351721
  outputFile,
351348
351722
  threshold
351349
351723
  );
351724
+ if (typeof truncatedText === "string" && Buffer.byteLength(truncatedText, "utf8") > MAX_STORED_TOOL_OUTPUT_BYTES) {
351725
+ truncatedText = truncateToolOutput(
351726
+ truncatedText,
351727
+ MAX_STORED_TOOL_OUTPUT_BYTES
351728
+ );
351729
+ }
351350
351730
  const truncatedContent = [
351351
351731
  { ...firstPart, text: truncatedText }
351352
351732
  ];
@@ -351363,7 +351743,69 @@ var ToolExecutor = class {
351363
351743
  }
351364
351744
  }
351365
351745
  }
351366
- return { truncatedContent: content, outputFile };
351746
+ const ensureOutputFile = async (rawText) => {
351747
+ if (!outputFile) {
351748
+ try {
351749
+ const { outputFile: savedPath } = await saveTruncatedToolOutput(
351750
+ rawText,
351751
+ toolName,
351752
+ callId,
351753
+ this.config.storage.getProjectTempDir(),
351754
+ this.context.promptId
351755
+ );
351756
+ outputFile = savedPath;
351757
+ } catch {
351758
+ }
351759
+ }
351760
+ return outputFile;
351761
+ };
351762
+ let finalContent = content;
351763
+ if (typeof finalContent === "string") {
351764
+ if (Buffer.byteLength(finalContent, "utf8") > MAX_STORED_TOOL_OUTPUT_BYTES) {
351765
+ const savedPath = await ensureOutputFile(finalContent);
351766
+ finalContent = truncateToolOutput(
351767
+ finalContent,
351768
+ MAX_STORED_TOOL_OUTPUT_BYTES,
351769
+ savedPath
351770
+ );
351771
+ }
351772
+ } else if (Array.isArray(finalContent)) {
351773
+ finalContent = await Promise.all(
351774
+ finalContent.map(async (part) => {
351775
+ if (typeof part === "string" && Buffer.byteLength(part, "utf8") > MAX_STORED_TOOL_OUTPUT_BYTES) {
351776
+ const savedPath = await ensureOutputFile(part);
351777
+ return truncateToolOutput(
351778
+ part,
351779
+ MAX_STORED_TOOL_OUTPUT_BYTES,
351780
+ savedPath
351781
+ );
351782
+ }
351783
+ if (typeof part === "object" && part !== null && "text" in part && typeof part.text === "string" && Buffer.byteLength(part.text, "utf8") > MAX_STORED_TOOL_OUTPUT_BYTES) {
351784
+ const savedPath = await ensureOutputFile(part.text);
351785
+ return {
351786
+ ...part,
351787
+ text: truncateToolOutput(
351788
+ part.text,
351789
+ MAX_STORED_TOOL_OUTPUT_BYTES,
351790
+ savedPath
351791
+ )
351792
+ };
351793
+ }
351794
+ return part;
351795
+ })
351796
+ );
351797
+ } else if (typeof finalContent === "object" && finalContent !== null && "text" in finalContent && typeof finalContent.text === "string" && Buffer.byteLength(finalContent.text, "utf8") > MAX_STORED_TOOL_OUTPUT_BYTES) {
351798
+ const savedPath = await ensureOutputFile(finalContent.text);
351799
+ finalContent = {
351800
+ ...finalContent,
351801
+ text: truncateToolOutput(
351802
+ finalContent.text,
351803
+ MAX_STORED_TOOL_OUTPUT_BYTES,
351804
+ savedPath
351805
+ )
351806
+ };
351807
+ }
351808
+ return { truncatedContent: finalContent, outputFile };
351367
351809
  }
351368
351810
  async createCancelledResult(call, reason, toolResult) {
351369
351811
  const errorMessage = `[Operation Cancelled] ${reason}`;
@@ -351564,6 +352006,9 @@ var ToolModificationHandler = class {
351564
352006
  };
351565
352007
 
351566
352008
  // packages/core/src/scheduler/scheduler.ts
352009
+ function isTaintRiskDetectable(invocation) {
352010
+ return typeof invocation === "object" && invocation !== null && "hasTaintedOrBuildFileRisk" in invocation && typeof invocation.hasTaintedOrBuildFileRisk === "function";
352011
+ }
351567
352012
  var createErrorResponse = (request, error40, errorType) => ({
351568
352013
  callId: request.callId,
351569
352014
  error: error40,
@@ -352004,6 +352449,10 @@ var Scheduler = class {
352004
352449
  if (hookDecision === "ask") {
352005
352450
  decision = "ask_user" /* ASK_USER */;
352006
352451
  }
352452
+ const hasTaintRisk = isTaintRiskDetectable(toolCall.invocation) && toolCall.invocation.hasTaintedOrBuildFileRisk();
352453
+ if (decision === "allow" /* ALLOW */ && hasTaintRisk) {
352454
+ decision = this.config.isInteractive?.() ?? true ? "ask_user" /* ASK_USER */ : "deny" /* DENY */;
352455
+ }
352007
352456
  if (decision === "deny" /* DENY */) {
352008
352457
  const { errorMessage, errorType } = getPolicyDenialError(
352009
352458
  this.config,
@@ -352023,6 +352472,7 @@ var Scheduler = class {
352023
352472
  let outcome = "proceed_once" /* ProceedOnce */;
352024
352473
  let lastDetails;
352025
352474
  if (decision === "ask_user" /* ASK_USER */) {
352475
+ const forcedDecision = hookDecision === "ask" || policyDecision === "allow" /* ALLOW */ && hasTaintRisk ? "ask_user" : void 0;
352026
352476
  const result2 = await resolveConfirmation(toolCall, signal, {
352027
352477
  config: this.config,
352028
352478
  messageBus: this.messageBus,
@@ -352032,7 +352482,7 @@ var Scheduler = class {
352032
352482
  schedulerId: this.schedulerId,
352033
352483
  onWaitingForConfirmation: this.onWaitingForConfirmation,
352034
352484
  systemMessage: hookSystemMessage,
352035
- forcedDecision: hookDecision === "ask" ? "ask_user" : void 0
352485
+ forcedDecision
352036
352486
  });
352037
352487
  outcome = result2.outcome;
352038
352488
  lastDetails = result2.lastDetails;
@@ -352360,14 +352810,14 @@ function normalizeSpace(text) {
352360
352810
  return text.replace(/\s+/g, " ").trim();
352361
352811
  }
352362
352812
  function safeSlice(text, start2, end) {
352363
- const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
352364
- const segments = Array.from(segmenter.segment(text));
352813
+ const segmenter2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
352814
+ const segments = Array.from(segmenter2.segment(text));
352365
352815
  return segments.slice(start2, end).map((s2) => s2.segment).join("");
352366
352816
  }
352367
352817
  function safeLength(text) {
352368
- const segmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
352818
+ const segmenter2 = new Intl.Segmenter(void 0, { granularity: "grapheme" });
352369
352819
  let count2 = 0;
352370
- for (const _ of segmenter.segment(text)) {
352820
+ for (const _ of segmenter2.segment(text)) {
352371
352821
  count2++;
352372
352822
  }
352373
352823
  return count2;
@@ -353616,6 +354066,22 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
353616
354066
  }
353617
354067
  async tryCompressChat(chat, prompt_id, abortSignal) {
353618
354068
  const model = this.definition.modelConfig.model ?? DEFAULT_GEMINI_MODEL;
354069
+ const threshold = await this.context.config.getCompressionThreshold() ?? DEFAULT_COMPRESSION_TOKEN_THRESHOLD;
354070
+ const modelLimit = tokenLimit(model);
354071
+ const lastPromptTokenCount = chat.getLastPromptTokenCount();
354072
+ const currentHistory = chat.getHistory(false);
354073
+ const originalTokenCount = lastPromptTokenCount > 0 ? lastPromptTokenCount : estimateTokenCountSync(currentHistory.flatMap((c4) => c4.parts || []));
354074
+ if (originalTokenCount >= threshold * modelLimit) {
354075
+ const collapsedHistory = collapseOlderFunctionResponses(currentHistory);
354076
+ if (collapsedHistory !== currentHistory) {
354077
+ const existingTurns = chat.getHistoryTurns?.(false) ?? [];
354078
+ const turns = collapsedHistory.map((c4, idx) => ({
354079
+ id: existingTurns[idx]?.id ?? randomUUID13(),
354080
+ content: c4
354081
+ }));
354082
+ chat.setHistory(turns);
354083
+ }
354084
+ }
353619
354085
  const { newHistory, info: info2 } = await this.compressionService.compress(
353620
354086
  chat,
353621
354087
  prompt_id,
@@ -353629,8 +354095,9 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
353629
354095
  this.hasFailedCompressionAttempt = true;
353630
354096
  } else if (info2.compressionStatus === 1 /* COMPRESSED */) {
353631
354097
  if (newHistory) {
353632
- const turns = newHistory.map((c4) => ({
353633
- id: randomUUID13(),
354098
+ const existingTurns = chat.getHistoryTurns?.(false) ?? [];
354099
+ const turns = newHistory.map((c4, idx) => ({
354100
+ id: existingTurns[idx]?.id ?? randomUUID13(),
353634
354101
  content: c4
353635
354102
  }));
353636
354103
  chat.setHistory(turns);
@@ -353638,8 +354105,9 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
353638
354105
  }
353639
354106
  } else if (info2.compressionStatus === 6 /* CONTENT_TRUNCATED */) {
353640
354107
  if (newHistory) {
353641
- const turns = newHistory.map((c4) => ({
353642
- id: randomUUID13(),
354108
+ const existingTurns = chat.getHistoryTurns?.(false) ?? [];
354109
+ const turns = newHistory.map((c4, idx) => ({
354110
+ id: existingTurns[idx]?.id ?? randomUUID13(),
353643
354111
  content: c4
353644
354112
  }));
353645
354113
  chat.setHistory(turns);
@@ -353850,6 +354318,25 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
353850
354318
  onWaitingForConfirmation
353851
354319
  }
353852
354320
  );
354321
+ for (const call of completedCalls) {
354322
+ const outputFile = call.response?.outputFile;
354323
+ if (call.response?.responseParts) {
354324
+ call.response.responseParts = call.response.responseParts.map(
354325
+ (p) => truncateFunctionResponsePart(
354326
+ p,
354327
+ MAX_STORED_TOOL_OUTPUT_BYTES,
354328
+ outputFile
354329
+ )
354330
+ );
354331
+ }
354332
+ if (typeof call.response?.resultDisplay === "string" && Buffer.byteLength(call.response.resultDisplay, "utf8") > MAX_STORED_TOOL_OUTPUT_BYTES) {
354333
+ call.response.resultDisplay = truncateToolOutput(
354334
+ call.response.resultDisplay,
354335
+ MAX_STORED_TOOL_OUTPUT_BYTES,
354336
+ outputFile
354337
+ );
354338
+ }
354339
+ }
353853
354340
  chat.recordCompletedToolCalls(model, completedCalls);
353854
354341
  for (const call of completedCalls) {
353855
354342
  const toolName = toolNameMap.get(call.request.callId) || call.request.name;
@@ -353915,7 +354402,9 @@ var LocalAgentExecutor = class _LocalAgentExecutor {
353915
354402
  const callId = functionCall.id ?? `${promptId}-${index}`;
353916
354403
  const part = syncResults.get(callId);
353917
354404
  if (part) {
353918
- toolResponseParts.push(part);
354405
+ toolResponseParts.push(
354406
+ truncateFunctionResponsePart(part, MAX_STORED_TOOL_OUTPUT_BYTES)
354407
+ );
353919
354408
  continue;
353920
354409
  }
353921
354410
  const isAborted2 = signal.aborted;
@@ -367717,9 +368206,12 @@ var PolicyEngine = class {
367717
368206
  isAlwaysAllowRule(rule) {
367718
368207
  return rule.priority !== void 0 && Math.round(rule.priority % 1 * 1e3) === ALWAYS_ALLOW_PRIORITY_FRACTION;
367719
368208
  }
367720
- shouldDowngradeForRedirection(command, allowRedirection) {
368209
+ shouldDowngradeForRedirection(command, allowRedirection, rule) {
367721
368210
  if (allowRedirection) return false;
367722
368211
  if (!hasRedirection(command)) return false;
368212
+ if (rule?.argsPattern && !allowRedirection) {
368213
+ return true;
368214
+ }
367723
368215
  if (this.approvalMode === "autoEdit" /* AUTO_EDIT */ || this.approvalMode === "yolo" /* YOLO */) {
367724
368216
  return false;
367725
368217
  }
@@ -367826,7 +368318,7 @@ var PolicyEngine = class {
367826
368318
  }
367827
368319
  let aggregateDecision = ruleDecision;
367828
368320
  let responsibleRule = rule && ruleDecision === rule.decision ? rule : void 0;
367829
- if (this.shouldDowngradeForRedirection(command, allowRedirection)) {
368321
+ if (this.shouldDowngradeForRedirection(command, allowRedirection, rule)) {
367830
368322
  if (aggregateDecision === "allow" /* ALLOW */) {
367831
368323
  debugLogger.debug(
367832
368324
  `[PolicyEngine.check] Downgrading ALLOW to ASK_USER for redirected command: ${command}`
@@ -367878,7 +368370,11 @@ var PolicyEngine = class {
367878
368370
  }
367879
368371
  aggregateDecision = "ask_user" /* ASK_USER */;
367880
368372
  }
367881
- if (subResult.decision === "allow" /* ALLOW */ && this.shouldDowngradeForRedirection(subCmd, allowRedirection)) {
368373
+ if (subResult.decision === "allow" /* ALLOW */ && this.shouldDowngradeForRedirection(
368374
+ subCmd,
368375
+ subResult.rule?.allowRedirection ?? allowRedirection,
368376
+ subResult.rule
368377
+ )) {
367882
368378
  if (aggregateDecision === "allow" /* ALLOW */) {
367883
368379
  aggregateDecision = "ask_user" /* ASK_USER */;
367884
368380
  responsibleRule = void 0;
@@ -368134,6 +368630,9 @@ var PolicyEngine = class {
368134
368630
  }
368135
368631
  }
368136
368632
  }
368633
+ if (this.nonInteractive && decision === "ask_user" /* ASK_USER */) {
368634
+ decision = "deny" /* DENY */;
368635
+ }
368137
368636
  return {
368138
368637
  decision,
368139
368638
  rule: matchedRule
@@ -371042,7 +371541,7 @@ var SecurityValidator = class {
371042
371541
  };
371043
371542
  function getWindowsPowerShellPath() {
371044
371543
  let systemRoot = process.env["SystemRoot"] || process.env["systemroot"] || process.env["windir"] || process.env["WINDIR"] || "C:\\Windows";
371045
- if (!/^[a-zA-Z]:\\/.test(systemRoot)) {
371544
+ if (!/^[a-zA-Z]:\\Windows\\?$/i.test(systemRoot) || systemRoot.includes("..")) {
371046
371545
  systemRoot = "C:\\Windows";
371047
371546
  }
371048
371547
  const pathModule = os33.platform() === "win32" ? path87.win32 : path87.posix;
@@ -372379,7 +372878,8 @@ import * as fs77 from "node:fs";
372379
372878
 
372380
372879
  // packages/core/src/safety/built-in.ts
372381
372880
  import * as path89 from "node:path";
372382
- var VSCODE_SFN_REGEX = /^(vscode|vs[0-9a-f]{4})~\d+$/;
372881
+ var VSCODE_SFN_REGEX = /^(vscode|vs[0-9a-f]{4})~\d+(\..+)?$/i;
372882
+ var GEMINI_SFN_REGEX = /^(gemini|ge[0-9a-f]{4})~\d+(\..+)?$/i;
372383
372883
  var AllowedPathChecker = class {
372384
372884
  async check(input) {
372385
372885
  const { toolCall, context: context2 } = input;
@@ -372406,6 +372906,7 @@ var AllowedPathChecker = class {
372406
372906
  }
372407
372907
  let hasBlockedSegment = false;
372408
372908
  let isVscodePath = false;
372909
+ let isGeminiPath = false;
372409
372910
  for (const resolvedDir of resolvedAllowedDirs) {
372410
372911
  if (!this.isPathAllowed(resolvedPath, resolvedDir)) continue;
372411
372912
  const relative12 = path89.relative(resolvedDir, resolvedPath);
@@ -372420,6 +372921,9 @@ var AllowedPathChecker = class {
372420
372921
  if (clean === ".vscode" || VSCODE_SFN_REGEX.test(clean)) {
372421
372922
  isVscodePath = true;
372422
372923
  }
372924
+ if (clean === ".gemini" || GEMINI_SFN_REGEX.test(clean)) {
372925
+ isGeminiPath = true;
372926
+ }
372423
372927
  }
372424
372928
  }
372425
372929
  if (hasBlockedSegment) {
@@ -372428,6 +372932,12 @@ var AllowedPathChecker = class {
372428
372932
  reason: `Access to sensitive path "${p}" in argument "${argName}" is blocked.`
372429
372933
  };
372430
372934
  }
372935
+ if (isGeminiPath) {
372936
+ return {
372937
+ decision: "ask_user" /* ASK_USER */,
372938
+ reason: `Modifying .gemini configuration files requires explicit user confirmation.`
372939
+ };
372940
+ }
372431
372941
  if (isVscodePath) {
372432
372942
  return {
372433
372943
  decision: "ask_user" /* ASK_USER */,
@@ -397080,7 +397590,7 @@ var LegacyAgentSession = class extends AgentSession {
397080
397590
  };
397081
397591
 
397082
397592
  // packages/core/src/tools/read-many-files.ts
397083
- import * as fsPromises11 from "node:fs/promises";
397593
+ import * as fsPromises12 from "node:fs/promises";
397084
397594
  import * as path107 from "node:path";
397085
397595
  function getDefaultExcludes(config2) {
397086
397596
  return config2?.getFileExclusions().getReadManyFilesExcludes() ?? [];
@@ -397133,7 +397643,7 @@ ${finalExclusionPatternsForDescription.slice(0, 2).join(
397133
397643
  const fullPath = path107.join(dir, normalizedP);
397134
397644
  let exists2 = false;
397135
397645
  try {
397136
- const st = await fsPromises11.stat(fullPath);
397646
+ const st = await fsPromises12.stat(fullPath);
397137
397647
  exists2 = st.isFile();
397138
397648
  } catch {
397139
397649
  exists2 = false;
@@ -405236,6 +405746,7 @@ export {
405236
405746
  DEFAULT_MAX_LINES_TEXT_FILE,
405237
405747
  MAX_LINE_LENGTH_TEXT_FILE,
405238
405748
  MAX_FILE_SIZE_MB,
405749
+ MAX_STORED_TOOL_OUTPUT_BYTES,
405239
405750
  EMPTY_RESPONSE_COMPRESS_SUGGESTION,
405240
405751
  THINKING_ONLY_COMPRESS_SUGGESTION,
405241
405752
  MAX_TOKENS_EXCEEDED_SUGGESTION,
@@ -405247,6 +405758,7 @@ export {
405247
405758
  loadWasmBinary,
405248
405759
  DEFAULT_ENCODING,
405249
405760
  detectBOM,
405761
+ readSecureFileBuffer,
405250
405762
  readFileWithEncoding,
405251
405763
  getSpecificMimeType,
405252
405764
  canonicalizeMacosPath,
@@ -406009,6 +406521,11 @@ export {
406009
406521
  SessionStartSource,
406010
406522
  SessionEndReason,
406011
406523
  PreCompressTrigger,
406524
+ isToolCallResponseInfo,
406525
+ getToolSuggestion,
406526
+ doesToolInvocationMatch,
406527
+ truncateToolOutput,
406528
+ truncateFunctionResponsePart,
406012
406529
  AgentTerminateMode,
406013
406530
  DEFAULT_QUERY_STRING,
406014
406531
  DEFAULT_MAX_TURNS,
@@ -406043,9 +406560,6 @@ export {
406043
406560
  exchangeCodeForToken,
406044
406561
  refreshAccessToken,
406045
406562
  ModelConfigService,
406046
- isToolCallResponseInfo,
406047
- getToolSuggestion,
406048
- doesToolInvocationMatch,
406049
406563
  getPolicyDenialError,
406050
406564
  checkPolicy,
406051
406565
  updatePolicy,
@@ -406155,6 +406669,7 @@ export {
406155
406669
  createPathSecurityCache,
406156
406670
  clearSecurityCacheForTesting,
406157
406671
  SecurityValidator,
406672
+ getWindowsPowerShellPath,
406158
406673
  isDirectorySecure,
406159
406674
  normalizeSecurityPath,
406160
406675
  isPathSecureSync,