Skip to content

Commit e518c12

Browse files
Asm3r96123vivekr
authored andcommitted
fix(tauri): add windows support for claude binary detection
This commit adds support for detecting the Claude binary on Windows. The previous implementation used Unix-specific commands and paths, which caused the application to fail to locate the Claude binary on Windows systems. This commit introduces conditional compilation for Windows and Unix-like systems to fix the issue.
1 parent e3fff0d commit e518c12

File tree

1 file changed

+150
-0
lines changed

1 file changed

+150
-0
lines changed

src-tauri/src/claude_binary.rs

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ fn discover_system_installations() -> Vec<ClaudeInstallation> {
166166
}
167167

168168
/// Try using the 'which' command to find Claude
169+
#[cfg(unix)]
169170
fn try_which_command() -> Option<ClaudeInstallation> {
170171
debug!("Trying 'which claude' to find binary...");
171172

@@ -209,7 +210,49 @@ fn try_which_command() -> Option<ClaudeInstallation> {
209210
}
210211
}
211212

213+
#[cfg(windows)]
214+
fn try_which_command() -> Option<ClaudeInstallation> {
215+
debug!("Trying 'where claude' to find binary...");
216+
217+
match Command::new("where").arg("claude").output() {
218+
Ok(output) if output.status.success() => {
219+
let output_str = String::from_utf8_lossy(&output.stdout).trim().to_string();
220+
221+
if output_str.is_empty() {
222+
return None;
223+
}
224+
225+
// On Windows, `where` can return multiple paths, newline-separated. We take the first one.
226+
let path = output_str.lines().next().unwrap_or("").trim().to_string();
227+
228+
if path.is_empty() {
229+
return None;
230+
}
231+
232+
debug!("'where' found claude at: {}", path);
233+
234+
// Verify the path exists
235+
if !PathBuf::from(&path).exists() {
236+
warn!("Path from 'where' does not exist: {}", path);
237+
return None;
238+
}
239+
240+
// Get version
241+
let version = get_claude_version(&path).ok().flatten();
242+
243+
Some(ClaudeInstallation {
244+
path,
245+
version,
246+
source: "where".to_string(),
247+
installation_type: InstallationType::System,
248+
})
249+
}
250+
_ => None,
251+
}
252+
}
253+
212254
/// Find Claude installations in NVM directories
255+
#[cfg(unix)]
213256
fn find_nvm_installations() -> Vec<ClaudeInstallation> {
214257
let mut installations = Vec::new();
215258

@@ -266,7 +309,44 @@ fn find_nvm_installations() -> Vec<ClaudeInstallation> {
266309
installations
267310
}
268311

312+
#[cfg(windows)]
313+
fn find_nvm_installations() -> Vec<ClaudeInstallation> {
314+
let mut installations = Vec::new();
315+
316+
if let Ok(nvm_home) = std::env::var("NVM_HOME") {
317+
debug!("Checking NVM_HOME directory: {:?}", nvm_home);
318+
319+
if let Ok(entries) = std::fs::read_dir(&nvm_home) {
320+
for entry in entries.flatten() {
321+
if entry.file_type().map(|t| t.is_dir()).unwrap_or(false) {
322+
let claude_path = entry.path().join("claude.exe");
323+
324+
if claude_path.exists() && claude_path.is_file() {
325+
let path_str = claude_path.to_string_lossy().to_string();
326+
let node_version = entry.file_name().to_string_lossy().to_string();
327+
328+
debug!("Found Claude in NVM node {}: {}", node_version, path_str);
329+
330+
// Get Claude version
331+
let version = get_claude_version(&path_str).ok().flatten();
332+
333+
installations.push(ClaudeInstallation {
334+
path: path_str,
335+
version,
336+
source: format!("nvm ({})", node_version),
337+
installation_type: InstallationType::System,
338+
});
339+
}
340+
}
341+
}
342+
}
343+
}
344+
345+
installations
346+
}
347+
269348
/// Check standard installation paths
349+
#[cfg(unix)]
270350
fn find_standard_installations() -> Vec<ClaudeInstallation> {
271351
let mut installations = Vec::new();
272352

@@ -347,6 +427,76 @@ fn find_standard_installations() -> Vec<ClaudeInstallation> {
347427
installations
348428
}
349429

430+
#[cfg(windows)]
431+
fn find_standard_installations() -> Vec<ClaudeInstallation> {
432+
let mut installations = Vec::new();
433+
434+
// Common installation paths for claude on Windows
435+
let mut paths_to_check: Vec<(String, String)> = vec![];
436+
437+
// Check user-specific paths
438+
if let Ok(user_profile) = std::env::var("USERPROFILE") {
439+
paths_to_check.extend(vec![
440+
(
441+
format!("{}\\.claude\\local\\claude.exe", user_profile),
442+
"claude-local".to_string(),
443+
),
444+
(
445+
format!("{}\\.local\\bin\\claude.exe", user_profile),
446+
"local-bin".to_string(),
447+
),
448+
(
449+
format!("{}\\AppData\\Roaming\\npm\\claude.cmd", user_profile),
450+
"npm-global".to_string(),
451+
),
452+
(
453+
format!("{}\\.yarn\\bin\\claude.cmd", user_profile),
454+
"yarn".to_string(),
455+
),
456+
(
457+
format!("{}\\.bun\\bin\\claude.exe", user_profile),
458+
"bun".to_string(),
459+
),
460+
]);
461+
}
462+
463+
// Check each path
464+
for (path, source) in paths_to_check {
465+
let path_buf = PathBuf::from(&path);
466+
if path_buf.exists() && path_buf.is_file() {
467+
debug!("Found claude at standard path: {} ({})", path, source);
468+
469+
// Get version
470+
let version = get_claude_version(&path).ok().flatten();
471+
472+
installations.push(ClaudeInstallation {
473+
path,
474+
version,
475+
source,
476+
installation_type: InstallationType::System,
477+
});
478+
}
479+
}
480+
481+
// Also check if claude is available in PATH (without full path)
482+
if let Ok(output) = Command::new("claude.exe").arg("--version").output() {
483+
if output.status.success() {
484+
debug!("claude.exe is available in PATH");
485+
let version = extract_version_from_output(&output.stdout);
486+
487+
installations.push(ClaudeInstallation {
488+
path: "claude.exe".to_string(),
489+
version,
490+
source: "PATH".to_string(),
491+
installation_type: InstallationType::System,
492+
});
493+
}
494+
}
495+
496+
installations
497+
}
498+
499+
350500
/// Get Claude version by running --version command
351501
fn get_claude_version(path: &str) -> Result<Option<String>, String> {
352502
match Command::new(path).arg("--version").output() {

0 commit comments

Comments
 (0)