import { soundPlayer } from "./soundPlayer"; import { NotificationType, NOTIFICATION_SOUNDS } from "./types"; import { invoke } from "@tauri-apps/api/core"; import { sendTerminalNotification } from "./terminalNotifier"; class NotificationManager { async notify(type: NotificationType, message?: string): Promise { // Always play sound (if enabled) await soundPlayer.play(type); const sound = NOTIFICATION_SOUNDS[type]; const title = sound.phrase; const body = message || this.getDefaultMessage(type); // Try multiple notification methods in order const notificationMethods = [ // Method 1: Try Windows PowerShell (best for system tray notifications) async () => { console.log("Trying Windows PowerShell notifications..."); await invoke("send_windows_notification", { title, body }); }, // Method 2: Try native Windows toast (for Windows builds) async () => { console.log("Trying native Windows toast..."); await invoke("send_windows_toast", { title, body }); }, // Method 3: Try WSL-specific notification (Windows toast via PowerShell - for WSL) async () => { console.log("Trying WSL notification..."); await invoke("send_wsl_notification", { title, body }); }, // Method 4: Try native Tauri notifications async () => { console.log("Trying Tauri native notifications..."); const { sendNotification, isPermissionGranted, requestPermission } = await import("@tauri-apps/plugin-notification"); let hasPermission = await isPermissionGranted(); if (!hasPermission) { const permission = await requestPermission(); hasPermission = permission === "granted"; } if (hasPermission) { await sendNotification({ title, body }); } else { throw new Error("Notification permission denied"); } }, // Method 5: Try notify-send (for native Linux) async () => { console.log("Trying notify-send..."); await invoke("send_notify_send", { title, body }); }, // Skip VBScript and simple message as they create popup dialogs // Only use them in the debugger for testing ]; // Try each method until one succeeds for (const method of notificationMethods) { try { await method(); console.log("Notification sent successfully"); return; // Success, stop trying other methods } catch (error) { console.warn("Notification method failed:", error); // Continue to next method } } console.error("All notification methods failed, using terminal notification"); // Final fallback: Show in terminal sendTerminalNotification(type, body); } private getDefaultMessage(type: NotificationType): string { switch (type) { case NotificationType.SUCCESS: return "Task completed successfully!"; case NotificationType.ERROR: return "Something went wrong..."; case NotificationType.PERMISSION: return "Permission needed to continue"; case NotificationType.CONNECTION: return "Successfully connected to Claude Code"; case NotificationType.TASK_START: return "Starting task..."; case NotificationType.COST_ALERT: return "You've exceeded your cost threshold!"; default: return "Notification"; } } // Helper methods for common notifications async notifySuccess(message?: string): Promise { await this.notify(NotificationType.SUCCESS, message); } async notifyError(message?: string): Promise { await this.notify(NotificationType.ERROR, message); } async notifyPermission(message?: string): Promise { await this.notify(NotificationType.PERMISSION, message); } async notifyConnection(message?: string): Promise { await this.notify(NotificationType.CONNECTION, message); } async notifyTaskStart(message?: string): Promise { await this.notify(NotificationType.TASK_START, message); } async notifyCostAlert(message?: string): Promise { await this.notify(NotificationType.COST_ALERT, message); } } // Export singleton instance export const notificationManager = new NotificationManager();