dsh-autorestart 0.8.3 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -0
- package/README.md +78 -18
- package/client.js +581 -9
- package/docs/README.zh.md +23 -8
- package/index.js +727 -47
- package/lib/backup.js +219 -4
- package/lib/checkpoint.js +93 -3
- package/lib/restart-phase.js +5 -0
- package/locale/en.json +21 -1
- package/locale/zh.json +21 -1
- package/package.json +2 -2
package/docs/README.zh.md
CHANGED
|
@@ -133,7 +133,7 @@ session resume on boot, durable-goal re-arm, and an agent-callable idle-aware gr
|
|
|
133
133
|
| --- | --- |
|
|
134
134
|
| Agent 工具(6 个) | `continuum_restart`、`continuum_status`、`continuum_cancel_restart`、`continuum_park_goal`、`continuum_recover_now`、`continuum_handoff` |
|
|
135
135
|
| HTTP 路由(7 条) | `<healthPath>`(默认 `/__dsh_autorestart`)下的 `GET /health`(另有 `?state=1`、`?gate=1`、`?probeIndex=1`)、`POST /park`、`POST /recover`、`POST /handoff`、`GET /sleep`、`POST /sleep`(收工关机——桌面端和 web 端走的是同一条路由)、`GET /announcements`、`POST /announcements`(一次性新功能公告);只接受本机回环或已认证的浏览器 |
|
|
136
|
-
| 前端槽位(6 个) | `conversation.input.left`(待重启小胶囊,id `autorestart-restart-pill`)、`sidebar.session.row.leading`(侧栏状态圆点,id `autorestart-restart-dot`)、`conversation.input.dock`(一次性安装提问,id `autorestart-backup-choice`;一次性新功能公告,id `autorestart-feature-announcement`)、`sidebar.footer.action`(收工关机的月亮按钮,id `autorestart-sleep-button`)、`shell.overlay
|
|
136
|
+
| 前端槽位(6 个) | `conversation.input.left`(待重启小胶囊,id `autorestart-restart-pill`)、`sidebar.session.row.leading`(侧栏状态圆点,id `autorestart-restart-dot`)、`conversation.input.dock`(一次性安装提问,id `autorestart-backup-choice`;一次性新功能公告,id `autorestart-feature-announcement`)、`sidebar.footer.action`(收工关机的月亮按钮,id `autorestart-sleep-button`)、`shell.overlay`(倒数浮动卡片,以及**主界面居中的重启阶段浮层**:`autorestart-sleep-overlay`、`autorestart-restart-overlay`)、`settings.section`(设置页里的「自动重启与关机」分区,id `dsh-autorestart`;保存回执也渲染在这个面板**内部**,不占窗口级浮层) |
|
|
137
137
|
| 系统提示词 | 一段「重启政策」说明,告诉 agent 怎么请求重启、插件会做什么 |
|
|
138
138
|
| 宿主事件 | `agent/status`(跟踪哪些会话在忙)、`tools/pre-execute`(拦下"手动杀/重启 DSH"的 shell 命令)、启动时的恢复流程 |
|
|
139
139
|
| profile 行 | 一条 bundle 行:`dsh-autorestart` |
|
|
@@ -148,7 +148,10 @@ session resume on boot, durable-goal re-arm, and an agent-callable idle-aware gr
|
|
|
148
148
|
- 拷回本身也有**时间上限**(`rollbackCopyTimeoutMs`,默认 120 秒/步):拷不完就放弃,并把原因写进报告。
|
|
149
149
|
- **托管模式(`restartMode: command`)也有同一张安全网**:重启命令通常会把插件自己所在的进程一起杀掉,所以看护脚本在命令**之前**就启动了,由它来确认新实例有没有起来。命令起不来或以非零码退出时,插件**如实报错**(带退出码和输出)并把快照拷回去,绝不静默当成功。
|
|
150
150
|
- 下次启动时 `continuum_status` 会报 `lastRollback`(时间、等了多久、是否回滚、**失败原因**、快照路径、崩溃日志名与尾部摘要)。
|
|
151
|
-
-
|
|
151
|
+
- **回滚目标是「最新的安全份」,不是「最新的一份」**(用户决定,2026-10-30):每份备份旁边有一张 `meta.json` 记着身份——`known-good`(安全份,已经有一次启动成功验证过)、`snapshot`(本次快照,重启前刚拍、还没验证)、`unknown`(身份层之前的旧备份)。**这次重启前拍的那份永远不是回滚目标**,因为它可能正是坏掉的那一份(「改坏了插件再点重启」就是这个场景)。第一次安装时会种子一份安全份;每次启动成功(健康检查通过)后,把那次重启前的快照提升为安全份。
|
|
152
|
+
- **没有安全份就一份都不还原**:找不到 latest known-good 时,回滚什么都不做,报告里写 `no-known-good: <原因>`,profile 保持失败重启后的原样,看门狗也**不挂**(没有可还原的目标,挂上去只会再把坏配置写一遍)。
|
|
153
|
+
- **可以手动回退到任意一份备份**(含更早、未验证的那份,用户决定 2026-10-30):设置页每行都有「回退到这一份」,点了先弹**二次确认**(写清还原哪一份、当前状态会被覆盖、还原后会自动重启),确认后才动,取消则什么都不发。服务端 `POST /__dsh_autorestart/rollback-to` 只收**备份目录名**(必须是本机列表里的那一份,路径 / 路径穿越直接拒绝),顺序是先存一份当前快照(`reason: before-manual-rollback`,所以这次回退本身还能再退回来)→ 再还原选中的那份 → 写 `last-manual-rollback.json` 回执 → 走既有重启流程请求重启(插件自己绝不 kill 进程);当前状态存不下来、或看门狗正持有回滚锁时直接拒绝(409),不会出现还原了一半。
|
|
154
|
+
- 开关:`backupOnRestart`(默认 `true`)、`backupIncludePlugins`(默认 `true`,关掉就只备配置文件)、`maxBackups`(默认 `3`:当前一份 + 之前两份;**最新的 known-good 永远不删**)、`rollbackTimeoutMs`(默认 `90000`)、`restartCommandTimeoutMs`(默认 `30000`)、`rollbackCopyTimeoutMs`(默认 `120000`)。
|
|
152
155
|
|
|
153
156
|
### 这台电脑不让建计划任务时(自动回滚就没了)
|
|
154
157
|
|
|
@@ -330,7 +333,7 @@ agent/status(running) ──► 写 checkpoint(<DSH_HOME>\storages\dsh-autores
|
|
|
330
333
|
|
|
331
334
|
## 安装
|
|
332
335
|
|
|
333
|
-
当前版本:**0.8.
|
|
336
|
+
当前版本:**0.8.5**。
|
|
334
337
|
|
|
335
338
|
```powershell
|
|
336
339
|
# 在 dsh 里(或对 Agent 说):把工作区里的这个包安装为 profile bundle
|
|
@@ -364,9 +367,20 @@ dsh plugin --profile desktop add C:\path\to\dsh-autorestart
|
|
|
364
367
|
|
|
365
368
|
## 配置
|
|
366
369
|
|
|
367
|
-
|
|
370
|
+
设置页里关于「备份」「回执」和「启动方式」的几块,先说清楚它们看的是什么:
|
|
368
371
|
|
|
369
|
-
- **现在备份了什么**(在两个备份勾选的下面):宿主真的去读 `<DSH_HOME>/storages/dsh-autorestart/backups
|
|
372
|
+
- **现在备份了什么**(在两个备份勾选的下面):宿主真的去读 `<DSH_HOME>/storages/dsh-autorestart/backups/`,所以份数、每份的**本地时间**、大小、有没有含已装插件、以及存放路径都是真的。只有目录元信息被读,备份里的内容**不遍历**(一份就可能 150 MB)。没有备份时写的是「还没有备份;每次重启前会自动生成一份」。每份备份先写**身份**(它到底能不能用来回滚),再写两行带标签的数值:
|
|
373
|
+
|
|
374
|
+
```
|
|
375
|
+
身份 安全份 · 版本 0.8.5
|
|
376
|
+
备份时间 2026-10-29 22:08
|
|
377
|
+
备份大小 156 MB(含已装插件)
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
身份只有三种:**安全份**(已经有一次启动成功验证过,自动回滚只认它)、**本次快照**(每次重启前刚拍的,还没验证)、**旧备份(未验证)**(身份层之前的拷贝,或者没有身份文件)。列表上方还有一段说明,讲清两种身份、看门狗只回滚安全份、第一次安装会生成安全份、最多保留 3 份、旧备份不会被自动回滚、手动回退会先二次确认再重启。身份和版本由宿主给(`backups.items[].kind` / `backups.items[].version`)——浏览器读不到 `meta.json`。
|
|
381
|
+
|
|
382
|
+
时间就是拍快照那台机器的本地时间,**精确到分、不带时区偏移**(`+08:00` 只会添乱——看的人本来就看自己的钟)。大小自动选单位(`92 KB` / `156 MB`),只在有意义时保留一位小数(`117.7 MB`,永远不写 `156.0 MB`);「(含已装插件)」紧跟在大小后面,因为它正是这份备份为什么这么大。两份备份就是两组,组与组之间留空隙。
|
|
383
|
+
- **设置改动有回执**:每个开关/下拉都是改了就写,所以面板必须说清写没写进去——宿主回 `ok: true` 之后,**设置面板内部顶部**(面板自己的 `sticky` 条,往下滚动也一直可见)出现绿色**「已生效」** + 小字时间(`已生效 21:40:12`),3 秒后淡出;被拒绝时是红色**「没保存成功」** + 宿主给的原因,不自动消失,直到下一次改动成功或你自己点 × 关掉。**宿主没回话之前一律不显示**:首次渲染、轮询刷新、点控件都不会亮。
|
|
370
384
|
- **启动方式**(Web 托管端才有):默认只给**一行大白话**(例如「我记下的启动方式:由你的脚本拉起(重启交给它,我不插手)」)加两个小动作(重新检测 / 撤销);命令原文收在**「技术细节」**折叠里,默认收起,展开才出现。**桌面客户端这一整块不渲染** —— 它自己拉起自己,也不该写 `restartCommand`。宿主说不清是哪一端时,宁可整块不显示。
|
|
371
385
|
|
|
372
386
|
所有键都有默认值,写在 `cordis.patch.yml` 的 insert 行里;要覆盖就在 profile 的
|
|
@@ -399,7 +413,7 @@ dsh plugin --profile desktop add C:\path\to\dsh-autorestart
|
|
|
399
413
|
| `continuationText` | `''` | 覆盖默认续接提示文本 |
|
|
400
414
|
| `backupOnRestart` | `true` | 每次重启前给 profile 拍快照;重启后起不来时能自动回退 |
|
|
401
415
|
| `backupIncludePlugins` | `true` | 快照里是否带上已安装插件目录(本机约 117 MB、多约 3 秒);关掉就只备配置文件 |
|
|
402
|
-
| `maxBackups` | `
|
|
416
|
+
| `maxBackups` | `3` | 保留几份快照(当前一份 + 之前两份);写新的时自动删旧的——但**最新的 known-good 一份永远不删** |
|
|
403
417
|
| `rollbackTimeoutMs` | `90000` | 看护脚本等新宿主多久(毫秒),超时就回退快照(**不会再拉起第二个宿主**) |
|
|
404
418
|
| `restartCommandTimeoutMs` | `30000` | 重启命令最多让插件等多久(毫秒)。前台跑着宿主的命令永远不返回——那会报「还在运行」,不算失败 |
|
|
405
419
|
| `rollbackCopyTimeoutMs` | `120000` | 拷回快照的**每一步**最多花多久(毫秒):拷不完就放弃,并把原因写进回退报告 |
|
|
@@ -529,8 +543,7 @@ restart gate: action=wait reason=agents-busy-within-soft-window busyCount=1 quie
|
|
|
529
543
|
|
|
530
544
|
### 小胶囊:点它看详情,也从这儿自己撤掉
|
|
531
545
|
|
|
532
|
-
输入框那排的小胶囊只有 22px
|
|
533
|
-
不放名字,也不放任何"双击可以取消"之类的提示(没地方放)。**单击**它(或聚焦后按 Enter / 空格)会在上方
|
|
546
|
+
输入框那排的小胶囊只有 22px 高、一行宽,所以它**只放一句短话**(`待重启 · 空闲后自动重启` / `待重启 · 等待 2 个会话`,≤12 字)——不放名字,也不放「双击可以取消」之类的提示(没地方放)。细节都下沉一层:长句只做 tooltip,**阶段**(备份中 / 重启中 / 已回来)显示在**主界面居中的浮层卡片**上,数量和「怎么撤」在点开的小面板里。**单击**它(或聚焦后按 Enter / 空格)会在上方
|
|
534
547
|
弹出一个小面板:
|
|
535
548
|
|
|
536
549
|
- 这次重启还在等几个会话;
|
|
@@ -545,6 +558,8 @@ restart gate: action=wait reason=agents-busy-within-soft-window busyCount=1 quie
|
|
|
545
558
|
`{ "sessionId": "…", "scope": "mine" }`):别的会话照样重启。面板里**没有**"全撤"——那种操作只留给
|
|
546
559
|
工具显式调用(`continuum_cancel_restart` 带 `scope: "all"`)。
|
|
547
560
|
|
|
561
|
+
**浮层不会悬停,也不说假话**:重启被新会话打断时,浮层立刻从「正在重启…」换成「**有新会话在跑,重启已暂缓**」,第二行小字「等它结束会自动继续 · 已等 N 个会话」——这时候说「正在重启」就是假话。宿主每 350ms 复查一次空闲门,那句假话最多只存在一个心跳;备份一结束、进入「正在重启」阶段之前也会当场复查一次,被挡就在同一次 tick 退回等待。阶段超过 15 秒无更新视为过期,不再显示,胶囊仍显示等待数。
|
|
562
|
+
|
|
548
563
|
## 收工关机(Graceful shutdown)
|
|
549
564
|
|
|
550
565
|
**它干什么。** 左侧栏最底部一个月亮按钮:点一下 → 等**所有**会话都收工 → 屏幕上倒数(一个巨大的数字 + 一只蓝色小鲸鱼,每秒换一句中文)→ **关掉整台电脑**。倒数期间随时可以取消:卡片上有按钮,月亮按钮本身在关机期间也变成了"再点一下 = 取消"。倒数期间要是有会话又开始干活,倒计时会退回"等待",**绝不关机**。
|