-
Notifications
You must be signed in to change notification settings - Fork 28
🤖 feat: improve Windows bash runtime detection with WSL support #927
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add BashRuntime types (GitBashRuntime, WslRuntime, UnixBashRuntime) - Detect available runtimes: WSL (preferred) and Git for Windows (fallback) - Automatic Windows path translation for WSL (C:\ -> /mnt/c/) - cwd embedded in script via 'cd' since WSL needs Linux paths - Use -- separator to avoid WSL arg parsing issues - Use absolute paths to bash for each runtime - Always wrap commands in bash -c for consistent behavior - Update BashExecutionService, execAsync, and LocalBaseRuntime - Add comprehensive tests for runtime detection and path translation _Generated with mux_
- Pass bash script via stdin instead of command-line args to avoid PowerShell mangling special characters like %(refname:short) - Add comprehensive PowerShell path detection (pwsh + Windows PowerShell) - Add stdin field to SpawnConfig interface for callers to pipe to process - Update all spawn sites to handle stdin content This approach completely sidesteps command-line escaping issues because the script content never touches PowerShell's argument parser.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
src/node/utils/main/bashPath.ts
Outdated
| return command.replace( | ||
| /(["']?)([a-zA-Z]):[/\\]([^"'\s]*)\1/g, | ||
| (_match: string, quote: string, drive: string, rest: string) => { | ||
| const wslPath = `/mnt/${drive.toLowerCase()}/${rest.replace(/\\/g, "/")}`; | ||
| return quote ? `${quote}${wslPath}${quote}` : wslPath; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Translate quoted Windows paths containing spaces
translateWindowsPathsInCommand only matches drive paths up to the first whitespace because the regex uses [^"'\s]* (lines 89-93), so a quoted path like "C:\\Users\\John Doe\\repo" is rewritten to "/mnt/c/Users/John Doe\\repo" with the remainder left in Windows form. When WSL is chosen as the preferred runtime, any script that references a Windows path with spaces now receives a broken path and the command fails. The matcher should allow spaces inside quoted paths so the conversion to /mnt/... is complete.
Useful? React with 👍 / 👎.
PowerShell's $input automatic variable doesn't work reliably with -Command because it's designed for pipeline input in functions/filters, not for reading stdin directly. Use [Console]::In.ReadToEnd() instead.
Fixed regex to properly handle paths like "C:\Users\John Doe\repo": - Double-quoted paths: match content up to closing quote (allows spaces) - Single-quoted paths: match content up to closing quote (allows spaces) - Unquoted paths: match up to whitespace (no spaces allowed) Added 3 new tests for paths with spaces.
Stdin piping to PowerShell didn't work reliably ($input and [Console]::In both failed). Instead, use base64 encoding to embed the script safely in the PowerShell command line: 1. Base64 encode the bash script (completely avoids escaping issues) 2. PowerShell decodes it with [System.Text.Encoding]::UTF8.GetString() 3. Echo the decoded script and pipe to WSL bash This approach is robust because base64 strings only contain [A-Za-z0-9+/=] which have no special meaning in PowerShell. Also removes the now-unused stdin field from SpawnConfig.
When using 'echo $s | wsl bash', the output from bash wasn't being captured by PowerShell. Change to 'wsl bash -c $s' which passes the script as an argument and properly captures stdout/stderr.
Without quotes, PowerShell expands $s and bash only receives the first word as the -c argument. The rest becomes positional args to bash. Use escaped double quotes (\`"$s\`") so the entire decoded script is passed as a single argument to bash -c.
The previous approach had PowerShell decode base64 then pass to bash -c, but the decoded script contained double quotes that conflicted with the outer quoting. New approach: pass base64 string directly to bash which decodes it: wsl bash -c 'echo BASE64 | base64 -d | bash' This works because: 1. Base64 only contains [A-Za-z0-9+/=] - no special chars 2. The decode happens inside bash, so no quoting issues 3. Single quotes pass the string literally through PowerShell to WSL
b4ba586 to
16a2265
Compare
16a2265 to
fc250b6
Compare
On Windows, detached:true creates a separate console window which interferes with output capture when combined with PowerShell's -WindowStyle Hidden. The detached option is primarily needed on Unix for process group management. On Windows with the PowerShell wrapper, we don't need it and it actively breaks stdout/stderr capture.
Scripts containing 'exec </dev/null' would break when piped to bash via 'echo BASE64 | base64 -d | bash' because the stdin redirection would cut off bash's ability to read the rest of the script. Solution: Use 'eval "$(echo BASE64 | base64 -d)"' which captures the entire decoded script via command substitution before executing it. This way stdin redirection in the script doesn't affect script reading.
eval "$(...)" had nested quote conflicts with commands containing double quotes like --format="%(refname:short)". Use process substitution instead: bash <(echo BASE64 | base64 -d) This creates a file descriptor containing the decoded script, so: - Bash reads script from file descriptor (not stdin or quoted arg) - No quoting conflicts because script content isn't in quotes - Script can still redirect stdin freely (exec </dev/null works)
Summary
Improves bash runtime detection on Windows with proper WSL support:
C:\Users\...→/mnt/c/Users/...)Key implementation details
detectBashRuntimes()returns all available runtimes with a preferred choice (WSL > Git for Windows)getSpawnConfig()generates appropriate spawn parameters for each runtime type%(refname:short)-WindowStyle Hiddenin PowerShell to prevent console window flashTesting
Generated with
mux