Files
openclaw/src/plugins/install-overrides.ts
2026-06-04 04:36:44 -04:00

72 lines
2.1 KiB
TypeScript

// Resolves plugin install override paths and package specs.
import path from "node:path";
import { parseRegistryNpmSpec } from "../infra/npm-registry-spec.js";
import { isRecord, resolveUserPath } from "../utils.js";
/** Env var containing JSON plugin install override specs. */
export const PLUGIN_INSTALL_OVERRIDES_ENV = "OPENCLAW_PLUGIN_INSTALL_OVERRIDES";
/** Env var gate that must be enabled before install overrides are honored. */
export const ALLOW_PLUGIN_INSTALL_OVERRIDES_ENV = "OPENCLAW_ALLOW_PLUGIN_INSTALL_OVERRIDES";
/** Parsed plugin install override for tests and maintainer repair flows. */
export type PluginInstallOverride =
| {
kind: "npm";
spec: string;
}
| {
kind: "npm-pack";
archivePath: string;
};
function overrideAllowed(env: NodeJS.ProcessEnv): boolean {
return env[ALLOW_PLUGIN_INSTALL_OVERRIDES_ENV]?.trim() === "1";
}
function parseOverrideSpec(raw: string): PluginInstallOverride | null {
const trimmed = raw.trim();
if (!trimmed) {
return null;
}
const npmPrefix = "npm:";
if (trimmed.startsWith(npmPrefix)) {
const spec = trimmed.slice(npmPrefix.length).trim();
return spec && parseRegistryNpmSpec(spec) ? { kind: "npm", spec } : null;
}
const npmPackPrefix = "npm-pack:";
if (trimmed.startsWith(npmPackPrefix)) {
const rawPath = trimmed.slice(npmPackPrefix.length).trim();
if (!rawPath) {
return null;
}
return { kind: "npm-pack", archivePath: path.resolve(resolveUserPath(rawPath)) };
}
return null;
}
/** Resolves a gated plugin install override from environment configuration. */
export function resolvePluginInstallOverride(params: {
pluginId: string;
env?: NodeJS.ProcessEnv;
}): PluginInstallOverride | null {
const env = params.env ?? process.env;
if (!overrideAllowed(env)) {
return null;
}
const raw = env[PLUGIN_INSTALL_OVERRIDES_ENV]?.trim();
if (!raw) {
return null;
}
let parsed: unknown;
try {
parsed = JSON.parse(raw);
} catch {
return null;
}
if (!isRecord(parsed)) {
return null;
}
const value = parsed[params.pluginId];
return typeof value === "string" ? parseOverrideSpec(value) : null;
}