fix: repair ci test and loader regressions

This commit is contained in:
Peter Steinberger
2026-03-27 18:39:29 +00:00
parent 3cec3bd48b
commit c9d68fb9c2
23 changed files with 553 additions and 224 deletions

View File

@@ -1,7 +1,14 @@
import { spawnSync } from "node:child_process";
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { createJiti } from "jiti";
import { buildChannelConfigSchema } from "../src/channels/plugins/config-schema.js";
import {
buildPluginLoaderJitiOptions,
resolvePluginSdkAliasFile,
resolvePluginSdkScopedAliasMap,
} from "../src/plugins/sdk-alias.js";
function isBuiltChannelConfigSchema(
value: unknown,
@@ -182,9 +189,88 @@ export async function loadChannelConfigSurfaceModule(
options?: { repoRoot?: string },
): Promise<{ schema: Record<string, unknown>; uiHints?: Record<string, unknown> } | null> {
const repoRoot = options?.repoRoot ?? resolveRepoRoot();
const loaderRepoRoot = resolveRepoRoot();
const bunBuildChannelConfigSchemaUrl = pathToFileURL(
path.join(loaderRepoRoot, "src/channels/plugins/config-schema.ts"),
).href;
const loadViaBun = (candidatePath: string) => {
const script = `
import { pathToFileURL } from "node:url";
const { buildChannelConfigSchema } = await import(${JSON.stringify(bunBuildChannelConfigSchemaUrl)});
const modulePath = process.env.OPENCLAW_CONFIG_SURFACE_MODULE;
if (!modulePath) {
throw new Error("missing OPENCLAW_CONFIG_SURFACE_MODULE");
}
const imported = await import(pathToFileURL(modulePath).href);
const isBuilt = (value) => Boolean(
value &&
typeof value === "object" &&
value.schema &&
typeof value.schema === "object"
);
const resolve = (mod) => {
for (const [name, value] of Object.entries(mod)) {
if (name.endsWith("ChannelConfigSchema") && isBuilt(value)) return value;
}
for (const [name, value] of Object.entries(mod)) {
if (!name.endsWith("ConfigSchema") || name.endsWith("AccountConfigSchema")) continue;
if (isBuilt(value)) return value;
if (value && typeof value === "object") return buildChannelConfigSchema(value);
}
for (const value of Object.values(mod)) {
if (isBuilt(value)) return value;
}
return null;
};
process.stdout.write(JSON.stringify(resolve(imported)));
`;
const result = spawnSync("bun", ["-e", script], {
cwd: repoRoot,
encoding: "utf8",
env: {
...process.env,
OPENCLAW_CONFIG_SURFACE_MODULE: path.resolve(candidatePath),
},
});
if (result.status !== 0) {
throw new Error(result.stderr || result.stdout || `bun loader failed for ${candidatePath}`);
}
return JSON.parse(result.stdout || "null") as {
schema: Record<string, unknown>;
uiHints?: Record<string, unknown>;
} | null;
};
const loadViaJiti = (candidatePath: string) => {
const resolvedPath = path.resolve(candidatePath);
const pluginSdkAlias = resolvePluginSdkAliasFile({
srcFile: "root-alias.cjs",
distFile: "root-alias.cjs",
modulePath: resolvedPath,
pluginSdkResolution: "src",
});
const aliasMap = {
...(pluginSdkAlias ? { "openclaw/plugin-sdk": pluginSdkAlias } : {}),
...resolvePluginSdkScopedAliasMap({
modulePath: resolvedPath,
pluginSdkResolution: "src",
}),
};
const jiti = createJiti(import.meta.url, {
...buildPluginLoaderJitiOptions(aliasMap),
interopDefault: true,
tryNative: false,
moduleCache: false,
fsCache: false,
});
return jiti(resolvedPath) as Record<string, unknown>;
};
try {
const imported = (await import(pathToFileURL(modulePath).href)) as Record<string, unknown>;
const bunLoaded = loadViaBun(modulePath);
if (bunLoaded && isBuiltChannelConfigSchema(bunLoaded)) {
return bunLoaded;
}
const imported = loadViaJiti(modulePath);
return resolveConfigSchemaExport(imported);
} catch (error) {
if (!shouldRetryViaIsolatedCopy(error)) {
@@ -193,9 +279,11 @@ export async function loadChannelConfigSurfaceModule(
const isolatedCopy = copyModuleImportGraphWithoutNodeModules({ modulePath, repoRoot });
try {
const imported = (await import(
`${pathToFileURL(isolatedCopy.copiedModulePath).href}?isolated=${Date.now()}`
)) as Record<string, unknown>;
const bunLoaded = loadViaBun(isolatedCopy.copiedModulePath);
if (bunLoaded && isBuiltChannelConfigSchema(bunLoaded)) {
return bunLoaded;
}
const imported = loadViaJiti(isolatedCopy.copiedModulePath);
return resolveConfigSchemaExport(imported);
} finally {
isolatedCopy.cleanup();