Shutdown Guard · 任务完成后关机

为 DeepSeek Harness 中的侧边栏添加「所有任务完成后自动关机」卡片,拥有更好且多样的视觉效果、判定逻辑与个性化定制。位于「技能中心」下方、会话列表上方,随任务状态实时变化。
▶ 交互演示页 —— 不用装插件,先看它长什么样、它怎么判断。左右两页:了解(判定、外观、状态)与 试一试(随机一个场景,亲手点武装、取消、解除,一路看到关机或阻断)。数据全部本地随机,不联网。
为什么需要它
跑长任务的人常有这个场景:晚上让 agent 把一批活干完,想让它干完就关机,人不在跟前。
但「任务结束」不等于「可以关机」——后台任务还在跑、会话报错了、agent 在等你回答问题、你在半路手动终止了……这些情况下关机全是事故。这个插件把这些情况逐个挡下来,只有真的可以关的时候才关。
判定:什么时候才关
处于阻断态(见下文)时直接不下发;其余五道闸门同时满足才下发 shutdown /s:
- 已武装 —— 你手动点的
- 没有倒计时在跑 —— 避免重复下发
- 所有 root 会话都空闲 —— 没有任何 agent 还在干活
- 没有运行中 / 停止中的后台任务 ——
blockOnJobs,默认开 - 本批次没有会话报错 ——
onlyOnSuccess,默认开
缺任何一条都不关,并把原因写在卡片和设置页里。
三种外观
| A · 警戒带 | B · 雷达 | C · 终端 |
|---|---|---|
![]() |
![]() |
![]() |
| 大字状态 + 底部滚动的红黄斜纹 | 同心圆 + 扫描光束,会话与后台任务以圆点呈现 | 命令行摘要 + 六段判定条件指示灯 |
雷达里的圆点按数量增删、不重排:数量变化时,你正在看的那几个点不会跳位置。

设置里切换,立即生效,无需重启。
六种运行状态
| 未开启 | 待命 | 等待后台任务 |
|---|---|---|
![]() |
![]() |
![]() |
| 倒计时 | 已下发 | 阻断 |
|---|---|---|
![]() |
![]() |
![]() |
未开启 → 待命 → 等待后台任务 → 倒计时 → 已下发;任意阶段遇到阻断性错误会进入 阻断。倒计时期间随时可取消,取消后仍保持武装——下一批任务干完照样会关。
想在这六种状态之间来回看?演示页「了解」第 04 节右上角有 A B C 三枚胶囊,切换的是当前预览用哪种外观。
阻断态
| halted · 需人工处理 | waiting · 自动重试 |
|---|---|
![]() |
![]() |
遇到没法当普通失败处理的错误,插件不解除武装,卡片转色、把原因写出来:
halted(灰蓝)—— 额度不足、凭证失效、上下文超限、能力不支持、磁盘写满。只有人能处理,点「解除并重试」。waiting(灰绿,圆点呼吸)—— 限流、5xx、网络中断、空响应、超时、图片卸载。按策略自动重试,到点注入「继续原计划」指令。

重试节奏按故障类型分别配置,见 重试策略。
AFK 自动接管
人不在跟前时,插件替你顶三件事:
- 自动回答提问(默认开):agent 问你问题时,回复「用户处于 AFK,先完成已交代的任务,汇总报告并落盘,不碰未交代的分支」。返回
selected: []+ 自定义文本,不会替你选中任何选项;关掉后提问照常抛给你。 - 错误恢复:会话报错时先要求 agent 排查并继续原计划;同一会话再次失败改为「停止重试、写报告收尾」。
- 中断保护:你在半路手动终止任务,不会触发关机。
装在哪里
| 武装时:技能中心下方、会话列表上方 | 倒计时:同一位置,整条转红 |
|---|---|
![]() |
![]() |
卡片目前固定在侧边栏的这个位置。后续计划把它做成可以独立出现的形态(设置里给个开关),届时这里会补充说明。
其他
纵向折叠:收起只留标题和状态,点标题展开。
主题自适应:卡片自带
--dsp-*调色板,按宿主表面亮度自动取深浅色;也可强制锁定深色 / 浅色 / Claude Style 配色。事件日志:设置页里能看最近的事件与「上次为什么没关机」,完整流水在
data/events.log。
设置页
| 深色 | 浅色 |
|---|---|
![]() |
![]() |
分三组:外观 / 何时关机 / 状态。所有开关立即生效。
- 默认配置锁定 60 秒不可改;另有 8 个自定义档位可自由调。
- 「会话都停下来」是底线条件,始终开启,不可关。
- 「后台任务跑完」挡后台任务,「有会话报错就跳过这一轮」挡出错批次。
- 「AFK 自动回答」控制武装期间是否替你回复提问;说明里写明「回复不会替你选中任何选项,关闭后提问照常弹给你」。
浅色与第三方主题
| 浅色卡片 | Claude Style |
|---|---|
![]() |
![]() |
卡片不套用宿主配色,自带调色板;设置页则跟宿主主题走。第三方的 Claude Style 也有对应配色。
安装
已发布到 npm,推荐:
dsh plugin --profile web add dsh-shutdown-guard
或者直接从 GitHub 装:
dsh plugin --profile web add github:ltayshark0637/dsh-Shutdown-Guard
装完重启 DSH。
⚠️ 客户端 bundle 只在 DSH 启动时编入模块图:改
lib/client.js后必须重启,刷新页面无效。服务端同理。
网络受限时:GitHub 那条本质是 pnpm add github:...,需要 clone。若 clone 不通,优先用 npm 那条(走 registry);都不通再用本地路径安装——DSH 设置 → 插件 → 添加,填本目录的绝对路径 → 安装 → 重启。
手工兜底:在 profiles\web 下建 node_modules\dsh-shutdown-guard 软链指向本目录,然后:
profiles\web\package.json的dependencies与pnpm.overrides加link:<本目录绝对路径>dsh.profile.bundles追加dsh-shutdown-guard
权限与影响
装上之后,这个插件会做以下几件事:
| 影响面 | 具体行为 |
|---|---|
| 执行命令 | 经 subprocess 调 Windows 的 shutdown.exe:/s /t <秒> 安排关机、/a 取消。只在武装且五道闸门全满足时才调 |
| 读写文件 | 只在插件目录下的 data/:config.json(配置)与 events.log(事件日志) |
| 监听事件 | agent/status、agent/error、session/event、user-questions/request |
| HTTP 路由 | 本机 DSH Web 服务下 /api/dsh-shutdown-guard/ 的 GET /state、GET /events、POST /arm、POST /disarm、POST /cancel、POST /config;POST 校验 Origin 必须为 127.0.0.1 或 localhost |
| 网络 | 不发起任何外部请求,不收集数据 |
| 平台 | 仅 Windows。非 win32 时插件静默不加载 |
AFK 自动接管开启时,插件会在武装期间替你回答 agent 的提问、并向报错会话注入恢复指令;这个开关在设置里可以随时关掉。
配置
写在 cordis.patch.yml(插件包内的 patch),或经 POST /config 在运行时修改。
| 键 | 范围 | 默认 | 说明 |
|---|---|---|---|
countdownSec |
10–600 | 60 | 关机前倒计时秒数(默认档固定 60,不可改) |
marginSec |
0–60 | 5 | 传给 shutdown /t 的额外余量 |
onlyOnSuccess |
bool | true |
本批次有会话报错时跳过关机 |
blockOnJobs |
bool | true |
有运行中的后台任务时跳过关机 |
afkAutoAnswer |
bool | true |
武装期间替用户回答提问、做错误恢复 |
重试策略
每个错误码分配一个策略名,策略本身可配置:
| 策略 | 默认节奏 | 分配给 |
|---|---|---|
rate-limit |
backoff 30 → 60 → 120 → 240 → 300 封顶 | RATE_LIMIT |
transient |
固定 20 秒 | SERVER / TRANSPORT / TIMEOUT |
empty |
固定 30 秒 | EMPTY_RESPONSE |
offload |
固定 5 秒 | IMAGE_OFFLOAD_REQUIRED |
限流用退避而不是固定间隔,是因为对限流服务高频重试会延长限流期,而不只是浪费请求。5xx 和网络故障恢复时间可预测,固定间隔反而更快。图片卸载是本地磁盘操作,几乎立刻可重试,所以给 5 秒。
覆盖单个错误码:
retryAssign:
RATE_LIMIT: slow-limit
retryPolicies:
slow-limit: { mode: backoff, base: 60, max: 900 }
未知 code 回落 transient;形状写错的策略会被丢弃并保留默认值。当前生效的分配可从 /state 的 retryAssign、retryPolicies 读到。
UI 偏好存在浏览器 localStorage:dsh-shutdown-guard.variant / .theme / .folded。
HTTP 接口
前缀 /api/dsh-shutdown-guard,供卡片自己的同源轮询使用:
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /state?since=<ms> |
完整状态 + 增量事件 |
| POST | /arm /disarm /cancel |
武装 / 解除 / 取消本次倒计时 |
| POST | /config |
改配置:customEnabled、activeProfileId、profileId+patch、afkAutoAnswer |
| GET | /events?since=&limit= |
事件流水 |
非本机 Origin 的 POST 返回 403;非 POST 返回 405。
日志
<插件目录>\data\events.log—— 人类可读的事件流水(config/afk/skip分类),设置页「事件日志」即读它<DSH_HOME>\dsh-shutdown-guard.log—— 进程级追加日志
开发
node test/host.test.mjs # 服务端:26 项断言,mock ctx,不真的关机
node test/client.test.cjs # 客户端 bundle smoke
node scripts/gen-gallery.cjs # 从 lib/client.js 真实 CSS 生成截图页
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/screenshot.ps1 # headless Edge 渲染 PNG(透明背景 + 自动裁边)
node scripts/gen-gif.cjs # 生成 README 里的三张动图
node scripts/gen-banner.cjs # 生成 1280x640 的社交预览图
node scripts/gen-demo.cjs # 生成 docs/demo.html(交互演示页)
截图全部由 lib/client.js 里的真实 CSS 生成,不会与产品脱节。动图同理:把 CSS 动画用 animation-delay 冻结在若干时间点逐帧截图,再用内置的 GIF89a 编码器合成——本机不需要 ffmpeg 或 ImageMagick。
演示页面的「了解」部分同样是实时渲染:六种状态用与产品同一套 card() 标记现场生成,不是截图。
常见问题
Q:为什么改了设置没反应? A:服务端和客户端都得重启 DSH 才加载新代码。本机 HMR 对本地链接插件不生效。
Q:武装后为什么不关机? A:看设置页「上次为什么没关机」,那里写着具体原因(后台任务、报错、未武装等)。
Q:倒计时期间能反悔吗?
A:能。卡片上的「取消关机」或直接 shutdown /a 都行,取消后仍保持武装,下一个批次继续生效。
Q:会误关机吗? A:默认配置下,插件要看到「所有会话空闲 + 没有后台任务 + 没有报错 + 你手动武装」四条同时成立才动手,其中任何一条被打破都会取消或跳过。手动终止任务也已被识别并排除。
Q:非 Windows 能用吗? A:暂时不能,等待后续开发。
约束
- 仅 Windows:非
win32平台早退,不挂载。 - 零运行时依赖:服务端只用
node:fs/node:path/node:crypto,浏览器只require('react')。 - 不修改
app.asar与 DSH 源码。















No comments yet. Be the first to write one.