fix: respect requested pnpm version when bootstrap differs

The bootstrap pnpm binary at PNPM_HOME shadows the self-updated
binary at PNPM_HOME/bin because addPath(pnpmHome) was called after
addPath(pnpmHome/bin), giving the bootstrap higher PATH precedence.

Swap the addPath order so the self-updated binary takes priority.
The bootstrap is invoked via absolute path, so this doesn't affect
the bootstrap step.

Also extract the version from the packageManager field and pass it
to self-update explicitly, instead of returning undefined and relying
on the bootstrap's auto-switching which can modify the lockfile.

Fixes #225, fixes #227, fixes #228
This commit is contained in:
oniani1 2026-04-16 00:22:17 +04:00
parent 08c4be7e2e
commit d2a862f169
2 changed files with 11 additions and 6 deletions

BIN
dist/index.js vendored

Binary file not shown.

View File

@ -40,11 +40,13 @@ export async function runSelfInstaller(inputs: Inputs): Promise<number> {
const pnpmHome = standalone && process.platform === 'win32'
? path.join(dest, 'node_modules', '@pnpm', 'exe')
: path.join(dest, 'node_modules', '.bin')
// pnpm expects PNPM_HOME/bin in PATH for global binaries (e.g. node
// installed via `pnpm runtime`). Add it first so the next addPath
// (pnpmHome itself, which contains pnpm.exe) has higher precedence.
addPath(path.join(pnpmHome, 'bin'))
// PNPM_HOME/bin is where `pnpm self-update` places the target version
// binary. It must have higher PATH precedence than pnpmHome (which
// contains the bootstrap binary) so the self-updated version is found
// first. The bootstrap pnpm is invoked via absolute path, not PATH,
// so this ordering does not affect the bootstrap step.
addPath(pnpmHome)
addPath(path.join(pnpmHome, 'bin'))
exportVariable('PNPM_HOME', pnpmHome)
// Ensure pnpm bin link exists — npm ci sometimes doesn't create it
@ -117,9 +119,12 @@ Remove one of these versions to avoid version mismatch errors like ERR_PNPM_BAD_
return version
}
// pnpm will automatically download and switch to the right version
// Extract the version from the packageManager field so self-update
// installs it explicitly. Relying on pnpm's auto-switching can cause
// the bootstrap version to modify the lockfile when it differs from
// the target version.
if (typeof packageManager === 'string' && packageManager.startsWith('pnpm@')) {
return undefined
return packageManager.replace('pnpm@', '').split('+')[0]
}
if (devEngines?.packageManager?.name === 'pnpm' && devEngines.packageManager.version) {