feat(cli): auto-migrate pnpm-workspace.yaml on resolution failure (#34993)
Deno deliberately does not read `pnpm-workspace.yaml` during module
resolution. A project whose workspace members (or catalog versions) live
in that file therefore fails to resolve, and the baked-in error ("did you
forget to run `deno install`?") sends the user in circles.
Instead of adding a dedicated subcommand for a single package manager,
this handles pnpm automatically on the failure path. When a command exits
with a workspace/npm resolution error and a `pnpm-workspace.yaml` is found in
the cwd or an ancestor, Deno converts its `packages`, `catalog`, and `catalogs`
into the equivalent config fields and prints a note telling the user to run
the command again:
```
error: Could not find package.json with name '@scope/lib' in workspace.
warning: Found pnpm-workspace.yaml nearby, which Deno does not read directly.
hint: Migrated its workspace configuration into package.json. Run the command again.
```
The second run resolves normally. npm, Yarn, and Bun workspaces already
work out of the box because they store their globs in
`package.json#workspaces`; pnpm is the only major
package manager that uses a separate file, which
is why it is the lone case that needs this bridge.
The migration prefers `package.json`. A pnpm project already keeps its
config there, and Deno reads `workspaces`, `catalog`, and `catalogs` from it
natively (top-level `catalog`/`catalogs` even take precedence), so the project's
config stays in one file. It falls back to `deno.json`/`deno.jsonc` only when
there is no `package.json` next to the `pnpm-workspace.yaml`.
The conversion preserves existing comments and formatting via the jsonc
CST and never overwrites fields the user already set, so re-running is a no-op
once the configuration is in place (no migration loop). Keys with no equivalent
in Deno (`overrides`, `patchedDependencies`, `registries`, ...) are listed in a
note rather than silently dropped. YAML parsing reuses the in-tree
`yaml_parser` crate that `deno fmt` already uses, so no new dependency family is
added.
Implementation lives in `cli/util/pnpm_workspace.rs` and is invoked from
`exit_for_error`, the single chokepoint every subcommand's errors pass
through (it formats both Rust errors and downcast JS errors), so the detection
is entirely off the resolution hot path. This run-it-again flow replaces
the earlier `deno migrate pnpm` subcommand and its separate
resolution-failure hint.
Closes #29786.