English | 简体中文
一个 yazi / rmpc 风格的 TUI,用于操作已经在运行的官方 DeepSeek Harness
(npx @deepseek-ai/dsh web,默认 http://127.0.0.1:3080)。
重要:
harnessTUI不自己启动 Harness,也不直接调用 DeepSeek API、不保存会话历史。 它只是官方 Web UI 的终端替代前端:会话、模式、模型、历史、审批全部通过 Harness 官方 HTTP RPC 与 WebSocket 接口读写。
本项目是第三方非官方客户端,与 DeepSeek(深度求索)及其官方 DeepSeek Harness 项目无关。
本项目的代码全部或绝大部分由 AI(大语言模型)生成,发布前经过人工审阅、整理和修改。使用前请自行评估风险。
┌──────────────┐ HTTP POST /api/<method> ┌──────────────────────────┐
│ harnessTUI (本 TUI) │ ───────────────────────────▶ │ DeepSeek Harness (dsh web)│
│ │ ◀─────────────────────────── │ 127.0.0.1:3080 │
│ │ WS /api/events.mux/host │ · agent / tools / model │
└──────────────┘ │ · sessions / presets │
└──────────────────────────┘
官方接口(源码 deepseek-ai/deepseek-harness):
POST /api/session.list|history|prompt|cancel|create|models|selectModel|renamePOST /api/agentPreset.list|selectPOST /api/respond(审批/提问响应)GET /api/session.export- WebSocket
/api/events.mux、/api/events.host
先确保 Harness 在运行:
npx @deepseek-ai/dsh web再启动 TUI:
# 在本项目根目录执行
./harness-tui
# 或指定地址
./harness-tui --url http://127.0.0.1:3080按 M 打开模式选择器,使用官方返回的名称与描述:
| preset id | 官方显示名 | 说明 |
|---|---|---|
standard |
标准模式 | 文件编辑、Shell、文件与网页检索、Skills、计划、目标、子代理、工作流 |
code |
PTC 模式 | 标准能力 + Code Mode SDK,一个 TypeScript 程序组合多步操作 |
minimal |
极简模式 | 持久 bash + str_replace_editor 双工具 |
cordis |
创造模式 | 标准能力 + 运行时检查、插件实验、preset 创作 |
模式选择对新建会话生效;已产生消息的会话由 Harness 锁定,不能中途换模式。尚未发送消息的空白会话可在发送前切换模式。
侧栏默认按会话工作目录分组显示:最近活跃的目录排在最前,目录内会话按最近
更新排序;缺失目录的会话放在“未指定工作目录”组。目录分组可以折叠:在分组
标题上按 Enter 切换,或使用 z c / z o / z O。折叠后当前打开的会话
仍会保留在列表中。可通过配置关闭分组或改为路径字母序(见下文“配置”)。
界面不常驻快捷键提示。按 ? 会打开与当前焦点窗口匹配的快捷键帮助:
聚焦侧栏时显示全局 + 侧栏,聚焦聊天时显示全局 + 聊天,聚焦输入框时显示
当前 vi 模式实际可用的键;? 在插入模式、搜索与命令输入框中按普通字符处理。
| 按键 | 作用 |
|---|---|
j / k |
侧栏移动;聊天区光标下/上一行 |
g g / G |
侧栏列表顶部/底部;聊天区光标跳至顶部/底部 |
Ctrl+d / Ctrl+u |
半页下 / 上 |
Tab / S-Tab / Ctrl+w h/l |
切换面板 |
/ |
搜索会话(标题 / 模式 / 工作目录),n / N 跳转 |
Enter(侧栏) |
打开会话;在目录分组上切换折叠/展开 |
z c / z o |
折叠 / 展开当前目录分组 |
z O |
展开所有目录分组 |
i / a / A / o / O |
进入 vi 输入框 |
o(侧栏) |
用当前 Agent 模式 + 默认工作目录新建会话 |
c(侧栏) |
重命名光标所在会话 |
s(聊天) |
取消/停止当前会话 |
y |
复制标题或目录路径(侧栏)/ 当前大项内容(聊天) |
Y |
复制最后回复(聊天) |
h / l |
聊天区光标跳至上/下一条消息 |
[ / ] |
聊天区光标跳至上/下一个大项 |
{ / } |
聊天区光标跳至上/下一轮 |
t |
展开/折叠光标所在条目(思考、bash、结果) |
b |
展开/折叠全部工具条目 |
L |
手动加载更早轮次(历史默认后台自动加载完整) |
m |
循环切换当前会话模型 |
M |
选择 Agent 模式 |
? |
按键帮助(只显示当前聚焦窗口可用键) |
: |
命令模式 |
q / Ctrl+c |
退出 |
Ctrl+X 发送到 Harness 的 session.prompt。其余是 vi 编辑器:
hjkl、w b e、0 ^ $、gg G、v/V、d/y/c + motion、p、u/Ctrl+R。
- Normal 模式未处理的按键(如
q、?、Tab、C-w h/l)会进入全局 keymap。 - Insert 模式按键由编辑器独占:
Ctrl+W删除前一个词,切换面板请先Esc回 Normal 后使用Tab/S-Tab。
Harness 请求工具审批时,底部会显示提示:
⚠ 审批 bash:... — [y] 允许一次 [n] 拒绝
响应通过官方 /api/respond 发回。
:build 编译 harnessTUI 自身(cargo build --release)
:new [目录] [模式] 新建会话,可指定工作目录与 Agent 模式
:preset <id> 选择 Agent 模式
:model <id> 切换当前会话模型
:rename <标题> 重命名当前打开的会话
:older 加载更早轮次
:cancel 取消当前会话
:refresh 刷新会话与模式
:help 打开当前窗口快捷键帮助
:keymap 备份/迁移并重新加载 keymap
:q 退出
侧栏 c 重命名光标所在会话;手动输入 :rename 仍重命名当前打开的会话。
搜索与命令模式使用内置单行编辑器(暂未 TOML 化):
Esc 取消,Enter 确认,C-a / C-e 行首/行尾,C-b / C-f 左右移动,
Backspace / Delete 删除,C-u 删到行首,C-k 删到行尾,C-w 删除前一词。
:new 的两个参数都可省略,目录在前、模式在后:
:new → 默认目录 + 默认模式(见配置)
:new /home/me/project → 指定目录,模式用默认
:new /home/me/project code → 指定目录 + 指定模式
:new minimal → 单个裸词按模式名处理
目录必须是已存在的绝对路径(支持 ~ 展开);模式必须来自官方
agentPreset.list。省略目录时使用 default_working_dir,留空则交给
Harness 决定(其进程 cwd);省略模式时使用最近通过 M / :preset 选择的
模式。
聊天区像 vim 看日志一样使用,光标现在停在实际渲染的行上:
j/k:光标在可视行之间移动,长回复、工具输出会自动跨行并跟随滚动;g g/G:光标跳至聊天区顶部 / 底部;h/l:光标在用户消息、助手消息、轮次分隔符之间跳转;[/]:光标在上/下一个大项之间跳转;{/}:光标在上/下一轮之间跳转;t:展开/折叠光标所在的思考、bash 命令或工具结果;b:展开/折叠全部工具条目;y:复制光标所在大项内容;Y:复制最后一条回复;- 光标所在行会高亮显示;
- 页面只在光标到达上下边缘时滚动,光标在视口内移动时页面保持不动;
- 打开会话时,光标自动定位在最近一条用户消息上,并保留其上方上下文。
打开会话时:
- 先加载最近 16 条消息,并自动定位到最近一条用户消息;
- 随后在后台按
beforeSeq分页加载更早历史,直到加载完整; - 加载期间视口始终锚定在最近的用户消息,不会被旧内容“挤走”;
L/:older保留为手动补页入口。
历史没有内容截断;展开工具后同样按真实换行高度滚动。
可以。harnessTUI 只是 Harness 的客户端;让 Harness 的会话工作目录位于项目目录(例如在
项目目录启动 npx @deepseek-ai/dsh web),然后在 TUI 中直接发送:
修改 harnessTUI 的源代码,把发送键改成 Ctrl+G
Harness agent 会用官方工具修改 src/ 下的文件。修改源码不会影响正在运行的
harnessTUI 进程;之后:
- 在 TUI 里执行
:build(后台执行cargo build --release,结果显示在状态栏); - 退出后运行
./harness-tui。启动脚本会检测源码比 release 二进制新,自动重新编译; - 新版本即可生效。
注意:不要一边构建一边让 agent 改源码,否则可能编译到半成品;构建失败时看
:build返回的 stderr 尾部。
顶部状态行显示全局信息,会话信息位于输入框上方:
SIDEBAR mux✓ host✓ harnessTUI
IDLE preset minimal · deepseek-official / deepseek-v4-pro · 思考 high
- 顶部首段表示当前按键路由:
SIDEBAR/CHAT/COMPOSER;进入SEARCH、COMMAND、HELP、PRESET等全局模态时优先显示模态名; - 输入框的
INSERT / VISUAL等 vi 子模式由输入框边框自己显示,不再出现在顶部; mux✓/host✓/harnessTUI固定锚定在右上角,切换焦点时不会左右移动;- 输入框上方:
RUN / IDLE、会话实际使用的preset、下一轮模型与有效思考强度; - 聊天框下边框:全对话轮次/步骤、LLM 与工具耗时、平均 TTFT、解码速度,以及累计 token(来自官方
sessionStats/tokenUsageprojection,随 mux 实时更新); - 每条回复标题:本次
assistant/message的输入/输出 token、step 用时与 TTFT; - 思考块标题:思考持续时间与思考 token。思考时长由首个
reasoning-delta到首个正文/工具 delta 的事件时间戳估算,不是模型服务端精确计时。
TUI 配置包含连接、侧栏会话显示与键位超时信息:
# ~/.config/harness-tui/config.toml
base_url = "http://127.0.0.1:3080"
default_preset = "minimal"
default_working_dir = "/home/NeedtoPratice/Codes/deepWork"
# 侧栏会话按工作目录分组;设为 "none" 则回到扁平列表
sidebar_group_by = "cwd"
# recent = 最近活跃的目录/会话优先;path = 按路径字母序
sidebar_group_sort = "recent"
normal_timeout_ms = 1200
insert_timeout_ms = 300快捷键在 ~/.config/harness-tui/keymap.toml,首次启动自动生成;context 支持
global | sidebar | chat | picker | help。旧版文件会备份为 keymap.toml.bak
后按“按键序列 + context”合并缺失的默认绑定,保留自定义键位。
会话历史、API Key、模型、权限、Agent 模式全部由 Harness 管理,TUI 不写
harness.json。
export CARGO_HOME="$PWD/.cargo" # 仅当 ~/.cargo 不可写时需要
cargo test
cargo run -- --url http://127.0.0.1:3080src/
├── main.rs CLI(--url)
├── app.rs 模态 TUI:vi 键位、模式选择、会话/历史渲染
├── harness.rs 官方 Harness HTTP RPC + WebSocket 客户端
├── keymap.rs yazi 式 TOML 多键序列
├── composer.rs tui-textarea vim 状态机
├── input.rs 单行编辑器(搜索/命令)
├── markdown.rs Harness 事件内容 → ratatui
├── config.rs base_url / 默认模式与工作目录 / 键位超时
└── paths.rs 可写目录探测与回退
- 用户提问(questions)响应
- 基于
session.search的官方全文搜索 - 语法高亮(syntect)
- keymap 热重载(
:keymap)