`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.
3.8 KiB
ui/:面向用户和 SDK 客户端的集成接口
English | 中文
面向用户的交互通道和进程外 SDK 服务器。这些是产品包(package):由用户或 SDK 客户端直接操作的真实接口。
| 包 | 职责 | ctx 键 |
|---|---|---|
commands/ |
用户命令注册表:共享发现元数据、作用域遮蔽、取消以及 UI 直接分派 | ctx.commands |
user-approval/ |
一次性用户审批机制、封闭的结果词汇、审计事件和逐会话审批策略 | ctx.approval |
permission/ |
面向用户的权限预设(workspace-write/danger-full-access):通过一项产品级选择组合沙箱模式与审批策略两个可调参数,并写入各自的会话事件 |
ctx.permission |
user-interaction/ |
UI 支持的确认工具所使用的抽象用户问答 seam | ctx.userInteraction |
tool-ask-user/ |
模型侧 ask_user_question 工具,基于 ctx.userInteraction 实现 |
(注册到 ctx.tools) |
tui/ |
交互式 pi-tui 终端通道:渲染会话标题、事件和工具意图,响应 ctx.userInteraction,并托管由 effect 持有的插件浮层 |
ctx.tui(驱动 ctx.agents) |
jsonrpc/ |
面向进程外 SDK 客户端的 stdio JSON-RPC 服务器 | (驱动 ctx.agents) |
app-boot/ |
app bin 的共享启动粘合层:加载 .env、会明确报错的 Loader 保护机制、感知快照的配置解析,以及等待整棵树停稳的启动序列 |
(供各 bin 使用的库) |
UI 集成属于由客户端驱动的插件,而非对循环的修改:它使用现有的 agent/* 事件分类和 dsh-agent 工厂。tui 是交互式终端入口,并提供终端本地的 ctx.tui 扩展服务;jsonrpc 为进程外 SDK 客户端提供服务,非交互式的一次性任务则使用 cli-demo。commands 是 TUI 使用的仅面向用户的发现与分派通道;命令输入和输出不会成为模型消息。
user-approval、user-interaction 和 tool-ask-user 位于此处,因为向用户提问是由 UI 支持的产品功能,并不属于无提供方的核心主干。user-approval 负责一次性的 ctx.approval 决策机制及其策略层级;应答逻辑仍由负责 agent(智能体)的通道或自动化传输层提供。user-interaction 保持提供方无关(ctx.userInteraction),tool-ask-user 是其模型侧消费方,而交互式 app 包提供具体的提供方。
<<<<<<< HEAD
基于 agent-spine-demo 组合的可运行 app bundle 位于 examples/(tui-demo、acp-demo、jsonrpc-demo)。acp-demo 和 jsonrpc-demo 各自提供启动 bin;tui-demo bundle 则由产品 dsh CLI(命令行界面)启动。ui/ 保留可复用的用户/SDK 通道插件和共享 app-boot 粘合层;仅供自动化使用的 ACP(Agent Client Protocol)传输层位于 acp/。每个入口都负责自己的 stdout 策略,叶子 cordis.yml 则提供后端与可选工具。
基于 agent-spine-demo 组合的可运行 app bundle 位于 examples/(cli-demo、acp-demo、jsonrpc-demo)。acp-demo 和 jsonrpc-demo 持有启动 bin;产品 dsh CLI 不使用 bundle:它启动 apps/cli 中的平铺 config tree。ui/ 保留可复用的用户/SDK 通道插件和共享 app-boot 粘合层;仅供自动化使用的 ACP 传输层位于 acp/。每个入口都持有自己的 stdout 策略,叶子 cordis.yml 则提供后端与可选工具。
a1c6a2c3f (refactor(cli)!: one shared base config with per-surface overlays)