Repository navigation
[BUG] System prompt on windows says shell is cmd.exe but if powershell is used via VS Code terminal provider when inline terminal is off #82
Description
Problem
On Windows, the system prompt reports the shell as cmd.exe (and generates cmd.exe-appropriate command chaining hints), but when using the VS Code terminal provider, commands actually execute in the user's configured default shell (typically PowerShell). This causes the Zoo to generate commands incompatible with the actual runtime shell.
Context (who is affected and when)
Affects all Windows users who have inline terminal off. When Inline terminal is unticked it uses VS Code default terminal profile, typically PowerShell or pwsh.
Reproduction steps
- On Windows, ensure VS Code default terminal profile is PowerShell (the default):
terminal.integrated.defaultProfile.windowsis set to a PowerShell profile. - Go to Zoo Settings, Terminal Settings and Untick "Use Inline Terminal" .
- Start a Zoo Code task and ask it to run a command.
- Observe:
- The system prompt will contain
Default Shell: C:\Windows\System32\cmd.exein the SYSTEM INFORMATION section. - The rules section will include cmd.exe-specific notes like "Using
&&for cmd.exe command chaining". - The actual command will execute in the VS Code integrated terminal, which runs PowerShell.
- The system prompt will contain
Expected result
The system prompt should report the same shell that will actually execute commands. When the VS Code terminal provider is active, the shell reported should match the user's VS Code terminal profile. When the Execa provider is active, it should report the Execa shell (which may differ).
Actual result
The system prompt always reports the shell determined by getShell() in src/utils/shell.ts, which independently reads VS Code terminal config but falls back to cmd.exe. Meanwhile, the VS Code terminal provider executes commands in whatever shell VS Code actually uses (typically PowerShell). The two code paths do not coordinate.
Analysis
The prompt-side shell detection
The system prompt is built in src/core/prompts/sections/system-info.ts and calls getShell() from src/utils/shell.ts:
| Default Shell: ${getShell()} |
The getShell() function in src/utils/shell.ts reads VS Code's terminal.integrated.defaultProfile.windows config to determine the shell:
Lines 196 to 213 in d191fe0
| // If the profile name indicates PowerShell, do version-based detection. | |
| // In testing it was found these typically do not have a path, and this | |
| // implementation manages to deductively get the correct version of PowerShell | |
| if (defaultProfileName.toLowerCase().includes("powershell")) { | |
| const normalizedPath = normalizeShellPath(profile?.path) | |
| if (normalizedPath) { | |
| // If there's an explicit PowerShell path, return that | |
| return normalizedPath | |
| } else if (profile?.source === "PowerShell") { | |
| // If the profile is sourced from PowerShell, assume the newest | |
| return SHELL_PATHS.POWERSHELL_7 | |
| } | |
| // Otherwise, assume legacy Windows PowerShell | |
| return SHELL_PATHS.POWERSHELL_LEGACY | |
| } | |
| // If there's a specific path, return that immediately | |
| const normalizedPath = normalizeShellPath(profile?.path) |
When defaultProfileName is not set (null), the fallback chain eventually reaches COMSPEC or cmd.exe:
Lines 355 to 359 in d191fe0
| if (!shell) { | |
| shell = getShellFromEnv() | |
| } | |
| // 4. Finally, fall back to a default |
This same getShell() function is also used to determine command chaining operators and shell-specific notes in the rules section:
Zoo-Code/src/core/prompts/sections/rules.ts
Lines 12 to 28 in d191fe0
| export function getCommandChainOperator(): string { | |
| const shell = getShell().toLowerCase() | |
| // Check for PowerShell (both Windows PowerShell and PowerShell Core) | |
| if (shell.includes("powershell") || shell.includes("pwsh")) { | |
| return ";" | |
| } | |
| // Check for cmd.exe | |
| if (shell.includes("cmd.exe")) { | |
| return "&&" | |
| } | |
| // Default to Unix-style && for bash, zsh, sh, and other shells | |
| // This also covers Git Bash, WSL, and other Unix-like environments on Windows | |
| return "&&" | |
| } |
The execution-side shell selection
The actual terminal provider is selected in src/core/tools/ExecuteCommandTool.ts based on terminalShellIntegrationDisabled:
Zoo-Code/src/core/tools/ExecuteCommandTool.ts
Line 202 in d191fe0
| const terminalProvider = terminalShellIntegrationDisabled ? "execa" : "vscode" |
When using the VS Code terminal provider (src/integrations/terminal/Terminal.ts), the shell is whatever VS Code's integrated terminal uses. The extension does not control this; VS Code uses the user's configured default profile.
When using the Execa provider (src/integrations/terminal/ExecaTerminalProcess.ts), the shell defaults to true (which means cmd.exe on Windows) unless an explicit execaShellPath is set:
| shell: BaseTerminal.getExecaShellPath() || true, |
Cause
The root cause is that getShell() does not account for which terminal provider will actually be used at execution time, and does not handle the case where VS Code's defaultProfile.windows is not explicitly set but the effective default is still PowerShell. VS Code defaults to PowerShell on Windows without writing it to settings, so the config lookup returns null, causing the fallback to cmd.exe.
Possible fix
-
Use unified logic for
getShell()so the system prompt is aware of the terminal provider.getShell()should checkterminalShellIntegrationDisabledsetting and use different detection logic:- For the VS Code terminal provider: detect the shell VS Code will actually use. Consider using terminal profile detection logic that accounts for VS Code's built-in defaults (PowerShell on Windows).
- For the Execa provider: use
getExecaShellPath()if set, otherwise reportcmd.exeon Windows.
-
Fix
getWindowsShellFromVSCode()to handle the case wheredefaultProfileNameis null. VS Code's effective default on Windows is PowerShell, so the fallback should not immediately jump tocmd.exe. Consider returning PowerShell as the default when no profile name is configured on Windows.
Environment
- OS: Windows 11
- App version: latest
Activity
proyectoauraorg commentedon May 21, 2026
Opened #239. The root cause is that `getShell()` fell through to `COMSPEC` (cmd.exe) when no Windows terminal profile is configured, while the integrated terminal launches PowerShell (VS Code's default). The fix reports PowerShell in that case so the system prompt matches the real shell; explicit cmd/WSL/custom profiles are unaffected.
fix(shell): default to PowerShell on Windows when no terminal profile…
fix(shell): prefer PowerShell 7 over legacy when no Windows profile i…
fix(shell): default to PowerShell on Windows when no terminal profile…
fix(shell): prefer PowerShell 7 over legacy when no Windows profile i…
fix(shell): report PowerShell on Windows when no profile is configured (