@chenkai114/dsh-daemon
将 DeepSeek Harness 的 web 服务(dsh web)注册为自启动、自愈的后台服务:LaunchAgent / systemd / cron 加 30 秒健康检查 watchdog,并提供 7 个 dsh_daemon_* 工具(安装/卸载/重装/状态/启动/停止/更新)。
安装
dsh plugin --profile web add @chenkai114/dsh-daemon
沙箱测试结果
| 阶段 | 结果 |
|---|---|
| 1 安装 | ✓ |
| 2 列装 | ✓ |
| 3 挂载 | ✓ |
| 4 启动 | — |
四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。
README
版本对照(dsh-daemon ↔ dsh)
dsh-daemon · 支撑的 dsh · 说明
0.1.29 · 0.1.x 与 0.2.x · 自动更新加 dsh 兼容门禁:每版在 package.json 声明 dsh.requires.dsh,更新前比对客户端已装 dsh 版本,不满足/未声明/读不到就跳过自动升级(dsh-daemon update --apply 可人工强制);更新检查改为 2 次尝试 + 15s 预算,错误细分为 timeout / DNS / HTTP / 连接失败,status 显示上次成功检查时间
0.1.28 · 0.1.x 与 0.2.x · 修「健康检查误杀 + 重启风暴」:/health 单次预算 5s → 20s、失败阈值 3 → 5(~50s 真超时才重启);tick 串行(tickBusy)+ launch() 单飞,杜绝同一秒拉起两个 dsh web(EADDRINUSE);收养未托管但正在服务的 dsh web(纠正 pid 文件)而不是再拉一个;停进程前校验「这个 PID 真的是 dsh web」(PID 复用不误杀);status 报出 pid 文件与实际监听者不一致;非 JS 入口(dsh.ps1/.cmd shim)拒绝启动并明确报错
0.1.27 · 0.1.x 与 0.2.x · 健康检查间隔默认 30s → 10s(自愈更快);新增 dsh-daemon logs 与 dsh_daemon_logs:dsh web 启动失败时像 systemctl 一样打印明细入口(web + watchdog 日志尾部、/health、PID、启动时长)
0.1.26 · 0.1.x 与 0.2.x · 启动宽限期:dsh web 启动慢(大插件集、冷缓存)时不再被 watchdog 按 90 秒判死反复重启,宽限期内不计健康失败(DSH_DAEMON_STARTUP_GRACE,默认 5 分钟);停旧进程改为先 SIGTERM 再 SIGKILL 并等端口真正释放(修 EADDRINUSE 连锁失败);status / start 如实报「仍在启动」
0.1.25 · 0.1.x 与 0.2.x · 适配 0.2.x 的 shell 服务改名:run(spec) → execute(spec) + 句柄 result()(0.2.1 上 reinstall 曾报 shell.run is not a function),并兼容两种结果形状
0.1.24 · 0.1.x(0.2.x 部分路径不可用) · OIDC 发布流水线;未适配 0.2.x shell API
0.1.23 · ≥ 0.1.2-alpha.1(token 认证起) · 注册漂移自愈、status 如实上报注册状态、拒绝易失 DSH_HOME
0.1.21–0.1.22 · 同上 · 单实例守卫校验 cmdline、dsh web 显式传 cwd
0.1.20 · 同上 · DSH_DAEMON_TRUSTED_HOST:反代场景下给 dsh web 追 --trusted-host
0.1.19 · 同上 · 自动开浏览器补齐 token 认证的入场 cookie
≤ 0.1.18 · ≥ 0.1.0-rc.8(--no-open 起) · 更早的 dsh 没有 --no-open,watchdog 启动时会跳过该参数
两个门限常量取自代码(lib/index.js):DSH_NO_OPEN_MIN = 0.1.0-rc.8、DSH_TOKEN_AUTH_MIN = 0.1.2-alpha.1。
dsh 侧与 daemon 交互的接口只有三处:web 启动参数、/health 探活、以及注入的 shell/fs 服务 —— 后者是 0.2.x 唯一改过的地方。
dsh-daemon
[中文](README.md) | [English](README.en.md)
将 DeepSeek Harness 网络服务(dsh web)注册为自启动、自愈的后台服务。
安装后,dsh web 将:
- 登录时自动启动(LaunchAgent
RunAtLoad/ systemdWantedBy=default.target/ cron@reboot) - 睡眠唤醒后自动重启
- 自愈:watchdog 每 10 秒(可配置)健康检查一次
http://127.0.0.1:<port>/health,连续 3 次失败后重启服务 - 慢启动安全:刚拉起的
dsh web处在启动宽限期(DSH_DAEMON_STARTUP_GRACE,默认 5 分钟)内时,健康检查失败不计入重启阈值,进程也不会被杀 - 不依赖当前会话:watchdog 是独立生成的脚本,而非内存中的插件
安装/卸载永远不会触碰当前正在运行的会话。
账号对应关系(npm scope / GitHub 账号)见 [CONTEXT.md](CONTEXT.md)。
使用方式
方式 A —— 用 dsh plugin 安装(v0.1.9+,推荐)
1. 用官方插件管理器将包安装到 web profile(在 profile 目录内运行 pnpm,使 loader 能解析到它;仅全局安装不够——见下):
dsh plugin --profile web add @chenkai114/dsh-daemon
(需要 PATH 上有 pnpm——用 corepack enable 一次性启用。)
> 为什么不能只 npm install -g?loader 以 Node ESM 解析导入 name: 行,解析锚点是 profile 目录(~/.dsh/profiles/web/);全局 node_modules 不在该解析链上(NODE_PATH 对 ESM 无效)。profile 自己的 node_modules——由 pnpm 管理——才是包可达的原因。
2. 重启 dsh web。包声明了 dsh.bundle manifest,dsh plugin add 会把它自动加入 dsh.profile.bundles,启动时作为 bundle 层挂载——不需要(也不应该)再手动往 ~/.dsh/profiles/web/cordis.patch.yml 里 insert 同一行,否则会触发 duplicate loader entry id: dsh-daemon 启动失败。
七个 dsh_daemon_* 工具即可供每个 agent 使用——直接让 agent 运行 dsh_daemon_install。
以后升级:dsh plugin --profile web update @chenkai114/dsh-daemon(并重启)。
⚠️ 从 v0.1.8 及更早版本升级:如果你之前按旧文档在~/.dsh/profiles/web/cordis.patch.yml里手动加过- insert: dsh-daemon行,升级后必须删掉那一行(保留文件里其他内容),否则 bundle 层 + 手动层会插入同一个id: dsh-daemon两次,dsh web启动时报duplicate loader entry id。删除后重启即可。
权限说明:daemon 管理用户级系统服务(LaunchAgent plist、$DSH_HOME下的状态文件),因此插件对其文件与命令操作请求danger-full-access。若部署拒绝提权,工具会以沙箱拒绝失败。
方式 B —— 动态 Cordis 插件(无需安装)
将 lib/index.js 的内容粘贴到 cordis_define 的 code.host 字段并运行。这正是插件在真实会话中开发与验证的方式:沙箱提供 harness 全局,文件以 return plugin; 结尾。
端口
默认端口为当前监听的 webServer 端口(通常 3080),其次 DSH_WEB_PORT,再其次工具显式 port 参数。更换端口后运行 dsh_daemon_reinstall。
架构
守护进程是一个watchdog 监督者,由三部分组成。
1. 平台注册
一个按用户注册的服务,负责在登录时启动 watchdog 并保持其存活:
平台 · 机制
macOS · LaunchAgent ~/Library/LaunchAgents/com.deepseek-ai.dsh-watchdog.plist —— ProgramArguments=[node, watchdog.js]、RunAtLoad、KeepAlive{SuccessfulExit:false}、ThrottleInterval=10,环境变量携带 DSH_WEB_PORT 与 DSH_HOME。通过 launchctl load -w 加载。
Linux · systemd 用户单元 ~/.config/systemd/user/dsh-watchdog.service —— Type=simple、Restart=always、RestartSec=10、StartLimitIntervalSec=0;通过 systemctl --user enable --now 启用。systemd 不可用时回退为 cron @reboot 条目。
Windows · VBS 启动器 + 计划任务 —— 任务 DshWatchdog(XML 在 $DSH_HOME/daemon/dsh-watchdog-task.xml,UTF-16LE)在登录时运行 wscript.exe //B dsh-watchdog.vbs;VBS 设置 DSH_WEB_PORT/DSH_HOME 并以隐藏窗口启动 node watchdog.js。RestartOnFailure PT1M/999,MultipleInstancesPolicy=IgnoreNew。通过 schtasks /Create 注册。
Windows 支持按 macOS/Linux 的同等行为实现(插件的 shell 层在 win32 下切换到 PowerShell,即 DSH 的 shell 执行器),但尚未在真实 Windows 机器上验证。
2. watchdog 循环
生成的独立脚本 $DSH_HOME/daemon/watchdog.js(零依赖,任意 Node ≥ 18 可运行,无需会话):
- 将自身 PID 写入
.dsh-watchdog.pid;SIGINT / SIGTERM / SIGHUP 清理后退出;单实例锁拒绝重复的 watchdog - 启动时若
http://127.0.0.1:<port>/health不健康,则拉起 web 服务(node <dsh> web --port <port>,分离运行,输出到logs/dsh-web.log) - 之后每 10 秒(可通过
DSH_DAEMON_HEALTH_INTERVAL配置): - 存在
.daemon-stopped(用户暂停监控)或.daemon-restart.lock较新(< 120 秒,重启进行中)时跳过; - tick 间隔超过 90 秒(睡眠唤醒)时重启服务;
- 服务仍在启动宽限期内(
.dsh-web.started距今 <DSH_DAEMON_STARTUP_GRACE,默认 5 分钟)且进程存活时,只记录「仍在启动」,不计失败、不重启——大插件集/冷缓存的dsh web可能几十秒到几分钟才对外提供/health,旧的「90 秒判死」会让它永远起不来; - 进程已消失(崩溃、激活期
EADDRINUSE、OOM)时立刻重启,不等满 3 次失败; - 连续 3 次健康检查失败后重启服务(进程存活但超过宽限期仍未健康);
- 停旧进程先发 SIGTERM,等待最多 8 秒(
dsh web会优雅退出并释放监听端口),仍不退再 SIGKILL;随后等端口真正空闲(最多 5 秒)才拉起新进程,避免新进程在插件激活期报EADDRINUSE而秒退; .daemon-installed标记消失(已卸载)时退出;- 日志写入
logs/watchdog.log(5 MB × 3 轮转)。
3. daemon 感知的 start / stop
dsh_daemon_stop写入.daemon-stopped(watchdog 不再重启服务),并停止正在运行的托管服务。dsh_daemon_start清除该标记、确保 watchdog 运行,并在服务不健康时拉起它。
工具
插件仅包含 Host 侧,注册 8 个可供模型调用的工具:
工具 · 功能
dsh_daemon_install · 生成 watchdog.js 与状态文件,写入 L
…(truncated)
以上内容来自 npm 上的 README,我们只做格式化,不改内容。
版本
npm 上共发布:30,最后更新 2026-10-29