





















@@ -2,13 +2,21 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
22import type { PluginManifestRecord } from "./manifest-registry.js";
33import type { ProviderPlugin } from "./types.js";
445-const mocks = vi.hoisted(() => ({
6-loadPluginMetadataSnapshot: vi.fn(),
7-resolvePluginMetadataSnapshot: vi.fn(),
8-resolveDiscoveredProviderPluginIds: vi.fn(),
9-resolvePluginProviders: vi.fn(),
10-loadSource: vi.fn(),
11-}));
5+const mocks = vi.hoisted(() => {
6+const loadSource = vi.fn();
7+const loaderCache = { kind: "provider-discovery-loader-cache", clear: vi.fn() };
8+return {
9+loadPluginMetadataSnapshot: vi.fn(),
10+resolvePluginMetadataSnapshot: vi.fn(),
11+resolveDiscoveredProviderPluginIds: vi.fn(),
12+resolvePluginProviders: vi.fn(),
13+ loadSource,
14+ loaderCache,
15+clearNativeRequireJavaScriptModuleCache: vi.fn(),
16+createPluginModuleLoaderCache: vi.fn(() => loaderCache),
17+getCachedPluginModuleLoader: vi.fn(() => loadSource),
18+};
19+});
12201321vi.mock("./plugin-metadata-snapshot.js", async (importOriginal) => {
1422const actual = await importOriginal<typeof import("./plugin-metadata-snapshot.js")>();
@@ -27,10 +35,16 @@ vi.mock("./providers.runtime.js", () => ({
2735resolvePluginProviders: mocks.resolvePluginProviders,
2836}));
293730-vi.mock("./source-loader.js", () => ({
31-createPluginSourceLoader: () => mocks.loadSource,
38+vi.mock("./plugin-module-loader-cache.js", () => ({
39+createPluginModuleLoaderCache: mocks.createPluginModuleLoaderCache,
40+getCachedPluginModuleLoader: mocks.getCachedPluginModuleLoader,
41+}));
42+43+vi.mock("./native-module-require.js", () => ({
44+clearNativeRequireJavaScriptModuleCache: mocks.clearNativeRequireJavaScriptModuleCache,
3245}));
334647+import { clearPluginMetadataLifecycleCaches } from "./plugin-metadata-lifecycle.js";
3448import { resolvePluginDiscoveryProvidersRuntime } from "./provider-discovery.runtime.js";
35493650function createManifestPlugin(id: string): PluginManifestRecord {
@@ -167,6 +181,79 @@ describe("resolvePluginDiscoveryProvidersRuntime", () => {
167181expect(mocks.resolvePluginProviders).not.toHaveBeenCalled();
168182});
169183184+it("loads discovery entries through the native-capable module loader", () => {
185+const staticProvider = createProvider({ id: "deepseek", mode: "static" });
186+mocks.loadSource.mockReturnValue(staticProvider);
187+188+expect(resolvePluginDiscoveryProvidersRuntime({})).toEqual([
189+{ ...staticProvider, pluginId: "deepseek" },
190+]);
191+192+expect(mocks.getCachedPluginModuleLoader).toHaveBeenCalledOnce();
193+const calls = mocks.getCachedPluginModuleLoader.mock.calls as unknown[][];
194+const params = calls[0]?.[0] as
195+| {
196+cache?: unknown;
197+modulePath?: string;
198+importerUrl?: string;
199+loaderFilename?: string;
200+preferBuiltDist?: boolean;
201+tryNative?: boolean;
202+}
203+| undefined;
204+expect(params).toEqual(
205+expect.objectContaining({
206+cache: mocks.loaderCache,
207+modulePath: "/tmp/deepseek/provider-discovery.ts",
208+importerUrl: expect.stringContaining("provider-discovery.runtime"),
209+loaderFilename: expect.stringContaining("provider-discovery.runtime"),
210+preferBuiltDist: true,
211+}),
212+);
213+expect(params?.tryNative).toBeUndefined();
214+});
215+216+it("clears the discovery module loader cache with plugin metadata lifecycle caches", () => {
217+const staticProvider = createProvider({ id: "deepseek", mode: "static" });
218+mocks.loadSource.mockReturnValue(staticProvider);
219+220+resolvePluginDiscoveryProvidersRuntime({});
221+clearPluginMetadataLifecycleCaches();
222+223+expect(mocks.loaderCache.clear).toHaveBeenCalledOnce();
224+expect(mocks.clearNativeRequireJavaScriptModuleCache).toHaveBeenCalledWith(
225+"/tmp/deepseek/provider-discovery.ts",
226+{ dependencyRoot: "/tmp/deepseek" },
227+);
228+});
229+230+it("clears bundled dist discovery chunks from the dist root", () => {
231+const staticProvider = createProvider({ id: "deepseek", mode: "static" });
232+mocks.loadSource.mockReturnValue(staticProvider);
233+mocks.loadPluginMetadataSnapshot.mockReturnValue({
234+index: { plugins: [] },
235+manifestRegistry: {
236+plugins: [
237+{
238+ ...createManifestPlugin("deepseek"),
239+rootDir: "/tmp/openclaw/dist/extensions/deepseek",
240+manifestPath: "/tmp/openclaw/dist/extensions/deepseek/openclaw.plugin.json",
241+providerDiscoverySource: "/tmp/openclaw/dist/extensions/deepseek/provider-discovery.js",
242+},
243+],
244+diagnostics: [],
245+},
246+});
247+248+resolvePluginDiscoveryProvidersRuntime({});
249+clearPluginMetadataLifecycleCaches();
250+251+expect(mocks.clearNativeRequireJavaScriptModuleCache).toHaveBeenCalledWith(
252+"/tmp/openclaw/dist/extensions/deepseek/provider-discovery.js",
253+{ dependencyRoot: "/tmp/openclaw/dist" },
254+);
255+});
256+170257it("keeps unscoped discovery bounded for mixed live and static-only entries", () => {
171258const codexEntryProvider = createProvider({ id: "codex", mode: "catalog" });
172259const deepseekEntryProvider = createProvider({ id: "deepseek", mode: "static" });
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。