From 84f1c19265db4ac221778805f72fd7c47c6642e5 Mon Sep 17 00:00:00 2001 From: Gen Zhang Date: Thu, 26 Mar 2026 20:10:49 +0000 Subject: [PATCH] feat(cli): enable notifications cross-platform via terminal bell fallback (#21618) Co-authored-by: Sandy Tao --- docs/cli/notifications.md | 10 +++++----- docs/cli/settings.md | 2 +- docs/reference/configuration.md | 2 +- packages/cli/src/config/settingsSchema.ts | 2 +- ...ttings-list-with-visual-indicators.snap.svg | 2 +- ...ibility-settings-enabled-correctly.snap.svg | 2 +- ...oolean-settings-disabled-correctly.snap.svg | 2 +- ...uld-render-default-state-correctly.snap.svg | 2 +- ...ring-settings-configured-correctly.snap.svg | 2 +- ...ocused-on-scope-selector-correctly.snap.svg | 2 +- ...lean-and-number-settings-correctly.snap.svg | 2 +- ...ls-and-security-settings-correctly.snap.svg | 2 +- ...boolean-settings-enabled-correctly.snap.svg | 2 +- .../__snapshots__/SettingsDialog.test.tsx.snap | 18 +++++++++--------- .../src/utils/terminalNotifications.test.ts | 8 +++++--- .../cli/src/utils/terminalNotifications.ts | 13 +++---------- schemas/settings.schema.json | 4 ++-- 17 files changed, 36 insertions(+), 41 deletions(-) diff --git a/docs/cli/notifications.md b/docs/cli/notifications.md index 8cff6c54f3..abe6743c56 100644 --- a/docs/cli/notifications.md +++ b/docs/cli/notifications.md @@ -15,14 +15,14 @@ CLI works in the background. ## Requirements -Currently, system notifications are only supported on macOS. - ### Terminal support The CLI uses the OSC 9 terminal escape sequence to trigger system notifications. -This is supported by several modern terminal emulators. If your terminal does -not support OSC 9 notifications, Gemini CLI falls back to a system alert sound -to get your attention. +This is supported by several modern terminal emulators including iTerm2, +WezTerm, Ghostty, and Kitty. If your terminal does not support OSC 9 +notifications, Gemini CLI falls back to a terminal bell (BEL) to get your +attention. Most terminals respond to BEL with a taskbar flash or system alert +sound. ## Enable notifications diff --git a/docs/cli/settings.md b/docs/cli/settings.md index 2792606959..5f432b8c8d 100644 --- a/docs/cli/settings.md +++ b/docs/cli/settings.md @@ -29,7 +29,7 @@ they appear in the UI. | Vim Mode | `general.vimMode` | Enable Vim keybindings | `false` | | Default Approval Mode | `general.defaultApprovalMode` | The default approval mode for tool execution. 'default' prompts for approval, 'auto_edit' auto-approves edit tools, and 'plan' is read-only mode. YOLO mode (auto-approve all actions) can only be enabled via command line (--yolo or --approval-mode=yolo). | `"default"` | | Enable Auto Update | `general.enableAutoUpdate` | Enable automatic updates. | `true` | -| Enable Notifications | `general.enableNotifications` | Enable run-event notifications for action-required prompts and session completion. Currently macOS only. | `false` | +| Enable Notifications | `general.enableNotifications` | Enable run-event notifications for action-required prompts and session completion. | `false` | | Plan Directory | `general.plan.directory` | The directory where planning artifacts are stored. If not specified, defaults to the system temporary directory. A custom directory requires a policy to allow write access in Plan Mode. | `undefined` | | Plan Model Routing | `general.plan.modelRouting` | Automatically switch between Pro and Flash models based on Plan Mode status. Uses Pro for the planning phase and Flash for the implementation phase. | `true` | | Retry Fetch Errors | `general.retryFetchErrors` | Retry on "exception TypeError: fetch failed sending request" errors. | `true` | diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index ef325681ce..ec8f74de95 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -133,7 +133,7 @@ their corresponding top-level category object in your `settings.json` file. - **`general.enableNotifications`** (boolean): - **Description:** Enable run-event notifications for action-required prompts - and session completion. Currently macOS only. + and session completion. - **Default:** `false` - **`general.checkpointing.enabled`** (boolean): diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts index aba97ca179..aec521317c 100644 --- a/packages/cli/src/config/settingsSchema.ts +++ b/packages/cli/src/config/settingsSchema.ts @@ -261,7 +261,7 @@ const SETTINGS_SCHEMA = { requiresRestart: false, default: false, description: - 'Enable run-event notifications for action-required prompts and session completion. Currently macOS only.', + 'Enable run-event notifications for action-required prompts and session completion.', showInDialog: true, }, checkpointing: { diff --git a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Initial-Rendering-should-render-settings-list-with-visual-indicators.snap.svg b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Initial-Rendering-should-render-settings-list-with-visual-indicators.snap.svg index fc567671b8..655e9bce71 100644 --- a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Initial-Rendering-should-render-settings-list-with-visual-indicators.snap.svg +++ b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Initial-Rendering-should-render-settings-list-with-visual-indicators.snap.svg @@ -71,7 +71,7 @@ false - Enable run-event notifications for action-required prompts and session completion. … + Enable run-event notifications for action-required prompts and session completion. diff --git a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-accessibility-settings-enabled-correctly.snap.svg b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-accessibility-settings-enabled-correctly.snap.svg index a01eae091d..54b716a36b 100644 --- a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-accessibility-settings-enabled-correctly.snap.svg +++ b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-accessibility-settings-enabled-correctly.snap.svg @@ -71,7 +71,7 @@ false - Enable run-event notifications for action-required prompts and session completion. … + Enable run-event notifications for action-required prompts and session completion. diff --git a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-all-boolean-settings-disabled-correctly.snap.svg b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-all-boolean-settings-disabled-correctly.snap.svg index d777591e70..78dd34369d 100644 --- a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-all-boolean-settings-disabled-correctly.snap.svg +++ b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-all-boolean-settings-disabled-correctly.snap.svg @@ -71,7 +71,7 @@ false - Enable run-event notifications for action-required prompts and session completion. … + Enable run-event notifications for action-required prompts and session completion. diff --git a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-default-state-correctly.snap.svg b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-default-state-correctly.snap.svg index fc567671b8..655e9bce71 100644 --- a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-default-state-correctly.snap.svg +++ b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-default-state-correctly.snap.svg @@ -71,7 +71,7 @@ false - Enable run-event notifications for action-required prompts and session completion. … + Enable run-event notifications for action-required prompts and session completion. diff --git a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-file-filtering-settings-configured-correctly.snap.svg b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-file-filtering-settings-configured-correctly.snap.svg index fc567671b8..655e9bce71 100644 --- a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-file-filtering-settings-configured-correctly.snap.svg +++ b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-file-filtering-settings-configured-correctly.snap.svg @@ -71,7 +71,7 @@ false - Enable run-event notifications for action-required prompts and session completion. … + Enable run-event notifications for action-required prompts and session completion. diff --git a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-focused-on-scope-selector-correctly.snap.svg b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-focused-on-scope-selector-correctly.snap.svg index 3d11268eff..3d1e8b7dc9 100644 --- a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-focused-on-scope-selector-correctly.snap.svg +++ b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-focused-on-scope-selector-correctly.snap.svg @@ -60,7 +60,7 @@ false - Enable run-event notifications for action-required prompts and session completion. … + Enable run-event notifications for action-required prompts and session completion. diff --git a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-mixed-boolean-and-number-settings-correctly.snap.svg b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-mixed-boolean-and-number-settings-correctly.snap.svg index 0f619971c1..3868b38e23 100644 --- a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-mixed-boolean-and-number-settings-correctly.snap.svg +++ b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-mixed-boolean-and-number-settings-correctly.snap.svg @@ -71,7 +71,7 @@ false - Enable run-event notifications for action-required prompts and session completion. … + Enable run-event notifications for action-required prompts and session completion. diff --git a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-tools-and-security-settings-correctly.snap.svg b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-tools-and-security-settings-correctly.snap.svg index fc567671b8..655e9bce71 100644 --- a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-tools-and-security-settings-correctly.snap.svg +++ b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-tools-and-security-settings-correctly.snap.svg @@ -71,7 +71,7 @@ false - Enable run-event notifications for action-required prompts and session completion. … + Enable run-event notifications for action-required prompts and session completion. diff --git a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-various-boolean-settings-enabled-correctly.snap.svg b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-various-boolean-settings-enabled-correctly.snap.svg index 3a7a0580ff..196b1e5ed1 100644 --- a/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-various-boolean-settings-enabled-correctly.snap.svg +++ b/packages/cli/src/ui/components/__snapshots__/SettingsDialog-SettingsDialog-Snapshot-Tests-should-render-various-boolean-settings-enabled-correctly.snap.svg @@ -71,7 +71,7 @@ false - Enable run-event notifications for action-required prompts and session completion. … + Enable run-event notifications for action-required prompts and session completion. diff --git a/packages/cli/src/ui/components/__snapshots__/SettingsDialog.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/SettingsDialog.test.tsx.snap index 19158681b2..a3d3581677 100644 --- a/packages/cli/src/ui/components/__snapshots__/SettingsDialog.test.tsx.snap +++ b/packages/cli/src/ui/components/__snapshots__/SettingsDialog.test.tsx.snap @@ -20,7 +20,7 @@ exports[`SettingsDialog > Initial Rendering > should render settings list with v │ Enable automatic updates. │ │ │ │ Enable Notifications false │ -│ Enable run-event notifications for action-required prompts and session completion. … │ +│ Enable run-event notifications for action-required prompts and session completion. │ │ │ │ Plan Directory undefined │ │ The directory where planning artifacts are stored. If not specified, defaults t… │ @@ -66,7 +66,7 @@ exports[`SettingsDialog > Snapshot Tests > should render 'accessibility settings │ Enable automatic updates. │ │ │ │ Enable Notifications false │ -│ Enable run-event notifications for action-required prompts and session completion. … │ +│ Enable run-event notifications for action-required prompts and session completion. │ │ │ │ Plan Directory undefined │ │ The directory where planning artifacts are stored. If not specified, defaults t… │ @@ -112,7 +112,7 @@ exports[`SettingsDialog > Snapshot Tests > should render 'all boolean settings d │ Enable automatic updates. │ │ │ │ Enable Notifications false │ -│ Enable run-event notifications for action-required prompts and session completion. … │ +│ Enable run-event notifications for action-required prompts and session completion. │ │ │ │ Plan Directory undefined │ │ The directory where planning artifacts are stored. If not specified, defaults t… │ @@ -158,7 +158,7 @@ exports[`SettingsDialog > Snapshot Tests > should render 'default state' correct │ Enable automatic updates. │ │ │ │ Enable Notifications false │ -│ Enable run-event notifications for action-required prompts and session completion. … │ +│ Enable run-event notifications for action-required prompts and session completion. │ │ │ │ Plan Directory undefined │ │ The directory where planning artifacts are stored. If not specified, defaults t… │ @@ -204,7 +204,7 @@ exports[`SettingsDialog > Snapshot Tests > should render 'file filtering setting │ Enable automatic updates. │ │ │ │ Enable Notifications false │ -│ Enable run-event notifications for action-required prompts and session completion. … │ +│ Enable run-event notifications for action-required prompts and session completion. │ │ │ │ Plan Directory undefined │ │ The directory where planning artifacts are stored. If not specified, defaults t… │ @@ -250,7 +250,7 @@ exports[`SettingsDialog > Snapshot Tests > should render 'focused on scope selec │ Enable automatic updates. │ │ │ │ Enable Notifications false │ -│ Enable run-event notifications for action-required prompts and session completion. … │ +│ Enable run-event notifications for action-required prompts and session completion. │ │ │ │ Plan Directory undefined │ │ The directory where planning artifacts are stored. If not specified, defaults t… │ @@ -296,7 +296,7 @@ exports[`SettingsDialog > Snapshot Tests > should render 'mixed boolean and numb │ Enable automatic updates. │ │ │ │ Enable Notifications false │ -│ Enable run-event notifications for action-required prompts and session completion. … │ +│ Enable run-event notifications for action-required prompts and session completion. │ │ │ │ Plan Directory undefined │ │ The directory where planning artifacts are stored. If not specified, defaults t… │ @@ -342,7 +342,7 @@ exports[`SettingsDialog > Snapshot Tests > should render 'tools and security set │ Enable automatic updates. │ │ │ │ Enable Notifications false │ -│ Enable run-event notifications for action-required prompts and session completion. … │ +│ Enable run-event notifications for action-required prompts and session completion. │ │ │ │ Plan Directory undefined │ │ The directory where planning artifacts are stored. If not specified, defaults t… │ @@ -388,7 +388,7 @@ exports[`SettingsDialog > Snapshot Tests > should render 'various boolean settin │ Enable automatic updates. │ │ │ │ Enable Notifications false │ -│ Enable run-event notifications for action-required prompts and session completion. … │ +│ Enable run-event notifications for action-required prompts and session completion. │ │ │ │ Plan Directory undefined │ │ The directory where planning artifacts are stored. If not specified, defaults t… │ diff --git a/packages/cli/src/utils/terminalNotifications.test.ts b/packages/cli/src/utils/terminalNotifications.test.ts index 7efa1c4f34..f05e650325 100644 --- a/packages/cli/src/utils/terminalNotifications.test.ts +++ b/packages/cli/src/utils/terminalNotifications.test.ts @@ -43,7 +43,7 @@ describe('terminal notifications', () => { }); }); - it('returns false without writing on non-macOS platforms', async () => { + it('emits notification on non-macOS platforms', async () => { Object.defineProperty(process, 'platform', { value: 'linux', configurable: true, @@ -54,8 +54,8 @@ describe('terminal notifications', () => { body: 'b', }); - expect(shown).toBe(false); - expect(writeToStdout).not.toHaveBeenCalled(); + expect(shown).toBe(true); + expect(writeToStdout).toHaveBeenCalled(); }); it('returns false without writing when disabled', async () => { @@ -69,6 +69,7 @@ describe('terminal notifications', () => { }); it('emits OSC 9 notification when supported terminal is detected', async () => { + vi.stubEnv('WT_SESSION', ''); vi.stubEnv('TERM_PROGRAM', 'iTerm.app'); const shown = await notifyViaTerminal(true, { @@ -126,6 +127,7 @@ describe('terminal notifications', () => { }); it('strips terminal control sequences and newlines from payload text', async () => { + vi.stubEnv('WT_SESSION', ''); vi.stubEnv('TERM_PROGRAM', 'iTerm.app'); const shown = await notifyViaTerminal(true, { diff --git a/packages/cli/src/utils/terminalNotifications.ts b/packages/cli/src/utils/terminalNotifications.ts index d774e852d3..c0ad259a4b 100644 --- a/packages/cli/src/utils/terminalNotifications.ts +++ b/packages/cli/src/utils/terminalNotifications.ts @@ -75,17 +75,10 @@ export function buildRunEventNotificationContent( export function isNotificationsEnabled(settings: LoadedSettings): boolean { const general = settings.merged.general as - | { - enableNotifications?: boolean; - enableMacOsNotifications?: boolean; - } + | { enableNotifications?: boolean } | undefined; - return ( - process.platform === 'darwin' && - (general?.enableNotifications === true || - general?.enableMacOsNotifications === true) - ); + return general?.enableNotifications === true; } function buildTerminalNotificationMessage( @@ -112,7 +105,7 @@ export async function notifyViaTerminal( notificationsEnabled: boolean, content: RunEventNotificationContent, ): Promise { - if (!notificationsEnabled || process.platform !== 'darwin') { + if (!notificationsEnabled) { return false; } diff --git a/schemas/settings.schema.json b/schemas/settings.schema.json index 28194b587c..74988cb240 100644 --- a/schemas/settings.schema.json +++ b/schemas/settings.schema.json @@ -93,8 +93,8 @@ }, "enableNotifications": { "title": "Enable Notifications", - "description": "Enable run-event notifications for action-required prompts and session completion. Currently macOS only.", - "markdownDescription": "Enable run-event notifications for action-required prompts and session completion. Currently macOS only.\n\n- Category: `General`\n- Requires restart: `no`\n- Default: `false`", + "description": "Enable run-event notifications for action-required prompts and session completion.", + "markdownDescription": "Enable run-event notifications for action-required prompts and session completion.\n\n- Category: `General`\n- Requires restart: `no`\n- Default: `false`", "default": false, "type": "boolean" },