| use std::process::Command; |
| use std::thread; |
| use std::time::Duration; |
| use sysinfo::System; |
|
|
| #[cfg(target_os = "windows")] |
| use std::os::windows::process::CommandExt; |
|
|
| |
| fn get_current_exe_path() -> Option<std::path::PathBuf> { |
| std::env::current_exe() |
| .ok() |
| .and_then(|p| p.canonicalize().ok()) |
| } |
|
|
| |
| pub fn is_antigravity_running() -> bool { |
| let mut system = System::new(); |
| system.refresh_processes(sysinfo::ProcessesToUpdate::All); |
|
|
| let current_exe = get_current_exe_path(); |
| let current_pid = std::process::id(); |
|
|
| |
| let manual_path = crate::modules::config::load_app_config() |
| .ok() |
| .and_then(|c| c.antigravity_executable) |
| .and_then(|p| std::path::PathBuf::from(p).canonicalize().ok()); |
|
|
| for (pid, process) in system.processes() { |
| let pid_u32 = pid.as_u32(); |
| if pid_u32 == current_pid { |
| continue; |
| } |
|
|
| let name = process.name().to_string_lossy().to_lowercase(); |
| let exe_path = process |
| .exe() |
| .and_then(|p| p.to_str()) |
| .unwrap_or("") |
| .to_lowercase(); |
|
|
| |
| if let (Some(ref my_path), Some(p_exe)) = (¤t_exe, process.exe()) { |
| if let Ok(p_path) = p_exe.canonicalize() { |
| if my_path == &p_path { |
| continue; |
| } |
| } |
| } |
|
|
| |
| if let (Some(ref m_path), Some(p_exe)) = (&manual_path, process.exe()) { |
| if let Ok(p_path) = p_exe.canonicalize() { |
| |
| #[cfg(target_os = "macos")] |
| { |
| let m_path_str = m_path.to_string_lossy(); |
| let p_path_str = p_path.to_string_lossy(); |
| if let (Some(m_idx), Some(p_idx)) = |
| (m_path_str.find(".app"), p_path_str.find(".app")) |
| { |
| if m_path_str[..m_idx + 4] == p_path_str[..p_idx + 4] { |
| |
| let args = process.cmd(); |
| let is_helper_by_args = args |
| .iter() |
| .any(|arg| arg.to_string_lossy().contains("--type=")); |
| let is_helper_by_name = name.contains("helper") |
| || name.contains("plugin") |
| || name.contains("renderer") |
| || name.contains("gpu") |
| || name.contains("crashpad") |
| || name.contains("utility") |
| || name.contains("audio") |
| || name.contains("sandbox"); |
| if !is_helper_by_args && !is_helper_by_name { |
| return true; |
| } |
| } |
| } |
| } |
|
|
| #[cfg(not(target_os = "macos"))] |
| if m_path == &p_path { |
| return true; |
| } |
| } |
| } |
|
|
| |
| |
| let args = process.cmd(); |
| let args_str = args |
| .iter() |
| .map(|arg| arg.to_string_lossy().to_lowercase()) |
| .collect::<Vec<String>>() |
| .join(" "); |
|
|
| let is_helper = args_str.contains("--type=") |
| || name.contains("helper") |
| || name.contains("plugin") |
| || name.contains("renderer") |
| || name.contains("gpu") |
| || name.contains("crashpad") |
| || name.contains("utility") |
| || name.contains("audio") |
| || name.contains("sandbox") |
| || exe_path.contains("crashpad"); |
|
|
| #[cfg(target_os = "macos")] |
| { |
| if exe_path.contains("antigravity.app") && !is_helper { |
| return true; |
| } |
| } |
|
|
| #[cfg(target_os = "windows")] |
| { |
| if name == "antigravity.exe" && !is_helper { |
| return true; |
| } |
| } |
|
|
| #[cfg(target_os = "linux")] |
| { |
| if (name.contains("antigravity") || exe_path.contains("/antigravity")) |
| && !name.contains("tools") |
| && !is_helper |
| { |
| return true; |
| } |
| } |
| } |
|
|
| false |
| } |
|
|
| #[cfg(target_os = "linux")] |
| |
| fn get_self_family_pids(system: &sysinfo::System) -> std::collections::HashSet<u32> { |
| let current_pid = std::process::id(); |
| let mut family_pids = std::collections::HashSet::new(); |
| family_pids.insert(current_pid); |
|
|
| |
| let mut next_pid = current_pid; |
| |
| for _ in 0..10 { |
| let pid_val = sysinfo::Pid::from_u32(next_pid); |
| if let Some(process) = system.process(pid_val) { |
| if let Some(parent) = process.parent() { |
| let parent_id = parent.as_u32(); |
| |
| if !family_pids.insert(parent_id) { |
| break; |
| } |
| next_pid = parent_id; |
| } else { |
| break; |
| } |
| } else { |
| break; |
| } |
| } |
|
|
| |
| |
| let mut adj: std::collections::HashMap<u32, Vec<u32>> = std::collections::HashMap::new(); |
| for (pid, process) in system.processes() { |
| if let Some(parent) = process.parent() { |
| adj.entry(parent.as_u32()).or_default().push(pid.as_u32()); |
| } |
| } |
|
|
| |
| let mut queue = std::collections::VecDeque::new(); |
| queue.push_back(current_pid); |
|
|
| while let Some(pid) = queue.pop_front() { |
| if let Some(children) = adj.get(&pid) { |
| for &child in children { |
| if family_pids.insert(child) { |
| queue.push_back(child); |
| } |
| } |
| } |
| } |
|
|
| family_pids |
| } |
|
|
| |
| fn get_antigravity_pids() -> Vec<u32> { |
| let mut system = System::new(); |
| system.refresh_processes(sysinfo::ProcessesToUpdate::All); |
|
|
| |
| #[cfg(target_os = "linux")] |
| let family_pids = get_self_family_pids(&system); |
|
|
| let mut pids = Vec::new(); |
| let current_pid = std::process::id(); |
| let current_exe = get_current_exe_path(); |
|
|
| |
| let manual_path = crate::modules::config::load_app_config() |
| .ok() |
| .and_then(|c| c.antigravity_executable) |
| .and_then(|p| std::path::PathBuf::from(p).canonicalize().ok()); |
|
|
| for (pid, process) in system.processes() { |
| let pid_u32 = pid.as_u32(); |
|
|
| |
| if pid_u32 == current_pid { |
| continue; |
| } |
|
|
| |
| if let (Some(ref my_path), Some(p_exe)) = (¤t_exe, process.exe()) { |
| if let Ok(p_path) = p_exe.canonicalize() { |
| if my_path == &p_path { |
| continue; |
| } |
| } |
| } |
|
|
| let _name = process.name().to_string_lossy().to_lowercase(); |
|
|
| #[cfg(target_os = "linux")] |
| { |
| |
| if family_pids.contains(&pid_u32) { |
| continue; |
| } |
| |
| if _name.contains("tools") { |
| continue; |
| } |
| } |
|
|
| #[cfg(not(target_os = "linux"))] |
| { |
| |
| if pid_u32 == current_pid { |
| continue; |
| } |
| } |
|
|
| |
| if let (Some(ref m_path), Some(p_exe)) = (&manual_path, process.exe()) { |
| if let Ok(p_path) = p_exe.canonicalize() { |
| #[cfg(target_os = "macos")] |
| { |
| let m_path_str = m_path.to_string_lossy(); |
| let p_path_str = p_path.to_string_lossy(); |
| if let (Some(m_idx), Some(p_idx)) = |
| (m_path_str.find(".app"), p_path_str.find(".app")) |
| { |
| if m_path_str[..m_idx + 4] == p_path_str[..p_idx + 4] { |
| let args = process.cmd(); |
| let is_helper_by_args = args |
| .iter() |
| .any(|arg| arg.to_string_lossy().contains("--type=")); |
| let is_helper_by_name = _name.contains("helper") |
| || _name.contains("plugin") |
| || _name.contains("renderer") |
| || _name.contains("gpu") |
| || _name.contains("crashpad") |
| || _name.contains("utility") |
| || _name.contains("audio") |
| || _name.contains("sandbox"); |
| if !is_helper_by_args && !is_helper_by_name { |
| pids.push(pid_u32); |
| continue; |
| } |
| } |
| } |
| } |
|
|
| #[cfg(not(target_os = "macos"))] |
| if m_path == &p_path { |
| pids.push(pid_u32); |
| continue; |
| } |
| } |
| } |
|
|
| |
| let exe_path = process |
| .exe() |
| .and_then(|p| p.to_str()) |
| .unwrap_or("") |
| .to_lowercase(); |
|
|
| |
| let args = process.cmd(); |
| let args_str = args |
| .iter() |
| .map(|arg| arg.to_string_lossy().to_lowercase()) |
| .collect::<Vec<String>>() |
| .join(" "); |
|
|
| let is_helper = args_str.contains("--type=") |
| || _name.contains("helper") |
| || _name.contains("plugin") |
| || _name.contains("renderer") |
| || _name.contains("gpu") |
| || _name.contains("crashpad") |
| || _name.contains("utility") |
| || _name.contains("audio") |
| || _name.contains("sandbox") |
| || exe_path.contains("crashpad"); |
|
|
| #[cfg(target_os = "macos")] |
| { |
| |
| if exe_path.contains("antigravity.app") && !is_helper { |
| pids.push(pid_u32); |
| } |
| } |
|
|
| #[cfg(target_os = "windows")] |
| { |
| let name = process.name().to_string_lossy().to_lowercase(); |
| if name == "antigravity.exe" && !is_helper { |
| pids.push(pid_u32); |
| } |
| } |
|
|
| #[cfg(target_os = "linux")] |
| { |
| let name = process.name().to_string_lossy().to_lowercase(); |
| if (name == "antigravity" || exe_path.contains("/antigravity")) |
| && !name.contains("tools") |
| && !is_helper |
| { |
| pids.push(pid_u32); |
| } |
| } |
| } |
|
|
| if !pids.is_empty() { |
| crate::modules::logger::log_info(&format!( |
| "Found {} Antigravity processes: {:?}", |
| pids.len(), |
| pids |
| )); |
| } |
|
|
| pids |
| } |
|
|
| |
| pub fn close_antigravity(#[allow(unused_variables)] timeout_secs: u64) -> Result<(), String> { |
| crate::modules::logger::log_info("Closing Antigravity..."); |
|
|
| #[cfg(target_os = "windows")] |
| { |
| |
| let pids = get_antigravity_pids(); |
| if !pids.is_empty() { |
| crate::modules::logger::log_info(&format!( |
| "Precisely closing {} identified processes on Windows...", |
| pids.len() |
| )); |
| for pid in pids { |
| let _ = Command::new("taskkill") |
| .args(["/F", "/PID", &pid.to_string()]) |
| .creation_flags(0x08000000) |
| .output(); |
| } |
| |
| thread::sleep(Duration::from_millis(200)); |
| } |
| } |
|
|
| #[cfg(target_os = "macos")] |
| { |
| |
| |
|
|
| let pids = get_antigravity_pids(); |
| if !pids.is_empty() { |
| |
| |
| let mut system = System::new(); |
| system.refresh_processes(sysinfo::ProcessesToUpdate::All); |
|
|
| let mut main_pid = None; |
|
|
| |
| let manual_path = crate::modules::config::load_app_config() |
| .ok() |
| .and_then(|c| c.antigravity_executable) |
| .and_then(|p| std::path::PathBuf::from(p).canonicalize().ok()); |
|
|
| crate::modules::logger::log_info("Analyzing process list to identify main process:"); |
| for pid_u32 in &pids { |
| let pid = sysinfo::Pid::from_u32(*pid_u32); |
| if let Some(process) = system.process(pid) { |
| let name = process.name().to_string_lossy(); |
| let args = process.cmd(); |
| let args_str = args |
| .iter() |
| .map(|arg| arg.to_string_lossy().into_owned()) |
| .collect::<Vec<String>>() |
| .join(" "); |
|
|
| crate::modules::logger::log_info(&format!( |
| " - PID: {} | Name: {} | Args: {}", |
| pid_u32, name, args_str |
| )); |
|
|
| |
| if let (Some(ref m_path), Some(p_exe)) = (&manual_path, process.exe()) { |
| if let Ok(p_path) = p_exe.canonicalize() { |
| let m_path_str = m_path.to_string_lossy(); |
| let p_path_str = p_path.to_string_lossy(); |
| if let (Some(m_idx), Some(p_idx)) = |
| (m_path_str.find(".app"), p_path_str.find(".app")) |
| { |
| if m_path_str[..m_idx + 4] == p_path_str[..p_idx + 4] { |
| |
| let is_helper_by_args = args_str.contains("--type="); |
| let is_helper_by_name = name.to_lowercase().contains("helper") |
| || name.to_lowercase().contains("plugin") |
| || name.to_lowercase().contains("renderer") |
| || name.to_lowercase().contains("gpu") |
| || name.to_lowercase().contains("crashpad") |
| || name.to_lowercase().contains("utility") |
| || name.to_lowercase().contains("audio") |
| || name.to_lowercase().contains("sandbox") |
| || name.to_lowercase().contains("language_server"); |
|
|
| if !is_helper_by_args && !is_helper_by_name { |
| main_pid = Some(pid_u32); |
| crate::modules::logger::log_info(&format!( |
| " => Identified as main process (manual path match)" |
| )); |
| break; |
| } |
| } |
| } |
| } |
| } |
|
|
| |
| let is_helper_by_name = name.to_lowercase().contains("helper") |
| || name.to_lowercase().contains("crashpad") |
| || name.to_lowercase().contains("utility") |
| || name.to_lowercase().contains("audio") |
| || name.to_lowercase().contains("sandbox") |
| || name.to_lowercase().contains("language_server") |
| || name.to_lowercase().contains("plugin") |
| || name.to_lowercase().contains("renderer"); |
|
|
| let is_helper_by_args = args_str.contains("--type="); |
|
|
| if !is_helper_by_name && !is_helper_by_args { |
| if main_pid.is_none() { |
| main_pid = Some(pid_u32); |
| crate::modules::logger::log_info(&format!( |
| " => Identified as main process (Name/Args analysis)" |
| )); |
| } |
| } else { |
| crate::modules::logger::log_info(&format!( |
| " => Identified as helper process (Helper/Args)" |
| )); |
| } |
| } |
| } |
|
|
| |
| if let Some(pid) = main_pid { |
| crate::modules::logger::log_info(&format!( |
| "Sending SIGTERM to main process PID: {}", |
| pid |
| )); |
| let output = Command::new("kill") |
| .args(["-15", &pid.to_string()]) |
| .output(); |
|
|
| if let Ok(result) = output { |
| if !result.status.success() { |
| let error = String::from_utf8_lossy(&result.stderr); |
| crate::modules::logger::log_warn(&format!( |
| "Main process SIGTERM failed: {}", |
| error |
| )); |
| } |
| } |
| } else { |
| crate::modules::logger::log_warn( |
| "No clear main process identified, attempting SIGTERM for all processes (may cause popups)", |
| ); |
| for pid in &pids { |
| let _ = Command::new("kill") |
| .args(["-15", &pid.to_string()]) |
| .output(); |
| } |
| } |
|
|
| |
| let graceful_timeout = (timeout_secs * 7) / 10; |
| let start = std::time::Instant::now(); |
| while start.elapsed() < Duration::from_secs(graceful_timeout) { |
| if !is_antigravity_running() { |
| crate::modules::logger::log_info("All Antigravity processes gracefully closed"); |
| return Ok(()); |
| } |
| thread::sleep(Duration::from_millis(500)); |
| } |
|
|
| |
| if is_antigravity_running() { |
| let remaining_pids = get_antigravity_pids(); |
| if !remaining_pids.is_empty() { |
| crate::modules::logger::log_warn(&format!( |
| "Graceful exit timeout, force killing {} remaining processes (SIGKILL)", |
| remaining_pids.len() |
| )); |
| for pid in &remaining_pids { |
| let output = Command::new("kill").args(["-9", &pid.to_string()]).output(); |
|
|
| if let Ok(result) = output { |
| if !result.status.success() { |
| let error = String::from_utf8_lossy(&result.stderr); |
| if !error.contains("No such process") { |
| |
| crate::modules::logger::log_error(&format!( |
| "SIGKILL process {} failed: {}", |
| pid, error |
| )); |
| } |
| } |
| } |
| } |
| thread::sleep(Duration::from_secs(1)); |
| } |
|
|
| |
| if !is_antigravity_running() { |
| crate::modules::logger::log_info("All processes exited after forced cleanup"); |
| return Ok(()); |
| } |
| } else { |
| crate::modules::logger::log_info("All processes exited after SIGTERM"); |
| return Ok(()); |
| } |
| } else { |
| |
| crate::modules::logger::log_info("Antigravity not running, no need to close"); |
| return Ok(()); |
| } |
| } |
|
|
| #[cfg(target_os = "linux")] |
| { |
| |
| let pids = get_antigravity_pids(); |
| if !pids.is_empty() { |
| let mut system = System::new(); |
| system.refresh_processes(sysinfo::ProcessesToUpdate::All); |
|
|
| let mut main_pid = None; |
|
|
| |
| let manual_path = crate::modules::config::load_app_config() |
| .ok() |
| .and_then(|c| c.antigravity_executable) |
| .and_then(|p| std::path::PathBuf::from(p).canonicalize().ok()); |
|
|
| crate::modules::logger::log_info("Analyzing Linux process list to identify main process:"); |
| for pid_u32 in &pids { |
| let pid = sysinfo::Pid::from_u32(*pid_u32); |
| if let Some(process) = system.process(pid) { |
| let name = process.name().to_string_lossy().to_lowercase(); |
| let args = process.cmd(); |
| let args_str = args |
| .iter() |
| .map(|arg| arg.to_string_lossy().into_owned()) |
| .collect::<Vec<String>>() |
| .join(" "); |
|
|
| crate::modules::logger::log_info(&format!( |
| " - PID: {} | Name: {} | Args: {}", |
| pid_u32, name, args_str |
| )); |
|
|
| |
| if let (Some(ref m_path), Some(p_exe)) = (&manual_path, process.exe()) { |
| if let Ok(p_path) = p_exe.canonicalize() { |
| if &p_path == m_path { |
| |
| let is_helper_by_args = args_str.contains("--type="); |
| let is_helper_by_name = name.contains("helper") |
| || name.contains("renderer") |
| || name.contains("gpu") |
| || name.contains("crashpad") |
| || name.contains("utility") |
| || name.contains("audio") |
| || name.contains("sandbox"); |
| if !is_helper_by_args && !is_helper_by_name { |
| main_pid = Some(pid_u32); |
| crate::modules::logger::log_info(&format!( |
| " => Identified as main process (manual path match)" |
| )); |
| break; |
| } |
| } |
| } |
| } |
|
|
| |
| let is_helper_by_args = args_str.contains("--type="); |
| let is_helper_by_name = name.contains("helper") |
| || name.contains("renderer") |
| || name.contains("gpu") |
| || name.contains("crashpad") |
| || name.contains("utility") |
| || name.contains("audio") |
| || name.contains("sandbox") |
| || name.contains("plugin") |
| || name.contains("language_server"); |
|
|
| if !is_helper_by_args && !is_helper_by_name { |
| if main_pid.is_none() { |
| main_pid = Some(pid_u32); |
| crate::modules::logger::log_info(&format!( |
| " => Identified as main process (Feature analysis)" |
| )); |
| } |
| } else { |
| crate::modules::logger::log_info(&format!( |
| " => Identified as helper process (Helper/Args)" |
| )); |
| } |
| } |
| } |
|
|
| |
| if let Some(pid) = main_pid { |
| crate::modules::logger::log_info(&format!("Attempting to gracefully close main process {} (SIGTERM)", pid)); |
| let _ = Command::new("kill") |
| .args(["-15", &pid.to_string()]) |
| .output(); |
| } else { |
| crate::modules::logger::log_warn( |
| "No clear Linux main process identified, sending SIGTERM to all associated processes", |
| ); |
| for pid in &pids { |
| let _ = Command::new("kill") |
| .args(["-15", &pid.to_string()]) |
| .output(); |
| } |
| } |
|
|
| |
| let graceful_timeout = (timeout_secs * 7) / 10; |
| let start = std::time::Instant::now(); |
| while start.elapsed() < Duration::from_secs(graceful_timeout) { |
| if !is_antigravity_running() { |
| crate::modules::logger::log_info("Antigravity gracefully closed"); |
| return Ok(()); |
| } |
| thread::sleep(Duration::from_millis(500)); |
| } |
|
|
| |
| if is_antigravity_running() { |
| let remaining_pids = get_antigravity_pids(); |
| if !remaining_pids.is_empty() { |
| crate::modules::logger::log_warn(&format!( |
| "Graceful exit timeout, force killing {} remaining processes (SIGKILL)", |
| remaining_pids.len() |
| )); |
| for pid in &remaining_pids { |
| let _ = Command::new("kill").args(["-9", &pid.to_string()]).output(); |
| } |
| thread::sleep(Duration::from_secs(1)); |
| } |
| } |
| } else { |
| |
| crate::modules::logger::log_info( |
| "No Antigravity processes found to close (possibly filtered or not running)", |
| ); |
| } |
| } |
|
|
| |
| if is_antigravity_running() { |
| return Err("Unable to close Antigravity process, please close manually and retry".to_string()); |
| } |
|
|
| crate::modules::logger::log_info("Antigravity closed successfully"); |
| Ok(()) |
| } |
|
|
| |
| #[allow(unused_mut)] |
| pub fn start_antigravity() -> Result<(), String> { |
| crate::modules::logger::log_info("Starting Antigravity..."); |
|
|
| |
| let config = crate::modules::config::load_app_config().ok(); |
| let manual_path = config |
| .as_ref() |
| .and_then(|c| c.antigravity_executable.clone()); |
| let args = config.and_then(|c| c.antigravity_args.clone()); |
|
|
| if let Some(mut path_str) = manual_path { |
| let mut path = std::path::PathBuf::from(&path_str); |
|
|
| #[cfg(target_os = "macos")] |
| { |
| |
| if let Some(app_idx) = path_str.find(".app") { |
| let corrected_app = &path_str[..app_idx + 4]; |
| if corrected_app != path_str { |
| crate::modules::logger::log_info(&format!( |
| "Detected macOS path inside .app bundle, auto-correcting to: {}", |
| corrected_app |
| )); |
| path_str = corrected_app.to_string(); |
| path = std::path::PathBuf::from(&path_str); |
| } |
| } |
| } |
|
|
| if path.exists() { |
| crate::modules::logger::log_info(&format!("Starting with manual configuration path: {}", path_str)); |
|
|
| #[cfg(target_os = "macos")] |
| { |
| |
| if path_str.ends_with(".app") || path.is_dir() { |
| let mut cmd = Command::new("open"); |
| cmd.arg("-a").arg(&path_str); |
|
|
| |
| if let Some(ref args) = args { |
| for arg in args { |
| cmd.arg(arg); |
| } |
| } |
|
|
| cmd.spawn().map_err(|e| format!("Startup failed (open): {}", e))?; |
| } else { |
| let mut cmd = Command::new(&path_str); |
|
|
| |
| if let Some(ref args) = args { |
| for arg in args { |
| cmd.arg(arg); |
| } |
| } |
|
|
| cmd.spawn() |
| .map_err(|e| format!("Startup failed (direct): {}", e))?; |
| } |
| } |
|
|
| #[cfg(not(target_os = "macos"))] |
| { |
| let mut cmd = Command::new(&path_str); |
|
|
| |
| if let Some(ref args) = args { |
| for arg in args { |
| cmd.arg(arg); |
| } |
| } |
|
|
| cmd.spawn().map_err(|e| format!("Startup failed: {}", e))?; |
| } |
|
|
| crate::modules::logger::log_info(&format!( |
| "Antigravity startup command sent (manual path: {}, args: {:?})", |
| path_str, args |
| )); |
| return Ok(()); |
| } else { |
| crate::modules::logger::log_warn(&format!( |
| "Manual configuration path does not exist: {}, falling back to auto-detection", |
| path_str |
| )); |
| } |
| } |
|
|
| #[cfg(target_os = "macos")] |
| { |
| |
| let mut cmd = Command::new("open"); |
| cmd.args(["-a", "Antigravity"]); |
|
|
| |
| if let Some(ref args) = args { |
| for arg in args { |
| cmd.arg(arg); |
| } |
| } |
|
|
| let output = cmd |
| .output() |
| .map_err(|e| format!("Unable to execute open command: {}", e))?; |
|
|
| if !output.status.success() { |
| let error = String::from_utf8_lossy(&output.stderr); |
| return Err(format!( |
| "Startup failed (open exited with {}): {}", |
| output.status, error |
| )); |
| } |
| } |
|
|
| #[cfg(target_os = "windows")] |
| { |
| let has_args = args.as_ref().map_or(false, |a| !a.is_empty()); |
| |
| if has_args { |
| if let Some(detected_path) = get_antigravity_executable_path() { |
| let path_str = detected_path.to_string_lossy().to_string(); |
| crate::modules::logger::log_info(&format!( |
| "Starting with auto-detected path (has args): {}", |
| path_str |
| )); |
| |
| use crate::utils::command::CommandExtWrapper; |
| let mut cmd = Command::new(&path_str); |
| cmd.creation_flags_windows(); |
| if let Some(ref args) = args { |
| for arg in args { |
| cmd.arg(arg); |
| } |
| } |
| |
| cmd.spawn().map_err(|e| format!("Startup failed: {}", e))?; |
| } else { |
| return Err("Startup arguments configured but cannot find Antigravity executable path. Please set the executable path manually in Settings.".to_string()); |
| } |
| } else { |
| use crate::utils::command::CommandExtWrapper; |
| let mut cmd = Command::new("cmd"); |
| cmd.creation_flags_windows(); |
| cmd.args(["/C", "start", "antigravity://"]); |
| |
| let result = cmd.spawn(); |
| if result.is_err() { |
| return Err("Startup failed, please open Antigravity manually".to_string()); |
| } |
| } |
| } |
|
|
| #[cfg(target_os = "linux")] |
| { |
| let mut cmd = Command::new("antigravity"); |
|
|
| |
| if let Some(ref args) = args { |
| for arg in args { |
| cmd.arg(arg); |
| } |
| } |
|
|
| cmd.spawn().map_err(|e| format!("Startup failed: {}", e))?; |
| } |
|
|
| crate::modules::logger::log_info(&format!( |
| "Antigravity startup command sent (default detection, args: {:?})", |
| args |
| )); |
| Ok(()) |
| } |
|
|
| |
| |
| |
| fn get_process_info() -> (Option<std::path::PathBuf>, Option<Vec<String>>) { |
| let mut system = System::new_all(); |
| system.refresh_all(); |
|
|
| let current_exe = get_current_exe_path(); |
| let current_pid = std::process::id(); |
|
|
| for (pid, process) in system.processes() { |
| let pid_u32 = pid.as_u32(); |
| if pid_u32 == current_pid { |
| continue; |
| } |
|
|
| |
| if let (Some(ref my_path), Some(p_exe)) = (¤t_exe, process.exe()) { |
| if let Ok(p_path) = p_exe.canonicalize() { |
| if my_path == &p_path { |
| continue; |
| } |
| } |
| } |
|
|
| let name = process.name().to_string_lossy().to_lowercase(); |
|
|
| |
| if let Some(exe) = process.exe() { |
| let mut args = process.cmd().iter(); |
| let exe_path = args |
| .next() |
| .map_or(exe.to_string_lossy(), |arg| arg.to_string_lossy()) |
| .to_lowercase(); |
|
|
| |
| let args = args |
| .map(|arg| arg.to_string_lossy().to_lowercase()) |
| .collect::<Vec<String>>(); |
|
|
| let args_str = args.join(" "); |
|
|
| |
| let is_helper = args_str.contains("--type=") |
| || args_str.contains("node-ipc") |
| || args_str.contains("nodeipc") |
| || args_str.contains("max-old-space-size") |
| || args_str.contains("node_modules") |
| || name.contains("helper") |
| || name.contains("plugin") |
| || name.contains("renderer") |
| || name.contains("gpu") |
| || name.contains("crashpad") |
| || name.contains("utility") |
| || name.contains("audio") |
| || name.contains("sandbox") |
| || exe_path.contains("crashpad"); |
|
|
| let path = Some(exe.to_path_buf()); |
| let args = Some(args); |
| #[cfg(target_os = "macos")] |
| { |
| |
| if exe_path.contains("antigravity.app") |
| && !is_helper |
| && !exe_path.contains("frameworks") |
| { |
| |
| if let Some(app_idx) = exe_path.find(".app") { |
| let app_path_str = &exe.to_string_lossy()[..app_idx + 4]; |
| let path = Some(std::path::PathBuf::from(app_path_str)); |
| return (path, args); |
| } |
| return (path, args); |
| } |
| } |
|
|
| #[cfg(target_os = "windows")] |
| { |
| |
| if name == "antigravity.exe" && !is_helper { |
| return (path, args); |
| } |
| } |
|
|
| #[cfg(target_os = "linux")] |
| { |
| |
| if (name == "antigravity" || exe_path.contains("/antigravity")) |
| && !name.contains("tools") |
| && !is_helper |
| { |
| return (path, args); |
| } |
| } |
| } |
| } |
| (None, None) |
| } |
|
|
| |
| |
| |
| pub fn get_path_from_running_process() -> Option<std::path::PathBuf> { |
| let (path, _) = get_process_info(); |
| path |
| } |
|
|
| |
| pub fn get_args_from_running_process() -> Option<Vec<String>> { |
| let (_, args) = get_process_info(); |
| args |
| } |
|
|
| |
| pub fn get_user_data_dir_from_process() -> Option<std::path::PathBuf> { |
| |
| if let Ok(config) = crate::modules::config::load_app_config() { |
| if let Some(args) = config.antigravity_args { |
| |
| for i in 0..args.len() { |
| if args[i] == "--user-data-dir" && i + 1 < args.len() { |
| |
| let path = std::path::PathBuf::from(&args[i + 1]); |
| if path.exists() { |
| return Some(path); |
| } |
| } else if args[i].starts_with("--user-data-dir=") { |
| |
| let parts: Vec<&str> = args[i].splitn(2, '=').collect(); |
| if parts.len() == 2 { |
| let path_str = parts[1]; |
| let path = std::path::PathBuf::from(path_str); |
| if path.exists() { |
| return Some(path); |
| } |
| } |
| } |
| } |
| } |
| } |
|
|
| |
| if let Some(args) = get_args_from_running_process() { |
| for i in 0..args.len() { |
| if args[i] == "--user-data-dir" && i + 1 < args.len() { |
| |
| let path = std::path::PathBuf::from(&args[i + 1]); |
| if path.exists() { |
| return Some(path); |
| } |
| } else if args[i].starts_with("--user-data-dir=") { |
| |
| let parts: Vec<&str> = args[i].splitn(2, '=').collect(); |
| if parts.len() == 2 { |
| let path_str = parts[1]; |
| let path = std::path::PathBuf::from(path_str); |
| if path.exists() { |
| return Some(path); |
| } |
| } |
| } |
| } |
| } |
|
|
| None |
| } |
|
|
| |
| |
| |
| |
| |
| |
| pub fn get_antigravity_executable_path() -> Option<std::path::PathBuf> { |
| |
| if let Some(path) = get_path_from_running_process() { |
| return Some(path); |
| } |
|
|
| |
| check_standard_locations() |
| } |
|
|
| |
| fn check_standard_locations() -> Option<std::path::PathBuf> { |
| #[cfg(target_os = "macos")] |
| { |
| let path = std::path::PathBuf::from("/Applications/Antigravity.app"); |
| if path.exists() { |
| return Some(path); |
| } |
| } |
|
|
| #[cfg(target_os = "windows")] |
| { |
| use std::env; |
|
|
| |
| let local_appdata = env::var("LOCALAPPDATA").ok(); |
| let program_files = |
| env::var("ProgramFiles").unwrap_or_else(|_| "C:\\Program Files".to_string()); |
| let program_files_x86 = |
| env::var("ProgramFiles(x86)").unwrap_or_else(|_| "C:\\Program Files (x86)".to_string()); |
|
|
| let mut possible_paths = Vec::new(); |
|
|
| |
| if let Some(local) = local_appdata { |
| possible_paths.push( |
| std::path::PathBuf::from(&local) |
| .join("Programs") |
| .join("Antigravity") |
| .join("Antigravity.exe"), |
| ); |
| } |
|
|
| |
| possible_paths.push( |
| std::path::PathBuf::from(&program_files) |
| .join("Antigravity") |
| .join("Antigravity.exe"), |
| ); |
|
|
| |
| possible_paths.push( |
| std::path::PathBuf::from(&program_files_x86) |
| .join("Antigravity") |
| .join("Antigravity.exe"), |
| ); |
|
|
| |
| for path in possible_paths { |
| if path.exists() { |
| return Some(path); |
| } |
| } |
| } |
|
|
| #[cfg(target_os = "linux")] |
| { |
| let possible_paths = vec![ |
| std::path::PathBuf::from("/usr/bin/antigravity"), |
| std::path::PathBuf::from("/opt/Antigravity/antigravity"), |
| std::path::PathBuf::from("/usr/share/antigravity/antigravity"), |
| ]; |
|
|
| |
| if let Some(home) = dirs::home_dir() { |
| let user_local = home.join(".local/bin/antigravity"); |
| if user_local.exists() { |
| return Some(user_local); |
| } |
| } |
|
|
| for path in possible_paths { |
| if path.exists() { |
| return Some(path); |
| } |
| } |
| } |
|
|
| None |
| } |
|
|