diff --git a/src/channels/plugins/bundled.shape-guard.test.ts b/src/channels/plugins/bundled.shape-guard.test.ts index b5fe7d80916..e719107471f 100644 --- a/src/channels/plugins/bundled.shape-guard.test.ts +++ b/src/channels/plugins/bundled.shape-guard.test.ts @@ -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(); @@ -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) => { diff --git a/src/channels/plugins/bundled.ts b/src/channels/plugins/bundled.ts index 4a20c18ce92..666086b347c 100644 --- a/src/channels/plugins/bundled.ts +++ b/src/channels/plugins/bundled.ts @@ -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"; diff --git a/src/channels/plugins/module-loader.test.ts b/src/channels/plugins/module-loader.test.ts index 365a0e6bc40..4217c46c5c8 100644 --- a/src/channels/plugins/module-loader.test.ts +++ b/src/channels/plugins/module-loader.test.ts @@ -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); }); diff --git a/src/channels/plugins/module-loader.ts b/src/channels/plugins/module-loader.ts index 4cd509318f4..575395ee8ff 100644 --- a/src/channels/plugins/module-loader.ts +++ b/src/channels/plugins/module-loader.ts @@ -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); diff --git a/src/channels/plugins/package-state-probes.ts b/src/channels/plugins/package-state-probes.ts index 8ff20ace6bb..2f30fff0eab 100644 --- a/src/channels/plugins/package-state-probes.ts +++ b/src/channels/plugins/package-state-probes.ts @@ -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;