diff --git a/packages/tui/src/desktop-notify.ts b/packages/tui/src/desktop-notify.ts index 79f92c340..880f5a14e 100644 --- a/packages/tui/src/desktop-notify.ts +++ b/packages/tui/src/desktop-notify.ts @@ -20,6 +20,8 @@ // iTerm2, WezTerm, …) keep working unchanged and the BEL emission still fires // for tmux `monitor-bell`, X11 urgency hints, and audible-bell handlers. +import * as fs from "node:fs"; +import * as path from "node:path"; import { $which } from "@oh-my-pi/pi-utils"; import type { TerminalId, TerminalNotification } from "./terminal-capabilities"; @@ -42,9 +44,12 @@ export interface DesktopNotifier { export function hasLinuxDesktopSession( platform: NodeJS.Platform = process.platform, env: NodeJS.ProcessEnv = Bun.env, + fileExists: (path: string) => boolean = fs.existsSync, ): boolean { if (platform !== "linux") return false; - return Boolean(env.DBUS_SESSION_BUS_ADDRESS); + if (env.DBUS_SESSION_BUS_ADDRESS) return true; + const runtimeDir = env.XDG_RUNTIME_DIR; + return Boolean(runtimeDir && fileExists(path.join(runtimeDir, "bus"))); } /** diff --git a/packages/tui/test/desktop-notify.test.ts b/packages/tui/test/desktop-notify.test.ts index 24a23083e..a0ef6203c 100644 --- a/packages/tui/test/desktop-notify.test.ts +++ b/packages/tui/test/desktop-notify.test.ts @@ -19,6 +19,14 @@ describe("hasLinuxDesktopSession", () => { expect(hasLinuxDesktopSession("darwin", LINUX_ENV)).toBe(false); expect(hasLinuxDesktopSession("win32", LINUX_ENV)).toBe(false); }); + + it("accepts the systemd user bus socket when the address is not exported", () => { + const env = { XDG_RUNTIME_DIR: "/run/user/1000" }; + const fileExists = (path: string) => path === "/run/user/1000/bus"; + + expect(hasLinuxDesktopSession("linux", env, fileExists)).toBe(true); + expect(hasLinuxDesktopSession("linux", env, () => false)).toBe(false); + }); }); describe("shouldDeliverDesktopNotification", () => {