fix(notification): resolve platform in scheduler callbacks instead of using stale init value

The idle notification scheduler was initialized with platform 'unsupported'
before platform detection had run. This stale value was passed to send/playSound
callbacks, causing sendSessionNotification to silently no-op (no switch case for
'unsupported'). Session-idle notifications never fired as a result.

Fix: remove platform from scheduler options entirely. Callbacks now resolve
platform via ensureNotificationPlatform() which is sync, cached, and already
called by each event handler before scheduling.
This commit is contained in:
mrosnerr
2026-04-28 10:34:29 -04:00
parent fbaeb032c0
commit 384bc53bfd
2 changed files with 10 additions and 9 deletions
+4 -6
View File
@@ -1,5 +1,4 @@
import type { PluginInput } from "@opencode-ai/plugin" import type { PluginInput } from "@opencode-ai/plugin"
import type { Platform } from "./session-notification-sender"
type SessionNotificationConfig = { type SessionNotificationConfig = {
playSound: boolean playSound: boolean
@@ -13,11 +12,10 @@ type SessionNotificationConfig = {
export function createIdleNotificationScheduler(options: { export function createIdleNotificationScheduler(options: {
ctx: PluginInput ctx: PluginInput
platform: Platform
config: SessionNotificationConfig config: SessionNotificationConfig
hasIncompleteTodos: (ctx: PluginInput, sessionID: string) => Promise<boolean> hasIncompleteTodos: (ctx: PluginInput, sessionID: string) => Promise<boolean>
send: (ctx: PluginInput, platform: Platform, sessionID: string) => Promise<void> send: (ctx: PluginInput, sessionID: string) => Promise<void>
playSound: (ctx: PluginInput, platform: Platform, soundPath: string) => Promise<void> playSound: (ctx: PluginInput, soundPath: string) => Promise<void>
}) { }) {
const notifiedSessions = new Set<string>() const notifiedSessions = new Set<string>()
const pendingTimers = new Map<string, ReturnType<typeof setTimeout>>() const pendingTimers = new Map<string, ReturnType<typeof setTimeout>>()
@@ -136,10 +134,10 @@ export function createIdleNotificationScheduler(options: {
notifiedSessions.add(sessionID) notifiedSessions.add(sessionID)
await options.send(options.ctx, options.platform, sessionID) await options.send(options.ctx, sessionID)
if (options.config.playSound && options.config.soundPath) { if (options.config.playSound && options.config.soundPath) {
await options.playSound(options.ctx, options.platform, options.config.soundPath) await options.playSound(options.ctx, options.config.soundPath)
} }
} finally { } finally {
executingNotifications.delete(sessionID) executingNotifications.delete(sessionID)
+6 -3
View File
@@ -47,10 +47,10 @@ export function createSessionNotification(ctx: PluginInput, config: SessionNotif
const scheduler = createIdleNotificationScheduler({ const scheduler = createIdleNotificationScheduler({
ctx, ctx,
platform: "unsupported",
config: mergedConfig, config: mergedConfig,
hasIncompleteTodos, hasIncompleteTodos,
send: async (hookCtx, platform, sessionID) => { send: async (hookCtx, sessionID) => {
const platform = ensureNotificationPlatform()
if (typeof hookCtx.client.session.get !== "function" && typeof hookCtx.client.session.messages !== "function") { if (typeof hookCtx.client.session.get !== "function" && typeof hookCtx.client.session.messages !== "function") {
await sessionNotificationSender.sendSessionNotification(hookCtx, platform, mergedConfig.title, mergedConfig.message) await sessionNotificationSender.sendSessionNotification(hookCtx, platform, mergedConfig.title, mergedConfig.message)
return return
@@ -64,7 +64,10 @@ export function createSessionNotification(ctx: PluginInput, config: SessionNotif
await sessionNotificationSender.sendSessionNotification(hookCtx, platform, content.title, content.message) await sessionNotificationSender.sendSessionNotification(hookCtx, platform, content.title, content.message)
}, },
playSound: sessionNotificationSender.playSessionNotificationSound, playSound: async (hookCtx, soundPath) => {
const platform = ensureNotificationPlatform()
await sessionNotificationSender.playSessionNotificationSound(hookCtx, platform, soundPath)
},
}) })
const QUESTION_TOOLS = new Set(["question", "ask_user_question", "askuserquestion"]) const QUESTION_TOOLS = new Set(["question", "ask_user_question", "askuserquestion"])