Auto-detect 'wsl.exe -d Ubuntu bash -lc claude' as default on Windows; record milestone in memory

This commit is contained in:
megaproxy 2026-05-09 01:55:51 +01:00
parent 97864374aa
commit 75049903e7
2 changed files with 50 additions and 18 deletions

View file

@ -65,6 +65,39 @@ pub fn fetch_blocking(command_override: Option<&str>) -> Result<CliUsage> {
parse_usage_text(&stripped, raw)
}
/// Pick a sensible default command line for invoking `claude`.
///
/// On Windows, `claude` may resolve to a Windows-native install that isn't
/// authenticated, while the user's real session lives in WSL. Prefer the
/// WSL Ubuntu invocation when a `wsl.exe` is detectable on PATH.
///
/// On Linux/macOS, just `claude`.
fn default_command() -> CommandBuilder {
if cfg!(windows) {
// Probe for wsl.exe; if present, run claude through a login bash in
// the Ubuntu distro (the most common dev setup, and the user's PATH
// is wired through .profile / .bashrc so `claude` resolves).
if which_exists("wsl.exe") {
let mut c = CommandBuilder::new("wsl.exe");
for a in ["-d", "Ubuntu", "bash", "-lc", "claude"] {
c.arg(a);
}
return c;
}
}
CommandBuilder::new("claude")
}
fn which_exists(name: &str) -> bool {
use std::process::Command;
let probe = if cfg!(windows) { "where" } else { "which" };
Command::new(probe)
.arg(name)
.output()
.map(|o| o.status.success() && !o.stdout.is_empty())
.unwrap_or(false)
}
/// Spawn the CLI in a PTY, send `/usage`, capture stdout for `total_timeout`,
/// then send `/exit` and return raw bytes (still containing ANSI escapes).
fn drive_claude_usage(command_override: Option<&str>, total_timeout: Duration) -> Result<Vec<u8>> {
@ -79,19 +112,16 @@ fn drive_claude_usage(command_override: Option<&str>, total_timeout: Duration) -
.context("openpty")?;
let mut cmd = match command_override {
Some(s) => {
// Allow simple "wsl.exe -- claude" style strings.
Some(s) if !s.trim().is_empty() => {
// Allow simple "wsl.exe -d Ubuntu bash -lc claude" style strings.
let parts: Vec<&str> = s.split_whitespace().collect();
if parts.is_empty() {
return Err(anyhow!("empty command_override"));
}
let mut c = CommandBuilder::new(parts[0]);
for arg in &parts[1..] {
c.arg(arg);
}
c
}
None => CommandBuilder::new("claude"),
_ => default_command(),
};
// claude inspects $TERM; give it something reasonable.
cmd.env("TERM", "xterm-256color");