diff --git a/src-tauri/src/sidecar/mod.rs b/src-tauri/src/sidecar/mod.rs index bc4efc6..9d97ab5 100644 --- a/src-tauri/src/sidecar/mod.rs +++ b/src-tauri/src/sidecar/mod.rs @@ -463,11 +463,63 @@ impl SidecarManager { .take() .ok_or("Failed to capture sidecar stdout")?; - let port = Self::wait_for_ready(stdout)?; + // Capture stderr in a background thread so we can log it + let stderr = child + .stderr + .take() + .ok_or("Failed to capture sidecar stderr")?; - self.child = Some(child); - self.port = Some(port); - Ok(port) + let log_dir = DIRS.get().map(|d| d.data_dir.clone()); + std::thread::spawn(move || { + use std::io::BufRead; + let reader = std::io::BufReader::new(stderr); + let mut log_file = log_dir.and_then(|d| { + std::fs::OpenOptions::new() + .create(true) + .append(true) + .open(d.join("sidecar.log")) + .ok() + }); + for line in reader.lines() { + if let Ok(line) = line { + eprintln!("[sidecar-stderr] {}", line); + if let Some(ref mut f) = log_file { + use std::io::Write; + let _ = writeln!(f, "{}", line); + } + } + } + }); + + match Self::wait_for_ready(stdout) { + Ok(port) => { + self.child = Some(child); + self.port = Some(port); + Ok(port) + } + Err(e) => { + // Kill the child if ready failed + let _ = child.kill(); + let _ = child.wait(); + + // Read the sidecar.log for context + let log_hint = DIRS + .get() + .and_then(|d| std::fs::read_to_string(d.data_dir.join("sidecar.log")).ok()) + .and_then(|s| { + let lines: Vec<&str> = s.lines().collect(); + let tail: Vec<&str> = lines.iter().rev().take(10).rev().cloned().collect(); + if tail.is_empty() { None } else { Some(tail.join("\n")) } + }) + .unwrap_or_default(); + + if log_hint.is_empty() { + Err(e) + } else { + Err(format!("{e}\n\nSidecar stderr (last 10 lines):\n{log_hint}")) + } + } + } } /// Stop the sidecar process if running.