2026-07-22 10:55:17 +08:00
|
|
|
{
|
|
|
|
|
"name": "@deepseek-ai/dsh",
|
2026-08-06 04:40:32 +08:00
|
|
|
"description": "dsh CLI: profile boot, plugin management, and the browser UI alias",
|
2026-08-11 03:04:47 +08:00
|
|
|
"version": "0.0.1-rc.1",
|
2026-08-11 00:02:53 +08:00
|
|
|
"publishConfig": {
|
|
|
|
|
"access": "restricted"
|
|
|
|
|
},
|
|
|
|
|
"repository": {
|
|
|
|
|
"type": "git",
|
|
|
|
|
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
|
|
|
|
"directory": "apps/cli"
|
|
|
|
|
},
|
2026-07-22 10:55:17 +08:00
|
|
|
"type": "module",
|
|
|
|
|
"bin": {
|
|
|
|
|
"dsh": "lib/bin.js"
|
|
|
|
|
},
|
|
|
|
|
"files": [
|
2026-08-03 23:04:56 +08:00
|
|
|
"lib/*.js",
|
2026-08-04 22:06:32 +08:00
|
|
|
"config"
|
2026-07-22 10:55:17 +08:00
|
|
|
],
|
|
|
|
|
"license": "BSD-3-Clause",
|
|
|
|
|
"dependencies": {
|
fix(release): close the review findings on the release sequences
The root manifest carries the dsh family version. bump writes it with the
members, because the workspace constraint requires them to match, and that
constraint now accepts a prerelease segment: without both, release:dsh 0.0.2
left the root behind and 0.0.1-rc.1 could satisfy neither check.
The Landlock workflow no longer passes --access public, which overrode the
restricted publishConfig this repository just adopted for those packages.
Vendored change detection reads build inputs when a package publishes build
output, and vendor/cordis publishes the src its export map already pointed at:
its lib/ is untracked, so a real source edit read as 'nothing changed' and the
next publish would fail on a version whose bytes moved. The next version also
takes the last published version as its baseline, so a re-sync that restores a
lower upstream version cannot recompute a version already on the registry, and
bump confirms the registry carries what the newest tag names.
Tag prefixes are constructed rather than recovered from a full tag, which a
hyphenated version defeated. Pack runs group per ref so concurrent pull requests
stop displacing each other, the publish job carries the global group, and the
unused id-token permission is gone.
Every release script sits behind an entry guard, which is what lets the pure
judgements carry tests: tag naming, publish order and cycle reporting, version
arithmetic, payload policy, and the change judgement.
The Agent Note moves to implemented and states what shipped: one probe command,
the registry confirmation that now exists, and byte reproducibility recorded as
assumed rather than measured.
2026-08-11 01:26:36 +08:00
|
|
|
"@deepseek-ai/cordis-plugin-hmr": "workspace:^",
|
|
|
|
|
"@deepseek-ai/cordis-plugin-include": "workspace:^",
|
|
|
|
|
"@deepseek-ai/cordis-plugin-loader": "workspace:^",
|
|
|
|
|
"@deepseek-ai/cordis-plugin-timer": "workspace:^",
|
feat(tools): let one agent choose its tool presentation, and ship `code`
Code Mode was a deployment-wide field on the host `tools` row: a
deployment ran every session that way or none. The obvious product
shape — 代码模式 beside 标准/极简/创造 in the preset picker — had
nothing to hang on.
The registry itself cannot move into a preset; the agent loop's
scheduler, the api-proxy's presenters, and every tool plugin are its
consumers. So split the registry from its projection: `presentAs(mode)`
writes one cell on the calling agent's scope layer, exactly as
`restrict()` does, and the three reads that decided presentation take
that scope's mode instead of the service's. The config `mode` becomes
the default agents shadow rather than a process-wide fact.
Two consequences are load-bearing. `run_code` now enters a view only
for scopes whose own mode presents it — a native agent must not find it
dispatchable because another agent in the process does — and the
reserved name holds whatever the configured mode, since any agent may
select a code mode later.
`dsh-agent-tool-mode` is the row a preset carries to declare this. A
code mode waits for the host's `codeRuntime` rather than assuming it,
so a runtime-less deployment fails the preset at mount, naming the
row, instead of at the session's first request.
The shipped `code` preset is `standard` plus that row, ordered second.
2026-08-05 20:31:52 +08:00
|
|
|
"@deepseek-ai/dsh-agent-tool-mode": "workspace:^",
|
2026-07-22 10:55:20 +08:00
|
|
|
"@deepseek-ai/dsh-app-boot": "workspace:^",
|
2026-08-06 04:40:32 +08:00
|
|
|
"@deepseek-ai/dsh-base": "workspace:^",
|
2026-08-04 00:25:19 +08:00
|
|
|
"@deepseek-ai/dsh-client-ui-agent-preset": "workspace:^",
|
fix(cli): boot the composition test the way the profile boot now does
The shipped surface stopped being two yml files: `base.cordis.yml` and
`web.cordis.yml` are bundle patch layers now, applied over an empty preset
root. This test still opened the old paths, so it failed before asserting
anything. It composes the same two layers the profile boot composes, over the
same empty root, and heals the flat module fallback the way the boot does —
the root lives outside this workspace, so bare plugin names have no other way
to resolve.
The web bundle's runtime row is disabled beside the webserver: it injects
`httpServer`, so a disabled port leaves it pending forever. It owns dist
serving and the URL prompt line, neither of which decides an agent's
capabilities.
`apps/cli` declares the packages the shipped agent presets name again. The
bundle split emptied its plugin dependencies, and the flat fallback links only
the app's dependency closure — so a preset row naming `dsh-persona` resolved
to nothing, and every preset mount failed. Which packages the shipped
presets compose is not implied by any bundle: the presets live beside this
app's config, so this app is what has to declare them.
2026-08-06 21:20:56 +08:00
|
|
|
"@deepseek-ai/dsh-command-compact": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-command-goal": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-compact-basic": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-compact-tool-result-prune": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-goal": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-goal-session": "workspace:^",
|
2026-08-06 20:52:26 +08:00
|
|
|
"@deepseek-ai/dsh-cmdline": "workspace:^",
|
2026-08-09 18:23:25 +08:00
|
|
|
"@deepseek-ai/dsh-environment": "workspace:^",
|
2026-08-06 04:40:32 +08:00
|
|
|
"@deepseek-ai/dsh-headless": "workspace:^",
|
2026-07-31 01:57:19 -07:00
|
|
|
"@deepseek-ai/dsh-mcp-client": "workspace:^",
|
2026-07-22 20:45:24 +08:00
|
|
|
"@deepseek-ai/dsh-paths": "workspace:^",
|
fix(cli): boot the composition test the way the profile boot now does
The shipped surface stopped being two yml files: `base.cordis.yml` and
`web.cordis.yml` are bundle patch layers now, applied over an empty preset
root. This test still opened the old paths, so it failed before asserting
anything. It composes the same two layers the profile boot composes, over the
same empty root, and heals the flat module fallback the way the boot does —
the root lives outside this workspace, so bare plugin names have no other way
to resolve.
The web bundle's runtime row is disabled beside the webserver: it injects
`httpServer`, so a disabled port leaves it pending forever. It owns dist
serving and the URL prompt line, neither of which decides an agent's
capabilities.
`apps/cli` declares the packages the shipped agent presets name again. The
bundle split emptied its plugin dependencies, and the flat fallback links only
the app's dependency closure — so a preset row naming `dsh-persona` resolved
to nothing, and every preset mount failed. Which packages the shipped
presets compose is not implied by any bundle: the presets live beside this
app's config, so this app is what has to declare them.
2026-08-06 21:20:56 +08:00
|
|
|
"@deepseek-ai/dsh-persona": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-plan-mode": "workspace:^",
|
2026-07-31 14:28:52 +08:00
|
|
|
"@deepseek-ai/dsh-pty": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-pty-local": "workspace:^",
|
2026-08-07 00:15:55 +08:00
|
|
|
"@deepseek-ai/dsh-pwsh-local": "workspace:^",
|
2026-08-08 13:44:05 +08:00
|
|
|
"@deepseek-ai/dsh-pwsh-sandbox": "workspace:^",
|
fix(preset): keep the token meter host-plane and name unjoined agents
Moving the agent plane behind presets left two readers on the wrong side of
the host/agent line.
`dsh-token-meter` was disabled on the host and mounted inside each preset's
`compaction` realm, but its three projection units register into the
process-wide `sessionProjections` table. A unit registered from one preset
answers for every session, so whether a `minimal` session showed a context
meter depended on whether some other session had mounted `standard` since
boot, and a process that only ever ran `minimal` showed none. The meter takes
no configuration, keys every fold by Session, and registers no tool or prompt
section, so it returns to the host composition and leaves the presets'
`isolate` map; the realm and `compact-basic` stay, because what a preset
chooses is whether its agent compacts, not whether its tokens are counted.
Nothing named an agent that joined no preset. The join is a scope-parent link,
and without it the tools, prompt-section, and skill views resolve the empty
global layer: the agent publishes, the turn runs, and the model receives
nothing. `AgentPresets` now logs one warning per such agent while a roster is
configured, and the invariant companion fails outright — at
`system-prompt/assemble` rather than at publication, because an unjoined agent
is legal until it addresses a model and `recompose` binds exactly such an
agent. The warning stays advisory: a synchronous `agent/created` throw vetoes
publication, and the ACP bridge, SDK server, and headless bundle all create an
unjoined agent today.
Three limits are recorded rather than fixed: projection key presence is not a
per-session capability signal, a superseded standing generation is never
reclaimed, and a `cordis_mount` temporary plugin belongs to the composition
rather than the session that mounted it.
Fixes #2203
2026-08-10 22:36:06 +08:00
|
|
|
"@deepseek-ai/dsh-session-projection": "workspace:^",
|
2026-08-06 09:27:44 +08:00
|
|
|
"@deepseek-ai/dsh-session-reference": "workspace:^",
|
2026-08-09 16:30:11 +08:00
|
|
|
"@deepseek-ai/dsh-time-context": "workspace:^",
|
fix(cli): boot the composition test the way the profile boot now does
The shipped surface stopped being two yml files: `base.cordis.yml` and
`web.cordis.yml` are bundle patch layers now, applied over an empty preset
root. This test still opened the old paths, so it failed before asserting
anything. It composes the same two layers the profile boot composes, over the
same empty root, and heals the flat module fallback the way the boot does —
the root lives outside this workspace, so bare plugin names have no other way
to resolve.
The web bundle's runtime row is disabled beside the webserver: it injects
`httpServer`, so a disabled port leaves it pending forever. It owns dist
serving and the URL prompt line, neither of which decides an agent's
capabilities.
`apps/cli` declares the packages the shipped agent presets name again. The
bundle split emptied its plugin dependencies, and the flat fallback links only
the app's dependency closure — so a preset row naming `dsh-persona` resolved
to nothing, and every preset mount failed. Which packages the shipped
presets compose is not implied by any bundle: the presets live beside this
app's config, so this app is what has to declare them.
2026-08-06 21:20:56 +08:00
|
|
|
"@deepseek-ai/dsh-skill": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-skill-local": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tasks-local": "workspace:^",
|
2026-08-06 09:27:44 +08:00
|
|
|
"@deepseek-ai/dsh-tmux-context": "workspace:^",
|
fix(cli): boot the composition test the way the profile boot now does
The shipped surface stopped being two yml files: `base.cordis.yml` and
`web.cordis.yml` are bundle patch layers now, applied over an empty preset
root. This test still opened the old paths, so it failed before asserting
anything. It composes the same two layers the profile boot composes, over the
same empty root, and heals the flat module fallback the way the boot does —
the root lives outside this workspace, so bare plugin names have no other way
to resolve.
The web bundle's runtime row is disabled beside the webserver: it injects
`httpServer`, so a disabled port leaves it pending forever. It owns dist
serving and the URL prompt line, neither of which decides an agent's
capabilities.
`apps/cli` declares the packages the shipped agent presets name again. The
bundle split emptied its plugin dependencies, and the flat fallback links only
the app's dependency closure — so a preset row naming `dsh-persona` resolved
to nothing, and every preset mount failed. Which packages the shipped
presets compose is not implied by any bundle: the presets live beside this
app's config, so this app is what has to declare them.
2026-08-06 21:20:56 +08:00
|
|
|
"@deepseek-ai/dsh-token-meter": "workspace:^",
|
2026-08-06 09:27:44 +08:00
|
|
|
"@deepseek-ai/dsh-tool-ask-user": "workspace:^",
|
fix(cli): boot the composition test the way the profile boot now does
The shipped surface stopped being two yml files: `base.cordis.yml` and
`web.cordis.yml` are bundle patch layers now, applied over an empty preset
root. This test still opened the old paths, so it failed before asserting
anything. It composes the same two layers the profile boot composes, over the
same empty root, and heals the flat module fallback the way the boot does —
the root lives outside this workspace, so bare plugin names have no other way
to resolve.
The web bundle's runtime row is disabled beside the webserver: it injects
`httpServer`, so a disabled port leaves it pending forever. It owns dist
serving and the URL prompt line, neither of which decides an agent's
capabilities.
`apps/cli` declares the packages the shipped agent presets name again. The
bundle split emptied its plugin dependencies, and the flat fallback links only
the app's dependency closure — so a preset row naming `dsh-persona` resolved
to nothing, and every preset mount failed. Which packages the shipped
presets compose is not implied by any bundle: the presets live beside this
app's config, so this app is what has to declare them.
2026-08-06 21:20:56 +08:00
|
|
|
"@deepseek-ai/dsh-tool-bash": "workspace:^",
|
2026-07-31 14:28:52 +08:00
|
|
|
"@deepseek-ai/dsh-tool-bash-persistent": "workspace:^",
|
2026-07-30 20:25:13 +08:00
|
|
|
"@deepseek-ai/dsh-tool-cordis": "workspace:^",
|
fix(cli): boot the composition test the way the profile boot now does
The shipped surface stopped being two yml files: `base.cordis.yml` and
`web.cordis.yml` are bundle patch layers now, applied over an empty preset
root. This test still opened the old paths, so it failed before asserting
anything. It composes the same two layers the profile boot composes, over the
same empty root, and heals the flat module fallback the way the boot does —
the root lives outside this workspace, so bare plugin names have no other way
to resolve.
The web bundle's runtime row is disabled beside the webserver: it injects
`httpServer`, so a disabled port leaves it pending forever. It owns dist
serving and the URL prompt line, neither of which decides an agent's
capabilities.
`apps/cli` declares the packages the shipped agent presets name again. The
bundle split emptied its plugin dependencies, and the flat fallback links only
the app's dependency closure — so a preset row naming `dsh-persona` resolved
to nothing, and every preset mount failed. Which packages the shipped
presets compose is not implied by any bundle: the presets live beside this
app's config, so this app is what has to declare them.
2026-08-06 21:20:56 +08:00
|
|
|
"@deepseek-ai/dsh-tool-fs": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tool-fs-search": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tool-goal": "workspace:^",
|
2026-08-07 00:15:55 +08:00
|
|
|
"@deepseek-ai/dsh-tool-pwsh": "workspace:^",
|
fix(cli): boot the composition test the way the profile boot now does
The shipped surface stopped being two yml files: `base.cordis.yml` and
`web.cordis.yml` are bundle patch layers now, applied over an empty preset
root. This test still opened the old paths, so it failed before asserting
anything. It composes the same two layers the profile boot composes, over the
same empty root, and heals the flat module fallback the way the boot does —
the root lives outside this workspace, so bare plugin names have no other way
to resolve.
The web bundle's runtime row is disabled beside the webserver: it injects
`httpServer`, so a disabled port leaves it pending forever. It owns dist
serving and the URL prompt line, neither of which decides an agent's
capabilities.
`apps/cli` declares the packages the shipped agent presets name again. The
bundle split emptied its plugin dependencies, and the flat fallback links only
the app's dependency closure — so a preset row naming `dsh-persona` resolved
to nothing, and every preset mount failed. Which packages the shipped
presets compose is not implied by any bundle: the presets live beside this
app's config, so this app is what has to declare them.
2026-08-06 21:20:56 +08:00
|
|
|
"@deepseek-ai/dsh-tool-ralph": "workspace:^",
|
2026-08-08 22:39:07 +08:00
|
|
|
"@deepseek-ai/dsh-tool-schedule": "workspace:^",
|
fix(cli): boot the composition test the way the profile boot now does
The shipped surface stopped being two yml files: `base.cordis.yml` and
`web.cordis.yml` are bundle patch layers now, applied over an empty preset
root. This test still opened the old paths, so it failed before asserting
anything. It composes the same two layers the profile boot composes, over the
same empty root, and heals the flat module fallback the way the boot does —
the root lives outside this workspace, so bare plugin names have no other way
to resolve.
The web bundle's runtime row is disabled beside the webserver: it injects
`httpServer`, so a disabled port leaves it pending forever. It owns dist
serving and the URL prompt line, neither of which decides an agent's
capabilities.
`apps/cli` declares the packages the shipped agent presets name again. The
bundle split emptied its plugin dependencies, and the flat fallback links only
the app's dependency closure — so a preset row naming `dsh-persona` resolved
to nothing, and every preset mount failed. Which packages the shipped
presets compose is not implied by any bundle: the presets live beside this
app's config, so this app is what has to declare them.
2026-08-06 21:20:56 +08:00
|
|
|
"@deepseek-ai/dsh-tool-skill": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tool-str-replace-editor": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tool-subagent": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tool-subagent-control": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tool-tasks": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tool-todo": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tool-web": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tool-workflow": "workspace:^",
|
2026-08-06 04:40:32 +08:00
|
|
|
"@deepseek-ai/dsh-web-app": "workspace:^",
|
fix(cli): boot the composition test the way the profile boot now does
The shipped surface stopped being two yml files: `base.cordis.yml` and
`web.cordis.yml` are bundle patch layers now, applied over an empty preset
root. This test still opened the old paths, so it failed before asserting
anything. It composes the same two layers the profile boot composes, over the
same empty root, and heals the flat module fallback the way the boot does —
the root lives outside this workspace, so bare plugin names have no other way
to resolve.
The web bundle's runtime row is disabled beside the webserver: it injects
`httpServer`, so a disabled port leaves it pending forever. It owns dist
serving and the URL prompt line, neither of which decides an agent's
capabilities.
`apps/cli` declares the packages the shipped agent presets name again. The
bundle split emptied its plugin dependencies, and the flat fallback links only
the app's dependency closure — so a preset row naming `dsh-persona` resolved
to nothing, and every preset mount failed. Which packages the shipped
presets compose is not implied by any bundle: the presets live beside this
app's config, so this app is what has to declare them.
2026-08-06 21:20:56 +08:00
|
|
|
"@deepseek-ai/dsh-workflow-workerthread": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-workspace-context": "workspace:^",
|
2026-07-25 12:02:28 +08:00
|
|
|
"commander": "^15.0.0",
|
2026-08-11 00:16:45 +08:00
|
|
|
"@deepseek-ai/cordis": "workspace:^",
|
2026-08-03 23:04:45 +08:00
|
|
|
"js-yaml": "^4.2.0",
|
|
|
|
|
"node-addon-require-builtin": "^0.1.4"
|
2026-07-25 01:19:47 +08:00
|
|
|
},
|
|
|
|
|
"devDependencies": {
|
2026-08-07 15:33:56 +08:00
|
|
|
"@deepseek-ai/dsh-agent": "workspace:^",
|
2026-08-06 04:40:32 +08:00
|
|
|
"@deepseek-ai/dsh-frontend-static": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-host-apiproxy": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-host-webserver": "workspace:^",
|
2026-08-07 15:33:56 +08:00
|
|
|
"@deepseek-ai/dsh-llm": "workspace:^",
|
2026-08-07 21:41:22 +08:00
|
|
|
"@deepseek-ai/dsh-llm-mock-server": "workspace:^",
|
2026-08-06 04:40:32 +08:00
|
|
|
"@deepseek-ai/dsh-loader-smoke": "workspace:^",
|
2026-08-07 15:33:56 +08:00
|
|
|
"@deepseek-ai/dsh-session": "workspace:^",
|
feat(agent-presets): make the default preset a user setting
`config.default` becomes the composition base of an `agent-presets` settings
namespace, so the user document layers over the deployment's engineering
default and a person can change which preset new sessions get without a
restart.
The value is read per resolution rather than snapshotted: a hot-reloaded
document takes effect on the next session created, and every running session
stays on the preset it was composed from — which is the same rule the
session-header guard enforces from the other side.
`resolve()` read `config.default` directly, which would have made the whole
setting inert; it now goes through `defaultId` like every other caller.
The write-protection test is rewritten against a temp profile root. It was
passing vacuously: the un-overridden Loader REWRITES the composition it read —
stamping `disabled: true` onto the self-disposing row — so the committed
fixture had been mutated by the very run that proved the bug, and every later
run compared against the damaged file and passed. Building the preset in a
temp directory makes the assertion immune to its own failure mode, and it now
fails with a visible `+ disabled: true` when the override is removed.
Review follow-ups on this layer. The exported schema is
`AgentPresetSettingsSchema`, symmetric with the `AgentPresetSettings`
interface it resolves and self-describing at an import site. The `session.create`
JSDoc promised "the deployment's default preset" for an omitted `agentPreset`,
which this layer makes false — it now names the effective default. The
constructor records why it does not use `installSettingsSection`: that helper
re-judges what a consumer DERIVED across attach and detach, and nothing here is
derived. The provider-unload test disposes the fiber `ctx.plugin()` handed back
instead of reaching into `ctx.reflect.store`, and the write-protection wait says
why slack is the right shape for an absence assertion.
The real composition covers the layering too. `apps/cli` boots the shipped
`cordis.yml`, stores `agent-presets.default`, and asserts an unnamed session
composes from it — the package suite proves the layering against a hand-built
context, this proves the roster and the settings provider are wired to each
other. That test also pins the settings row at a temp file: it defaulted to
`$DSH_HOME/settings.yaml`, so a developer's own stored default decided the
outcome of a file whose whole point is that only the shipped root does.
The Agent Note records the per-resolution read and its correspondence with the
session header, and the vacuous-test finding above.
2026-08-04 00:07:11 +08:00
|
|
|
"@deepseek-ai/dsh-settings": "workspace:^",
|
fix(subagent): compose children from their parent's preset
Tool and prompt-section visibility is inherited along dsh-scope's parent
chain, and an agent's scope key is minted with no parent. Per-session agent
presets moved every model-facing row onto the agent plane and made
AgentPresets.mount() the one thing that binds that link, from the api-proxy's
session create, resume, and fork paths. The two in-process subagent drivers
installed only the per-child persona and tool filter, so a child's scope chain
had length one and its registry view resolved the global layer alone — which
is empty wherever a preset roster is composed. One-shot children reached the
model with no tools, continuable ones with only the host-plane `report`, and
neither carried its parent's persona, workspace context, or skill catalog.
AgentPresets.composeFrom() joins one agent to the standing composition another
already runs on. It is a bind, not a mount: the child gets its parent's exact
generation, so a composition edited since the parent started cannot fork it
onto another one, and it is synchronous, which is what lets a child creation
window use it. applyChildComposition() now takes the parent and performs the
join first, making a child composed without it unrepresentable at the call
sites. childSessionMeta() records the joined id so a cold read rebuilds the
composition the child actually ran under.
The audit that followed found two api-proxy readers on the wrong authority:
presenterScopeFor() and the live-agent branch of assertPresetUnchanged() both
read header.agentPreset, which goes stale the moment a blank session switches
preset. A switched session's cold transcript resolved presenters in the older
composition's layer and silently degraded to generic cards, and the gateway
refused to adopt a live session under the preset it actually runs while
accepting the one it left. Both now resolve through resolveSessionPreset(),
matching the resume branch fifteen lines above. The owning architecture Agent
Note carried the stale claim that the header records what a session runs; it
is corrected to name the header/log pair and its three readers.
Fixes #2165
2026-08-10 17:46:34 +08:00
|
|
|
"@deepseek-ai/dsh-subagent": "workspace:^",
|
2026-08-06 04:40:32 +08:00
|
|
|
"@deepseek-ai/dsh-system-prompt": "workspace:^",
|
|
|
|
|
"@deepseek-ai/dsh-tools": "workspace:^",
|
refactor(cli)!: one shared base config with per-surface overlays
`dsh` shipped two config trees that were 43 rows the same: apps/cli/cordis.yml
composed web as 74 flat rows, while the TUI booted examples/tui-agent/cordis.yml
whose single `@deepseek-ai/dsh-tui-demo` row mounted twelve plugins behind a
twenty-key pass-through Config. Neither file was what its location claimed —
apps/cli hardcoded the "example" as the product default and the "demo" bundle
was the application — and every capability change had to be made twice.
- apps/cli/base.cordis.yml holds the 43 shared rows; tui.cordis.yml and
web.cordis.yml are patch lists stating only what differs per surface
- overlays apply as SIBLING patch lists at one include level, because include
patches never cross an include boundary. Precedence: base < surface <
(--config | personal ~/.dsh/config.yaml) < launcher flag/profile patches
- `--config` now applies an overlay INSTEAD OF the personal one, so a demo or
test tree never inherits the user's route; new `--config-replace` boots a file
as the entire tree (the old `--config` behaviour). Both survive /resume
- vendor/include: index each `insert`ed row as it is added so a later patch can
configure or disable it. Upstream built the id index once before the patch
loop, leaving every surface-only row — the whole TUI front door — silently
unpatchable from user config. Logged as local modification 8
- session identity moves to dsh-agent-loop's CONFIGURED_AGENT_IDENTITIES_KEY;
dsh-tui's MAIN_SESSION_ID_KEY is deleted (only the bundle read it)
- delete examples/tui-agent, examples/cordis-agent, packages/examples/tui-demo;
TUI tests → apps/cli/tests, cordis e2e → packages/cordis/tool-cordis/tests,
examples/code-mode survives as an overlay leaf
- `dsh web` gains --config, threaded into AppCLIEntry as an extra overlay
Three latent defects surfaced and are fixed here: the TUI captured the optional
sessionQuery service once at construction and could permanently disable /resume
when it won the mount race; the session-store root silently reverted to a
project-local ./.sessions; --config-replace was dropped by the resume handoff.
Verified by booting each tree through the real Loader (TUI 55 entries, web 75,
zero unsettled) rather than reading YAML. All eight terminal snapshots replay
byte-identically; 14/14 PTY smoke, 112/112 snapshots, 25/25 doc-sync, hygiene
and lint clean.
2026-07-29 13:58:21 +08:00
|
|
|
"@types/js-yaml": "^4.0.9",
|
2026-08-04 10:07:17 +08:00
|
|
|
"execa": "^10.0.0"
|
2026-07-22 10:55:17 +08:00
|
|
|
}
|
|
|
|
|
}
|