Compare commits

...
Author SHA1 Message Date
Brendonovich 4cff5b5788 fix(desktop): retain notification click handlers 2026-08-25 05:40:25 +00:00
2 changed files with 45 additions and 0 deletions
@@ -0,0 +1,38 @@
import { expect, test } from "bun:test"
import { createDesktopNotify } from "./notifications"
test("retains notifications until they are handled", async () => {
const original = globalThis.Notification
let reference: WeakRef<Notification> | undefined
class TestNotification extends EventTarget {
onclick: Notification["onclick"] = null
onclose: Notification["onclose"] = null
constructor() {
super()
reference = new WeakRef(this as Notification)
}
close() {}
}
globalThis.Notification = TestNotification as unknown as typeof Notification
try {
const notify = createDesktopNotify({
getWindowFocused: async () => false,
} as never)
await notify("Response ready", "session")
for (let attempt = 0; attempt < 20 && reference?.deref(); attempt++) {
Bun.gc(true)
await Bun.sleep(0)
}
expect(reference?.deref()).toBeDefined()
expect(notify).toBeFunction()
} finally {
globalThis.Notification = original
}
})
@@ -2,6 +2,8 @@ import type { Platform } from "@opencode-ai/app/desktop"
import type { ElectronAPI } from "../api-types"
export function createDesktopNotify(api: ElectronAPI): Platform["notify"] {
const notifications = new Set<Notification>()
return async (title, description, onClick) => {
const focused = await api.getWindowFocused().catch(() => document.hasFocus())
if (focused) return
@@ -10,10 +12,15 @@ export function createDesktopNotify(api: ElectronAPI): Platform["notify"] {
body: description ?? "",
icon: "https://opencode.ai/favicon-96x96-v3.png",
})
notifications.add(notification)
const clear = () => notifications.delete(notification)
notification.onclose = clear
notification.onerror = clear
notification.onclick = () => {
void api.showWindow()
void api.setWindowFocus()
onClick?.()
clear()
notification.close()
}
}