The smoke's inline Python pty driver only ran on POSIX (no termios on
Windows). Rebuild every scenario — banner sweep, scripted conversation with
model switch, /skill:, Code Mode overlay, resume failure, and the dsh CLI
suite (default boot, personal overlay, invalid overlay, --resume flag,
source-path prompt) — as marker-gated action lists on pty-harness.ts, which
drives ConPTY via node-pty on Windows and the Python driver elsewhere. The
harness gains configArgs (bins with built-in default configs), prepare
(workspace seeding), and inspect (post-run log assertions); examples/
declares the session-title provider the shipped cordis.yml now mounts.
Master's log-backed session-title capability already titles sessions durably
(deterministic fallback in the spine, optional model providers). Remove the
TUI's own autoTitle generation — the latch, prompt, cap, and llm stream call —
and keep the terminal rename: the TUI folds the logged title on mount and sets
'<session title> — <configured title>' on every accepted session/title event.
The tui-agent example and the scripted PTY fixture mount
session-title-first-message-llm so titles stay model-made; the scripted
adapter's tool-less branch now answers that provider's auxiliary request.
See .agents/notes/implemented/simplification/2026-07-22-tui-titles-from-session-title-service.md
The acp escalation smoke advertises the shipped deepseek-v4-pro; the
workspace-context e2e asserts the per-candidate scope key. The PTY harness
drops COLORTERM (deterministic banner) and gains configArgs/prepare/inspect
for the dsh CLI scenarios.
Replace /mode [name] with same-named no-argument commands such as /plan. Update the TUI and ACP snapshots, and validate mode names against command syntax.
The built-bin fail-loud test needs the TTY refusal before Loader boot (a
compose-time throw is logged per-entry, not rethrown); the PTY driver drops
COLORTERM so a developer's truecolor shell cannot flip the banner to the
gradient path mid-assertion; the scripted fixture persists raw JSONL so the
smoke's system-prompt inspection can read the log.
- acp/headless whole-config snapshot patches restate persistenceCompression:
none so raw JSONL fixtures stay harvestable, and re-pin the recorded
deepseek-v4-flash where the shipped config moved to pro
- depth-two overlay gains the app-config re-pin master's other overlays carry
- headless-agent stays on flash: goal/ralph overlays include it via a nested
include, which a config patch cannot reach to re-pin
- workspace-context scenarios re-record their session fixtures for the
per-candidate scope keys and both-siblings loading; acp session fixtures
otherwise return to master's (session/title + delegationDepth events)
Make todo_write opt-in for the tui-agent example (disabled by default; TUI
still renders plans when the tool is loaded). Both enabled and disabled cases
covered by tests.
Squashes three linearized steps (feat/tui-startup, feat/banner-reveal,
feat/remove-banner): the banner experiment converged on removing the
startup banner entirely; later commits restore it borderless and add the
brand gradient.
Squash of the linearized fix/tui-color-scheme-v2 merge and the follow-up
catalog regeneration. Renders error cause chains at every diagnostic seam
(origin/fetch-failed-diagnostics) and adds color scheme detection with a
light-terminal palette.
Delete packages/ui/stdio and examples/repl-agent; rename stdio-demo to
@deepseek-ai/dsh-tui-demo (TUI-only, refuses pipes before Loader boot).
tui-agent owns the coding composition inline; echo-agent and the CI demo
smoke move to the one-shot cli-demo bin, which gains -p/--prompt. The
UI-independent with-key e2es move verbatim to tui-agent. SDK wizard's
'stdio' interface becomes 'tui'. PTY testing stays confined to TUI
surfaces; all other subprocess tests ride pipes.
See .agents/notes/implemented/simplification/2026-07-20-retire-readline-front-door.md
The master merge (windows-runtime) shifted TuiConfig's source line without
regenerating docs/config-catalog.md, and its Windows stdout pin for
workspace-edit was recorded on master without dsh-mode — the session/new
result lacked the modes advertisement and the command list lacked /mode.
Both lines carry no filesystem paths, so the POSIX pin's bytes are correct
on Windows too; graft them verbatim.
The remaining red CI on this PR head (windows coverage/static LSP failures,
the web-search live e2e) reproduces on master's own HEAD 32ccc405b and is
not a branch regression.
Four ds-review-bot findings:
- examples/tui-agent composed dsh-mode without the now-required
modes.plan.section, so the TUI leaf failed at Loader startup (the keyless
smoke only asserts the banner and missed it); graft the same deployment
plan instructions the ACP leaf carries.
- The prompt-submit and turn-continuation flushes ran before next(), so a
session/set_mode arriving while a downstream async listener (the shipped
hooks listeners' shape) awaited applied one request late; both listeners
now prepend and flush after next(), matching the request-error wrapper,
with a regression test pinning the ordering.
- An HMR unload during the exit_plan_mode review let a later approval write
into the disposed service and claim an exit whose flush could never land;
the execute path now checks the fiber lifetime after the await and fails
the call (the mode stays plan; the model re-presents).
- resolveConfig accepted empty/untrimmed mode names that list()/ACP then
advertised while the package invariant rejected their selection,
desynchronizing the picker; names are validated non-empty and trimmed at
load, the same shape the invariant enforces.
Master arrivals re-grafted onto the plan-mode surfaces:
- Package invariant runtime contracts: every package owns ./invariant —
added the dsh-mode companion (mode/set payload validation: non-empty
trimmed name), its unit spec, exports/peer wiring, and the mode group in
the tsconfig invariant paths glob.
- Interception waterfalls gained an AbortSignal parameter
(agent/prompt-submit, agent/turn-continuation) and ToolExecutionInput.signal
became required: listeners and test dispatch updated; the exit tool now
forwards exec.signal unconditionally.
- TUI question dialog: master's position/unanswered header layout kept,
the plan-review detail block re-grafted between question and answers.
- LSP capability family arrived: lsp tool joins the catalog pin, dsh-lsp
examples deps beside dsh-mode; lsp-definition snapshot refreshed with
the mode command and modes advertisement.
- docs/architecture.md and packages/README.md regenerated tables re-grafted
(ctx.modes row, mode package row) and condensed within word ceilings.
- examples/acp-agent cordis.yml: kept the deployment-owned plan instructions
(incl. the conversational-agreement sentence) beside master's routed-model
compaction comment; snapshot expected outputs refreshed keyless and noise
fixtures restored.
Real-session evidence (Zed, 2026-07-21): in plan mode the model asked for
deletion confirmation through ask_user_question, took the user's follow-up
"对的" as approval, and attempted the rm directly — the independent
read-only sandbox contained it, and the one-shot escalation was rejected.
The plan instructions covered imperative execution requests but not a
confirming answer to the model's own question, so add the missing sentence:
conversational agreement approves nothing and does not end plan mode; the
confirmed decision belongs in the exit_plan_mode plan. Codex's plan template
carries the equivalent rule ("Plan Mode is not changed by user intent").
The plan-mode system-prompt pin refreshes with the section text.
Master landed the tool-subagent depth budget while this branch was in
flight: the numeric default maxDepth now fails the mount against the
ACP provider's depthLimit: false, so the composition fixture must state
maxDepth: 'provider-managed' — the documented opt-out for a provider
whose recursion budget lives in the child harness. The fixture also
moves off the retired stdio-demo REPL onto the current app-boot driver
pattern (runLoaderSmoke + one-shot cli), and the split isDirectory
statements gain the file-not-a-directory case the single-expression
form used to cover implicitly.
The inheritance branch ran only under hand-mounted plugin tests, and
the with-key e2e always configures an explicit cwd. Add a test-only
cordis.yml (scripted delegating model + the scripted mock ACP child)
booting the stdio app through the real Loader with cwd omitted: the
child proves it ran in — and was announced — the parent session's
workspace, keylessly.
The master merge brought the tool registry's per-scope restriction layer
(tools.restrict), which makes dsh-mode's prepend assemble filter a duplicate
enforcement shape: it re-implemented the registry's SDK-section rendering
(renderToolsSdk + the RUN_CODE_NAME exclusion) and hid the exit tool from
prompts only — dispatch stayed open and the execute-time re-check was the
real gate. The service now reconciles a per-agent deny restriction on
agent.ctx at agent/created and at every boundary flush, so wire schemas, the
Code Mode tools:sdk section, AND dispatch resolve exit_plan_mode through the
one registry view (a default-mode call answers UNKNOWN_TOOL, byte-identical
to a no-dsh-mode deployment). The execute-time folded-mode re-check stays as
defense in depth for a direct foreign mode/set append no boundary has
reconciled yet.
Two zero-consumer surfaces removed per the pre-release stance:
- AgentOptions.mode creation seeding (declaration merge + agent/created
listener); a caller selects through set() before the first turn, and the
deferred subagent inheritance returns together with its consumer.
- The dropped-definition boundary notice (droppedNoticed + narration):
custom mode definitions have no production consumer, so nothing can be
dropped; fold-to-default degradation is unchanged.
The stdio removal had left plan mode ACP-only while docs still claimed a
/mode command. dsh-mode now registers /mode on the plugin-owned command
registry through an optional ctx.inject(['commands']) child (type-only peer
edge on dsh-commands), so the TUI and the ACP slash-command surface both
gain it; examples/tui-agent composes dsh-mode. ACP/TUI expected outputs
refreshed keyless for the available_commands_update delta.
Docs updated in place (mode READMEs, the plan-mode Agent Note's realization
sections); catalogs and graphs regenerated.