
























@@ -661,6 +661,7 @@ function generateShrinkwrap(packageDir, options = {}) {
661661const tempDir = mkdtempSync(path.join(tmpdir(), "openclaw-shrinkwrap-"));
662662try {
663663const packageJson = JSON.parse(readFileSync(path.join(packageDir, "package.json"), "utf8"));
664+const currentShrinkwrap = readCurrentShrinkwrap(packageDir);
664665const shrinkwrapOverrides = mergeOverrides(
665666options.useCurrentShrinkwrapOverrides
666667 ? readCurrentShrinkwrapOverrides(packageDir, declaredPackageDependencies(packageJson))
@@ -683,10 +684,13 @@ function generateShrinkwrap(packageDir, options = {}) {
683684runNpm(npmInstallArgs, tempDir);
684685runNpm(["shrinkwrap", "--ignore-scripts", "--no-audit", "--no-fund"], tempDir);
685686normalizeShrinkwrapOverrides(tempDir, shrinkwrapOverrides, npmInstallArgs);
686-const generated = normalizeNpmVersionDrift(
687-applyPackageExtensionPeerMetadata(
688-JSON.parse(readFileSync(path.join(tempDir, "npm-shrinkwrap.json"), "utf8")),
687+const generated = restoreCurrentPnpmLockedPackages(
688+normalizeNpmVersionDrift(
689+applyPackageExtensionPeerMetadata(
690+JSON.parse(readFileSync(path.join(tempDir, "npm-shrinkwrap.json"), "utf8")),
691+),
689692),
693+currentShrinkwrap,
690694);
691695assertShrinkwrapMatchesPnpmLock(generated);
692696return `${JSON.stringify(generated, null, 2)}\n`;
@@ -859,6 +863,139 @@ function readCurrentShrinkwrapOverrides(
859863}
860864}
861865866+function readCurrentShrinkwrap(packageDir) {
867+try {
868+return JSON.parse(readFileSync(shrinkwrapPathForPackage(packageDir), "utf8"));
869+} catch (error) {
870+if (error?.code === "ENOENT") {
871+return null;
872+}
873+throw error;
874+}
875+}
876+877+function isStablePatchDrift(generatedVersion, currentVersion) {
878+const generatedParts = stableVersionParts(generatedVersion);
879+const currentParts = stableVersionParts(currentVersion);
880+return (
881+generatedParts !== null &&
882+currentParts !== null &&
883+generatedParts.major === currentParts.major &&
884+generatedParts.minor === currentParts.minor &&
885+generatedParts.patch !== currentParts.patch
886+);
887+}
888+889+function compareStableVersions(leftVersion, rightVersion) {
890+const left = stableVersionParts(leftVersion);
891+const right = stableVersionParts(rightVersion);
892+if (!left || !right) {
893+return null;
894+}
895+return left.major - right.major || left.minor - right.minor || left.patch - right.patch;
896+}
897+898+function versionSatisfiesSimpleSpec(version, spec) {
899+const normalized = typeof spec === "string" ? spec.trim() : "";
900+if (normalized === "" || normalized === "*") {
901+return true;
902+}
903+const match = normalized.match(/^(?<operator>\^|~|>=)?(?<version>\d+\.\d+\.\d+)$/u);
904+if (!match?.groups) {
905+return normalized === version;
906+}
907+const minimumVersion = match.groups.version;
908+const comparison = compareStableVersions(version, minimumVersion);
909+if (comparison === null || comparison < 0) {
910+return false;
911+}
912+const candidate = stableVersionParts(version);
913+const minimum = stableVersionParts(minimumVersion);
914+if (!candidate || !minimum) {
915+return false;
916+}
917+switch (match.groups.operator) {
918+case "^":
919+return minimum.major > 0
920+ ? candidate.major === minimum.major
921+ : minimum.minor > 0
922+ ? candidate.major === 0 && candidate.minor === minimum.minor
923+ : candidate.major === 0 && candidate.minor === 0 && candidate.patch === minimum.patch;
924+case "~":
925+return candidate.major === minimum.major && candidate.minor === minimum.minor;
926+case ">=":
927+return true;
928+default:
929+return comparison === 0;
930+}
931+}
932+933+function dependencySpecForLockPath(packages, lockPath, dependencyName) {
934+const packagePath = parseLockPackagePath(lockPath);
935+const parentPath = packagePath.at(-2)?.path ?? "";
936+const parent = packages[parentPath];
937+return (
938+parent?.dependencies?.[dependencyName] ??
939+parent?.optionalDependencies?.[dependencyName] ??
940+parent?.peerDependencies?.[dependencyName] ??
941+null
942+);
943+}
944+945+function restoreCurrentPnpmLockedPackages(
946+generated,
947+current,
948+pnpmLockPackages = readPnpmLockPackages(),
949+) {
950+if (!current) {
951+return generated;
952+}
953+const generatedPackages = generated?.packages;
954+const currentPackages = current?.packages;
955+if (
956+!generatedPackages ||
957+typeof generatedPackages !== "object" ||
958+!currentPackages ||
959+typeof currentPackages !== "object"
960+) {
961+return generated;
962+}
963+964+for (const [lockPath, metadata] of Object.entries(generatedPackages)) {
965+if (lockPath === "" || !metadata || typeof metadata !== "object" || !metadata.version) {
966+continue;
967+}
968+const packageName = metadata.name ?? packageNameForLockPath(lockPath);
969+if (!packageName || pnpmLockPackages.has(`${packageName}@${metadata.version}`)) {
970+continue;
971+}
972+973+const currentMetadata = currentPackages[lockPath];
974+const currentPackageName = currentMetadata?.name ?? packageNameForLockPath(lockPath);
975+if (
976+!currentMetadata ||
977+typeof currentMetadata !== "object" ||
978+!currentMetadata.version ||
979+currentPackageName !== packageName ||
980+!isStablePatchDrift(metadata.version, currentMetadata.version) ||
981+!versionSatisfiesSimpleSpec(
982+currentMetadata.version,
983+dependencySpecForLockPath(generatedPackages, lockPath, packageName),
984+) ||
985+!pnpmLockPackages.has(`${packageName}@${currentMetadata.version}`)
986+) {
987+continue;
988+}
989+990+// npm can float transitive patch ranges beyond pnpm's lock when one package
991+// name has multiple locked major lines. Keep the existing shrinkwrap entry
992+// when it still matches the canonical pnpm lock.
993+generatedPackages[lockPath] = currentMetadata;
994+}
995+996+return generated;
997+}
998+862999function assertShrinkwrapMatchesPnpmLock(shrinkwrap) {
8631000const violations = collectPnpmLockViolations(shrinkwrap);
8641001if (violations.length === 0) {
@@ -1143,6 +1280,7 @@ export {
11431280parsePnpmPackageKey,
11441281parseLockPackagePath,
11451282readShrinkwrapOverrides,
1283+restoreCurrentPnpmLockedPackages,
11461284shouldUseLegacyPeerDepsForShrinkwrap,
11471285shrinkwrapPackageDirsForChangedPaths,
11481286};
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。