import { notificationToDesktopText, type NotificationInput } from "./notify-protocol.ts"; import type { Runtime } from "./runtime.ts"; import { $which } from "./which.ts"; export function resolveWindowsNotifier(runtime: Runtime, preferredPath?: string): string | null { if (preferredPath) return preferredPath; return $which("powershell.exe", runtime); } function base64Utf16(value: string): string { return Buffer.from(value, "utf16le").toString("base64"); } /** * The script is intentionally static apart from base64 data literals. Text is * inserted through DOM APIs rather than PowerShell/XML syntax. */ export function buildWindowsNotifyCommand(input: NotificationInput, powershellPath: string): string[] { const { title, body } = notificationToDesktopText(input); const title64 = base64Utf16(title); const body64 = base64Utf16(body); const script = [ "$ErrorActionPreference='Stop';", `$t=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('${title64}'));`, `$b=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('${body64}'));`, "try {", "Add-Type -AssemblyName System.Runtime.WindowsRuntime;", "[void][Windows.UI.Notifications.ToastNotificationManager,Windows.UI.Notifications,ContentType=WindowsRuntime];", "$xml=New-Object Windows.Data.Xml.Dom.XmlDocument;", "$toast=$xml.CreateElement('toast'); $visual=$xml.CreateElement('visual'); $binding=$xml.CreateElement('binding');", "$binding.SetAttribute('template','ToastText02');", "$line1=$xml.CreateElement('text'); $line1.InnerText=$t; $line2=$xml.CreateElement('text'); $line2.InnerText=$b;", "$null=$binding.AppendChild($line1); $null=$binding.AppendChild($line2); $null=$visual.AppendChild($binding); $null=$toast.AppendChild($visual);", "$notification=New-Object Windows.UI.Notifications.ToastNotification($xml);", "$notifier=[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier();", "$notifier.Show($notification);", "} catch { }", ].join(""); return [powershellPath, "-NoProfile", "-NonInteractive", "-Command", script]; } export function resolveWindowsDesktopCommand(input: NotificationInput, runtime: Runtime, preferredPath?: string): { command: string; args: string[] } | null { const path = resolveWindowsNotifier(runtime, preferredPath); if (!path) return null; const argv = buildWindowsNotifyCommand(input, path); return { command: argv[0]!, args: argv.slice(1) }; } export function sendWindowsDesktopNotification(input: NotificationInput, runtime: Runtime, preferredPath?: string): boolean { const resolved = resolveWindowsDesktopCommand(input, runtime, preferredPath); if (!resolved) return false; runtime.spawnDetached(resolved.command, resolved.args); return true; }