Skip to content

Commit 5c1011e

Browse files
committed
Merge remote-tracking branch 'origin/main' into agent-session-agent-only
2 parents 476e011 + 838f6f8 commit 5c1011e

53 files changed

Lines changed: 2204 additions & 790 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/gemini-scheduled-issue-triage.yml

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -233,17 +233,38 @@ jobs:
233233
core.info(`Raw labels JSON: ${rawLabels}`);
234234
let parsedLabels;
235235
try {
236+
// First, try to parse the raw output as JSON.
237+
parsedLabels = JSON.parse(rawLabels);
238+
} catch (jsonError) {
239+
// If that fails, check for a markdown code block.
240+
core.warning(`Direct JSON parsing failed: ${jsonError.message}. Trying to extract from a markdown block.`);
236241
const jsonMatch = rawLabels.match(/```json\s*([\s\S]*?)\s*```/);
237-
if (!jsonMatch || !jsonMatch[1]) {
238-
throw new Error("Could not find a ```json ... ``` block in the output.");
242+
if (jsonMatch && jsonMatch[1]) {
243+
try {
244+
parsedLabels = JSON.parse(jsonMatch[1].trim());
245+
} catch (markdownError) {
246+
core.setFailed(`Failed to parse JSON even after extracting from markdown block: ${markdownError.message}\nRaw output: ${rawLabels}`);
247+
return;
248+
}
249+
} else {
250+
// If no markdown block, try to find a raw JSON array in the output.
251+
// The CLI may include debug/log lines (e.g. telemetry init, YOLO mode)
252+
// before the actual JSON response.
253+
const jsonArrayMatch = rawLabels.match(/(\[[\s\S]*\])/);
254+
if (jsonArrayMatch) {
255+
try {
256+
parsedLabels = JSON.parse(jsonArrayMatch[0]);
257+
} catch (extractError) {
258+
core.setFailed(`Found JSON-like content but failed to parse: ${extractError.message}\nRaw output: ${rawLabels}`);
259+
return;
260+
}
261+
} else {
262+
core.setFailed(`Output is not valid JSON and does not contain extractable JSON.\nRaw output: ${rawLabels}`);
263+
return;
264+
}
239265
}
240-
const jsonString = jsonMatch[1].trim();
241-
parsedLabels = JSON.parse(jsonString);
242-
core.info(`Parsed labels JSON: ${JSON.stringify(parsedLabels)}`);
243-
} catch (err) {
244-
core.setFailed(`Failed to parse labels JSON from Gemini output: ${err.message}\nRaw output: ${rawLabels}`);
245-
return;
246266
}
267+
core.info(`Parsed labels JSON: ${JSON.stringify(parsedLabels)}`);
247268
248269
for (const entry of parsedLabels) {
249270
const issueNumber = entry.issue_number;

docs/changelogs/preview.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Preview release: v0.42.0-preview.0
1+
# Preview release: v0.42.0-preview.2
22

3-
Released: May 05, 2026
3+
Released: May 06, 2026
44

55
Our preview release includes the latest, new, and experimental features. This
66
release may not be as stable as our [latest weekly release](latest.md).
@@ -242,4 +242,4 @@ npm install -g @google/gemini-cli@preview
242242
[#26357](https://github.com/google-gemini/gemini-cli/pull/26357)
243243

244244
**Full Changelog**:
245-
https://github.com/google-gemini/gemini-cli/compare/v0.41.0-preview.3...v0.42.0-preview.0
245+
https://github.com/google-gemini/gemini-cli/compare/v0.41.0-preview.3...v0.42.0-preview.2

docs/cli/settings.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ they appear in the UI.
169169
| Voice Activation Mode | `experimental.voice.activationMode` | How to trigger voice recording with the Space key. | `"push-to-talk"` |
170170
| Voice Transcription Backend | `experimental.voice.backend` | The backend to use for voice transcription. Note: When using the Gemini Live backend, voice recordings are sent to Google Cloud for transcription. | `"gemini-live"` |
171171
| Whisper Model | `experimental.voice.whisperModel` | The Whisper model to use for local transcription. | `"ggml-base.en.bin"` |
172-
| Voice Stop Grace Period (ms) | `experimental.voice.stopGracePeriodMs` | How long to wait for final transcription after stopping recording. | `1000` |
172+
| Voice Stop Grace Period (ms) | `experimental.voice.stopGracePeriodMs` | How long to wait for final transcription after stopping recording. | `4000` |
173173
| Enable Git Worktrees | `experimental.worktrees` | Enable automated Git worktree management for parallel work. | `false` |
174174
| Use OSC 52 Paste | `experimental.useOSC52Paste` | Use OSC 52 for pasting. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |
175175
| Use OSC 52 Copy | `experimental.useOSC52Copy` | Use OSC 52 for copying. This may be more robust than the default system when using remote terminal sessions (if your terminal is configured to allow it). | `false` |

docs/extensions/releasing.md

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Release extensions
22

33
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.
56

67
Git repository releases are the simplest approach and offer the most flexibility
78
for managing development branches. GitHub Releases are more efficient for
@@ -153,29 +154,62 @@ jobs:
153154
release/win32.arm64.my-tool.zip
154155
```
155156
156-
## Migrating an Extension Repository
157+
## Migrate an extension repository
157158
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
161161
users.
162162

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.

docs/reference/configuration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1795,7 +1795,7 @@ their corresponding top-level category object in your `settings.json` file.
17951795
- **`experimental.voice.stopGracePeriodMs`** (number):
17961796
- **Description:** How long to wait for final transcription after stopping
17971797
recording.
1798-
- **Default:** `1000`
1798+
- **Default:** `4000`
17991799

18001800
- **`experimental.adk.agentSessionNoninteractiveEnabled`** (boolean):
18011801
- **Description:** Enable non-interactive agent sessions.

docs/reference/keyboard-shortcuts.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,29 @@ lines and `3w` moves forward three words.
326326
Counts are also supported for editing commands. For example, `3dd` deletes three
327327
lines and `2cw` changes two words.
328328

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+
329352
## Limitations
330353

331354
- On [Windows Terminal](https://en.wikipedia.org/wiki/Windows_Terminal):

integration-tests/plan-mode.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,8 @@ describe('Plan Mode', () => {
231231
`Expected write_file to succeed, but it failed with error: ${'error' in (planWrite?.toolRequest || {}) ? (planWrite?.toolRequest as unknown as Record<string, string>)['error'] : 'unknown'}`,
232232
).toBe(true);
233233
});
234-
it('should switch from a pro model to a flash model after exiting plan mode', async () => {
234+
235+
it.skip('should switch from a pro model to a flash model after exiting plan mode', async () => {
235236
const plansDir = 'plans-folder';
236237
const planFilename = 'my-plan.md';
237238

packages/cli/src/config/config.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ describe('parseArguments', () => {
234234
afterEach(() => {
235235
vi.restoreAllMocks();
236236
});
237-
it('should fail if both --resume and --session-id are provided', async () => {
237+
it('should fail if multiple session flags are provided', async () => {
238238
process.argv = [
239239
'node',
240240
'script.js',
@@ -255,7 +255,7 @@ describe('parseArguments', () => {
255255

256256
expect(mockConsoleError).toHaveBeenCalledWith(
257257
expect.stringContaining(
258-
'Cannot use both --resume (-r) and --session-id together',
258+
'The flags --resume, --session-id, and --session-file are mutually exclusive. Please provide only one.',
259259
),
260260
);
261261
});

packages/cli/src/config/config.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export interface CliArgs {
9797
extensions: string[] | undefined;
9898
listExtensions: boolean | undefined;
9999
resume: string | typeof RESUME_LATEST | undefined;
100+
sessionFile?: string | undefined;
100101
sessionId: string | undefined;
101102
listSessions: boolean | undefined;
102103
deleteSession: string | undefined;
@@ -239,8 +240,14 @@ export async function parseArguments(
239240
? query.length > 0
240241
: !!query;
241242

242-
if (argv['resume'] !== undefined && argv['session-id'] !== undefined) {
243-
return 'Cannot use both --resume (-r) and --session-id together';
243+
const sessionFlags = [
244+
argv['resume'] !== undefined,
245+
argv['session-id'] !== undefined,
246+
argv['session-file'] !== undefined,
247+
].filter(Boolean).length;
248+
249+
if (sessionFlags > 1) {
250+
return 'The flags --resume, --session-id, and --session-file are mutually exclusive. Please provide only one.';
244251
}
245252

246253
if (argv['prompt'] && hasPositionalQuery) {
@@ -412,6 +419,11 @@ export async function parseArguments(
412419
return trimmed;
413420
},
414421
})
422+
.option('session-file', {
423+
type: 'string',
424+
nargs: 1,
425+
description: 'Load a session from a JSON file',
426+
})
415427
.option('session-id', {
416428
type: 'string',
417429
nargs: 1,

packages/cli/src/config/footerItems.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ describe('footerItems', () => {
120120
'quota',
121121
'memory-usage',
122122
'session-id',
123+
'hostname',
123124
'code-changes',
124125
'token-count',
125126
]);

0 commit comments

Comments
 (0)