refactor(plugins): delete registry compat scaffolding (#117749)

* refactor(plugins): delete registry compat scaffolding

* test(plugins): update CLI registry handle mock

* fix(plugins): preserve explicitly initialized hook registries

* test(plugins): update registry ownership fixtures

* fix(channels): restore registry snapshot memo
This commit is contained in:
Peter Steinberger
2026-08-01 21:18:47 -07:00
committed by GitHub
parent a084763814
commit ccee629359
129 changed files with 1677 additions and 6720 deletions
+1 -142
View File
@@ -1,6 +1,5 @@
// Plugin registry CLI tests cover registry loading, command integration, and reset behavior.
// Plugin registry CLI tests cover canonical process-root load scopes.
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { createEmptyPluginRegistry } from "../plugins/registry.js";
const logger = {
info: vi.fn(),
@@ -80,17 +79,8 @@ function expectLoadOpenClawPluginsCall(
const mocks = vi.hoisted(() => ({
loadOpenClawPlugins: vi.fn<typeof import("../plugins/loader.js").loadOpenClawPlugins>(),
resolveCompatibleRuntimePluginRegistry:
vi.fn<typeof import("../plugins/loader.js").resolveCompatibleRuntimePluginRegistry>(),
resolveRuntimePluginRegistry:
vi.fn<typeof import("../plugins/loader.js").resolveRuntimePluginRegistry>(),
getActivePluginRegistry: vi.fn<typeof import("../plugins/runtime.js").getActivePluginRegistry>(),
resolveConfiguredChannelPluginIds:
vi.fn<typeof import("../plugins/channel-plugin-ids.js").resolveConfiguredChannelPluginIds>(),
resolveDiscoverableScopedChannelPluginIds:
vi.fn<
typeof import("../plugins/channel-plugin-ids.js").resolveDiscoverableScopedChannelPluginIds
>(),
resolveChannelPluginIds:
vi.fn<typeof import("../plugins/channel-plugin-ids.js").resolveChannelPluginIds>(),
resolveEffectivePluginIds:
@@ -100,30 +90,16 @@ const mocks = vi.hoisted(() => ({
}));
let ensurePluginRegistryLoaded: typeof import("./plugin-registry.js").ensurePluginRegistryLoaded;
let resetPluginRegistryLoadedForTests: typeof import("./plugin-registry.js").testing.resetPluginRegistryLoadedForTests;
vi.mock("../plugins/loader.js", () => ({
loadOpenClawPlugins: (...args: Parameters<typeof mocks.loadOpenClawPlugins>) =>
mocks.loadOpenClawPlugins(...args),
resolveCompatibleRuntimePluginRegistry: (
...args: Parameters<typeof mocks.resolveCompatibleRuntimePluginRegistry>
) => mocks.resolveCompatibleRuntimePluginRegistry(...args),
resolveRuntimePluginRegistry: (...args: Parameters<typeof mocks.resolveRuntimePluginRegistry>) =>
mocks.resolveRuntimePluginRegistry(...args),
}));
vi.mock("../plugins/runtime.js", () => ({
getActivePluginRegistry: (...args: Parameters<typeof mocks.getActivePluginRegistry>) =>
mocks.getActivePluginRegistry(...args),
}));
vi.mock("../plugins/channel-plugin-ids.js", () => ({
resolveConfiguredChannelPluginIds: (
...args: Parameters<typeof mocks.resolveConfiguredChannelPluginIds>
) => mocks.resolveConfiguredChannelPluginIds(...args),
resolveDiscoverableScopedChannelPluginIds: (
...args: Parameters<typeof mocks.resolveDiscoverableScopedChannelPluginIds>
) => mocks.resolveDiscoverableScopedChannelPluginIds(...args),
resolveChannelPluginIds: (...args: Parameters<typeof mocks.resolveChannelPluginIds>) =>
mocks.resolveChannelPluginIds(...args),
}));
@@ -181,25 +157,14 @@ describe("ensurePluginRegistryLoaded", () => {
beforeAll(async () => {
const mod = await import("./plugin-registry.js");
ensurePluginRegistryLoaded = mod.ensurePluginRegistryLoaded;
resetPluginRegistryLoadedForTests = () => mod.testing.resetPluginRegistryLoadedForTests();
});
beforeEach(() => {
mocks.loadOpenClawPlugins.mockReset();
mocks.resolveCompatibleRuntimePluginRegistry.mockReset();
mocks.resolveRuntimePluginRegistry.mockReset();
mocks.getActivePluginRegistry.mockReset();
mocks.resolveConfiguredChannelPluginIds.mockReset();
mocks.resolveDiscoverableScopedChannelPluginIds.mockReset();
mocks.resolveChannelPluginIds.mockReset();
mocks.resolveEffectivePluginIds.mockReset();
mocks.resolvePluginRuntimeLoadContext.mockReset();
resetPluginRegistryLoadedForTests();
mocks.getActivePluginRegistry.mockReturnValue(createEmptyPluginRegistry());
mocks.resolveCompatibleRuntimePluginRegistry.mockReturnValue(undefined);
mocks.resolveRuntimePluginRegistry.mockReturnValue(undefined);
mocks.resolveDiscoverableScopedChannelPluginIds.mockReturnValue([]);
mocks.resolveEffectivePluginIds.mockReturnValue(["demo"]);
mocks.resolvePluginRuntimeLoadContext.mockImplementation((options) => {
const rawConfig = (options?.config ?? {}) as Record<string, unknown>;
@@ -292,110 +257,4 @@ describe("ensurePluginRegistryLoaded", () => {
throwOnLoadError: true,
});
});
it("does not treat a pre-seeded partial registry as all scope", () => {
const config = {
plugins: { enabled: true },
channels: { "demo-channel-a": { enabled: true } },
};
mocks.resolvePluginRuntimeLoadContext.mockReturnValue({
rawConfig: config,
config,
activationSourceConfig: config,
autoEnabledReasons: {},
workspaceDir: "/tmp/workspace",
env: process.env,
logger,
} as never);
mocks.getActivePluginRegistry.mockReturnValue({
plugins: [],
channels: [{ plugin: { id: "demo-channel-a" } }],
tools: [],
} as never);
ensurePluginRegistryLoaded({ scope: "all" });
expect(mocks.loadOpenClawPlugins).toHaveBeenCalledTimes(1);
expectLoadOpenClawPluginsCall(0, {
config,
onlyPluginIds: ["demo"],
throwOnLoadError: true,
workspaceDir: "/tmp/workspace",
});
});
it("does not treat a tools-only pre-seeded registry as channel scope", () => {
const config = {
plugins: { enabled: true },
channels: { "demo-channel-a": { enabled: true } },
};
const activatedConfig = withActivatedPluginIdsForTest(config, ["demo-channel-a"]);
mocks.resolvePluginRuntimeLoadContext.mockReturnValue({
rawConfig: config,
config,
activationSourceConfig: config,
autoEnabledReasons: {},
workspaceDir: "/tmp/workspace",
env: process.env,
logger,
} as never);
mocks.resolveConfiguredChannelPluginIds.mockReturnValue(["demo-channel-a"]);
mocks.getActivePluginRegistry.mockReturnValue({
plugins: [],
channels: [],
tools: [{ pluginId: "demo-tool" }],
} as never);
ensurePluginRegistryLoaded({ scope: "configured-channels" });
expect(mocks.loadOpenClawPlugins).toHaveBeenCalledTimes(1);
expectLoadOpenClawPluginsCall(0, {
config: activatedConfig,
activationSourceConfig: activatedConfig,
onlyPluginIds: ["demo-channel-a"],
throwOnLoadError: true,
workspaceDir: "/tmp/workspace",
});
});
it("reloads when a pre-seeded channel registry is missing the configured channel plugin ids", () => {
const config = {
plugins: { enabled: true },
channels: {
"demo-channel-a": {
botToken: "demo-bot-token",
appToken: "demo-app-token",
},
},
};
const activatedConfig = withActivatedPluginIdsForTest(config, ["demo-channel-a"]);
mocks.resolvePluginRuntimeLoadContext.mockReturnValue({
rawConfig: config,
config,
activationSourceConfig: config,
autoEnabledReasons: {},
workspaceDir: "/tmp/workspace",
env: process.env,
logger,
} as never);
mocks.resolveConfiguredChannelPluginIds.mockReturnValue(["demo-channel-a"]);
mocks.getActivePluginRegistry.mockReturnValue({
plugins: [{ id: "demo-channel-b" }],
channels: [{ plugin: { id: "demo-channel-b" } }],
tools: [],
} as never);
ensurePluginRegistryLoaded({ scope: "configured-channels" });
expect(mocks.loadOpenClawPlugins).toHaveBeenCalledTimes(1);
expectLoadOpenClawPluginsCall(0, {
config: activatedConfig,
activationSourceConfig: activatedConfig,
onlyPluginIds: ["demo-channel-a"],
throwOnLoadError: true,
workspaceDir: "/tmp/workspace",
});
});
});
-1
View File
@@ -1,6 +1,5 @@
// CLI-facing plugin registry loader re-export.
export {
testing,
ensurePluginRegistryLoaded,
type PluginRegistryScope,
} from "../plugins/runtime/runtime-registry-loader.js";
+4 -12
View File
@@ -26,7 +26,6 @@ import { withPluginRuntimeRegistryScope } from "../../../plugins/runtime/gateway
import { defaultRuntime } from "../../../runtime.js";
import { runCommandWithRuntime } from "../../cli-utils.js";
import { createDefaultDeps } from "../../deps.js";
import type { PluginRegistryScope } from "../../plugin-registry.js";
/** Shared helpers used by every message subcommand registration. */
export type MessageCliHelpers = {
@@ -51,10 +50,7 @@ const STRICT_NON_NEGATIVE_INTEGER_OPTIONS = new Map([
["deleteDays", "--delete-days"],
]);
type MessagePluginLoadOptions = { scope: PluginRegistryScope; onlyChannelIds?: string[] };
type MessagePluginPreloadPlan =
| { preload: true; loadOptions: MessagePluginLoadOptions }
| { preload: false };
type MessagePluginPreloadPlan = { preload: true; channelId?: string } | { preload: false };
function normalizeMessageOptions(opts: Record<string, unknown>): Record<string, unknown> {
const { account, ...rest } = opts;
@@ -136,9 +132,6 @@ function resolveMessagePluginPreloadPlan(
opts: Record<string, unknown>,
): MessagePluginPreloadPlan {
const scopedChannel = resolveScopedMessageChannel(opts);
const loadOptions = scopedChannel
? { scope: "configured-channels" as const, onlyChannelIds: [scopedChannel] }
: { scope: "configured-channels" as const };
// Gateway-owned actions can execute without loading channel plugins in the CLI process;
// dry-runs, broadcasts, and local actions need registry metadata before building payloads.
if (
@@ -146,7 +139,7 @@ function resolveMessagePluginPreloadPlan(
ACTIONS_REQUIRING_CONFIGURED_CHANNEL_PRELOAD.has(action) ||
!isGatewayOwnedMessageAction(action, scopedChannel)
) {
return { preload: true, loadOptions };
return { preload: true, ...(scopedChannel ? { channelId: scopedChannel } : {}) };
}
return { preload: false };
}
@@ -183,12 +176,11 @@ export function createMessageCliHelpers(
const preloadPlan = resolveMessagePluginPreloadPlan(action, opts);
if (preloadPlan.preload) {
const config = getRuntimeConfig();
const requestedChannelIds = preloadPlan.loadOptions.onlyChannelIds;
const pluginIds = requestedChannelIds
const pluginIds = preloadPlan.channelId
? resolveDiscoverableScopedChannelPluginIds({
config,
activationSourceConfig: config,
channelIds: requestedChannelIds,
channelIds: [preloadPlan.channelId],
env: process.env,
})
: resolveConfiguredChannelPluginIds({