The Web bundle now mounts `time-context` and `schedule` and leaves the
`ui-schedule` client row enabled, so the Automation tasks page, the Session
reminder catalog, and the `schedule_*` tools work without an overlay. Both
packages join the bundle's declared dependencies, and the example overlay is
deleted: re-inserting its rows would mount both Host plugins twice.
The fixed-rate floor drops from 300 to 60 seconds across the Host decoder,
the create and update validation, the model-visible tool schema, and the
client's per-unit floors.
Web recorded sessions and header sidecars are refreshed for the readings
`time-context` now appends; `normalizeWebSessionVolatiles` tokenizes their
sampled instant, browser zone, and elapsed duration so replay stays stable.
Review asked why the launcher special-cases one plugin's row. It no
longer does: the four shipped compositions move into the package
(presets/, in files), dsh-agent-presets resolves its own shipped root
and prepends it before configured roots (includeShippedRoot, default
true, opt-out for bare-machinery embedders), and the per-composition
derived patch, its spec, and the dump layer are deleted — profile-boot
and dump-config return to plain layer stacking. The always-load
guarantee now rides the schema default instead of patch ordering, so a
whole-config replacement keeps the shipped set and the squash, reload
freeze, and dump divergence stop being possible.
Gate globs, the web scaffold, and both preset browser lanes drop their
hand-fed shipped roots; the roster e2e keeps asserting configured roots
beside the shipped four against the built lib.
Fixes#2863.
Overlaps master on the preset e2e, the web scaffold, and the generated
config-catalog triplet; all merged textually, so the catalog is regenerated and
its pairing hashes re-recorded rather than trusted.
Adds @deepseek-ai/dsh-tool-pwsh-persistent, the mirror of
tool-bash-persistent for PowerShell: one owner-scoped persistent pwsh
per agent, an Invoke-Expression wrapper with backtick-escaped bodies and
exact native exit codes ( reset, \True fallback, catch to 1),
PSReadLine-echo tolerance (the echoed wrapper is stripped from captured
output and can never fabricate completion), and the same
timeout/cancel/exit reset semantics with pwsh-flavored diagnostics.
The minimal preset now gates its persistent shell stack by platform with
the #2234 disabled interpolation: the bash rows mount on POSIX and the
pwsh rows (pty-local shellDialect pwsh + the new tool) on win32, keeping
exactly one persistent shell per host. windows-shell.spec pins the
per-platform roster; the real Loader composition proves cwd/env
persistence, multiline and here-string commands, large-output clipping,
and exit/reset over a real ConPTY pwsh.
Drop the filler and factually loose comments added with the tool-pwsh rows:
the platform expressions self-explain, the web-app overlay comment repeats
the file header, and the spec comments now state only the platform-scoped
evaluation fact.
The service moved its "is a roster composed" reads to the derived root set;
the invariant companion still read `config.roots`. In the shape this change
exists for — an app configures nothing and the roster is the harness home
alone — that made the advisory warning fire while the fail-loud invariant
stayed silent, so an agent could address a model against an empty global
layer unchecked.
Both now read one source: `roots` exposes the resolved set, and the invariant
asks it. That decides the behavior deliberately rather than by omission — a
composition that mounts the roster now fails an unjoined agent whether its
roots were configured or derived, and `includeUserRoot: false` with no
configured roots is how a deployment keeps its agents on the host plane. Both
shapes are pinned; the derived-only case fails against the old predicate.
Three pieces of prose went stale with the first commit: the web-app bundle
comment still called the writable root an assembly fact patched in by
AppCLIEntry (removed in the profile-plugin-bundles refactor — `composeProfile`
owns it now, and only for the shipped root), and the shipped skill and its
Agent Note still called both roots "configuration". The README gains the
resolved-roster reader and the discoverable-but-undeletable preset a second
writable root produces.
The web-app overlay now disables the host tool-pwsh row too, and the shipped
presets (standard/code/cordis) declare both shell tool rows with inverted
platform gates — tool-bash on POSIX, tool-pwsh on win32 — so the preset layer
exposes exactly one shell tool per host and a preset can drop or replace the
shell tool on either platform. windows-shell.spec pins both preset gates and
both host tool rows disabled in the web composition; the loader and Windows
pwsh notes are updated in place.
The previous pass over-corrected: presenting both roots as unknowable made the
guidance vaguer without making it truer. Every `dsh` launcher puts authored
presets under `$DSH_HOME/.agent-presets`, so the skill and persona state that
as the answer to "where do my presets live" and reserve the read-back for the
path an agent actually opens or edits, which `copy()` already reports.
Neither root is a property of the preset layer. `Config.roots` defaults to `[]`;
the two the shipped agent sees are patched in by the dsh CLI, whose user root is
`dshHomePath('.agent-presets')` and whose system root ships beside the install.
`writableRoot()` then takes the first `user` root from whatever configuration
supplied it.
The skill and the persona stated `${DSH_HOME:-$HOME/.dsh}/.agent-presets/<id>/`
as where authored presets live, which is only the default install's answer, and
no call reports either root: `authorable` says whether a writable one exists,
and `list()` cannot reveal a user root that is still empty. Both now keep that
path as what to tell a user asking where to look, and direct every path an agent
acts on to `list()` or `resolve()` — which is also what `copy()` already relies
on, since it chooses the writable root itself and reports the file it created.