dsh-TUI

1.8kStar78Fork56Issue0Watching

DeepSeek Harness 的 Claude Code 风格终端前端,含流式 Markdown、工具卡、`/resume`、会话 fork 与全屏渲染。

语言
TypeScript
License
MIT
分支
main
claude-codecoding-agentdeepseekdeepseek-harnessdsh-plugininkreactterminal

安装

$ dsh plugin --profile web add github:ccch1mneyyy/dsh-TUI

在终端中运行以上命令,通过 dsh CLI 安装此插件。可在右上角切换 Profile。 第一次用 dsh?看这篇新手教程

一句话定位

dsh-TUI 是 DeepSeek Harness 的 Claude Code 风格终端交互前端,作为 Cordis bundle 插件挂在 dsh-base 之上,复用官方 Agent、模型、会话和工具服务,向用户提供流式 Markdown 对话、/resume//new/模型切换、双击 Esc 回溯和全屏 alt-screen 渲染。

核心能力

  • 在终端内提供流式 Markdown、结构化工具卡、命令与文件补全、@ 文件引用(任意位置补全、图片发为持久附件)、历史搜索、消息选择,并支持 inline 与 alt-screen 两种渲染模式
  • 在状态栏实时显示工作进度、分段上下文用量、TPS、缓存命中率、推理等级、输入/输出 token 与 Git/会话信息
  • 提供完整的会话工作流:/resume 会话浏览器、/new 新会话、/compact 压缩、/export Markdown 导出、/btw 侧问、模型切换,以及空输入双击 Esc 通过 session fork 进行时间回溯
  • 接入 DSH 官方能力:Agent preset 名册(/preset)、Skills(/audit /bug /review 等)、MCP(/mcp)、Goals、Todos、子代理和 ask_user_question 问卷
  • 为长会话做了事件驱动投影、差分终端输出、消息虚拟化、回放合并与有界缓存,避免渲染与内存随会话无限增长
  • /theme 内置 auto/light/dark/dark-ansi 四种主题并支持 ~/.dsh-tui/themes/<名字>.json 自定义,/lang 中英界面切换,全部走 Cordis 配置 + 持久化 + env 三级覆盖

技术实现

  • 语言: TypeScript(ESM,"type": "module"tsc 编译到 lib/types/
  • 关键依赖: react@^19.2.0react-reconciler@^0.33.0@deepseek-ai/cordis@^4.0.1@deepseek-ai/dsh-agent@^0.1.0-rc.6
  • 架构模式: 单一 Cordis 插件 name: 'dsh-tui',通过 dsh.bundle.patch → ./cordis.patch.yml 覆盖 dsh-base 默认行(禁用 host 层工具/计划/压缩/技能等,由 Agent preset 名册接管),官方 @deepseek-ai/* 导入集中在 src/dsh-adapter/ 边界之内,渲染基于移植的 Ink+Yoga(差分输出、终端能力探测、ConPTY 兼容路径)
  • 入口文件: src/index.ts(re-export shim)→ src/dsh-adapter/index.tsConfig Schema + apply)→ src/dsh-adapter/plugin.tsx(运行时实现),bin 入口为 bin/dsh-tui.js(一键探测 dsh/pnpm 并自举 profile)

适用场景

当你想把 DSH 用成"日常开发对话伙伴"——在终端里持续多轮对话、需要看思考与工具调用的可视化、随时回查或回溯历史会话、不希望被网页打断时,dsh-TUI 提供 Claude Code 熟悉的交互体验。同时它和官方 web 端共用 session/event 真源,所以 TUI 里开的会话也可以在 web 上接着看。

前置依赖与兼容性

依赖最低版本说明
DeepSeek Harness0.1.0-rc.6+package.json#peerDependencies 锁定的众多 @deepseek-ai/dsh-* 决定
Node.js^22.19.0 || >=24.0.0package.json#engines.node;CI 使用 24
pnpm10+(推荐 11+)profile 内包安装交给 pnpm;pnpm 9 传递依赖不提升会立即退出(issue #60)
平台macOS / Windows / Linux跨平台;Windows 走 dsh-tui.cmd、剪贴板读 PowerShell、sandbox 在 Windows 上不可用故退到 danger-full-access
原生模块全 JS/TS 依赖,无需 node-gyp 构建
Peer 依赖@deepseek-ai/cordis ^4.0.1 与全套 @deepseek-ai/dsh-* ^0.1.0-rc.6由宿主 DSH 提供;卸载请保证宿主版本对齐
必需凭证DEEPSEEK_API_KEY(自定义端点再加 DEEPSEEK_BASE_URLcordis.patch.yml:28-30

安装方式

dsh plugin --profile web add github:ccch1mneyyy/dsh-TUI

配置项

dsh-TUI 的所有可调参数都集中在 Config Schema(src/dsh-adapter/index.ts:87)。在 $DSH_HOME/profiles/dsh-tui/cordis.patch.yml 里以 dsh-tui 行的 config 块整段替换,整体改动一行完成;常用项如下:

配置类型说明默认值
sessionId字符串启动时恢复的已有会话 ID;留空则建新会话未设置
provider字符串LLM 路由名称;与 model 同时配置才视为显式路由Harness agentDefaultModel
model字符串启动模型;/model 通过 session fork 切换并写回持久化Harness agentDefaultModel
cwd字符串会话侧工作目录(Agent meta、@ 补全、/resume 过滤、状态栏);建议显式绝对路径启动目录所在的 git worktree 根
workspace字符串启动时解析的工作区目标:本地绝对路径、file:// URI 或插件注册 URI未设置
effort字符串每请求实际生效的推理等级(deepseek 仅 off/high/max,非法静默回落)max
activity布尔是否显示实时工作状态行true
activityFrames字符串工作状态动画预设(claude/moon/comet/dots/randomclaude
contextBar布尔是否显示输入框下方的分段上下文进度条true
fullscreen布尔true 用 alternate screen + 鼠标选区;false 用 inlinefalse
langen | zh界面语言(被 DSH_TUI_LANG 覆盖)zh
preset字符串新会话 Agent preset(standard/code/minimal/cordis/liangshen持久化或 standard
diffLayoutauto | split | unified文件编辑 diff 的展示方式(auto 按终端宽度选)auto
modes数组Shift+Tab 会话模式循环的原子组合(plan/sandbox/approval)内置三档默认→plan→full

Config 不直接暴露的主题/语言/调试等开关走环境变量(优先级:env > config > 持久化 > 默认):

环境变量说明
DSH_TUI_LANG锁定界面语言 en/zh
DSH_TUI_THEME锁定内置或自定义主题,优先于持久化选择
DSH_TUI_PERSONA覆盖 Agent persona(不设则为 You are a coding agent.
DSH_TUI_PRESET覆盖新会话默认 Agent preset
DSH_TUI_DISABLE_MOUSEfullscreen 模式下临时关闭鼠标捕获
DSH_TUI_SESSION_ROOT覆盖 JSONL 会话根目录
DSH_TUI_RESUME_SESSION启动时恢复指定会话(启动器通常帮你设)
DSH_TUI_WORKSPACE_TARGETdsh-tui <目标> 触发的启动工作区
DSH_TUI_WORKSPACEWindows dsh-tui.cmd 采用的工作目录
DSH_TUI_DEBUG启用 stderr 调试日志(不要打日志到 stdout,会破界面)
DSH_TUI_RENDER_LOG指定文件路径落原始 ANSI 帧用于取证(含可见内容,慎传)
DEEPSEEK_API_KEY / DEEPSEEK_BASE_URL模型凭证与自定义端点
DSH_PERMISSION_MODE非 Windows 平台覆盖 sandbox policy(workspace-write/danger-full-access

旧名 CC_TUI_*DSH_CC_* 自当前版本起不再生效(启动器会逐次警告),唯一例外是 resume 写双路径(DSH_TUI_RESUME_SESSIONDSH_CC_RESUME_SESSION 同时设置)。

常见问题

Q: 我用的是 pnpm 9,装完启动后立刻退回 shell、几乎没报错。

A: 这是 issue #60 的典型表现:pnpm 9 安装 profile 时不会把传递依赖 dsh-working-activity 提升到 loader 可解析位置,模块解析失败导致整棵插件树被回收,TUI 打完 resume 提示后直接退出。升 pnpm 到 10 或 11 即可:npm install -g pnpm@latest && dsh plugin --profile dsh-tui add @deepseek-harness-tui/dsh-tui@latest

Q: 启动器报"无法启动:profile 内运行的是 v…,而启动器是 v…"。

A: 这是 issue #183 的反向错位保护:全局启动器比 profile 内包新一个 minor 版本时,CLI 会用启动器的 bundle patch 套到旧包上,子路径导出可能解析不到,必然模块解析崩溃。让两者对齐:dsh plugin --profile dsh-tui add @deepseek-harness-tui/dsh-tui@<启动器版本>(或统一升 @latest)。

Q: /model 选了别的模型后我想回到原来那条对话,怎么办?

A: 模型切换在 TUI 里是 session fork 续聊,不修改历史。旧会话完整留在 /resume 列表里;选择本身持久化在 ~/.dsh-tui/model.json,下次 /new 与重启也沿用。

Q: 装了一遍版本看着没变?

A: 不带 @latest 时 pnpm 按 profile package.json 里已记录的版本范围(如 ^0.1.4)就地解析,会停留在旧的主线上。显式指定:dsh plugin --profile dsh-tui add @deepseek-harness-tui/dsh-tui@latest,启动后看顶栏右上角的 vX.Y.Z 验证。

Q: 状态栏的工作状态行有两个 / 不显示。

A: 重复多半是 profile 里另外加了 dsh-working-activity(README 与 docs/getting-started.md 都警告不要重复 add)。移除 profile 里的重复 bundle 配置、只保留本包 patch 自动插入的 working-activity 行即可。如果不显示,检查 cordis.ymldsh-tuiactivity: true 是否被覆写、/activity 选择是否误关,或用 DSH_TUI_DEBUG=1 dsh --profile dsh-tui 看 stderr。

Q: 卸载插件会不会丢会话数据/改动 DSH 核心?

A: 不会。dsh-TUI 是纯插件挂载(README.md:21),不修改 DSH 核心;卸载即还原。主题/语言/preset 等偏好继续留在 ~/.dsh-tui/ 下,需要时可手动删。会话日志仍在 $DSH_HOME/sessions/(profile)或 ~/.dsh-tui/sessions/(裸 cordis.yml)的原路径。

Q: Windows 上粘贴图片为什么不像文档里写的一样发为图片块?

A: Windows 走 PowerShell Get-Clipboard 读剪贴板。剪贴板被其他程序锁定时会先重试、最终若仍被锁则静默降级为临时文件路径插入(不内嵌 base64);Finder 多文件复制在 macOS 没有稳定的 AppleScript 读法,会按文本/图片回退。这些都是 README 与 architecture 文档列出的"已知限制"。

Q: 终端不支持 alt-screen 或想关闭鼠标怎么办?

A: 把 cordis.patch.ymldsh-tuifullscreen: false,或单次启动用 DSH_TUI_DISABLE_MOUSE=1 dsh --profile dsh-tui 临时关鼠标。Terminal.app(macOS 自带)会消费 组合,请在它里面继续用 Ctrl+<键>(iterm2/kitty/WezTerm/ghostty 等才支持 )。

上手难度

入门 — 默认配置可直接启动;想做主题、Agent preset、MCP、审批策略调优时再进入配置参考。

已知问题与限制

  • Windows 没有可用 sandbox 后端:profile 在 Windows 上默认 danger-full-access 且审批策略为 never;不可信仓库里跑前请先检查实际 patch 与 DSH_PERMISSION_MODE 设置(docs/architecture.md:110-111 / cordis.patch.yml:134)。
  • /model 通过 session fork 续聊:不原位替换;旧会话留在 /resume 列表里(docs/architecture.md:122-123 / README.md:225-228)。
  • Ctrl+V 剪贴板按平台分派:Windows 用 PowerShell Get-Clipboard(被锁时先重试仍失败会静默降级),macOS 用 osascript/pbpaste(Finder 多文件复制没有稳定 AppleScript 读法),Linux 按顺序探测 wl-paste/xclip/xsel(全部不可用即报错);剪贴板位图以临时文件路径插入而非内嵌为图片块(README.md:229-234)。
  • 注入到 system prompt 的插件上下文不独立展示:会并入上下文进度条统计(docs/architecture.md:121-122 / README.md:225)。
  • 退出路径不等待 Agent 异步落盘:以进程退出收尾,持久化插件兜底(README.md:235 / docs/architecture.md:129)。
  • /vim/connect/hooks 是占位命令:DSH 侧无等价机制时会给出明确说明而非静默(README.md:240-241 / docs/architecture.md:133)。
  • cordis.yml 启动没有 /permission 预设切换:只有 profile 组合(dsh-basepermission-presets 行默认挂载)才有(README.md:236-239 / docs/architecture.md:131-132)。
  • 旧名环境变量兼容:旧 CC_TUI_*DSH_CC_* 不再生效(启动器每次仍设到时会告警),唯一例外是 resume 写双路径(DSH_TUI_RESUME_SESSIONDSH_CC_RESUME_SESSION 同时设置保证旧启动器可用)(docs/getting-started.md:79-92 / src/utils/paths.ts:58-68)。
  • 数据目录迁移只复制不移动:首次启动若 ~/.dsh-cc 存在而 ~/.dsh-tui 不存在,会整体复制到新目录并提示一行;旧目录留给你确认新目录正常后手动删除(docs/getting-started.md:88-90 / docs/architecture.md:96-98)。
  • sessionHistory 仍兼容旧路径 ~/.dsh-cc/resume.txtsrc/sessionHistory.ts:14TODO: drop the legacy path once pre-rename users migrate,当前版本还需保留双写兜底。
  • Ink 渲染层有未结 TODO:移植的 Ink 子模块在 src/ink/screen.ts:805(软换行未实现时 SpacerHead cell 处理)与 src/ink/render-to-screen.ts:172(cell 转换待抽公共 helper)两处标 TODO,等代码稳定后跟进。