SIGN IN SIGN UP

fix(arborist): surface undeclared workspaces under the linked strategy (#9657)

In continuation of our exploration of using `install-strategy=linked` in
the [Gutenberg
monorepo](https://github.com/WordPress/gutenberg/pull/75814), which
powers the WordPress Block Editor.

Under `install-strategy=linked`, a declared workspace that the root does
not depend on is installed on disk but was invisible to `npm ls --all`,
`npm ls --workspaces`, and `npm query ':root > *'`, all of which
reported an empty tree. The hoisted strategy lists every workspace.

Undeclared workspaces are intentionally not symlinked into the root
`node_modules` under the linked strategy, so when `loadActual` rebuilds
the actual tree (from the filesystem scan or the hidden lockfile,
neither of which records a `node_modules/<ws>` entry) the root's
`workspace` edges resolve to nothing and the workspaces drop out of the
tree that `ls` and `query` traverse. `npm ls` then hid those missing
edges entirely to avoid a false `UNMET DEPENDENCY`.

The fix adds `loadActual` post-processing that, for the linked strategy,
synthesizes an in-memory `Link` at `node_modules/<ws>` for each
undeclared workspace so its root edge resolves, matching the logical
layout the regular `package-lock.json` already records. This is
introspection-only and writes nothing to disk. A declared workspace
whose root link is genuinely missing is left alone so it still reports
`UNMET`, an existing root child of the same name is never replaced, and
a workspace that was not loaded is skipped. With the edges now
resolving, the workspace-skip branch that `npm ls` used to suppress them
is removed.

## References

Fixes #9618
M
Manzoor Wani committed
ae6dbeb12a6f4b313a28c99068e34ba834ae91d1
Parent: 0c33947
Committed by GitHub <noreply@github.com> on 6/25/2026, 8:14:07 PM