@google/gemini-cli 0.41.0-preview.1 → 0.42.0-nightly.20260501.gcaa046641

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 (93) hide show
  1. package/bundle/{chunk-36LZQV4W.js → chunk-2HOG45IA.js} +1047 -1240
  2. package/bundle/{chunk-NGB7ZVQL.js → chunk-2WK6K7H4.js} +67 -507
  3. package/bundle/{chunk-DOHALVIP.js → chunk-3Y7ZPPS2.js} +1047 -1240
  4. package/bundle/chunk-4SBF4FWA.js +512 -0
  5. package/bundle/{chunk-XRLFHCHC.js → chunk-533APETE.js} +30 -12
  6. package/bundle/{chunk-T5I4M6M4.js → chunk-747IFMEA.js} +3 -3
  7. package/bundle/chunk-CTSXRP2T.js +512 -0
  8. package/bundle/{chunk-DCHOW6BK.js → chunk-CVJABGPV.js} +2 -2
  9. package/bundle/{chunk-VWYB6GSK.js → chunk-DDX3KSOF.js} +67 -507
  10. package/bundle/{chunk-DAEE6Y5T.js → chunk-EGV36KAI.js} +1047 -1240
  11. package/bundle/chunk-ESRGVL52.js +512 -0
  12. package/bundle/{chunk-SAJ72M2G.js → chunk-FABHOVMY.js} +23 -7
  13. package/bundle/chunk-FNLKMX3W.js +391 -0
  14. package/bundle/chunk-FTIY7CSS.js +391 -0
  15. package/bundle/{chunk-C5CRFFTY.js → chunk-GXIITUGM.js} +1 -1
  16. package/bundle/{chunk-45OGXTFK.js → chunk-HIYYW6PF.js} +3 -3
  17. package/bundle/chunk-IDYSRNE5.js +511 -0
  18. package/bundle/{chunk-QRSHDIRX.js → chunk-IJA7QQHF.js} +1 -1
  19. package/bundle/{chunk-U6WUS35U.js → chunk-ILECTCCH.js} +2 -2
  20. package/bundle/{chunk-R4LSW45D.js → chunk-J44J2AAV.js} +1 -1
  21. package/bundle/{chunk-KCDF3RDO.js → chunk-JPGLBVDA.js} +3 -3
  22. package/bundle/{chunk-VJ6K3S57.js → chunk-K5CA5JX2.js} +2 -2
  23. package/bundle/{chunk-6NFVEILC.js → chunk-L6URBAMF.js} +262 -81
  24. package/bundle/{chunk-5Z2T77EB.js → chunk-NNAHWZGK.js} +66 -507
  25. package/bundle/{chunk-KJ4M7JXR.js → chunk-SFDJ7FIE.js} +2 -2
  26. package/bundle/{chunk-QY23ZEK3.js → chunk-SYZNFSS3.js} +262 -81
  27. package/bundle/chunk-TBIPLAJP.js +391 -0
  28. package/bundle/{chunk-FFVUMIL3.js → chunk-TMQACI5N.js} +1047 -1240
  29. package/bundle/{chunk-XO6NKGWV.js → chunk-UCTXAZT6.js} +262 -81
  30. package/bundle/{chunk-VLSVN2FJ.js → chunk-USFRINC4.js} +1 -1
  31. package/bundle/chunk-VJOUKBFO.js +391 -0
  32. package/bundle/{chunk-EQSLZT5Z.js → chunk-VUMF52YD.js} +271 -81
  33. package/bundle/{chunk-5QI3ZXQB.js → chunk-WGWUS5AF.js} +67 -507
  34. package/bundle/{chunk-TBBDQEFQ.js → chunk-WTLXL6OZ.js} +3 -3
  35. package/bundle/{cleanup-3COTQVPP.js → cleanup-GQXJGC2H.js} +3 -3
  36. package/bundle/{cleanup-FIE6MCAE.js → cleanup-OSSEOJVY.js} +3 -3
  37. package/bundle/{cleanup-PREOBLFK.js → cleanup-TDBASRR5.js} +3 -3
  38. package/bundle/{cleanup-YY2EUT56.js → cleanup-XLWNSNLT.js} +3 -3
  39. package/bundle/{core-GZOFEER4.js → core-JH4LXS4F.js} +8 -2
  40. package/bundle/{devtoolsService-QXOHXSMJ.js → devtoolsService-DFWZ34A5.js} +3 -3
  41. package/bundle/{devtoolsService-DV36S632.js → devtoolsService-KZLK5WRW.js} +3 -3
  42. package/bundle/{devtoolsService-JPBL5I7F.js → devtoolsService-XIWMIEMB.js} +3 -3
  43. package/bundle/{devtoolsService-M4LZEBZD.js → devtoolsService-ZV5MJUBY.js} +3 -3
  44. package/bundle/{dist-HASTHPE3.js → dist-ATBEVH4R.js} +8 -2
  45. package/bundle/{dist-JVRDP7SO.js → dist-BOCIGIGG.js} +8 -2
  46. package/bundle/{dist-NSJ6AA4L.js → dist-TDGPCKNF.js} +8 -2
  47. package/bundle/docs/changelogs/index.md +18 -0
  48. package/bundle/docs/changelogs/latest.md +167 -242
  49. package/bundle/docs/changelogs/preview.md +99 -385
  50. package/bundle/docs/cli/cli-reference.md +1 -0
  51. package/bundle/docs/cli/creating-skills.md +165 -38
  52. package/bundle/docs/cli/custom-commands.md +1 -0
  53. package/bundle/docs/cli/model-routing.md +3 -3
  54. package/bundle/docs/cli/plan-mode.md +2 -1
  55. package/bundle/docs/cli/skills-best-practices.md +78 -0
  56. package/bundle/docs/cli/skills.md +98 -93
  57. package/bundle/docs/cli/tutorials/session-management.md +13 -0
  58. package/bundle/docs/cli/tutorials/skills-getting-started.md +140 -92
  59. package/bundle/docs/cli/using-agent-skills.md +89 -0
  60. package/bundle/docs/core/gemma-setup.md +83 -0
  61. package/bundle/docs/core/index.md +3 -2
  62. package/bundle/docs/core/local-model-routing.md +14 -7
  63. package/bundle/docs/reference/commands.md +14 -4
  64. package/bundle/docs/reference/configuration.md +76 -4
  65. package/bundle/docs/reference/keyboard-shortcuts.md +1 -1
  66. package/bundle/docs/reference/policy-engine.md +14 -3
  67. package/bundle/docs/sidebar.json +24 -2
  68. package/bundle/docs/tools/activate-skill.md +1 -1
  69. package/bundle/{gemini-IGRTXHCM.js → gemini-ETBA6M7V.js} +1067 -850
  70. package/bundle/{gemini-KIM7O55W.js → gemini-FUGMMZB7.js} +1067 -850
  71. package/bundle/{gemini-SFFHSCEY.js → gemini-QDNEMFTK.js} +1067 -850
  72. package/bundle/{gemini-FTUVOUHP.js → gemini-TZ26TZKD.js} +1067 -848
  73. package/bundle/gemini.js +20 -13
  74. package/bundle/{interactiveCli-LTPR447O.js → interactiveCli-74QXEIGP.js} +682 -609
  75. package/bundle/{interactiveCli-K4FIT7TA.js → interactiveCli-IBVICRF7.js} +682 -609
  76. package/bundle/{interactiveCli-7HPLINVC.js → interactiveCli-OKS4NPC7.js} +682 -609
  77. package/bundle/{interactiveCli-JOX7MFFH.js → interactiveCli-ZS4ZQWNV.js} +682 -609
  78. package/bundle/{liteRtServerManager-BENLLSF2.js → liteRtServerManager-I5CSGWRL.js} +5 -4
  79. package/bundle/{liteRtServerManager-KDO6UAQ5.js → liteRtServerManager-IDNLXYHP.js} +5 -4
  80. package/bundle/{liteRtServerManager-MQIQXXZQ.js → liteRtServerManager-J33F7APP.js} +5 -4
  81. package/bundle/{liteRtServerManager-VGYEHFUE.js → liteRtServerManager-RJF74BUI.js} +5 -4
  82. package/bundle/{memoryDiscovery-FN3IAPBT.js → memoryDiscovery-LIJKMASE.js} +1 -1
  83. package/bundle/{memoryDiscovery-R7PAR2NY.js → memoryDiscovery-WVH7QDNJ.js} +1 -1
  84. package/bundle/node_modules/@google/gemini-cli-devtools/package.json +1 -1
  85. package/bundle/{oauth2-provider-JPCBTTS2.js → oauth2-provider-7UM3XCQ4.js} +2 -2
  86. package/bundle/{oauth2-provider-EWMNT6D6.js → oauth2-provider-BFW5HE2U.js} +2 -2
  87. package/bundle/{oauth2-provider-M3WV4GJM.js → oauth2-provider-LONBXYVY.js} +2 -2
  88. package/bundle/{oauth2-provider-UVXCM7G3.js → oauth2-provider-N65VILW5.js} +2 -2
  89. package/bundle/{start-4MSISK2E.js → start-3B4FNGNM.js} +7 -6
  90. package/bundle/{start-ATOE57Z4.js → start-3OM5OXD2.js} +7 -6
  91. package/bundle/{start-AVEON6UU.js → start-N3S3BSEF.js} +7 -6
  92. package/bundle/{start-KBB2UTE5.js → start-PLPHF43U.js} +7 -6
  93. package/package.json +1 -1
@@ -9,7 +9,6 @@ import {
9
9
  INSTALL_WARNING_MESSAGE,
10
10
  McpPromptLoader,
11
11
  McpServerEnablementManager,
12
- RELAUNCH_EXIT_CODE,
13
12
  canLoadServer,
14
13
  checkForAllExtensionUpdates,
15
14
  checkForExtensionUpdate,
@@ -42,18 +41,18 @@ import {
42
41
  updateAllUpdatableExtensions,
43
42
  updateExtension,
44
43
  validateAuthMethod
45
- } from "./chunk-FFVUMIL3.js";
44
+ } from "./chunk-EGV36KAI.js";
46
45
  import {
47
46
  appEvents
48
47
  } from "./chunk-5PS3AYFU.js";
49
48
  import {
50
49
  startCommand,
51
50
  startServer
52
- } from "./chunk-45OGXTFK.js";
51
+ } from "./chunk-HIYYW6PF.js";
53
52
  import {
54
53
  exitCli,
55
54
  require_source
56
- } from "./chunk-C5CRFFTY.js";
55
+ } from "./chunk-J44J2AAV.js";
57
56
  import {
58
57
  DEFAULT_PORT,
59
58
  GEMMA_MODEL_NAME,
@@ -87,7 +86,11 @@ import {
87
86
  readServerProcessInfo,
88
87
  resolveGemmaConfig,
89
88
  saveModelChange
90
- } from "./chunk-NGB7ZVQL.js";
89
+ } from "./chunk-2WK6K7H4.js";
90
+ import {
91
+ RELAUNCH_EXIT_CODE
92
+ } from "./chunk-FTIY7CSS.js";
93
+ import "./chunk-ESRGVL52.js";
91
94
  import {
92
95
  cleanupCheckpoints,
93
96
  registerCleanup,
@@ -96,7 +99,7 @@ import {
96
99
  runExitCleanup,
97
100
  runSyncCleanup,
98
101
  setupSignalHandlers
99
- } from "./chunk-U6WUS35U.js";
102
+ } from "./chunk-K5CA5JX2.js";
100
103
  import {
101
104
  AuthType,
102
105
  ChatRecordingService,
@@ -113,7 +116,6 @@ import {
113
116
  JsonFormatter,
114
117
  JsonStreamEventType,
115
118
  LegacyAgentSession,
116
- LlmRole,
117
119
  Logger,
118
120
  MCPServerConfig,
119
121
  MCPServerStatus,
@@ -125,7 +127,7 @@ import {
125
127
  SessionEndReason,
126
128
  SessionStartSource,
127
129
  ShellExecutionService,
128
- StreamEventType,
130
+ SimpleExtensionLoader,
129
131
  StreamJsonFormatter,
130
132
  ToolCallEvent,
131
133
  TrustLevel,
@@ -167,6 +169,7 @@ import {
167
169
  getVersion,
168
170
  isGeminiWorktree,
169
171
  isHeadlessMode,
172
+ isTextPart,
170
173
  isWithinRoot,
171
174
  listExtensions,
172
175
  listInboxPatches,
@@ -195,7 +198,7 @@ import {
195
198
  updatePolicy,
196
199
  writeToStderr,
197
200
  writeToStdout
198
- } from "./chunk-6NFVEILC.js";
201
+ } from "./chunk-SYZNFSS3.js";
199
202
  import {
200
203
  ASK_USER_TOOL_NAME,
201
204
  ApprovalMode,
@@ -243,7 +246,7 @@ import {
243
246
  loadServerHierarchicalMemory,
244
247
  resolveToRealPath,
245
248
  setGeminiMdFilename
246
- } from "./chunk-SAJ72M2G.js";
249
+ } from "./chunk-FABHOVMY.js";
247
250
  import "./chunk-664ZODQF.js";
248
251
  import "./chunk-RJTRUG2J.js";
249
252
  import "./chunk-IUUIT4SU.js";
@@ -7822,7 +7825,7 @@ async function loadSandboxConfig(settings, argv) {
7822
7825
  }
7823
7826
  const command2 = getSandboxCommand(sandboxValue);
7824
7827
  const packageJson = await getPackageJson(__dirname3);
7825
- const image = process.env["GEMINI_SANDBOX_IMAGE"] ?? "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.41.0-preview.1" ?? customImage ?? packageJson?.config?.sandboxImageUri;
7828
+ const image = process.env["GEMINI_SANDBOX_IMAGE"] ?? "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.42.0-nightly.20260428.g59b2dea0e" ?? customImage ?? packageJson?.config?.sandboxImageUri;
7826
7829
  const isNative = command2 === "windows-native" || command2 === "sandbox-exec" || command2 === "lxc";
7827
7830
  return command2 && (image || isNative) ? { enabled: true, allowedPaths, networkAccess, command: command2, image } : void 0;
7828
7831
  }
@@ -8224,7 +8227,7 @@ function isDebugMode(argv) {
8224
8227
  );
8225
8228
  }
8226
8229
  async function loadCliConfig(settings, sessionId, argv, options = {}) {
8227
- const { cwd = process3.cwd(), projectHooks } = options;
8230
+ const { cwd = process3.cwd(), projectHooks, skipExtensions = false } = options;
8228
8231
  const debugMode = isDebugMode(argv);
8229
8232
  const worktreeSettings = options.worktreeSettings ?? await resolveWorktreeSettings(cwd);
8230
8233
  if (argv.sandbox) {
@@ -8270,18 +8273,21 @@ async function loadCliConfig(settings, sessionId, argv, options = {}) {
8270
8273
  });
8271
8274
  includeDirectories.push(...ideFolders);
8272
8275
  }
8273
- const extensionManager = new ExtensionManager({
8274
- settings,
8275
- requestConsent: requestConsentNonInteractive,
8276
- requestSetting: promptForSetting,
8277
- workspaceDir: cwd,
8278
- enabledExtensionOverrides: argv.extensions,
8279
- // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
8280
- eventEmitter: coreEvents,
8281
- clientVersion: await getVersion()
8282
- });
8283
- await extensionManager.loadExtensions();
8284
- const extensionPlanSettings = extensionManager.getExtensions().find((ext) => ext.isActive && ext.plan?.directory)?.plan;
8276
+ let extensionManager;
8277
+ if (!skipExtensions) {
8278
+ extensionManager = new ExtensionManager({
8279
+ settings,
8280
+ requestConsent: requestConsentNonInteractive,
8281
+ requestSetting: promptForSetting,
8282
+ workspaceDir: cwd,
8283
+ enabledExtensionOverrides: argv.extensions,
8284
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
8285
+ eventEmitter: coreEvents,
8286
+ clientVersion: await getVersion()
8287
+ });
8288
+ await extensionManager.loadExtensions();
8289
+ }
8290
+ const extensionPlanSettings = extensionManager?.getExtensions()?.find((ext) => ext.isActive && ext.plan?.directory)?.plan;
8285
8291
  const experimentalJitContext = settings.experimental.jitContext ?? true;
8286
8292
  let extensionRegistryURI = process3.env["GEMINI_CLI_EXTENSION_REGISTRY_URI"] ?? (trustedFolder ? settings.experimental?.extensionRegistryURI : void 0);
8287
8293
  if (extensionRegistryURI && !extensionRegistryURI.startsWith("http")) {
@@ -8292,12 +8298,13 @@ async function loadCliConfig(settings, sessionId, argv, options = {}) {
8292
8298
  let memoryContent = "";
8293
8299
  let fileCount = 0;
8294
8300
  let filePaths = [];
8301
+ const finalExtensionLoader = extensionManager ?? new SimpleExtensionLoader([]);
8295
8302
  if (!experimentalJitContext) {
8296
8303
  const result = await loadServerHierarchicalMemory(
8297
8304
  cwd,
8298
8305
  settings.context?.loadMemoryFromIncludeDirectories || false ? includeDirectories : [],
8299
8306
  fileService,
8300
- extensionManager,
8307
+ finalExtensionLoader,
8301
8308
  trustedFolder,
8302
8309
  memoryImportFormat,
8303
8310
  memoryFileFiltering,
@@ -8481,7 +8488,13 @@ async function loadCliConfig(settings, sessionId, argv, options = {}) {
8481
8488
  const ide = detectIdeFromEnv();
8482
8489
  if (ide && (ide.name !== "vscode" || process3.env["TERM_PROGRAM"] === "vscode")) {
8483
8490
  clientName = `acp-${ide.name}`;
8491
+ } else {
8492
+ clientName = "acp";
8484
8493
  }
8494
+ } else if (argv.isCommand) {
8495
+ clientName = "cli-command";
8496
+ } else {
8497
+ clientName = "tui";
8485
8498
  }
8486
8499
  let profileSelector = void 0;
8487
8500
  if (settings.experimental?.stressTestProfile) {
@@ -8555,7 +8568,7 @@ async function loadCliConfig(settings, sessionId, argv, options = {}) {
8555
8568
  listSessions: argv.listSessions || false,
8556
8569
  deleteSession: argv.deleteSession,
8557
8570
  enabledExtensions: argv.extensions,
8558
- extensionLoader: extensionManager,
8571
+ extensionLoader: finalExtensionLoader,
8559
8572
  extensionRegistryURI,
8560
8573
  enableExtensionReloading: settings.experimental?.extensionReloading,
8561
8574
  enableAgents: settings.experimental?.enableAgents,
@@ -8676,6 +8689,15 @@ async function resolveWorktreeSettings(cwd) {
8676
8689
  }
8677
8690
 
8678
8691
  // packages/cli/src/utils/readStdin.ts
8692
+ function truncateUtf8Bytes(str, maxBytes) {
8693
+ const buf = Buffer.from(str, "utf8");
8694
+ if (buf.length <= maxBytes) return str;
8695
+ let end = maxBytes;
8696
+ while (end > 0 && (buf[end] & 192) === 128) {
8697
+ end--;
8698
+ }
8699
+ return buf.subarray(0, end).toString("utf8");
8700
+ }
8679
8701
  async function readStdin() {
8680
8702
  const MAX_STDIN_SIZE = 8 * 1024 * 1024;
8681
8703
  return new Promise((resolve9, reject) => {
@@ -8693,9 +8715,10 @@ async function readStdin() {
8693
8715
  clearTimeout(pipedInputTimerId);
8694
8716
  pipedInputTimerId = null;
8695
8717
  }
8696
- if (totalSize + chunk.length > MAX_STDIN_SIZE) {
8697
- const remainingSize = MAX_STDIN_SIZE - totalSize;
8698
- data += chunk.slice(0, remainingSize);
8718
+ const chunkByteLength = Buffer.byteLength(chunk, "utf8");
8719
+ if (totalSize + chunkByteLength > MAX_STDIN_SIZE) {
8720
+ const remainingBytes = MAX_STDIN_SIZE - totalSize;
8721
+ data += truncateUtf8Bytes(chunk, remainingBytes);
8699
8722
  debugLogger.warn(
8700
8723
  `Warning: stdin input truncated to ${MAX_STDIN_SIZE} bytes.`
8701
8724
  );
@@ -8704,7 +8727,7 @@ async function readStdin() {
8704
8727
  break;
8705
8728
  }
8706
8729
  data += chunk;
8707
- totalSize += chunk.length;
8730
+ totalSize += chunkByteLength;
8708
8731
  }
8709
8732
  };
8710
8733
  const onEnd = () => {
@@ -10199,7 +10222,7 @@ async function runNonInteractive({
10199
10222
  }
10200
10223
  });
10201
10224
  if (process.env["GEMINI_CLI_ACTIVITY_LOG_TARGET"]) {
10202
- const { setupInitialActivityLogger } = await import("./devtoolsService-M4LZEBZD.js");
10225
+ const { setupInitialActivityLogger } = await import("./devtoolsService-KZLK5WRW.js");
10203
10226
  setupInitialActivityLogger(config);
10204
10227
  }
10205
10228
  const { stdout: workingStdout } = createWorkingStdio();
@@ -10386,7 +10409,13 @@ async function runNonInteractive({
10386
10409
  const formatter = new JsonFormatter();
10387
10410
  const stats = uiTelemetryService.getMetrics();
10388
10411
  textOutput.write(
10389
- formatter.format(config.getSessionId(), responseText, stats)
10412
+ formatter.format(
10413
+ config.getSessionId(),
10414
+ responseText,
10415
+ stats,
10416
+ void 0,
10417
+ warnings
10418
+ )
10390
10419
  );
10391
10420
  } else {
10392
10421
  textOutput.ensureTrailingNewline();
@@ -10457,6 +10486,7 @@ async function runNonInteractive({
10457
10486
  let responseText = "";
10458
10487
  let preToolResponseText;
10459
10488
  let streamEnded = false;
10489
+ const warnings = [];
10460
10490
  for await (const event of session.stream({ streamId })) {
10461
10491
  if (streamEnded) break;
10462
10492
  switch (event.type) {
@@ -10555,10 +10585,19 @@ async function runNonInteractive({
10555
10585
  }
10556
10586
  const errorCode = event._meta?.["code"];
10557
10587
  if (errorCode === "AGENT_EXECUTION_BLOCKED") {
10588
+ const blockMessage = `Agent execution blocked: ${event.message.trim()}`;
10558
10589
  if (config.getOutputFormat() === OutputFormat.TEXT) {
10559
- process.stderr.write(`[WARNING] ${event.message}
10590
+ process.stderr.write(`[WARNING] ${blockMessage}
10560
10591
  `);
10592
+ } else if (streamFormatter) {
10593
+ streamFormatter.emitEvent({
10594
+ type: JsonStreamEventType.ERROR,
10595
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10596
+ severity: "warning",
10597
+ message: stripAnsi(blockMessage)
10598
+ });
10561
10599
  }
10600
+ warnings.push(blockMessage);
10562
10601
  break;
10563
10602
  }
10564
10603
  const severity = event.status === "RESOURCE_EXHAUSTED" ? "error" : "warning";
@@ -10571,9 +10610,10 @@ async function runNonInteractive({
10571
10610
  type: JsonStreamEventType.ERROR,
10572
10611
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10573
10612
  severity,
10574
- message: event.message
10613
+ message: stripAnsi(event.message)
10575
10614
  });
10576
10615
  }
10616
+ warnings.push(event.message);
10577
10617
  break;
10578
10618
  }
10579
10619
  case "agent_end": {
@@ -10650,7 +10690,7 @@ async function runNonInteractive2(params) {
10650
10690
  }
10651
10691
  });
10652
10692
  if (process.env["GEMINI_CLI_ACTIVITY_LOG_TARGET"]) {
10653
- const { setupInitialActivityLogger } = await import("./devtoolsService-M4LZEBZD.js");
10693
+ const { setupInitialActivityLogger } = await import("./devtoolsService-KZLK5WRW.js");
10654
10694
  setupInitialActivityLogger(config);
10655
10695
  }
10656
10696
  const { stdout: workingStdout } = createWorkingStdio();
@@ -10793,6 +10833,8 @@ async function runNonInteractive2(params) {
10793
10833
  }
10794
10834
  let currentMessages = [{ role: "user", parts: query }];
10795
10835
  let turnCount = 0;
10836
+ let invalidStreamError;
10837
+ const warnings = [];
10796
10838
  while (true) {
10797
10839
  turnCount++;
10798
10840
  if (config.getMaxSessionTurns() >= 0 && turnCount > config.getMaxSessionTurns()) {
@@ -10842,23 +10884,27 @@ async function runNonInteractive2(params) {
10842
10884
  }
10843
10885
  toolCallRequests.push(event.value);
10844
10886
  } else if (event.type === GeminiEventType.LoopDetected) {
10887
+ const message = "Loop detected, stopping execution";
10845
10888
  if (streamFormatter) {
10846
10889
  streamFormatter.emitEvent({
10847
10890
  type: JsonStreamEventType.ERROR,
10848
10891
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10849
10892
  severity: "warning",
10850
- message: "Loop detected, stopping execution"
10893
+ message
10851
10894
  });
10852
10895
  }
10896
+ warnings.push(message);
10853
10897
  } else if (event.type === GeminiEventType.MaxSessionTurns) {
10898
+ const message = "Maximum session turns exceeded";
10854
10899
  if (streamFormatter) {
10855
10900
  streamFormatter.emitEvent({
10856
10901
  type: JsonStreamEventType.ERROR,
10857
10902
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10858
10903
  severity: "error",
10859
- message: "Maximum session turns exceeded"
10904
+ message
10860
10905
  });
10861
10906
  }
10907
+ warnings.push(message);
10862
10908
  } else if (event.type === GeminiEventType.Error) {
10863
10909
  throw event.value.error;
10864
10910
  } else if (event.type === GeminiEventType.AgentExecutionStopped) {
@@ -10885,8 +10931,31 @@ async function runNonInteractive2(params) {
10885
10931
  const blockMessage = `Agent execution blocked: ${event.value.systemMessage?.trim() || event.value.reason}`;
10886
10932
  if (config.getOutputFormat() === OutputFormat.TEXT) {
10887
10933
  process.stderr.write(`[WARNING] ${blockMessage}
10934
+ `);
10935
+ } else if (streamFormatter) {
10936
+ streamFormatter.emitEvent({
10937
+ type: JsonStreamEventType.ERROR,
10938
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10939
+ severity: "warning",
10940
+ message: stripAnsi(blockMessage)
10941
+ });
10942
+ }
10943
+ warnings.push(blockMessage);
10944
+ } else if (event.type === GeminiEventType.InvalidStream) {
10945
+ invalidStreamError = "Invalid stream: The model returned an empty response or malformed tool call.";
10946
+ if (streamFormatter) {
10947
+ streamFormatter.emitEvent({
10948
+ type: JsonStreamEventType.ERROR,
10949
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10950
+ severity: "error",
10951
+ message: invalidStreamError
10952
+ });
10953
+ } else if (config.getOutputFormat() === OutputFormat.TEXT) {
10954
+ process.stderr.write(`[ERROR] ${invalidStreamError}
10888
10955
  `);
10889
10956
  }
10957
+ toolCallRequests.length = 0;
10958
+ break;
10890
10959
  }
10891
10960
  }
10892
10961
  if (toolCallRequests.length > 0) {
@@ -10959,7 +11028,13 @@ async function runNonInteractive2(params) {
10959
11028
  const formatter = new JsonFormatter();
10960
11029
  const stats = uiTelemetryService.getMetrics();
10961
11030
  textOutput.write(
10962
- formatter.format(config.getSessionId(), responseText, stats)
11031
+ formatter.format(
11032
+ config.getSessionId(),
11033
+ responseText,
11034
+ stats,
11035
+ void 0,
11036
+ warnings
11037
+ )
10963
11038
  );
10964
11039
  } else {
10965
11040
  textOutput.ensureTrailingNewline();
@@ -10974,14 +11049,20 @@ async function runNonInteractive2(params) {
10974
11049
  streamFormatter.emitEvent({
10975
11050
  type: JsonStreamEventType.RESULT,
10976
11051
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
10977
- status: "success",
11052
+ status: invalidStreamError ? "error" : "success",
10978
11053
  stats: streamFormatter.convertToStreamStats(metrics, durationMs)
10979
11054
  });
10980
11055
  } else if (config.getOutputFormat() === OutputFormat.JSON) {
10981
11056
  const formatter = new JsonFormatter();
10982
11057
  const stats = uiTelemetryService.getMetrics();
10983
11058
  textOutput.write(
10984
- formatter.format(config.getSessionId(), responseText, stats)
11059
+ formatter.format(
11060
+ config.getSessionId(),
11061
+ responseText,
11062
+ stats,
11063
+ invalidStreamError ? { type: "INVALID_STREAM", message: invalidStreamError } : void 0,
11064
+ warnings
11065
+ )
10985
11066
  );
10986
11067
  } else {
10987
11068
  textOutput.ensureTrailingNewline();
@@ -12540,59 +12621,8 @@ var RequestError = class _RequestError extends Error {
12540
12621
  }
12541
12622
  };
12542
12623
 
12543
- // packages/cli/src/acp/fileSystemService.ts
12544
- import os5 from "node:os";
12545
- import path10 from "node:path";
12546
- var AcpFileSystemService = class {
12547
- constructor(connection, sessionId, capabilities, fallback, root) {
12548
- this.connection = connection;
12549
- this.sessionId = sessionId;
12550
- this.capabilities = capabilities;
12551
- this.fallback = fallback;
12552
- this.root = root;
12553
- }
12554
- geminiDir = path10.join(os5.homedir(), ".gemini");
12555
- shouldUseFallback(filePath) {
12556
- return !isWithinRoot(filePath, this.root) || isWithinRoot(filePath, this.geminiDir);
12557
- }
12558
- normalizeFileSystemError(err) {
12559
- const errorMessage = err instanceof Error ? err.message : String(err);
12560
- if (errorMessage.includes("Resource not found") || errorMessage.includes("ENOENT") || errorMessage.includes("does not exist") || errorMessage.includes("No such file")) {
12561
- const newErr = new Error(errorMessage);
12562
- newErr.code = "ENOENT";
12563
- throw newErr;
12564
- }
12565
- throw err;
12566
- }
12567
- async readTextFile(filePath) {
12568
- if (!this.capabilities.readTextFile || this.shouldUseFallback(filePath)) {
12569
- return this.fallback.readTextFile(filePath);
12570
- }
12571
- try {
12572
- const response = await this.connection.readTextFile({
12573
- path: filePath,
12574
- sessionId: this.sessionId
12575
- });
12576
- return response.content;
12577
- } catch (err) {
12578
- this.normalizeFileSystemError(err);
12579
- }
12580
- }
12581
- async writeTextFile(filePath, content) {
12582
- if (!this.capabilities.writeTextFile || this.shouldUseFallback(filePath)) {
12583
- return this.fallback.writeTextFile(filePath, content);
12584
- }
12585
- try {
12586
- await this.connection.writeTextFile({
12587
- path: filePath,
12588
- content,
12589
- sessionId: this.sessionId
12590
- });
12591
- } catch (err) {
12592
- this.normalizeFileSystemError(err);
12593
- }
12594
- }
12595
- };
12624
+ // packages/cli/src/acp/acpStdioTransport.ts
12625
+ import { Readable, Writable } from "node:stream";
12596
12626
 
12597
12627
  // packages/cli/src/acp/acpErrors.ts
12598
12628
  function getAcpErrorMessage(error) {
@@ -12614,10 +12644,12 @@ function extractRecursiveMessage(input) {
12614
12644
  return input;
12615
12645
  }
12616
12646
 
12617
- // packages/cli/src/acp/acpClient.ts
12618
- import { Readable, Writable } from "node:stream";
12647
+ // packages/cli/src/acp/acpSessionManager.ts
12648
+ import { randomUUID as randomUUID2 } from "node:crypto";
12649
+
12650
+ // packages/cli/src/acp/acpSession.ts
12619
12651
  import * as fs12 from "node:fs/promises";
12620
- import * as path13 from "node:path";
12652
+ import * as path12 from "node:path";
12621
12653
  import { randomUUID } from "node:crypto";
12622
12654
 
12623
12655
  // packages/cli/src/acp/commands/commandRegistry.ts
@@ -13089,7 +13121,7 @@ var UpdateExtensionCommand = class {
13089
13121
 
13090
13122
  // packages/cli/src/acp/commands/init.ts
13091
13123
  import * as fs10 from "node:fs";
13092
- import * as path11 from "node:path";
13124
+ import * as path10 from "node:path";
13093
13125
  var InitCommand = class {
13094
13126
  name = "init";
13095
13127
  description = "Analyzes the project and creates a tailored GEMINI.md file";
@@ -13099,7 +13131,7 @@ var InitCommand = class {
13099
13131
  if (!targetDir) {
13100
13132
  throw new Error("Command requires a workspace.");
13101
13133
  }
13102
- const geminiMdPath = path11.join(targetDir, "GEMINI.md");
13134
+ const geminiMdPath = path10.join(targetDir, "GEMINI.md");
13103
13135
  const result = performInit(fs10.existsSync(geminiMdPath));
13104
13136
  switch (result.type) {
13105
13137
  case "message":
@@ -13132,7 +13164,7 @@ ${result.content}`
13132
13164
 
13133
13165
  // packages/cli/src/acp/commands/restore.ts
13134
13166
  import * as fs11 from "node:fs/promises";
13135
- import * as path12 from "node:path";
13167
+ import * as path11 from "node:path";
13136
13168
  var RestoreCommand = class {
13137
13169
  name = "restore";
13138
13170
  description = "Restore to a previous checkpoint, or list available checkpoints to restore. This will reset the conversation and file history to the state it was in when the checkpoint was created";
@@ -13154,7 +13186,7 @@ var RestoreCommand = class {
13154
13186
  }
13155
13187
  const selectedFile = argsStr.endsWith(".json") ? argsStr : `${argsStr}.json`;
13156
13188
  const checkpointDir = config.storage.getProjectTempCheckpointsDir();
13157
- const filePath = path12.join(checkpointDir, selectedFile);
13189
+ const filePath = path11.join(checkpointDir, selectedFile);
13158
13190
  let data;
13159
13191
  try {
13160
13192
  data = await fs11.readFile(filePath, "utf-8");
@@ -13228,7 +13260,7 @@ var ListCheckpointsCommand = class {
13228
13260
  }
13229
13261
  const checkpointFiles = /* @__PURE__ */ new Map();
13230
13262
  for (const file of jsonFiles) {
13231
- const filePath = path12.join(checkpointDir, file);
13263
+ const filePath = path11.join(checkpointDir, file);
13232
13264
  const data = await fs11.readFile(filePath, "utf-8");
13233
13265
  checkpointFiles.set(file, data);
13234
13266
  }
@@ -13335,7 +13367,7 @@ var HelpCommand = class {
13335
13367
  }
13336
13368
  };
13337
13369
 
13338
- // packages/cli/src/acp/commandHandler.ts
13370
+ // packages/cli/src/acp/acpCommandHandler.ts
13339
13371
  var CommandHandler = class _CommandHandler {
13340
13372
  registry;
13341
13373
  constructor() {
@@ -13422,7 +13454,7 @@ var CommandHandler = class _CommandHandler {
13422
13454
  }
13423
13455
  };
13424
13456
 
13425
- // packages/cli/src/acp/acpClient.ts
13457
+ // packages/cli/src/acp/acpUtils.ts
13426
13458
  function hasMeta(obj) {
13427
13459
  return typeof obj === "object" && obj !== null && "_meta" in obj;
13428
13460
  }
@@ -13435,380 +13467,273 @@ var RequestPermissionResponseSchema = external_exports.object({
13435
13467
  })
13436
13468
  ])
13437
13469
  });
13438
- async function runAcpClient(config, settings, argv) {
13439
- const { stdout: workingStdout } = createWorkingStdio();
13440
- const stdout = Writable.toWeb(workingStdout);
13441
- const stdin = Readable.toWeb(process.stdin);
13442
- const stream = ndJsonStream(stdout, stdin);
13443
- const connection = new AgentSideConnection(
13444
- (connection2) => new GeminiAgent(config, settings, argv, connection2),
13445
- stream
13446
- );
13447
- await connection.closed.finally(runExitCleanup);
13448
- }
13449
- var GeminiAgent = class _GeminiAgent {
13450
- constructor(context, settings, argv, connection) {
13451
- this.context = context;
13452
- this.settings = settings;
13453
- this.argv = argv;
13454
- this.connection = connection;
13455
- }
13456
- static callIdCounter = 0;
13457
- static generateCallId(name) {
13458
- return `${name}-${Date.now()}-${++_GeminiAgent.callIdCounter}`;
13470
+ function toToolCallContent(toolResult) {
13471
+ if (toolResult.error?.message) {
13472
+ throw new Error(toolResult.error.message);
13459
13473
  }
13460
- sessions = /* @__PURE__ */ new Map();
13461
- clientCapabilities;
13462
- apiKey;
13463
- baseUrl;
13464
- customHeaders;
13465
- async initialize(args) {
13466
- this.clientCapabilities = args.clientCapabilities;
13467
- const authMethods = [
13468
- {
13469
- id: AuthType.LOGIN_WITH_GOOGLE,
13470
- name: "Log in with Google",
13471
- description: "Log in with your Google account"
13472
- },
13473
- {
13474
- id: AuthType.USE_GEMINI,
13475
- name: "Gemini API key",
13476
- description: "Use an API key with Gemini Developer API",
13477
- _meta: {
13478
- "api-key": {
13479
- provider: "google"
13480
- }
13481
- }
13482
- },
13483
- {
13484
- id: AuthType.USE_VERTEX_AI,
13485
- name: "Vertex AI",
13486
- description: "Use an API key with Vertex AI GenAI API"
13487
- },
13488
- {
13489
- id: AuthType.GATEWAY,
13490
- name: "AI API Gateway",
13491
- description: "Use a custom AI API Gateway",
13492
- _meta: {
13493
- gateway: {
13494
- protocol: "google",
13495
- restartRequired: "false"
13474
+ if (toolResult.returnDisplay) {
13475
+ if (typeof toolResult.returnDisplay === "string") {
13476
+ return {
13477
+ type: "content",
13478
+ content: { type: "text", text: toolResult.returnDisplay }
13479
+ };
13480
+ } else {
13481
+ if ("fileName" in toolResult.returnDisplay) {
13482
+ return {
13483
+ type: "diff",
13484
+ path: toolResult.returnDisplay.filePath ?? toolResult.returnDisplay.fileName,
13485
+ oldText: toolResult.returnDisplay.originalContent,
13486
+ newText: toolResult.returnDisplay.newContent,
13487
+ _meta: {
13488
+ kind: !toolResult.returnDisplay.originalContent ? "add" : toolResult.returnDisplay.newContent === "" ? "delete" : "modify"
13496
13489
  }
13497
- }
13498
- }
13499
- ];
13500
- await this.context.config.initialize();
13501
- const version = await getVersion();
13502
- return {
13503
- protocolVersion: PROTOCOL_VERSION,
13504
- authMethods,
13505
- agentInfo: {
13506
- name: "gemini-cli",
13507
- title: "Gemini CLI",
13508
- version
13509
- },
13510
- agentCapabilities: {
13511
- loadSession: true,
13512
- promptCapabilities: {
13513
- image: true,
13514
- audio: true,
13515
- embeddedContext: true
13516
- },
13517
- mcpCapabilities: {
13518
- http: true,
13519
- sse: true
13520
- }
13521
- }
13522
- };
13523
- }
13524
- async authenticate(req) {
13525
- const { methodId } = req;
13526
- const method = external_exports.nativeEnum(AuthType).parse(methodId);
13527
- const selectedAuthType = this.settings.merged.security.auth.selectedType;
13528
- if (selectedAuthType && selectedAuthType !== method) {
13529
- await clearCachedCredentialFile();
13530
- }
13531
- const meta = hasMeta(req) ? req._meta : void 0;
13532
- const apiKey = typeof meta?.["api-key"] === "string" ? meta["api-key"] : void 0;
13533
- try {
13534
- if (apiKey) {
13535
- this.apiKey = apiKey;
13536
- }
13537
- const gatewaySchema = external_exports.object({
13538
- baseUrl: external_exports.string().optional(),
13539
- headers: external_exports.record(external_exports.string()).optional()
13540
- });
13541
- let baseUrl;
13542
- let headers;
13543
- if (meta?.["gateway"]) {
13544
- const result = gatewaySchema.safeParse(meta["gateway"]);
13545
- if (result.success) {
13546
- baseUrl = result.data.baseUrl;
13547
- headers = result.data.headers;
13548
- } else {
13549
- throw new RequestError(
13550
- -32602,
13551
- `Malformed gateway payload: ${result.error.message}`
13552
- );
13553
- }
13490
+ };
13554
13491
  }
13555
- this.baseUrl = baseUrl;
13556
- this.customHeaders = headers;
13557
- await this.context.config.refreshAuth(
13558
- method,
13559
- apiKey ?? this.apiKey,
13560
- baseUrl,
13561
- headers
13562
- );
13563
- } catch (e) {
13564
- throw new RequestError(-32e3, getAcpErrorMessage(e));
13492
+ return null;
13565
13493
  }
13566
- this.settings.setValue(
13567
- "User" /* User */,
13568
- "security.auth.selectedType",
13569
- method
13570
- );
13494
+ } else {
13495
+ return null;
13571
13496
  }
13572
- async newSession({
13573
- cwd,
13574
- mcpServers
13575
- }) {
13576
- const sessionId = randomUUID();
13577
- const loadedSettings = loadSettings(cwd);
13578
- const config = await this.newSessionConfig(
13579
- sessionId,
13580
- cwd,
13581
- mcpServers,
13582
- loadedSettings
13583
- );
13584
- const authType = loadedSettings.merged.security.auth.selectedType || AuthType.USE_GEMINI;
13585
- let isAuthenticated = false;
13586
- let authErrorMessage = "";
13587
- try {
13588
- await config.refreshAuth(
13589
- authType,
13590
- this.apiKey,
13591
- this.baseUrl,
13592
- this.customHeaders
13593
- );
13594
- isAuthenticated = true;
13595
- const contentGeneratorConfig = config.getContentGeneratorConfig();
13596
- if (authType === AuthType.USE_GEMINI && (!contentGeneratorConfig || !contentGeneratorConfig.apiKey)) {
13597
- isAuthenticated = false;
13598
- authErrorMessage = "Gemini API key is missing or not configured.";
13599
- }
13600
- } catch (e) {
13601
- isAuthenticated = false;
13602
- authErrorMessage = getAcpErrorMessage(e);
13603
- debugLogger.error(
13604
- `Authentication failed: ${e instanceof Error ? e.stack : e}`
13605
- );
13606
- }
13607
- if (!isAuthenticated) {
13608
- throw new RequestError(
13609
- -32e3,
13610
- authErrorMessage || "Authentication required."
13611
- );
13612
- }
13613
- if (this.clientCapabilities?.fs) {
13614
- const acpFileSystemService = new AcpFileSystemService(
13615
- this.connection,
13616
- sessionId,
13617
- this.clientCapabilities.fs,
13618
- config.getFileSystemService(),
13619
- cwd
13620
- );
13621
- config.setFileSystemService(acpFileSystemService);
13622
- }
13623
- await config.initialize();
13624
- startupProfiler.flush(config);
13625
- startAutoMemoryIfEnabled(config);
13626
- const geminiClient = config.getGeminiClient();
13627
- const chat = await geminiClient.startChat();
13628
- const session = new Session(
13629
- sessionId,
13630
- chat,
13631
- config,
13632
- this.connection,
13633
- this.settings
13634
- );
13635
- this.sessions.set(sessionId, session);
13636
- setTimeout(() => {
13637
- session.sendAvailableCommands();
13638
- }, 0);
13639
- const { availableModels, currentModelId } = buildAvailableModels(
13640
- config,
13641
- loadedSettings
13642
- );
13643
- const response = {
13644
- sessionId,
13645
- modes: {
13646
- availableModes: buildAvailableModes(config.isPlanEnabled()),
13647
- currentModeId: config.getApprovalMode()
13648
- },
13649
- models: {
13650
- availableModels,
13651
- currentModelId
13652
- }
13653
- };
13654
- return response;
13655
- }
13656
- async loadSession({
13657
- sessionId,
13658
- cwd,
13659
- mcpServers
13660
- }) {
13661
- const config = await this.initializeSessionConfig(
13662
- sessionId,
13663
- cwd,
13664
- mcpServers
13665
- );
13666
- const sessionSelector = new SessionSelector(config.storage);
13667
- const { sessionData, sessionPath } = await sessionSelector.resolveSession(sessionId);
13668
- const clientHistory = convertSessionToClientHistory(sessionData.messages);
13669
- const geminiClient = config.getGeminiClient();
13670
- await geminiClient.initialize();
13671
- await geminiClient.resumeChat(clientHistory, {
13672
- conversation: sessionData,
13673
- filePath: sessionPath
13674
- });
13675
- const session = new Session(
13676
- sessionId,
13677
- geminiClient.getChat(),
13678
- config,
13679
- this.connection,
13680
- this.settings
13681
- );
13682
- this.sessions.set(sessionId, session);
13683
- session.streamHistory(sessionData.messages);
13684
- setTimeout(() => {
13685
- session.sendAvailableCommands();
13686
- }, 0);
13687
- const { availableModels, currentModelId } = buildAvailableModels(
13688
- config,
13689
- this.settings
13690
- );
13691
- const response = {
13692
- modes: {
13693
- availableModes: buildAvailableModes(config.isPlanEnabled()),
13694
- currentModeId: config.getApprovalMode()
13695
- },
13696
- models: {
13697
- availableModels,
13698
- currentModelId
13699
- }
13700
- };
13701
- return response;
13702
- }
13703
- async initializeSessionConfig(sessionId, cwd, mcpServers) {
13704
- const selectedAuthType = this.settings.merged.security.auth.selectedType;
13705
- if (!selectedAuthType) {
13706
- throw RequestError.authRequired();
13707
- }
13708
- const config = await this.newSessionConfig(sessionId, cwd, mcpServers);
13709
- try {
13710
- await config.refreshAuth(
13711
- selectedAuthType,
13712
- this.apiKey,
13713
- this.baseUrl,
13714
- this.customHeaders
13715
- );
13716
- } catch (e) {
13717
- debugLogger.error(`Authentication failed: ${e}`);
13718
- throw RequestError.authRequired();
13719
- }
13720
- if (this.clientCapabilities?.fs) {
13721
- const acpFileSystemService = new AcpFileSystemService(
13722
- this.connection,
13723
- sessionId,
13724
- this.clientCapabilities.fs,
13725
- config.getFileSystemService(),
13726
- cwd
13727
- );
13728
- config.setFileSystemService(acpFileSystemService);
13729
- }
13730
- await config.initialize();
13731
- startupProfiler.flush(config);
13732
- startAutoMemoryIfEnabled(config);
13733
- return config;
13497
+ }
13498
+ var basicPermissionOptions = [
13499
+ {
13500
+ optionId: ToolConfirmationOutcome.ProceedOnce,
13501
+ name: "Allow",
13502
+ kind: "allow_once"
13503
+ },
13504
+ {
13505
+ optionId: ToolConfirmationOutcome.Cancel,
13506
+ name: "Reject",
13507
+ kind: "reject_once"
13734
13508
  }
13735
- async newSessionConfig(sessionId, cwd, mcpServers, loadedSettings) {
13736
- const currentSettings = loadedSettings || this.settings;
13737
- const mergedMcpServers = { ...currentSettings.merged.mcpServers };
13738
- for (const server of mcpServers) {
13739
- if ("type" in server && (server.type === "sse" || server.type === "http")) {
13740
- const headers = Object.fromEntries(
13741
- server.headers.map(({ name, value }) => [name, value])
13742
- );
13743
- mergedMcpServers[server.name] = new MCPServerConfig(
13744
- void 0,
13745
- // command
13746
- void 0,
13747
- // args
13748
- void 0,
13749
- // env
13750
- void 0,
13751
- // cwd
13752
- server.type === "sse" ? server.url : void 0,
13753
- // url (sse)
13754
- server.type === "http" ? server.url : void 0,
13755
- // httpUrl
13756
- headers
13757
- );
13758
- } else if ("command" in server) {
13759
- const env2 = {};
13760
- for (const { name: envName, value } of server.env) {
13761
- env2[envName] = value;
13509
+ ];
13510
+ function toPermissionOptions(confirmation, config, enablePermanentToolApproval = false) {
13511
+ const disableAlwaysAllow = config.getDisableAlwaysAllow();
13512
+ const options = [];
13513
+ if (!disableAlwaysAllow) {
13514
+ switch (confirmation.type) {
13515
+ case "edit":
13516
+ options.push({
13517
+ optionId: ToolConfirmationOutcome.ProceedAlways,
13518
+ name: "Allow for this session",
13519
+ kind: "allow_always"
13520
+ });
13521
+ if (enablePermanentToolApproval) {
13522
+ options.push({
13523
+ optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
13524
+ name: "Allow for this file in all future sessions",
13525
+ kind: "allow_always"
13526
+ });
13762
13527
  }
13763
- mergedMcpServers[server.name] = new MCPServerConfig(
13764
- server.command,
13765
- server.args,
13766
- env2,
13767
- cwd
13528
+ break;
13529
+ case "exec":
13530
+ options.push({
13531
+ optionId: ToolConfirmationOutcome.ProceedAlways,
13532
+ name: "Allow for this session",
13533
+ kind: "allow_always"
13534
+ });
13535
+ if (enablePermanentToolApproval) {
13536
+ options.push({
13537
+ optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
13538
+ name: "Allow this command for all future sessions",
13539
+ kind: "allow_always"
13540
+ });
13541
+ }
13542
+ break;
13543
+ case "mcp":
13544
+ options.push(
13545
+ {
13546
+ optionId: ToolConfirmationOutcome.ProceedAlwaysServer,
13547
+ name: "Allow all server tools for this session",
13548
+ kind: "allow_always"
13549
+ },
13550
+ {
13551
+ optionId: ToolConfirmationOutcome.ProceedAlwaysTool,
13552
+ name: "Allow tool for this session",
13553
+ kind: "allow_always"
13554
+ }
13768
13555
  );
13769
- }
13556
+ if (enablePermanentToolApproval) {
13557
+ options.push({
13558
+ optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
13559
+ name: "Allow tool for all future sessions",
13560
+ kind: "allow_always"
13561
+ });
13562
+ }
13563
+ break;
13564
+ case "info":
13565
+ options.push({
13566
+ optionId: ToolConfirmationOutcome.ProceedAlways,
13567
+ name: "Allow for this session",
13568
+ kind: "allow_always"
13569
+ });
13570
+ if (enablePermanentToolApproval) {
13571
+ options.push({
13572
+ optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
13573
+ name: "Allow for all future sessions",
13574
+ kind: "allow_always"
13575
+ });
13576
+ }
13577
+ break;
13578
+ case "ask_user":
13579
+ case "exit_plan_mode":
13580
+ break;
13581
+ default:
13582
+ break;
13770
13583
  }
13771
- const settings = {
13772
- ...currentSettings.merged,
13773
- mcpServers: mergedMcpServers
13774
- };
13775
- const config = await loadCliConfig(settings, sessionId, this.argv, { cwd });
13776
- createPolicyUpdater2(
13777
- config.getPolicyEngine(),
13778
- config.messageBus,
13779
- config.storage
13780
- );
13781
- return config;
13782
13584
  }
13783
- async cancel(params) {
13784
- const session = this.sessions.get(params.sessionId);
13785
- if (!session) {
13786
- throw new Error(`Session not found: ${params.sessionId}`);
13585
+ options.push(...basicPermissionOptions);
13586
+ switch (confirmation.type) {
13587
+ case "edit":
13588
+ case "exec":
13589
+ case "mcp":
13590
+ case "info":
13591
+ case "ask_user":
13592
+ case "exit_plan_mode":
13593
+ case "sandbox_expansion":
13594
+ break;
13595
+ default: {
13596
+ const unreachable = confirmation;
13597
+ throw new Error(`Unexpected: ${unreachable}`);
13787
13598
  }
13788
- await session.cancelPendingPrompt();
13789
13599
  }
13790
- async prompt(params) {
13791
- const session = this.sessions.get(params.sessionId);
13792
- if (!session) {
13793
- throw new Error(`Session not found: ${params.sessionId}`);
13600
+ return options;
13601
+ }
13602
+ function toAcpToolKind(kind) {
13603
+ switch (kind) {
13604
+ case Kind.Read:
13605
+ case Kind.Edit:
13606
+ case Kind.Execute:
13607
+ case Kind.Search:
13608
+ case Kind.Delete:
13609
+ case Kind.Move:
13610
+ case Kind.Think:
13611
+ case Kind.Fetch:
13612
+ case Kind.SwitchMode:
13613
+ case Kind.Other:
13614
+ return kind;
13615
+ case Kind.Agent:
13616
+ return "think";
13617
+ case Kind.Plan:
13618
+ case Kind.Communicate:
13619
+ default:
13620
+ return "other";
13621
+ }
13622
+ }
13623
+ function buildAvailableModes(isPlanEnabled) {
13624
+ const modes = [
13625
+ {
13626
+ id: ApprovalMode.DEFAULT,
13627
+ name: "Default",
13628
+ description: "Prompts for approval"
13629
+ },
13630
+ {
13631
+ id: ApprovalMode.AUTO_EDIT,
13632
+ name: "Auto Edit",
13633
+ description: "Auto-approves edit tools"
13634
+ },
13635
+ {
13636
+ id: ApprovalMode.YOLO,
13637
+ name: "YOLO",
13638
+ description: "Auto-approves all tools"
13794
13639
  }
13795
- return session.prompt(params);
13640
+ ];
13641
+ if (isPlanEnabled) {
13642
+ modes.push({
13643
+ id: ApprovalMode.PLAN,
13644
+ name: "Plan",
13645
+ description: "Read-only mode"
13646
+ });
13796
13647
  }
13797
- async setSessionMode(params) {
13798
- const session = this.sessions.get(params.sessionId);
13799
- if (!session) {
13800
- throw new Error(`Session not found: ${params.sessionId}`);
13648
+ return modes;
13649
+ }
13650
+ function buildAvailableModels(config, settings) {
13651
+ const preferredModel = config.getModel() || DEFAULT_GEMINI_MODEL_AUTO;
13652
+ const shouldShowPreviewModels = config.getHasAccessToPreviewModel();
13653
+ const useGemini31 = config.getGemini31LaunchedSync?.() ?? false;
13654
+ const useGemini31FlashLite = config.getGemini31FlashLiteLaunchedSync?.() ?? false;
13655
+ const selectedAuthType = settings.merged.security.auth.selectedType;
13656
+ const useCustomToolModel = useGemini31 && selectedAuthType === AuthType.USE_GEMINI;
13657
+ if (config.getExperimentalDynamicModelConfiguration?.() === true && config.getModelConfigService) {
13658
+ const options = config.getModelConfigService().getAvailableModelOptions({
13659
+ useGemini3_1: useGemini31,
13660
+ useGemini3_1FlashLite: useGemini31FlashLite,
13661
+ useCustomTools: useCustomToolModel,
13662
+ hasAccessToPreview: shouldShowPreviewModels
13663
+ });
13664
+ return {
13665
+ availableModels: options,
13666
+ currentModelId: preferredModel
13667
+ };
13668
+ }
13669
+ const mainOptions = [
13670
+ {
13671
+ value: DEFAULT_GEMINI_MODEL_AUTO,
13672
+ title: getDisplayString(DEFAULT_GEMINI_MODEL_AUTO),
13673
+ description: "Let Gemini CLI decide the best model for the task: gemini-2.5-pro, gemini-2.5-flash"
13801
13674
  }
13802
- return session.setMode(params.modeId);
13675
+ ];
13676
+ if (shouldShowPreviewModels) {
13677
+ mainOptions.unshift({
13678
+ value: PREVIEW_GEMINI_MODEL_AUTO,
13679
+ title: getDisplayString(PREVIEW_GEMINI_MODEL_AUTO),
13680
+ description: useGemini31 ? "Let Gemini CLI decide the best model for the task: gemini-3.1-pro, gemini-3-flash" : "Let Gemini CLI decide the best model for the task: gemini-3-pro, gemini-3-flash"
13681
+ });
13803
13682
  }
13804
- async unstable_setSessionModel(params) {
13805
- const session = this.sessions.get(params.sessionId);
13806
- if (!session) {
13807
- throw new Error(`Session not found: ${params.sessionId}`);
13683
+ const manualOptions = [
13684
+ {
13685
+ value: DEFAULT_GEMINI_MODEL,
13686
+ title: getDisplayString(DEFAULT_GEMINI_MODEL)
13687
+ },
13688
+ {
13689
+ value: DEFAULT_GEMINI_FLASH_MODEL,
13690
+ title: getDisplayString(DEFAULT_GEMINI_FLASH_MODEL)
13691
+ },
13692
+ {
13693
+ value: DEFAULT_GEMINI_FLASH_LITE_MODEL,
13694
+ title: getDisplayString(DEFAULT_GEMINI_FLASH_LITE_MODEL)
13808
13695
  }
13809
- return session.setModel(params.modelId);
13696
+ ];
13697
+ if (shouldShowPreviewModels) {
13698
+ const previewProModel = useGemini31 ? PREVIEW_GEMINI_3_1_MODEL : PREVIEW_GEMINI_MODEL;
13699
+ const previewProValue = useCustomToolModel ? PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL : previewProModel;
13700
+ const previewOptions = [
13701
+ {
13702
+ value: previewProValue,
13703
+ title: getDisplayString(previewProModel)
13704
+ },
13705
+ {
13706
+ value: PREVIEW_GEMINI_FLASH_MODEL,
13707
+ title: getDisplayString(PREVIEW_GEMINI_FLASH_MODEL)
13708
+ }
13709
+ ];
13710
+ if (useGemini31FlashLite) {
13711
+ previewOptions.push({
13712
+ value: PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL,
13713
+ title: getDisplayString(PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL)
13714
+ });
13715
+ }
13716
+ manualOptions.unshift(...previewOptions);
13810
13717
  }
13811
- };
13718
+ const scaleOptions = (options) => options.map((o) => ({
13719
+ modelId: o.value,
13720
+ name: o.title,
13721
+ description: o.description
13722
+ }));
13723
+ return {
13724
+ availableModels: [
13725
+ ...scaleOptions(mainOptions),
13726
+ ...scaleOptions(manualOptions)
13727
+ ],
13728
+ currentModelId: preferredModel
13729
+ };
13730
+ }
13731
+
13732
+ // packages/cli/src/acp/acpSession.ts
13733
+ var StructuredErrorSchema = external_exports.object({
13734
+ status: external_exports.number().optional(),
13735
+ message: external_exports.string().optional()
13736
+ });
13812
13737
  var Session = class {
13813
13738
  constructor(id, chat, context, connection, settings) {
13814
13739
  this.id = id;
@@ -13819,6 +13744,10 @@ var Session = class {
13819
13744
  }
13820
13745
  pendingPrompt = null;
13821
13746
  commandHandler = new CommandHandler();
13747
+ callIdCounter = 0;
13748
+ generateCallId(name) {
13749
+ return `${name}-${Date.now()}-${++this.callIdCounter}`;
13750
+ }
13822
13751
  async cancelPendingPrompt() {
13823
13752
  if (!this.pendingPrompt) {
13824
13753
  throw new Error("Not currently generating");
@@ -13919,16 +13848,13 @@ ${thought.description}`;
13919
13848
  this.pendingPrompt = pendingSend;
13920
13849
  await this.context.config.waitForMcpInit();
13921
13850
  const promptId = Math.random().toString(16).slice(2);
13922
- const chat = this.chat;
13923
13851
  const parts = await this.#resolvePrompt(params.prompt, pendingSend.signal);
13924
13852
  let commandText = "";
13925
13853
  for (const part of parts) {
13926
13854
  if (typeof part === "object" && part !== null) {
13927
- if ("text" in part) {
13855
+ if (isTextPart(part)) {
13928
13856
  const text = part.text;
13929
- if (typeof text === "string") {
13930
- commandText += text;
13931
- }
13857
+ commandText += text;
13932
13858
  } else {
13933
13859
  break;
13934
13860
  }
@@ -13952,80 +13878,108 @@ ${thought.description}`;
13952
13878
  let totalInputTokens = 0;
13953
13879
  let totalOutputTokens = 0;
13954
13880
  const modelUsageMap = /* @__PURE__ */ new Map();
13955
- let nextMessage = { role: "user", parts };
13956
- while (nextMessage !== null) {
13881
+ let currentParts = parts;
13882
+ let turnCount = 0;
13883
+ const maxTurns = this.context.config.getMaxSessionTurns();
13884
+ while (true) {
13885
+ turnCount++;
13886
+ if (maxTurns >= 0 && turnCount > maxTurns) {
13887
+ return {
13888
+ stopReason: "max_turn_requests",
13889
+ _meta: {
13890
+ quota: {
13891
+ token_count: {
13892
+ input_tokens: totalInputTokens,
13893
+ output_tokens: totalOutputTokens
13894
+ },
13895
+ model_usage: Array.from(modelUsageMap.entries()).map(
13896
+ ([modelName, counts]) => ({
13897
+ model: modelName,
13898
+ token_count: {
13899
+ input_tokens: counts.input,
13900
+ output_tokens: counts.output
13901
+ }
13902
+ })
13903
+ )
13904
+ }
13905
+ }
13906
+ };
13907
+ }
13957
13908
  if (pendingSend.signal.aborted) {
13958
- chat.addHistory(nextMessage);
13959
- return { stopReason: CoreToolCallStatus.Cancelled };
13909
+ return { stopReason: "cancelled" };
13960
13910
  }
13961
- const functionCalls = [];
13911
+ const toolCallRequests = [];
13912
+ let stopReason = "end_turn";
13913
+ let turnModelId = this.context.config.getModel();
13914
+ let turnInputTokens = 0;
13915
+ let turnOutputTokens = 0;
13962
13916
  try {
13963
- const routingContext = {
13964
- history: chat.getHistory(
13965
- /*curated=*/
13966
- true
13967
- ),
13968
- request: nextMessage?.parts ?? [],
13969
- signal: pendingSend.signal,
13970
- requestedModel: this.context.config.getModel()
13971
- };
13972
- const router = this.context.config.getModelRouterService();
13973
- const { model } = await router.route(routingContext);
13974
- const responseStream = await chat.sendMessageStream(
13975
- { model },
13976
- nextMessage?.parts ?? [],
13977
- promptId,
13917
+ const responseStream = this.context.geminiClient.sendMessageStream(
13918
+ currentParts,
13978
13919
  pendingSend.signal,
13979
- LlmRole.MAIN
13920
+ promptId
13980
13921
  );
13981
- nextMessage = null;
13982
- let turnInputTokens = 0;
13983
- let turnOutputTokens = 0;
13984
- let turnModelId = model;
13985
- for await (const resp of responseStream) {
13922
+ for await (const event of responseStream) {
13986
13923
  if (pendingSend.signal.aborted) {
13987
- return { stopReason: CoreToolCallStatus.Cancelled };
13988
- }
13989
- if (resp.type === StreamEventType.CHUNK && resp.value.usageMetadata) {
13990
- turnInputTokens = resp.value.usageMetadata.promptTokenCount ?? turnInputTokens;
13991
- turnOutputTokens = resp.value.usageMetadata.candidatesTokenCount ?? turnOutputTokens;
13992
- if (resp.value.modelVersion) {
13993
- turnModelId = resp.value.modelVersion;
13994
- }
13924
+ return { stopReason: "cancelled" };
13995
13925
  }
13996
- if (resp.type === StreamEventType.CHUNK && resp.value.candidates && resp.value.candidates.length > 0) {
13997
- const candidate = resp.value.candidates[0];
13998
- for (const part of candidate.content?.parts ?? []) {
13999
- if (!part.text) {
14000
- continue;
14001
- }
13926
+ switch (event.type) {
13927
+ case GeminiEventType.Content: {
14002
13928
  const content = {
14003
13929
  type: "text",
14004
- text: part.text
13930
+ text: event.value
14005
13931
  };
14006
- this.sendUpdate({
14007
- sessionUpdate: part.thought ? "agent_thought_chunk" : "agent_message_chunk",
13932
+ await this.sendUpdate({
13933
+ sessionUpdate: "agent_message_chunk",
14008
13934
  content
14009
13935
  });
13936
+ break;
13937
+ }
13938
+ case GeminiEventType.Thought: {
13939
+ const thoughtText = `**${event.value.subject}**
13940
+ ${event.value.description}`;
13941
+ await this.sendUpdate({
13942
+ sessionUpdate: "agent_thought_chunk",
13943
+ content: { type: "text", text: thoughtText }
13944
+ });
13945
+ break;
14010
13946
  }
13947
+ case GeminiEventType.ToolCallRequest:
13948
+ toolCallRequests.push(event.value);
13949
+ break;
13950
+ case GeminiEventType.Finished: {
13951
+ const usage2 = event.value.usageMetadata;
13952
+ if (usage2) {
13953
+ turnInputTokens = usage2.promptTokenCount ?? turnInputTokens;
13954
+ turnOutputTokens = usage2.candidatesTokenCount ?? turnOutputTokens;
13955
+ }
13956
+ break;
13957
+ }
13958
+ case GeminiEventType.ModelInfo:
13959
+ turnModelId = event.value;
13960
+ break;
13961
+ case GeminiEventType.MaxSessionTurns:
13962
+ stopReason = "max_turn_requests";
13963
+ break;
13964
+ case GeminiEventType.LoopDetected:
13965
+ stopReason = "max_turn_requests";
13966
+ break;
13967
+ case GeminiEventType.ContextWindowWillOverflow:
13968
+ stopReason = "max_tokens";
13969
+ break;
13970
+ case GeminiEventType.Error: {
13971
+ const parseResult = StructuredErrorSchema.safeParse(
13972
+ event.value.error
13973
+ );
13974
+ const errData = parseResult.success ? parseResult.data : {};
13975
+ throw new RequestError(
13976
+ errData.status ?? 500,
13977
+ errData.message ?? "Unknown stream execution error."
13978
+ );
13979
+ }
13980
+ default:
13981
+ break;
14011
13982
  }
14012
- if (resp.type === StreamEventType.CHUNK && resp.value.functionCalls) {
14013
- functionCalls.push(...resp.value.functionCalls);
14014
- }
14015
- }
14016
- totalInputTokens += turnInputTokens;
14017
- totalOutputTokens += turnOutputTokens;
14018
- if (turnInputTokens > 0 || turnOutputTokens > 0) {
14019
- const existing = modelUsageMap.get(turnModelId) ?? {
14020
- input: 0,
14021
- output: 0
14022
- };
14023
- existing.input += turnInputTokens;
14024
- existing.output += turnOutputTokens;
14025
- modelUsageMap.set(turnModelId, existing);
14026
- }
14027
- if (pendingSend.signal.aborted) {
14028
- return { stopReason: CoreToolCallStatus.Cancelled };
14029
13983
  }
14030
13984
  } catch (error) {
14031
13985
  if (getErrorStatus(error) === 429) {
@@ -14035,7 +13989,10 @@ ${thought.description}`;
14035
13989
  );
14036
13990
  }
14037
13991
  if (pendingSend.signal.aborted || error instanceof Error && error.name === "AbortError") {
14038
- return { stopReason: CoreToolCallStatus.Cancelled };
13992
+ return { stopReason: "cancelled" };
13993
+ }
13994
+ if (error instanceof RequestError) {
13995
+ throw error;
14039
13996
  }
14040
13997
  if (error instanceof InvalidStreamError || error && typeof error === "object" && "type" in error && (error.type === "NO_RESPONSE_TEXT" || error.type === "NO_FINISH_REASON" || error.type === "MALFORMED_FUNCTION_CALL" || error.type === "UNEXPECTED_TOOL_CALL")) {
14041
13998
  return {
@@ -14064,14 +14021,53 @@ ${thought.description}`;
14064
14021
  getAcpErrorMessage(error)
14065
14022
  );
14066
14023
  }
14067
- if (functionCalls.length > 0) {
14068
- const toolResponseParts = [];
14069
- for (const fc of functionCalls) {
14070
- const response = await this.runTool(pendingSend.signal, promptId, fc);
14071
- toolResponseParts.push(...response);
14072
- }
14073
- nextMessage = { role: "user", parts: toolResponseParts };
14024
+ totalInputTokens += turnInputTokens;
14025
+ totalOutputTokens += turnOutputTokens;
14026
+ if (turnInputTokens > 0 || turnOutputTokens > 0) {
14027
+ const existing = modelUsageMap.get(turnModelId) ?? {
14028
+ input: 0,
14029
+ output: 0
14030
+ };
14031
+ existing.input += turnInputTokens;
14032
+ existing.output += turnOutputTokens;
14033
+ modelUsageMap.set(turnModelId, existing);
14034
+ }
14035
+ if (stopReason !== "end_turn") {
14036
+ return {
14037
+ stopReason,
14038
+ _meta: {
14039
+ quota: {
14040
+ token_count: {
14041
+ input_tokens: totalInputTokens,
14042
+ output_tokens: totalOutputTokens
14043
+ },
14044
+ model_usage: Array.from(modelUsageMap.entries()).map(
14045
+ ([modelName, counts]) => ({
14046
+ model: modelName,
14047
+ token_count: {
14048
+ input_tokens: counts.input,
14049
+ output_tokens: counts.output
14050
+ }
14051
+ })
14052
+ )
14053
+ }
14054
+ }
14055
+ };
14056
+ }
14057
+ if (toolCallRequests.length === 0) {
14058
+ break;
14059
+ }
14060
+ const toolResponseParts = [];
14061
+ for (const tReq of toolCallRequests) {
14062
+ const fc = {
14063
+ id: tReq.callId,
14064
+ name: tReq.name,
14065
+ args: tReq.args
14066
+ };
14067
+ const response = await this.runTool(pendingSend.signal, promptId, fc);
14068
+ toolResponseParts.push(...response);
14074
14069
  }
14070
+ currentParts = toolResponseParts;
14075
14071
  }
14076
14072
  const modelUsageArray = Array.from(modelUsageMap.entries()).map(
14077
14073
  ([modelName, counts]) => ({
@@ -14118,7 +14114,7 @@ ${thought.description}`;
14118
14114
  await this.connection.sessionUpdate(params);
14119
14115
  }
14120
14116
  async runTool(abortSignal, promptId, fc) {
14121
- const callId = fc.id ?? GeminiAgent.generateCallId(fc.name || "unknown");
14117
+ const callId = fc.id ?? this.generateCallId(fc.name || "unknown");
14122
14118
  const args = fc.args ?? {};
14123
14119
  const startTime = Date.now();
14124
14120
  const errorResponse = (error) => {
@@ -14410,7 +14406,7 @@ ${thought.description}`;
14410
14406
  let resolvedSuccessfully = false;
14411
14407
  let readDirectly = false;
14412
14408
  try {
14413
- const absolutePath = path13.resolve(
14409
+ const absolutePath = path12.resolve(
14414
14410
  this.context.config.getTargetDir(),
14415
14411
  pathName
14416
14412
  );
@@ -14486,7 +14482,7 @@ ${thought.description}`;
14486
14482
  }
14487
14483
  }
14488
14484
  if (!validationError) {
14489
- if ((path13.isAbsolute(pathName) || !isWithinRoot(
14485
+ if ((path12.isAbsolute(pathName) || !isWithinRoot(
14490
14486
  absolutePath,
14491
14487
  this.context.config.getTargetDir()
14492
14488
  )) && !readDirectly) {
@@ -14590,7 +14586,7 @@ ${contentToPush}`;
14590
14586
  const lines = globResult.llmContent.split("\n");
14591
14587
  if (lines.length > 1 && lines[1]) {
14592
14588
  const firstMatchAbsolute = lines[1].trim();
14593
- currentPathSpec = path13.relative(
14589
+ currentPathSpec = path12.relative(
14594
14590
  this.context.config.getTargetDir(),
14595
14591
  firstMatchAbsolute
14596
14592
  );
@@ -14672,7 +14668,7 @@ ${contentToPush}`;
14672
14668
  const toolArgs = {
14673
14669
  include: pathSpecsToRead
14674
14670
  };
14675
- const callId = GeminiAgent.generateCallId(readManyFilesTool.name);
14671
+ const callId = this.generateCallId(readManyFilesTool.name);
14676
14672
  try {
14677
14673
  const invocation = readManyFilesTool.build(toolArgs);
14678
14674
  await this.sendUpdate({
@@ -14750,321 +14746,524 @@ Content from @${filePathSpecInContent}:
14750
14746
  throw error;
14751
14747
  }
14752
14748
  }
14753
- if (directContents.length > 0) {
14754
- const hasReferenceStart = processedQueryParts.some(
14755
- (p) => "text" in p && typeof p.text === "string" && p.text.includes(REFERENCE_CONTENT_START)
14749
+ if (directContents.length > 0) {
14750
+ const hasReferenceStart = processedQueryParts.some(
14751
+ (p) => "text" in p && typeof p.text === "string" && p.text.includes(REFERENCE_CONTENT_START)
14752
+ );
14753
+ if (!hasReferenceStart) {
14754
+ processedQueryParts.push({
14755
+ text: `
14756
+ ${REFERENCE_CONTENT_START}`
14757
+ });
14758
+ }
14759
+ for (const item of directContents) {
14760
+ processedQueryParts.push({
14761
+ text: `
14762
+ Content from @${item.spec}:
14763
+ `
14764
+ });
14765
+ if (item.content) {
14766
+ processedQueryParts.push({ text: item.content });
14767
+ } else if (item.part) {
14768
+ processedQueryParts.push(item.part);
14769
+ }
14770
+ }
14771
+ }
14772
+ if (embeddedContext.length > 0) {
14773
+ processedQueryParts.push({
14774
+ text: "\n--- Content from referenced context ---"
14775
+ });
14776
+ for (const contextPart of embeddedContext) {
14777
+ processedQueryParts.push({
14778
+ text: `
14779
+ Content from @${contextPart.uri}:
14780
+ `
14781
+ });
14782
+ if ("text" in contextPart) {
14783
+ processedQueryParts.push({
14784
+ text: contextPart.text
14785
+ });
14786
+ } else {
14787
+ processedQueryParts.push({
14788
+ inlineData: {
14789
+ mimeType: contextPart.mimeType ?? "application/octet-stream",
14790
+ data: contextPart.blob
14791
+ }
14792
+ });
14793
+ }
14794
+ }
14795
+ }
14796
+ return processedQueryParts;
14797
+ }
14798
+ debug(msg) {
14799
+ if (this.context.config.getDebugMode()) {
14800
+ debugLogger.warn(msg);
14801
+ }
14802
+ }
14803
+ };
14804
+
14805
+ // packages/cli/src/acp/acpFileSystemService.ts
14806
+ import os5 from "node:os";
14807
+ import path13 from "node:path";
14808
+ var AcpFileSystemService = class {
14809
+ constructor(connection, sessionId, capabilities, fallback, root) {
14810
+ this.connection = connection;
14811
+ this.sessionId = sessionId;
14812
+ this.capabilities = capabilities;
14813
+ this.fallback = fallback;
14814
+ this.root = root;
14815
+ }
14816
+ geminiDir = path13.join(os5.homedir(), ".gemini");
14817
+ shouldUseFallback(filePath) {
14818
+ return !isWithinRoot(filePath, this.root) || isWithinRoot(filePath, this.geminiDir);
14819
+ }
14820
+ normalizeFileSystemError(err) {
14821
+ const errorMessage = err instanceof Error ? err.message : String(err);
14822
+ if (errorMessage.includes("Resource not found") || errorMessage.includes("ENOENT") || errorMessage.includes("does not exist") || errorMessage.includes("No such file")) {
14823
+ const newErr = new Error(errorMessage);
14824
+ newErr.code = "ENOENT";
14825
+ throw newErr;
14826
+ }
14827
+ throw err;
14828
+ }
14829
+ async readTextFile(filePath) {
14830
+ if (!this.capabilities.readTextFile || this.shouldUseFallback(filePath)) {
14831
+ return this.fallback.readTextFile(filePath);
14832
+ }
14833
+ try {
14834
+ const response = await this.connection.readTextFile({
14835
+ path: filePath,
14836
+ sessionId: this.sessionId
14837
+ });
14838
+ return response.content;
14839
+ } catch (err) {
14840
+ this.normalizeFileSystemError(err);
14841
+ }
14842
+ }
14843
+ async writeTextFile(filePath, content) {
14844
+ if (!this.capabilities.writeTextFile || this.shouldUseFallback(filePath)) {
14845
+ return this.fallback.writeTextFile(filePath, content);
14846
+ }
14847
+ try {
14848
+ await this.connection.writeTextFile({
14849
+ path: filePath,
14850
+ content,
14851
+ sessionId: this.sessionId
14852
+ });
14853
+ } catch (err) {
14854
+ this.normalizeFileSystemError(err);
14855
+ }
14856
+ }
14857
+ };
14858
+
14859
+ // packages/cli/src/acp/acpSessionManager.ts
14860
+ var AcpSessionManager = class {
14861
+ constructor(settings, argv, connection) {
14862
+ this.settings = settings;
14863
+ this.argv = argv;
14864
+ this.connection = connection;
14865
+ }
14866
+ sessions = /* @__PURE__ */ new Map();
14867
+ clientCapabilities;
14868
+ setClientCapabilities(capabilities) {
14869
+ this.clientCapabilities = capabilities;
14870
+ }
14871
+ getSession(sessionId) {
14872
+ return this.sessions.get(sessionId);
14873
+ }
14874
+ async newSession({ cwd, mcpServers }, authDetails) {
14875
+ const sessionId = randomUUID2();
14876
+ const loadedSettings = loadSettings(cwd);
14877
+ const config = await this.newSessionConfig(
14878
+ sessionId,
14879
+ cwd,
14880
+ mcpServers,
14881
+ loadedSettings
14882
+ );
14883
+ const authType = loadedSettings.merged.security.auth.selectedType || AuthType.USE_GEMINI;
14884
+ let isAuthenticated = false;
14885
+ let authErrorMessage = "";
14886
+ try {
14887
+ await config.refreshAuth(
14888
+ authType,
14889
+ authDetails.apiKey,
14890
+ authDetails.baseUrl,
14891
+ authDetails.customHeaders
14892
+ );
14893
+ isAuthenticated = true;
14894
+ const contentGeneratorConfig = config.getContentGeneratorConfig();
14895
+ if (authType === AuthType.USE_GEMINI && (!contentGeneratorConfig || !contentGeneratorConfig.apiKey)) {
14896
+ isAuthenticated = false;
14897
+ authErrorMessage = "Gemini API key is missing or not configured.";
14898
+ }
14899
+ } catch (e) {
14900
+ isAuthenticated = false;
14901
+ authErrorMessage = getAcpErrorMessage(e);
14902
+ debugLogger.error(
14903
+ `Authentication failed: ${e instanceof Error ? e.stack : e}`
14904
+ );
14905
+ }
14906
+ if (!isAuthenticated) {
14907
+ throw new RequestError(
14908
+ -32e3,
14909
+ authErrorMessage || "Authentication required."
14910
+ );
14911
+ }
14912
+ if (this.clientCapabilities?.fs) {
14913
+ const acpFileSystemService = new AcpFileSystemService(
14914
+ this.connection,
14915
+ sessionId,
14916
+ this.clientCapabilities.fs,
14917
+ config.getFileSystemService(),
14918
+ cwd
14919
+ );
14920
+ config.setFileSystemService(acpFileSystemService);
14921
+ }
14922
+ await config.initialize();
14923
+ startupProfiler.flush(config);
14924
+ startAutoMemoryIfEnabled(config);
14925
+ const geminiClient = config.getGeminiClient();
14926
+ const chat = await geminiClient.startChat();
14927
+ const session = new Session(
14928
+ sessionId,
14929
+ chat,
14930
+ config,
14931
+ this.connection,
14932
+ this.settings
14933
+ );
14934
+ this.sessions.set(sessionId, session);
14935
+ setTimeout(() => {
14936
+ session.sendAvailableCommands();
14937
+ }, 0);
14938
+ const { availableModels, currentModelId } = buildAvailableModels(
14939
+ config,
14940
+ loadedSettings
14941
+ );
14942
+ const response = {
14943
+ sessionId,
14944
+ modes: {
14945
+ availableModes: buildAvailableModes(config.isPlanEnabled()),
14946
+ currentModeId: config.getApprovalMode()
14947
+ },
14948
+ models: {
14949
+ availableModels,
14950
+ currentModelId
14951
+ }
14952
+ };
14953
+ return response;
14954
+ }
14955
+ async loadSession({ sessionId, cwd, mcpServers }, authDetails) {
14956
+ const config = await this.initializeSessionConfig(
14957
+ sessionId,
14958
+ cwd,
14959
+ mcpServers,
14960
+ authDetails
14961
+ );
14962
+ const sessionSelector = new SessionSelector(config.storage);
14963
+ const { sessionData, sessionPath } = await sessionSelector.resolveSession(sessionId);
14964
+ const clientHistory = convertSessionToClientHistory(sessionData.messages);
14965
+ const geminiClient = config.getGeminiClient();
14966
+ await geminiClient.initialize();
14967
+ await geminiClient.resumeChat(clientHistory, {
14968
+ conversation: sessionData,
14969
+ filePath: sessionPath
14970
+ });
14971
+ const session = new Session(
14972
+ sessionId,
14973
+ geminiClient.getChat(),
14974
+ config,
14975
+ this.connection,
14976
+ this.settings
14977
+ );
14978
+ this.sessions.set(sessionId, session);
14979
+ session.streamHistory(sessionData.messages);
14980
+ setTimeout(() => {
14981
+ session.sendAvailableCommands();
14982
+ }, 0);
14983
+ const { availableModels, currentModelId } = buildAvailableModels(
14984
+ config,
14985
+ this.settings
14986
+ );
14987
+ const response = {
14988
+ modes: {
14989
+ availableModes: buildAvailableModes(config.isPlanEnabled()),
14990
+ currentModeId: config.getApprovalMode()
14991
+ },
14992
+ models: {
14993
+ availableModels,
14994
+ currentModelId
14995
+ }
14996
+ };
14997
+ return response;
14998
+ }
14999
+ async initializeSessionConfig(sessionId, cwd, mcpServers, authDetails) {
15000
+ const selectedAuthType = this.settings.merged.security.auth.selectedType;
15001
+ if (!selectedAuthType) {
15002
+ throw RequestError.authRequired();
15003
+ }
15004
+ const config = await this.newSessionConfig(sessionId, cwd, mcpServers);
15005
+ try {
15006
+ await config.refreshAuth(
15007
+ selectedAuthType,
15008
+ authDetails.apiKey,
15009
+ authDetails.baseUrl,
15010
+ authDetails.customHeaders
15011
+ );
15012
+ } catch (e) {
15013
+ debugLogger.error(`Authentication failed: ${e}`);
15014
+ throw RequestError.authRequired();
15015
+ }
15016
+ if (this.clientCapabilities?.fs) {
15017
+ const acpFileSystemService = new AcpFileSystemService(
15018
+ this.connection,
15019
+ sessionId,
15020
+ this.clientCapabilities.fs,
15021
+ config.getFileSystemService(),
15022
+ cwd
14756
15023
  );
14757
- if (!hasReferenceStart) {
14758
- processedQueryParts.push({
14759
- text: `
14760
- ${REFERENCE_CONTENT_START}`
14761
- });
14762
- }
14763
- for (const item of directContents) {
14764
- processedQueryParts.push({
14765
- text: `
14766
- Content from @${item.spec}:
14767
- `
14768
- });
14769
- if (item.content) {
14770
- processedQueryParts.push({ text: item.content });
14771
- } else if (item.part) {
14772
- processedQueryParts.push(item.part);
14773
- }
14774
- }
15024
+ config.setFileSystemService(acpFileSystemService);
14775
15025
  }
14776
- if (embeddedContext.length > 0) {
14777
- processedQueryParts.push({
14778
- text: "\n--- Content from referenced context ---"
14779
- });
14780
- for (const contextPart of embeddedContext) {
14781
- processedQueryParts.push({
14782
- text: `
14783
- Content from @${contextPart.uri}:
14784
- `
14785
- });
14786
- if ("text" in contextPart) {
14787
- processedQueryParts.push({
14788
- text: contextPart.text
14789
- });
14790
- } else {
14791
- processedQueryParts.push({
14792
- inlineData: {
14793
- mimeType: contextPart.mimeType ?? "application/octet-stream",
14794
- data: contextPart.blob
14795
- }
14796
- });
15026
+ await config.initialize();
15027
+ startupProfiler.flush(config);
15028
+ startAutoMemoryIfEnabled(config);
15029
+ return config;
15030
+ }
15031
+ async newSessionConfig(sessionId, cwd, mcpServers, loadedSettings) {
15032
+ const currentSettings = loadedSettings || this.settings;
15033
+ const mergedMcpServers = { ...currentSettings.merged.mcpServers };
15034
+ for (const server of mcpServers) {
15035
+ if ("type" in server && (server.type === "sse" || server.type === "http")) {
15036
+ const headers = Object.fromEntries(
15037
+ server.headers.map(({ name, value }) => [name, value])
15038
+ );
15039
+ mergedMcpServers[server.name] = new MCPServerConfig(
15040
+ void 0,
15041
+ // command
15042
+ void 0,
15043
+ // args
15044
+ void 0,
15045
+ // env
15046
+ void 0,
15047
+ // cwd
15048
+ server.type === "sse" ? server.url : void 0,
15049
+ // url (sse)
15050
+ server.type === "http" ? server.url : void 0,
15051
+ // httpUrl
15052
+ headers
15053
+ );
15054
+ } else if ("command" in server) {
15055
+ const env2 = {};
15056
+ for (const { name: envName, value } of server.env) {
15057
+ env2[envName] = value;
14797
15058
  }
15059
+ mergedMcpServers[server.name] = new MCPServerConfig(
15060
+ server.command,
15061
+ server.args,
15062
+ env2,
15063
+ cwd
15064
+ );
14798
15065
  }
14799
15066
  }
14800
- return processedQueryParts;
14801
- }
14802
- debug(msg) {
14803
- if (this.context.config.getDebugMode()) {
14804
- debugLogger.warn(msg);
14805
- }
15067
+ const settings = {
15068
+ ...currentSettings.merged,
15069
+ mcpServers: mergedMcpServers
15070
+ };
15071
+ const config = await loadCliConfig(settings, sessionId, this.argv, { cwd });
15072
+ createPolicyUpdater(
15073
+ config.getPolicyEngine(),
15074
+ config.messageBus,
15075
+ config.storage
15076
+ );
15077
+ return config;
14806
15078
  }
14807
15079
  };
14808
- function toToolCallContent(toolResult) {
14809
- if (toolResult.error?.message) {
14810
- throw new Error(toolResult.error.message);
15080
+
15081
+ // packages/cli/src/acp/acpRpcDispatcher.ts
15082
+ var GeminiAgent = class {
15083
+ constructor(context, settings, argv, connection) {
15084
+ this.context = context;
15085
+ this.settings = settings;
15086
+ this.sessionManager = new AcpSessionManager(settings, argv, connection);
14811
15087
  }
14812
- if (toolResult.returnDisplay) {
14813
- if (typeof toolResult.returnDisplay === "string") {
14814
- return {
14815
- type: "content",
14816
- content: { type: "text", text: toolResult.returnDisplay }
14817
- };
14818
- } else {
14819
- if ("fileName" in toolResult.returnDisplay) {
14820
- return {
14821
- type: "diff",
14822
- path: toolResult.returnDisplay.filePath ?? toolResult.returnDisplay.fileName,
14823
- oldText: toolResult.returnDisplay.originalContent,
14824
- newText: toolResult.returnDisplay.newContent,
14825
- _meta: {
14826
- kind: !toolResult.returnDisplay.originalContent ? "add" : toolResult.returnDisplay.newContent === "" ? "delete" : "modify"
14827
- }
14828
- };
14829
- }
14830
- return null;
15088
+ apiKey;
15089
+ baseUrl;
15090
+ customHeaders;
15091
+ sessionManager;
15092
+ async initialize(args) {
15093
+ if (args.clientCapabilities) {
15094
+ this.sessionManager.setClientCapabilities(args.clientCapabilities);
14831
15095
  }
14832
- } else {
14833
- return null;
14834
- }
14835
- }
14836
- var basicPermissionOptions = [
14837
- {
14838
- optionId: ToolConfirmationOutcome.ProceedOnce,
14839
- name: "Allow",
14840
- kind: "allow_once"
14841
- },
14842
- {
14843
- optionId: ToolConfirmationOutcome.Cancel,
14844
- name: "Reject",
14845
- kind: "reject_once"
14846
- }
14847
- ];
14848
- function toPermissionOptions(confirmation, config, enablePermanentToolApproval = false) {
14849
- const disableAlwaysAllow = config.getDisableAlwaysAllow();
14850
- const options = [];
14851
- if (!disableAlwaysAllow) {
14852
- switch (confirmation.type) {
14853
- case "edit":
14854
- options.push({
14855
- optionId: ToolConfirmationOutcome.ProceedAlways,
14856
- name: "Allow for this session",
14857
- kind: "allow_always"
14858
- });
14859
- if (enablePermanentToolApproval) {
14860
- options.push({
14861
- optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
14862
- name: "Allow for this file in all future sessions",
14863
- kind: "allow_always"
14864
- });
14865
- }
14866
- break;
14867
- case "exec":
14868
- options.push({
14869
- optionId: ToolConfirmationOutcome.ProceedAlways,
14870
- name: "Allow for this session",
14871
- kind: "allow_always"
14872
- });
14873
- if (enablePermanentToolApproval) {
14874
- options.push({
14875
- optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
14876
- name: "Allow this command for all future sessions",
14877
- kind: "allow_always"
14878
- });
15096
+ const authMethods = [
15097
+ {
15098
+ id: AuthType.LOGIN_WITH_GOOGLE,
15099
+ name: "Log in with Google",
15100
+ description: "Log in with your Google account"
15101
+ },
15102
+ {
15103
+ id: AuthType.USE_GEMINI,
15104
+ name: "Gemini API key",
15105
+ description: "Use an API key with Gemini Developer API",
15106
+ _meta: {
15107
+ "api-key": {
15108
+ provider: "google"
15109
+ }
14879
15110
  }
14880
- break;
14881
- case "mcp":
14882
- options.push(
14883
- {
14884
- optionId: ToolConfirmationOutcome.ProceedAlwaysServer,
14885
- name: "Allow all server tools for this session",
14886
- kind: "allow_always"
14887
- },
14888
- {
14889
- optionId: ToolConfirmationOutcome.ProceedAlwaysTool,
14890
- name: "Allow tool for this session",
14891
- kind: "allow_always"
15111
+ },
15112
+ {
15113
+ id: AuthType.USE_VERTEX_AI,
15114
+ name: "Vertex AI",
15115
+ description: "Use an API key with Vertex AI GenAI API"
15116
+ },
15117
+ {
15118
+ id: AuthType.GATEWAY,
15119
+ name: "AI API Gateway",
15120
+ description: "Use a custom AI API Gateway",
15121
+ _meta: {
15122
+ gateway: {
15123
+ protocol: "google",
15124
+ restartRequired: "false"
14892
15125
  }
14893
- );
14894
- if (enablePermanentToolApproval) {
14895
- options.push({
14896
- optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
14897
- name: "Allow tool for all future sessions",
14898
- kind: "allow_always"
14899
- });
14900
15126
  }
14901
- break;
14902
- case "info":
14903
- options.push({
14904
- optionId: ToolConfirmationOutcome.ProceedAlways,
14905
- name: "Allow for this session",
14906
- kind: "allow_always"
14907
- });
14908
- if (enablePermanentToolApproval) {
14909
- options.push({
14910
- optionId: ToolConfirmationOutcome.ProceedAlwaysAndSave,
14911
- name: "Allow for all future sessions",
14912
- kind: "allow_always"
14913
- });
15127
+ }
15128
+ ];
15129
+ await this.context.config.initialize();
15130
+ const version = await getVersion();
15131
+ return {
15132
+ protocolVersion: PROTOCOL_VERSION,
15133
+ authMethods,
15134
+ agentInfo: {
15135
+ name: "gemini-cli",
15136
+ title: "Gemini CLI",
15137
+ version
15138
+ },
15139
+ agentCapabilities: {
15140
+ loadSession: true,
15141
+ promptCapabilities: {
15142
+ image: true,
15143
+ audio: true,
15144
+ embeddedContext: true
15145
+ },
15146
+ mcpCapabilities: {
15147
+ http: true,
15148
+ sse: true
14914
15149
  }
14915
- break;
14916
- case "ask_user":
14917
- case "exit_plan_mode":
14918
- break;
14919
- default:
14920
- break;
14921
- }
15150
+ }
15151
+ };
14922
15152
  }
14923
- options.push(...basicPermissionOptions);
14924
- switch (confirmation.type) {
14925
- case "edit":
14926
- case "exec":
14927
- case "mcp":
14928
- case "info":
14929
- case "ask_user":
14930
- case "exit_plan_mode":
14931
- case "sandbox_expansion":
14932
- break;
14933
- default: {
14934
- const unreachable = confirmation;
14935
- throw new Error(`Unexpected: ${unreachable}`);
15153
+ async authenticate(req) {
15154
+ const { methodId } = req;
15155
+ const method = external_exports.nativeEnum(AuthType).parse(methodId);
15156
+ const selectedAuthType = this.settings.merged.security.auth.selectedType;
15157
+ if (selectedAuthType && selectedAuthType !== method) {
15158
+ await clearCachedCredentialFile();
14936
15159
  }
14937
- }
14938
- return options;
14939
- }
14940
- function toAcpToolKind(kind) {
14941
- switch (kind) {
14942
- case Kind.Read:
14943
- case Kind.Edit:
14944
- case Kind.Execute:
14945
- case Kind.Search:
14946
- case Kind.Delete:
14947
- case Kind.Move:
14948
- case Kind.Think:
14949
- case Kind.Fetch:
14950
- case Kind.SwitchMode:
14951
- case Kind.Other:
14952
- return kind;
14953
- case Kind.Agent:
14954
- return "think";
14955
- case Kind.Plan:
14956
- case Kind.Communicate:
14957
- default:
14958
- return "other";
14959
- }
14960
- }
14961
- function buildAvailableModes(isPlanEnabled) {
14962
- const modes = [
14963
- {
14964
- id: ApprovalMode.DEFAULT,
14965
- name: "Default",
14966
- description: "Prompts for approval"
14967
- },
14968
- {
14969
- id: ApprovalMode.AUTO_EDIT,
14970
- name: "Auto Edit",
14971
- description: "Auto-approves edit tools"
14972
- },
14973
- {
14974
- id: ApprovalMode.YOLO,
14975
- name: "YOLO",
14976
- description: "Auto-approves all tools"
15160
+ const meta = hasMeta(req) ? req._meta : void 0;
15161
+ const apiKey = typeof meta?.["api-key"] === "string" ? meta["api-key"] : void 0;
15162
+ try {
15163
+ if (apiKey) {
15164
+ this.apiKey = apiKey;
15165
+ }
15166
+ const gatewaySchema = external_exports.object({
15167
+ baseUrl: external_exports.string().optional(),
15168
+ headers: external_exports.record(external_exports.string()).optional()
15169
+ });
15170
+ let baseUrl;
15171
+ let headers;
15172
+ if (meta?.["gateway"]) {
15173
+ const result = gatewaySchema.safeParse(meta["gateway"]);
15174
+ if (result.success) {
15175
+ baseUrl = result.data.baseUrl;
15176
+ headers = result.data.headers;
15177
+ } else {
15178
+ throw new RequestError(
15179
+ -32602,
15180
+ `Malformed gateway payload: ${result.error.message}`
15181
+ );
15182
+ }
15183
+ }
15184
+ this.baseUrl = baseUrl;
15185
+ this.customHeaders = headers;
15186
+ await this.context.config.refreshAuth(
15187
+ method,
15188
+ apiKey ?? this.apiKey,
15189
+ baseUrl,
15190
+ headers
15191
+ );
15192
+ } catch (e) {
15193
+ throw new RequestError(-32e3, getAcpErrorMessage(e));
14977
15194
  }
14978
- ];
14979
- if (isPlanEnabled) {
14980
- modes.push({
14981
- id: ApprovalMode.PLAN,
14982
- name: "Plan",
14983
- description: "Read-only mode"
14984
- });
15195
+ this.settings.setValue(
15196
+ "User" /* User */,
15197
+ "security.auth.selectedType",
15198
+ method
15199
+ );
14985
15200
  }
14986
- return modes;
14987
- }
14988
- function buildAvailableModels(config, settings) {
14989
- const preferredModel = config.getModel() || DEFAULT_GEMINI_MODEL_AUTO;
14990
- const shouldShowPreviewModels = config.getHasAccessToPreviewModel();
14991
- const useGemini31 = config.getGemini31LaunchedSync?.() ?? false;
14992
- const useGemini31FlashLite = config.getGemini31FlashLiteLaunchedSync?.() ?? false;
14993
- const selectedAuthType = settings.merged.security.auth.selectedType;
14994
- const useCustomToolModel = useGemini31 && selectedAuthType === AuthType.USE_GEMINI;
14995
- if (config.getExperimentalDynamicModelConfiguration?.() === true && config.getModelConfigService) {
14996
- const options = config.getModelConfigService().getAvailableModelOptions({
14997
- useGemini3_1: useGemini31,
14998
- useGemini3_1FlashLite: useGemini31FlashLite,
14999
- useCustomTools: useCustomToolModel,
15000
- hasAccessToPreview: shouldShowPreviewModels
15001
- });
15201
+ getAuthDetails() {
15002
15202
  return {
15003
- availableModels: options,
15004
- currentModelId: preferredModel
15203
+ apiKey: this.apiKey,
15204
+ baseUrl: this.baseUrl,
15205
+ customHeaders: this.customHeaders
15005
15206
  };
15006
15207
  }
15007
- const mainOptions = [
15008
- {
15009
- value: DEFAULT_GEMINI_MODEL_AUTO,
15010
- title: getDisplayString(DEFAULT_GEMINI_MODEL_AUTO),
15011
- description: "Let Gemini CLI decide the best model for the task: gemini-2.5-pro, gemini-2.5-flash"
15208
+ async newSession(params) {
15209
+ return this.sessionManager.newSession(params, this.getAuthDetails());
15210
+ }
15211
+ async loadSession(params) {
15212
+ return this.sessionManager.loadSession(params, this.getAuthDetails());
15213
+ }
15214
+ async cancel(params) {
15215
+ const session = this.sessionManager.getSession(params.sessionId);
15216
+ if (!session) {
15217
+ throw new RequestError(
15218
+ -32602,
15219
+ `Session not found: ${params.sessionId}`
15220
+ );
15012
15221
  }
15013
- ];
15014
- if (shouldShowPreviewModels) {
15015
- mainOptions.unshift({
15016
- value: PREVIEW_GEMINI_MODEL_AUTO,
15017
- title: getDisplayString(PREVIEW_GEMINI_MODEL_AUTO),
15018
- description: useGemini31 ? "Let Gemini CLI decide the best model for the task: gemini-3.1-pro, gemini-3-flash" : "Let Gemini CLI decide the best model for the task: gemini-3-pro, gemini-3-flash"
15019
- });
15222
+ await session.cancelPendingPrompt();
15020
15223
  }
15021
- const manualOptions = [
15022
- {
15023
- value: DEFAULT_GEMINI_MODEL,
15024
- title: getDisplayString(DEFAULT_GEMINI_MODEL)
15025
- },
15026
- {
15027
- value: DEFAULT_GEMINI_FLASH_MODEL,
15028
- title: getDisplayString(DEFAULT_GEMINI_FLASH_MODEL)
15029
- },
15030
- {
15031
- value: DEFAULT_GEMINI_FLASH_LITE_MODEL,
15032
- title: getDisplayString(DEFAULT_GEMINI_FLASH_LITE_MODEL)
15224
+ async prompt(params) {
15225
+ const session = this.sessionManager.getSession(params.sessionId);
15226
+ if (!session) {
15227
+ throw new RequestError(
15228
+ -32602,
15229
+ `Session not found: ${params.sessionId}`
15230
+ );
15033
15231
  }
15034
- ];
15035
- if (shouldShowPreviewModels) {
15036
- const previewProModel = useGemini31 ? PREVIEW_GEMINI_3_1_MODEL : PREVIEW_GEMINI_MODEL;
15037
- const previewProValue = useCustomToolModel ? PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL : previewProModel;
15038
- const previewOptions = [
15039
- {
15040
- value: previewProValue,
15041
- title: getDisplayString(previewProModel)
15042
- },
15043
- {
15044
- value: PREVIEW_GEMINI_FLASH_MODEL,
15045
- title: getDisplayString(PREVIEW_GEMINI_FLASH_MODEL)
15046
- }
15047
- ];
15048
- if (useGemini31FlashLite) {
15049
- previewOptions.push({
15050
- value: PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL,
15051
- title: getDisplayString(PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL)
15052
- });
15232
+ return session.prompt(params);
15233
+ }
15234
+ async setSessionMode(params) {
15235
+ const session = this.sessionManager.getSession(params.sessionId);
15236
+ if (!session) {
15237
+ throw new RequestError(
15238
+ -32602,
15239
+ `Session not found: ${params.sessionId}`
15240
+ );
15053
15241
  }
15054
- manualOptions.unshift(...previewOptions);
15242
+ return session.setMode(params.modeId);
15055
15243
  }
15056
- const scaleOptions = (options) => options.map((o) => ({
15057
- modelId: o.value,
15058
- name: o.title,
15059
- description: o.description
15060
- }));
15061
- return {
15062
- availableModels: [
15063
- ...scaleOptions(mainOptions),
15064
- ...scaleOptions(manualOptions)
15065
- ],
15066
- currentModelId: preferredModel
15067
- };
15244
+ async unstable_setSessionModel(params) {
15245
+ const session = this.sessionManager.getSession(params.sessionId);
15246
+ if (!session) {
15247
+ throw new RequestError(
15248
+ -32602,
15249
+ `Session not found: ${params.sessionId}`
15250
+ );
15251
+ }
15252
+ return session.setModel(params.modelId);
15253
+ }
15254
+ };
15255
+
15256
+ // packages/cli/src/acp/acpStdioTransport.ts
15257
+ async function runAcpClient(config, settings, argv) {
15258
+ const { stdout: workingStdout } = createWorkingStdio();
15259
+ const stdout = Writable.toWeb(workingStdout);
15260
+ const stdin = Readable.toWeb(process.stdin);
15261
+ const stream = ndJsonStream(stdout, stdin);
15262
+ const connection = new AgentSideConnection(
15263
+ (connection2) => new GeminiAgent(config, settings, argv, connection2),
15264
+ stream
15265
+ );
15266
+ await connection.closed.finally(runExitCleanup);
15068
15267
  }
15069
15268
 
15070
15269
  // packages/cli/src/validateNonInterActiveAuth.ts
@@ -15426,7 +15625,7 @@ function getNodeMemoryArgs(isDebugMode2) {
15426
15625
  `Current heap size ${currentMaxOldSpaceSizeMb.toFixed(2)} MB`
15427
15626
  );
15428
15627
  }
15429
- if (process.env["GEMINI_CLI_NO_RELAUNCH"]) {
15628
+ if (process.env["IS_BINARY"] === "true" || process.env["GEMINI_CLI_NO_RELAUNCH"] || process.env["SANDBOX"]) {
15430
15629
  return [];
15431
15630
  }
15432
15631
  const args = [];
@@ -15511,7 +15710,7 @@ async function resolveSessionId(resumeArg, sessionIdArg) {
15511
15710
  }
15512
15711
  }
15513
15712
  async function startInteractiveUI(config, settings, startupWarnings, workspaceRoot = process.cwd(), resumedSessionData, initializationResult) {
15514
- const { startInteractiveUI: doStartUI } = await import("./interactiveCli-7HPLINVC.js");
15713
+ const { startInteractiveUI: doStartUI } = await import("./interactiveCli-74QXEIGP.js");
15515
15714
  await doStartUI(
15516
15715
  config,
15517
15716
  settings,
@@ -15522,12 +15721,13 @@ async function startInteractiveUI(config, settings, startupWarnings, workspaceRo
15522
15721
  );
15523
15722
  }
15524
15723
  async function main() {
15724
+ let config;
15525
15725
  const cliStartupHandle = startupProfiler.start("cli_startup");
15526
15726
  const adminControlsListner = setupAdminControlsListener();
15527
15727
  registerCleanup(adminControlsListner.cleanup);
15528
15728
  const cleanupStdio = patchStdio();
15529
15729
  registerSyncCleanup(() => {
15530
- initializeOutputListenersAndFlush();
15730
+ initializeOutputListenersAndFlush(config);
15531
15731
  cleanupStdio();
15532
15732
  });
15533
15733
  setupUnhandledRejectionHandler();
@@ -15622,7 +15822,8 @@ async function main() {
15622
15822
  }
15623
15823
  }
15624
15824
  const partialConfig = await loadCliConfig(settings.merged, sessionId, argv, {
15625
- projectHooks: settings.workspace.settings.hooks
15825
+ projectHooks: settings.workspace.settings.hooks,
15826
+ skipExtensions: true
15626
15827
  });
15627
15828
  adminControlsListner.setConfig(partialConfig);
15628
15829
  let initialAuthFailed = false;
@@ -15707,7 +15908,7 @@ ${finalArgs[promptIndex + 1]}`;
15707
15908
  }
15708
15909
  {
15709
15910
  const loadConfigHandle = startupProfiler.start("load_cli_config");
15710
- const config = await loadCliConfig(settings.merged, sessionId, argv, {
15911
+ config = await loadCliConfig(settings.merged, sessionId, argv, {
15711
15912
  projectHooks: settings.workspace.settings.hooks,
15712
15913
  worktreeSettings: worktreeInfo
15713
15914
  });
@@ -15715,7 +15916,7 @@ ${finalArgs[promptIndex + 1]}`;
15715
15916
  await config.storage.initialize();
15716
15917
  adminControlsListner.setConfig(config);
15717
15918
  if (config.isInteractive() && settings.merged.general.devtools) {
15718
- const { setupInitialActivityLogger } = await import("./devtoolsService-M4LZEBZD.js");
15919
+ const { setupInitialActivityLogger } = await import("./devtoolsService-KZLK5WRW.js");
15719
15920
  setupInitialActivityLogger(config);
15720
15921
  }
15721
15922
  registerTelemetryConfig(config);
@@ -15774,7 +15975,7 @@ ${finalArgs[promptIndex + 1]}`;
15774
15975
  const initAppHandle = startupProfiler.start("initialize_app");
15775
15976
  const initializationResult = await initializeApp(config, settings);
15776
15977
  initAppHandle?.end();
15777
- import("./liteRtServerManager-BENLLSF2.js").then(({ LiteRtServerManager }) => {
15978
+ import("./liteRtServerManager-J33F7APP.js").then(({ LiteRtServerManager }) => {
15778
15979
  const mergedGemma = settings.merged.experimental?.gemmaModelRouter;
15779
15980
  if (!mergedGemma) return;
15780
15981
  const userGemma = settings.forScope("User" /* User */).settings.experimental?.gemmaModelRouter;
@@ -15881,7 +16082,7 @@ ${input}` : wrappedContext;
15881
16082
  if (config.getDebugMode()) {
15882
16083
  debugLogger.log("Session ID: %s", sessionId);
15883
16084
  }
15884
- initializeOutputListenersAndFlush();
16085
+ initializeOutputListenersAndFlush(config);
15885
16086
  await runNonInteractive2({
15886
16087
  config,
15887
16088
  settings,
@@ -15893,7 +16094,7 @@ ${input}` : wrappedContext;
15893
16094
  process.exit(ExitCodes.SUCCESS);
15894
16095
  }
15895
16096
  }
15896
- function initializeOutputListenersAndFlush() {
16097
+ function initializeOutputListenersAndFlush(config) {
15897
16098
  if (coreEvents.listenerCount(CoreEvent.Output) === 0) {
15898
16099
  coreEvents.on(CoreEvent.Output, (payload) => {
15899
16100
  if (payload.isStderr) {
@@ -15902,22 +16103,38 @@ function initializeOutputListenersAndFlush() {
15902
16103
  writeToStdout(payload.chunk, payload.encoding);
15903
16104
  }
15904
16105
  });
15905
- if (coreEvents.listenerCount(CoreEvent.ConsoleLog) === 0) {
15906
- coreEvents.on(CoreEvent.ConsoleLog, (payload) => {
15907
- if (payload.type === "error" || payload.type === "warn") {
15908
- writeToStderr(payload.content + "\n");
15909
- } else {
15910
- writeToStderr(payload.content + "\n");
16106
+ }
16107
+ if (coreEvents.listenerCount(CoreEvent.ConsoleLog) === 0) {
16108
+ coreEvents.on(CoreEvent.ConsoleLog, (payload) => {
16109
+ if (payload.type === "error" || payload.type === "warn") {
16110
+ writeToStderr(payload.content + "\n");
16111
+ } else {
16112
+ writeToStderr(payload.content + "\n");
16113
+ }
16114
+ });
16115
+ }
16116
+ if (coreEvents.listenerCount(CoreEvent.UserFeedback) === 0) {
16117
+ coreEvents.on(CoreEvent.UserFeedback, (payload) => {
16118
+ writeToStderr(payload.message + "\n");
16119
+ });
16120
+ }
16121
+ const outputFormat = config?.getOutputFormat();
16122
+ const forceToStderr = outputFormat === "json" || config === void 0;
16123
+ coreEvents.drainBacklogs(
16124
+ (event, args) => {
16125
+ if (forceToStderr && event === CoreEvent.Output) {
16126
+ const payload = args[0];
16127
+ if (!payload.isStderr) {
16128
+ return {
16129
+ event,
16130
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
16131
+ args: [{ ...payload, isStderr: true }]
16132
+ };
15911
16133
  }
15912
- });
15913
- }
15914
- if (coreEvents.listenerCount(CoreEvent.UserFeedback) === 0) {
15915
- coreEvents.on(CoreEvent.UserFeedback, (payload) => {
15916
- writeToStderr(payload.message + "\n");
15917
- });
16134
+ }
16135
+ return { event, args };
15918
16136
  }
15919
- }
15920
- coreEvents.drainBacklogs();
16137
+ );
15921
16138
  }
15922
16139
  function setupAdminControlsListener() {
15923
16140
  let pendingSettings;