dsh-smart-restart

devinstall failsnpmMIT

Wakes the main agent after any DSH restart so interrupted work resumes automatically — adds a restart tool and an optional canary that validates the boot and aborts with an alert before a broken restart.

下载量 / Downloads
909
测试时间 / Tested
2026-11-07
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add dsh-smart-restart

Sandbox test results

StageResult
1 install✗
2 list—
3 mount—
4 boot—
First error
dsh: initialized profile web at /home/node/.dsh/profiles/web

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

dsh-smart-restart

[English](README.md) | 中文

一个 DeepSeek Harness (DSH) 宿主插件,让主代理在服务重启后保持感知——无需用户主动提示。每次启动时,它都会检测到新进程已经接管,并以一条简短的“Smart-restart”通知唤醒目标代理(启动时间、上一次启动时间、停机时长)。v0.2.0 新增了 smart_restart 工具,用于重启 DSH 本身,并将通知返回到发起请求的那一个会话;v0.3.0 新增了在代理会话处于活动状态期间服务被停止时的自动检测功能,因此即使是代理运行过的普通 systemctl restart,也会在启动时通知该会话;v0.4.0 新增了先校验再启动的能力——通过可选的 canary 预重启门控,在临时实例启动失败时中止重启;新版本 v0.5.0 支持自动检测 systemd 服务单元(读取 /proc/self/cgroup),在 systemd 托管的安装中,工具与 canary 无需任何配置即可工作。

![npm](https://www.npmjs.com/package/dsh-smart-restart)

![license](LICENSE)

![stars](https://github.com/edusrez/dsh-smart-restart)

![last commit](https://github.com/edusrez/dsh-smart-restart)

目录

  • [概述](#概述)
  • [工作原理](#工作原理)
  • [smart_restart 工具](#smart_restart-工具)
  • [环境要求](#环境要求)
  • [安装](#安装)
  • [配置](#配置)
  • [行为与生命周期](#行为与生命周期)
  • [限制](#限制)
  • [开发](#开发)
  • [许可证](#许可证)

概述

长期运行的 DSH 实例会因多种原因重启:代理安装或重新配置插件并触发重启、宿主机重启,或者服务在 systemd 下被重启。经过任何此类重启之后,代理会再次启动并运行,但它对发生的情况一无所知——之前的会话已经消失了。如今,让代理继续工作的唯一办法就是由用户告知它,通常类似 “you restarted”。

dsh-smart-restart 填补了这一空白。它自行检测重启,并在启动时以一条简短、自足的通知唤醒主代理,说明发生了什么,从而由代理决定是恢复被打断的工作、记录停机,还是仅仅确认——无需用户提示。

v0.3.0 新增,该插件还覆盖活动代理的非计划重启。它会跟踪最近一次活动的会话,并在关闭(SIGTERM/SIGINT)时持久化写入 shutdown-notice.json;在启动时则把通知固定回该会话(当它在 shutdownGraceMs 内处于活动状态时)。因此,代理运行过的普通 systemctl restart——或者代理正在处理任务中途发生的重启——都会自动收到通知,无需用户提示。v0.2.0 让主代理能够主动触发重启:smart_restart 工具会记录调用它的会话,并通过 systemd 重启 DSH,把通知返回到该确切会话。

  • 零提示 — 用户永远不必告诉代理“you restarted”。
  • 自我重启 — 主代理可以自行重启 DSH,并在之后自动恢复其任务。
  • 自动唤醒 — 空闲的主代理会被唤醒,并自行收到通知。
  • 定向投递 — 重启后的通知会返回给发起请求的会话;否则由 target 配置决定它落到哪里。
  • 精确上下文 — 通知携带启动时间、上一次启动时间、停机时长以及可选的原因。
  • 自足 — 单个宿主包;无需运行任何东西,也没有外部服务。

工作原理

该插件在每次启动时:

1. 读取上一次的标记 — 一个持久化的 marker.json({lastBootAt, pid, dshVersion?}),存放在 <DSH_HOME>/<stateDir>/ 下。

2. 检测重启 — 若上一次的标记带有与当前 process.pid 不同的 pid,则意味着新进程已经启动,也就是说服务重启了;停机时长为 now − 上一次 lastBootAt,并限制为 ≥ 0。

3. 立即写入新标记,以便下一次启动能与本次进行比较。

4. 检查是否有待处理的通知 — 如果 smart_restart 工具在之前那次重启前留下了 pending-notice.json,本次启动就会把投递固定到该确切会话(最高优先级;该文件读取一次即被消费)。

5. 检查是否有关机通知 — 如果没有待处理通知,插件会读取 shutdown-notice.json(由前一个进程在 SIGTERM/SIGINT 时写入,记录最近一次活动的会话)。若该会话在 shutdownGraceMs 内处于活动状态,本次启动会把它固定为投递目标(第二优先级);否则跳过固定,投递回退到 target。该文件读取一次即被消费。

6. 投递通知 — 每次启动只投递一次,通过来源无关的 agent/session-start 钩子(被固定的会话无论发布来源如何都会被匹配,因此连以 source: 'resume' 恢复的会话也能被捕获到),并由有界轮询(750ms 周期,约 15s 上限)支撑,用于捕捉延迟懒恢复的被固定会话。

根据重启发生的方式,共有三条投递路径:

(a) 代理发起的重启(smart_restart 工具)

主代理调用 smart_restart(reason?)。该工具:

  • 校验配置好的 restartUnit 令牌,
  • 同步持久化待处理通知(调用会话 + 可选原因)到状态目录下的 pending-notice.json,在任何 spawn 之前完成,以便在即将到来的服务终止中存活下来,
  • 派生一个分离的 setsid bash 进程(约 1s 延迟让工具响应的写入得以完成),该进程运行 systemctl restart <unit>,并能在本进程被 systemd 终止后存活,
  • 返回 {ok: true, restarting: true, ...}。

在下次启动时,上面的第 4 步会读取待处理通知,把它固定到调用它的会话(最高优先级),通知便在那里返回——无论来源如何——因此发起请求的代理会恢复其被打断的任务。

(b) 智能关机自动检测(代理活动时发生普通重启)

如果没有待处理通知,插件会查找 shutdown-notice.json。该文件由前一个进程在 SIGTERM/SIGINT 时同步写入,记录最近一次活动的会话(在 agent/session-start 和 agent/pre-step 上跟踪)及其时间戳。在启动时,插件仅当该会话在关机的 shutdownGraceMs 内处于活动状态时,才把通知固定到该会话(最近有活动 ⇒ 用户是在代理处理任务中途重启的,因此自动通知)。如果该会话在关机前早已空闲(用户可能是在空闲时重启的),则跳过固定,投递回退到 target。

这正是让代理运行过的普通 systemctl restart——或者代理活动时发生的重启——在启动时自动通知该会话的原因,无需用户提示,也无需调用过 smart_restart。

(c) 外部重启(systemd、宿主机重启、开发工具)——没有活动会话

没有待处理通知,也没有可用的关机通知(要么没有写入,要么最近的活动早于 shutdownGraceMs)。启动回退到 target 配置(primary | all | <session-id>),以决定哪个/哪些代理收到通知。source === 'startup' 的这个门控只适用于这条非固定路径。

重启与 HMR 的语义

检测是刻意精确的:

情况 · 是否检测为重启?

新的 OS 进程,且存在上一次标记 · 是 — 服务(重新)启动。

同一个 OS 进程(进程内 HMR / 热重载) · 否 — 被忽略。

首次启动(没有标记) · 否 — 没有可比较的对象。

标记存在但 lastBootAt 过期/损坏 · 是 — 停机时长报告为 0。

只有真正意义上的新进程才算一次重启。进程内热重载保持同一个 pid,因此不会被当作服务重启。投递每次启动只发生一次:一个 deliveredIds 集合加上一个 primary 守卫(针对 primary 目标)可防止启动事件与回退轮询重复发送。

通知

默认通知(英文)如下:

Smart-restart: the DSH service restarted at <iso>. Previous boot: <iso> (downtime ~2m 9s). If a task was in progress, resume it; otherwise reply with a one-line acknowledgment.

当 smart_restart 记录了 reason 时,它会被追加(… reason: <reason>.)到恢复指令之前。当没有已知的上一次启动时间时,会省略上一次启动/停机时长的段落,而整段文本都可通过 notice 配置完全自定义(见下文)。

smart_restart 工具

当 toolEnabled 为 true(默认值)时,通过 apply 中的 ctx.tools.register 注册(因此代理会话可用)。它让主代理能够通过 systemd 自行重启 DSH。

参数

参数 · 类型 · 必填 · 描述

reason · string · 否 · 可选的人类可读说明,例如 "installed dshmarket in stable+dev"。会包含在重启后的通知中。

行为

  • 校验配置好的 restartUnit — 单个 systemd 单元令牌(/^[A-Za-z0-9_.@-]+$/,不含空格/斜杠),以防对分离命令进行 shell 注入。
  • 当 restartUnit 未配置且从 /proc/self/cgroup 的自动检测也找不到单元时快速失败(ok: false,错误 restartUnit not configured),而不是猜测单元名——空的 restartUnit 会先被自动检测,只有检测失败才会产生该错误。
  • 同步持久化 pending-notice.json(在任何 spawn 之前),以便在服务终止时存活,并定向到正在重启的会话。
  • 通过一个分离的 setsid bash 进程(sleep 1 && systemctl restart <unit>)重启,该进程比本进程存活更久,然后对其 unref。
  • 成功时返回 {ok: true, restarting: true, sessionId, reason},失败时返回 {ok: false, restarting: false, error}。

预期的代理流程

install/change a plugin
  → call smart_restart(reason)   # e.g. "installed dshmarket in stable+dev"
  → DSH restarts (detached, ~1s)
  → after boot, the notice returns to THIS session (pinned)
  → the task continues automatically — no user prompt needed

安全说明

  • 单元令牌会针对严格的正则进行校验,以阻止通过 restartUnit 对分离 shell 命令进行 shell 注入。
  • 该工具面向 systemd 托管的 DSH 安装(setsid / systemctl);它不适用于没有 systemd 单元的裸进程。

环境要求

  • DSH 0.1.0-rc.7+ / 0.1.1-rc.x — 一个长期运行、带有实时主代理会话的实例(web / GUI

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::8,最后更新 2026-08-22

Links

GitHub · Homepage · npm

Same category