fix(plugins): resolve plugin paths from root

This commit is contained in:
Peter Steinberger
2026-04-30 04:13:20 +01:00
parent 09310931cf
commit 5138d3f8b6
2 changed files with 31 additions and 1 deletions

View File

@@ -32,6 +32,7 @@ import {
resolveProviderOwners,
resolveSetupProviderOwners,
} from "./plugin-registry.js";
import { resolvePluginPath } from "./registry.js";
import { cleanupTrackedTempDirs, makeTrackedTempDir } from "./test-helpers/fs-fixtures.js";
const tempDirs: string[] = [];
@@ -144,6 +145,27 @@ function createIndex(
}
describe("plugin registry facade", () => {
it("resolves relative plugin API paths against the plugin root", () => {
const pluginRoot = path.join(makeTempDir(), "plugins", "demo");
expect(resolvePluginPath("data/cache.json", pluginRoot)).toBe(
path.join(pluginRoot, "data", "cache.json"),
);
expect(resolvePluginPath("./data/cache.json", pluginRoot)).toBe(
path.join(pluginRoot, "data", "cache.json"),
);
});
it("keeps absolute and home plugin API paths user-resolved", () => {
const pluginRoot = path.join(makeTempDir(), "plugins", "demo");
const absolute = path.resolve(pluginRoot, "..", "outside.txt");
expect(resolvePluginPath(absolute, pluginRoot)).toBe(resolvePluginPath(absolute, undefined));
expect(resolvePluginPath("~/openclaw/plugin.txt", pluginRoot)).toBe(
resolvePluginPath("~/openclaw/plugin.txt", undefined),
);
});
it("resolves cold plugin records and contribution owners without loading runtime", () => {
const rootDir = makeTempDir();
const candidate = createCandidate(rootDir);

View File

@@ -236,6 +236,14 @@ const constrainLegacyPromptInjectionHook = (
export { createEmptyPluginRegistry } from "./registry-empty.js";
export function resolvePluginPath(input: string, rootDir: string | undefined): string {
const trimmed = input.trim();
if (!trimmed || path.isAbsolute(trimmed) || trimmed.startsWith("~")) {
return resolveUserPath(input);
}
return rootDir ? path.resolve(rootDir, trimmed) : resolveUserPath(input);
}
const ACTIVE_PLUGIN_HOOK_REGISTRATIONS_KEY = Symbol.for("openclaw.activePluginHookRegistrations");
const activePluginHookRegistrations = resolveGlobalSingleton<
Map<string, Array<{ event: string; handler: Parameters<typeof registerInternalHook>[1] }>>
@@ -2020,7 +2028,7 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
pluginConfig: params.pluginConfig,
runtime: resolvePluginRuntime(record.id),
logger: normalizeLogger(registryParams.logger),
resolvePath: (input: string) => resolveUserPath(input),
resolvePath: (input: string) => resolvePluginPath(input, record.rootDir),
handlers: {
...(registrationCapabilities.capabilityHandlers
? {