Skip to content

Commit f4db1a8

Browse files
Merge branch 'main' into feat/browser-agent-progress-emission
2 parents f1df13a + ca7ac00 commit f4db1a8

Some content is hidden

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

51 files changed

+1959
-574
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ jobs:
169169
npm run test:ci --workspace @google/gemini-cli
170170
else
171171
# Explicitly list non-cli packages to ensure they are sharded correctly
172-
npm run test:ci --workspace @google/gemini-cli-core --workspace @google/gemini-cli-a2a-server --workspace gemini-cli-vscode-ide-companion --workspace @google/gemini-cli-test-utils --if-present
172+
npm run test:ci --workspace @google/gemini-cli-core --workspace @google/gemini-cli-a2a-server --workspace gemini-cli-vscode-ide-companion --workspace @google/gemini-cli-test-utils --if-present -- --coverage.enabled=false
173173
npm run test:scripts
174174
fi
175175

docs/cli/notifications.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Notifications (experimental)
2+
3+
Gemini CLI can send system notifications to alert you when a session completes
4+
or when it needs your attention, such as when it's waiting for you to approve a
5+
tool call.
6+
7+
> **Note:** This is a preview feature currently under active development.
8+
> Preview features may be available on the **Preview** channel or may need to be
9+
> enabled under `/settings`.
10+
11+
Notifications are particularly useful when running long-running tasks or using
12+
[Plan Mode](./plan-mode.md), letting you switch to other windows while Gemini
13+
CLI works in the background.
14+
15+
## Requirements
16+
17+
Currently, system notifications are only supported on macOS.
18+
19+
### Terminal support
20+
21+
The CLI uses the OSC 9 terminal escape sequence to trigger system notifications.
22+
This is supported by several modern terminal emulators. If your terminal does
23+
not support OSC 9 notifications, Gemini CLI falls back to a system alert sound
24+
to get your attention.
25+
26+
## Enable notifications
27+
28+
Notifications are disabled by default. You can enable them using the `/settings`
29+
command or by updating your `settings.json` file.
30+
31+
1. Open the settings dialog by typing `/settings` in an interactive session.
32+
2. Navigate to the **General** category.
33+
3. Toggle the **Enable Notifications** setting to **On**.
34+
35+
Alternatively, add the following to your `settings.json`:
36+
37+
```json
38+
{
39+
"general": {
40+
"enableNotifications": true
41+
}
42+
}
43+
```
44+
45+
## Types of notifications
46+
47+
Gemini CLI sends notifications for the following events:
48+
49+
- **Action required:** Triggered when the model is waiting for user input or
50+
tool approval. This helps you know when the CLI has paused and needs you to
51+
intervene.
52+
- **Session complete:** Triggered when a session finishes successfully. This is
53+
useful for tracking the completion of automated tasks.
54+
55+
## Next steps
56+
57+
- Start planning with [Plan Mode](./plan-mode.md).
58+
- Configure your experience with other [settings](./settings.md).

docs/cli/session-management.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,15 @@ Browser**:
6161
/resume
6262
```
6363

64+
When typing `/resume` (or `/chat`) in slash completion, commands are grouped
65+
under titled separators:
66+
67+
- `-- auto --` (session browser)
68+
- `list` is selectable and opens the session browser
69+
- `-- checkpoints --` (manual tagged checkpoint commands)
70+
71+
Unique prefixes such as `/resum` and `/cha` resolve to the same grouped menu.
72+
6473
The Session Browser provides an interactive interface where you can perform the
6574
following actions:
6675

@@ -72,6 +81,21 @@ following actions:
7281
- **Select:** Press **Enter** to resume the selected session.
7382
- **Esc:** Press **Esc** to exit the Session Browser.
7483

84+
### Manual chat checkpoints
85+
86+
For named branch points inside a session, use chat checkpoints:
87+
88+
```text
89+
/resume save decision-point
90+
/resume list
91+
/resume resume decision-point
92+
```
93+
94+
Compatibility aliases:
95+
96+
- `/chat ...` works for the same commands.
97+
- `/resume checkpoints ...` also remains supported during migration.
98+
7599
## Managing sessions
76100

77101
You can list and delete sessions to keep your history organized and manage disk

docs/cli/tutorials/session-management.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ Gemini gives you granular control over the undo process. You can choose to:
8989
Sometimes you want to try two different approaches to the same problem.
9090

9191
1. Start a session and get to a decision point.
92-
2. Save the current state with `/chat save decision-point`.
92+
2. Save the current state with `/resume save decision-point`.
9393
3. Try your first approach.
94-
4. Later, use `/chat resume decision-point` to fork the conversation back to
94+
4. Later, use `/resume resume decision-point` to fork the conversation back to
9595
that moment and try a different approach.
9696

9797
This creates a new branch of history without losing your original work.
@@ -101,5 +101,5 @@ This creates a new branch of history without losing your original work.
101101
- Learn about [Checkpointing](../../cli/checkpointing.md) to understand the
102102
underlying safety mechanism.
103103
- Explore [Task planning](task-planning.md) to keep complex sessions organized.
104-
- See the [Command reference](../../reference/commands.md) for all `/chat` and
105-
`/resume` options.
104+
- See the [Command reference](../../reference/commands.md) for `/resume`
105+
options, grouped checkpoint menus, and `/chat` compatibility aliases.

docs/reference/commands.md

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,33 @@ Slash commands provide meta-level control over the CLI itself.
2828

2929
### `/chat`
3030

31-
- **Description:** Save and resume conversation history for branching
32-
conversation state interactively, or resuming a previous state from a later
33-
session.
31+
- **Description:** Alias for `/resume`. Both commands now expose the same
32+
session browser action and checkpoint subcommands.
33+
- **Menu layout when typing `/chat` (or `/resume`)**:
34+
- `-- auto --`
35+
- `list` (selecting this opens the auto-saved session browser)
36+
- `-- checkpoints --`
37+
- `list`, `save`, `resume`, `delete`, `share` (manual tagged checkpoints)
38+
- **Note:** Unique prefixes (for example `/cha` or `/resum`) resolve to the
39+
same grouped menu.
3440
- **Sub-commands:**
3541
- **`debug`**
3642
- **Description:** Export the most recent API request as a JSON payload.
3743
- **`delete <tag>`**
3844
- **Description:** Deletes a saved conversation checkpoint.
45+
- **Equivalent:** `/resume delete <tag>`
3946
- **`list`**
40-
- **Description:** Lists available tags for chat state resumption.
47+
- **Description:** Lists available tags for manually saved checkpoints.
4148
- **Note:** This command only lists chats saved within the current project.
4249
Because chat history is project-scoped, chats saved in other project
4350
directories will not be displayed.
51+
- **Equivalent:** `/resume list`
4452
- **`resume <tag>`**
4553
- **Description:** Resumes a conversation from a previous save.
4654
- **Note:** You can only resume chats that were saved within the current
4755
project. To resume a chat from a different project, you must run the
4856
Gemini CLI from that project's directory.
57+
- **Equivalent:** `/resume resume <tag>`
4958
- **`save <tag>`**
5059
- **Description:** Saves the current conversation history. You must add a
5160
`<tag>` for identifying the conversation state.
@@ -60,10 +69,12 @@ Slash commands provide meta-level control over the CLI itself.
6069
conversation states. For automatic checkpoints created before file
6170
modifications, see the
6271
[Checkpointing documentation](../cli/checkpointing.md).
72+
- **Equivalent:** `/resume save <tag>`
6373
- **`share [filename]`**
6474
- **Description** Writes the current conversation to a provided Markdown or
6575
JSON file. If no filename is provided, then the CLI will generate one.
6676
- **Usage** `/chat share file.md` or `/chat share file.json`.
77+
- **Equivalent:** `/resume share [filename]`
6778

6879
### `/clear`
6980

@@ -314,10 +325,13 @@ Slash commands provide meta-level control over the CLI itself.
314325

315326
### `/resume`
316327

317-
- **Description:** Browse and resume previous conversation sessions. Opens an
318-
interactive session browser where you can search, filter, and select from
319-
automatically saved conversations.
328+
- **Description:** Browse and resume previous conversation sessions, and manage
329+
manual chat checkpoints.
320330
- **Features:**
331+
- **Auto sessions:** Run `/resume` to open the interactive session browser for
332+
automatically saved conversations.
333+
- **Chat checkpoints:** Use checkpoint subcommands directly (`/resume save`,
334+
`/resume resume`, etc.).
321335
- **Management:** Delete unwanted sessions directly from the browser
322336
- **Resume:** Select any session to resume and continue the conversation
323337
- **Search:** Use `/` to search through conversation content across all
@@ -328,6 +342,23 @@ Slash commands provide meta-level control over the CLI itself.
328342
- **Note:** All conversations are automatically saved as you chat - no manual
329343
saving required. See [Session Management](../cli/session-management.md) for
330344
complete details.
345+
- **Alias:** `/chat` provides the same behavior and subcommands.
346+
- **Sub-commands:**
347+
- **`list`**
348+
- **Description:** Lists available tags for manual chat checkpoints.
349+
- **`save <tag>`**
350+
- **Description:** Saves the current conversation as a tagged checkpoint.
351+
- **`resume <tag>`** (alias: `load`)
352+
- **Description:** Loads a previously saved tagged checkpoint.
353+
- **`delete <tag>`**
354+
- **Description:** Deletes a tagged checkpoint.
355+
- **`share [filename]`**
356+
- **Description:** Exports the current conversation to Markdown or JSON.
357+
- **`debug`**
358+
- **Description:** Export the most recent API request as JSON payload
359+
(nightly builds).
360+
- **Compatibility alias:** `/resume checkpoints ...` is still accepted for the
361+
same checkpoint commands.
331362

332363
### `/settings`
333364

docs/sidebar.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@
106106
{ "label": "MCP servers", "slug": "docs/tools/mcp-server" },
107107
{ "label": "Model routing", "slug": "docs/cli/model-routing" },
108108
{ "label": "Model selection", "slug": "docs/cli/model" },
109+
{
110+
"label": "Notifications",
111+
"badge": "🔬",
112+
"slug": "docs/cli/notifications"
113+
},
109114
{ "label": "Plan mode", "badge": "🔬", "slug": "docs/cli/plan-mode" },
110115
{
111116
"label": "Subagents",

docs/tools/mcp-server.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ To authenticate with a server using Service Account Impersonation, you must set
372372
the `authProviderType` to `service_account_impersonation` and provide the
373373
following properties:
374374

375-
- **`targetAudience`** (string): The OAuth Client ID allowslisted on the
375+
- **`targetAudience`** (string): The OAuth Client ID allowlisted on the
376376
IAP-protected application you are trying to access.
377377
- **`targetServiceAccount`** (string): The email address of the Google Cloud
378378
Service Account to impersonate.

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,6 @@ describe('resolveWorkspacePolicyState', () => {
183183
setAutoAcceptWorkspacePolicies(originalValue);
184184
}
185185
});
186-
187186
it('should not return workspace policies if cwd is the home directory', async () => {
188187
const policiesDir = path.join(tempDir, '.gemini', 'policies');
189188
fs.mkdirSync(policiesDir, { recursive: true });

packages/cli/src/services/BuiltinCommandLoader.test.ts

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,17 @@ vi.mock('../ui/commands/agentsCommand.js', () => ({
7373
}));
7474
vi.mock('../ui/commands/bugCommand.js', () => ({ bugCommand: {} }));
7575
vi.mock('../ui/commands/chatCommand.js', () => ({
76-
chatCommand: { name: 'chat', subCommands: [] },
76+
chatCommand: {
77+
name: 'chat',
78+
subCommands: [
79+
{ name: 'list' },
80+
{ name: 'save' },
81+
{ name: 'resume' },
82+
{ name: 'delete' },
83+
{ name: 'share' },
84+
{ name: 'checkpoints', hidden: true, subCommands: [{ name: 'list' }] },
85+
],
86+
},
7787
debugCommand: { name: 'debug' },
7888
}));
7989
vi.mock('../ui/commands/clearCommand.js', () => ({ clearCommand: {} }));
@@ -94,7 +104,19 @@ vi.mock('../ui/commands/modelCommand.js', () => ({
94104
}));
95105
vi.mock('../ui/commands/privacyCommand.js', () => ({ privacyCommand: {} }));
96106
vi.mock('../ui/commands/quitCommand.js', () => ({ quitCommand: {} }));
97-
vi.mock('../ui/commands/resumeCommand.js', () => ({ resumeCommand: {} }));
107+
vi.mock('../ui/commands/resumeCommand.js', () => ({
108+
resumeCommand: {
109+
name: 'resume',
110+
subCommands: [
111+
{ name: 'list' },
112+
{ name: 'save' },
113+
{ name: 'resume' },
114+
{ name: 'delete' },
115+
{ name: 'share' },
116+
{ name: 'checkpoints', hidden: true, subCommands: [{ name: 'list' }] },
117+
],
118+
},
119+
}));
98120
vi.mock('../ui/commands/statsCommand.js', () => ({ statsCommand: {} }));
99121
vi.mock('../ui/commands/themeCommand.js', () => ({ themeCommand: {} }));
100122
vi.mock('../ui/commands/toolsCommand.js', () => ({ toolsCommand: {} }));
@@ -256,7 +278,7 @@ describe('BuiltinCommandLoader', () => {
256278
});
257279

258280
describe('chat debug command', () => {
259-
it('should NOT add debug subcommand to chatCommand if not a nightly build', async () => {
281+
it('should NOT add debug subcommand to chat/resume commands if not a nightly build', async () => {
260282
vi.mocked(isNightly).mockResolvedValue(false);
261283
const loader = new BuiltinCommandLoader(mockConfig);
262284
const commands = await loader.loadCommands(new AbortController().signal);
@@ -265,9 +287,30 @@ describe('BuiltinCommandLoader', () => {
265287
expect(chatCmd?.subCommands).toBeDefined();
266288
const hasDebug = chatCmd!.subCommands!.some((c) => c.name === 'debug');
267289
expect(hasDebug).toBe(false);
290+
291+
const resumeCmd = commands.find((c) => c.name === 'resume');
292+
const resumeHasDebug =
293+
resumeCmd?.subCommands?.some((c) => c.name === 'debug') ?? false;
294+
expect(resumeHasDebug).toBe(false);
295+
296+
const chatCheckpointsCmd = chatCmd?.subCommands?.find(
297+
(c) => c.name === 'checkpoints',
298+
);
299+
const chatCheckpointHasDebug =
300+
chatCheckpointsCmd?.subCommands?.some((c) => c.name === 'debug') ??
301+
false;
302+
expect(chatCheckpointHasDebug).toBe(false);
303+
304+
const resumeCheckpointsCmd = resumeCmd?.subCommands?.find(
305+
(c) => c.name === 'checkpoints',
306+
);
307+
const resumeCheckpointHasDebug =
308+
resumeCheckpointsCmd?.subCommands?.some((c) => c.name === 'debug') ??
309+
false;
310+
expect(resumeCheckpointHasDebug).toBe(false);
268311
});
269312

270-
it('should add debug subcommand to chatCommand if it is a nightly build', async () => {
313+
it('should add debug subcommand to chat/resume commands if it is a nightly build', async () => {
271314
vi.mocked(isNightly).mockResolvedValue(true);
272315
const loader = new BuiltinCommandLoader(mockConfig);
273316
const commands = await loader.loadCommands(new AbortController().signal);
@@ -276,6 +319,27 @@ describe('BuiltinCommandLoader', () => {
276319
expect(chatCmd?.subCommands).toBeDefined();
277320
const hasDebug = chatCmd!.subCommands!.some((c) => c.name === 'debug');
278321
expect(hasDebug).toBe(true);
322+
323+
const resumeCmd = commands.find((c) => c.name === 'resume');
324+
const resumeHasDebug =
325+
resumeCmd?.subCommands?.some((c) => c.name === 'debug') ?? false;
326+
expect(resumeHasDebug).toBe(true);
327+
328+
const chatCheckpointsCmd = chatCmd?.subCommands?.find(
329+
(c) => c.name === 'checkpoints',
330+
);
331+
const chatCheckpointHasDebug =
332+
chatCheckpointsCmd?.subCommands?.some((c) => c.name === 'debug') ??
333+
false;
334+
expect(chatCheckpointHasDebug).toBe(true);
335+
336+
const resumeCheckpointsCmd = resumeCmd?.subCommands?.find(
337+
(c) => c.name === 'checkpoints',
338+
);
339+
const resumeCheckpointHasDebug =
340+
resumeCheckpointsCmd?.subCommands?.some((c) => c.name === 'debug') ??
341+
false;
342+
expect(resumeCheckpointHasDebug).toBe(true);
279343
});
280344
});
281345
});

0 commit comments

Comments
 (0)