Found while evaluating 0.24.0-rc.3 in an adopter project.
Two related defects in how link finishes up: it deletes tracked lockfiles, and the guidance it prints afterwards is npm-only even when the project is bun-managed. Together they push an adopter into swapping package manager as a side effect of trying a pre-release.
1. link deletes lockfiles that are tracked, without warning
The script is careful about tracked files everywhere else. .npmrc, NuGet.config and .mvn/* go into .git/info/exclude; pyproject.toml and pom.xml get a loud warning precisely because they are tracked by definition:
! pom.xml is tracked by definition — the managed block is committable; 'unlink' removes it
Lockfiles get neither. They are simply removed:
dropped lockfile(s): bun.lock
bun.lock / package-lock.json are tracked in essentially every real project, so this is a destructive edit to committed state, reported in the same neutral tone as the configuration changes — and, unlike the managed blocks, it is not something unlink can put back.
Observed across three install roots:
$ git status --short
D <app>/bun.lock
D <console>/bun.lock
D <scripts/docs>/bun.lock
Why it matters beyond the deletion
Dropping the lockfile turns a targeted pin into a full dependency re-resolution. For evaluating a pre-release that is the wrong default: it mixes "does the RC work" with "does a fresh resolve of every unrelated transitive dependency work", and any breakage lands in the same diff.
Restoring the lockfiles first and letting the package manager reconcile the changed manifest gives a much cleaner test. Doing that here moved exactly the 16 vendor packages and nothing else:
$ git checkout -- <app>/bun.lock && bun install
+ @metaobjectsdev/cli@0.24.0-rc.3
... 10 packages ...
16 packages installed
2. The post-link instructions assume npm
link always prints:
npm rm -f package-lock.json && npm install
For a bun-managed project (a bun.lock, no package-lock.json) following that literally runs npm install, which creates a package-lock.json beside the deleted bun.lock and silently migrates the project to a different package manager and a different resolution. The .npmrc the script writes is read by both tools, so the install succeeds — it just quietly leaves the repo on npm.
Since link has already detected the lockfile — it names it in dropped lockfile(s): bun.lock — it has everything it needs to print the right command.
Suggested fix
- Do not delete lockfiles by default. Prefer repin-then-reconcile (
bun install / npm install against the edited manifest), which is both less destructive and a better-isolated test. If a clean re-resolve is genuinely wanted, put it behind a flag.
- If a lockfile is deleted, warn when it is tracked, in the same register as the
pom.xml / pyproject.toml warnings, and say that unlink cannot restore it.
- Derive the printed install command from the lockfile already detected:
bun.lock → bun install, pnpm-lock.yaml → pnpm install, yarn.lock → yarn, else npm.
Related
#325 notes the lockfile-dropping set is inconsistent across nested roots. This issue is about the dropping itself (tracked-file destruction) and the manager-specific guidance, rather than which roots it reaches.
Found while evaluating
0.24.0-rc.3in an adopter project.Two related defects in how
linkfinishes up: it deletes tracked lockfiles, and the guidance it prints afterwards is npm-only even when the project is bun-managed. Together they push an adopter into swapping package manager as a side effect of trying a pre-release.1.
linkdeletes lockfiles that are tracked, without warningThe script is careful about tracked files everywhere else.
.npmrc,NuGet.configand.mvn/*go into.git/info/exclude;pyproject.tomlandpom.xmlget a loud warning precisely because they are tracked by definition:Lockfiles get neither. They are simply removed:
bun.lock/package-lock.jsonare tracked in essentially every real project, so this is a destructive edit to committed state, reported in the same neutral tone as the configuration changes — and, unlike the managed blocks, it is not somethingunlinkcan put back.Observed across three install roots:
Why it matters beyond the deletion
Dropping the lockfile turns a targeted pin into a full dependency re-resolution. For evaluating a pre-release that is the wrong default: it mixes "does the RC work" with "does a fresh resolve of every unrelated transitive dependency work", and any breakage lands in the same diff.
Restoring the lockfiles first and letting the package manager reconcile the changed manifest gives a much cleaner test. Doing that here moved exactly the 16 vendor packages and nothing else:
2. The post-link instructions assume npm
linkalways prints:For a bun-managed project (a
bun.lock, nopackage-lock.json) following that literally runsnpm install, which creates apackage-lock.jsonbeside the deletedbun.lockand silently migrates the project to a different package manager and a different resolution. The.npmrcthe script writes is read by both tools, so the install succeeds — it just quietly leaves the repo on npm.Since
linkhas already detected the lockfile — it names it indropped lockfile(s): bun.lock— it has everything it needs to print the right command.Suggested fix
bun install/npm installagainst the edited manifest), which is both less destructive and a better-isolated test. If a clean re-resolve is genuinely wanted, put it behind a flag.pom.xml/pyproject.tomlwarnings, and say thatunlinkcannot restore it.bun.lock→bun install,pnpm-lock.yaml→pnpm install,yarn.lock→yarn, else npm.Related
#325 notes the lockfile-dropping set is inconsistent across nested roots. This issue is about the dropping itself (tracked-file destruction) and the manager-specific guidance, rather than which roots it reaches.