refactor: trim channel plugin loader helpers

This commit is contained in:
Peter Steinberger
2026-05-01 22:11:19 +01:00
parent e302353d61
commit 9efa9419a9
5 changed files with 22 additions and 55 deletions

View File

@@ -3,7 +3,6 @@ import os from "node:os";
import path from "node:path";
import { importFreshModule } from "openclaw/plugin-sdk/test-fixtures";
import { afterEach, describe, expect, it, vi } from "vitest";
import { loadPluginManifestRegistry } from "../../plugins/manifest-registry.js";
vi.mock("../../plugins/bundled-dir.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../../plugins/bundled-dir.js")>();
@@ -92,6 +91,19 @@ function collectBundledChannelEntrypointOffenders(
return offenders;
}
function listSourceBundledPluginRoots(): string[] {
const extensionsDir = path.resolve("extensions");
return fs
.readdirSync(extensionsDir, { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => path.join(extensionsDir, entry.name))
.filter(
(entryPath) =>
fs.existsSync(path.join(entryPath, "package.json")) ||
fs.existsSync(path.join(entryPath, "openclaw.plugin.json")),
);
}
afterEach(() => {
vi.resetModules();
vi.doUnmock("../../plugins/bundled-channel-runtime.js");
@@ -104,9 +116,7 @@ afterEach(() => {
});
describe("bundled channel entry shape guards", () => {
const bundledPluginRoots = loadPluginManifestRegistry({ config: {} })
.plugins.filter((plugin) => plugin.origin === "bundled")
.map((plugin) => plugin.rootDir);
const bundledPluginRoots = listSourceBundledPluginRoots();
it("treats missing bundled discovery results as empty", async () => {
vi.doMock("../../plugins/bundled-channel-runtime.js", async (importOriginal) => {

View File

@@ -15,11 +15,12 @@ import {
import { normalizePluginsConfig } from "../../plugins/config-state.js";
import { passesManifestOwnerBasePolicy } from "../../plugins/manifest-owner-policy.js";
import { unwrapDefaultModuleExport } from "../../plugins/module-export.js";
import { isJavaScriptModulePath } from "../../plugins/native-module-require.js";
import type { PluginRuntime } from "../../plugins/runtime/types.js";
import { normalizeOptionalLowercaseString } from "../../shared/string-coerce.js";
import { resolveBundledChannelRootScope, type BundledChannelRootScope } from "./bundled-root.js";
import { normalizeChannelMeta } from "./meta-normalization.js";
import { isJavaScriptModulePath, loadChannelPluginModule } from "./module-loader.js";
import { loadChannelPluginModule } from "./module-loader.js";
import type { ChannelPlugin } from "./types.plugin.js";
import type { ChannelId } from "./types.public.js";

View File

@@ -3,12 +3,8 @@ import os from "node:os";
import path from "node:path";
import { importFreshModule } from "openclaw/plugin-sdk/test-fixtures";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
isJavaScriptModulePath,
resolveCompiledBundledModulePath,
resolveExistingPluginModulePath,
resolvePluginModuleCandidates,
} from "./module-loader.js";
import { isJavaScriptModulePath } from "../../plugins/native-module-require.js";
import { resolveExistingPluginModulePath } from "./module-loader.js";
const tempDirs: string[] = [];
@@ -27,38 +23,12 @@ function createTempDir(): string {
}
describe("channel plugin module loader helpers", () => {
it("prefers compiled bundled dist output when present", () => {
const rootDir = createTempDir();
const runtimePath = path.join(rootDir, "dist-runtime", "entry.js");
const compiledPath = path.join(rootDir, "dist", "entry.js");
fs.mkdirSync(path.dirname(compiledPath), { recursive: true });
fs.writeFileSync(compiledPath, "export {};\n", "utf8");
expect(resolveCompiledBundledModulePath(runtimePath)).toBe(compiledPath);
});
it("keeps dist-runtime path when compiled bundled output is absent", () => {
const rootDir = createTempDir();
const runtimePath = path.join(rootDir, "dist-runtime", "entry.js");
expect(resolveCompiledBundledModulePath(runtimePath)).toBe(runtimePath);
});
it("resolves plugin module candidates and picks the first existing extension", () => {
it("resolves extensionless plugin module specifiers to the first existing extension", () => {
const rootDir = createTempDir();
const expectedPath = path.join(rootDir, "src", "checker.mts");
fs.mkdirSync(path.dirname(expectedPath), { recursive: true });
fs.writeFileSync(expectedPath, "export const ok = true;\n", "utf8");
expect(resolvePluginModuleCandidates(rootDir, "./src/checker")).toEqual([
path.join(rootDir, "src", "checker"),
path.join(rootDir, "src", "checker.ts"),
path.join(rootDir, "src", "checker.mts"),
path.join(rootDir, "src", "checker.js"),
path.join(rootDir, "src", "checker.mjs"),
path.join(rootDir, "src", "checker.cts"),
path.join(rootDir, "src", "checker.cjs"),
]);
expect(resolveExistingPluginModulePath(rootDir, "./src/checker")).toBe(expectedPath);
});

View File

@@ -5,7 +5,6 @@ import {
getCachedPluginJitiLoader,
type PluginJitiLoaderCache,
} from "../../plugins/jiti-loader-cache.js";
export { isJavaScriptModulePath } from "../../plugins/native-module-require.js";
const jitiLoaders: PluginJitiLoaderCache = new Map();
@@ -21,17 +20,7 @@ function loadModule(modulePath: string, tryNative?: boolean) {
});
}
export function resolveCompiledBundledModulePath(modulePath: string): string {
const compiledDistModulePath = modulePath.replace(
`${path.sep}dist-runtime${path.sep}`,
`${path.sep}dist${path.sep}`,
);
return compiledDistModulePath !== modulePath && fs.existsSync(compiledDistModulePath)
? compiledDistModulePath
: modulePath;
}
export function resolvePluginModuleCandidates(rootDir: string, specifier: string): string[] {
function resolvePluginModuleCandidates(rootDir: string, specifier: string): string[] {
const normalizedSpecifier = specifier.replace(/\\/g, "/");
const resolvedPath = path.resolve(rootDir, normalizedSpecifier);
const ext = path.extname(resolvedPath);

View File

@@ -5,12 +5,9 @@ import {
listChannelCatalogEntries,
type PluginChannelCatalogEntry,
} from "../../plugins/channel-catalog-registry.js";
import { isJavaScriptModulePath } from "../../plugins/native-module-require.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import {
isJavaScriptModulePath,
loadChannelPluginModule,
resolveExistingPluginModulePath,
} from "./module-loader.js";
import { loadChannelPluginModule, resolveExistingPluginModulePath } from "./module-loader.js";
type ChannelPackageStateChecker = (params: {
cfg: OpenClawConfig;