/** * Shell picker for the `bash` tool on Windows. * * Historically the bash tool always fell back to `cmd.exe` on Windows — a * reasonable default for the small set of POSIX-style commands the tool was * built around (`echo`, `dir`, `cd`, `set`, etc.). That breaks when the * caller emits PowerShell-style commands (e.g. Codex on Windows routinely * emits `Get-Content`, `Get-ChildItem`, `Set-Location`, …), which `cmd.exe` * rejects with "'Get-Content' is not recognized as an internal or external * command, operable program or batch file." This module decides — purely from * the command string and a few well-known env vars — which shell should run * the command. It returns a tagged value; bash.ts does the actual spawn. * * The picker never spawns anything itself, so it is safe to unit-test in * isolation. Shell *resolution* (finding the actual binary on PATH) lives in * `_win32-resolve.ts` and runs at spawn time. * @see {@link ../../docs/configuration.md#windows-shell-selection-wrongstackshell} for user-facing documentation of the WRONGSTACK_SHELL env var and auto-detection behavior. * * Selection precedence (Windows only): * 1. `WRONGSTACK_SHELL` env var, if it names a known shell (cmd | powershell * | pwsh). This is the override for users who want a fixed shell. * 2. Auto-detect: if the command "looks like" PowerShell — i.e. uses cmdlet * verb-noun syntax, $-variables, subexpressions, here-strings, etc. — * route to PowerShell. Prefers `pwsh` (PowerShell 7+) and falls back to * `powershell` (Windows PowerShell 5.1) at spawn time. * 3. Default: `cmd.exe` (preserves legacy behavior). * * On non-Windows the picker is a no-op — bash.ts already routes through * `/bin/bash -c`. We return `'cmd'` as a sentinel value that means "the * platform default"; bash.ts maps it to the right binary. * * See docs/configuration.md § "Windows shell selection (WRONGSTACK_SHELL)" for * user-facing documentation of the env var and auto-detection behaviour. */ export type BashShell = 'cmd' | 'powershell' | 'pwsh'; /** Sentinel returned on POSIX — bash.ts maps this to `/bin/bash -c`. */ export declare const POSIX_DEFAULT: BashShell; interface PickShellEnv { /** Read-only env view. Tests pass `{ get: (k) => process.env[k] }`. */ get(key: string): string | undefined; } /** * Decide which shell should execute `command` on `platform`. Pure function — * no I/O, no side effects, no exceptions (invalid input returns the default). */ export declare function pickShell(platform: NodeJS.Platform, command: string, env: PickShellEnv): BashShell; /** * Heuristic PowerShell detector. Conservative on purpose — false positives * route `cmd.exe` work into PowerShell (different parsing rules, different * exit-code semantics, sometimes very different stdout), which is more * disruptive than a single "command not recognized" error. We only return * true for patterns that are unambiguously PowerShell. * * Detected patterns: * - cmdlet verb-noun syntax (`Get-`, `Set-`, `New-`, `Remove-`, `Add-`, * `Clear-`, `Copy-`, `Move-`, `Rename-`, `Test-`, `Update-`, `Write-`, * `Read-`, `Push-`, `Pop-`, `Invoke-`, `Start-`, `Stop-`, `Wait-`, * `Out-`, `Format-`, `Group-`, `Measure-`, `Compare-`, `Resolve-`, * `ConvertTo-`, `ConvertFrom-`, `Import-`, `Export-`, `Select-`, * `Where-`, `ForEach-`, `Sort-`, `Tee-`, `Split-`, `Join-`, `Limit-`, * `Skip-`, `Step-`, `Trace-`, `Debug-`, `Register-`, `Unregister-`, * `Enable-`, `Disable-`, `Restart-`, `Suspend-`, `Resume-`, `Save-`, * `Open-`, `Close-`, `Lock-`, `Unlock-`, `Mount-`, `Dismount-`, * `Enter-`, `Exit-`, `Use-`, `Show-`, `Hide-`, `Find-`, `Search-`, * `Watch-`, `Initialize-`, `Optimize-`, `Compress-`, `Expand-`, * `Convert-`, `Merge-`, `Checkpoint-`, `Undo-`, `Redo-`, `Approve-`, * `Deny-`, `Block-`, `Grant-`, `Revoke-`, `Assert-`, `Confirm-`, * `Resolve-`, `Wait-`, `Receive-`, `Send-`, `Connect-`, `Disconnect-`, * `Read-`, `Write-`). * - $-prefixed variables (`$env:`, `$foo`, `$script:bar`, `$_`). * - Subexpressions (`$(...)`). * - Here-strings (`@"…"@`, `@'…'@`). * - Splatting (`@(...)` at start of argument, `@{}` hash table). * - PowerShell-comparison operators (`-eq`, `-ne`, `-lt`, `-gt`, `-le`, * `-ge`, `-like`, `-notlike`, `-match`, `-notmatch`, `-contains`, * `-in`, `-and`, `-or`, `-not`, `-band`, `-bor`, `-bxor`, * `-replace`, `-split`, `-join`, `-is`, `-as`, `-f`). * - `.ps1` extension mentioned in the command. * - `&` call operator followed by a `$`-variable (`& $cmd ...`). * - PowerShell-only aliases: `gci`, `gi`, `gp`, `gcm`, `gps`. Unix-style * names (`ls`, `cat`, `cp`, `mv`, `rm`, `sl`) are deliberately NOT * treated as PowerShell tells — they are Git-Bash/MSYS-normal on * Windows and their PS alias semantics differ (`rm -rf` fails in PS). * - `#requires` directive at start of script. * - `param()` block at start of script. * * The Windows-style path `C:\` alone is not a PowerShell tell — both * shells accept it. We only flip on PS-specific syntax. * * The function is case-insensitive and tolerates leading whitespace. */ export declare function looksLikePowerShell(command: string): boolean; /** * Extended PowerShell detection — patterns that are unambiguous but less * common than the verb-noun cmdlets caught by the first pass. * * Covers: -WhatIf / -Confirm / -ErrorAction flags, trailing `2>&1` in * combination with other PS signals, `[type]` casts, Where/ForEach/ * Select-Object pipeline, PS comment blocks, Write-* output cmdlets, * registry paths (HKLM:/HKCU:), -AsPlainText, -PipelineVariable. */ export declare function looksLikePowerShellExtended(command: string): boolean; /** * Wrap a user command for execution via `pwsh -Command -` (stdin pipe). * * The wrapper addresses four reliability gaps in Windows PowerShell: * * 1. **Console output encoding**: PS 5.1 outputs in the system codepage * (often Windows-1252) which mojibakes non-ASCII. Setting * `[Console]::OutputEncoding = [System.Text.Encoding]::UTF8` at the * top of the script ensures UTF-8 output in both editions. * * 2. **Exit-code propagation**: Native commands (dotnet, npm, node, etc.) * set `$LASTEXITCODE`. Without explicit propagation, `pwsh -Command -` * exits 0 even when the native command failed. Running the command body * and then exiting with `$LASTEXITCODE` when it is numeric preserves native * exit codes without swallowing PowerShell output. * * 3. **Confirmation suppression**: `$ConfirmPreference='None'` suppresses * interactive confirmation prompts (e.g. `-Confirm` cmdlets) so scripts * don't block waiting for user input. `$WhatIfPreference=$false` ensures * commands actually RUN (not just print what they would do). * * The caller encodes this script as UTF-16LE Base64 for `-EncodedCommand`. * Do not prefix it with a BOM: the encoded command is already decoded using * PowerShell's required UTF-16LE representation. */ export declare function wrapPowerShellScript(command: string): string; /** * Return the argv prefix for a given shell. The bash tool passes a single * command string and expects the shell to interpret it. cmd.exe uses * `/c `; PowerShell uses `-EncodedCommand `. The encoded payload * avoids quoting bugs for multi-line, quoted, and dollar-sign-laden scripts. */ export declare function shellArgs(shell: BashShell): string[]; /** * Post-failure diagnosis: when a Windows shell command exits non-zero, scan it * for bash/POSIX idioms the shell does not accept and return a short, targeted * hint (with the right replacement) so the model self-corrects on the next turn. * * Deliberately **failure-coupled** — the bash tool only calls this on a * non-zero exit. That keeps it noise-free (PowerShell aliases `ls`/`cat`/`rm` * succeed, so they never reach here) and side-steps shell-version nuance: `&&` * works in PowerShell 7 and cmd.exe (so those commands succeed and are never * flagged) but breaks in Windows PowerShell 5.1 (where the command fails and is * flagged). Never mutates or blocks — advisory only. * * Returns `undefined` when nothing actionable is found (including any POSIX * call — bash idioms are correct there). */ export declare function diagnoseBashism(command: string, shell: BashShell): string | undefined; export {}; //# sourceMappingURL=_shell-pick.d.ts.map