@google/gemini-cli 0.42.0-preview.2 → 0.43.0-preview.0

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 (80) hide show
  1. package/bundle/{chunk-FIIOJPLW.js → chunk-43AGRA7S.js} +3 -3
  2. package/bundle/{chunk-M6ZQAQKH.js → chunk-46T44JOY.js} +1 -1
  3. package/bundle/{chunk-OFOKTVUH.js → chunk-4TLQKGTR.js} +1 -1
  4. package/bundle/{chunk-4NXNVHPO.js → chunk-6XOSIMPZ.js} +8 -9
  5. package/bundle/{chunk-AAU5XCLJ.js → chunk-HQXINMBL.js} +2 -2
  6. package/bundle/{chunk-QM234EIA.js → chunk-JENIU3E3.js} +1 -1
  7. package/bundle/{chunk-R7BHIYZD.js → chunk-LBQFRHYD.js} +1 -1
  8. package/bundle/{chunk-WLPWIJ3Y.js → chunk-LFGJVOVZ.js} +486 -381
  9. package/bundle/{chunk-DEKZKOVU.js → chunk-MRHFLHPJ.js} +2 -2
  10. package/bundle/{chunk-ODIOD5TJ.js → chunk-MXKXLNQD.js} +3 -3
  11. package/bundle/{chunk-ECNYAST2.js → chunk-N6QYTC2T.js} +5417 -5376
  12. package/bundle/{chunk-WOGMVEEF.js → chunk-NBRZ4A3S.js} +2170 -791
  13. package/bundle/{chunk-Q24MYLMP.js → chunk-P4UQCQUB.js} +3 -3
  14. package/bundle/{chunk-S3WIE72K.js → chunk-PGJUNQPO.js} +34 -16
  15. package/bundle/{chunk-THNM4JU6.js → chunk-PSWUV2OO.js} +3 -3
  16. package/bundle/{chunk-6QBZKEWW.js → chunk-PYLHDAUK.js} +3 -3
  17. package/bundle/{chunk-2KRAWFEQ.js → chunk-Q23X5R4A.js} +486 -381
  18. package/bundle/{chunk-SJ6AOVZF.js → chunk-QYUN3J2L.js} +533 -441
  19. package/bundle/{chunk-77HSANAH.js → chunk-SAISHGWW.js} +1907 -716
  20. package/bundle/{chunk-I6IY72IP.js → chunk-SYD5SJFT.js} +38 -23
  21. package/bundle/{chunk-JW36FWGZ.js → chunk-T3SUXLQQ.js} +2 -2
  22. package/bundle/{chunk-BLNG7CSO.js → chunk-UIG2IVPJ.js} +34 -16
  23. package/bundle/{chunk-JEW7ZIWE.js → chunk-UJ26GAE5.js} +5326 -5290
  24. package/bundle/{chunk-E54WEGH3.js → chunk-UNAVBUTP.js} +14729 -7452
  25. package/bundle/{chunk-LYMYMKWM.js → chunk-WQOLTO3C.js} +1 -1
  26. package/bundle/{chunk-WFKT4UTI.js → chunk-X26T73X6.js} +3 -3
  27. package/bundle/{cleanup-5FPOUEHR.js → cleanup-EIZJH2E3.js} +3 -3
  28. package/bundle/{cleanup-G7DNOS4V.js → cleanup-MI76P55B.js} +3 -3
  29. package/bundle/{cleanup-GZM5KIZA.js → cleanup-NZBQYB7U.js} +3 -3
  30. package/bundle/{core-IYSSLWMM.js → core-ERSGIOMQ.js} +30 -2
  31. package/bundle/{dist-D7FZVGG3.js → core-T2TBFAYG.js} +30 -2
  32. package/bundle/{devtoolsService-UADEEKOH.js → devtoolsService-7KZDSYEF.js} +3 -3
  33. package/bundle/{devtoolsService-3XOQOECV.js → devtoolsService-FYTOIC37.js} +3 -3
  34. package/bundle/{devtoolsService-7ZN7CSSO.js → devtoolsService-LV5NJ2BT.js} +4 -5
  35. package/bundle/{dist-GF2RNVWZ.js → dist-ETX67B7P.js} +30 -2
  36. package/bundle/docs/changelogs/index.md +14 -0
  37. package/bundle/docs/changelogs/latest.md +108 -166
  38. package/bundle/docs/changelogs/preview.md +227 -103
  39. package/bundle/docs/cli/auto-memory.md +60 -38
  40. package/bundle/docs/cli/settings.md +1 -1
  41. package/bundle/docs/cli/tutorials/memory-management.md +1 -1
  42. package/bundle/docs/extensions/releasing.md +58 -24
  43. package/bundle/docs/reference/configuration.md +14 -1
  44. package/bundle/docs/reference/keyboard-shortcuts.md +23 -0
  45. package/bundle/{gemini-IRKIMLB4.js → gemini-IVKBXHDT.js} +160 -60
  46. package/bundle/{gemini-MWN2MSYV.js → gemini-JKWQQTKP.js} +160 -60
  47. package/bundle/{gemini-IMX43TZ4.js → gemini-Z77GAAR6.js} +331 -245
  48. package/bundle/gemini.js +8 -8
  49. package/bundle/{interactiveCli-SAMKYHUU.js → interactiveCli-36WZS6KT.js} +1704 -1457
  50. package/bundle/{interactiveCli-752P4PTI.js → interactiveCli-BQ36B66Z.js} +1703 -1457
  51. package/bundle/{interactiveCli-VX6GBWOV.js → interactiveCli-SME5QTEN.js} +1967 -1739
  52. package/bundle/{liteRtServerManager-CDLVKT7N.js → liteRtServerManager-2QD4R3A3.js} +5 -5
  53. package/bundle/{liteRtServerManager-FPYU5KEK.js → liteRtServerManager-ISYDOBNC.js} +5 -5
  54. package/bundle/{liteRtServerManager-OWPZ35U6.js → liteRtServerManager-N6OMT6W5.js} +5 -5
  55. package/bundle/{memoryDiscovery-FB7MMKTA.js → memoryDiscovery-LLSKN6HL.js} +1 -1
  56. package/bundle/{memoryDiscovery-KSYZVCWF.js → memoryDiscovery-SJ7P6RCN.js} +1 -1
  57. package/bundle/node_modules/@google/gemini-cli-devtools/package.json +1 -1
  58. package/bundle/{oauth2-provider-446FDCUW.js → oauth2-provider-DOSIH6VE.js} +2 -2
  59. package/bundle/{oauth2-provider-RQNNLGWV.js → oauth2-provider-TZF6EZRX.js} +2 -2
  60. package/bundle/{oauth2-provider-6W4IY3LC.js → oauth2-provider-VFOABWBW.js} +73 -39
  61. package/bundle/{start-6U3XBAVH.js → start-3GPIRK3E.js} +7 -7
  62. package/bundle/{start-KUNHDGRA.js → start-6NONW677.js} +7 -7
  63. package/bundle/{start-TTLMBKNX.js → start-M6MUPEJS.js} +7 -7
  64. package/package.json +1 -1
  65. package/bundle/chunk-76KOJPMV.js +0 -391
  66. package/bundle/chunk-LHVIO4J4.js +0 -81544
  67. package/bundle/chunk-OP6THN3K.js +0 -118
  68. package/bundle/chunk-RO2XVFEU.js +0 -512
  69. package/bundle/chunk-WRDVEMWE.js +0 -1571
  70. package/bundle/chunk-YDC4M26X.js +0 -156
  71. package/bundle/chunk-ZDP2ZWKG.js +0 -17230
  72. package/bundle/chunk-ZFOGBX2H.js +0 -356008
  73. package/bundle/cleanup-J6AUEKWI.js +0 -33
  74. package/bundle/devtoolsService-KTUMQHXG.js +0 -857
  75. package/bundle/dist-HBMVDPXB.js +0 -2096
  76. package/bundle/gemini-SYFUC6XO.js +0 -16256
  77. package/bundle/interactiveCli-37SKHAKX.js +0 -34505
  78. package/bundle/liteRtServerManager-OWTQEYE6.js +0 -66
  79. package/bundle/oauth2-provider-TITPL3DN.js +0 -237
  80. package/bundle/start-TZXEJLTH.js +0 -19
@@ -1,7 +1,8 @@
1
1
  # Release extensions
2
2
 
3
3
  Release Gemini CLI extensions to your users through a Git repository or GitHub
4
- Releases.
4
+ Releases. This guide explains how to share your work, list it in the gallery,
5
+ and manage updates.
5
6
 
6
7
  Git repository releases are the simplest approach and offer the most flexibility
7
8
  for managing development branches. GitHub Releases are more efficient for
@@ -153,29 +154,62 @@ jobs:
153
154
  release/win32.arm64.my-tool.zip
154
155
  ```
155
156
 
156
- ## Migrating an Extension Repository
157
+ ## Migrate an extension repository
157
158
 
158
- If you need to move your extension to a new repository (for example, from a
159
- personal account to an organization) or rename it, you can use the `migratedTo`
160
- property in your `gemini-extension.json` file to seamlessly transition your
159
+ If you move your extension to a new repository or rename it, use the
160
+ `migratedTo` property in `gemini-extension.json` to seamlessly transition your
161
161
  users.
162
162
 
163
- 1. **Create the new repository**: Setup your extension in its new location.
164
- 2. **Update the old repository**: In your original repository, update the
165
- `gemini-extension.json` file to include the `migratedTo` property, pointing
166
- to the new repository URL, and bump the version number. You can optionally
167
- change the `name` of your extension at this time in the new repository.
168
- ```json
169
- {
170
- "name": "my-extension",
171
- "version": "1.1.0",
172
- "migratedTo": "https://github.com/new-owner/new-extension-repo"
173
- }
174
- ```
175
- 3. **Release the update**: Publish this new version in your old repository.
176
-
177
- When users check for updates, Gemini CLI will detect the `migratedTo` field,
178
- verify that the new repository contains a valid extension update, and
179
- automatically update their local installation to track the new source and name
180
- moving forward. All extension settings will automatically migrate to the new
181
- installation.
163
+ 1. **Create the new repository:** Set up your extension in its new location.
164
+ 2. **Update the old repository:** In your original repository, update the
165
+ `gemini-extension.json` file to include the `migratedTo` property pointing
166
+ to the new repository URL, and increment the version number.
167
+ ```json
168
+ {
169
+ "name": "my-extension",
170
+ "version": "1.1.0",
171
+ "migratedTo": "https://github.com/new-owner/new-extension-repo"
172
+ }
173
+ ```
174
+ 3. **Release the update:** Publish this new version in your old repository.
175
+
176
+ When users check for updates, Gemini CLI detects the `migratedTo` field,
177
+ verifies the new repository, and automatically updates their local installation
178
+ to track the new source. All settings migrate automatically.
179
+
180
+ ## How updates work
181
+
182
+ Gemini CLI automatically checks for extension updates based on the installation
183
+ method. Understanding these mechanisms helps you ensure your users always have
184
+ the latest version.
185
+
186
+ ### Sync manifest and tags
187
+
188
+ For GitHub releases, always ensure the `version` in `gemini-extension.json`
189
+ matches your GitHub release tag. While the CLI uses tags for update detection,
190
+ it displays the manifest version in the UI. Keeping them in sync prevents
191
+ confusion.
192
+
193
+ ### Update mechanisms
194
+
195
+ <details>
196
+ <summary>Technical update details</summary>
197
+
198
+ The CLI uses different strategies depending on the installation type:
199
+
200
+ - **GitHub releases:** The CLI queries the GitHub API for the latest release
201
+ tag. It ignores the `version` field in the manifest for detection.
202
+ - **Git clones:** The CLI runs `git ls-remote` to compare the latest remote
203
+ commit hash with your local `HEAD`.
204
+ - **Local extensions:** The CLI compares the `version` field in the source
205
+ directory's manifest with the installed version.
206
+
207
+ To verify an extension's installation type, inspect the `type` field in the
208
+ metadata file at `~/.gemini/extensions/<name>/.gemini-extension-install.json`.
209
+
210
+ </details>
211
+
212
+ <!-- prettier-ignore -->
213
+ > [!IMPORTANT]
214
+ > The `migratedTo` flow requires at least one release on the new repository for
215
+ > the CLI to recognize it as a valid update source.
@@ -700,6 +700,19 @@ their corresponding top-level category object in your `settings.json` file.
700
700
  "extends": "gemini-3-flash-base",
701
701
  "modelConfig": {}
702
702
  },
703
+ "context-snapshotter": {
704
+ "extends": "gemini-3-flash-base",
705
+ "modelConfig": {
706
+ "generateContentConfig": {
707
+ "thinkingConfig": {
708
+ "thinkingLevel": "HIGH"
709
+ },
710
+ "temperature": 1,
711
+ "topP": 0.95,
712
+ "topK": 64
713
+ }
714
+ }
715
+ },
703
716
  "chat-compression-3-pro": {
704
717
  "modelConfig": {
705
718
  "model": "gemini-3-pro-preview"
@@ -1795,7 +1808,7 @@ their corresponding top-level category object in your `settings.json` file.
1795
1808
  - **`experimental.voice.stopGracePeriodMs`** (number):
1796
1809
  - **Description:** How long to wait for final transcription after stopping
1797
1810
  recording.
1798
- - **Default:** `1000`
1811
+ - **Default:** `4000`
1799
1812
 
1800
1813
  - **`experimental.adk.agentSessionNoninteractiveEnabled`** (boolean):
1801
1814
  - **Description:** Enable non-interactive agent sessions.
@@ -326,6 +326,29 @@ lines and `3w` moves forward three words.
326
326
  Counts are also supported for editing commands. For example, `3dd` deletes three
327
327
  lines and `2cw` changes two words.
328
328
 
329
+ ### Find, replace, yank, and paste in NORMAL mode
330
+
331
+ | Action | Keys |
332
+ | ----------------------------------------- | ----------- |
333
+ | Find next matching character | `f{char}` |
334
+ | Find previous matching character | `F{char}` |
335
+ | Move until before next matching character | `t{char}` |
336
+ | Move until after previous matching char | `T{char}` |
337
+ | Repeat latest character find | `;` |
338
+ | Repeat latest character find in reverse | `,` |
339
+ | Delete character before cursor | `X` |
340
+ | Toggle case under cursor | `~` |
341
+ | Replace character under cursor | `r{char}` |
342
+ | Yank line | `yy` |
343
+ | Yank to end of line | `Y` or `y$` |
344
+ | Yank word / WORD | `yw`, `yW` |
345
+ | Yank to end of word / WORD | `ye`, `yE` |
346
+ | Paste after cursor | `p` |
347
+ | Paste before cursor | `P` |
348
+
349
+ Delete and change operators also compose with character-find motions, so
350
+ commands such as `dfx`, `dtx`, `cFx`, and `cTx` are supported.
351
+
329
352
  ## Limitations
330
353
 
331
354
  - On [Windows Terminal](https://en.wikipedia.org/wiki/Windows_Terminal):
@@ -41,18 +41,18 @@ import {
41
41
  updateAllUpdatableExtensions,
42
42
  updateExtension,
43
43
  validateAuthMethod
44
- } from "./chunk-2KRAWFEQ.js";
44
+ } from "./chunk-Q23X5R4A.js";
45
45
  import {
46
46
  appEvents
47
47
  } from "./chunk-5PS3AYFU.js";
48
48
  import {
49
49
  startCommand,
50
50
  startServer
51
- } from "./chunk-OP6THN3K.js";
51
+ } from "./chunk-X26T73X6.js";
52
52
  import {
53
53
  exitCli,
54
54
  require_source
55
- } from "./chunk-R7BHIYZD.js";
55
+ } from "./chunk-4TLQKGTR.js";
56
56
  import {
57
57
  DEFAULT_PORT,
58
58
  GEMMA_MODEL_NAME,
@@ -86,11 +86,11 @@ import {
86
86
  readServerProcessInfo,
87
87
  resolveGemmaConfig,
88
88
  saveModelChange
89
- } from "./chunk-S3WIE72K.js";
89
+ } from "./chunk-PGJUNQPO.js";
90
90
  import {
91
91
  RELAUNCH_EXIT_CODE
92
- } from "./chunk-6QBZKEWW.js";
93
- import "./chunk-M6ZQAQKH.js";
92
+ } from "./chunk-PYLHDAUK.js";
93
+ import "./chunk-6XOSIMPZ.js";
94
94
  import {
95
95
  cleanupCheckpoints,
96
96
  registerCleanup,
@@ -99,7 +99,7 @@ import {
99
99
  runExitCleanup,
100
100
  runSyncCleanup,
101
101
  setupSignalHandlers
102
- } from "./chunk-DEKZKOVU.js";
102
+ } from "./chunk-MRHFLHPJ.js";
103
103
  import {
104
104
  AuthType,
105
105
  ChatRecordingService,
@@ -166,6 +166,7 @@ import {
166
166
  listInboxPatches,
167
167
  listInboxSkills,
168
168
  listMemoryFiles,
169
+ loadConversationRecord,
169
170
  logToolCall,
170
171
  logUserPrompt,
171
172
  parseAndFormatApiError,
@@ -189,7 +190,7 @@ import {
189
190
  updatePolicy,
190
191
  writeToStderr,
191
192
  writeToStdout
192
- } from "./chunk-WOGMVEEF.js";
193
+ } from "./chunk-NBRZ4A3S.js";
193
194
  import {
194
195
  ASK_USER_TOOL_NAME,
195
196
  DEFAULT_FILE_FILTERING_OPTIONS,
@@ -227,13 +228,14 @@ import {
227
228
  getDisplayString,
228
229
  getErrorMessage,
229
230
  getErrorType,
231
+ getProjectHash,
230
232
  homedir,
231
233
  isFatalToolError,
232
234
  isNodeError,
233
235
  loadServerHierarchicalMemory,
234
236
  resolveToRealPath,
235
237
  setGeminiMdFilename
236
- } from "./chunk-ECNYAST2.js";
238
+ } from "./chunk-N6QYTC2T.js";
237
239
  import "./chunk-664ZODQF.js";
238
240
  import "./chunk-RJTRUG2J.js";
239
241
  import "./chunk-IUUIT4SU.js";
@@ -1518,11 +1520,11 @@ var parser = new YargsParser({
1518
1520
  resolve: resolve2,
1519
1521
  // TODO: figure out a way to combine ESM and CJS coverage, such that
1520
1522
  // we can exercise all the lines below:
1521
- require: (path15) => {
1523
+ require: (path16) => {
1522
1524
  if (typeof __require !== "undefined") {
1523
- return __require(path15);
1524
- } else if (path15.match(/\.json$/)) {
1525
- return JSON.parse(readFileSync(path15, "utf8"));
1525
+ return __require(path16);
1526
+ } else if (path16.match(/\.json$/)) {
1527
+ return JSON.parse(readFileSync(path16, "utf8"));
1526
1528
  } else {
1527
1529
  throw Error("only .json config files are supported in ESM");
1528
1530
  }
@@ -5433,12 +5435,16 @@ async function getServerStatus(serverName, server, isTrusted, activeSettings) {
5433
5435
  }
5434
5436
  return "disabled" /* DISABLED */;
5435
5437
  }
5438
+ if (!isTrusted) {
5439
+ return "disabled" /* DISABLED */;
5440
+ }
5436
5441
  return testMCPConnection(serverName, server, isTrusted, activeSettings);
5437
5442
  }
5438
5443
  async function listMcpServers(loadedSettingsArg) {
5439
5444
  const loadedSettings = loadedSettingsArg ?? loadSettings();
5440
5445
  const activeSettings = loadedSettings.merged;
5441
- const { mcpServers, blockedServerNames } = await getMcpServersFromConfig(activeSettings);
5446
+ const allSettings = !loadedSettings.isTrusted ? loadedSettings.getMergedSettingsAsIfTrusted() : activeSettings;
5447
+ const { mcpServers, blockedServerNames } = await getMcpServersFromConfig(allSettings);
5442
5448
  const serverNames = Object.keys(mcpServers);
5443
5449
  if (blockedServerNames.length > 0) {
5444
5450
  const message = getAdminBlockedMcpServersMessage(
@@ -5453,6 +5459,13 @@ async function listMcpServers(loadedSettingsArg) {
5453
5459
  }
5454
5460
  return;
5455
5461
  }
5462
+ if (!loadedSettings.isTrusted) {
5463
+ debugLogger.log(
5464
+ import_chalk.default.yellow(
5465
+ "Warning: MCP servers are configured but disabled because this folder is untrusted.\nUser-level servers are also suppressed in untrusted folders to prevent accidental side-effects.\n"
5466
+ )
5467
+ );
5468
+ }
5456
5469
  debugLogger.log("Configured MCP servers:\n");
5457
5470
  for (const serverName of serverNames) {
5458
5471
  const server = mcpServers[serverName];
@@ -6292,27 +6305,27 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
6292
6305
  var __filename = fileURLToPath2(import.meta.url);
6293
6306
  var __dirname2 = dirname3(__filename);
6294
6307
  var EXAMPLES_PATH = join(__dirname2, "examples");
6295
- async function pathExists(path15) {
6308
+ async function pathExists(path16) {
6296
6309
  try {
6297
- await access(path15);
6310
+ await access(path16);
6298
6311
  return true;
6299
6312
  } catch {
6300
6313
  return false;
6301
6314
  }
6302
6315
  }
6303
- async function createDirectory(path15) {
6304
- if (await pathExists(path15)) {
6305
- throw new Error(`Path already exists: ${path15}`);
6316
+ async function createDirectory(path16) {
6317
+ if (await pathExists(path16)) {
6318
+ throw new Error(`Path already exists: ${path16}`);
6306
6319
  }
6307
- await mkdir(path15, { recursive: true });
6320
+ await mkdir(path16, { recursive: true });
6308
6321
  }
6309
- async function copyDirectory(template, path15) {
6310
- await createDirectory(path15);
6322
+ async function copyDirectory(template, path16) {
6323
+ await createDirectory(path16);
6311
6324
  const examplePath = join(EXAMPLES_PATH, template);
6312
6325
  const entries = await readdir(examplePath, { withFileTypes: true });
6313
6326
  for (const entry of entries) {
6314
6327
  const srcPath = join(examplePath, entry.name);
6315
- const destPath = join(path15, entry.name);
6328
+ const destPath = join(path16, entry.name);
6316
6329
  await cp(srcPath, destPath, { recursive: true });
6317
6330
  }
6318
6331
  }
@@ -6587,7 +6600,7 @@ async function handleEnable3(args) {
6587
6600
  const result = enableSkill(settings, name);
6588
6601
  const feedback = renderSkillActionFeedback(
6589
6602
  result,
6590
- (label, path15) => `${import_chalk5.default.bold(label)} (${import_chalk5.default.dim(path15)})`
6603
+ (label, path16) => `${import_chalk5.default.bold(label)} (${import_chalk5.default.dim(path16)})`
6591
6604
  );
6592
6605
  debugLogger.log(feedback);
6593
6606
  }
@@ -6617,7 +6630,7 @@ async function handleDisable3(args) {
6617
6630
  const result = disableSkill(settings, name, scope);
6618
6631
  const feedback = renderSkillActionFeedback(
6619
6632
  result,
6620
- (label, path15) => `${import_chalk6.default.bold(label)} (${import_chalk6.default.dim(path15)})`
6633
+ (label, path16) => `${import_chalk6.default.bold(label)} (${import_chalk6.default.dim(path16)})`
6621
6634
  );
6622
6635
  debugLogger.log(feedback);
6623
6636
  }
@@ -7812,7 +7825,7 @@ async function loadSandboxConfig(settings, argv) {
7812
7825
  }
7813
7826
  const command2 = getSandboxCommand(sandboxValue);
7814
7827
  const packageJson = await getPackageJson(__dirname3);
7815
- const image = process.env["GEMINI_SANDBOX_IMAGE"] ?? "us-docker.pkg.dev/gemini-code-dev/gemini-cli/sandbox:0.42.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.43.0-preview.0" ?? customImage ?? packageJson?.config?.sandboxImageUri;
7816
7829
  const isNative = command2 === "windows-native" || command2 === "sandbox-exec" || command2 === "lxc";
7817
7830
  return command2 && (image || isNative) ? { enabled: true, allowedPaths, networkAccess, command: command2, image } : void 0;
7818
7831
  }
@@ -7980,8 +7993,13 @@ async function parseArguments(settings) {
7980
7993
  const queryArg2 = argv["query"];
7981
7994
  const query = typeof queryArg2 === "string" || Array.isArray(queryArg2) ? queryArg2 : void 0;
7982
7995
  const hasPositionalQuery = Array.isArray(query) ? query.length > 0 : !!query;
7983
- if (argv["resume"] !== void 0 && argv["session-id"] !== void 0) {
7984
- return "Cannot use both --resume (-r) and --session-id together";
7996
+ const sessionFlags = [
7997
+ argv["resume"] !== void 0,
7998
+ argv["session-id"] !== void 0,
7999
+ argv["session-file"] !== void 0
8000
+ ].filter(Boolean).length;
8001
+ if (sessionFlags > 1) {
8002
+ return "The flags --resume, --session-id, and --session-file are mutually exclusive. Please provide only one.";
7985
8003
  }
7986
8004
  if (argv["prompt"] && hasPositionalQuery) {
7987
8005
  return "Cannot use both a positional prompt and the --prompt (-p) flag together";
@@ -8112,6 +8130,10 @@ async function parseArguments(settings) {
8112
8130
  }
8113
8131
  return trimmed;
8114
8132
  }
8133
+ }).option("session-file", {
8134
+ type: "string",
8135
+ nargs: 1,
8136
+ description: "Load a session from a JSON file"
8115
8137
  }).option("session-id", {
8116
8138
  type: "string",
8117
8139
  nargs: 1,
@@ -8596,7 +8618,11 @@ async function loadCliConfig(settings, sessionId, argv, options = {}) {
8596
8618
  shellBackgroundCompletionBehavior: settings.tools?.shell?.backgroundCompletionBehavior,
8597
8619
  shellToolInactivityTimeout: settings.tools?.shell?.inactivityTimeout,
8598
8620
  enableShellOutputEfficiency: settings.tools?.shell?.enableShellOutputEfficiency ?? true,
8599
- skipNextSpeakerCheck: settings.model?.skipNextSpeakerCheck,
8621
+ // In ACP mode, always skip the next-speaker check. This check triggers
8622
+ // recursive continuation turns inside GeminiClient.processTurn() that
8623
+ // conflict with ACP's explicit turn management via session/prompt,
8624
+ // causing infinite agent_thought_chunk loops.
8625
+ skipNextSpeakerCheck: isAcpMode || settings.model?.skipNextSpeakerCheck,
8600
8626
  truncateToolOutputThreshold: settings.tools?.truncateToolOutputThreshold,
8601
8627
  eventEmitter: coreEvents,
8602
8628
  useWriteTodos: argv.useWriteTodos ?? settings.useWriteTodos,
@@ -8755,6 +8781,8 @@ import { createHash as createHash2 } from "node:crypto";
8755
8781
  import v8 from "node:v8";
8756
8782
  import os6 from "node:os";
8757
8783
  import dns from "node:dns";
8784
+ import * as path15 from "node:path";
8785
+ import * as fsPromises from "node:fs/promises";
8758
8786
 
8759
8787
  // packages/cli/src/utils/sandbox.ts
8760
8788
  var import_shell_quote2 = __toESM(require_shell_quote(), 1);
@@ -9215,21 +9243,11 @@ async function start_sandbox(config, nodeArgs = [], cliConfig, cliArgs = []) {
9215
9243
  }
9216
9244
  const imageName = parseImageName(image);
9217
9245
  const isIntegrationTest = process.env["GEMINI_CLI_INTEGRATION_TEST"] === "true";
9218
- let containerName;
9219
- if (isIntegrationTest) {
9220
- containerName = `gemini-cli-integration-test-${randomBytes(4).toString(
9221
- "hex"
9222
- )}`;
9223
- debugLogger.log(`ContainerName: ${containerName}`);
9224
- } else {
9225
- let index = 0;
9226
- const containerNameCheck = (await execAsync(`${command2} ps -a --format "{{.Names}}"`)).stdout.trim();
9227
- while (containerNameCheck.includes(`${imageName}-${index}`)) {
9228
- index++;
9229
- }
9230
- containerName = `${imageName}-${index}`;
9231
- debugLogger.log(`ContainerName (regular): ${containerName}`);
9232
- }
9246
+ const containerNamePrefix = isIntegrationTest ? "gemini-cli-integration-test" : imageName;
9247
+ const containerName = `${containerNamePrefix}-${randomBytes(6).toString(
9248
+ "hex"
9249
+ )}`;
9250
+ debugLogger.log(`ContainerName: ${containerName}`);
9233
9251
  args.push("--name", containerName, "--hostname", containerName);
9234
9252
  if (process.env["GEMINI_CLI_TEST_VAR"]) {
9235
9253
  args.push(
@@ -10215,7 +10233,7 @@ async function runNonInteractive({
10215
10233
  }
10216
10234
  });
10217
10235
  if (process.env["GEMINI_CLI_ACTIVITY_LOG_TARGET"]) {
10218
- const { setupInitialActivityLogger } = await import("./devtoolsService-UADEEKOH.js");
10236
+ const { setupInitialActivityLogger } = await import("./devtoolsService-LV5NJ2BT.js");
10219
10237
  setupInitialActivityLogger(config);
10220
10238
  }
10221
10239
  const { stdout: workingStdout } = createWorkingStdio();
@@ -10670,6 +10688,9 @@ async function runNonInteractive({
10670
10688
  async function runNonInteractive2(params) {
10671
10689
  const useAgentSession = params.config.getAgentSessionNoninteractiveEnabled();
10672
10690
  if (useAgentSession) {
10691
+ debugLogger.debug(
10692
+ "[ADK] Running non-interactive mode with ADK agent session"
10693
+ );
10673
10694
  return runNonInteractive(params);
10674
10695
  }
10675
10696
  const { config, settings, input, prompt_id, resumedSessionData } = params;
@@ -10683,7 +10704,7 @@ async function runNonInteractive2(params) {
10683
10704
  }
10684
10705
  });
10685
10706
  if (process.env["GEMINI_CLI_ACTIVITY_LOG_TARGET"]) {
10686
- const { setupInitialActivityLogger } = await import("./devtoolsService-UADEEKOH.js");
10707
+ const { setupInitialActivityLogger } = await import("./devtoolsService-LV5NJ2BT.js");
10687
10708
  setupInitialActivityLogger(config);
10688
10709
  }
10689
10710
  const { stdout: workingStdout } = createWorkingStdio();
@@ -10917,6 +10938,20 @@ async function runNonInteractive2(params) {
10917
10938
  durationMs
10918
10939
  )
10919
10940
  });
10941
+ } else if (config.getOutputFormat() === "json" /* JSON */) {
10942
+ const formatter = new JsonFormatter();
10943
+ const stats = uiTelemetryService.getMetrics();
10944
+ textOutput.write(
10945
+ formatter.format(
10946
+ config.getSessionId(),
10947
+ responseText,
10948
+ stats,
10949
+ void 0,
10950
+ [...warnings, stopMessage]
10951
+ )
10952
+ );
10953
+ } else {
10954
+ textOutput.ensureTrailingNewline();
10920
10955
  }
10921
10956
  return;
10922
10957
  } else if (event.type === "agent_execution_blocked" /* AgentExecutionBlocked */) {
@@ -14179,12 +14214,6 @@ ${event.value.description}`;
14179
14214
  const invocation = tool.build(args);
14180
14215
  const displayTitle = typeof invocation.getDisplayTitle === "function" ? invocation.getDisplayTitle() : invocation.getDescription();
14181
14216
  const explanation = typeof invocation.getExplanation === "function" ? invocation.getExplanation() : "";
14182
- if (explanation) {
14183
- await this.sendUpdate({
14184
- sessionUpdate: "agent_thought_chunk",
14185
- content: { type: "text", text: explanation }
14186
- });
14187
- }
14188
14217
  const confirmationDetails = await invocation.shouldConfirmExecute(abortSignal);
14189
14218
  if (confirmationDetails) {
14190
14219
  const content2 = [];
@@ -14199,6 +14228,12 @@ ${event.value.description}`;
14199
14228
  }
14200
14229
  });
14201
14230
  }
14231
+ if (content2.length === 0 && explanation) {
14232
+ content2.push({
14233
+ type: "content",
14234
+ content: { type: "text", text: explanation }
14235
+ });
14236
+ }
14202
14237
  const params = {
14203
14238
  sessionId: this.id,
14204
14239
  options: toPermissionOptions(
@@ -14247,6 +14282,12 @@ ${event.value.description}`;
14247
14282
  }
14248
14283
  } else {
14249
14284
  const content2 = [];
14285
+ if (explanation) {
14286
+ content2.push({
14287
+ type: "content",
14288
+ content: { type: "text", text: explanation }
14289
+ });
14290
+ }
14250
14291
  await this.sendUpdate({
14251
14292
  sessionUpdate: "tool_call",
14252
14293
  toolCallId: callId,
@@ -15706,13 +15747,69 @@ ${reason.stack}` : ""}`;
15706
15747
  }
15707
15748
  });
15708
15749
  }
15709
- async function resolveSessionId(resumeArg, sessionIdArg) {
15710
- if (!resumeArg && !sessionIdArg) {
15750
+ async function resolveSessionId(resumeArg, sessionIdArg, sessionFileArg) {
15751
+ if (!resumeArg && !sessionIdArg && !sessionFileArg) {
15711
15752
  return { sessionId: createSessionId() };
15712
15753
  }
15713
15754
  const storage = new Storage(process.cwd());
15714
15755
  await storage.initialize();
15715
15756
  const sessionSelector = new SessionSelector(storage);
15757
+ if (sessionFileArg) {
15758
+ try {
15759
+ const sessionData = await loadConversationRecord(sessionFileArg);
15760
+ if (!sessionData) {
15761
+ throw new Error(`File not found or invalid format: ${sessionFileArg}`);
15762
+ }
15763
+ const now = Date.now();
15764
+ const isoNow = new Date(now).toISOString();
15765
+ sessionData.messages = (sessionData.messages || []).filter(
15766
+ (m) => typeof m === "object" && m !== null && (m.type === "user" || m.type === "gemini") && m.content !== void 0
15767
+ );
15768
+ sessionData.messages.unshift({
15769
+ id: `import-${now}`,
15770
+ type: "info",
15771
+ content: `Imported session from ${sessionFileArg}`,
15772
+ timestamp: isoNow
15773
+ });
15774
+ const newSessionId = createSessionId();
15775
+ sessionData.sessionId = newSessionId;
15776
+ sessionData.projectHash = getProjectHash(storage.getProjectRoot());
15777
+ sessionData.startTime = isoNow;
15778
+ sessionData.lastUpdated = isoNow;
15779
+ const chatsDir = path15.join(storage.getProjectTempDir(), "chats");
15780
+ const newSessionPath = path15.join(
15781
+ chatsDir,
15782
+ `session-${now}-${newSessionId.slice(0, 8)}.jsonl`
15783
+ );
15784
+ const { messages: _messages, ...initialMetadata } = sessionData;
15785
+ const lines = [JSON.stringify(initialMetadata)];
15786
+ if (sessionData.messages) {
15787
+ for (const msg of sessionData.messages) {
15788
+ lines.push(JSON.stringify(msg));
15789
+ }
15790
+ }
15791
+ await fsPromises.mkdir(chatsDir, { recursive: true });
15792
+ await fsPromises.writeFile(
15793
+ newSessionPath,
15794
+ lines.join("\n") + "\n",
15795
+ "utf-8"
15796
+ );
15797
+ return {
15798
+ sessionId: newSessionId,
15799
+ resumedSessionData: {
15800
+ conversation: sessionData,
15801
+ filePath: newSessionPath
15802
+ }
15803
+ };
15804
+ } catch (error) {
15805
+ coreEvents.emitFeedback(
15806
+ "error",
15807
+ `Error importing session from file: ${error instanceof Error ? error.message : "Unknown error"}`
15808
+ );
15809
+ await runExitCleanup();
15810
+ process.exit(ExitCodes.FATAL_INPUT_ERROR);
15811
+ }
15812
+ }
15716
15813
  if (sessionIdArg) {
15717
15814
  if (await sessionSelector.sessionExists(sessionIdArg)) {
15718
15815
  coreEvents.emitFeedback(
@@ -15734,8 +15831,10 @@ async function resolveSessionId(resumeArg, sessionIdArg) {
15734
15831
  };
15735
15832
  } catch (error) {
15736
15833
  if (error instanceof SessionError && error.code === "NO_SESSIONS_FOUND") {
15737
- coreEvents.emitFeedback("warning", error.message);
15738
- return { sessionId: createSessionId() };
15834
+ if (resumeArg === RESUME_LATEST) {
15835
+ coreEvents.emitFeedback("warning", error.message);
15836
+ return { sessionId: createSessionId() };
15837
+ }
15739
15838
  }
15740
15839
  coreEvents.emitFeedback(
15741
15840
  "error",
@@ -15746,7 +15845,7 @@ async function resolveSessionId(resumeArg, sessionIdArg) {
15746
15845
  }
15747
15846
  }
15748
15847
  async function startInteractiveUI(config, settings, startupWarnings, workspaceRoot = process.cwd(), resumedSessionData, initializationResult) {
15749
- const { startInteractiveUI: doStartUI } = await import("./interactiveCli-752P4PTI.js");
15848
+ const { startInteractiveUI: doStartUI } = await import("./interactiveCli-BQ36B66Z.js");
15750
15849
  await doStartUI(
15751
15850
  config,
15752
15851
  settings,
@@ -15809,7 +15908,8 @@ async function main() {
15809
15908
  const argv = await argvPromise;
15810
15909
  const { sessionId, resumedSessionData } = await resolveSessionId(
15811
15910
  argv.resume,
15812
- argv.sessionId
15911
+ argv.sessionId,
15912
+ argv.sessionFile
15813
15913
  );
15814
15914
  if (argv.allowedTools && argv.allowedTools.length > 0 || settings.merged.tools?.allowed && settings.merged.tools.allowed.length > 0) {
15815
15915
  coreEvents.emitFeedback(
@@ -15953,7 +16053,7 @@ ${finalArgs[promptIndex + 1]}`;
15953
16053
  await config.storage.initialize();
15954
16054
  adminControlsListner.setConfig(config);
15955
16055
  if (config.isInteractive() && settings.merged.general.devtools) {
15956
- const { setupInitialActivityLogger } = await import("./devtoolsService-UADEEKOH.js");
16056
+ const { setupInitialActivityLogger } = await import("./devtoolsService-LV5NJ2BT.js");
15957
16057
  setupInitialActivityLogger(config);
15958
16058
  }
15959
16059
  registerTelemetryConfig(config);
@@ -16012,7 +16112,7 @@ ${finalArgs[promptIndex + 1]}`;
16012
16112
  const initAppHandle = startupProfiler.start("initialize_app");
16013
16113
  const initializationResult = await initializeApp(config, settings);
16014
16114
  initAppHandle?.end();
16015
- import("./liteRtServerManager-FPYU5KEK.js").then(({ LiteRtServerManager }) => {
16115
+ import("./liteRtServerManager-ISYDOBNC.js").then(({ LiteRtServerManager }) => {
16016
16116
  const mergedGemma = settings.merged.experimental?.gemmaModelRouter;
16017
16117
  if (!mergedGemma) return;
16018
16118
  const userGemma = settings.forScope("User" /* User */).settings.experimental?.gemmaModelRouter;