Skip to content

Commit d31f821

Browse files
author
Taís (Luna Agent)
committed
fix(shell): use PowerShell CLI args for custom pwsh/powershell shell paths on Windows
1 parent 67e1d43 commit d31f821

2 files changed

Lines changed: 47 additions & 2 deletions

File tree

src/agents/shell-utils.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,36 @@ describe("getShellConfig", () => {
144144
expect(getShellConfig(shellPath)).toEqual({ shell: shellPath, args: ["-f", "-c"] });
145145
});
146146

147+
it("uses PowerShell CLI args for a custom pwsh.exe shell path", () => {
148+
const binDir = createTempCommandDir(tempDirs, [{ name: "pwsh.exe" }]);
149+
const shellPath = path.join(binDir, "pwsh.exe");
150+
151+
expect(getShellConfig(shellPath)).toEqual({
152+
shell: shellPath,
153+
args: ["-NoProfile", "-NonInteractive", "-Command"],
154+
});
155+
});
156+
157+
it("uses PowerShell CLI args for a custom powershell.exe shell path", () => {
158+
const binDir = createTempCommandDir(tempDirs, [{ name: "powershell.exe" }]);
159+
const shellPath = path.join(binDir, "powershell.exe");
160+
161+
expect(getShellConfig(shellPath)).toEqual({
162+
shell: shellPath,
163+
args: ["-NoProfile", "-NonInteractive", "-Command"],
164+
});
165+
});
166+
167+
it("uses PowerShell CLI args for a custom pwsh (no extension) shell path", () => {
168+
const binDir = createTempCommandDir(tempDirs, [{ name: "pwsh" }]);
169+
const shellPath = path.join(binDir, "pwsh");
170+
171+
expect(getShellConfig(shellPath)).toEqual({
172+
shell: shellPath,
173+
args: ["-NoProfile", "-NonInteractive", "-Command"],
174+
});
175+
});
176+
147177
it("rejects a missing explicit custom shell path", () => {
148178
expect(() => getShellConfig(path.join(os.tmpdir(), "missing-openclaw-shell"))).toThrow(
149179
"Custom shell path not found",

src/agents/shell-utils.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ export function getPosixShellArgs(shellPath: string): string[] {
8181
}
8282
}
8383

84+
// Windows PowerShell (powershell.exe / pwsh.exe) does not accept POSIX-style
85+
// invocation flags. When a custom shell path points at a PowerShell binary we
86+
// must use the PowerShell CLI flags (-NoProfile -NonInteractive -Command)
87+
// instead of the POSIX default (-c), which PowerShell would reject.
88+
function isPowerShellShell(shellPath: string): boolean {
89+
const base = path.basename(shellPath).toLowerCase();
90+
return base === "pwsh.exe" || base === "powershell.exe" || base === "pwsh" || base === "powershell";
91+
}
92+
93+
const WINDOWS_POWERSHELL_ARGS = ["-NoProfile", "-NonInteractive", "-Command"];
94+
8495
export function resolveWindowsBashPath(env: NodeJS.ProcessEnv = process.env): string | undefined {
8596
const candidates = [env.ProgramFiles, env["ProgramFiles(x86)"]]
8697
.filter((dir): dir is string => Boolean(dir?.trim()))
@@ -98,7 +109,9 @@ export function getShellConfig(customShellPath?: string): ShellConfig {
98109
if (!fs.existsSync(customShellPath)) {
99110
throw new Error(`Custom shell path not found: ${customShellPath}`);
100111
}
101-
return { shell: customShellPath, args: getPosixShellArgs(customShellPath) };
112+
// A custom PowerShell path must use PowerShell CLI args, not POSIX args.
113+
const args = isPowerShellShell(customShellPath) ? WINDOWS_POWERSHELL_ARGS : getPosixShellArgs(customShellPath);
114+
return { shell: customShellPath, args };
102115
}
103116

104117
if (process.platform === "win32") {
@@ -141,7 +154,9 @@ export function getBashShellConfig(customShellPath?: string): ShellConfig {
141154
if (!fs.existsSync(customShellPath)) {
142155
throw new Error(`Custom shell path not found: ${customShellPath}`);
143156
}
144-
return { shell: customShellPath, args: getPosixShellArgs(customShellPath) };
157+
// A custom PowerShell path must use PowerShell CLI args, not POSIX args.
158+
const args = isPowerShellShell(customShellPath) ? WINDOWS_POWERSHELL_ARGS : getPosixShellArgs(customShellPath);
159+
return { shell: customShellPath, args };
145160
}
146161

147162
if (process.platform === "win32") {

0 commit comments

Comments
 (0)