Skip to content

feat(tui): send native Windows toast notifications in Windows Terminal - #3075

Open
bj456736 wants to merge 1 commit into
MoonshotAI:mainfrom
bj456736:fix/windows-terminal-toast-notification
Open

feat(tui): send native Windows toast notifications in Windows Terminal#3075
bj456736 wants to merge 1 commit into
MoonshotAI:mainfrom
bj456736:fix/windows-terminal-toast-notification

Conversation

@bj456736

Copy link
Copy Markdown
Contributor

Problem

Desktop notifications in the TUI are delivered via OSC 9 escape sequences, gated on a small allow-list (iTerm2 / WezTerm / Ghostty / Warp / Kitty). Every other terminal only gets a bare BEL. Windows Terminal does not support OSC 9 desktop notifications — its OSC 9 is taken by ConEmu progress semantics — so Windows Terminal users never get a visual notification when a task completes or approval is needed; they only get the bell.

Fix

When the session is Windows Terminal (WT_SESSION is set) and OSC 9 is not supported, the BEL fallback path now additionally fires a native Windows toast via the system powershell.exe (WinRT Windows.UI.Notifications, ToastText01 template, notifier id Kimi Code). The spawn is fire-and-forget: execFile with an error-swallowing callback, wrapped in try/catch, and unrefed — notification delivery can never crash or hang the TUI.

Ported from the MIT-licensed pi-notify (credited in code comments), with two fixes over the original:

  • the notification text is single-quote escaped (''') before being interpolated into the PowerShell script;
  • execFile gets an error callback (the original passes none, so a missing powershell.exe would raise an unhandled error and crash the process).

No new npm dependencies, no binaries.

Design trade-offs

  • WT only. The OSC 9 path is completely untouched, and we do not pre-send OSC 777 to Windows Terminal — if WT ever grows OSC 9/777 notification support, users won't get double notifications.
  • BEL stays as the generic audible fallback: a double sound is preferable to no notification.
  • Env-only detection (WT_SESSION non-empty, no process.platform check): under WSL, process.platform is linux but WT_SESSION is inherited and powershell.exe works via interop.
  • No click callback / AUMID registration: the toast uses the fixed notifier id Kimi Code and the single-text ToastText01 template; XML injection is a non-issue since CreateTextNode escapes for us.

Tests

New cases in apps/kimi-code/test/tui/terminal-notification.test.ts:

  • isWindowsTerminalSession detection with and without WT_SESSION
  • buildWindowsToastCommand shape (powershell.exe -NoProfile -NonInteractive -Command …, ToastText01, notifier id Kimi Code) and single-quote escaping
  • emitTerminalNotification (with node:child_process execFile mocked): WT + no OSC 9 → BEL written and toast spawned; WT + OSC 9 → no spawn; non-WT + no OSC 9 → no spawn; execFile callback invoked with an Error → no throw; empty message → no spawn

Local results: vitest run test/tui/terminal-notification.test.ts — 31/31 passed; tsc --noEmit typecheck clean; oxlint --type-aware on the changed files reports 0 warnings / 0 errors.

On-Windows verification (actual toast rendering in Windows Terminal) will be done by maintainer 瑞丰.

@changeset-bot

changeset-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a082644

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@bj456736

Copy link
Copy Markdown
Contributor Author

@codex review

@pkg-pr-new

pkg-pr-new Bot commented Aug 19, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@a082644
npx https://pkg.pr.new/@moonshot-ai/kimi-code@a082644

commit: a082644

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a082644d1c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +194 to +197
const child = execFile(file, args, () => {
// Intentionally empty: delivery errors are not actionable here.
});
child.unref();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Detach the toast subprocess's stdio before unref

When a user exits while PowerShell is still running—or PowerShell wedges—this is not actually fire-and-forget: execFile creates referenced stdout/stderr pipes for its callback, and child.unref() only unreferences the child-process handle, so those pipes keep Node's event loop alive until the subprocess exits. Spawn the notifier with ignored/detached stdio (while retaining an error handler), or otherwise close/unref the streams and impose a timeout, so toast delivery cannot delay or hang TUI shutdown.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant