fix(desktop): preserve relaunch through mesh shutdown (#1966)

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Pinky <44b8e82baa6e0e254e0208d68f335c283c94e7b78dd1fa10d5a49d3f13dd0435@sprout-oss.stage.blox.sqprod.co>
This commit is contained in:
Wes
2026-07-16 10:57:13 -07:00
committed by GitHub
co-authored by Pinky
parent 19dc33bda6
commit a1626f96ce
4 changed files with 87 additions and 17 deletions
+1
View File
@@ -1010,6 +1010,7 @@ dependencies = [
"notify-rust",
"objc2-app-kit",
"opus",
"plist",
"png 0.18.1",
"regex",
"reqwest 0.13.4",
+1
View File
@@ -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"] }
+15 -16
View File
@@ -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::<AppState>()
.shutdown_started
.store(true, Ordering::SeqCst);
if !run_shutdown_done.swap(true, Ordering::SeqCst) {
prevent_sleep::release(&app_handle.state::<AppState>().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
+70 -1
View File
@@ -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<i32>) -> 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::<AppState>()
.shutdown_started
.store(true, Ordering::SeqCst);
if !shutdown_done.swap(true, Ordering::SeqCst) {
prevent_sleep::release(&app.state::<AppState>().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,43 @@ pub(crate) fn install_signal_handler(
}
}
#[cfg(all(feature = "mesh-llm", target_os = "macos"))]
fn updated_macos_binary(current_binary: &std::path::Path) -> Option<std::path::PathBuf> {
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);
let env = app.env();
match tauri::process::current_binary(&env) {
Ok(current_binary) => {
let binary = updated_macos_binary(&current_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"))]
pub(crate) fn hard_exit_after_mesh_shutdown() -> ! {
// SAFETY: all Buzz-managed subprocesses and the embedded Mesh runtime have
@@ -201,3 +258,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)));
}
}