perf(plugins): add O(1) fast-path for empty plugin loads

This commit is contained in:
Super Zheng
2026-04-29 18:04:21 +08:00
committed by GitHub
parent 48683a7f71
commit 1c45592e62
2 changed files with 53 additions and 0 deletions

View File

@@ -3285,6 +3285,39 @@ module.exports = { id: "throws-after-import", register() {} };`,
expect(registry.plugins).toEqual([]);
});
it("skips discovery and manifest registry loading entirely when onlyPluginIds is an explicit empty array", async () => {
useNoBundledPlugins();
const allowed = writePlugin({
id: "allowed-empty-scope",
filename: "allowed-empty-scope.cjs",
body: `module.exports = { id: "allowed-empty-scope", register() {} };`,
});
const discovery = await import("./discovery.js");
const manifestRegistry = await import("./manifest-registry.js");
const discoverySpy = vi.spyOn(discovery, "discoverOpenClawPlugins");
const manifestSpy = vi.spyOn(manifestRegistry, "loadPluginManifestRegistry");
const registry = loadOpenClawPlugins({
cache: false,
activate: false,
config: {
plugins: {
load: { paths: [allowed.file] },
allow: ["allowed-empty-scope"],
},
},
onlyPluginIds: [],
});
expect(registry.plugins).toEqual([]);
expect(discoverySpy).not.toHaveBeenCalled();
expect(manifestSpy).not.toHaveBeenCalled();
discoverySpy.mockRestore();
manifestSpy.mockRestore();
});
it("only publishes plugin commands to the global registry during activating loads", async () => {
useNoBundledPlugins();
const plugin = writePlugin({

View File

@@ -115,6 +115,7 @@ import {
serializePluginIdScope,
} from "./plugin-scope.js";
import { createPluginRegistry, type PluginRecord, type PluginRegistry } from "./registry.js";
import { createEmptyPluginRegistry } from "./registry-empty.js";
import { resolvePluginCacheInputs } from "./roots.js";
import {
getActivePluginRegistry,
@@ -2233,6 +2234,25 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
const logger = options.logger ?? defaultLogger();
const validateOnly = options.mode === "validate";
const onlyPluginIdSet = createPluginIdScopeSet(onlyPluginIds);
if (onlyPluginIdSet && onlyPluginIdSet.size === 0) {
const emptyRegistry = createEmptyPluginRegistry();
if (shouldActivate) {
clearAgentHarnesses();
clearPluginCommands();
clearPluginInteractiveHandlers();
clearDetachedTaskLifecycleRuntimeRegistration();
clearMemoryPluginState();
activatePluginRegistry(
emptyRegistry,
cacheKey,
runtimeSubagentMode,
options.workspaceDir,
);
}
return emptyRegistry;
}
const cacheEnabled = options.cache !== false;
if (cacheEnabled) {
const cached = getCachedPluginRegistry(cacheKey);