mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-21 05:32:53 +00:00
refactor(exec): dedupe executable candidate resolution
This commit is contained in:
@@ -445,5 +445,14 @@ describe("exec-command-resolution", () => {
|
||||
String.raw`C:\Users\demo\AI\system\openclaw`,
|
||||
),
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
resolveAllowlistCandidatePath(
|
||||
{
|
||||
rawExecutable: String.raw`:/Users/demo/AI/system/openclaw`,
|
||||
executableName: "openclaw",
|
||||
},
|
||||
String.raw`C:\Users\demo\AI\system\openclaw`,
|
||||
),
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,8 +3,10 @@ import path from "node:path";
|
||||
import { matchesExecAllowlistPattern } from "./exec-allowlist-pattern.js";
|
||||
import type { ExecAllowlistEntry } from "./exec-approvals.js";
|
||||
import { resolveExecWrapperTrustPlan } from "./exec-wrapper-trust-plan.js";
|
||||
import { resolveExecutablePath as resolveExecutableCandidatePath } from "./executable-path.js";
|
||||
import { expandHomePrefix } from "./home-dir.js";
|
||||
import {
|
||||
resolveExecutablePath as resolveExecutableCandidatePath,
|
||||
resolveExecutablePathCandidate,
|
||||
} from "./executable-path.js";
|
||||
|
||||
export type ExecutableResolution = {
|
||||
rawExecutable: string;
|
||||
@@ -45,10 +47,6 @@ function parseFirstToken(command: string): string | null {
|
||||
return match ? match[0] : null;
|
||||
}
|
||||
|
||||
function isDriveLessWindowsRootedPath(value: string): boolean {
|
||||
return process.platform === "win32" && /^:[\\/]/.test(value);
|
||||
}
|
||||
|
||||
function tryResolveRealpath(filePath: string | undefined): string | undefined {
|
||||
if (!filePath) {
|
||||
return undefined;
|
||||
@@ -179,18 +177,10 @@ function resolveExecutableCandidatePathFromResolution(
|
||||
if (!raw) {
|
||||
return undefined;
|
||||
}
|
||||
const expanded = raw.startsWith("~") ? expandHomePrefix(raw) : raw;
|
||||
if (isDriveLessWindowsRootedPath(expanded)) {
|
||||
return undefined;
|
||||
}
|
||||
if (!expanded.includes("/") && !expanded.includes("\\")) {
|
||||
return undefined;
|
||||
}
|
||||
if (path.isAbsolute(expanded)) {
|
||||
return expanded;
|
||||
}
|
||||
const base = cwd && cwd.trim() ? cwd.trim() : process.cwd();
|
||||
return path.resolve(base, expanded);
|
||||
return resolveExecutablePathCandidate(raw, {
|
||||
cwd,
|
||||
requirePathSeparator: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveExecutionTargetResolution(
|
||||
|
||||
@@ -85,5 +85,10 @@ describe("executable path helpers", () => {
|
||||
cwd: String.raw`C:\Users\demo\AI\system\openclaw`,
|
||||
}),
|
||||
).toBeUndefined();
|
||||
expect(
|
||||
resolveExecutablePath(String.raw`:/Users/demo/AI/system/openclaw/git.exe`, {
|
||||
cwd: String.raw`C:\Users\demo\AI\system\openclaw`,
|
||||
}),
|
||||
).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,10 +2,34 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { expandHomePrefix } from "./home-dir.js";
|
||||
|
||||
function isDriveLessWindowsRootedPath(value: string): boolean {
|
||||
export function isDriveLessWindowsRootedPath(value: string): boolean {
|
||||
return process.platform === "win32" && /^:[\\/]/.test(value);
|
||||
}
|
||||
|
||||
export function resolveExecutablePathCandidate(
|
||||
rawExecutable: string,
|
||||
options?: { cwd?: string; env?: NodeJS.ProcessEnv; requirePathSeparator?: boolean },
|
||||
): string | undefined {
|
||||
const expanded = rawExecutable.startsWith("~")
|
||||
? expandHomePrefix(rawExecutable, { env: options?.env })
|
||||
: rawExecutable;
|
||||
if (isDriveLessWindowsRootedPath(expanded)) {
|
||||
return undefined;
|
||||
}
|
||||
const hasPathSeparator = expanded.includes("/") || expanded.includes("\\");
|
||||
if (options?.requirePathSeparator && !hasPathSeparator) {
|
||||
return undefined;
|
||||
}
|
||||
if (!hasPathSeparator) {
|
||||
return expanded;
|
||||
}
|
||||
if (path.isAbsolute(expanded)) {
|
||||
return expanded;
|
||||
}
|
||||
const base = options?.cwd && options.cwd.trim() ? options.cwd.trim() : process.cwd();
|
||||
return path.resolve(base, expanded);
|
||||
}
|
||||
|
||||
function resolveWindowsExecutableExtensions(
|
||||
executable: string,
|
||||
env: NodeJS.ProcessEnv | undefined,
|
||||
@@ -87,21 +111,14 @@ export function resolveExecutablePath(
|
||||
rawExecutable: string,
|
||||
options?: { cwd?: string; env?: NodeJS.ProcessEnv },
|
||||
): string | undefined {
|
||||
const expanded = rawExecutable.startsWith("~")
|
||||
? expandHomePrefix(rawExecutable, { env: options?.env })
|
||||
: rawExecutable;
|
||||
if (isDriveLessWindowsRootedPath(expanded)) {
|
||||
const candidate = resolveExecutablePathCandidate(rawExecutable, options);
|
||||
if (!candidate) {
|
||||
return undefined;
|
||||
}
|
||||
if (expanded.includes("/") || expanded.includes("\\")) {
|
||||
if (path.isAbsolute(expanded)) {
|
||||
return isExecutableFile(expanded) ? expanded : undefined;
|
||||
}
|
||||
const base = options?.cwd && options.cwd.trim() ? options.cwd.trim() : process.cwd();
|
||||
const candidate = path.resolve(base, expanded);
|
||||
if (candidate.includes("/") || candidate.includes("\\")) {
|
||||
return isExecutableFile(candidate) ? candidate : undefined;
|
||||
}
|
||||
const envPath =
|
||||
options?.env?.PATH ?? options?.env?.Path ?? process.env.PATH ?? process.env.Path ?? "";
|
||||
return resolveExecutableFromPathEnv(expanded, envPath, options?.env);
|
||||
return resolveExecutableFromPathEnv(candidate, envPath, options?.env);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user