/** * @file Browser-notification preferences — the single definition of the shape, * the defaults, and the `localStorage` read/write. Settings (which edits them) * and `useNotifications` (which obeys them) both import from here; they used to * carry private copies, so adding a notification type meant editing the same * literal twice and a miss went unnoticed until a toggle did nothing. * @author Nguyễn Ngọc Trí Vĩ */ export const NOTIF_KEY = "agent-monitor-notifications"; export interface NotifPrefs { /** Master switch; when false no notification fires, whatever the flags say. */ enabled: boolean; onNewSession: boolean; onSessionError: boolean; /** Claude is BLOCKED on the user — a permission prompt or a question. */ onAwaitingInput: boolean; /** Claude finished its turn and is waiting for the next prompt (`Stop`). */ onTurnComplete: boolean; /** The whole session closed (`SessionEnd`), not just one turn. */ onSessionComplete: boolean; onSubagentSpawn: boolean; } // The two "Claude is waiting for you" types default ON: they are the reason // notifications exist (issue #29 — the user walks away during a long run and // needs to know when they are the blocker). The rest stay as they were. export const defaultNotifPrefs: NotifPrefs = { enabled: false, onNewSession: false, onSessionError: true, onAwaitingInput: true, onTurnComplete: true, onSessionComplete: false, onSubagentSpawn: false, }; /** Reads prefs, merged over the defaults so a stored blob written by an older * build (missing the newer flags) still yields a complete object. */ export function loadNotifPrefs(): NotifPrefs { try { const raw = localStorage.getItem(NOTIF_KEY); if (!raw) return { ...defaultNotifPrefs }; return { ...defaultNotifPrefs, ...(JSON.parse(raw) as Partial) }; } catch { return { ...defaultNotifPrefs }; } } export function saveNotifPrefs(prefs: NotifPrefs) { try { localStorage.setItem(NOTIF_KEY, JSON.stringify(prefs)); } catch { /* private mode / quota — the toggle still applies for this tab */ } }