← Back to home@felixpu

dsh-restart-autostart

在 DSH 网页版「设置 → 通用」加入进程控制行:手动重启 dsh web 宿主进程,以及「跟随系统启动」勾选框(写入 macOS launchd / Linux systemd / Windows 服务自启条目,开机拉起并在崩溃后自动重启)。

Stars
1
Language
JavaScript
Created
Oct 10, 2026
Updated
Oct 13, 2026
GitHub repo

Introduction

dsh-restart-autostart

给 DSH(DeepSeek Harness)网页版加入两处进程控制入口:

  • 手动重启:设置面板标题栏上的红色「重启」按钮(紧挨「打开配置文件」左侧)。 任何设置分页都能点到它,不必滚动到「通用」页去找;重启后页面自动探测服务恢复。
  • 跟随系统启动:「设置 → 通用」里的勾选框,写入系统自启条目 (macOS launchd / Linux systemd / Windows 服务),开机拉起,并在崩溃后自动重启

关于包名:本包是 dsh-restart 的重命名版本 —— npm 上 dsh-restart 已被第三方占用(维护者 anweat),故更名为 dsh-restart-autostart 发布。

安装

dsh plugin --profile web add github:felixpu/dsh-restart-autostart

安装后重启宿主进程。

使用

手动重启

  1. 打开设置(任意分页都可以)。
  2. 点标题栏右侧、「打开配置文件」左边的红色「重启」按钮。
  3. 二次确认后开始重启:按钮下方出现进度浮层(正在停止旧服务 → 正在启动新服务 → 已恢复)。

前端会轮询 GET /dsh-restart-autostart/health 判断服务是否恢复,因此重启过程无需手动刷新。

按钮用 danger 配色是刻意的:重启会中断所有正在进行的会话与后台任务。 失败或超时也会在同一个浮层里显示原因,并保持显示直到你手动关闭。

跟随系统启动

设置 → 通用 → 勾选「跟随系统启动」。

重启按钮搬到标题栏后,通用页这一行只剩自启开关,标题也随之改成「跟随系统启动」。

勾选后会向当前平台注册自启条目:

平台机制条目名
macOSlaunchdcom.dsh.restartautostart.<port>
Linuxsystemd 用户级服务dsh-restart-autostart-<port>.service
Windows系统服务dsh-restart-autostart-<port>

守护默认作用于当前宿主进程所使用的端口,因此不会与既有 3080 生产守护冲突。

Linux 上依赖 systemd 用户实例的 linger 才能在无人登录时拉起;非 systemd 发行版(如 Alpine 用 OpenRC)不可用。

启动互斥:为什么两个实例不会抢端口

手动重启与守护是两条独立通道,都能拉起宿主。宿主被 kill 后到新宿主 listen 之间约有 10 秒空窗(新宿主在加载整棵插件树),这段空窗里端口是空的 —— 两个通道 会双双认定「现在就我,我上」,各自加载一遍插件树,最后只有一个能绑上端口,另一方报 EADDRINUSE 退出。日志里看着像随机故障,其实是必然。

解法是一把**「正在启动」跨进程锁**(logs/starting-<port>.lock,内容为纯十进制 pid):

  1. 手动重启脚本在动手 kill 之前先把自己写进锁;
  2. 拉起新宿主后,立刻把锁改写成新宿主的 pid(脚本随即退出,新宿主才活得够久);
  3. 守护自己拉起宿主时也做同一件事 —— 否则这把锁只覆盖了插件这条通道, 像 ~/.dsh/start.sh 这样的第三方看不到「守护正在启动」,照旧会插进来抢;
  4. 守护每次启动前读锁:持有者进程还活着就让路,等对方出结果; 持有者已不存在 → 孤儿锁,随手清掉,自己接管启动。

判据是「锁里记的 pid 还活着没有」,不是等待时长 —— 进程一死锁即失效,永远不会 留下需要人工清理的残锁,也不需要「等满 N 秒就假定安全」这类靠不住的启发式。

两条通道各自「正确执行」却互相踩踏,是这类故障最难查的地方:没有谁写错了代码。 让它们对同一件事(谁在启动)有共同认知,比在任一方加延迟或重试都可靠。

第三方重建了同一份判据也没问题 —— 关键是持有者身份的约定(pid 存 logs/starting-<port>.lock) 要对所有拉起路径统一,任何一方自己发明一套都会重新打开这个缺口。

数据落盘位置

全部落在 ~/.dsh-restart-autostart/,与 ~/.dsh/ 完全分离:

路径用途
~/.dsh-restart-autostart/guard.mjs守护运行体(稳定落点)
~/.dsh-restart-autostart/logs/日志与计数
~/.dsh-restart-autostart/logs/starting-<port>.lock启动互斥锁(持有者为存活进程时有效,自动失效无需清理)

守护脚本被安装到 ~/.dsh-restart-autostart/guard.mjs 而非包内路径 —— 因为包目录会随 pnpm 重装、换 profile、link: realpath 而漂移。

⚠️ 从旧名 dsh-restart 升级

本包从旧版升级时,运行时标识全部改名,旧数据不会自动迁移:

项目旧新
配置目录~/.dsh-restart/~/.dsh-restart-autostart/
路由/dsh-restart/*/dsh-restart-autostart/*
launchd Labelcom.dsh.restart.<port>com.dsh.restartautostart.<port>
systemd unitdsh-restart-<port>.servicedsh-restart-autostart-<port>.service

升级步骤:

  1. 移除旧包(dsh plugin --profile web remove dsh-restart)
  2. 安装新包并重启
  3. 重新勾选一次「跟随系统启动」
  4. 手动清理旧条目与旧目录,否则可能残留两个守护进程抢同一端口
# macOS 示例
launchctl bootout gui/$(id -u)/com.dsh.restart.3080 2>/dev/null
rm -f ~/Library/LaunchAgents/com.dsh.restart.*.plist
rm -rf ~/.dsh-restart

宿主路由

方法路径用途
GET/dsh-restart-autostart/health存活探针(前端轮询判断恢复)
POST/dsh-restart-autostart/restart手动重启
GET/dsh-restart-autostart/autostart/status读取自启状态
POST/dsh-restart-autostart/autostart/enable启用自启
POST/dsh-restart-autostart/autostart/disable停用自启

测试

DSH_RESTART_GUARD="$PWD/lib/guard/guard.js" bash test/guard-classify.test.sh

覆盖守护的失败分类逻辑:端口被占、起来了但非零退出、插件树加载失败、启动过慢、待命状态。

测试需指定 DSH_RESTART_GUARD 指到包内守护脚本;未指定时默认读 ~/.dsh-restart-autostart/guard.mjs(需先在设置里启用过一次自启)。

展示元数据(locale)

locale/en.json 与 locale/zh.json 提供插件展示元数据(meta.title / meta.description), Plugin Manager 与设置页无需激活插件即可读取,用于显示本地化的插件名与说明。 这与运行时 UI 文案(客户端 ctx.locale.register)是两套东西。

{ "meta": { "title": "…", "description": "…" } }

⚠️ 两个容易漏的点(漏任一个都会静默失效,不报错):

  1. 必须在 package.json 的 exports 里导出 ./locale/*.json —— 宿主经 Node 模块解析器 读取该资源,未导出的子路径会得到 ERR_PACKAGE_PATH_NOT_EXPORTED,被当作「没有 locale」跳过。
  2. files 需包含 locale —— 否则 pnpm pack / npm publish 的产物里不会带上它。

icon.svg 走顶层 icon 字段(相对路径),不需要 exports。

客户端挂载点

| 槽位 | 注册 id | 用途 | 排序 | |---|---|---|---|---| | settings.action | dsh-restart-autostart/restart | 设置面板标题栏的重启按钮(所有分页共用) | -10(官方「打开配置文件」为 0,故排在它左侧)| | settings.general.item | dsh-restart-autostart/autostart | 「设置 → 通用」里的「跟随系统启动」行 | 90 |

客户端 bundle 仅 require 平台种子表内的模块(react、@deepseek-ai/dsh-client-ui-primitives)。

许可证

MIT © felixpu

仓库

https://github.com/felixpu/dsh-restart-autostart