import { beforeEach, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { PluginMetadataSnapshot } from "./plugin-metadata-snapshot.js"; const mocks = vi.hoisted(() => ({ applyPluginAutoEnable: vi.fn(), listExplicitlyDisabledChannelIdsForConfig: vi.fn(), listPotentialConfiguredChannelIds: vi.fn(), listExplicitConfiguredChannelIdsForConfig: vi.fn(), loadGatewayStartupPluginPlan: vi.fn(), resolveConfiguredChannelPluginIds: vi.fn(), loadManifestMetadataSnapshot: vi.fn(), passesManifestOwnerBasePolicy: vi.fn(), })); vi.mock("../config/plugin-auto-enable.js", () => ({ applyPluginAutoEnable: (...args: Parameters) => mocks.applyPluginAutoEnable(...args), })); vi.mock("../channels/config-presence.js", () => ({ listExplicitlyDisabledChannelIdsForConfig: ( ...args: Parameters ) => mocks.listExplicitlyDisabledChannelIdsForConfig(...args), listPotentialConfiguredChannelIds: ( ...args: Parameters ) => mocks.listPotentialConfiguredChannelIds(...args), })); vi.mock("./channel-plugin-ids.js", () => ({ listExplicitConfiguredChannelIdsForConfig: ( ...args: Parameters ) => mocks.listExplicitConfiguredChannelIdsForConfig(...args), loadGatewayStartupPluginPlan: (...args: Parameters) => mocks.loadGatewayStartupPluginPlan(...args), resolveConfiguredChannelPluginIds: ( ...args: Parameters ) => mocks.resolveConfiguredChannelPluginIds(...args), })); vi.mock("./manifest-contract-eligibility.js", () => ({ loadManifestMetadataSnapshot: (...args: Parameters) => mocks.loadManifestMetadataSnapshot(...args), })); vi.mock("./manifest-owner-policy.js", () => ({ passesManifestOwnerBasePolicy: ( ...args: Parameters ) => mocks.passesManifestOwnerBasePolicy(...args), })); import { resolveEffectivePluginIds } from "./effective-plugin-ids.js"; function resolve(config: OpenClawConfig): string[] { return resolveEffectivePluginIds({ config, env: {}, workspaceDir: "/workspace", }); } describe("resolveEffectivePluginIds", () => { beforeEach(() => { mocks.applyPluginAutoEnable.mockReset(); mocks.listExplicitlyDisabledChannelIdsForConfig.mockReset(); mocks.listPotentialConfiguredChannelIds.mockReset(); mocks.listExplicitConfiguredChannelIdsForConfig.mockReset(); mocks.loadGatewayStartupPluginPlan.mockReset(); mocks.resolveConfiguredChannelPluginIds.mockReset(); mocks.loadManifestMetadataSnapshot.mockReset(); mocks.passesManifestOwnerBasePolicy.mockReset(); mocks.applyPluginAutoEnable.mockImplementation((params) => ({ config: params.config ?? {}, changes: [], autoEnabledReasons: {}, })); mocks.listExplicitlyDisabledChannelIdsForConfig.mockReturnValue([]); mocks.listPotentialConfiguredChannelIds.mockReturnValue([]); mocks.listExplicitConfiguredChannelIdsForConfig.mockReturnValue([]); mocks.loadGatewayStartupPluginPlan.mockReturnValue({ channelPluginIds: [], configuredDeferredChannelPluginIds: [], pluginIds: [], }); mocks.resolveConfiguredChannelPluginIds.mockReturnValue([]); mocks.loadManifestMetadataSnapshot.mockReturnValue({ plugins: [], } as unknown as PluginMetadataSnapshot); mocks.passesManifestOwnerBasePolicy.mockReturnValue(true); }); it("includes a selected context-engine slot even when omitted from explicit allow and entries", () => { expect( resolve({ plugins: { slots: { contextEngine: "lossless-claw" }, }, }), ).toEqual(["lossless-claw"]); }); it("keeps the built-in legacy context engine out of plugin preload ids", () => { expect( resolve({ plugins: { slots: { contextEngine: "legacy" }, }, }), ).toEqual([]); }); it.each([ { name: "plugins disabled", plugins: { enabled: false, slots: { contextEngine: "lossless-claw" }, }, }, { name: "denylisted", plugins: { deny: ["lossless-claw"], slots: { contextEngine: "lossless-claw" }, }, }, { name: "entry disabled", plugins: { entries: { "lossless-claw": { enabled: false }, }, slots: { contextEngine: "lossless-claw" }, }, }, ] satisfies Array<{ name: string; plugins: NonNullable }>)( "does not preload a selected context-engine slot when $name", ({ plugins }) => { expect(resolve({ plugins })).toEqual([]); }, ); });