ajia1206/dsh-restart ↗★ 0

dsh-restart

One-call restart for the running DSH process, with launchd-aware supervision detection, a verifiable restart log, and a bottom-right GUI control. 适合需要频繁重启DSH服务以应用配置或更新插件的开发与运维人员。

패키지
dsh-restart
호환성
미검증
Harness peer 범위
*
버전
0.1.0
라이선스
MIT
최근 업데이트
2026. 9. 29.

같은 패키지 이름의 다른 저장소

설치

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:ajia1206/dsh-restart

配置

- 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

路径必须是绝对路径:这两个值会被原样使用,不展开 ~,也不展开环境变量。写 ~/.dsh/... 会在当前工作目录下真的建一个名叫 ~ 的目录。不想手写路径就不要配这两项,用默认值——默认值由 homedir() 拼出来,是正确的。

字段默认值含义
logPath/.dsh/logs/dsh-restart.log重启记录(JSONL)
childLogPath/.dsh/logs/dsh-restart-child.logsupervisor 拉起的新进程的 stdout/stderr
defaultDelaySeconds10默认延迟秒数
maxDelaySeconds600delaySeconds 上限
superviseFallbacktrue无托管时是否派 supervisor 兜底
trustParentJobfalse见下方"launchd 与父进程"
healthUrl空留空则用 --port 推导 http://127.0.0.1:/
healthTimeoutMs60000supervisor 等端口恢复的上限
healthIntervalMs500健康检查轮询间隔
exitTimeoutMs45000supervisor 等旧进程退出的上限;超时不强制终止任何进程,直接如实报失败
bootHistoryLimit5状态里保留的最近重启次数

端口是从 DSH 自己的 cmdlineArgs 里读 --port 得来的,不靠猜;读不到才退回 lsof。两者都拿不到且 healthUrl 为空时,拉起照常执行(这条路径上能阻止拉起的只有两件事:旧进程没退出、宿主没提交退出),只是「服务是否恢复」只能由新进程写的 boot 记录来确认,没有端口层面的证据。

launchd 与父进程

判断"launchd 会不会把我拉回来"时,只认两种情况之一:本进程就是某个 KeepAlive 任务的主进程(job.pid === pid),或者该任务的主进程是本进程的直接父进程(job.pid === ppid)。

只有第一种能证明 launchd 会重启我。第二种依赖一个额外假设——父进程会随本进程一起退出——而这个假设无法在本地证明:如果父进程是个不随子进程退出的包装进程,本进程退出后就没有任何人拉起它。

所以第二种默认不走 launchd,改用 supervisor 兜底(慢一点,但不会把自己关在门外)。只有你明确知道自己的父进程会随子进程退出时,才把 trustParentJob 打开;打开后 warning 仍会保留,因为那条链路上 KeepAlive 重启的毕竟是 job 主进程,比自持多两个不确定环节。

KeepAlive 的读法按这个原则收紧:只在 launchctl print 输出的 properties 里读,且支持它的两种真实渲染——本机(macOS 26)是单行旗标表 properties = keepalive | runatload | ...,列表里有 keepalive 才算无条件开启;旧式多行 properties = { keepalive = 1 } 块也认。不对整段输出做关键字匹配——否则 job label、环境变量值或 endpoint 名里出现 "keepalive" 就会被误判成有人托管。条件式策略(semaphores = { successful exit => 0 },或块里的字典值)一律不认;没有 properties 行时按"无法确认"处理,同样倒向 supervisor。