fix: correct WSL detection and binary lookup for GUI context

- detect_wsl() now short-circuits on Windows builds (cfg! compile-time
  check), preventing inherited WSL_DISTRO_NAME from routing a native
  Windows .exe through the Linux code path
- find_claude_binary() no longer early-exits when HOME is unset; falls
  back to bash -lc "which claude" so GUI apps (which don't inherit
  shell PATH) can still locate the binary via the login shell
This commit is contained in:
2026-02-23 20:15:27 -08:00
committed by Naomi Carrigan
parent b8aefef071
commit 0abf410aa9
+26 -14
View File
@@ -39,6 +39,12 @@ const SEARCH_TOOLS: [&str; 5] = ["Read", "Glob", "Grep", "WebSearch", "WebFetch"
const CODING_TOOLS: [&str; 3] = ["Edit", "Write", "NotebookEdit"]; const CODING_TOOLS: [&str; 3] = ["Edit", "Write", "NotebookEdit"];
fn detect_wsl() -> bool { fn detect_wsl() -> bool {
// A native Windows binary is never running inside WSL, even if launched from a WSL
// terminal that has WSL_DISTRO_NAME set in its environment.
if cfg!(target_os = "windows") {
return false;
}
// Check /proc/version for WSL indicators // Check /proc/version for WSL indicators
if let Ok(version) = std::fs::read_to_string("/proc/version") { if let Ok(version) = std::fs::read_to_string("/proc/version") {
let version_lower = version.to_lowercase(); let version_lower = version.to_lowercase();
@@ -61,23 +67,29 @@ fn detect_wsl() -> bool {
} }
fn find_claude_binary() -> Option<String> { fn find_claude_binary() -> Option<String> {
// Check common installation locations for claude // Check common installation locations for claude (when HOME is available)
let home = std::env::var("HOME").ok()?; if let Ok(home) = std::env::var("HOME") {
let paths_to_check = [ let paths_to_check = [
format!("{}/.local/bin/claude", home), format!("{}/.local/bin/claude", home),
format!("{}/.claude/local/claude", home), format!("{}/.claude/local/claude", home),
"/usr/local/bin/claude".to_string(), ];
"/usr/bin/claude".to_string(), for path in &paths_to_check {
]; if std::path::Path::new(path).exists() {
return Some(path.clone());
for path in &paths_to_check { }
if std::path::Path::new(path).exists() {
return Some(path.clone());
} }
} }
// Fall back to checking PATH via which // Check system-wide locations
if let Ok(output) = Command::new("which").arg("claude").output() { for path in &["/usr/local/bin/claude", "/usr/bin/claude"] {
if std::path::Path::new(path).exists() {
return Some((*path).to_string());
}
}
// Use a login shell to resolve claude via the user's PATH - GUI apps don't
// inherit shell PATH, so bare `which` may miss ~/.local/bin entries
if let Ok(output) = Command::new("bash").args(["-lc", "which claude"]).output() {
if output.status.success() { if output.status.success() {
let path = String::from_utf8_lossy(&output.stdout).trim().to_string(); let path = String::from_utf8_lossy(&output.stdout).trim().to_string();
if !path.is_empty() { if !path.is_empty() {