dsh-cli
Verified@aruvelut_6/dsh-cli · v0.1.1 · MIT
Interactive terminal CLI for DeepSeek Harness — a Claude Code-like REPL
Install
dsh plugin add @aruvelut_6/dsh-cli Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Published to npm without a public repository. Inspect the package contents before installing.
Creators
Readme
dshcli
DeepSeek Harness 的交互式终端 CLI —— 一个 Claude Code 风格的 REPL。
它启动 Harness 自带的 agent/session/tools 核心(与 dsh web / dsh --profile headless 同一套机制),但用全屏 Ink(React)TUI 驱动,支持流式输出、多轮上下文和会话续接。
安装
从 npm 全局安装(推荐):
npm install -g @aruvelut_6/dsh-cli # 需要 Node ≥ 20.12
装完直接敲 dshcli 进入交互界面(命令名保持 dshcli,npm 包名是
@aruvelut_6/dsh-cli——dshcli、dsh-cli 这两个非作用域名分别被占用和
被 npm 的反抢注策略拦截)。
开发者本地构建:
cd dshcli
npm install --registry https://registry.npmjs.org/ # 如果 node_modules 尚未安装
npm link # 把 dshcli 放到 PATH 上
本项目自带
.npmrc,把源固定为公共 npm(https://registry.npmjs.org/), 保证@deepseek-ai/*依赖取到最新版本。如果你的全局 npm 配置指向了其他镜像, 请保留该文件(项目级.npmrc优先于全局配置)。
dshcli 复用 $DSH_HOME(默认 ~/.dsh)存放凭据、设置和会话——已装过
DeepSeek Harness 的用户直接共享现有的 API key 和模型配置。
首次运行:API Key 引导
不需要预先安装 DeepSeek Harness:harness 全套是 npm 依赖,npm install -g
自动装齐。首次运行如果检测不到 DeepSeek API Key(来源顺序:环境变量
DEEPSEEK_API_KEY > $DSH_HOME/.credentials.yaml > 项目 .env > 用户
.env),终端里会交互式引导输入(Enter 跳过,跳过则打印手动配置方法):
- key 通过 harness 凭据通道写入
~/.dsh/.credentials.yaml(原子写入、权限 600、保留文件里其他条目,写入后当前进程立即生效) - 申请地址:https://platform.deepseek.com/api_keys
- 也可以绕过引导:
DEEPSEEK_API_KEY=sk-... dshcli只对本次运行生效,或手动 创建~/.dsh/.credentials.yaml写入DEEPSEEK_API_KEY: sk-...再chmod 600
非 TTY(管道)场景不打断流程,只在 stderr 打印配置提示。
用法
dshcli # 新建交互会话
dshcli "run the tests" # 先执行一个初始任务,然后保持交互
dshcli --resume <session-id> # 按 id 续接已持久化的会话
dshcli --continue # 续接最近一次会话
dshcli -m deepseek-chat # 指定模型
dshcli --help # 查看本应用的命令行参数
会话内命令
| 命令 | 作用 |
|---|---|
/help |
显示命令列表 |
/sessions |
列出已持久化的会话(id · 时间) |
/model [name] |
切换模型(真正的热切换,下一条消息立即生效) |
/model(裸命令) |
打开交互式模型选择器(读取 harness 的 llm 目录,↑↓ 选择) |
/compact |
压缩上下文(走 harness 的 compaction seam,超出阈值时生成摘要) |
/clear |
物理清屏,开始全新对话记录 |
/exit、/quit |
保存并退出 |
Tab |
斜杠命令补全:/ 开头时循环补全,否则弹出命令调色板 |
Esc |
中断当前回合 / 关闭对话框(Claude Code 同款) |
| Ctrl-C | 中断当前回合(空闲时则退出) |
| Ctrl-D | 输入为空时退出 |
| ↑/↓ | 输入历史(调色板/选择器中为移动选择) |
| 其他内容 | 作为消息发给 agent |
界面布局
╭──────────────────────────────────────╮
│ 🐋 Welcome to dshcli! │ ← 圆角蓝色边框欢迎横幅(Claude Code 同款)
│ /help for help │
│ cwd: /path/to/dshcli │
│ model: deepseek-v4-pro │
╰──────────────────────────────────────╯
> Reply with exactly one word: OK ← 对话滚动区(<Static>),用户行蓝色
OK
⚙ bash ls ← 工具调用一行摘要
✓
🐋 Thinking… (3s · esc to interrupt) ← 流式期间:动词循环思考指示器
╭──────────────────────────────╮
│> /model show or switch the model│ ← Tab 调色板 / /model 选择器(圆角边框浮层)
│ ↑↓ select · esc cancel │
╰──────────────────────────────╯
> ← 输入行(自研单行编辑器,CJK 感知)
🐋 dshcli · deepseek-v4-pro · ↑73 ↓2 … ← 反白状态栏
整体视觉以 DeepSeek 蓝(#4D6BFE)+ 🐋 鲸鱼品牌标识重设计,参考 Claude Code 的
UI 规范:圆角欢迎横幅、动词循环思考指示器(esc to interrupt)、Tab 命令调色板、
低上下文警告(Context low (…) · Run /compact to compact & continue)。
每一条完成的输出行都会先用 string-width 按终端宽度预换行(CJK 安全),再立即
锁定进 <Static>,和 Claude Code 把完成行锁进滚动区的方式一致。动态区保持很小
(流式行 + 思考指示器 + 待回答问题 + 浮层),光标移动全部交给 Ink,退出时终端状态
必然恢复。当 stdin/stdout 不是 TTY 时(管道用法),同一套 runner 回退到普通的
readline REPL。
工作原理
dshcli 既是一个 npm 包,也是一个 Harness bundle(类似 dsh-headless)。
首次运行会在 $DSH_HOME/profiles/dshcli 初始化 profile,并通过
@deepseek-ai/dsh-app-boot 在进程内启动它,在 dsh-base 之上挂载两个插件:
dshcli/startup— 解析命令行参数并发布 flags。dshcli(runner,index.js)— 创建或续接 agent,然后交给tui.js(TTY 上的 Ink UI)或行内 REPL(管道场景)。
事件泵消费 assistant/chunk 事件做流式输出,工具调用渲染成一行摘要
(⚙ bash echo hi),str_replace_editor 的编辑以红/绿 diff 高亮,应答 agent 的
ask_user_question 提问,应答 tools 流水线的 approval/request 审批瀑布流。
/model 直接改 harness 的每步模型选择(installModelSelection),无需重建 agent,
下一条消息立即生效;裸 /model 的选择器读取 ctx.llm.listProviders() /
listModels() 的模型目录。/compact 走 ctx.compaction.compactNow()(由
dsh-compaction-basic 引擎实现),成功后重同步事件泵。
TUI 的几个"踩坑"细节(下面的测试套件都会覆盖):
- Ink 只会把单独的
\r识别为key.return;连发按键或粘贴会以单个多字符 chunk 到达,其中的\r会被当成字面字符插入导致画面乱码。输入分发器按 readline 语义拆分 chunk、逐行提交。 - Ink 的
<Static>按items引用做 diff(useMemo),历史数组必须每次渲染传 一份新拷贝,否则追加的行永远画不出来。 /clear必须自己物理清屏并重置 Ink 累积的静态输出——Ink 只会擦除最后一帧。
测试 —— PTY 闭环
scripts/pty-driver.py 在真实伪终端里启动这个二进制,喂入脚本化输入,再用迷你
VT100 解释器渲染屏幕——每个布局断言都对照真实渲染画面验证,无需人工介入。截图
输出在 scripts/out/。
python3 scripts/pty-driver.py <case> [rows cols] # 例如 all、basic、cjk
| 用例 | 验证内容 | API 调用次数 |
|---|---|---|
basic |
启动横幅、/help、/sessions、/model 热切换、/clear 物理清屏、/exit → 0 |
0 |
turn |
完整模型回合、状态栏 token 统计 | 1 |
tool |
bash 工具调用渲染(⚙ → ✓) |
1 |
interrupt |
流式中 Esc 与 Ctrl-C 各中断一次、输入恢复 | 2 |
cjk |
中文提问/回复、所有可见行不超终端宽度(含双宽字符) | 1 |
palette |
Tab 调色板、输入过滤、Enter 把命令插回输入行 | 0 |
picker |
裸 /model 选择器浮层、Esc 关闭 |
0 |
compact |
一轮对话后 /compact 走 harness compaction seam 出结果 |
1 |
firstrun |
空 DSH_HOME 首启:key 引导出现、0600 落盘、进入 TUI 退出 | 0 |
功能状态
已完成:流式多轮 REPL、全屏 Ink TUI(滚动区 + 状态栏)、会话续接
(--resume / --continue)、动词循环思考指示器、工具调用摘要、红/绿 diff 高亮、
斜杠命令、用户提问应答、审批应答、CJK 安全换行、蓝色系 + 鲸鱼品牌 UI、
Tab 命令调色板、Esc 中断、交互式 /model 选择器、/compact 上下文压缩、
PTY 测试闭环(9 个用例,含 4 个零 API 调用用例)。
尚未完成:独立的 subagent 面板。Harness 底层能力已具备,剩余的是终端渲染工作。