From 8514e4c91340a3bc3948c0a8fe80a9e989fb6a25 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 2 May 2026 03:04:05 +0100 Subject: [PATCH] fix(release): stage runtime deps from plugin package root --- scripts/postinstall-bundled-plugins.mjs | 10 ++++++- .../postinstall-bundled-plugins.test.ts | 29 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/scripts/postinstall-bundled-plugins.mjs b/scripts/postinstall-bundled-plugins.mjs index 2edb66a13c5..f533198d5ef 100644 --- a/scripts/postinstall-bundled-plugins.mjs +++ b/scripts/postinstall-bundled-plugins.mjs @@ -414,7 +414,15 @@ function expandInstalledDistImportClosure(params) { if (!JS_DIST_FILE_RE.test(importerPath) || importerPath.includes("/node_modules/")) { continue; } - const source = params.readText(importerPath); + let source; + try { + source = params.readText(importerPath); + } catch (error) { + if (error?.code === "ENOENT") { + continue; + } + throw error; + } for (const specifier of collectImportSpecifiers(source)) { const importedPath = resolveDistImportPath(importerPath, specifier); if (!importedPath || !fileSet.has(importedPath) || expectedSet.has(importedPath)) { diff --git a/test/scripts/postinstall-bundled-plugins.test.ts b/test/scripts/postinstall-bundled-plugins.test.ts index 8748a9ddfba..dbd451cc5a3 100644 --- a/test/scripts/postinstall-bundled-plugins.test.ts +++ b/test/scripts/postinstall-bundled-plugins.test.ts @@ -1,3 +1,4 @@ +import { readFileSync as readFileSyncOriginal } from "node:fs"; import fs from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; @@ -402,6 +403,34 @@ describe("bundled plugin postinstall", () => { await expect(fs.stat(staleFile)).rejects.toMatchObject({ code: "ENOENT" }); }); + it("does not abort dist pruning when a listed chunk disappears before import expansion", async () => { + const packageRoot = await createTempDirAsync("openclaw-packaged-install-missing-chunk-"); + const entryFile = path.join(packageRoot, "dist", "control-ui", "assets", "instances.js"); + const staleFile = path.join(packageRoot, "dist", "stale.js"); + await fs.mkdir(path.dirname(entryFile), { recursive: true }); + await fs.writeFile(entryFile, 'import "./chunk.js";\n'); + await writePackageDistInventory(packageRoot); + await fs.writeFile(staleFile, "export {};\n"); + const readFileSync = vi.fn((filePath: string | Buffer | URL, options?: BufferEncoding) => { + if (String(filePath).endsWith("dist/control-ui/assets/instances.js")) { + const error = new Error("missing generated asset") as NodeJS.ErrnoException; + error.code = "ENOENT"; + throw error; + } + return readFileSyncOriginal(filePath, options); + }); + + expect(() => + pruneInstalledPackageDist({ + packageRoot, + readFileSync, + log: { log: vi.fn(), warn: vi.fn() }, + }), + ).not.toThrow(); + + await expect(fs.stat(staleFile)).rejects.toMatchObject({ code: "ENOENT" }); + }); + it("prunes stale private QA files without restoring compat sidecars", async () => { const packageRoot = await createTempDirAsync("openclaw-packaged-install-qa-compat-"); const currentFile = path.join(packageRoot, "dist", "entry.js");