Move @deepseek-ai/dsh-official-bundles from packages/boot to packages/util
and move the plugin manager's protected plugin list and the Web plugin
page's hidden, ordered, and experimental bundle lists into it, so editing
any of these lists no longer touches app-boot or either plugin manager
package.
Profile templates and the default, optional, on-demand, retired, and
installation-owned bundle lists move to the new data-only package
@deepseek-ai/dsh-official-bundles, so editing a bundle list no longer
touches app-boot.
* feat(experimental): ship every experimental capability as an optional bundle
dsh-base mounts the registration-only browser-use and computer-use
services; the Playwright MCP, Chrome DevTools MCP, native and MCP Cua
Driver providers, Auto review, and the Inspector become one-row bundles
listed in OPTIONAL_BUNDLES with an icon and locale display metadata.
verify-default-product-isolation requires both for every optional
bundle. Python PTC and Stagehand stay explicit compositions.
* feat(experimental): keep optional bundles inside the install closure
Drop the Playwright MCP, Chrome DevTools MCP, and native Cua Driver
bundles: each is a runtime dependency of every install and would add
about 85 MB of provider runtimes whether or not enabled. dsh-browser-use
leaves dsh-base with them. The three packages keep their locale display
metadata for component rows.
* feat(experimental): drop the Cua Driver MCP bundle and leave dsh-base untouched
* test(web): refresh Official-group goldens for the four optional bundles
* fix(plugins): use an uninstalled bundle as the install example and pin optional-bundle metadata
The install guide's example is now @deepseek-ai/dsh-subagent-codex,
a published bundle no shipped profile carries, since Auto review is an
installed optional bundle. The optional-bundle spec guards its corpus and
pins each bundle's title, description, and icon in both languages; the
Inspector's Loader test mounts its real bundle patch, its Client names
the reload a hot-enabled page needs, and its description states the
loopback DevTools endpoint's reach.
* test(web): refresh GitHub install recovery placeholder snapshot
* feat(preset): declare Agent compositions in profile YAML
* fix(preset): share scope binding cleanup and refresh module graph
* fix(preset): use host syntax colors in the YAML editor
* fix(preset): write new profile declarations as block YAML
* fix(preset): align eager activation with browser and worker surfaces
* fix(ui-agent-preset): retain the existing preset card layout
* fix(preset): keep rows waiting for a Host service mounted and re-audit after settlement
A preset row whose Host provider was still activating at declaration time
was reported as waiting for a missing service, and the registry recorded the
definition as broken for the rest of the process. Split the mount audit into
failed and pending rows: failures and root-realm leaks still reject the
mount, while pending rows stay mounted and every read and binding re-audits
them after the Host Loader tree settles.
Remove the accidental self-dependency of @deepseek-ai/dsh-web-app and its
lockfile self-link. Archive the copy-only preset authoring note, which the
declarative-preset note fully supersedes, and update the ralph note's
restore recipe to the profile-patch mechanism.
* chore(lint): re-key and prune the unknown-cast baseline after the master merge
* refactor(web-app): ship each Agent preset as its own bundle patch file
`dsh.bundle.patch` accepts an ordered file list, so the four shipped preset
declarations move out of the 1000-line web patch into
`presets/<id>.patch.yml`, one insert per file, applied after the host patch.
The host patch keeps the preset registry row. Gates and test scaffolds that
read the web layer resolve every patch file through `bundlePatchPaths`
instead of one hardcoded path.
* refactor(preset): drop the save notice injected into live Agents
The notice duplicated the save result the Web editor already shows, and
after the producer-owned message sources it would have needed its own
persisted source kind. Saving now only persists and reports the activation
diagnostic; the persistence catalog is unchanged from master.
* docs: regenerate the module graph after dropping the registry's llm dependency
* test(ui-agent-preset): cover the guide dialog's keyboard handling on the declarative section
* fix(preset): address the remaining review comments
Apply the lowercase id rule only when creating a declaration, so presets
declared with other ids stay editable. Export `isBuiltInPreset` from the
display fold and key the client card groups on it. Remove the dead `error`
and `retry` locale keys, the JSDoc orphaned by the `trust` removal, the
`trust` fields in the plugin-inventory test fixtures, and the stale
`dsh-agent-presets` package name in comments and READMEs.
* refactor(preset): make the Web preset page view-and-select only
Remove the child-plugin YAML editor, the `agent_preset` tool and the
registry's read/save Remote methods. Presets are declared and changed only by
bundle patches; the settings page keeps the roster, the new-task default and
the mode help, and its question icon explains that and offers to start a
Creator-mode task. The `editing-cordis-compositions` skill and the Creator
persona describe the bundle-based path, and the authored skill-load Session
and Web snapshots are refreshed for it.
* docs(skill): make the composition skill self-sufficient for preset authoring
State where the shipped declarations live, list every declaration field,
inline a complete minimal bundle and an override example, and name the
verification calls, so Creator mode no longer reads DSH package sources to
infer the format. Refresh the authored skill-load Session for the new text.
* test(tools): drop the removed agent_preset tool from the catalog expectation
* feat(bundle): accept an ordered patch file list in dsh.bundle.patch
`dsh.bundle.patch` now accepts `string | string[]`. A list names patch
files applied in order as one bundle layer; each file's relative plugin
paths still resolve beside that file. `bundlePatchPaths` in dsh-app-boot
is the one resolver from a declaration to absolute paths, and every
reader uses it: profile loading, plugin-manager reconcile and bundle
rows, the client-runtime roster, and the workspace, cordis-config, and
product-isolation gates. `ProfileLayer.patchPath` becomes `patchPaths`.
* fix(bundle): keep declared patch files package-relative in the workspace gate
path.join produced backslash entries on Windows, so the expected files
list did not match package.json files. bundlePatchFiles returns the
validated declaration as written; bundlePatchPaths joins it.
OPTIONAL_BUNDLES in app-boot lists the bundles the installation ships
switched off; the plugin manager, the default-product isolation gate,
the workspace constraints, and the packed-install check read that one
list instead of a dsh.optionalBundles field in apps/cli/package.json.
The dsh installation lists under `dsh.optionalBundles` the bundles it
ships for a person to switch on. The plugin manager reports them as
`optional`, and the Web plugin page shows them first, in a built-in
group with an official tag, off until selected and never removable.
Agent Teams ships this way, so a blank profile offers both of its
layers. Default-product isolation, the workspace constraints, and the
packed-install check accept that one dependency edge and nothing else
experimental.
A bundle's title and one-liner come from `dsh.title` and the new
`dsh.description`, else from the package name and `description`. A
dependency without a bundle patch is no longer listed unless the
profile selects it. The install dialog asks for a package name or
address; a guide under the field shows the three accepted forms with
an example each and ends in a security warning, and the copy no longer
speaks of a plugin ID.