mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-21 15:01:03 +00:00
* Gateway: treat scope-limited probe RPC as degraded * Docs: clarify gateway probe degraded scope output * test: fix CI type regressions in gateway and outbound suites * Tests: fix Node24 diffs theme loading and Windows assertions * Tests: fix extension typing after main rebase * Tests: fix Windows CI regressions after rebase * Tests: normalize executable path assertions on Windows * Tests: remove duplicate gateway daemon result alias * Tests: stabilize Windows approval path assertions * Tests: fix Discord rate-limit startup fixture typing * Tests: use Windows-friendly relative exec fixtures --------- Co-authored-by: Mainframe <mainframe@MainfraacStudio.localdomain>
101 lines
2.7 KiB
TypeScript
101 lines
2.7 KiB
TypeScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { expandHomePrefix } from "./home-dir.js";
|
|
|
|
function resolveWindowsExecutableExtensions(
|
|
executable: string,
|
|
env: NodeJS.ProcessEnv | undefined,
|
|
): string[] {
|
|
if (process.platform !== "win32") {
|
|
return [""];
|
|
}
|
|
if (path.extname(executable).length > 0) {
|
|
return [""];
|
|
}
|
|
return [
|
|
"",
|
|
...(
|
|
env?.PATHEXT ??
|
|
env?.Pathext ??
|
|
process.env.PATHEXT ??
|
|
process.env.Pathext ??
|
|
".EXE;.CMD;.BAT;.COM"
|
|
)
|
|
.split(";")
|
|
.map((ext) => ext.toLowerCase()),
|
|
];
|
|
}
|
|
|
|
function resolveWindowsExecutableExtSet(env: NodeJS.ProcessEnv | undefined): Set<string> {
|
|
return new Set(
|
|
(
|
|
env?.PATHEXT ??
|
|
env?.Pathext ??
|
|
process.env.PATHEXT ??
|
|
process.env.Pathext ??
|
|
".EXE;.CMD;.BAT;.COM"
|
|
)
|
|
.split(";")
|
|
.map((ext) => ext.toLowerCase())
|
|
.filter(Boolean),
|
|
);
|
|
}
|
|
|
|
export function isExecutableFile(filePath: string): boolean {
|
|
try {
|
|
const stat = fs.statSync(filePath);
|
|
if (!stat.isFile()) {
|
|
return false;
|
|
}
|
|
if (process.platform === "win32") {
|
|
const ext = path.extname(filePath).toLowerCase();
|
|
if (!ext) {
|
|
return true;
|
|
}
|
|
return resolveWindowsExecutableExtSet(undefined).has(ext);
|
|
}
|
|
fs.accessSync(filePath, fs.constants.X_OK);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function resolveExecutableFromPathEnv(
|
|
executable: string,
|
|
pathEnv: string,
|
|
env?: NodeJS.ProcessEnv,
|
|
): string | undefined {
|
|
const entries = pathEnv.split(path.delimiter).filter(Boolean);
|
|
const extensions = resolveWindowsExecutableExtensions(executable, env);
|
|
for (const entry of entries) {
|
|
for (const ext of extensions) {
|
|
const candidate = path.join(entry, executable + ext);
|
|
if (isExecutableFile(candidate)) {
|
|
return candidate;
|
|
}
|
|
}
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
export function resolveExecutablePath(
|
|
rawExecutable: string,
|
|
options?: { cwd?: string; env?: NodeJS.ProcessEnv },
|
|
): string | undefined {
|
|
const expanded = rawExecutable.startsWith("~")
|
|
? expandHomePrefix(rawExecutable, { env: options?.env })
|
|
: rawExecutable;
|
|
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);
|
|
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);
|
|
}
|