Found while evaluating 0.24.0-rc.3 in an adopter project.
Summary
link_npm() writes exactly one file — $PROJECT/.npmrc — and unlink strips only that one. But repin_npm() repins every package.json it finds.
In a repo where a sub-directory is its own install root (its own lockfile, not an npm/bun workspace member), that sub-project receives the pre-release pin but no registry configuration. Neither npm nor bun walks up parent directories for .npmrc — they read the current directory and the user-level file — so the sub-project resolves the vendor scope against the public registry and fails.
Observed
Repo with two independent roots (./ and ./<sub>/, each with its own lockfile, no workspaces). After a link that reported success:
$ cd <sub> && bun install
error: No version matching "0.24.0-rc.3" found for specifier "@metaobjectsdev/sdk" (but package exists)
error: @metaobjectsdev/sdk@0.24.0-rc.3 failed to resolve
This is exactly the notarget failure the tooling's docs warn about, reached from the opposite direction: link reports success, and the breakage surfaces only at install time inside the sub-project.
The tell
The check verb already understands sub-projects — it scanned and reported on <sub>/bun.lock. So the detector walks nested install roots while link does not. That asymmetry is the bug in one line.
Relatedly, link dropped only the root lockfile (dropped lockfile(s): bun.lock) and left the sub-project's lockfile in place, so the two roots can disagree about the resolved version.
Suggested fix
Write — and on unlink, strip — a managed .npmrc beside every manifest repin_npm actually changed; or, more conservatively, beside every directory that owns a lockfile. Each needs the same local_exclude treatment. Lockfile dropping should follow the same set.
Workaround for adopters today
After link, hand-create the same managed block in each sub-project root:
# >>> metaobjects prerelease (managed) >>>
@metaobjectsdev:registry=<registry>/api/packages/<owner>/npm/
# <<< metaobjects prerelease (managed) <<<
Note that unlink will not remove these, since it strips only $PROJECT/.npmrc — they must be deleted by hand, or the project keeps pointing at the private registry after unlinking.
Found while evaluating
0.24.0-rc.3in an adopter project.Summary
link_npm()writes exactly one file —$PROJECT/.npmrc— andunlinkstrips only that one. Butrepin_npm()repins everypackage.jsonit finds.In a repo where a sub-directory is its own install root (its own lockfile, not an npm/bun workspace member), that sub-project receives the pre-release pin but no registry configuration. Neither npm nor bun walks up parent directories for
.npmrc— they read the current directory and the user-level file — so the sub-project resolves the vendor scope against the public registry and fails.Observed
Repo with two independent roots (
./and./<sub>/, each with its own lockfile, no workspaces). After alinkthat reported success:This is exactly the
notargetfailure the tooling's docs warn about, reached from the opposite direction:linkreports success, and the breakage surfaces only at install time inside the sub-project.The tell
The
checkverb already understands sub-projects — it scanned and reported on<sub>/bun.lock. So the detector walks nested install roots whilelinkdoes not. That asymmetry is the bug in one line.Relatedly,
linkdropped only the root lockfile (dropped lockfile(s): bun.lock) and left the sub-project's lockfile in place, so the two roots can disagree about the resolved version.Suggested fix
Write — and on
unlink, strip — a managed.npmrcbeside every manifestrepin_npmactually changed; or, more conservatively, beside every directory that owns a lockfile. Each needs the samelocal_excludetreatment. Lockfile dropping should follow the same set.Workaround for adopters today
After
link, hand-create the same managed block in each sub-project root:Note that
unlinkwill not remove these, since it strips only$PROJECT/.npmrc— they must be deleted by hand, or the project keeps pointing at the private registry after unlinking.