Without a controlling terminal, and in a concurrent recursive run of
pnpm v12, each script pnpm starts leads a process group of its own.
Since pnpm/pnpm#15564 a `sh` stood watch over each such group so that
it dies with pnpm. That doubled the processes a recursive run starts:
`pnpm -r run` over 50 projects started 100 shells, and on macOS each
bare `sh` spawn also walked PATH.
One watchdog per pnpm process now watches every group. It starts with
the first group pnpm creates. pnpm writes `+<pgid>` to its stdin when
it starts watching a group and `-<pgid>` once it is done with it. End
of input means pnpm died, and the watchdog kills every group still
listed, so the guarantee of pnpm/pnpm#15564 holds for any number of
concurrent groups. The watchdog keeps the groups in one string, so a
release costs two pattern expansions rather than a loop over every
group. A watchdog that died is replaced and takes over the groups
still watched: pacquet on its next write, pnpm v11 as soon as it exits.
Both runners change: pacquet's GroupWatch behind spawn_child, and
watchProcessGroup in pnpm v11's npm-lifecycle, whose watchdog and pipe
are unref'd so they never keep pnpm alive.
Closespnpm/pnpm#16489
---------
Co-authored-by: Zoltan Kochan <z@kochan.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>