DSH 对 profile 配置保持热监听,新增或移除 bundle 会当场挂载,工具立刻可用。但 hmr 默认只监听配置,不监听源码模块,修改已经挂载的插件源码不会生效,必须重启。重启 DSH 意味着当前浏览器连接断开,如果重启失败,服务就再也起不来了。dsh-restart 把这件事做成一次工具调用,并保证两件事:一是优雅退出,二是退出前确认“有人会把它拉起来”。
插件简介¶
dsh-restart 是一个 DSH 插件,由 ajia1206 维护,采用 MIT 许可证。它为正在运行的 DSH 进程提供一键重启能力,具备 launchd 监管检测、可核验的重启日志以及右下角 GUI 控件。
核心能力¶
优雅退出与托管检测¶
插件探测自己是被谁托管的,再决定退出策略:
- Desktop 策略:识别为 macOS 桌面版(有主进程与 IPC 连接),通过 macOS 应用退出/重新打开走一遍。
- Launchd 策略:本进程是该 launchctl job 的主进程,且 KeepAlive 是无条件开启(条件式策略不认),则直接调用
ctx.appExit(0)优雅退出。 - Supervisor 策略:没有可确认的 KeepAlive 托管(手动启动、父进程不随退出的情况),派 detached supervisor。它在被杀之前先写记录,并在恢复资源预检通过后写
supervisor-ready。插件必须等到这两条齐全才允许自己退出,8 秒内没等到就中止。 - None 策略:没有托管且
superviseFallback=false,拒绝重启。
可核验的重启日志¶
重启日志以 JSONL 格式记录在 <home>/.dsh/logs/dsh-restart.log,以 0600 权限创建。关键记录类型包括:
* boot:插件就绪时写入,带 pid/ppid/模式/端口/profile。
* armed:安排重启时写入,带 armId、fireAt 与原因。
* supervisor / supervisor-ready:Supervisor 握手状态。
* exiting / supervised:退出过程与拉起结果。
* cancelled / aborted:取消或中止状态。
GUI 控件与鉴权¶
Web 界面右下角有一个悬浮的“↻ 重启”按钮,显示托管方式、端口、停机时长,支持延迟选择与原因填写。控件落在 shell.overlay 座位上,点击穿透。
鉴权方面,注册路由本身不带鉴权,但强制只接受回环来源(127.0.0.0/8、::1、::ffff:127.x)。非回环一律 403。这是为了防止反向代理转发的外部请求误伤。
安装¶
安装前请检查源码与许可证。
dsh plugin --profile web add github:ajia1206/dsh-restart
典型用法¶
插件提供三个命令行工具和一个浏览器控件,共用同一套实现。
- dsh_restart [delaySeconds] [reason] [dryRun]
安排一次重启。默认延迟 10 秒,为了让工具结果先送达浏览器。dryRun只看计划不安排。 - dsh_restart_status
查看托管方式、当前是否已安排重启、以及重启历史。这是核验手段,可计算停机时长。 - dsh_restart_cancel
在触发前取消重启。 - 浏览器右下角悬浮按钮
点击悬浮按钮进行重启,需经过确认弹窗。
配置¶
插件依赖 cordis.patch.yml 补丁,路径配置需使用绝对路径(不展开 ~ 或环境变量)。
- id: dsh-restart
name: dsh-restart
config:
logPath: /绝对路径/.dsh/logs/dsh-restart.log
childLogPath: /绝对路径/.dsh/logs/dsh-restart-child.log
defaultDelaySeconds: 10
maxDelaySeconds: 600
superviseFallback: true
trustParentJob: false
healthUrl: ''
healthTimeoutMs: 60000
healthIntervalMs: 500
exitTimeoutMs: 45000
bootHistoryLimit: 5
注意事项¶
- 未发布到 npm:
dsh-restart这个名字在 npm 上已被占用,本包通过 GitHub Release 的 tgz 安装。 - 绝对路径:
logPath和childLogPath必须是绝对路径,写~会在当前目录下创建名为~的目录。 - 鉴权说明:强制只接受回环来源。如果宿主没有 connection 服务,外部请求(即使是本机反向代理)也会被 403。
- 重复实例:Supervisor 无法证明没有别人已经把它拉起来(launchd、手工操作等),因此可能存在两个实例同时运行的情况。
- 权限:重启日志以 0600 创建,但 supervisor 的子进程日志
childLogPath按系统默认权限创建。