@google/gemini-cli 0.36.0 → 0.37.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.
Files changed (74) hide show
  1. package/bundle/{chunk-UNM3DGTG.js → chunk-33B2YA3V.js} +711 -240
  2. package/bundle/{chunk-2OFO4ODK.js → chunk-43UUP7VO.js} +6717 -4203
  3. package/bundle/{chunk-MYI75E6G.js → chunk-5OOT636U.js} +262 -92
  4. package/bundle/{chunk-GHJNEZXJ.js → chunk-BLL44IGV.js} +777 -294
  5. package/bundle/{chunk-S2IQOR7T.js → chunk-JS5WSGB2.js} +243 -88
  6. package/bundle/{chunk-QVTX2M5J.js → chunk-PPWUMHZT.js} +6355 -4117
  7. package/bundle/chunk-TSSVZ7RZ.js +98376 -0
  8. package/bundle/chunk-U4FACSVX.js +30 -0
  9. package/bundle/{chunk-VB55KQW3.js → chunk-VSXV53B7.js} +11735 -14377
  10. package/bundle/{chunk-EAXTBDLN.js → chunk-WZB27TDF.js} +711 -240
  11. package/bundle/chunk-ZB4UQCX5.js +356418 -0
  12. package/bundle/{core-6V2OYDRU.js → core-RMRIZ3E5.js} +60 -4
  13. package/bundle/{devtoolsService-ZKU2HLK2.js → devtoolsService-2ULAA43E.js} +20 -3
  14. package/bundle/{devtoolsService-UL6JE436.js → devtoolsService-AWVCG2N2.js} +22 -4
  15. package/bundle/devtoolsService-IWSTJYRB.js +871 -0
  16. package/bundle/{devtoolsService-QTW7GHQP.js → devtoolsService-SZYXXACN.js} +20 -3
  17. package/bundle/{core-BMLL5RF4.js → dist-4FKFY6XB.js} +60 -4
  18. package/bundle/{dist-PYC2JXAJ.js → dist-PRDBNGX2.js} +60 -4
  19. package/bundle/dist-TCCEQJDV.js +1942 -0
  20. package/bundle/docs/CONTRIBUTING.md +10 -7
  21. package/bundle/docs/assets/theme-tokyonight-dark.png +0 -0
  22. package/bundle/docs/changelogs/index.md +24 -0
  23. package/bundle/docs/changelogs/latest.md +366 -459
  24. package/bundle/docs/changelogs/preview.md +362 -356
  25. package/bundle/docs/cli/acp-mode.md +126 -0
  26. package/bundle/docs/cli/cli-reference.md +1 -1
  27. package/bundle/docs/cli/notifications.md +5 -5
  28. package/bundle/docs/cli/plan-mode.md +22 -11
  29. package/bundle/docs/cli/sandbox.md +1 -1
  30. package/bundle/docs/cli/settings.md +14 -13
  31. package/bundle/docs/cli/themes.md +5 -0
  32. package/bundle/docs/core/index.md +2 -2
  33. package/bundle/docs/core/subagents.md +134 -23
  34. package/bundle/docs/get-started/gemini-3.md +1 -1
  35. package/bundle/docs/get-started/index.md +127 -1
  36. package/bundle/docs/ide-integration/index.md +99 -24
  37. package/bundle/docs/index.md +0 -2
  38. package/bundle/docs/redirects.json +1 -0
  39. package/bundle/docs/reference/commands.md +1 -3
  40. package/bundle/docs/reference/configuration.md +182 -91
  41. package/bundle/docs/reference/keyboard-shortcuts.md +14 -6
  42. package/bundle/docs/reference/policy-engine.md +36 -31
  43. package/bundle/docs/reference/tools.md +56 -23
  44. package/bundle/docs/resources/quota-and-pricing.md +23 -9
  45. package/bundle/docs/sidebar.json +11 -4
  46. package/bundle/docs/tools/planning.md +6 -4
  47. package/bundle/events-CLX3JQHP.js +12 -0
  48. package/bundle/gemini.js +342 -52
  49. package/bundle/{interactiveCli-VLQHRXHU.js → interactiveCli-24VGI5NV.js} +5066 -4010
  50. package/bundle/{interactiveCli-A6HZ2TDO.js → interactiveCli-D2MTTARB.js} +5066 -4010
  51. package/bundle/{interactiveCli-DWMSDCKV.js → interactiveCli-DX76MWWT.js} +5296 -4223
  52. package/bundle/interactiveCli-VNDJAKWG.js +50355 -0
  53. package/bundle/{memoryDiscovery-BQGYT4OD.js → memoryDiscovery-A265O6ML.js} +3 -1
  54. package/bundle/{memoryDiscovery-FCEPFZ3M.js → memoryDiscovery-H6J7KIH2.js} +3 -1
  55. package/bundle/node_modules/@google/gemini-cli-devtools/dist/client/main.js +26 -19
  56. package/bundle/node_modules/@google/gemini-cli-devtools/dist/src/_client-assets.d.ts +1 -1
  57. package/bundle/node_modules/@google/gemini-cli-devtools/dist/src/_client-assets.js +1 -1
  58. package/bundle/node_modules/@google/gemini-cli-devtools/dist/src/_client-assets.js.map +1 -1
  59. package/bundle/node_modules/@google/gemini-cli-devtools/dist/src/index.js +35 -1
  60. package/bundle/node_modules/@google/gemini-cli-devtools/dist/src/index.js.map +1 -1
  61. package/bundle/node_modules/@google/gemini-cli-devtools/package.json +1 -1
  62. package/bundle/{oauth2-provider-5ENESIRQ.js → oauth2-provider-FZUTS3SV.js} +2 -2
  63. package/bundle/{oauth2-provider-CAKFQRQV.js → oauth2-provider-K25DXIWC.js} +2 -2
  64. package/bundle/{oauth2-provider-RVED6DAZ.js → oauth2-provider-N73M7SQI.js} +39 -73
  65. package/bundle/oauth2-provider-RMDEEXSP.js +237 -0
  66. package/bundle/policies/discovered.toml +7 -0
  67. package/bundle/policies/non-interactive.toml +7 -0
  68. package/bundle/policies/plan.toml +25 -0
  69. package/bundle/policies/read-only.toml +6 -0
  70. package/bundle/policies/sandbox-default.toml +3 -2
  71. package/bundle/policies/write.toml +21 -0
  72. package/bundle/policies/yolo.toml +1 -1
  73. package/package.json +1 -1
  74. package/bundle/docs/get-started/examples.md +0 -141
package/bundle/gemini.js CHANGED
@@ -16,7 +16,6 @@ import {
16
16
  SessionSelector,
17
17
  SettingScope,
18
18
  USER_SETTINGS_PATH,
19
- appEvents,
20
19
  canLoadServer,
21
20
  checkForAllExtensionUpdates,
22
21
  checkForExtensionUpdate,
@@ -67,7 +66,7 @@ import {
67
66
  updateAllUpdatableExtensions,
68
67
  updateExtension,
69
68
  validateAuthMethod
70
- } from "./chunk-UNM3DGTG.js";
69
+ } from "./chunk-TSSVZ7RZ.js";
71
70
  import {
72
71
  AuthType,
73
72
  ChatRecordingService,
@@ -79,6 +78,7 @@ import {
79
78
  FolderTrustDiscoveryService,
80
79
  GeminiEventType,
81
80
  IntegrityStatus,
81
+ InvalidStreamError,
82
82
  JsonFormatter,
83
83
  JsonStreamEventType,
84
84
  LlmRole,
@@ -139,6 +139,7 @@ import {
139
139
  patchStdio,
140
140
  performInit,
141
141
  performRestore,
142
+ processSingleFileContent,
142
143
  promptIdContext,
143
144
  recordToolCallInteractions,
144
145
  refreshMemory,
@@ -151,9 +152,10 @@ import {
151
152
  startupProfiler,
152
153
  stripAnsi,
153
154
  uiTelemetryService,
155
+ updatePolicy,
154
156
  writeToStderr,
155
157
  writeToStdout
156
- } from "./chunk-QVTX2M5J.js";
158
+ } from "./chunk-ZB4UQCX5.js";
157
159
  import {
158
160
  ASK_USER_TOOL_NAME,
159
161
  ApprovalMode,
@@ -177,6 +179,7 @@ import {
177
179
  GEMINI_MODEL_ALIAS_AUTO,
178
180
  Kind,
179
181
  PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL,
182
+ PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL,
180
183
  PREVIEW_GEMINI_3_1_MODEL,
181
184
  PREVIEW_GEMINI_FLASH_MODEL,
182
185
  PREVIEW_GEMINI_MODEL,
@@ -191,15 +194,18 @@ import {
191
194
  getCurrentGeminiMdFilename,
192
195
  getDisplayString,
193
196
  getErrorMessage,
197
+ getErrorType,
194
198
  homedir,
195
199
  isFatalToolError,
196
200
  isNodeError,
197
201
  loadServerHierarchicalMemory,
198
- resolveModel,
199
202
  resolveToRealPath,
200
203
  setGeminiMdFilename
201
- } from "./chunk-S2IQOR7T.js";
204
+ } from "./chunk-JS5WSGB2.js";
202
205
  import "./chunk-664ZODQF.js";
206
+ import {
207
+ appEvents
208
+ } from "./chunk-U4FACSVX.js";
203
209
  import "./chunk-RJTRUG2J.js";
204
210
  import "./chunk-IUUIT4SU.js";
205
211
  import {
@@ -7245,7 +7251,7 @@ async function loadSandboxConfig(settings, argv) {
7245
7251
  }
7246
7252
  const command2 = getSandboxCommand(sandboxValue);
7247
7253
  const packageJson = await getPackageJson(__dirname3);
7248
- const image = process.env["GEMINI_SANDBOX_IMAGE"] ?? "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.36.0" ?? customImage ?? packageJson?.config?.sandboxImageUri;
7254
+ const image = process.env["GEMINI_SANDBOX_IMAGE"] ?? "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.37.0-preview.1" ?? customImage ?? packageJson?.config?.sandboxImageUri;
7249
7255
  const isNative = command2 === "windows-native" || command2 === "sandbox-exec" || command2 === "lxc";
7250
7256
  return command2 && (image || isNative) ? { enabled: true, allowedPaths, networkAccess, command: command2, image } : void 0;
7251
7257
  }
@@ -7268,7 +7274,7 @@ function resolvePath(p) {
7268
7274
  // packages/cli/src/config/policy.ts
7269
7275
  var autoAcceptWorkspacePolicies = true;
7270
7276
  var disableWorkspacePolicies = true;
7271
- async function createPolicyEngineConfig2(settings, approvalMode, workspacePoliciesDir) {
7277
+ async function createPolicyEngineConfig2(settings, approvalMode, workspacePoliciesDir, interactive = true) {
7272
7278
  const policySettings = {
7273
7279
  mcp: settings.mcp,
7274
7280
  tools: settings.tools,
@@ -7278,7 +7284,12 @@ async function createPolicyEngineConfig2(settings, approvalMode, workspacePolici
7278
7284
  workspacePoliciesDir,
7279
7285
  disableAlwaysAllow: settings.security?.disableAlwaysAllow || settings.admin?.secureModeEnabled
7280
7286
  };
7281
- return createPolicyEngineConfig(policySettings, approvalMode);
7287
+ return createPolicyEngineConfig(
7288
+ policySettings,
7289
+ approvalMode,
7290
+ void 0,
7291
+ interactive
7292
+ );
7282
7293
  }
7283
7294
  function createPolicyUpdater2(policyEngine, messageBus, storage) {
7284
7295
  return createPolicyUpdater(policyEngine, messageBus, storage);
@@ -7682,7 +7693,8 @@ async function loadCliConfig(settings, sessionId2, argv, options = {}) {
7682
7693
  trustedFolder,
7683
7694
  memoryImportFormat,
7684
7695
  memoryFileFiltering,
7685
- settings.context?.discoveryMaxDirs
7696
+ settings.context?.discoveryMaxDirs,
7697
+ settings.context?.memoryBoundaryMarkers
7686
7698
  );
7687
7699
  memoryContent = result.memoryContent;
7688
7700
  fileCount = result.fileCount;
@@ -7700,9 +7712,9 @@ async function loadCliConfig(settings, sessionId2, argv, options = {}) {
7700
7712
  approvalMode = ApprovalMode.AUTO_EDIT;
7701
7713
  break;
7702
7714
  case "plan":
7703
- if (!(settings.experimental?.plan ?? false)) {
7715
+ if (!(settings.general?.plan?.enabled ?? true)) {
7704
7716
  debugLogger.warn(
7705
- 'Approval mode "plan" is only available when experimental.plan is enabled. Falling back to "default".'
7717
+ 'Approval mode "plan" is disabled in your settings. Falling back to "default".'
7706
7718
  );
7707
7719
  approvalMode = ApprovalMode.DEFAULT;
7708
7720
  } else {
@@ -7799,9 +7811,9 @@ async function loadCliConfig(settings, sessionId2, argv, options = {}) {
7799
7811
  const policyEngineConfig = await createPolicyEngineConfig2(
7800
7812
  effectiveSettings,
7801
7813
  approvalMode,
7802
- workspacePoliciesDir
7814
+ workspacePoliciesDir,
7815
+ interactive
7803
7816
  );
7804
- policyEngineConfig.nonInteractive = !interactive;
7805
7817
  const defaultModel = PREVIEW_GEMINI_MODEL_AUTO;
7806
7818
  const specifiedModel = argv.model || process3.env["GEMINI_MODEL"] || settings.model?.name;
7807
7819
  const resolvedModel = specifiedModel === GEMINI_MODEL_ALIAS_AUTO ? defaultModel : specifiedModel || defaultModel;
@@ -7875,6 +7887,7 @@ async function loadCliConfig(settings, sessionId2, argv, options = {}) {
7875
7887
  includeDirectories,
7876
7888
  loadMemoryFromIncludeDirectories: settings.context?.loadMemoryFromIncludeDirectories || false,
7877
7889
  discoveryMaxDirs: settings.context?.discoveryMaxDirs,
7890
+ memoryBoundaryMarkers: settings.context?.memoryBoundaryMarkers,
7878
7891
  importFormat: settings.context?.importFormat,
7879
7892
  debugMode,
7880
7893
  question,
@@ -7926,7 +7939,7 @@ async function loadCliConfig(settings, sessionId2, argv, options = {}) {
7926
7939
  extensionRegistryURI,
7927
7940
  enableExtensionReloading: settings.experimental?.extensionReloading,
7928
7941
  enableAgents: settings.experimental?.enableAgents,
7929
- plan: settings.experimental?.plan,
7942
+ plan: settings.general?.plan?.enabled ?? true,
7930
7943
  tracker: settings.experimental?.taskTracker,
7931
7944
  directWebFetch: settings.experimental?.directWebFetch,
7932
7945
  planSettings: settings.general?.plan?.directory ? settings.general.plan : extensionPlanSettings ?? settings.general?.plan,
@@ -7935,9 +7948,12 @@ async function loadCliConfig(settings, sessionId2, argv, options = {}) {
7935
7948
  disabledSkills: settings.skills?.disabled,
7936
7949
  experimentalJitContext: settings.experimental?.jitContext,
7937
7950
  experimentalMemoryManager: settings.experimental?.memoryManager,
7951
+ contextManagement: {
7952
+ enabled: settings.experimental?.contextManagement,
7953
+ ...settings?.contextManagement
7954
+ },
7938
7955
  modelSteering: settings.experimental?.modelSteering,
7939
7956
  topicUpdateNarration: settings.experimental?.topicUpdateNarration,
7940
- toolOutputMasking: settings.experimental?.toolOutputMasking,
7941
7957
  noBrowser: !!process3.env["NO_BROWSER"],
7942
7958
  summarizeToolOutput: settings.model?.summarizeToolOutput,
7943
7959
  ideMode,
@@ -7950,6 +7966,7 @@ async function loadCliConfig(settings, sessionId2, argv, options = {}) {
7950
7966
  useAlternateBuffer: settings.ui?.useAlternateBuffer,
7951
7967
  useRipgrep: settings.tools?.useRipgrep,
7952
7968
  enableInteractiveShell: settings.tools?.shell?.enableInteractiveShell,
7969
+ shellBackgroundCompletionBehavior: settings.tools?.shell?.backgroundCompletionBehavior,
7953
7970
  shellToolInactivityTimeout: settings.tools?.shell?.inactivityTimeout,
7954
7971
  enableShellOutputEfficiency: settings.tools?.shell?.enableShellOutputEfficiency ?? true,
7955
7972
  skipNextSpeakerCheck: settings.model?.skipNextSpeakerCheck,
@@ -9233,7 +9250,7 @@ function createNonInteractiveUI() {
9233
9250
  },
9234
9251
  removeComponent: () => {
9235
9252
  },
9236
- toggleBackgroundShell: () => {
9253
+ toggleBackgroundTasks: () => {
9237
9254
  },
9238
9255
  toggleShortcutsHelp: () => {
9239
9256
  }
@@ -9335,7 +9352,7 @@ function handleError(error, config, customErrorCode) {
9335
9352
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
9336
9353
  status: "error",
9337
9354
  error: {
9338
- type: error instanceof Error ? error.constructor.name : "Error",
9355
+ type: getErrorType(error),
9339
9356
  message: errorMessage
9340
9357
  },
9341
9358
  stats: streamFormatter.convertToStreamStats(metrics, 0)
@@ -9401,7 +9418,7 @@ function handleCancellationError(config) {
9401
9418
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
9402
9419
  status: "error",
9403
9420
  error: {
9404
- type: "FatalCancellationError",
9421
+ type: getErrorType(cancellationError),
9405
9422
  message: cancellationError.message
9406
9423
  },
9407
9424
  stats: streamFormatter.convertToStreamStats(metrics, 0)
@@ -9436,7 +9453,7 @@ function handleMaxTurnsExceededError(config) {
9436
9453
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
9437
9454
  status: "error",
9438
9455
  error: {
9439
- type: "FatalTurnLimitedError",
9456
+ type: getErrorType(maxTurnsError),
9440
9457
  message: maxTurnsError.message
9441
9458
  },
9442
9459
  stats: streamFormatter.convertToStreamStats(metrics, 0)
@@ -9515,13 +9532,14 @@ async function runNonInteractive({
9515
9532
  return promptIdContext.run(prompt_id, async () => {
9516
9533
  const consolePatcher = new ConsolePatcher({
9517
9534
  stderr: true,
9535
+ interactive: false,
9518
9536
  debugMode: config.getDebugMode(),
9519
9537
  onNewMessage: (msg) => {
9520
9538
  coreEvents.emitConsoleLog(msg.type, msg.content);
9521
9539
  }
9522
9540
  });
9523
9541
  if (process.env["GEMINI_CLI_ACTIVITY_LOG_TARGET"]) {
9524
- const { setupInitialActivityLogger } = await import("./devtoolsService-ZKU2HLK2.js");
9542
+ const { setupInitialActivityLogger } = await import("./devtoolsService-IWSTJYRB.js");
9525
9543
  await setupInitialActivityLogger(config);
9526
9544
  }
9527
9545
  const { stdout: workingStdout } = createWorkingStdio();
@@ -12179,6 +12197,15 @@ var CommandHandler = class _CommandHandler {
12179
12197
  function hasMeta(obj) {
12180
12198
  return typeof obj === "object" && obj !== null && "_meta" in obj;
12181
12199
  }
12200
+ var RequestPermissionResponseSchema = external_exports.object({
12201
+ outcome: external_exports.discriminatedUnion("outcome", [
12202
+ external_exports.object({ outcome: external_exports.literal("cancelled") }),
12203
+ external_exports.object({
12204
+ outcome: external_exports.literal("selected"),
12205
+ optionId: external_exports.string()
12206
+ })
12207
+ ])
12208
+ });
12182
12209
  async function runAcpClient(config, settings, argv) {
12183
12210
  const { stdout: workingStdout } = createWorkingStdio();
12184
12211
  const stdout = Writable.toWeb(workingStdout);
@@ -12515,6 +12542,11 @@ var GeminiAgent = class _GeminiAgent {
12515
12542
  mcpServers: mergedMcpServers
12516
12543
  };
12517
12544
  const config = await loadCliConfig(settings, sessionId2, this.argv, { cwd });
12545
+ createPolicyUpdater2(
12546
+ config.getPolicyEngine(),
12547
+ config.messageBus,
12548
+ config.storage
12549
+ );
12518
12550
  return config;
12519
12551
  }
12520
12552
  async cancel(params) {
@@ -12697,10 +12729,17 @@ ${thought.description}`;
12697
12729
  }
12698
12730
  const functionCalls = [];
12699
12731
  try {
12700
- const model = resolveModel(
12701
- this.context.config.getModel(),
12702
- await this.context.config.getGemini31Launched?.() ?? false
12703
- );
12732
+ const routingContext = {
12733
+ history: chat.getHistory(
12734
+ /*curated=*/
12735
+ true
12736
+ ),
12737
+ request: nextMessage?.parts ?? [],
12738
+ signal: pendingSend.signal,
12739
+ requestedModel: this.context.config.getModel()
12740
+ };
12741
+ const router = this.context.config.getModelRouterService();
12742
+ const { model } = await router.route(routingContext);
12704
12743
  const responseStream = await chat.sendMessageStream(
12705
12744
  { model },
12706
12745
  nextMessage?.parts ?? [],
@@ -12767,6 +12806,28 @@ ${thought.description}`;
12767
12806
  if (pendingSend.signal.aborted || error instanceof Error && error.name === "AbortError") {
12768
12807
  return { stopReason: CoreToolCallStatus.Cancelled };
12769
12808
  }
12809
+ if (error instanceof InvalidStreamError || error && typeof error === "object" && "type" in error && error.type === "NO_RESPONSE_TEXT") {
12810
+ return {
12811
+ stopReason: "end_turn",
12812
+ _meta: {
12813
+ quota: {
12814
+ token_count: {
12815
+ input_tokens: totalInputTokens,
12816
+ output_tokens: totalOutputTokens
12817
+ },
12818
+ model_usage: Array.from(modelUsageMap.entries()).map(
12819
+ ([modelName, counts]) => ({
12820
+ model: modelName,
12821
+ token_count: {
12822
+ input_tokens: counts.input,
12823
+ output_tokens: counts.output
12824
+ }
12825
+ })
12826
+ )
12827
+ }
12828
+ }
12829
+ };
12830
+ }
12770
12831
  throw new RequestError(
12771
12832
  getErrorStatus(error) || 500,
12772
12833
  getAcpErrorMessage(error)
@@ -12892,7 +12953,8 @@ ${thought.description}`;
12892
12953
  sessionId: this.id,
12893
12954
  options: toPermissionOptions(
12894
12955
  confirmationDetails,
12895
- this.context.config
12956
+ this.context.config,
12957
+ this.settings.merged.security.enablePermanentToolApproval
12896
12958
  ),
12897
12959
  toolCall: {
12898
12960
  toolCallId: callId,
@@ -12903,9 +12965,19 @@ ${thought.description}`;
12903
12965
  kind: toAcpToolKind(tool.kind)
12904
12966
  }
12905
12967
  };
12906
- const output = await this.connection.requestPermission(params);
12907
- const outcome = output.outcome.outcome === CoreToolCallStatus.Cancelled ? ToolConfirmationOutcome.Cancel : external_exports.nativeEnum(ToolConfirmationOutcome).parse(output.outcome.optionId);
12968
+ const output = RequestPermissionResponseSchema.parse(
12969
+ await this.connection.requestPermission(params)
12970
+ );
12971
+ const outcome = output.outcome.outcome === "cancelled" ? ToolConfirmationOutcome.Cancel : external_exports.nativeEnum(ToolConfirmationOutcome).parse(output.outcome.optionId);
12908
12972
  await confirmationDetails.onConfirm(outcome);
12973
+ await updatePolicy(
12974
+ tool,
12975
+ outcome,
12976
+ confirmationDetails,
12977
+ this.context,
12978
+ this.context.messageBus,
12979
+ invocation
12980
+ );
12909
12981
  switch (outcome) {
12910
12982
  case ToolConfirmationOutcome.Cancel:
12911
12983
  return errorResponse(
@@ -13084,6 +13156,7 @@ ${thought.description}`;
13084
13156
  const pathSpecsToRead = [];
13085
13157
  const contentLabelsForDisplay = [];
13086
13158
  const ignoredPaths = [];
13159
+ const directContents = [];
13087
13160
  const toolRegistry = this.context.toolRegistry;
13088
13161
  const readManyFilesTool = new ReadManyFilesTool(
13089
13162
  this.context.config,
@@ -13102,26 +13175,169 @@ ${thought.description}`;
13102
13175
  }
13103
13176
  let currentPathSpec = pathName;
13104
13177
  let resolvedSuccessfully = false;
13178
+ let readDirectly = false;
13105
13179
  try {
13106
13180
  const absolutePath = path12.resolve(
13107
13181
  this.context.config.getTargetDir(),
13108
13182
  pathName
13109
13183
  );
13110
- if (isWithinRoot(absolutePath, this.context.config.getTargetDir())) {
13111
- const stats = await fs9.stat(absolutePath);
13112
- if (stats.isDirectory()) {
13113
- currentPathSpec = pathName.endsWith("/") ? `${pathName}**` : `${pathName}/**`;
13184
+ let validationError = this.context.config.validatePathAccess(
13185
+ absolutePath,
13186
+ "read"
13187
+ );
13188
+ if (validationError && !isWithinRoot(absolutePath, this.context.config.getTargetDir())) {
13189
+ try {
13190
+ const stats = await fs9.stat(absolutePath);
13191
+ if (stats.isFile()) {
13192
+ const syntheticCallId = `resolve-prompt-${pathName}-${randomUUID()}`;
13193
+ const params = {
13194
+ sessionId: this.id,
13195
+ options: [
13196
+ {
13197
+ optionId: ToolConfirmationOutcome.ProceedOnce,
13198
+ name: "Allow once",
13199
+ kind: "allow_once"
13200
+ },
13201
+ {
13202
+ optionId: ToolConfirmationOutcome.Cancel,
13203
+ name: "Deny",
13204
+ kind: "reject_once"
13205
+ }
13206
+ ],
13207
+ toolCall: {
13208
+ toolCallId: syntheticCallId,
13209
+ status: "pending",
13210
+ title: `Allow access to absolute path: ${pathName}`,
13211
+ content: [
13212
+ {
13213
+ type: "content",
13214
+ content: {
13215
+ type: "text",
13216
+ text: `The Agent needs access to read an attached file outside your workspace: ${pathName}`
13217
+ }
13218
+ }
13219
+ ],
13220
+ locations: [],
13221
+ kind: "read"
13222
+ }
13223
+ };
13224
+ const output = RequestPermissionResponseSchema.parse(
13225
+ await this.connection.requestPermission(params)
13226
+ );
13227
+ const outcome = output.outcome.outcome === "cancelled" ? ToolConfirmationOutcome.Cancel : external_exports.nativeEnum(ToolConfirmationOutcome).parse(output.outcome.optionId);
13228
+ if (outcome === ToolConfirmationOutcome.ProceedOnce) {
13229
+ this.context.config.getWorkspaceContext().addReadOnlyPath(absolutePath);
13230
+ validationError = null;
13231
+ } else {
13232
+ this.debug(
13233
+ `Direct read authorization denied for absolute path ${pathName}`
13234
+ );
13235
+ directContents.push({
13236
+ spec: pathName,
13237
+ content: `[Warning: Access to absolute path \`${pathName}\` denied by user.]`
13238
+ });
13239
+ continue;
13240
+ }
13241
+ }
13242
+ } catch (error) {
13114
13243
  this.debug(
13115
- `Path ${pathName} resolved to directory, using glob: ${currentPathSpec}`
13244
+ `Failed to request permission for absolute attachment ${pathName}: ${getErrorMessage(error)}`
13116
13245
  );
13117
- } else {
13118
- this.debug(`Path ${pathName} resolved to file: ${currentPathSpec}`);
13246
+ await this.sendUpdate({
13247
+ sessionUpdate: "agent_thought_chunk",
13248
+ content: {
13249
+ type: "text",
13250
+ text: `Warning: Failed to display permission dialog for \`${absolutePath}\`. Error: ${getErrorMessage(error)}`
13251
+ }
13252
+ });
13253
+ }
13254
+ }
13255
+ if (!validationError) {
13256
+ if ((path12.isAbsolute(pathName) || !isWithinRoot(
13257
+ absolutePath,
13258
+ this.context.config.getTargetDir()
13259
+ )) && !readDirectly) {
13260
+ try {
13261
+ const stats = await fs9.stat(absolutePath);
13262
+ if (stats.isFile()) {
13263
+ const fileReadResult = await processSingleFileContent(
13264
+ absolutePath,
13265
+ this.context.config.getTargetDir(),
13266
+ this.context.config.getFileSystemService()
13267
+ );
13268
+ if (!fileReadResult.error) {
13269
+ if (typeof fileReadResult.llmContent === "object" && "inlineData" in fileReadResult.llmContent) {
13270
+ directContents.push({
13271
+ spec: pathName,
13272
+ part: fileReadResult.llmContent
13273
+ });
13274
+ } else if (typeof fileReadResult.llmContent === "string") {
13275
+ let contentToPush = fileReadResult.llmContent;
13276
+ if (fileReadResult.isTruncated) {
13277
+ contentToPush = `[WARNING: This file was truncated]
13278
+
13279
+ ${contentToPush}`;
13280
+ }
13281
+ directContents.push({
13282
+ spec: pathName,
13283
+ content: contentToPush
13284
+ });
13285
+ }
13286
+ readDirectly = true;
13287
+ resolvedSuccessfully = true;
13288
+ } else {
13289
+ this.debug(
13290
+ `Direct read failed for absolute path ${pathName}: ${fileReadResult.error}`
13291
+ );
13292
+ await this.sendUpdate({
13293
+ sessionUpdate: "agent_thought_chunk",
13294
+ content: {
13295
+ type: "text",
13296
+ text: `Warning: file read failed for \`${pathName}\`. Reason: ${fileReadResult.error}`
13297
+ }
13298
+ });
13299
+ continue;
13300
+ }
13301
+ }
13302
+ } catch (error) {
13303
+ this.debug(
13304
+ `File stat/access error for absolute path ${pathName}: ${getErrorMessage(error)}`
13305
+ );
13306
+ await this.sendUpdate({
13307
+ sessionUpdate: "agent_thought_chunk",
13308
+ content: {
13309
+ type: "text",
13310
+ text: `Warning: file access failed for \`${pathName}\`. Reason: ${getErrorMessage(error)}`
13311
+ }
13312
+ });
13313
+ continue;
13314
+ }
13315
+ }
13316
+ if (!readDirectly) {
13317
+ const stats = await fs9.stat(absolutePath);
13318
+ if (stats.isDirectory()) {
13319
+ currentPathSpec = pathName.endsWith("/") ? `${pathName}**` : `${pathName}/**`;
13320
+ this.debug(
13321
+ `Path ${pathName} resolved to directory, using glob: ${currentPathSpec}`
13322
+ );
13323
+ } else {
13324
+ this.debug(
13325
+ `Path ${pathName} resolved to file: ${currentPathSpec}`
13326
+ );
13327
+ }
13328
+ resolvedSuccessfully = true;
13119
13329
  }
13120
- resolvedSuccessfully = true;
13121
13330
  } else {
13122
13331
  this.debug(
13123
- `Path ${pathName} is outside the project directory. Skipping.`
13332
+ `Path ${pathName} access disallowed: ${validationError}. Skipping.`
13124
13333
  );
13334
+ await this.sendUpdate({
13335
+ sessionUpdate: "agent_thought_chunk",
13336
+ content: {
13337
+ type: "text",
13338
+ text: `Warning: skipping access to \`${pathName}\`. Reason: ${validationError}`
13339
+ }
13340
+ });
13125
13341
  }
13126
13342
  } catch (error) {
13127
13343
  if (isNodeError(error) && error.code === "ENOENT") {
@@ -13176,7 +13392,9 @@ ${thought.description}`;
13176
13392
  }
13177
13393
  }
13178
13394
  if (resolvedSuccessfully) {
13179
- pathSpecsToRead.push(currentPathSpec);
13395
+ if (!readDirectly) {
13396
+ pathSpecsToRead.push(currentPathSpec);
13397
+ }
13180
13398
  atPathToResolvedSpecMap.set(pathName, currentPathSpec);
13181
13399
  contentLabelsForDisplay.push(pathName);
13182
13400
  }
@@ -13213,7 +13431,7 @@ ${thought.description}`;
13213
13431
  );
13214
13432
  }
13215
13433
  const processedQueryParts = [{ text: initialQueryText }];
13216
- if (pathSpecsToRead.length === 0 && embeddedContext.length === 0) {
13434
+ if (pathSpecsToRead.length === 0 && embeddedContext.length === 0 && directContents.length === 0) {
13217
13435
  debugLogger.warn("No valid file paths found in @ commands to read.");
13218
13436
  return [{ text: initialQueryText }];
13219
13437
  }
@@ -13299,6 +13517,29 @@ Content from @${filePathSpecInContent}:
13299
13517
  throw error;
13300
13518
  }
13301
13519
  }
13520
+ if (directContents.length > 0) {
13521
+ const hasReferenceStart = processedQueryParts.some(
13522
+ (p) => "text" in p && typeof p.text === "string" && p.text.includes(REFERENCE_CONTENT_START)
13523
+ );
13524
+ if (!hasReferenceStart) {
13525
+ processedQueryParts.push({
13526
+ text: `
13527
+ ${REFERENCE_CONTENT_START}`
13528
+ });
13529
+ }
13530
+ for (const item of directContents) {
13531
+ processedQueryParts.push({
13532
+ text: `
13533
+ Content from @${item.spec}:
13534
+ `
13535
+ });
13536
+ if (item.content) {
13537
+ processedQueryParts.push({ text: item.content });
13538
+ } else if (item.part) {
13539
+ processedQueryParts.push(item.part);
13540
+ }
13541
+ }
13542
+ }
13302
13543
  if (embeddedContext.length > 0) {
13303
13544
  processedQueryParts.push({
13304
13545
  text: "\n--- Content from referenced context ---"
@@ -13371,7 +13612,7 @@ var basicPermissionOptions = [
13371
13612
  kind: "reject_once"
13372
13613
  }
13373
13614
  ];
13374
- function toPermissionOptions(confirmation, config) {
13615
+ function toPermissionOptions(confirmation, config, enablePermanentToolApproval = false) {
13375
13616
  const disableAlwaysAllow = config.getDisableAlwaysAllow();
13376
13617
  const options = [];
13377
13618
  if (!disableAlwaysAllow) {
@@ -13379,37 +13620,65 @@ function toPermissionOptions(confirmation, config) {
13379
13620
  case "edit":
13380
13621
  options.push({
13381
13622
  optionId: ToolConfirmationOutcome.ProceedAlways,
13382
- name: "Allow All Edits",
13623
+ name: "Allow for this session",
13383
13624
  kind: "allow_always"
13384
13625
  });
13626
+ if (enablePermanentToolApproval) {
13627
+ options.push({
13628
+ optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
13629
+ name: "Allow for this file in all future sessions",
13630
+ kind: "allow_always"
13631
+ });
13632
+ }
13385
13633
  break;
13386
13634
  case "exec":
13387
13635
  options.push({
13388
13636
  optionId: ToolConfirmationOutcome.ProceedAlways,
13389
- name: `Always Allow ${confirmation.rootCommand}`,
13637
+ name: "Allow for this session",
13390
13638
  kind: "allow_always"
13391
13639
  });
13640
+ if (enablePermanentToolApproval) {
13641
+ options.push({
13642
+ optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
13643
+ name: "Allow this command for all future sessions",
13644
+ kind: "allow_always"
13645
+ });
13646
+ }
13392
13647
  break;
13393
13648
  case "mcp":
13394
13649
  options.push(
13395
13650
  {
13396
13651
  optionId: ToolConfirmationOutcome.ProceedAlwaysServer,
13397
- name: `Always Allow ${confirmation.serverName}`,
13652
+ name: "Allow all server tools for this session",
13398
13653
  kind: "allow_always"
13399
13654
  },
13400
13655
  {
13401
13656
  optionId: ToolConfirmationOutcome.ProceedAlwaysTool,
13402
- name: `Always Allow ${confirmation.toolName}`,
13657
+ name: "Allow tool for this session",
13403
13658
  kind: "allow_always"
13404
13659
  }
13405
13660
  );
13661
+ if (enablePermanentToolApproval) {
13662
+ options.push({
13663
+ optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
13664
+ name: "Allow tool for all future sessions",
13665
+ kind: "allow_always"
13666
+ });
13667
+ }
13406
13668
  break;
13407
13669
  case "info":
13408
13670
  options.push({
13409
13671
  optionId: ToolConfirmationOutcome.ProceedAlways,
13410
- name: `Always Allow`,
13672
+ name: "Allow for this session",
13411
13673
  kind: "allow_always"
13412
13674
  });
13675
+ if (enablePermanentToolApproval) {
13676
+ options.push({
13677
+ optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
13678
+ name: "Allow for all future sessions",
13679
+ kind: "allow_always"
13680
+ });
13681
+ }
13413
13682
  break;
13414
13683
  case "ask_user":
13415
13684
  case "exit_plan_mode":
@@ -13487,8 +13756,21 @@ function buildAvailableModels(config, settings) {
13487
13756
  const preferredModel = config.getModel() || DEFAULT_GEMINI_MODEL_AUTO;
13488
13757
  const shouldShowPreviewModels = config.getHasAccessToPreviewModel();
13489
13758
  const useGemini31 = config.getGemini31LaunchedSync?.() ?? false;
13759
+ const useGemini31FlashLite = config.getGemini31FlashLiteLaunchedSync?.() ?? false;
13490
13760
  const selectedAuthType = settings.merged.security.auth.selectedType;
13491
13761
  const useCustomToolModel = useGemini31 && selectedAuthType === AuthType.USE_GEMINI;
13762
+ if (config.getExperimentalDynamicModelConfiguration?.() === true && config.getModelConfigService) {
13763
+ const options = config.getModelConfigService().getAvailableModelOptions({
13764
+ useGemini3_1: useGemini31,
13765
+ useGemini3_1FlashLite: useGemini31FlashLite,
13766
+ useCustomTools: useCustomToolModel,
13767
+ hasAccessToPreview: shouldShowPreviewModels
13768
+ });
13769
+ return {
13770
+ availableModels: options,
13771
+ currentModelId: preferredModel
13772
+ };
13773
+ }
13492
13774
  const mainOptions = [
13493
13775
  {
13494
13776
  value: DEFAULT_GEMINI_MODEL_AUTO,
@@ -13520,7 +13802,7 @@ function buildAvailableModels(config, settings) {
13520
13802
  if (shouldShowPreviewModels) {
13521
13803
  const previewProModel = useGemini31 ? PREVIEW_GEMINI_3_1_MODEL : PREVIEW_GEMINI_MODEL;
13522
13804
  const previewProValue = useCustomToolModel ? PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL : previewProModel;
13523
- manualOptions.unshift(
13805
+ const previewOptions = [
13524
13806
  {
13525
13807
  value: previewProValue,
13526
13808
  title: getDisplayString(previewProModel)
@@ -13529,7 +13811,14 @@ function buildAvailableModels(config, settings) {
13529
13811
  value: PREVIEW_GEMINI_FLASH_MODEL,
13530
13812
  title: getDisplayString(PREVIEW_GEMINI_FLASH_MODEL)
13531
13813
  }
13532
- );
13814
+ ];
13815
+ if (useGemini31FlashLite) {
13816
+ previewOptions.push({
13817
+ value: PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL,
13818
+ title: getDisplayString(PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL)
13819
+ });
13820
+ }
13821
+ manualOptions.unshift(...previewOptions);
13533
13822
  }
13534
13823
  const scaleOptions = (options) => options.map((o) => ({
13535
13824
  modelId: o.value,
@@ -13700,7 +13989,7 @@ async function deleteSession(config, sessionIndex) {
13700
13989
  }
13701
13990
  try {
13702
13991
  const chatRecordingService = new ChatRecordingService(config);
13703
- chatRecordingService.deleteSession(sessionToDelete.file);
13992
+ await chatRecordingService.deleteSession(sessionToDelete.file);
13704
13993
  const time = formatRelativeTime(sessionToDelete.lastUpdated);
13705
13994
  writeToStdout(
13706
13995
  `Deleted session ${sessionToDelete.index}: ${sessionToDelete.firstUserMessage} (${time})`
@@ -13974,7 +14263,7 @@ ${reason.stack}` : ""}`;
13974
14263
  });
13975
14264
  }
13976
14265
  async function startInteractiveUI(config, settings, startupWarnings, workspaceRoot = process.cwd(), resumedSessionData, initializationResult) {
13977
- const { startInteractiveUI: doStartUI } = await import("./interactiveCli-VLQHRXHU.js");
14266
+ const { startInteractiveUI: doStartUI } = await import("./interactiveCli-DX76MWWT.js");
13978
14267
  await doStartUI(
13979
14268
  config,
13980
14269
  settings,
@@ -14061,6 +14350,7 @@ async function main() {
14061
14350
  const isDebugMode2 = isDebugMode(argv);
14062
14351
  const consolePatcher = new ConsolePatcher({
14063
14352
  stderr: true,
14353
+ interactive: isHeadlessMode() ? false : true,
14064
14354
  debugMode: isDebugMode2,
14065
14355
  onNewMessage: (msg) => {
14066
14356
  coreEvents.emitConsoleLog(msg.type, msg.content);
@@ -14170,7 +14460,7 @@ ${finalArgs[promptIndex + 1]}`;
14170
14460
  await config.storage.initialize();
14171
14461
  adminControlsListner.setConfig(config);
14172
14462
  if (config.isInteractive() && settings.merged.general.devtools) {
14173
- const { setupInitialActivityLogger } = await import("./devtoolsService-ZKU2HLK2.js");
14463
+ const { setupInitialActivityLogger } = await import("./devtoolsService-IWSTJYRB.js");
14174
14464
  await setupInitialActivityLogger(config);
14175
14465
  }
14176
14466
  registerTelemetryConfig(config);
@@ -14277,6 +14567,9 @@ ${finalArgs[promptIndex + 1]}`;
14277
14567
  }
14278
14568
  cliStartupHandle?.end();
14279
14569
  if (config.isInteractive()) {
14570
+ if (process.stdin.isTTY) {
14571
+ process.stdin.resume();
14572
+ }
14280
14573
  await startInteractiveUI(
14281
14574
  config,
14282
14575
  settings,
@@ -14315,9 +14608,6 @@ ${input}` : wrappedContext;
14315
14608
  }
14316
14609
  }
14317
14610
  }
14318
- registerCleanup(async () => {
14319
- await config.getHookSystem()?.fireSessionEndEvent(SessionEndReason.Exit);
14320
- });
14321
14611
  if (!input) {
14322
14612
  debugLogger.error(
14323
14613
  `No input provided via stdin. Input can be provided by piping data into gemini or using the --prompt option.`