Awaiting inside each arm of the scope ternary left v8 with a negative else
count on the response check, which the coverage gate read as an uncovered
branch; the request is now chosen first and awaited once. The breadcrumb
separator was a 1px filled divider where every other neutral line is 0.5px.
The duplication gate flagged three clones the plugin manager and the scoped
settings cards had grown: the bundle enable switch on a package's card and
page, the last-operation notice on the package list and a preset's section,
and the subscribe/bind/publish plumbing of CardForm and ScopedCardForms. Each
now has one owner: EnableSwitch, NoticeLine, and the ObservableForm base.
The tail dropped a whole kept chunk whenever a later chunk pushed the total
over the limit, so a flood that arrived as one read (Linux) left only the
bytes written after it. `StreamTail` trims the oldest kept chunk instead and
is unit-tested with both read patterns.
`disableBundle` now moves a package from `dsh.profile.bundles` to
`dsh.profile.disabledBundles`, and `reconcileInstalledBundles` enables only
a bundle named in neither list, so an unrelated pnpm run never re-enables a
bundle the user turned off while an update that gives a dependency
`dsh.bundle` still activates it (the built-bin e2e scenario the previous
"new dependencies only" rule broke). The record goes when its dependency
does.
Also: `visitIdentifiedRows` in patch-rows owns the per-patch restatement
tracking that compose-stack and external-bundles had cloned (duplication
gate), and the probe spec's flood fixture retries short and EAGAIN writes
because the child's stderr pipe is non-blocking once tsx touched
process.stderr (the test raced the parent's drain).
master now bounds a README Summary at 100 words; the boot group, the plugin
manager, and its host face say the same in fewer. The zh config catalog gains
the paragraph break the merge dropped.
The root entry now exports only what the CLI, the plugin inventory, the
plugin manager, and tool-cordis use, plus the parameter and result types of
those operations. The contained group and its registry, the external-layer
composition, the row-ownership helpers, the probe format number, and the
runtime option type stay module exports the package's own tests import.
The profile runtime reads user-disabled rows from the committed composition
now, so the e2e scaffold's stack carries the empty set and no longer hands the
runtime a patch reader.
The view attributes a disabled row through profileRuntime.userDisables, which
walks the groups holding the entry, and the manager spec stops passing the
runtime option the profile runtime no longer takes.
The inventory keeps dsh-app-boot an optional, type-only peer, so the walk
over an entry's owning groups moves behind ProfileRuntime.userDisables(): a
consumer with the runtime asks it, one without reports composition as before.
The module graph and the cordis catalog follow.
The probe compared two resolved URLs, which differ for one package under a
source launch (src against lib), across a symlink, and behind the proxy a
packaged executable writes; it now walks each URL up to the cordis manifest,
follows a dsh module proxy to its target, and compares real package
directories, with a probe test for the linked and the proxied case. The README
records that the probe child itself cannot run from a packaged executable.
The runtime's user-disabled row ids now come from the committed composition —
composeProfileStack collects them from the user layers it composed — so a
rejected or half-written patch file no longer makes the list disagree with the
running tree or fail to parse. The inventory attributes a row disabled through
a group the user disabled to the user, through the shared userDisablesEntry
walk, and lists a user-layer row the composition left out under the new user
trust instead of builtin.
The probe child now runs with the harness's credential-shaped variables
scrubbed — the one rule every spawner uses, now defined in
dsh-launch-environment and re-exported by dsh-subprocess — and its report is
the one message echoing a per-run token the child removes from its environment,
together with process.send, before importing anything. The failure text keeps
the last 16 KiB of stderr instead of every byte, and the probe settles only on
the child's close, so no pipe or channel outlives the call.
reconcileInstalledBundles now enables only the dependencies a run added, so
a bundle the user disabled keeps its state through an unrelated install or
removal. Row registration records the group each row is declared under: a
config override restates a row only under that group, while the same id twice
in one list or under another group is a duplicate — a contained bundle is left
out and a built-in layer fails loud, instead of the Loader rejecting the update
or moving the row at mount.