deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
PROJECT README
在无头服务器上把 DeepSeek Harness 变成 Claude Code 风格的交互式终端 CLI。
这是一个 out-of-tree 的 dsh profile bundle:叠加在官方 dsh-base 之上,
复用 dsh 的全部核心能力(agent 循环、会话持久化、工具、凭据、settings、沙箱审批),
只把官方 dsh-headless 的"提交一次任务就退出"换成持久 REPL 循环——
同一个 agent 反复对话、回复流式输出、审批在终端应答、每轮结束后会话落盘、
随时 --resume 找回旧会话。不挂载任何 Host / HTTP / 浏览器插件。
$DSH_HOME/sessions/*.jsonl(默认 ~/.dsh/sessions)--resume <sessionId>:恢复旧会话继续聊(复用官方 agents.resume())workspace-write + ask 策略下的权限询问直接在终端 y/n 应答/help /sessions /model /permission /cancel /session /workspace /exitagent.cancel({kind:'user'})),再按一次退出--model --provider --preset --once,任务位置参数可选(先跑一轮再进 REPL)$DSH_HOME/cli.history,上下键翻查,重进保留/he+Tab → /help;/model dee+Tab → 模型名--once:跑完任务(或一轮)即退出,脚本友好(dsh --profile cli --once "task")--task 或 resume 旧会话自动恢复),横幅 + 状态行显示dsh-cli · session-… · "标题" · 模型 · 策略 · cwdyou (deepseek-v4-flash)>,/model 切换后立即反映assistant [step N]>,step 推进处插入 [step N] 分隔(仅行首,不切断单词)⚙ bash … 行(仅行边界,绝不切断单词;行中则走活动行)⚙ step N · bash …(内容变化时才原位重绘:新 step / 工具开始 / 工具完成,绝不逐帧刷屏),完成 ✓;轮末摘要 ⚙ N tool call · S steps · ↑in ↓out tok/help 分组排版:session / info / control 三组⚠ approval required 框内分层显示工具名(亮黄粗体)/模式/原因NO_COLOR 下自动降级纯文本(FORCE_COLOR=1 可强制着色)dsh-cli-interactive/
├── package.json # 声明 dsh.bundle.patch → 安装时自动加入 profile 层栈
├── cordis.patch.yml # 组合层(不要动插件行,只可改 persona 等配置值)
├── lib/
│ ├── ui.js # ANSI 样式/布局助手(零依赖):色板、可见宽度、box、表格、spinner、工具摘要
│ ├── startup.js # 命令行参数(--resume/--model/--provider/--preset/[task]/--once)
│ └── runner.js # REPL 主循环——banner、you> 提示符、流式输出、slash 命令、审批提示、会话横幅
├── bin/dsh-cli.js # 便捷入口:dsh-cli ≡ dsh --profile cli
├── scripts/build.mjs # 构建脚本(node --check 语法校验 + 组装 dist/,零依赖)
├── tests/unit.mjs # 单元冒烟测试(node tests/unit.mjs)
└── README.md
零工具链、零网络依赖(Node ≥ 22 自带):
node scripts/build.mjs # 语法校验 + 生成 dist/
npm run check # 只做语法校验
产物在 dist/:lib/ + bin/ + cordis.patch.yml + package.json + README + LICENSE。
前置:Node 22 + 全局 @deepseek-ai/dsh(npm i -g @deepseek-ai/dsh)+
pnpm(npm i -g pnpm,dsh plugin 转发给 pnpm),
密钥放 ~/.dsh/.env(DEEPSEEK_API_KEY=sk-...)。
dsh plugin 首次使用会初始化 profile(bundles 起始为 [dsh-base]),
然后转发 pnpm 安装你的包;因为包声明了 dsh.bundle,会自动加入
dsh.profile.bundles 层栈(无需手改 manifest)。
任意一台装有 dsh 的机器(服务器 / 本机),clone 本仓库后构建出 dist/
再安装:
# 1. 拉取源码
git clone https://github.com/studyinglx/dsh-cli.git
cd dsh-cli
# 2. 构建出 dist/(零工具链,Node ≥ 22 自带即可)
node scripts/build.mjs
# 3. 安装到 dsh profile(本地路径指向 dist/)
dsh plugin --profile cli add file:$PWD/dist
# 4. 验证组合层(不启动)
dsh --profile cli --dump-config
# 5. 使用
dsh --profile cli # 进入 REPL
dsh --profile cli "先 review 一下代码库" # 先跑一轮,然后进入 REPL
dsh plugin首次运行会自动初始化cliprofile(bundles 起始为[dsh-base])。- 已安装过旧版本时,先
dsh plugin --profile cli remove dsh-cli-interactive再 add, 或重新 add 覆盖(pnpm 会按路径重装)。- 拉取到的源码可直接改(lib/、cordis.patch.yml),改完
node scripts/build.mjs重建再 add 即生效。
# 从 dist 目录安装(本地路径)
dsh plugin --profile cli add file:/path/to/dsh-cli-interactive/dist
# 或发布到 npm 后按包名安装
npm publish
dsh plugin --profile cli add dsh-cli-interactive
# 验证组合层(不启动)
dsh --profile cli --dump-config
cd /srv/workspace # 启动目录 = workspace 根
dsh --profile cli # 进入 REPL
dsh --profile cli "先 review 一下代码库" # 先跑一轮,然后进入 REPL
dsh --profile cli --once "先 review 一下代码库" # 跑一轮即退出(脚本友好)
dsh --profile cli --resume session-xxxx # 恢复旧会话
dsh --profile cli --model deepseek-v4-pro # 指定模型
dsh-cli --resume session-xxxx # 或用包装命令
| 命令 | 作用 |
|---|---|
/help |
命令列表(分组排版) |
/sessions |
列出 $DSH_HOME/sessions 下最近的 20 个会话(递归嵌套布局,id/大小/时间) |
/session |
显示当前会话 id |
/workspace |
显示 workspace 根目录 |
/model [id] |
查看 / 切换模型(下一轮生效;如 deepseek-v4-flash、deepseek-v4-pro) |
/permission [ask\|never] |
查看 / 切换审批策略(写会话日志,模型会看到通知) |
/cancel |
取消正在运行的轮次 |
/exit /quit |
退出(会话已持久化) |
agent 一轮内部会自主多轮调用工具直到停稳(whenIdle()),所以单条消息可以持续
几分钟到几小时;进程被杀则中断(会话日志保留,--resume 可续)。用 tmux 保活:
tmux new -s dsh 'cd /srv/workspace && dsh --profile cli'
# Ctrl-b d 分离,随时 tmux attach -t dsh 回来
管道模式(脚本友好):
echo "任务" | dsh --profile cli --once也可以正常 工作——readline 监听器在任何异步初始化之前注册,管道数据/EOF 不会丢失。 空输入(立即 EOF)同样干净退出。
| 官方 dsh-headless | 本包 |
|---|---|
headless-startup 只解析任务位置参数 |
cli-startup 增加 --resume/--model/--provider/--preset/--once |
headless-runner:提交 1 次 → 打印 → 退出 |
cli-runner:REPL 循环 + 流式 + 审批应答 + slash 命令 |
无审批应答(无人应答 → unavailable → 拒绝) |
在 setup 中注册 approval/request waterfall 监听器,终端 y/n 应答 |
agents.create() 一次 |
agents.create() / agents.resume()(resumeSessionId 字段) |
| 退出码 = 本轮结果 | 交互退出码 0;轮次 error 提示但不退出 |
ctx.config 在 apply 返回后不可读,config 必须从 apply 第二参数取。node scripts/build.mjs 做语法校验(npm run check 只校验不打包)。$DSH_HOME/sessions/<project>/<id>/session.jsonl[.zstd](嵌套布局,
/sessions 按此递归遍历)。$DSH_HOME/sessions/*.jsonl + --resume 恢复。/permission never 或 DSH_PERMISSION_MODE=danger-full-access 预置策略。~/.dsh/settings.yaml 的 llm-deepseek 段热加载;
DEEPSEEK_API_KEY 环境层优先)。dsh-cli-interactive)+ /startup 子路径,
与官方 @deepseek-ai/dsh-headless/startup 同款约定。apply(ctx, config) 只做
run(ctx, config).catch(...) 就返回,run 内部才 await loader。
async apply 会与 loader settle 互相等待而死锁(启动无任何输出);
ctx.config 在 apply 返回后不可读,config 必须从 apply 第二参数取。cordis.patch.yml 插入行,或在 profile 的
cordis.patch.yml($DSH_HOME/profiles/cli/cordis.patch.yml)覆盖。npm i -D typescript @types/node 后 npx tsc -p tsconfig.json。CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。