fix(install): run workspace member dependency lifecycle scripts with member INIT_CWD (#34700)
## Problem
The `postinstall` script of a third-party dependency of a workspace
member that
has a `package.json` does not produce its expected output. Reported in
denoland/deno#25417 (repro:
[zemili-group/moonrepoV3](https://github.com/zemili-group/moonrepoV3),
`deno install --allow-scripts` then `deno task dev` in
`apps/zemili/frontend`,
which fails with `Cannot find base config file
"./.svelte-kit/tsconfig.json"`).
The script itself *does* run on current `main`, but with `INIT_CWD`
pointing at
the directory `deno install` was invoked from — the workspace root. Many
workspace-aware lifecycle scripts use `INIT_CWD` to locate the
project(s) to set
up. `@sveltejs/kit`'s `postinstall` reads `INIT_CWD`'s `package.json`
and its
`workspaces` field to discover the projects, then runs `svelte-kit sync`
for
each (generating `.svelte-kit/tsconfig.json`).
In a `deno.json`-rooted workspace there is **no** root `package.json`
with a
`workspaces` field, so the script finds nothing at `INIT_CWD` and
silently does
nothing — the member's `.svelte-kit/` is never created.
## Fix
Run a dependency's lifecycle scripts **once per workspace member that
declares
it as a direct dependency**, with `INIT_CWD` set to that member's
directory.
This reproduces what npm/svelte-kit would do via a root `package.json`
`workspaces` field, which a `deno.json` workspace lacks.
- New helper `member_dep_init_cwds()` builds a map of package id → the
member
directories that declare it directly (from `NpmInstallDepsProvider`'s
`remote_pkgs`, resolved through the snapshot).
- `PackageWithScript` carries `init_cwds: Vec<PathBuf>`; the executor
loops over
them (falling back to the global init cwd when empty), wired through
both the
local and hoisted node_modules linkers.
- Packages declared directly by the workspace root keep running once
with the
global init cwd (npm's behaviour).
Verified end-to-end against moonrepoV3: `@sveltejs/kit`'s `postinstall`
now runs
once per consuming member and `.svelte-kit/tsconfig.json` is generated
in both
`apps/zemili/frontend` and `apps/opsap/clients/frontend`.
### Note / trade-off
A dependency declared by multiple members now has its scripts run once
per
member. For scripts that ignore `INIT_CWD` (e.g. native builds into the
package's own folder) this is some redundant work, but it is required
for
workspace-aware scripts to set up each member. `esbuild` is already
special-cased and skipped.
## Test
Adds `tests/specs/install/workspace_member_dep_lifecycle_init_cwd` with
a new
registry package `@denotest/lifecycle-scripts-init-cwd` whose
`postinstall`
writes a marker into `$INIT_CWD`. The test asserts the marker lands in
each
declaring member directory, not the workspace root.
Closes #25417
Closes denoland/divybot#413
Co-authored-by: divybot <divybot@users.noreply.github.com>
Co-authored-by: Divy Srivastava <me@littledivy.com>