Skip to content

Commit 59b035f

Browse files
fix(shell): report PowerShell on Windows when no profile is configured (#82) (#239)
* fix(shell): default to PowerShell on Windows when no terminal profile is set (#82) getShell() fell through to COMSPEC (cmd.exe) when VS Code had no explicit Windows terminal profile, so the system prompt advertised cmd.exe even though the integrated terminal actually launches PowerShell (VS Code's modern default). Return Windows PowerShell from getWindowsShellFromVSCode() in that case so the prompt and rules match the real shell. Explicitly configured cmd/WSL/custom profiles are unaffected. * fix(shell): prefer PowerShell 7 over legacy when no Windows profile is set (#82) --------- Co-authored-by: Armando Vaquera <263793884+proyectoauraorg@users.noreply.github.com>
1 parent 07f1bdc commit 59b035f

2 files changed

Lines changed: 35 additions & 8 deletions

File tree

src/utils/__tests__/shell.spec.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"
22
import * as vscode from "vscode"
3+
import { existsSync } from "fs"
34
import { userInfo } from "os"
45
import { getShell } from "../shell"
56

@@ -15,6 +16,11 @@ vi.mock("os", () => ({
1516
userInfo: vi.fn(() => ({ shell: null })),
1617
}))
1718

19+
// Mock the fs module — getWindowsShellFromVSCode probes for PowerShell 7 (pwsh.exe).
20+
vi.mock("fs", () => ({
21+
existsSync: vi.fn(() => false),
22+
}))
23+
1824
// Mock path module for testing
1925
vi.mock("path", async () => {
2026
const actual = await vi.importActual("path")
@@ -57,6 +63,8 @@ describe("Shell Detection Tests", () => {
5763

5864
// Reset userInfo mock to default
5965
vi.mocked(userInfo).mockReturnValue({ shell: null } as any)
66+
// Default: PowerShell 7 is not installed, so the probe falls back to legacy.
67+
vi.mocked(existsSync).mockReturnValue(false)
6068
})
6169

6270
afterEach(() => {
@@ -173,23 +181,36 @@ describe("Shell Detection Tests", () => {
173181
expect(getShell()).toBe("C:\\Windows\\System32\\cmd.exe")
174182
})
175183

176-
it("respects userInfo() if no VS Code config is available and shell is allowed", () => {
184+
it("defaults to PowerShell 7 when no profile is configured and pwsh.exe is installed", () => {
185+
// Modern VS Code launches PowerShell by default on Windows (issue #82) and
186+
// prefers PS7 when present, so getShell() should report pwsh.exe.
177187
vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any
178-
vi.mocked(userInfo).mockReturnValue({ shell: "C:\\Program Files\\PowerShell\\7\\pwsh.exe" } as any)
188+
vi.mocked(existsSync).mockReturnValue(true)
179189

180190
expect(getShell()).toBe("C:\\Program Files\\PowerShell\\7\\pwsh.exe")
181191
})
182192

183-
it("falls back to safe shell when userInfo() returns non-allowlisted shell", () => {
193+
it("falls back to Windows PowerShell 5.1 when no profile is configured and PS7 is absent", () => {
194+
// Without PS7 installed, the probe falls back to the always-present legacy
195+
// PowerShell rather than cmd.exe.
184196
vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any
185-
vi.mocked(userInfo).mockReturnValue({ shell: "C:\\Custom\\PowerShell.exe" } as any)
197+
vi.mocked(existsSync).mockReturnValue(false)
198+
199+
expect(getShell()).toBe("C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe")
200+
})
201+
202+
it("falls back to safe shell when the configured profile path is non-allowlisted", () => {
203+
mockVsCodeConfig("windows", "Custom", {
204+
Custom: { path: "C:\\Custom\\evil.exe" },
205+
})
186206

187207
expect(getShell()).toBe("C:\\Windows\\System32\\cmd.exe")
188208
})
189209

190-
it("falls back to safe shell when COMSPEC is non-allowlisted", () => {
191-
vscode.workspace.getConfiguration = () => ({ get: () => undefined }) as any
192-
process.env.COMSPEC = "D:\\CustomCmd\\cmd.exe"
210+
it("uses cmd.exe when a Command Prompt profile is explicitly configured", () => {
211+
mockVsCodeConfig("windows", "Command Prompt", {
212+
"Command Prompt": { path: "C:\\Windows\\System32\\cmd.exe" },
213+
})
193214

194215
expect(getShell()).toBe("C:\\Windows\\System32\\cmd.exe")
195216
})

src/utils/shell.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as vscode from "vscode"
2+
import { existsSync } from "fs"
23
import { userInfo } from "os"
34
import * as path from "path"
45

@@ -188,7 +189,12 @@ function normalizeShellPath(path: string | string[] | undefined): string | null
188189
function getWindowsShellFromVSCode(): string | null {
189190
const { defaultProfileName, profiles } = getWindowsTerminalConfig()
190191
if (!defaultProfileName) {
191-
return null
192+
// No explicit Windows terminal profile is configured. VS Code auto-detects
193+
// the default on modern Windows and prefers PowerShell 7 (pwsh.exe) when it
194+
// is installed, otherwise the always-present Windows PowerShell 5.1. Mirror
195+
// that here so the system prompt advertises the real shell instead of falling
196+
// through to COMSPEC (cmd.exe). See issue #82.
197+
return existsSync(SHELL_PATHS.POWERSHELL_7) ? SHELL_PATHS.POWERSHELL_7 : SHELL_PATHS.POWERSHELL_LEGACY
192198
}
193199

194200
const profile = profiles[defaultProfileName]

0 commit comments

Comments
 (0)