
























@@ -3,7 +3,13 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
33import { clearPluginLoaderCache, testing } from "../loader.js";
44import { createEmptyPluginRegistry } from "../registry-empty.js";
55import type { PluginRegistry } from "../registry-types.js";
6-import { resetPluginRuntimeStateForTest, setActivePluginRegistry } from "../runtime.js";
6+import {
7+getActivePluginChannelRegistry,
8+getActivePluginRegistry,
9+pinActivePluginChannelRegistry,
10+resetPluginRuntimeStateForTest,
11+setActivePluginRegistry,
12+} from "../runtime.js";
713814const loaderMocks = vi.hoisted(() => ({
915loadOpenClawPlugins: vi.fn<typeof import("../loader.js").loadOpenClawPlugins>(),
@@ -115,3 +121,93 @@ describe("ensureStandaloneRuntimePluginRegistryLoaded", () => {
115121expect(loaderMocks.loadOpenClawPlugins).toHaveBeenCalledOnce();
116122});
117123});
124+125+describe("ensureStandaloneRuntimePluginRegistryLoaded tool-discovery installs", () => {
126+it("does not replace active or pinned channel registries during tool discovery", () => {
127+const activeRegistry = createRegistryWithPlugin("provider-only");
128+setActivePluginRegistry(activeRegistry, "active-key", "default", "/tmp/ws");
129+const channelRegistry = createRegistryWithPlugin("channel-plugin");
130+pinActivePluginChannelRegistry(channelRegistry);
131+const toolRegistry = createRegistryWithPlugin("tool-plugin");
132+loaderMocks.loadOpenClawPlugins.mockReturnValue(toolRegistry);
133+134+ensureStandaloneRuntimePluginRegistryLoaded({
135+surface: "channel",
136+forceLoad: true,
137+loadOptions: {
138+onlyPluginIds: ["tool-plugin"],
139+activate: false,
140+toolDiscovery: true,
141+workspaceDir: "/tmp/ws",
142+},
143+});
144+145+expect(getActivePluginRegistry()).toBe(activeRegistry);
146+expect(getActivePluginChannelRegistry()).toBe(channelRegistry);
147+});
148+149+it("does not replace the active registry for a tool-discovery active load", () => {
150+const activeRegistry = createRegistryWithPlugin("provider-only");
151+setActivePluginRegistry(activeRegistry, "active-key", "default", "/tmp/ws");
152+const toolRegistry = createRegistryWithPlugin("tool-plugin");
153+loaderMocks.loadOpenClawPlugins.mockReturnValue(toolRegistry);
154+155+const result = ensureStandaloneRuntimePluginRegistryLoaded({
156+surface: "active",
157+forceLoad: true,
158+installRegistry: true,
159+loadOptions: {
160+onlyPluginIds: ["tool-plugin"],
161+activate: false,
162+toolDiscovery: true,
163+workspaceDir: "/tmp/ws",
164+},
165+});
166+167+expect(result).toBe(toolRegistry);
168+expect(getActivePluginRegistry()).toBe(activeRegistry);
169+});
170+171+it("still installs a non-tool-discovery active load (migration provider path)", () => {
172+const activeRegistry = createRegistryWithPlugin("provider-only");
173+setActivePluginRegistry(activeRegistry, "active-key", "default", "/tmp/ws");
174+const migrationRegistry = createRegistryWithPlugin("migration-plugin");
175+loaderMocks.loadOpenClawPlugins.mockReturnValue(migrationRegistry);
176+177+ensureStandaloneRuntimePluginRegistryLoaded({
178+surface: "active",
179+forceLoad: true,
180+installRegistry: true,
181+loadOptions: {
182+onlyPluginIds: ["migration-plugin"],
183+activate: false,
184+workspaceDir: "/tmp/ws",
185+},
186+});
187+188+// Without toolDiscovery the load must still become the active registry, since the migration
189+// provider resolver reads migrationProviders off the active registry.
190+expect(getActivePluginRegistry()).toBe(migrationRegistry);
191+});
192+193+it("keeps runtime surfaces empty for a cold tool-discovery load", () => {
194+// Establish the cold-start precondition deterministically (no active registry).
195+resetPluginRuntimeStateForTest();
196+const toolRegistry = createRegistryWithPlugin("tool-plugin");
197+loaderMocks.loadOpenClawPlugins.mockReturnValue(toolRegistry);
198+199+const result = ensureStandaloneRuntimePluginRegistryLoaded({
200+surface: "channel",
201+forceLoad: true,
202+loadOptions: {
203+onlyPluginIds: ["tool-plugin"],
204+activate: false,
205+toolDiscovery: true,
206+workspaceDir: "/tmp/ws",
207+},
208+});
209+210+expect(result).toBe(toolRegistry);
211+expect(getActivePluginRegistry()).toBeNull();
212+});
213+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。