import { NOTIFY_ENV } from "./constants.ts"; import { detectPlatform, type Platform } from "./platform.ts"; import { NotifyProtocol } from "./notify-protocol.ts"; import { resolveLinuxDesktopCommand } from "./notify-linux.ts"; import { resolveMacosDesktopCommand } from "./notify-macos.ts"; import { resolveWindowsDesktopCommand } from "./notify-windows.ts"; import { resolveWslDesktopCommand } from "./notify-wsl.ts"; import type { NotificationInput } from "./notify-protocol.ts"; import { createRuntime, type Runtime } from "./runtime.ts"; export type NotifyPlatformOverride = Platform | "auto" | "off"; export function normalizeNotifyPlatform(value: string | undefined): NotifyPlatformOverride { switch (value?.trim().toLowerCase()) { case "linux": case "macos": case "windows": case "wsl": case "off": case "auto": return value.trim().toLowerCase() as NotifyPlatformOverride; default: return "auto"; } } export function resolveNotifyPlatform(runtime: Runtime): Platform | "off" { const override = normalizeNotifyPlatform(runtime.env[NOTIFY_ENV.platform]); if (override === "off") return "off"; if (override !== "auto") return override; return detectPlatform(String(runtime.platform), runtime.env, () => runtime.readFileSync("/proc/version")); } function isTruthy(value: string | undefined): boolean { return value !== undefined && /^(?:1|true|on|yes)$/iu.test(value.trim()); } function isSuppressed(value: string | undefined): boolean { return value !== undefined && /^(?:0|false|off)$/iu.test(value.trim()); } export interface DesktopNotificationGateOptions { runtime?: Runtime; protocol?: NotifyProtocol; platform?: Platform | "off"; } /** Pure gate: no PATH probes, spawns, or filesystem checks. */ export function shouldDeliverDesktopNotification(options: DesktopNotificationGateOptions = {}): boolean { const runtime = options.runtime ?? createRuntime(); const protocol = options.protocol ?? NotifyProtocol.Bell; if (protocol !== NotifyProtocol.Bell || !runtime.stdoutIsTTY) return false; if (isSuppressed(runtime.env[NOTIFY_ENV.global]) || isTruthy(runtime.env[NOTIFY_ENV.desktop])) return false; const selected = options.platform ?? resolveNotifyPlatform(runtime); return selected !== "off" && selected !== "other"; } function commandFor(input: NotificationInput, selected: Platform, runtime: Runtime): { command: string; args: string[] } | null { switch (selected) { case "linux": return resolveLinuxDesktopCommand(input, runtime); case "macos": return resolveMacosDesktopCommand(input, runtime); case "windows": return resolveWindowsDesktopCommand(input, runtime); case "wsl": return resolveWslDesktopCommand(input, runtime); default: return null; } } /** Resolve one strategy and spawn it without waiting for delivery or exit. */ export function sendDesktopNotification(input: NotificationInput, runtime: Runtime = createRuntime(), protocol: NotifyProtocol = NotifyProtocol.Bell): boolean { try { const selected = resolveNotifyPlatform(runtime); if (!shouldDeliverDesktopNotification({ runtime, protocol, platform: selected })) return false; if (selected === "off" || selected === "other") return false; const command = commandFor(input, selected, runtime); if (!command) return false; runtime.spawnDetached(command.command, command.args); return true; } catch { return false; } }