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.
Reject case variants of shipped profile names, detect a concurrent winner by
the target's state instead of errno, warn instead of failing when staging
cleanup fails after a successful replacement, and cover the restore paths with
deterministic tests. Update the profile Agent Note, reference recovery path,
and upgrade-guide migration steps.
Repeated rescue runs such as `dsh rescue --from-default-profile web` failed
because the target profile already existed. The option now assembles a fresh
template copy in a staging directory, moves it over the target, and deletes the
previous profile; a failed move restores it.
`collectCliHelp` stops propagating an alias when it reaches a page
already on the current path, so a `help [command]` row that prints its
parent's help no longer recurses until the stack overflows. `serve|s`
command rows are split into separately collected names.
The CLI reference and upgrade guide describe the forwarded-argument
boundary that Commander applies, including a leading pnpm option, and
args.spec.ts pins that `--profile` placed after a leading pnpm option is
forwarded. Generated pages use the repository's two-line generated
header, and docs/AGENTS.md lists the CLI help among the generated
references.
Refs #4114
`scripts/gen-cli-help.ts` runs the source `dsh` launcher with temporary
Harness and Agents homes and captures the launcher, `dsh plugin`, and every
shipped profile's text help (profile names come from `PROFILE_TEMPLATES`).
It recursively discovers subcommands from each page's `Commands:` section,
shows identical alias help once with every invocation, and writes
`docs/cli-help.md`, its Chinese page, and their pairing record. The record
resolves links between the two pages as written, so a first run already
matches `verify-translation-pairing`. `verify-cli-help` checks all three
files and runs as the `cli-help` doc-sync leaf, which the static CI lane
also runs on an unbuilt tree.
`dsh plugin` now owns `-h`/`--help` and reads its own options only before
the forwarded pnpm arguments: `dsh plugin --help` prints its help instead of
failing on the missing `--profile`, while everything after the pnpm command
(including `-h`, `--help`, and `--profile`) reaches pnpm verbatim. A
`--profile` placed after the pnpm command is no longer accepted; the
v0.2.1-alpha.1 upgrade guide covers the migration.
Refs #4114
skippedProfileBundles recomputed the selected-minus-loaded bundle set from
the manifest, a second home for what loadProfileDirectory already records.
Runtime resolution and generateConfigSchema now read
profile.skippedBundles, so generateConfigSchema no longer reads the profile
manifest and drops its binName parameter.
loadProfileDirectory printed each skipped bundle on every call, and startup,
runtime resolution, the config editor, the plugin manager, and HMR all load
the profile, so one incompatible bundle printed the same warning six times at
startup and again on each Web page load. Loading now returns the skips in
Profile.skippedBundles, and the CLI and Desktop launchers print them once per
start with reportSkippedBundles.
Compatibility checks now yield the refused packages as data instead of a
profile-specific sentence. runProfilePnpm returns them as
PackageResult.incompatible, and the plugin manager refuses with the
incompatible-version code carrying the same records. Each surface renders
them: the CLI prints the exact allow-version command for its profile, the
Web plugin manager words them through its locale dictionary, and app-boot
keeps one neutral English diagnostic for logs and startup stderr.
A bundle package is not a plugin row, so startup admission never read its
own DSH peers: a bundle installed outside DSH or before a DSH upgrade still
applied its patch layer. loadProfileDirectory now skips such a bundle like an
unreadable one unless the profile exempts that exact pair.
A post-install refusal in a profile without a lockfile reinstalls from the
restored manifest instead of failing a frozen install and leaving the
rejected packages in node_modules.
Compatibility warnings now name the `dsh plugin allow-version` command for
CLI-managed profiles, startup denials name the row id instead of a resolved
module URL, and the CLI no longer reports "pnpm failed" when pnpm never ran.
* feat(cli): dump native Cordis config schemas
* test(cli): include schema dump in launcher help snapshot
* feat(cli): export JSON Schema for Cordis configuration
* fix(cli): preserve config schema discovery and annotations
* fix(cli): conservatively project effectful config validation
* refactor(boot): encapsulate profile config schema generation
* fix(cli): follow Loader disabling and native writeback in config schema
- Dormant group/include rows (disabled without group: true) may omit
config and are recorded as childless trees; the entry schema skips
their child declarations, matching the Loader, which never creates them.
- Lazy builders run once per document, and a wrapped null-only projection
keeps a deduplicated type list so the document stays compilable.
- Union widening applies only when an earlier branch can write adapted
values back through a container; +Infinity max and -Infinity min
without a step are treated as the native no-ops they are.
- Projection limitations repeat at every entry sharing a Config, and the
entry schema documents the boolean/expression domain of disabled.
- Record the schema-dump validation policy as an Agent Note.
The Consumer-owned strictness bullet names the Loader subtree that agent presets own instead of the runtime resolution; the service field, its file comment, the dispose JSDoc, and the route JSDoc use interception; the native-after-interception route documents both anchors it can carry; stale module-fallback comments name the runtime resolution; importFromResolution matches its parameter.
Move exact user-patch watching into app boot and audit activation explicitly.
Wait for CLI fallback HMR and preset subtrees. Join the first fiber-disposal
result in the directory chooser and browser package runner. Keep async
update errors observable without restoring generic Loader rollback.
Restore the current workspace-link and Schemastery manifests and their gate.
Preserve unconditional patch-input cloning, awaited Include initialization,
and durable teardown writes. Update diagnostics, snapshots, bilingual docs,
and the exhaustive vendor divergence ledger.
Validation: focused Loader, watcher, preset, inventory, and cleanup tests;
100% watcher coverage; 32 Web preset cases; real CLI webhook model session;
SDK smokes; 13 headless expected cases; 3 recorded-session replays; build,
typecheck, lint contracts, and all 34 doc-sync gates.
A full Node 24/Python 3.12 Vitest run had 21806 passes and two failures:
a baseline-reproduced experimental CSS import failure and a Python probe
timeout that passed alone. The default Node 26/Python 3.9 run additionally
exposed unsupported Python and FileHandle-GC host failures.