fix: preserve CLAUDE_CODE_GIT_BASH_PATH and auto-detect git-bash on Windows

The env var cleanup logic was stripping CLAUDE_CODE_GIT_BASH_PATH along
with other CLAUDE_CODE_* vars, causing Claude Code to fail even when the
user had explicitly set it. This also adds auto-detection of git-bash
from common install paths and git.exe on PATH.

Additionally, surface git-bash related stderr errors to the UI and show
a clear error message when the process fails with zero output.

Closes #109

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
GunwoongP 2026-03-30 22:45:56 +09:00
parent 4971a7d91a
commit ef5cd94f4d
2 changed files with 64 additions and 5 deletions

View file

@ -560,6 +560,10 @@ fn create_command(
cmd.env_remove("CLAUDECODE");
cmd.env_remove("CLAUDE_AGENT_SDK_VERSION");
for (key, _) in std::env::vars() {
// Keep CLAUDE_CODE_GIT_BASH_PATH — Claude Code needs it on Windows to locate git-bash
if key == "CLAUDE_CODE_GIT_BASH_PATH" {
continue;
}
if key.starts_with("CLAUDE_CODE_") || key.starts_with("CLAUDE_AGENT_") {
cmd.env_remove(&key);
}
@ -567,6 +571,42 @@ fn create_command(
// Set effort level (default: low for fast responses)
cmd.env("CLAUDE_CODE_EFFORT_LEVEL", effort_level.unwrap_or("low"));
// On Windows, auto-detect git-bash if CLAUDE_CODE_GIT_BASH_PATH is not set.
// Claude Code requires git-bash to run on Windows.
#[cfg(target_os = "windows")]
{
if std::env::var("CLAUDE_CODE_GIT_BASH_PATH").is_err() {
// Reuse the same detection logic as is_git_bash_available()
let mut found: Option<String> = None;
let candidates = [
r"C:\Program Files\Git\bin\bash.exe",
r"C:\Program Files (x86)\Git\bin\bash.exe",
];
for candidate in &candidates {
if std::path::Path::new(candidate).is_file() {
found = Some(candidate.to_string());
break;
}
}
// Also try deriving from git.exe on PATH
if found.is_none() {
if let Ok(git_path) = which::which("git") {
if let Some(cmd_dir) = git_path.parent() {
if let Some(git_root) = cmd_dir.parent() {
let bash = git_root.join("bin").join("bash.exe");
if bash.is_file() {
found = Some(bash.to_string_lossy().to_string());
}
}
}
}
}
if let Some(bash_path) = found {
cmd.env("CLAUDE_CODE_GIT_BASH_PATH", bash_path);
}
}
}
// Build PATH: start with current PATH, prepend program dir and venv bin
// Strip nul bytes from inherited PATH to prevent spawn failures
let mut current_path = strip_nul(&std::env::var("PATH").unwrap_or_default()).into_owned();

View file

@ -303,15 +303,21 @@ export function useClaudeEvents() {
if (
!success &&
count > 0 &&
!tab.error &&
!cancelledForAskRef.current.get(tabId) &&
!chatStore._cancelledByUser
) {
chatStore._setError(
tabId,
"Claude process exited unexpectedly. This may be due to rate limiting or an API error.",
);
if (count === 0) {
chatStore._setError(
tabId,
"Claude process failed to start. Check that Claude Code CLI is installed and git-bash is available on Windows.",
);
} else {
chatStore._setError(
tabId,
"Claude process exited unexpectedly. This may be due to rate limiting or an API error.",
);
}
}
// Clean up per-tab state
@ -417,6 +423,19 @@ export function useClaudeEvents() {
) {
log.error(`[${tabId}] CRITICAL: ${payload}`);
}
// Surface critical stderr messages to the user UI
if (
payload.includes("git-bash") ||
payload.includes("git bash") ||
payload.includes("bash.exe")
) {
useClaudeChatStore
.getState()
._setError(
tabId,
"Claude Code requires git-bash on Windows. Please install Git for Windows or set the CLAUDE_CODE_GIT_BASH_PATH environment variable.",
);
}
}
},
);