rabbitknight
dsh-tui
DeepSeek HarnessTerminal UI.
- Stars
- 1
- Language
- TypeScript
- Created
- Aug 13, 2026
- Updated
- Aug 13, 2026
Introduction
dsh-tui
Made in DeepSeek Harness — 构建于
DeepSeek Harness 之上的交互式终端界面
(dsh --profile tui),是一个挂在 dsh-base 上的 Cordis 插件 bundle
(cordis.patch.yml 补丁层)。渲染层基于
@earendil-works/pi-tui
(pi 的终端 UI 库,MIT),交互模式参考 pi-coding-agent,功能面以 DSH Web GUI
(apps/web + packages/client/ui-*)为基准复刻。
┌─────────────────────────────────────────────┐
│ dsh tui 0.1.0 · pi-tui 0.84.1 │ ← transcript (ScrollView, follow-end)
│ ╭ 官方 DeepSeek 鲸鱼(斜向 shimmer 光带扫描)╮ │ ← 空态开屏
│ ╰ 消息中的 URL 与文件路径自动变为 OSC 8 链接 ╯ │ ← ctrl/cmd+点击打开
│ You │
│ Say exactly: pty-ok │
│ Assistant · deepseek-official/deepseek-v4… │
│ pty-ok │
│ ⚙ bash … │
│ {"command":"ls"} │
│ total 0 │
├─────────────────────────────────────────────┤
│ ▶ build the tui · 2/30 rounds │ ← goal bar (dock)
│ Working… (turn 1) │ ← status
│ ─────────────────────────────────────────── │ ← editor
│ deepseek-official/deepseek-v4-flash · sess… │ ← footer
└─────────────────────────────────────────────┘
截图

安装与使用
前置:Node.js ≥ 22.19(或 ≥ 24)、npm(含 pnpm,npm i -g pnpm)。
1. 安装 bundle 到 tui profile
dsh plugin 会把剩余参数原样转发给 profile 目录内的 pnpm,所以下面的
命令等价于在 ~/.dsh/profiles/tui 里执行 pnpm add <bundle 路径>:
# 方式一:dsh CLI(需全局安装 @deepseek-ai/dsh)
dsh plugin --profile tui add "F:\work\ai\dsh-tui\packages\dsh-tui-app"
# 方式二:npx(无需全局安装,推荐)
npx @deepseek-ai/dsh plugin --profile tui add "F:\work\ai\dsh-tui\packages\dsh-tui-app"
在仓库根目录也可以一键(重)安装——它会先构建再装进 profile:
npm run install:profile
2. 启动
# 推荐:npx 启动(等价于 dsh --profile tui)
npx @deepseek-ai/dsh --profile tui # 新会话
npx @deepseek-ai/dsh --profile tui "run the tests" # 新会话并立即发送任务
npx @deepseek-ai/dsh --profile tui --resume <session> # 恢复持久化会话
Windows 下也可以运行仓库里的 start-tui.cmd(内部就是
npx @deepseek-ai/dsh --profile tui %*,支持同样的参数)。
说明:
dsh未加入 PATH 时,npx @deepseek-ai/dsh ...与全局安装的dsh ...完全等价;启动后代码改动即时生效(bundle 是工作区链接, 修改src/后重新npm run build即可,无需重装)。
功能清单(对照 Web GUI)
| 域 | 功能 | TUI 入口 |
|---|---|---|
| 聊天 | 会话 transcript、Markdown 渲染、reasoning(可隐藏)、流式输出、消息头时间戳、轮尾行(turn-tail:时钟 + 产出文件 chip)、context 注入行(↳ 生产者标签) | — |
| 统计 | 常驻统计行(轮/步/LLM·工具时长/首 token/tok/s/缓存命中/token)+ /stats 明细 | 自动 + /stats |
| 工具 | 工具调用卡(参数/结果,可折叠)、todo 列表、命令执行卡(⚡/✓/✗) | ctrl+o 展开/折叠 |
| 压缩/重试 | 压缩摘要卡(compaction 事件)、模型重试等待卡(等待重试 (n/m) · Ns,可展开失败原因)、max-tokens「发送继续」提示卡 | 自动 |
| 轨迹 | 时间线(节点符号区分:◈轮/↳步/❯用户/✦助手/⚙工具/⚡命令/⇊压缩)+ 右侧内容预览(选中节点显示文本/参数/结果摘要,j 切换 JSON),工具栏 / 搜索、f 折叠、d 时钟列 | /trajectory |
| 主题 | 内置调色板切换(dark/light/ocean/sunset,DSH_TUI_THEME 可设默认) | /theme |
| 审批 | 工具权限弹窗(Enter/y 允许一次 · Esc/n 拒绝) | 自动 |
| 用户问题 | 批量问题 + 选项(含 plan-review 计划审批) | 自动 |
| 会话管理 | 列表(状态徽标 ●/○、标题/cwd/workspace/归档)、resume/fork(任意 seq)/rename/archive、内容搜索(snippet + 分页) | /sessions /resume /manage /rename /fork [seq] /archive ctrl+r alt+s |
| Workspace | 列表/创建(目录浏览器)/重命名/删除(footer 显示当前 workspace) | /ws |
| 模型 | 模型选择(下一个 step 生效)、提供商 API key/baseURL/模型列表、端点探测 discoverModels、自定义提供商创建(route 校验/协议/key) | /model、/settings → Models |
| 设置 | General(语言/外观/权限预设/agent 预设)、Plugins(shell/agent-loop/web-search)、Agent presets、Plugin inventory | /settings |
| Goal | 目标创建(host 命令)、状态条(阶段/轮次/阻塞原因;完成自动隐藏)、操作菜单(暂停/恢复/编辑/清除,CAS)、自动续跑 | /goal、goal 条、alt+g |
| Plan | plan 模式开关、footer PLAN MODE 标记、exit_plan_mode 审批 | /plan |
| Workflow | 工作流运行卡(名称/成员/状态,事件重放) | 自动(tool-workflow/* 事件) |
| Jobs | 后台任务列表 + 取消 | /jobs |
| Skills | 技能目录 | /skills |
| Subagents | 子代理目录树(状态点/模式/时长/展开折叠)+ @ 引用自动补全 | /subagents、编辑器 @ |
| 队列 | 排队消息坞(next-step/next-turn 双队列)+ 单项操作(编辑/删除/插话,web updateQueue 语义) | alt+enter 排队 · alt+e 管理 · alt+up 恢复 |
| 上下文 | footer contextRing + 明细面板(~used/~window、system/tools/messages 三色占比条) | alt+c |
| 反馈 | 赞/踩 + 备注(messageFeedback CAS) | alt+l |
| 命令 | host 命令转发(/permission 菜单 /compact /export(落盘 ZIP) /feedback 等) | 斜杠输入 |
| 输入 | 斜杠命令自动补全、外部编辑器($EDITOR/notepad) | ctrl+g |
| 其它 | 模型切换提示注入、resume 提示、SIGTERM/崩溃时终端恢复 | — |
键位
| 键 | 动作 |
|---|---|
| Enter | 发送消息 |
| Esc | 取消运行中的 turn / 清空编辑器 |
| Ctrl+C | 清空编辑器;运行中中断;连续两次退出 |
| Ctrl+D | 空编辑器时退出 |
| Ctrl+T / Ctrl+O | 切换 thinking / 工具输出 |
| Ctrl+G | 外部编辑器 |
| Ctrl+R / Ctrl+N | 恢复会话 / 新会话 |
| Alt+Enter | 排队 follow-up 消息(下一轮) |
| Alt+Up | 把排队消息恢复到编辑器 |
| Alt+E | 队列管理(↑/↓ 选择 · e 编辑 · x 删除 · s 插话) |
| Alt+L | 反馈最近一条助手消息(赞/踩/备注) |
| Alt+C | 上下文仪表明细 |
| Alt+G | Goal 操作(暂停/恢复/编辑/清除) |
| Alt+S | 会话内容搜索 |
| 鼠标 | 滚轮滚动 transcript、拖选复制、Ctrl+点击打开消息中的链接/文件路径(OSC 8) |
| Shift+PageUp/Down、Ctrl+Home/End | 滚动 transcript |
/help | 帮助(键位 + 命令) |
布局
┌──────────────────────────────────────────────────────────┐
│ dsh tui v0.1.0 · deepseek-official/deepseek-v4-flash · … │ header 顶栏(brand/模型/会话/PLAN)
├───────────────────────────────────────────────┬──────────┤
│ Transcript(消息流,pi 风格) │ Detail 面板 │ ← /trajectory 时:左时间线右详情
│ You │ (轨迹/详情) │
│ ───────────────────────────────── │ │
│ ╔ 用户消息背景块 ╗ │ │
│ Assistant · 01:21 │ │
│ markdown 正文(无背景,同 pi) │ │
│ ──────────────────── │ │
│ ⚙ bash …(pending/success/error 三态背景卡) │ │
├───────────────────────────────────────────────┴──────────┤
│ 9 轮 · 379 步 | LLM 47m31s · 工具 34m6s | ↑152M ↓276K … │ 统计行(pi StatsLine 风格)
│ ⠋ Working… (turn 1) │ 状态行(spinner 动画)
│ ──────────────────────────────────────────────────────── │ 编辑器
│ ~work/project · ws-name 模型名(右对齐) │ footer 数据条
└──────────────────────────────────────────────────────────┘
响应式:窄终端(<110 列)自动截断 footer / 隐藏详情列;/trajectory 侧栏布局(左时间线、右节点详情,↑/↓ 选择、Enter 查看原始事件、Esc 返回)。
架构(分层分包)
packages/dsh-tui-app/
cordis.patch.yml # dsh 组合补丁
src/
index.ts / startup.ts # 入口层:bundle 插件(runner / 命令行)
core/ # 领域逻辑(无 pi-tui 依赖,纯函数/折叠)
stats.ts # 会话统计折叠(时长/token/上下文)+ pi 风格统计行
trajectory.ts # 轨迹时间线折叠(事件日志 → 行)
sessions.ts # 会话/workspace 数据与操作
settings.ts # 设置/凭据/提供商/插件清单
collab.ts # goal/jobs/skills/subagents
text.ts # content-block 文本提取
ui/ # 表现层(pi-tui 组件,纯展示)
theme.ts # 调色板/主题系统(4 套内置,/theme 切换)
components.ts # 消息/工具/命令/goal/workflow 卡
selectors.ts # 搜索选择器 + 文本表单
trajectory.ts # 轨迹侧栏 UI(列表 | 详情)
app/ # 应用组装层
dsh-tui.ts # 主应用(布局/模式切换/命令分发/响应式)
renderer.ts # 会话事件 → transcript 组件树
commands.ts # 斜杠命令 + 自动补全
keybindings.ts / custom-editor.ts
- 分层规则:
core/不含 pi-tui 与 Cordis;ui/只做展示;app/负责组装与交互。 - 斜杠命令拦截:web 在 api-proxy 层拦截
/命令,TUI 是 in-process,由runHostCommand调ctx.commands.execute实现同等拦截(未注册命令报 unknown,绝不发给模型)。
开发
npm install # 工作区依赖(npm)
npm run build # tsc → lib/
npm run check # 类型检查
npm run test # node:test 单元测试(组件渲染 + 事件折叠)
node scripts/pty-smoke.mjs # 真实伪终端端到端冒烟(需真实 LLM 凭证)
已知限制
- 附件图片(粘贴/拖放)未实现:终端无拖放,图片以文本路径处理;
/export会收集日志引用的媒体进 ZIP。 - Web 的 React 组件槽/主题系统不适用,视觉与 web 不同构(终端风格)。
- 会话内模型切换通过
selection.current在下一 step 生效(与 web 一致),图片模态校验未做。 - 会话搜索分页仅取第一页(cursor 分页可扩展);反馈目标限定最近一条落定 append-origin 助手消息。