mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-23 19:08:22 -06:00
eeffa53b20
* build(plugins): compile externalized plugins into local dist * test(plugins): assert native external plugin loading * chore(plugins): keep source runner asset scan unchanged * refactor(plugins): isolate external local dist builds * test(plugins): codify external artifact precedence * test(plugins): preserve contract path boundary
93 lines
3.4 KiB
TypeScript
93 lines
3.4 KiB
TypeScript
#!/usr/bin/env node
|
|
// Builds source-checkout runtime output for externally published first-party plugins.
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { performance } from "node:perf_hooks";
|
|
import { pathToFileURL } from "node:url";
|
|
import { DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV } from "./lib/bundled-plugin-build-entries.mjs";
|
|
import { shouldBuildBundledCluster } from "./lib/optional-bundled-clusters.mjs";
|
|
import { assertRealOutputRoot } from "./lib/output-root-guard.mjs";
|
|
import {
|
|
buildPluginNpmRuntime,
|
|
listPublishablePluginPackageDirs,
|
|
type PluginPackageJson,
|
|
} from "./lib/plugin-npm-runtime-build.mts";
|
|
|
|
type ExternalPluginLocalDistParams = {
|
|
repoRoot?: string;
|
|
env?: NodeJS.ProcessEnv;
|
|
logLevel?: "silent" | "warn";
|
|
};
|
|
|
|
function readPluginPackageJson(repoRoot: string, packageDir: string): PluginPackageJson {
|
|
return JSON.parse(fs.readFileSync(path.join(repoRoot, packageDir, "package.json"), "utf8"));
|
|
}
|
|
|
|
/** Lists external first-party packages that need source-checkout dist output. */
|
|
export function listExternalPluginLocalDistPackageDirs(
|
|
params: Pick<ExternalPluginLocalDistParams, "repoRoot" | "env"> = {},
|
|
): string[] {
|
|
const repoRoot = path.resolve(params.repoRoot ?? ".");
|
|
const env = params.env ?? process.env;
|
|
if (env[DOCKER_SELECTED_PLUGIN_BUILD_IDS_ENV]?.trim()) {
|
|
return [];
|
|
}
|
|
return listPublishablePluginPackageDirs({ repoRoot }).filter((packageDir) => {
|
|
const packageJson = readPluginPackageJson(repoRoot, packageDir);
|
|
return (
|
|
packageJson.openclaw?.build?.bundledDist === false &&
|
|
shouldBuildBundledCluster(path.basename(packageDir), env, { packageJson })
|
|
);
|
|
});
|
|
}
|
|
|
|
/** Builds isolated plugin graphs, then stages every output below its excluded root dist path. */
|
|
export async function buildExternalPluginLocalDist(
|
|
params: ExternalPluginLocalDistParams = {},
|
|
): Promise<{ durationMs: number; pluginDirs: string[] }> {
|
|
const repoRoot = path.resolve(params.repoRoot ?? ".");
|
|
const packageDirs = listExternalPluginLocalDistPackageDirs({
|
|
repoRoot,
|
|
env: params.env,
|
|
});
|
|
const startedAt = performance.now();
|
|
const pluginDirs: string[] = [];
|
|
|
|
for (const packageDir of packageDirs) {
|
|
const result = await buildPluginNpmRuntime({
|
|
repoRoot,
|
|
packageDir,
|
|
// Standalone package validation owns its existing bundler warnings; this
|
|
// root build still surfaces errors and validates every emitted host import.
|
|
logLevel: params.logLevel ?? "error",
|
|
});
|
|
if (!result) {
|
|
throw new Error(`${packageDir} did not produce source-checkout runtime output`);
|
|
}
|
|
const targetDir = path.join(repoRoot, "dist", "extensions", result.pluginDir);
|
|
assertRealOutputRoot(targetDir);
|
|
fs.rmSync(targetDir, { recursive: true, force: true });
|
|
fs.mkdirSync(path.dirname(targetDir), { recursive: true });
|
|
fs.cpSync(result.outDir, targetDir, { recursive: true });
|
|
fs.rmSync(result.outDir, { recursive: true, force: true });
|
|
pluginDirs.push(result.pluginDir);
|
|
}
|
|
|
|
return {
|
|
durationMs: performance.now() - startedAt,
|
|
pluginDirs,
|
|
};
|
|
}
|
|
|
|
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
|
|
try {
|
|
const result = await buildExternalPluginLocalDist();
|
|
console.log(
|
|
`[external-plugin-local-dist] built ${result.pluginDirs.length} plugins in ${Math.round(result.durationMs)}ms`,
|
|
);
|
|
} catch (error) {
|
|
console.error(error instanceof Error ? error.message : String(error));
|
|
process.exitCode = 1;
|
|
}
|
|
}
|