diff --git a/src-tauri/src/core/setup.rs b/src-tauri/src/core/setup.rs index ef372ec43..6883b2a3b 100644 --- a/src-tauri/src/core/setup.rs +++ b/src-tauri/src/core/setup.rs @@ -10,9 +10,9 @@ use tauri::{App, Emitter, Listener, Manager}; use tauri_plugin_shell::process::{CommandChild, CommandEvent}; use tauri_plugin_shell::ShellExt; use tauri_plugin_store::StoreExt; -use tokio::time::{sleep, Duration}; -use tokio::{sync::Mutex}; // Using tokio::sync::Mutex - // MCP +use tokio::sync::Mutex; +use tokio::time::{sleep, Duration}; // Using tokio::sync::Mutex + // MCP use super::{ cmd::{get_jan_data_folder_path, get_jan_extensions_path}, mcp::run_mcp_commands, @@ -220,6 +220,7 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> { let app_state = app_handle_for_spawn.state::(); let cortex_restart_count_state = app_state.cortex_restart_count.clone(); + let cortex_killed_intentionally_state = app_state.cortex_killed_intentionally.clone(); let app_data_dir = get_jan_data_folder_path(app_handle_for_spawn.clone()); let sidecar_command_builder = || { @@ -274,9 +275,11 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> { let child_to_kill_arc = child_process_clone_for_kill.clone(); tauri::async_runtime::spawn(async move { let app_state = app_handle.state::(); - let mut count = app_state.cortex_restart_count.lock().await; - *count = 5; - drop(count); + // Mark as intentionally killed to prevent restart + let mut killed_intentionally = app_state.cortex_killed_intentionally.lock().await; + *killed_intentionally = true; + drop(killed_intentionally); + log::info!("Received kill-sidecar event (processing async)."); if let Some(child) = child_to_kill_arc.lock().await.take() { log::info!("Attempting to kill sidecar process..."); @@ -329,6 +332,19 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> { ); *count = 0; } + drop(count); + + // Only reset the intentionally killed flag if it wasn't set during spawn + // This prevents overriding a concurrent kill event + let mut killed_intentionally = + cortex_killed_intentionally_state.lock().await; + if !*killed_intentionally { + // Flag wasn't set during spawn, safe to reset for future cycles + *killed_intentionally = false; + } else { + log::info!("Kill intent detected during spawn, preserving kill flag"); + } + drop(killed_intentionally); } let mut process_terminated_unexpectedly = false; @@ -373,7 +389,13 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> { log::info!("Cleared child process lock after termination."); } - if process_terminated_unexpectedly { + // Check if the process was killed intentionally + let killed_intentionally = *cortex_killed_intentionally_state.lock().await; + + if killed_intentionally { + log::info!("Cortex server was killed intentionally. Not restarting."); + break; + } else if process_terminated_unexpectedly { log::warn!("Cortex server terminated unexpectedly."); let mut count = cortex_restart_count_state.lock().await; *count += 1; @@ -387,9 +409,7 @@ pub fn setup_sidecar(app: &App) -> Result<(), String> { sleep(Duration::from_millis(RESTART_DELAY_MS)).await; continue; } else { - log::info!( - "Cortex server terminated normally or was killed. Not restarting." - ); + log::info!("Cortex server terminated normally. Not restarting."); break; } } diff --git a/src-tauri/src/core/state.rs b/src-tauri/src/core/state.rs index 7ce3db443..cb6a5d3fa 100644 --- a/src-tauri/src/core/state.rs +++ b/src-tauri/src/core/state.rs @@ -11,6 +11,7 @@ pub struct AppState { pub mcp_servers: Arc>>>, pub download_manager: Arc>, pub cortex_restart_count: Arc>, + pub cortex_killed_intentionally: Arc>, } pub fn generate_app_token() -> String { rand::thread_rng() diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 635e307c3..076984106 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -91,6 +91,7 @@ pub fn run() { mcp_servers: Arc::new(Mutex::new(HashMap::new())), download_manager: Arc::new(Mutex::new(DownloadManagerState::default())), cortex_restart_count: Arc::new(Mutex::new(0)), + cortex_killed_intentionally: Arc::new(Mutex::new(false)), }) .setup(|app| { app.handle().plugin(