* fix(plugin-manager): bound pnpm runs so a silent child cannot hold the profile lock A pnpm child that prints its completion line and then never exits holds the profile write lock until the host is restarted, so every other session and host on that profile fails after its own lock timeout (issue #4981). execa resolves its promise only once the piped stdio has ended, so a run now completes on the process's own exit and drains the pipes under a bound instead of awaiting their end. A service run whose captured output stays silent for idleTimeoutMs is terminated, reports timedOut alongside its exit status, and is not retried on the next registry; a run with inherited descriptors captures nothing and is left unbounded for its operator. * test(plugin-manager): type the mocked child and await the drain descendants The inherited-descriptor fixture no longer needs its legacy `as unknown` cast, because the mocked child is typed for the fields the operations read; the retired baseline entry is pruned (verify-no-unknown-casts). The drain specs wait for the killed descendant to exit before removing its directory: Windows refuses to delete a directory a live process still holds. * test(plugin-manager): stop the drain descendant deterministically The descendant that holds the pipes now ends on a stop file the teardown writes, and on its own after a minute, so the fixture leaves no process behind when a kill cannot be delivered. Windows stops it through taskkill, and the spec waits for the exit before removing the directory it ran in. * test(plugin-manager): run the drain descendant from its own script file Windows cannot carry a nested `-e` script through another spawn argument: the descendant failed to start there, so the fixture asserted on a process that was already gone. The descendant now runs from a script file the fixture writes. * test(plugin-manager): cover the bounded drain everywhere and stage the real descendant on POSIX Windows does not stage a descendant that keeps the inherited pipes open past the direct child's exit, so the real-process cases run on POSIX only. The mocked child now models execa's own completion rule — its promise settles only once both pipes end — which covers the bounded drain on every platform and still fails without the raw-exit race. * test(plugin-manager): cover the drain failure path without a child process An output consumer failure that the bounded drain cuts short is staged with the mocked child as well, so the per-file coverage gate also holds where the real-process cases are skipped. * fix(plugin-manager): terminate the whole tree of a stalled run A lifecycle script is a child of pnpm, so signalling pnpm alone left an approved postinstall writing into the profile after the operation reported a timeout and released the lock. A stalled run now stops its process group (or Windows process tree) and waits for it to disappear before the caller restores the files. The cut tail's close is told apart from a reading failure by where it happened, so a failure from before the cut still surfaces. * docs(plugin-manager): regenerate the config catalog after the rebase The English catalog gains `idleTimeoutMs` from the regenerator, and the Chinese counterpart carries the same interface line so the pair stays consistent. * fix(plugin-manager): terminate a run's tree through execa, keeping exit cleanup Spawning a service run with `detached` made execa skip the handler that kills the child when the manager exits, so a crashed manager left the pnpm tree running in the profile. `killDescendants` spawns the run as its own process group while keeping that cleanup, and it addresses the tree on every kill path, including cancellation. The module now only decides the probe target and waits for quiescence.
description, kind
| description | kind |
|---|---|
| The boot package group: how dsh app bins start — environment loading, profile and patch layers, clear startup failures, and app-owned command lines. | package-group |
boot/ — shared app-bin boot glue
English | 中文
Summary
The boot group launches profile applications and manages their installed composition. app-boot resolves configuration and starts the Loader, cmdline supplies application arguments, and plugin-manager exposes current-profile operations shared with the CLI. Each package README owns its details.
Table of Contents
Packages
| Package | Role | ctx key |
|---|---|---|
app-boot |
Boots a dsh app from a cordis.yml: loads .env, applies profile and patch layers, and reports startup failures clearly |
(library for the bins) |
cmdline |
Lets the app own its flags, --help, and exit code; passes everything after the launcher's flags through verbatim |
cmdlineArgs, appExit |
hmr |
Coordinates module and configuration reloads with package mutations | hmr |
config-editor |
Persists active profile configuration through Loader reconciliation | configEditor |
plugin-manager |
Manages current-profile plugins and bundle packages through shared CLI operations | pluginManager |
Related documentation
-
dsh app — the
dshbin that consumes these helpers for its boot sequence. -
Profile bundles — installable patch layers that
dsh --profilecompositions mount. -
dsh-home-paths — the harness-home resolver both packages build on.
-
dsh-cmdline — how an app owns its flag family instead of the launcher.
-
Profile management — service methods and result records.
Dev Note
None.