Skip to content

Commit da63b09

Browse files
authored
fix(session-notification): Replace blocking MessageBox with native toast on Windows (#62)
The previous Windows implementation used System.Windows.Forms.MessageBox which displays a blocking modal dialog requiring user interaction. This replaces it with the native Windows.UI.Notifications.ToastNotificationManager API (Windows 10+) which shows a non-intrusive toast notification in the corner, consistent with macOS and Linux behavior. - Uses native Toast API (no external dependencies like BurntToast) - Non-blocking: notification auto-dismisses - Graceful degradation: silently fails on older Windows versions - Fix escaping for each platform (PowerShell: '' for quotes, AppleScript: backslash)
1 parent aafee74 commit da63b09

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

src/hooks/session-notification.ts

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,34 @@ async function sendNotification(
4848
title: string,
4949
message: string
5050
): Promise<void> {
51-
const escapedTitle = title.replace(/"/g, '\\"').replace(/'/g, "\\'")
52-
const escapedMessage = message.replace(/"/g, '\\"').replace(/'/g, "\\'")
53-
5451
switch (p) {
55-
case "darwin":
56-
await ctx.$`osascript -e ${"display notification \"" + escapedMessage + "\" with title \"" + escapedTitle + "\""}`
52+
case "darwin": {
53+
const esTitle = title.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
54+
const esMessage = message.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
55+
await ctx.$`osascript -e ${"display notification \"" + esMessage + "\" with title \"" + esTitle + "\""}`
5756
break
57+
}
5858
case "linux":
59-
await ctx.$`notify-send ${escapedTitle} ${escapedMessage} 2>/dev/null`.catch(() => {})
59+
await ctx.$`notify-send ${title} ${message} 2>/dev/null`.catch(() => {})
6060
break
61-
case "win32":
62-
await ctx.$`powershell -Command ${"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('" + escapedMessage + "', '" + escapedTitle + "')"}`
61+
case "win32": {
62+
const psTitle = title.replace(/'/g, "''")
63+
const psMessage = message.replace(/'/g, "''")
64+
const toastScript = `
65+
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
66+
$Template = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02)
67+
$RawXml = [xml] $Template.GetXml()
68+
($RawXml.toast.visual.binding.text | Where-Object {$_.id -eq '1'}).AppendChild($RawXml.CreateTextNode('${psTitle}')) | Out-Null
69+
($RawXml.toast.visual.binding.text | Where-Object {$_.id -eq '2'}).AppendChild($RawXml.CreateTextNode('${psMessage}')) | Out-Null
70+
$SerializedXml = New-Object Windows.Data.Xml.Dom.XmlDocument
71+
$SerializedXml.LoadXml($RawXml.OuterXml)
72+
$Toast = [Windows.UI.Notifications.ToastNotification]::new($SerializedXml)
73+
$Notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('OpenCode')
74+
$Notifier.Show($Toast)
75+
`.trim().replace(/\n/g, "; ")
76+
await ctx.$`powershell -Command ${toastScript}`.catch(() => {})
6377
break
78+
}
6479
}
6580
}
6681

0 commit comments

Comments
 (0)