From yapp · yet another pi pack
Desktop notifications for terminal applications. Focus-aware — suppresses notifications when the terminal is in the foreground. Click-to-focus brings the terminal back when you interact with a notification.
- Focus tracking — detects terminal focus via DECSET 1004 escape sequences. Notifications are suppressed while the terminal is focused (configurable).
- Click-to-focus — clicking a notification focuses the terminal window. Supports macOS, niri, sway, and hyprland.
- Cross-platform — macOS via
terminal-notifier, Linux vianotify-send. - Zero dependencies — uses
node:child_processdirectly.
As a pi extension:
pi install npm:pi-desktop-notifyAs a library:
npm install pi-desktop-notifymacOS: Install terminal-notifier:
brew install terminal-notifierLinux: notify-send (usually pre-installed, part of libnotify).
import {
sendNotification,
startFocusTracking,
captureWindowId,
} from "pi-desktop-notify";
// Call once at startup
startFocusTracking(); // begin tracking terminal focus
await captureWindowId(); // capture window ID for click-to-focus
// Send notifications
await sendNotification({
title: "Task complete",
body: "Build finished successfully",
});
// Notifications are suppressed when focused (default).
// Override with skipIfFocused: false
await sendNotification({
title: "Important",
body: "Something needs attention",
skipIfFocused: false,
});Send a desktop notification.
| Option | Type | Default | Description |
|---|---|---|---|
title |
string |
required | Notification title |
body |
string |
required | Notification body |
cwd |
string |
process.cwd() |
Working directory (used for macOS click-to-focus in Zed) |
skipIfFocused |
boolean |
true |
Suppress when terminal is focused |
Start tracking terminal focus via DECSET 1004. Idempotent — safe to call multiple times. Listens on process.stdin for focus in/out escape sequences.
Stop tracking and disable focus reporting.
Returns true if the terminal is currently focused. Defaults to true before tracking starts.
Capture the currently focused window's compositor ID. Call when the terminal is guaranteed to be focused. Used by focusWindow() for click-to-focus on notifications.
Focus the previously captured terminal window. Called automatically on notification click.
Focus tracking uses the DECSET 1004 terminal escape sequence. When enabled, the terminal sends \x1b[I (focus gained) and \x1b[O (focus lost). These are intercepted on process.stdin before other handlers see them. Works with kitty, wezterm, foot, alacritty, iTerm2, Zed, and most modern terminals. Also works through tmux and abduco.
Click-to-focus captures the terminal's window ID at initialization, then uses compositor-specific commands to focus it when a notification is clicked:
| Platform | Method |
|---|---|
| macOS | osascript / terminal-notifier -activate |
| niri | niri msg action focus-window --id |
| sway | swaymsg [con_id=...] focus |
| hyprland | hyprctl dispatch focuswindow address:... |