Files
Hy-Memory/plugins/openclaw/python-env.ts
2026-10-16 16:26:27 +08:00

81 lines
2.5 KiB
TypeScript

import { execSync } from "node:child_process";
import { existsSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
export const VENV_DIR = join(homedir(), ".openclaw", "hy-memory-venv");
const IS_WIN = process.platform === "win32";
/** Default python command name for this OS (config placeholder / fallback). */
export function defaultPythonCommand(): string {
return IS_WIN ? "python" : "python3";
}
/** True when user did not set an explicit interpreter (use auto venv). */
export function isAutoPythonPath(path: string | undefined): boolean {
if (!path || !path.trim()) return true;
const t = path.trim();
return t === "python3" || t === "python";
}
/** Path to Python inside the managed venv. */
export function getVenvPythonPath(): string {
return IS_WIN
? join(VENV_DIR, "Scripts", "python.exe")
: join(VENV_DIR, "bin", "python");
}
/** Whether the venv layout exists (bin/ or Scripts/). */
export function venvLayoutExists(): boolean {
return IS_WIN
? existsSync(join(VENV_DIR, "Scripts", "python.exe"))
: existsSync(join(VENV_DIR, "bin", "python"));
}
/** Candidates to create a venv when none exists yet. */
export function systemPythonCandidates(): string[] {
if (IS_WIN) {
return ["python", "python3"];
}
if (process.platform === "darwin") {
return ["python3", "/usr/bin/python3", "/usr/local/bin/python3", "python"];
}
return ["python3", "/usr/bin/python3", "/usr/local/bin/python3", "python"];
}
function probePython(cmd: string): boolean {
try {
const opts = { stdio: "ignore" as const, timeout: 5_000 };
if (cmd.includes(" ")) {
execSync(`${cmd} --version`, { ...opts, shell: true });
} else {
execSync(`${cmd} --version`, opts);
}
return true;
} catch {
return false;
}
}
/** First working system Python for `python -m venv`. */
export function findSystemPython(): string {
for (const candidate of systemPythonCandidates()) {
if (probePython(candidate)) return candidate;
}
// Windows: py launcher
if (IS_WIN && probePython("py -3")) return "py -3";
return defaultPythonCommand();
}
/** Run `python -m …` (handles `py -3` on Windows). */
export function execPythonModule(python: string, moduleArgs: string, timeoutMs: number): void {
const cmd = `${python} -m ${moduleArgs}`;
const opts = { stdio: "pipe" as const, timeout: timeoutMs };
if (python.includes(" ")) {
execSync(cmd, { ...opts, shell: true });
} else {
execSync(cmd, opts);
}
}