fix(server): support Windows PowerShell shims in shared launcher
This commit is contained in:
@@ -40,6 +40,14 @@ export function isWindowsCommandScript(executablePath: string): boolean {
|
|||||||
return process.platform === "win32" && (extension === ".cmd" || extension === ".bat");
|
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> {
|
async function probeExecutable(executablePath: string): Promise<boolean> {
|
||||||
return await new Promise((resolve) => {
|
return await new Promise((resolve) => {
|
||||||
let settled = false;
|
let settled = false;
|
||||||
@@ -59,12 +67,19 @@ async function probeExecutable(executablePath: string): Promise<boolean> {
|
|||||||
|
|
||||||
let child: ChildProcess;
|
let child: ChildProcess;
|
||||||
try {
|
try {
|
||||||
child = spawn(executablePath, ["--version"], {
|
const isPowerShellScript = isWindowsPowerShellScript(executablePath);
|
||||||
stdio: "ignore",
|
child = spawn(
|
||||||
windowsHide: true,
|
isPowerShellScript ? "powershell.exe" : executablePath,
|
||||||
// Windows batch shims (.cmd/.bat) require cmd.exe; native binaries do not.
|
isPowerShellScript
|
||||||
shell: isWindowsCommandScript(executablePath),
|
? windowsPowerShellScriptArgs(executablePath, ["--version"])
|
||||||
});
|
: ["--version"],
|
||||||
|
{
|
||||||
|
stdio: "ignore",
|
||||||
|
windowsHide: true,
|
||||||
|
// Windows batch shims (.cmd/.bat) require cmd.exe; native binaries do not.
|
||||||
|
shell: isWindowsCommandScript(executablePath),
|
||||||
|
},
|
||||||
|
);
|
||||||
} catch {
|
} catch {
|
||||||
settle(false);
|
settle(false);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
import { execFile, spawn, type ChildProcess, type SpawnOptions } from "node:child_process";
|
import { execFile, spawn, type ChildProcess, type SpawnOptions } from "node:child_process";
|
||||||
import { promisify } from "node:util";
|
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);
|
const execFileAsync = promisify(execFile);
|
||||||
|
|
||||||
@@ -24,6 +30,14 @@ export function spawnProcess(
|
|||||||
options?: SpawnOptions,
|
options?: SpawnOptions,
|
||||||
): ChildProcess {
|
): ChildProcess {
|
||||||
const isWindows = process.platform === "win32";
|
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 shell = isWindowsCommandScript(command) ? true : (options?.shell ?? isWindows);
|
||||||
|
|
||||||
const shouldQuoteForShell = isWindows && shell !== false;
|
const shouldQuoteForShell = isWindows && shell !== false;
|
||||||
@@ -43,6 +57,18 @@ export async function execCommand(
|
|||||||
options?: ExecCommandOptions,
|
options?: ExecCommandOptions,
|
||||||
): Promise<ExecCommandResult> {
|
): Promise<ExecCommandResult> {
|
||||||
const isWindows = process.platform === "win32";
|
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 shell = isWindowsCommandScript(command) ? true : isWindows;
|
||||||
const shouldQuoteForShell = isWindows && shell !== false;
|
const shouldQuoteForShell = isWindows && shell !== false;
|
||||||
const resolvedCommand = shouldQuoteForShell ? quoteWindowsCommand(command) : command;
|
const resolvedCommand = shouldQuoteForShell ? quoteWindowsCommand(command) : command;
|
||||||
|
|||||||
Reference in New Issue
Block a user