From 9fa1e12ce0e8f83b68a741b106898ab04b35eae5 Mon Sep 17 00:00:00 2001 From: Wes Date: Thu, 16 Jul 2026 10:37:50 -0600 Subject: [PATCH 1/2] fix(desktop): preserve relaunch through mesh shutdown Capture Tauri's restart request before the macOS mesh hard-exit path and explicitly respawn after normal shutdown. Release the single-instance socket first so the replacement process can become the primary instance. Co-authored-by: Pinky <44b8e82baa6e0e254e0208d68f335c283c94e7b78dd1fa10d5a49d3f13dd0435@sprout-oss.stage.blox.sqprod.co> Signed-off-by: Wes --- desktop/src-tauri/src/lib.rs | 31 ++++++++++++------------ desktop/src-tauri/src/shutdown.rs | 40 ++++++++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/desktop/src-tauri/src/lib.rs b/desktop/src-tauri/src/lib.rs index 99fe6f1983..6cc38daafb 100644 --- a/desktop/src-tauri/src/lib.rs +++ b/desktop/src-tauri/src/lib.rs @@ -51,10 +51,8 @@ use huddle::{ }; use managed_agents::{backfill_persona_snapshots, ensure_nest, try_regenerate_nest}; #[cfg(all(feature = "mesh-llm", target_os = "macos"))] -use shutdown::hard_exit_after_mesh_shutdown; -use shutdown::shutdown_managed_agents; -#[cfg(feature = "mesh-llm")] -use shutdown::shutdown_mesh_runtime; +use shutdown::{hard_exit_after_mesh_shutdown, relaunch_after_mesh_shutdown}; +use shutdown::{is_restart_request, shut_down_app}; use std::sync::{ atomic::{AtomicBool, Ordering}, Arc, @@ -967,19 +965,20 @@ pub fn run() { shutdown::install_signal_handler(app.handle().clone(), Arc::clone(&shutdown_done)); let run_shutdown_done = Arc::clone(&shutdown_done); + let restart_requested = Arc::new(AtomicBool::new(false)); app.run(move |app_handle, event| match event { - RunEvent::ExitRequested { .. } | RunEvent::Exit => { - app_handle - .state::() - .shutdown_started - .store(true, Ordering::SeqCst); - if !run_shutdown_done.swap(true, Ordering::SeqCst) { - prevent_sleep::release(&app_handle.state::().prevent_sleep); - if let Err(error) = shutdown_managed_agents(app_handle) { - eprintln!("buzz-desktop: failed to stop managed agents: {error}"); - } - #[cfg(feature = "mesh-llm")] - shutdown_mesh_runtime(app_handle); + RunEvent::ExitRequested { code, .. } => { + if is_restart_request(code) { + restart_requested.store(true, Ordering::SeqCst); + } + shut_down_app(app_handle, &run_shutdown_done); + } + RunEvent::Exit => { + shut_down_app(app_handle, &run_shutdown_done); + + #[cfg(all(feature = "mesh-llm", target_os = "macos"))] + if restart_requested.load(Ordering::SeqCst) { + relaunch_after_mesh_shutdown(app_handle); } // AppKit terminates through libc exit(), which runs C++ static diff --git a/desktop/src-tauri/src/shutdown.rs b/desktop/src-tauri/src/shutdown.rs index 7401b85cb8..e6fe7b91ae 100644 --- a/desktop/src-tauri/src/shutdown.rs +++ b/desktop/src-tauri/src/shutdown.rs @@ -5,7 +5,27 @@ use crate::managed_agents::{ self, kill_stale_tracked_processes, load_managed_agents, save_managed_agents, sync_managed_agent_processes, BackendKind, ManagedAgentProcess, }; -use crate::util; +use crate::{prevent_sleep, util}; + +pub(crate) fn is_restart_request(code: Option) -> bool { + code == Some(tauri::RESTART_EXIT_CODE) +} + +pub(crate) fn shut_down_app(app: &tauri::AppHandle, shutdown_done: &std::sync::atomic::AtomicBool) { + use std::sync::atomic::Ordering; + + app.state::() + .shutdown_started + .store(true, Ordering::SeqCst); + if !shutdown_done.swap(true, Ordering::SeqCst) { + prevent_sleep::release(&app.state::().prevent_sleep); + if let Err(error) = shutdown_managed_agents(app) { + eprintln!("buzz-desktop: failed to stop managed agents: {error}"); + } + #[cfg(feature = "mesh-llm")] + shutdown_mesh_runtime(app); + } +} /// Install SIGINT/SIGTERM/SIGHUP cleanup on ctrlc's dedicated handler thread. #[cfg(unix)] @@ -33,6 +53,12 @@ pub(crate) fn install_signal_handler( } } +#[cfg(all(feature = "mesh-llm", target_os = "macos"))] +pub(crate) fn relaunch_after_mesh_shutdown(app: &tauri::AppHandle) -> ! { + tauri_plugin_single_instance::destroy(app); + tauri::process::restart(&app.env()); +} + #[cfg(all(feature = "mesh-llm", target_os = "macos"))] pub(crate) fn hard_exit_after_mesh_shutdown() -> ! { // SAFETY: all Buzz-managed subprocesses and the embedded Mesh runtime have @@ -201,3 +227,15 @@ pub(crate) fn shutdown_managed_agents(app: &tauri::AppHandle) -> Result<(), Stri Ok(()) } + +#[cfg(test)] +mod tests { + use super::is_restart_request; + + #[test] + fn only_tauri_restart_exit_code_requests_a_relaunch() { + assert!(is_restart_request(Some(tauri::RESTART_EXIT_CODE))); + assert!(!is_restart_request(None)); + assert!(!is_restart_request(Some(0))); + } +} From 7588645fbb5617d3283a8d96339bcb6ebc4510ed Mon Sep 17 00:00:00 2001 From: Wes Date: Thu, 16 Jul 2026 10:50:56 -0600 Subject: [PATCH 2/2] fix(desktop): hard-exit after spawning update Mirror Tauri's macOS updated-binary lookup and spawn the replacement directly, then retain the mesh-safe hard exit instead of running C++ destructors through std::process::exit. Co-authored-by: Pinky <44b8e82baa6e0e254e0208d68f335c283c94e7b78dd1fa10d5a49d3f13dd0435@sprout-oss.stage.blox.sqprod.co> Signed-off-by: Wes --- desktop/src-tauri/Cargo.lock | 1 + desktop/src-tauri/Cargo.toml | 1 + desktop/src-tauri/src/shutdown.rs | 33 ++++++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index 692e7a609f..addf6fa656 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -1010,6 +1010,7 @@ dependencies = [ "notify-rust", "objc2-app-kit", "opus", + "plist", "png 0.18.1", "regex", "reqwest 0.13.4", diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index a4dfc7b855..eaa62bca4e 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -47,6 +47,7 @@ keyring = { version = "3.6.3", default-features = false, features = ["apple-nati security-framework = { version = "3.7.0", features = ["OSX_10_15"] } window-vibrancy = "0.6" user-idle = { version = "0.6", default-features = false } +plist = "1" [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.61", features = ["Win32_Security", "Win32_Storage_FileSystem", "Win32_System_JobObjects", "Win32_System_Registry", "Win32_System_Threading", "Win32_Foundation"] } diff --git a/desktop/src-tauri/src/shutdown.rs b/desktop/src-tauri/src/shutdown.rs index e6fe7b91ae..03fc16d1eb 100644 --- a/desktop/src-tauri/src/shutdown.rs +++ b/desktop/src-tauri/src/shutdown.rs @@ -53,10 +53,41 @@ pub(crate) fn install_signal_handler( } } +#[cfg(all(feature = "mesh-llm", target_os = "macos"))] +fn updated_macos_binary(current_binary: &std::path::Path) -> Option { + let macos_directory = current_binary.parent()?; + if macos_directory.file_name()? != "MacOS" { + return None; + } + let contents_directory = macos_directory.parent()?; + if contents_directory.file_name()? != "Contents" { + return None; + } + let info_plist = + plist::from_file::<_, plist::Dictionary>(contents_directory.join("Info.plist")).ok()?; + let binary_name = info_plist.get("CFBundleExecutable")?.as_string()?; + Some(macos_directory.join(binary_name)) +} + #[cfg(all(feature = "mesh-llm", target_os = "macos"))] pub(crate) fn relaunch_after_mesh_shutdown(app: &tauri::AppHandle) -> ! { + use std::process::Command; + tauri_plugin_single_instance::destroy(app); - tauri::process::restart(&app.env()); + let env = app.env(); + match tauri::process::current_binary(&env) { + Ok(current_binary) => { + let binary = updated_macos_binary(¤t_binary).unwrap_or(current_binary); + if let Err(error) = Command::new(binary) + .args(env.args_os.iter().skip(1)) + .spawn() + { + eprintln!("buzz-desktop: failed to relaunch app: {error}"); + } + } + Err(error) => eprintln!("buzz-desktop: failed to locate app for relaunch: {error}"), + } + hard_exit_after_mesh_shutdown(); } #[cfg(all(feature = "mesh-llm", target_os = "macos"))]