mirror of
https://github.com/yuangyaa/openclaw.git
synced 2026-07-14 11:07:29 +08:00
refactor: share windows command shim resolution
This commit is contained in:
@@ -7,6 +7,7 @@ import { danger, shouldLogVerbose } from "../globals.js";
|
|||||||
import { markOpenClawExecEnv } from "../infra/openclaw-exec-env.js";
|
import { markOpenClawExecEnv } from "../infra/openclaw-exec-env.js";
|
||||||
import { logDebug, logError } from "../logger.js";
|
import { logDebug, logError } from "../logger.js";
|
||||||
import { resolveCommandStdio } from "./spawn-utils.js";
|
import { resolveCommandStdio } from "./spawn-utils.js";
|
||||||
|
import { resolveWindowsCommandShim } from "./windows-command.js";
|
||||||
|
|
||||||
const execFileAsync = promisify(execFile);
|
const execFileAsync = promisify(execFile);
|
||||||
|
|
||||||
@@ -76,19 +77,10 @@ function resolveNpmArgvForWindows(argv: string[]): string[] | null {
|
|||||||
* are handled by resolveNpmArgvForWindows to avoid spawn EINVAL (no direct .cmd).
|
* are handled by resolveNpmArgvForWindows to avoid spawn EINVAL (no direct .cmd).
|
||||||
*/
|
*/
|
||||||
function resolveCommand(command: string): string {
|
function resolveCommand(command: string): string {
|
||||||
if (process.platform !== "win32") {
|
return resolveWindowsCommandShim({
|
||||||
return command;
|
command,
|
||||||
}
|
cmdCommands: ["pnpm", "yarn"],
|
||||||
const basename = path.basename(command).toLowerCase();
|
});
|
||||||
const ext = path.extname(basename);
|
|
||||||
if (ext) {
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
const cmdCommands = ["pnpm", "yarn"];
|
|
||||||
if (cmdCommands.includes(basename)) {
|
|
||||||
return `${command}.cmd`;
|
|
||||||
}
|
|
||||||
return command;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shouldSpawnWithShell(params: {
|
export function shouldSpawnWithShell(params: {
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
import type { ChildProcessWithoutNullStreams, SpawnOptions } from "node:child_process";
|
import type { ChildProcessWithoutNullStreams, SpawnOptions } from "node:child_process";
|
||||||
import { killProcessTree } from "../../kill-tree.js";
|
import { killProcessTree } from "../../kill-tree.js";
|
||||||
import { spawnWithFallback } from "../../spawn-utils.js";
|
import { spawnWithFallback } from "../../spawn-utils.js";
|
||||||
|
import { resolveWindowsCommandShim } from "../../windows-command.js";
|
||||||
import type { ManagedRunStdin, SpawnProcessAdapter } from "../types.js";
|
import type { ManagedRunStdin, SpawnProcessAdapter } from "../types.js";
|
||||||
import { toStringEnv } from "./env.js";
|
import { toStringEnv } from "./env.js";
|
||||||
|
|
||||||
function resolveCommand(command: string): string {
|
function resolveCommand(command: string): string {
|
||||||
if (process.platform !== "win32") {
|
return resolveWindowsCommandShim({
|
||||||
return command;
|
command,
|
||||||
}
|
cmdCommands: ["npm", "pnpm", "yarn", "npx"],
|
||||||
const lower = command.toLowerCase();
|
});
|
||||||
if (lower.endsWith(".exe") || lower.endsWith(".cmd") || lower.endsWith(".bat")) {
|
|
||||||
return command;
|
|
||||||
}
|
|
||||||
const basename = lower.split(/[\\/]/).pop() ?? lower;
|
|
||||||
if (basename === "npm" || basename === "pnpm" || basename === "yarn" || basename === "npx") {
|
|
||||||
return `${command}.cmd`;
|
|
||||||
}
|
|
||||||
return command;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ChildAdapter = SpawnProcessAdapter<NodeJS.Signals | null>;
|
export type ChildAdapter = SpawnProcessAdapter<NodeJS.Signals | null>;
|
||||||
|
|||||||
34
src/process/windows-command.test.ts
Normal file
34
src/process/windows-command.test.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { resolveWindowsCommandShim } from "./windows-command.js";
|
||||||
|
|
||||||
|
describe("resolveWindowsCommandShim", () => {
|
||||||
|
it("leaves commands unchanged outside Windows", () => {
|
||||||
|
expect(
|
||||||
|
resolveWindowsCommandShim({
|
||||||
|
command: "pnpm",
|
||||||
|
cmdCommands: ["pnpm"],
|
||||||
|
platform: "linux",
|
||||||
|
}),
|
||||||
|
).toBe("pnpm");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("appends .cmd for configured Windows shims", () => {
|
||||||
|
expect(
|
||||||
|
resolveWindowsCommandShim({
|
||||||
|
command: "pnpm",
|
||||||
|
cmdCommands: ["pnpm", "yarn"],
|
||||||
|
platform: "win32",
|
||||||
|
}),
|
||||||
|
).toBe("pnpm.cmd");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("keeps explicit extensions on Windows", () => {
|
||||||
|
expect(
|
||||||
|
resolveWindowsCommandShim({
|
||||||
|
command: "npm.cmd",
|
||||||
|
cmdCommands: ["npm", "npx"],
|
||||||
|
platform: "win32",
|
||||||
|
}),
|
||||||
|
).toBe("npm.cmd");
|
||||||
|
});
|
||||||
|
});
|
||||||
20
src/process/windows-command.ts
Normal file
20
src/process/windows-command.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import path from "node:path";
|
||||||
|
import process from "node:process";
|
||||||
|
|
||||||
|
export function resolveWindowsCommandShim(params: {
|
||||||
|
command: string;
|
||||||
|
cmdCommands: readonly string[];
|
||||||
|
platform?: NodeJS.Platform;
|
||||||
|
}): string {
|
||||||
|
if ((params.platform ?? process.platform) !== "win32") {
|
||||||
|
return params.command;
|
||||||
|
}
|
||||||
|
const basename = path.basename(params.command).toLowerCase();
|
||||||
|
if (path.extname(basename)) {
|
||||||
|
return params.command;
|
||||||
|
}
|
||||||
|
if (params.cmdCommands.includes(basename)) {
|
||||||
|
return `${params.command}.cmd`;
|
||||||
|
}
|
||||||
|
return params.command;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user