DSH 重启按钮(DSH Restart Button)
一个 DeepSeek Harness(DSH)的持久化插件,在网页设置里加了一个「重启 DSH」按钮。点击后会强制结束当前 DSH 进程并重新拉起——是真正的进程级重启(杀进程 + 起新进程),而不是进程内热重载,页面会自动重连。
可选地,还可以搭配一个小型守护循环一起运行,让新进程在同一个控制台里回来(有日志、可 Ctrl+C),实现真正的「原地重启」。
> English version: README.md
---
功能
- 在 设置 → 通用 里、主题/外观开关下方,加了一个「重启 DSH」按钮。
- 两次点击确认(点一下 → 「确认重启」→ 执行),避免误触。
- 重启流程:
1. 写入标记文件(dsh-restart.pending); 2. 启动一个脱离式 worker,执行 taskkill /F /PID <dsh>; 3. worker 等待几秒: - 如果守护循环已经重新拉起 DSH(3080 端口恢复)→ 完成,原地重启; - 否则 → 后台无窗口兜底重启。
- 浏览器轮询插件接口,只有新进程(新 PID)开始服务后才刷新页面,并有 30 秒硬兜底。
---
为什么这样设计
动态 Cordis 插件随进程一起消亡,所以持久化插件没法从「自己内部」重启自己的宿主进程,必须借助外部「帮手」:
┌─────────────── Web UI ───────────────┐
│ settings.general.item (order 15) │
│ [重启 DSH] 按钮 ──POST─────────────►│
└──────────────────────────────────────┘
│
▼
宿主插件 (lib/index.js)
┌─────────────────────────────────────────────┐
│ 写标记 + 启动脱离式 node worker │
│ worker: taskkill /F /PID <dsh> │
│ 等待 → 3080 端口恢复? │
│ 是 → 守护器完成了重启 │
│ 否 → 后台兜底重启 │
└─────────────────────────────────────────────┘
可选守护器 (dsh-loop.cjs) ← 在你的终端里运行
┌─────────────────────────────────────────────┐
│ loop { spawn dsh web (stdio inherit) } │
│ 退出时: 有标记?→ 重新拉起 : 退出 │
└─────────────────────────────────────────────┘- worker 上的
detached: true是关键:它必须能活过 DSH 自己的死亡(taskkill)才能完成重启;Windows 下非脱离的子进程会随父进程一起被杀。 - 曾尝试用
AttachConsole把新进程挂回原终端,但在现代终端(ConPTY / Windows Terminal)下会报ERROR_INVALID_PARAMETER (87),所以改用了守护循环方案——不依赖任何控制台 API,更可靠。
---
仓库结构
dsh-restart-button/ # 插件包 (@dsh-external/dsh-restart-button)
├── package.json # DSH bundle + client 清单
├── cordis.patch.yml # 把插件行插入组合的补丁
├── lib/
│ ├── index.js # HOST:/api/dsh-restart 路由 + 重启 worker
│ └── client.js # CLIENT:设置页按钮 + 自动刷新轮询
├── dsh-loop.cjs # 原地重启守护器(在终端里运行)
└── desktop/
├── dsh-start.cmd # 双击启动器(可见控制台)
└── DSH.vbs # 桌面快捷方式(隐藏启动 + 自动开浏览器)---
安装
1. 把插件装进你的 DSH profile
node "C:\Users\<you>\AppData\Roaming\npm\node_modules\@deepseek-ai\dsh\lib\bin.js" plugin --profile web add "C:\path\to\dsh-restart-button"(如果 dsh 在 PATH 上,也可直接 dsh plugin --profile web add <path>)
这会把 @dsh-external/dsh-restart-button 加进 profile bundle。重启 DSH 后生效。
2.(可选)运行守护器实现原地重启
没有守护器时按钮也能用,但新 DSH 会以后台无窗口方式启动。想在自己的终端里原地重启:
node "C:\path\to\dsh-restart-button\dsh-loop.cjs"它会在同一个控制台里循环拉起 dsh web(stdio: inherit)。Ctrl+C 停止。
3.(可选)桌面快捷方式
desktop/DSH.vbs 就是桌面「DeepSeek Harness (DSH)」快捷方式背后的脚本。双击它会:
1. 检查 DSH 是否已在 http://127.0.0.1:3080 上运行; 2. 若没运行,启动守护器(隐藏控制台); 3. 等 DSH 起来后自动打开浏览器。
desktop/dsh-start.cmd 是可见控制台版本(能看到日志 / Ctrl+C)。
---
配置
有几处绝对路径是针对某台机器写死的,换机器安装时需要改:
| 文件 | 要改什么 |
|---|---|
lib/index.js | LOG(日志文件路径)、FLAG(重启标记路径) |
dsh-loop.cjs | BIN(DSH 的 bin.js 路径)、FLAG(必须与 lib/index.js 一致) |
desktop/DSH.vbs | powershell.exe ... node '<dsh-loop.cjs 的路径>' 这条命令 |
desktop/dsh-start.cmd | dsh-loop.cjs 的路径 |
插件运行时会从 process.execPath / process.argv 自动取 node 和 args,这两项不用写死。
---
排障
重启流程会把详细日志写到 dsh-restart.log(路径在 lib/index.js 里配置)。关键标记:
[runner] taskkill done, status=0— 旧进程已杀。[runner] port 3080 is up -> supervisor relaunched in-place, no fallback needed— 原地重启成功。[runner] port 3080 still down after wait -> headless fallback— 没在跑守护器,DSH 以后台方式重启。restart handler error:— 插件自身报错。
---
许可证
[MIT](LICENSE)