refactor: accept supplied plugin manifest registry

This commit is contained in:
Shakker
2026-04-28 02:25:10 +01:00
parent 8db21cdcde
commit 2aacc4053b
2 changed files with 70 additions and 17 deletions

View File

@@ -60,6 +60,7 @@ import {
useNoBundledPlugins,
writePlugin,
} from "./loader.test-fixtures.js";
import { loadPluginManifestRegistry } from "./manifest-registry.js";
import {
listMemoryEmbeddingProviders,
registerMemoryEmbeddingProvider,
@@ -897,6 +898,31 @@ afterAll(() => {
});
describe("loadOpenClawPlugins", () => {
it("can load scoped plugins from a supplied manifest registry without rereading manifests", () => {
useNoBundledPlugins();
const plugin = writePlugin({
id: "supplied-manifest",
body: `module.exports = { id: "supplied-manifest", register() {} };`,
});
const config = {
plugins: {
load: { paths: [plugin.file] },
allow: [plugin.id],
},
};
const manifestRegistry = loadPluginManifestRegistry({ config, cache: false });
fs.rmSync(path.join(plugin.dir, "openclaw.plugin.json"));
const registry = loadOpenClawPlugins({
cache: false,
config,
manifestRegistry,
onlyPluginIds: [plugin.id],
});
expect(registry.plugins.find((entry) => entry.id === plugin.id)?.status).toBe("loaded");
});
it("refreshes bundled plugin-sdk aliases without deleting the shared alias directory", () => {
const distRoot = makeTempDir();
const pluginSdkDir = path.join(distRoot, "plugin-sdk");

View File

@@ -68,7 +68,7 @@ import {
type NormalizedPluginsConfig,
type PluginActivationState,
} from "./config-state.js";
import { discoverOpenClawPlugins } from "./discovery.js";
import { discoverOpenClawPlugins, type PluginCandidate } from "./discovery.js";
import { getGlobalHookRunner, initializeGlobalHookRunner } from "./hook-runner-global.js";
import { toSafeImportPath } from "./import-specifier.js";
import { loadInstalledPluginIndexInstallRecordsSync } from "./installed-plugin-index-records.js";
@@ -79,7 +79,11 @@ import {
} from "./interactive-registry.js";
import { getCachedPluginJitiLoader, type PluginJitiLoaderCache } from "./jiti-loader-cache.js";
import { PluginLoaderCacheState } from "./loader-cache-state.js";
import { loadPluginManifestRegistry, type PluginManifestRecord } from "./manifest-registry.js";
import {
loadPluginManifestRegistry,
type PluginManifestRecord,
type PluginManifestRegistry,
} from "./manifest-registry.js";
import type { PluginBundleFormat, PluginDiagnostic, PluginFormat } from "./manifest-types.js";
import type { PluginManifestContracts } from "./manifest.js";
import {
@@ -173,6 +177,7 @@ export type PluginLoadOptions = {
installBundledRuntimeDeps?: boolean;
throwOnLoadError?: boolean;
bundledRuntimeDepsInstaller?: (params: BundledRuntimeDepsInstallParams) => void;
manifestRegistry?: PluginManifestRegistry;
};
const CLI_METADATA_ENTRY_BASENAMES = [
@@ -253,6 +258,20 @@ const LAZY_RUNTIME_REFLECTION_KEYS = [
"modelAuth",
] as const satisfies readonly (keyof PluginRuntime)[];
function createPluginCandidatesFromManifestRegistry(
manifestRegistry: PluginManifestRegistry,
): PluginCandidate[] {
return manifestRegistry.plugins.map((record) => ({
idHint: record.id,
rootDir: record.rootDir,
source: record.source,
origin: record.origin,
...(record.workspaceDir !== undefined ? { workspaceDir: record.workspaceDir } : {}),
...(record.format !== undefined ? { format: record.format } : {}),
...(record.bundleFormat !== undefined ? { bundleFormat: record.bundleFormat } : {}),
}));
}
export function clearPluginLoaderCache(): void {
pluginLoaderCacheState.clear();
clearBundledRuntimeDependencyNodePaths();
@@ -2311,21 +2330,29 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
activateGlobalSideEffects: shouldActivate,
});
const discovery = discoverOpenClawPlugins({
workspaceDir: options.workspaceDir,
extraPaths: normalized.loadPaths,
cache: options.cache,
env,
});
const manifestRegistry = loadPluginManifestRegistry({
config: cfg,
workspaceDir: options.workspaceDir,
cache: options.cache,
env,
candidates: discovery.candidates,
diagnostics: discovery.diagnostics,
installRecords: Object.keys(installRecords).length > 0 ? installRecords : undefined,
});
const suppliedManifestRegistry = options.manifestRegistry;
const discovery = suppliedManifestRegistry
? {
candidates: createPluginCandidatesFromManifestRegistry(suppliedManifestRegistry),
diagnostics: [] as PluginDiagnostic[],
}
: discoverOpenClawPlugins({
workspaceDir: options.workspaceDir,
extraPaths: normalized.loadPaths,
cache: options.cache,
env,
});
const manifestRegistry =
suppliedManifestRegistry ??
loadPluginManifestRegistry({
config: cfg,
workspaceDir: options.workspaceDir,
cache: options.cache,
env,
candidates: discovery.candidates,
diagnostics: discovery.diagnostics,
installRecords: Object.keys(installRecords).length > 0 ? installRecords : undefined,
});
pushDiagnostics(registry.diagnostics, manifestRegistry.diagnostics);
warnWhenAllowlistIsOpen({
emitWarning: shouldActivate,