From 5f6ec1f6491ddf3dc9326b9bc8f83c33f8e83749 Mon Sep 17 00:00:00 2001 From: mehmet turac Date: Sat, 16 May 2026 23:35:04 +0300 Subject: [PATCH 1/2] fix: avoid login flag for csh shells --- .../implementations/runTerminalCommand.ts | 17 +++++++++++++-- .../runTerminalCommand.vitest.ts | 14 ++++++++++++- .../cli/src/tools/runTerminalCommand.test.ts | 15 +++++++++++++ .../cli/src/tools/runTerminalCommand.ts | 21 ++++++++++++++++--- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/core/tools/implementations/runTerminalCommand.ts b/core/tools/implementations/runTerminalCommand.ts index 8f6201bd12c..3292330c9ae 100644 --- a/core/tools/implementations/runTerminalCommand.ts +++ b/core/tools/implementations/runTerminalCommand.ts @@ -22,7 +22,10 @@ function getDecodedOutput(data: Buffer): string { return data.toString(); } } // Simple helper function to use login shell on Unix/macOS and PowerShell on Windows -function getShellCommand(command: string): { shell: string; args: string[] } { +export function getShellCommand(command: string): { + shell: string; + args: string[]; +} { if (process.platform === "win32") { // Windows: Use PowerShell return { @@ -32,10 +35,20 @@ function getShellCommand(command: string): { shell: string; args: string[] } { } else { // Unix/macOS: Use login shell to source .bashrc/.zshrc etc. const userShell = process.env.SHELL || "/bin/bash"; - return { shell: userShell, args: ["-l", "-c", command] }; + return { + shell: userShell, + args: shellSupportsLoginFlag(userShell) + ? ["-l", "-c", command] + : ["-c", command], + }; } } +function shellSupportsLoginFlag(shell: string): boolean { + const shellName = shell.split(/[\\/]/).pop()?.toLowerCase(); + return shellName !== "csh" && shellName !== "tcsh"; +} + import { fileURLToPath } from "node:url"; import { ToolImpl } from "."; import { diff --git a/core/tools/implementations/runTerminalCommand.vitest.ts b/core/tools/implementations/runTerminalCommand.vitest.ts index 1f5b668db9e..7f1cb6b249d 100644 --- a/core/tools/implementations/runTerminalCommand.vitest.ts +++ b/core/tools/implementations/runTerminalCommand.vitest.ts @@ -15,7 +15,7 @@ import { import { IDE, ToolExtras } from "../.."; import * as processTerminalStates from "../../util/processTerminalStates"; import { runTerminalCommandTool } from "../definitions/runTerminalCommand"; -import { runTerminalCommandImpl } from "./runTerminalCommand"; +import { getShellCommand, runTerminalCommandImpl } from "./runTerminalCommand"; // We're using real child processes, so ensure these aren't mocked vi.unmock("node:child_process"); @@ -857,4 +857,16 @@ describe("runTerminalCommandTool.evaluateToolCallPolicy", () => { expect(result).toBe("allowedWithPermission"); }); + + it("does not pass login-shell flag to csh-family shells", () => { + const previousShell = process.env.SHELL; + process.env.SHELL = "/bin/tcsh"; + try { + const { shell, args } = getShellCommand("pwd"); + expect(shell).toBe("/bin/tcsh"); + expect(args).toEqual(["-c", "pwd"]); + } finally { + process.env.SHELL = previousShell; + } + }); }); diff --git a/extensions/cli/src/tools/runTerminalCommand.test.ts b/extensions/cli/src/tools/runTerminalCommand.test.ts index 32e8ba8ecb2..8e96506576e 100644 --- a/extensions/cli/src/tools/runTerminalCommand.test.ts +++ b/extensions/cli/src/tools/runTerminalCommand.test.ts @@ -1,4 +1,5 @@ import { + getShellCommand, isRunningInWsl, runTerminalCommandTool, } from "./runTerminalCommand.js"; @@ -121,4 +122,18 @@ describe("runTerminalCommandTool", () => { }); } }); + + describe("shell selection", () => { + it("does not pass login-shell flag to csh-family shells", () => { + const previousShell = process.env.SHELL; + process.env.SHELL = "/bin/tcsh"; + try { + const { shell, args } = getShellCommand("pwd"); + expect(shell).toBe("/bin/tcsh"); + expect(args).toEqual(["-c", "pwd"]); + } finally { + process.env.SHELL = previousShell; + } + }); + }); }); diff --git a/extensions/cli/src/tools/runTerminalCommand.ts b/extensions/cli/src/tools/runTerminalCommand.ts index 6b640c6a1c3..1b4ce2c8894 100644 --- a/extensions/cli/src/tools/runTerminalCommand.ts +++ b/extensions/cli/src/tools/runTerminalCommand.ts @@ -63,7 +63,10 @@ function getBashMaxLines(): number { } // Helper function to use login shell on Unix/macOS and PowerShell on Windows and available shell in WSL -function getShellCommand(command: string): { shell: string; args: string[] } { +export function getShellCommand(command: string): { + shell: string; + args: string[]; +} { if (process.platform === "win32") { // Windows: Use PowerShell return { @@ -77,13 +80,25 @@ function getShellCommand(command: string): { shell: string; args: string[] } { const wslShell = process.env.SHELL || "/bin/bash"; return { shell: wslShell, - args: ["-l", "-c", command], + args: shellSupportsLoginFlag(wslShell) + ? ["-l", "-c", command] + : ["-c", command], }; } // Unix/macOS: Use login shell to source .bashrc/.zshrc etc. const userShell = process.env.SHELL || "/bin/bash"; - return { shell: userShell, args: ["-l", "-c", command] }; + return { + shell: userShell, + args: shellSupportsLoginFlag(userShell) + ? ["-l", "-c", command] + : ["-c", command], + }; +} + +function shellSupportsLoginFlag(shell: string): boolean { + const shellName = shell.split(/[\\/]/).pop()?.toLowerCase(); + return shellName !== "csh" && shellName !== "tcsh"; } export function runCommandInBackground(command: string): { From 4a562bea7bde3732a390e542378749519e365a92 Mon Sep 17 00:00:00 2001 From: mehmet turac Date: Sat, 16 May 2026 23:58:56 +0300 Subject: [PATCH 2/2] test: guard csh shell regression on windows --- .../runTerminalCommand.vitest.ts | 29 ++++++++++++------- .../cli/src/tools/runTerminalCommand.test.ts | 29 ++++++++++++------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/core/tools/implementations/runTerminalCommand.vitest.ts b/core/tools/implementations/runTerminalCommand.vitest.ts index 7f1cb6b249d..d190bae7648 100644 --- a/core/tools/implementations/runTerminalCommand.vitest.ts +++ b/core/tools/implementations/runTerminalCommand.vitest.ts @@ -858,15 +858,22 @@ describe("runTerminalCommandTool.evaluateToolCallPolicy", () => { expect(result).toBe("allowedWithPermission"); }); - it("does not pass login-shell flag to csh-family shells", () => { - const previousShell = process.env.SHELL; - process.env.SHELL = "/bin/tcsh"; - try { - const { shell, args } = getShellCommand("pwd"); - expect(shell).toBe("/bin/tcsh"); - expect(args).toEqual(["-c", "pwd"]); - } finally { - process.env.SHELL = previousShell; - } - }); + it.runIf(process.platform !== "win32")( + "does not pass login-shell flag to csh-family shells", + () => { + const previousShell = process.env.SHELL; + process.env.SHELL = "/bin/tcsh"; + try { + const { shell, args } = getShellCommand("pwd"); + expect(shell).toBe("/bin/tcsh"); + expect(args).toEqual(["-c", "pwd"]); + } finally { + if (previousShell === undefined) { + delete process.env.SHELL; + } else { + process.env.SHELL = previousShell; + } + } + }, + ); }); diff --git a/extensions/cli/src/tools/runTerminalCommand.test.ts b/extensions/cli/src/tools/runTerminalCommand.test.ts index 8e96506576e..215c5c78a07 100644 --- a/extensions/cli/src/tools/runTerminalCommand.test.ts +++ b/extensions/cli/src/tools/runTerminalCommand.test.ts @@ -124,16 +124,23 @@ describe("runTerminalCommandTool", () => { }); describe("shell selection", () => { - it("does not pass login-shell flag to csh-family shells", () => { - const previousShell = process.env.SHELL; - process.env.SHELL = "/bin/tcsh"; - try { - const { shell, args } = getShellCommand("pwd"); - expect(shell).toBe("/bin/tcsh"); - expect(args).toEqual(["-c", "pwd"]); - } finally { - process.env.SHELL = previousShell; - } - }); + it.runIf(!isWindows)( + "does not pass login-shell flag to csh-family shells", + () => { + const previousShell = process.env.SHELL; + process.env.SHELL = "/bin/tcsh"; + try { + const { shell, args } = getShellCommand("pwd"); + expect(shell).toBe("/bin/tcsh"); + expect(args).toEqual(["-c", "pwd"]); + } finally { + if (previousShell === undefined) { + delete process.env.SHELL; + } else { + process.env.SHELL = previousShell; + } + } + }, + ); }); });