fix(server): support Windows PowerShell shims in shared launcher

This commit is contained in:
Mohamed Boudra
2026-04-16 17:58:12 +07:00
parent e0f82e7ad0
commit 086b3098b1
2 changed files with 48 additions and 7 deletions
+21 -6
View File
@@ -40,6 +40,14 @@ export function isWindowsCommandScript(executablePath: string): boolean {
return process.platform === "win32" && (extension === ".cmd" || extension === ".bat");
}
export function isWindowsPowerShellScript(executablePath: string): boolean {
return process.platform === "win32" && extname(executablePath).toLowerCase() === ".ps1";
}
export function windowsPowerShellScriptArgs(scriptPath: string, args: string[]): string[] {
return ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", scriptPath, ...args];
}
async function probeExecutable(executablePath: string): Promise<boolean> {
return await new Promise((resolve) => {
let settled = false;
@@ -59,12 +67,19 @@ async function probeExecutable(executablePath: string): Promise<boolean> {
let child: ChildProcess;
try {
child = spawn(executablePath, ["--version"], {
stdio: "ignore",
windowsHide: true,
// Windows batch shims (.cmd/.bat) require cmd.exe; native binaries do not.
shell: isWindowsCommandScript(executablePath),
});
const isPowerShellScript = isWindowsPowerShellScript(executablePath);
child = spawn(
isPowerShellScript ? "powershell.exe" : executablePath,
isPowerShellScript
? windowsPowerShellScriptArgs(executablePath, ["--version"])
: ["--version"],
{
stdio: "ignore",
windowsHide: true,
// Windows batch shims (.cmd/.bat) require cmd.exe; native binaries do not.
shell: isWindowsCommandScript(executablePath),
},
);
} catch {
settle(false);
return;
+27 -1
View File
@@ -1,7 +1,13 @@
import { execFile, spawn, type ChildProcess, type SpawnOptions } from "node:child_process";
import { promisify } from "node:util";
import { isWindowsCommandScript, quoteWindowsArgument, quoteWindowsCommand } from "./executable.js";
import {
isWindowsCommandScript,
isWindowsPowerShellScript,
quoteWindowsArgument,
quoteWindowsCommand,
windowsPowerShellScriptArgs,
} from "./executable.js";
const execFileAsync = promisify(execFile);
@@ -24,6 +30,14 @@ export function spawnProcess(
options?: SpawnOptions,
): ChildProcess {
const isWindows = process.platform === "win32";
if (isWindowsPowerShellScript(command)) {
return spawn("powershell.exe", windowsPowerShellScriptArgs(command, args), {
...options,
shell: false,
windowsHide: true,
});
}
const shell = isWindowsCommandScript(command) ? true : (options?.shell ?? isWindows);
const shouldQuoteForShell = isWindows && shell !== false;
@@ -43,6 +57,18 @@ export async function execCommand(
options?: ExecCommandOptions,
): Promise<ExecCommandResult> {
const isWindows = process.platform === "win32";
if (isWindowsPowerShellScript(command)) {
return execFileAsync("powershell.exe", windowsPowerShellScriptArgs(command, args), {
cwd: options?.cwd,
env: options?.env,
encoding: options?.encoding ?? "utf8",
timeout: options?.timeout,
maxBuffer: options?.maxBuffer,
shell: false,
windowsHide: true,
}) as Promise<ExecCommandResult>;
}
const shell = isWindowsCommandScript(command) ? true : isWindows;
const shouldQuoteForShell = isWindows && shell !== false;
const resolvedCommand = shouldQuoteForShell ? quoteWindowsCommand(command) : command;