diff --git a/package.json b/package.json index 3efe3e1..2bb4ed2 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,6 @@ "@tanstack/react-virtual": "^3.13.18", "@tauri-apps/api": "^2", "@tauri-apps/plugin-dialog": "^2.6.0", - "@tauri-apps/plugin-notification": "^2.3.3", "@tauri-apps/plugin-opener": "^2", "@tauri-apps/plugin-process": "^2.3.1", "@tauri-apps/plugin-updater": "^2.10.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32370b3..e8d3be0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,9 +41,6 @@ importers: '@tauri-apps/plugin-dialog': specifier: ^2.6.0 version: 2.6.0 - '@tauri-apps/plugin-notification': - specifier: ^2.3.3 - version: 2.3.3 '@tauri-apps/plugin-opener': specifier: ^2 version: 2.5.3 @@ -2533,9 +2530,6 @@ packages: '@tauri-apps/plugin-dialog@2.6.0': resolution: {integrity: sha512-q4Uq3eY87TdcYzXACiYSPhmpBA76shgmQswGkSVio4C82Sz2W4iehe9TnKYwbq7weHiL88Yw19XZm7v28+Micg==} - '@tauri-apps/plugin-notification@2.3.3': - resolution: {integrity: sha512-Zw+ZH18RJb41G4NrfHgIuofJiymusqN+q8fGUIIV7vyCH+5sSn5coqRv/MWB9qETsUs97vmU045q7OyseCV3Qg==} - '@tauri-apps/plugin-opener@2.5.3': resolution: {integrity: sha512-CCcUltXMOfUEArbf3db3kCE7Ggy1ExBEBl51Ko2ODJ6GDYHRp1nSNlQm5uNCFY5k7/ufaK5Ib3Du/Zir19IYQQ==} @@ -9080,10 +9074,6 @@ snapshots: dependencies: '@tauri-apps/api': 2.10.1 - '@tauri-apps/plugin-notification@2.3.3': - dependencies: - '@tauri-apps/api': 2.10.1 - '@tauri-apps/plugin-opener@2.5.3': dependencies: '@tauri-apps/api': 2.10.1 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index be3fcad..953e414 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -804,6 +804,7 @@ dependencies = [ "futures", "keyring", "kill_tree", + "mac-notification-sys", "notify", "portable-pty", "regex", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index b6d81c7..081d2ff 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -58,6 +58,9 @@ tauri-plugin-process = "2" tauri-plugin-notification = "2" +[target.'cfg(target_os = "macos")'.dependencies] +mac-notification-sys = "0.6" + [target.'cfg(target_os = "windows")'.dependencies] windows-sys = { version = "0.59", features = ["Win32_Storage_FileSystem"] } diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index 369ea11..e53c4bb 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -6,4 +6,5 @@ pub mod mcp; pub mod system_settings; pub mod terminal; pub mod version_control; +pub mod notification; pub mod windows; diff --git a/src-tauri/src/commands/notification.rs b/src-tauri/src/commands/notification.rs new file mode 100644 index 0000000..9155e7f --- /dev/null +++ b/src-tauri/src/commands/notification.rs @@ -0,0 +1,38 @@ +use tauri::AppHandle; + +use crate::app_error::AppCommandError; + +#[tauri::command] +pub async fn send_notification( + #[allow(unused_variables)] app: AppHandle, + title: String, + body: String, +) -> Result<(), AppCommandError> { + #[cfg(target_os = "macos")] + { + let app_id = if tauri::is_dev() { + "com.apple.Terminal" + } else { + "app.codeg" + }; + let _ = mac_notification_sys::set_application(app_id); + + let _ = mac_notification_sys::Notification::default() + .title(&title) + .message(&body) + .send(); + } + + #[cfg(not(target_os = "macos"))] + { + use tauri_plugin_notification::NotificationExt; + let _ = app + .notification() + .builder() + .title(title) + .body(body) + .show(); + } + + Ok(()) +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 6d4ca5f..f7b532d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -15,7 +15,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use acp::manager::ConnectionManager; use commands::{ acp as acp_commands, conversations, folder_commands, folders, mcp as mcp_commands, - system_settings, terminal as terminal_commands, version_control, windows, + notification, system_settings, terminal as terminal_commands, version_control, windows, }; use tauri::Manager; use terminal::manager::TerminalManager; @@ -319,6 +319,7 @@ pub fn run() { mcp_commands::mcp_upsert_local_server, mcp_commands::mcp_set_server_apps, mcp_commands::mcp_remove_server, + notification::send_notification, ]) .build(tauri::generate_context!()) .expect("error while building tauri application") diff --git a/src/contexts/acp-connections-context.tsx b/src/contexts/acp-connections-context.tsx index 8be3606..99319e6 100644 --- a/src/contexts/acp-connections-context.tsx +++ b/src/contexts/acp-connections-context.tsx @@ -44,6 +44,7 @@ import { } from "@/lib/constants" import { notifyTurnComplete } from "@/lib/notification" import { useAlertContext, type AlertAction } from "@/contexts/alert-context" +import { useFolderContext } from "@/contexts/folder-context" // ── Shared types (re-exported for consumers) ── @@ -1125,6 +1126,11 @@ function isAlertedError(error: unknown): error is AlertedError { export function AcpConnectionsProvider({ children }: { children: ReactNode }) { const t = useTranslations("Folder.chat.acpConnections") const { pushAlert } = useAlertContext() + const { folder } = useFolderContext() + const folderNameRef = useRef(folder?.name) + useEffect(() => { + folderNameRef.current = folder?.name + }, [folder?.name]) const pushAlertRef = useRef(pushAlert) useEffect(() => { pushAlertRef.current = pushAlert @@ -1551,8 +1557,10 @@ export function AcpConnectionsProvider({ children }: { children: ReactNode }) { const nc = storeRef.current.connections.get(contextKey) if (nc) { const agentLabel = AGENT_LABELS[nc.agentType] + const fn = folderNameRef.current + const title = fn ? `${fn} - Codeg` : "Codeg" notifyTurnComplete( - "Codeg", + title, t("notificationTurnComplete", { agent: agentLabel }), ).catch(() => {}) } diff --git a/src/lib/notification.ts b/src/lib/notification.ts new file mode 100644 index 0000000..f7f2cd3 --- /dev/null +++ b/src/lib/notification.ts @@ -0,0 +1,9 @@ +import { invoke } from "@tauri-apps/api/core" + +export async function notifyTurnComplete( + title: string, + body: string, +): Promise { + if (!document.hidden) return + await invoke("send_notification", { title, body }) +}