From 4dad7bd93b6caae036342fd4efbdb47c217b459f Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 31 May 2026 02:47:41 +0100 Subject: [PATCH] fix(release): tolerate npm README metadata lag --- .../verify-plugin-npm-published-runtime.mjs | 29 +++++++++++++++++-- ...erify-plugin-npm-published-runtime.test.ts | 10 +++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/scripts/verify-plugin-npm-published-runtime.mjs b/scripts/verify-plugin-npm-published-runtime.mjs index 1370dc449cb..eb9cbd64eca 100644 --- a/scripts/verify-plugin-npm-published-runtime.mjs +++ b/scripts/verify-plugin-npm-published-runtime.mjs @@ -306,12 +306,26 @@ function readPackedPackage(tarballPath, extractDir) { tar.x({ file: tarballPath, cwd: extractDir, sync: true }); const packageDir = path.join(extractDir, "package"); const packageJson = JSON.parse(fs.readFileSync(path.join(packageDir, "package.json"), "utf8")); + const files = listFiles(packageDir); return { packageJson, - files: listFiles(packageDir), + files, + readme: readPackedPackageReadme(packageDir, files), }; } +export function findPackedPackageReadmePath(files) { + return files.find((file) => /^readme(?:\.(?:md|markdown|txt|rst))?$/iu.test(file)) ?? ""; +} + +function readPackedPackageReadme(packageDir, files) { + const readmePath = findPackedPackageReadmePath(files); + if (!readmePath) { + return ""; + } + return fs.readFileSync(path.join(packageDir, readmePath), "utf8").trim(); +} + export async function verifyPublishedPluginRuntime(spec) { const workingDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-plugin-npm-runtime.")); try { @@ -326,7 +340,18 @@ export async function verifyPublishedPluginRuntime(spec) { if (errors.length > 0) { throw new Error(errors.join("\n")); } - const readme = await verifyPublishedPackageReadme(spec); + let readme; + try { + readme = await verifyPublishedPackageReadme(spec); + } catch (error) { + if (!packedPackage.readme) { + throw error; + } + console.error( + `npm readme metadata for ${spec} was unavailable; verified README from published tarball instead.`, + ); + readme = packedPackage.readme; + } return { packageName: packedPackage.packageJson.name, version: packedPackage.packageJson.version, diff --git a/test/scripts/verify-plugin-npm-published-runtime.test.ts b/test/scripts/verify-plugin-npm-published-runtime.test.ts index 80266efafa4..2b54cde29af 100644 --- a/test/scripts/verify-plugin-npm-published-runtime.test.ts +++ b/test/scripts/verify-plugin-npm-published-runtime.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from "vitest"; import { collectPluginNpmPublishedRuntimeErrors, + findPackedPackageReadmePath, parseNpmReadmeMetadata, readPositiveIntEnv, resolveNpmPackFilename, @@ -210,6 +211,15 @@ describe("resolveNpmPackFilename", () => { }); }); +describe("findPackedPackageReadmePath", () => { + it("finds a root package README without accepting nested documentation files", () => { + expect( + findPackedPackageReadmePath(["package.json", "docs/README.md", "README.md", "dist/index.js"]), + ).toBe("README.md"); + expect(findPackedPackageReadmePath(["package.json", "docs/README.md"])).toBe(""); + }); +}); + describe("parseNpmReadmeMetadata", () => { it("accepts non-empty npm readme metadata", () => { expect(parseNpmReadmeMetadata(JSON.stringify("# Plugin\n\nInstall it."))).toBe(