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.windows is 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.exe in 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.
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:
|
// 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:
|
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:
|
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:
|
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 check terminalShellIntegrationDisabled setting 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 report cmd.exe on Windows.
-
Fix getWindowsShellFromVSCode() to handle the case where defaultProfileName is null. VS Code's effective default on Windows is PowerShell, so the fallback should not immediately jump to cmd.exe. Consider returning PowerShell as the default when no profile name is configured on Windows.
Environment
- OS: Windows 11
- App version: latest
Related issues
RooCodeInc/Roo-Code#11958
RooCodeInc/Roo-Code#8530
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
terminal.integrated.defaultProfile.windowsis set to a PowerShell profile.Default Shell: C:\Windows\System32\cmd.exein the SYSTEM INFORMATION section.&&for cmd.exe command chaining".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()insrc/utils/shell.ts, which independently reads VS Code terminal config but falls back tocmd.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.tsand callsgetShell()fromsrc/utils/shell.ts:Zoo-Code/src/core/prompts/sections/system-info.ts
Line 23 in d191fe0
The
getShell()function insrc/utils/shell.tsreads VS Code'sterminal.integrated.defaultProfile.windowsconfig to determine the shell:Zoo-Code/src/utils/shell.ts
Lines 196 to 213 in d191fe0
When
defaultProfileNameis not set (null), the fallback chain eventually reachesCOMSPECorcmd.exe:Zoo-Code/src/utils/shell.ts
Lines 355 to 359 in d191fe0
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
The execution-side shell selection
The actual terminal provider is selected in
src/core/tools/ExecuteCommandTool.tsbased onterminalShellIntegrationDisabled:Zoo-Code/src/core/tools/ExecuteCommandTool.ts
Line 202 in d191fe0
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 totrue(which means cmd.exe on Windows) unless an explicitexecaShellPathis set:Zoo-Code/src/integrations/terminal/ExecaTerminalProcess.ts
Line 43 in d191fe0
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'sdefaultProfile.windowsis 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: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
Related issues
RooCodeInc/Roo-Code#11958
RooCodeInc/Roo-Code#8530