mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 17:53:39 +00:00
The official 2026.9.1 image cannot load its bundled externally distributed plugins (codex, diagnostics-otel): doctor and plugins inspect report every declared dependency as missing. Since the workspace moved to pnpm's isolated linker (#135728) those packages live only in /app/node_modules/.pnpm and are linked from /app/extensions/<id>/node_modules, neither of which is an ancestor of the packaged root /app/dist/extensions/<id> that the dependency lookup (src/plugins/status-dependencies-core.ts) and the managed Codex launcher resolution (extensions/codex/src/app-server/managed-binary.ts) start from. 2026.8.2 worked only because the hoisted linker placed them in /app/node_modules. Docker-selected plugins are built as unified outputs, so the source-checkout dependency links added in #135903 never applied to them. Move linkSourcePluginDependencies into a plain-Node module and have the Docker assembly stage link each retained root-package-excluded plugin's production install under dist/extensions/<id>/node_modules after package lifecycle cleanup, failing the image build when a declared dependency still does not resolve from the packaged root. Fixes #138777. Reported by 8bitsforge. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
36 lines
1.5 KiB
JavaScript
36 lines
1.5 KiB
JavaScript
// Links a plugin's source-installed dependency packages under its packaged root.
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
|
|
/**
|
|
* Link every package installed under `<pluginDir>/node_modules` into `distNodeModules` so
|
|
* dependency lookups rooted at the packaged plugin resolve the plugin-owned install.
|
|
*/
|
|
export function linkSourcePluginDependencies(pluginDir, distNodeModules) {
|
|
const sourceModules = path.join(pluginDir, "node_modules");
|
|
if (!fs.existsSync(sourceModules)) {
|
|
return;
|
|
}
|
|
const packages = fs.readdirSync(sourceModules).flatMap((name) => {
|
|
if (name.startsWith(".") && name !== ".bin") {
|
|
return [];
|
|
}
|
|
return name.startsWith("@")
|
|
? fs.readdirSync(path.join(sourceModules, name)).map((child) => path.join(name, child))
|
|
: [name];
|
|
});
|
|
// An outer node_modules junction misresolves pnpm's relative links on Windows.
|
|
// Link canonical package roots individually; keep scopes real and payloads source-owned.
|
|
// Preserve .bin for managed launchers that resolve the plugin's private CLI shim.
|
|
for (const name of packages) {
|
|
const target = path.join(distNodeModules, name);
|
|
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
const canonical = fs.realpathSync(path.join(sourceModules, name));
|
|
// POSIX release checkouts relocate as a unit; Windows junctions require absolute targets.
|
|
fs.symlinkSync(
|
|
process.platform === "win32" ? canonical : path.relative(path.dirname(target), canonical),
|
|
target,
|
|
"junction",
|
|
);
|
|
}
|
|
}
|