Files
deepseek-harness/apps/cli/composition.md
T
Turtle f290a8b851 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 21:15:42 +08:00

148 lines
7.2 KiB
Markdown

<!-- Generated by scripts/gen-doc-graphs.ts - do not edit by hand.
Run `pnpm run gen-doc-graphs` to regenerate. -->
# dsh TUI Composition
The TUI agent combines the real DeepSeek adapter, coding tools, compaction, subagents, and workflows with the full-screen terminal app package.
```mermaid
flowchart LR
cfg["apps/cli (dsh)<br/>cordis.yml"]
plugin_tui_timer["timer<br/>@cordisjs/plugin-timer"]
cfg --> plugin_tui_timer
plugin_tui_llm["llm<br/>@deepseek-ai/dsh-llm"]
cfg --> plugin_tui_llm
plugin_tui_session["session<br/>@deepseek-ai/dsh-session"]
cfg --> plugin_tui_session
plugin_tui_session_title["session-title<br/>@deepseek-ai/dsh-session-title"]
cfg --> plugin_tui_session_title
plugin_tui_session_title_llm["session-title-llm<br/>@deepseek-ai/dsh-session-title-first-message-llm"]
cfg --> plugin_tui_session_title_llm
plugin_tui_user_interaction["user-interaction<br/>@deepseek-ai/dsh-user-interaction"]
cfg --> plugin_tui_user_interaction
plugin_tui_agent["agent<br/>@deepseek-ai/dsh-agent"]
cfg --> plugin_tui_agent
plugin_tui_tasks["tasks<br/>@deepseek-ai/dsh-tasks-local"]
cfg --> plugin_tui_tasks
plugin_tui_llm_retry["llm-retry<br/>@deepseek-ai/dsh-llm-retry"]
cfg --> plugin_tui_llm_retry
plugin_tui_session_persistence_jsonl["session-persistence-jsonl<br/>@deepseek-ai/dsh-session-persistence-jsonl"]
cfg --> plugin_tui_session_persistence_jsonl
plugin_tui_subprocess["subprocess<br/>@deepseek-ai/dsh-subprocess-local"]
cfg --> plugin_tui_subprocess
plugin_tui_bash_local["bash-local<br/>@deepseek-ai/dsh-bash-local"]
cfg --> plugin_tui_bash_local
plugin_tui_tool_bash["tool-bash<br/>@deepseek-ai/dsh-tool-bash"]
cfg --> plugin_tui_tool_bash
plugin_tui_tool_tasks["tool-tasks<br/>@deepseek-ai/dsh-tool-tasks"]
cfg --> plugin_tui_tool_tasks
plugin_tui_fs_policy["fs-policy<br/>@deepseek-ai/dsh-fs-policy"]
cfg --> plugin_tui_fs_policy
plugin_tui_tool_fs["tool-fs<br/>@deepseek-ai/dsh-tool-fs"]
cfg --> plugin_tui_tool_fs
plugin_tui_tool_fs_search["tool-fs-search<br/>@deepseek-ai/dsh-tool-fs-search"]
cfg --> plugin_tui_tool_fs_search
plugin_tui_workspace_context["workspace-context<br/>@deepseek-ai/dsh-workspace-context"]
cfg --> plugin_tui_workspace_context
plugin_tui_skill["skill<br/>@deepseek-ai/dsh-skill"]
cfg --> plugin_tui_skill
plugin_tui_skill_local["skill-local<br/>@deepseek-ai/dsh-skill-local"]
cfg --> plugin_tui_skill_local
plugin_tui_tool_skill["tool-skill<br/>@deepseek-ai/dsh-tool-skill"]
cfg --> plugin_tui_tool_skill
plugin_tui_commands["commands<br/>@deepseek-ai/dsh-commands"]
cfg --> plugin_tui_commands
plugin_tui_goal["goal<br/>@deepseek-ai/dsh-goal"]
cfg --> plugin_tui_goal
plugin_tui_goal_session["goal-session<br/>@deepseek-ai/dsh-goal-session"]
cfg --> plugin_tui_goal_session
plugin_tui_command_goal["command-goal<br/>@deepseek-ai/dsh-command-goal"]
cfg --> plugin_tui_command_goal
plugin_tui_plan_mode["plan-mode<br/>@deepseek-ai/dsh-plan-mode"]
cfg --> plugin_tui_plan_mode
plugin_tui_token_meter["token-meter<br/>@deepseek-ai/dsh-token-meter"]
cfg --> plugin_tui_token_meter
plugin_tui_compact_basic["compact-basic<br/>@deepseek-ai/dsh-compact-basic"]
cfg --> plugin_tui_compact_basic
plugin_tui_subagent["subagent<br/>@deepseek-ai/dsh-subagent"]
cfg --> plugin_tui_subagent
plugin_tui_subagent_spawn["subagent-spawn<br/>@deepseek-ai/dsh-subagent-spawn"]
cfg --> plugin_tui_subagent_spawn
plugin_tui_subagent_fork["subagent-fork<br/>@deepseek-ai/dsh-subagent-fork"]
cfg --> plugin_tui_subagent_fork
plugin_tui_tool_subagent["tool-subagent<br/>@deepseek-ai/dsh-tool-subagent"]
cfg --> plugin_tui_tool_subagent
plugin_tui_tool_subagent_fork["tool-subagent-fork<br/>@deepseek-ai/dsh-tool-subagent"]
cfg --> plugin_tui_tool_subagent_fork
plugin_tui_workflow_workerthread["workflow-workerthread<br/>@deepseek-ai/dsh-workflow-workerthread"]
cfg --> plugin_tui_workflow_workerthread
plugin_tui_tool_workflow["tool-workflow<br/>@deepseek-ai/dsh-tool-workflow"]
cfg --> plugin_tui_tool_workflow
plugin_tui_timeout_policy["timeout-policy<br/>@deepseek-ai/dsh-timeout-policy"]
cfg --> plugin_tui_timeout_policy
plugin_tui_spill_local["spill-local<br/>@deepseek-ai/dsh-spill-local"]
cfg --> plugin_tui_spill_local
plugin_tui_spill_policy["spill-policy<br/>@deepseek-ai/dsh-spill-policy"]
cfg --> plugin_tui_spill_policy
plugin_tui_tools["tools<br/>@deepseek-ai/dsh-tools"]
cfg --> plugin_tui_tools
plugin_tui_system_prompt["system-prompt<br/>@deepseek-ai/dsh-system-prompt"]
cfg --> plugin_tui_system_prompt
plugin_tui_agent_loop["agent-loop<br/>@deepseek-ai/dsh-agent-loop"]
cfg --> plugin_tui_agent_loop
plugin_tui_fs_local["fs-local<br/>@deepseek-ai/dsh-fs-local"]
cfg --> plugin_tui_fs_local
plugin_tui_llm_deepseek["llm-deepseek<br/>@deepseek-ai/dsh-llm-deepseek"]
cfg --> plugin_tui_llm_deepseek
```
| Plugin id | Package / module |
| --- | --- |
| `timer` | `@cordisjs/plugin-timer` |
| `llm` | `@deepseek-ai/dsh-llm` |
| `session` | `@deepseek-ai/dsh-session` |
| `session-title` | `@deepseek-ai/dsh-session-title` |
| `session-title-llm` | `@deepseek-ai/dsh-session-title-first-message-llm` |
| `user-interaction` | `@deepseek-ai/dsh-user-interaction` |
| `agent` | `@deepseek-ai/dsh-agent` |
| `tasks` | `@deepseek-ai/dsh-tasks-local` |
| `llm-retry` | `@deepseek-ai/dsh-llm-retry` |
| `session-persistence-jsonl` | `@deepseek-ai/dsh-session-persistence-jsonl` |
| `subprocess` | `@deepseek-ai/dsh-subprocess-local` |
| `bash-local` | `@deepseek-ai/dsh-bash-local` |
| `tool-bash` | `@deepseek-ai/dsh-tool-bash` |
| `tool-tasks` | `@deepseek-ai/dsh-tool-tasks` |
| `fs-policy` | `@deepseek-ai/dsh-fs-policy` |
| `tool-fs` | `@deepseek-ai/dsh-tool-fs` |
| `tool-fs-search` | `@deepseek-ai/dsh-tool-fs-search` |
| `workspace-context` | `@deepseek-ai/dsh-workspace-context` |
| `skill` | `@deepseek-ai/dsh-skill` |
| `skill-local` | `@deepseek-ai/dsh-skill-local` |
| `tool-skill` | `@deepseek-ai/dsh-tool-skill` |
| `commands` | `@deepseek-ai/dsh-commands` |
| `goal` | `@deepseek-ai/dsh-goal` |
| `goal-session` | `@deepseek-ai/dsh-goal-session` |
| `command-goal` | `@deepseek-ai/dsh-command-goal` |
| `plan-mode` | `@deepseek-ai/dsh-plan-mode` |
| `token-meter` | `@deepseek-ai/dsh-token-meter` |
| `compact-basic` | `@deepseek-ai/dsh-compact-basic` |
| `subagent` | `@deepseek-ai/dsh-subagent` |
| `subagent-spawn` | `@deepseek-ai/dsh-subagent-spawn` |
| `subagent-fork` | `@deepseek-ai/dsh-subagent-fork` |
| `tool-subagent` | `@deepseek-ai/dsh-tool-subagent` |
| `tool-subagent-fork` | `@deepseek-ai/dsh-tool-subagent` |
| `workflow-workerthread` | `@deepseek-ai/dsh-workflow-workerthread` |
| `tool-workflow` | `@deepseek-ai/dsh-tool-workflow` |
| `timeout-policy` | `@deepseek-ai/dsh-timeout-policy` |
| `spill-local` | `@deepseek-ai/dsh-spill-local` |
| `spill-policy` | `@deepseek-ai/dsh-spill-policy` |
| `tools` | `@deepseek-ai/dsh-tools` |
| `system-prompt` | `@deepseek-ai/dsh-system-prompt` |
| `agent-loop` | `@deepseek-ai/dsh-agent-loop` |
| `fs-local` | `@deepseek-ai/dsh-fs-local` |
| `llm-deepseek` | `@deepseek-ai/dsh-llm-deepseek` |
Source config: [`apps/cli/base.cordis.yml`](base.cordis.yml).
Maintenance mode: hybrid: the leaf plugin list is parsed from its `cordis.yml`; app package expansion is curated from package source.