dsh-cli
Đã xác minh@aruvelut_6/dsh-cli · v0.1.1 · MIT
Interactive terminal CLI for DeepSeek Harness — a Claude Code-like REPL
Cài đặt
dsh plugin add @aruvelut_6/dsh-cli Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.
Mã nguồn
Phát hành lên npm mà không có repository công khai. Hãy kiểm tra nội dung package trước khi cài.
Tác giả
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 底层能力已具备,剩余的是终端渲染工作。