From eefd6248f4bcbc9edc1e7e9efbebac6181d2e98e Mon Sep 17 00:00:00 2001 From: Vincent Koc <25068+vincentkoc@users.noreply.github.com> Date: Fri, 10 Jul 2026 16:53:38 -0700 Subject: [PATCH] fix(release): manage tracked private shrinkwraps --- extensions/vault/npm-shrinkwrap.json | 4 ++-- scripts/generate-npm-shrinkwrap.mjs | 21 ++++++++++++-------- test/scripts/generate-npm-shrinkwrap.test.ts | 7 +++++++ 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/extensions/vault/npm-shrinkwrap.json b/extensions/vault/npm-shrinkwrap.json index 0ca13c30be41..6f4bf185acf4 100644 --- a/extensions/vault/npm-shrinkwrap.json +++ b/extensions/vault/npm-shrinkwrap.json @@ -1,12 +1,12 @@ { "name": "@openclaw/vault", - "version": "2026.6.2", + "version": "2026.6.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@openclaw/vault", - "version": "2026.6.2" + "version": "2026.6.11" } } } diff --git a/scripts/generate-npm-shrinkwrap.mjs b/scripts/generate-npm-shrinkwrap.mjs index 8a84fa7d0482..327564b31399 100644 --- a/scripts/generate-npm-shrinkwrap.mjs +++ b/scripts/generate-npm-shrinkwrap.mjs @@ -1080,9 +1080,11 @@ function shrinkwrapPathForPackage(packageDir) { return path.join(packageDir, "npm-shrinkwrap.json"); } -function listPublishablePluginPackageDirs() { +function listManagedShrinkwrapPackageDirs() { // Published workspace packages (packages/*) ship npm-shrinkwrap.json just // like publishable plugins so their transitive dependency tree stays pinned. + // Keep any already-tracked shrinkwrap managed too, including private packages, + // or version alignment can leave that release metadata silently stale. return ["extensions", "packages"] .flatMap((parentDir) => readdirSync(path.join(ROOT_DIR, parentDir), { withFileTypes: true }) @@ -1095,14 +1097,17 @@ function listPublishablePluginPackageDirs() { return false; } const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")); - return packageJson.openclaw?.release?.publishToNpm === true; + return ( + packageJson.openclaw?.release?.publishToNpm === true || + existsSync(shrinkwrapPathForPackage(path.join(ROOT_DIR, packageDir))) + ); }) .toSorted((left, right) => left.localeCompare(right)); } function shrinkwrapPackageDirsForChangedPaths(changedPaths) { const packageDirs = new Set(); - const publishablePluginPackageDirs = new Set(listPublishablePluginPackageDirs()); + const managedShrinkwrapPackageDirs = new Set(listManagedShrinkwrapPackageDirs()); let hasAmbiguousDependencyPolicyChange = false; let hasLockfileChange = false; @@ -1121,7 +1126,7 @@ function shrinkwrapPackageDirsForChangedPaths(changedPaths) { const workspacePackageMatch = changedPath.match( /^((?:extensions|packages)\/[^/]+)\/(?:package\.json|npm-shrinkwrap\.json)$/u, ); - if (workspacePackageMatch && publishablePluginPackageDirs.has(workspacePackageMatch[1])) { + if (workspacePackageMatch && managedShrinkwrapPackageDirs.has(workspacePackageMatch[1])) { packageDirs.add(path.resolve(ROOT_DIR, workspacePackageMatch[1])); continue; } @@ -1140,14 +1145,14 @@ function shrinkwrapPackageDirsForChangedPaths(changedPaths) { if (hasAmbiguousDependencyPolicyChange) { return [ ROOT_DIR, - ...listPublishablePluginPackageDirs().map((dir) => path.resolve(ROOT_DIR, dir)), + ...listManagedShrinkwrapPackageDirs().map((dir) => path.resolve(ROOT_DIR, dir)), ]; } if (hasLockfileChange) { return [ ROOT_DIR, - ...listPublishablePluginPackageDirs().map((dir) => path.resolve(ROOT_DIR, dir)), + ...listManagedShrinkwrapPackageDirs().map((dir) => path.resolve(ROOT_DIR, dir)), ]; } return [...packageDirs].toSorted((left, right) => @@ -1258,7 +1263,7 @@ export function resolvePackageDirs(args) { jobs, packageDirs: [ ROOT_DIR, - ...listPublishablePluginPackageDirs().map((dir) => path.resolve(ROOT_DIR, dir)), + ...listManagedShrinkwrapPackageDirs().map((dir) => path.resolve(ROOT_DIR, dir)), ], }; } @@ -1267,7 +1272,7 @@ export function resolvePackageDirs(args) { check, changedPaths: check ? listCheckChangedPaths() : [], jobs, - packageDirs: listPublishablePluginPackageDirs().map((dir) => path.resolve(ROOT_DIR, dir)), + packageDirs: listManagedShrinkwrapPackageDirs().map((dir) => path.resolve(ROOT_DIR, dir)), }; } if (changed) { diff --git a/test/scripts/generate-npm-shrinkwrap.test.ts b/test/scripts/generate-npm-shrinkwrap.test.ts index 57593f465100..0e330a50a573 100644 --- a/test/scripts/generate-npm-shrinkwrap.test.ts +++ b/test/scripts/generate-npm-shrinkwrap.test.ts @@ -491,6 +491,12 @@ describe("generate-npm-shrinkwrap", () => { ).toEqual(["extensions/acpx"]); }); + it("targets changed tracked shrinkwraps for private packages", () => { + expect( + shrinkwrapPackageDirsForChangedPaths(["extensions/vault/package.json"]).map(repoRelativePath), + ).toEqual(["extensions/vault"]); + }); + it("falls back to every shrinkwrap when lockfile ownership is ambiguous", () => { const packageDirs = shrinkwrapPackageDirsForChangedPaths(["pnpm-lock.yaml"]).map( repoRelativePath, @@ -498,6 +504,7 @@ describe("generate-npm-shrinkwrap", () => { expect(packageDirs).toContain(""); expect(packageDirs).toContain("extensions/acpx"); + expect(packageDirs).toContain("extensions/vault"); }); it("falls back to every shrinkwrap when mixed lockfile changes do not map to packages", () => {