basant307/AI_Governance_Project
045
1/**2 * @license3 * Copyright 2026 Qwen Team4 * SPDX-License-Identifier: Apache-2.05 */6 7/**8 * Notification routing service.9 *10 * When `terminalBell` setting is enabled, auto-detects the terminal and11 * sends notifications through the best available channel:12 *13 * iTerm.app → OSC 9 (native notification)14 * kitty → OSC 99 (desktop notification protocol)15 * ghostty → OSC 777 (notify)16 * others → terminal bell fallback17 *18 * When disabled, no notification is sent.19 */20 21import { createDebugLogger } from '@qwen-code/qwen-code-core';22import type { TerminalNotification } from '../ui/hooks/useTerminalNotification.js';23import { detectTerminal, generateKittyId } from '../utils/osc.js';24 25const debugLogger = createDebugLogger('NOTIFICATION_SERVICE');26 27export interface NotificationOptions {28 message: string;29 title?: string;30}31 32const DEFAULT_TITLE = 'Qwen Code';33 34/**35 * Send a notification through the auto-detected channel.36 *37 * @param opts - Notification content38 * @param terminal - Terminal notification primitives39 * @param enabled - Whether notifications are enabled (from `terminalBell` setting)40 * @returns The channel method that was actually used, or 'disabled'.41 */42export function sendNotification(43 opts: NotificationOptions,44 terminal: TerminalNotification,45 enabled: boolean,46): string {47 if (!enabled) {48 return 'disabled';49 }50 51 // Don't write raw escape sequences when stdout is not a TTY52 // (CI, piped output, redirected to log files, etc.)53 if (!process.stdout?.isTTY) {54 return 'disabled';55 }56 57 const title = opts.title ?? DEFAULT_TITLE;58 59 try {60 const terminalType = detectTerminal();61 62 switch (terminalType) {63 case 'iTerm.app':64 terminal.notifyITerm2({ ...opts, title });65 return 'iterm2';66 case 'kitty':67 terminal.notifyKitty({ ...opts, title, id: generateKittyId() });68 return 'kitty';69 case 'ghostty':70 terminal.notifyGhostty({ ...opts, title });71 return 'ghostty';72 case 'Apple_Terminal':73 default:74 terminal.notifyBell();75 return 'terminal_bell';76 }77 } catch (error) {78 debugLogger.warn('Failed to send notification:', error);79 return 'error';80 }81}82 