




























@@ -48,6 +48,27 @@ export type ResolveWindowsSpawnProgramCandidateParams = Omit<
4848ResolveWindowsSpawnProgramParams,
4949"allowShellFallback"
5050>;
51+export type WindowsSpawnCommandInlineArgs = {
52+executable: string;
53+arguments: string;
54+};
55+56+const INLINE_ARGUMENT_EXECUTABLES = new Set([
57+"node",
58+"node.exe",
59+"npm",
60+"npm.cmd",
61+"npm.exe",
62+"npx",
63+"npx.cmd",
64+"npx.exe",
65+"pnpm",
66+"pnpm.cmd",
67+"pnpm.exe",
68+"yarn",
69+"yarn.cmd",
70+"yarn.exe",
71+]);
51725273function isFilePath(candidate: string): boolean {
5374try {
@@ -57,6 +78,49 @@ function isFilePath(candidate: string): boolean {
5778}
5879}
598081+function readCommandToken(command: string): { token: string; rest: string } | null {
82+const trimmed = command.trim();
83+if (!trimmed) {
84+return null;
85+}
86+if (trimmed.startsWith('"')) {
87+const closeIndex = trimmed.indexOf('"', 1);
88+if (closeIndex <= 0) {
89+return null;
90+}
91+return {
92+token: trimmed.slice(1, closeIndex),
93+rest: trimmed.slice(closeIndex + 1).trim(),
94+};
95+}
96+const match = trimmed.match(/^(\S+)\s+(.+)$/);
97+if (!match) {
98+return null;
99+}
100+return {
101+token: match[1] ?? "",
102+rest: (match[2] ?? "").trim(),
103+};
104+}
105+106+export function detectWindowsSpawnCommandInlineArgs(
107+command: string,
108+): WindowsSpawnCommandInlineArgs | null {
109+const parsed = readCommandToken(command);
110+if (!parsed?.rest) {
111+return null;
112+}
113+const normalizedToken = parsed.token.replace(/\\/g, "/");
114+const executable = normalizeLowercaseStringOrEmpty(path.posix.basename(normalizedToken));
115+if (!INLINE_ARGUMENT_EXECUTABLES.has(executable)) {
116+return null;
117+}
118+return {
119+executable: parsed.token,
120+arguments: parsed.rest,
121+};
122+}
123+60124/** Resolve a Windows command name through PATH and PATHEXT so wrapper inspection sees the real file. */
61125export function resolveWindowsExecutablePath(command: string, env: NodeJS.ProcessEnv): string {
62126if (command.includes("/") || command.includes("\\") || path.isAbsolute(command)) {
@@ -214,6 +278,12 @@ export function resolveWindowsSpawnProgramCandidate(
214278resolution: "direct",
215279};
216280}
281+const inlineArgs = detectWindowsSpawnCommandInlineArgs(params.command);
282+if (inlineArgs) {
283+throw new Error(
284+`Windows spawn command must be an executable path only; "${inlineArgs.executable}" was configured with inline arguments "${inlineArgs.arguments}". Put arguments in the caller's args array instead.`,
285+);
286+}
217287218288const resolvedCommand = resolveWindowsExecutablePath(params.command, env);
219289const ext = normalizeLowercaseStringOrEmpty(path.extname(resolvedCommand));
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。