dsh-autorestart 0.8.2 → 0.8.4
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 +50 -1
- package/README.md +39 -14
- package/client.js +952 -56
- package/docs/README.zh.md +17 -10
- package/index.js +26 -7
- package/lib/checkpoint.js +23 -4
- package/lib/restart-phase.js +52 -11
- package/locale/en.json +26 -5
- package/locale/zh.json +26 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,54 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.4 — 2026-10-29
|
|
4
|
+
|
|
5
|
+
**只改文档与版本号,行为没有变化。**
|
|
6
|
+
|
|
7
|
+
### 文档
|
|
8
|
+
|
|
9
|
+
- **README(英)/ docs/README.zh.md 补齐 0.8.3 的真实界面行为**(npm 页面上原来还是 0.8.2 时代的旧描述):
|
|
10
|
+
- 重启阶段显示在**主界面居中浮层**(centered overlay card),**只排队等空闲时不出现**,只在真的备份 / 重启时出现,回来显示 1.5 秒后消失;
|
|
11
|
+
- 胶囊只有**一句短话**(≤12 字),长句降级为 tooltip,详情在点开的面板里;
|
|
12
|
+
- 备份进度是**真进度**(MB + 百分比),单位自适应(`92 KB` / `156 MB`),**备份快就一闪而过、不人为拉长**;
|
|
13
|
+
- 设置改动有回执:保存成功后**设置在面板内部顶部**(面板自己的 sticky 条)显示绿色「已生效 / Saved」+ 时间,3 秒淡出;失败红色「没保存成功 / Not saved」并保留宿主给的原因;
|
|
14
|
+
- 备份列表改成两行:`备份时间 / Backup time 2026-10-29 22:08`、`备份大小 / Backup size 156 MB(含已装插件 / plugins included)`,**不显示时区偏移**。
|
|
15
|
+
- 槽位表补上 `shell.overlay` 里的重启阶段浮层,并说明保存回执渲染在设置面板内部(不占窗口级浮层)。
|
|
16
|
+
|
|
17
|
+
### 版本号
|
|
18
|
+
|
|
19
|
+
- `package.json` 与 `index.js` 的 `PLUGIN_VERSION_FALLBACK` 同步到 **0.8.4**,两份 README 的「当前版本」同步。
|
|
20
|
+
|
|
21
|
+
## 0.8.3 — 2026-10-29
|
|
22
|
+
|
|
23
|
+
**重启阶段搬到界面正中:不再挤在输入框那一行被截断,靠数字说话,也不是常驻。**
|
|
24
|
+
|
|
25
|
+
### 现场(真机截图)
|
|
26
|
+
|
|
27
|
+
阶段那行字挤在输入框工具行的小胶囊里(22px 高、一行宽)。窗口不宽时「正在等待所有会话空闲…(还有 1 个会话在忙)」被省略号吃掉,用户看不出卡在哪、还要不要等。另一次截图里浮层上的「等待会话空闲」挂了十分钟不消失——那笔重启只是在**排队等空闲**,其实什么动作都没在跑。
|
|
28
|
+
|
|
29
|
+
### 改
|
|
30
|
+
|
|
31
|
+
- **阶段改为主界面居中浮层**(`shell.overlay` 槽位,id `autorestart-restart-overlay`):320px 固定宽、水平垂直居中、圆角、半透明,`pointer-events: none`——点哪里都照样点到下面的界面,不挡输入。
|
|
32
|
+
- `snapshotting`:「DSH 重启前备份中」+ **真实进度条** + 「12.3 / 40 MB」+ 百分比(数字来自拷贝循环的实测字节,没测到就一个数字都不写);
|
|
33
|
+
- `restarting`:「正在重启…」,一直挂着,直到宿主真的退出;
|
|
34
|
+
- `back`:「已回来」,**1.5 秒**后自动消失;
|
|
35
|
+
- `waiting`:**浮层不出现**——只是排队等空闲,没有任何动作在跑,会话数交给胶囊去说;
|
|
36
|
+
- state.json 里残留的旧阶段(`pendingRestart === false`)和页面的第一帧,都**不画**。
|
|
37
|
+
- **窄窗按字号缩放,不截断**:浮层里没有 `text-overflow`、没有省略号、不换行;窗口不够宽时用 `clamp()` 缩字号,数字永远完整可读。
|
|
38
|
+
- **底部胶囊恢复短句**(≤12 字、单行):等空闲时「待重启 · 空闲后自动重启」/「待重启 · 等待 N 个会话」;备份中 / 重启中 / 回来时整行换成「重启前备份中」/「正在重启…」/「已回来」。长句只留 tooltip,细节全部交给浮层。
|
|
39
|
+
- **胶囊与面板的数字同源**:修掉「胶囊说还有 1 个会话、点开面板却说等 0 个任务」。两处现在读同一个 `blocking` 数字——Host 在 `restartPhase.blocking` 里单独报出它,不再只藏在句子中。
|
|
40
|
+
- **设置修改有回执**:改完设置,面板里给回执——成功是绿色「已生效」+ 时间;失败是红色并保留原因、不自动消失。
|
|
41
|
+
- **回执贴在设置面板内部顶部**(`position:sticky` + `top:0`,往下滚动设置内容也一直可见;条高 30px,覆盖不挤压表单),不再浮到窗口层——`shell.overlay` 上那条注册已删,提示只出现在本插件的设置页里,关掉设置页即清空。
|
|
42
|
+
- **口径统一**:悬停提示里的「任务」改成「会话」(英文 session(s)),和胶囊、面板保持一致。
|
|
43
|
+
- **体积按大小自动选单位**:一份 92 KB 的 profile(Web/WSL)如果按 MB 印就是「0 MB」甚至「0.0 MB」,等于把一次真的备份说成什么都没干。现在 `92 KB` / `156 MB` / `12.3 MB` / `0 B` 各按大小选单位,进度行两侧也各带单位(`12.3 MB / 40 MB`)。浮层**没有任何保底显示时长**:备份快就一闪而过,慢就一直在,出现与消失完全跟随真实阶段(用户拍板:「浮层不用保底时间,短就算了,不用硬加长」)。Host 侧 `restartPhase.snapshotBytes` 仍跨阶段记录真实体积,供界面与诊断使用。
|
|
44
|
+
- **说清是什么备份**:光看「正在备份」看不出备份的是什么,所以浮层改成「DSH 重启前备份中」、胶囊改成「重启前备份中」(英文 "Backing up before DSH restart" / "Backing up…"),进度条与 MB 数字不变。设置页与 tooltip 那句长句也一起改成同一个说法:「DSH 重启前备份中(预计 X 秒,已完成 Y MB)…」(英文 "Backing up before DSH restart (about Xs, Y MB done)…"),「慢就明说」那条也把主语补成「DSH 重启前备份比预期慢…」,全产品不再出现孤立的「正在备份」。
|
|
45
|
+
|
|
46
|
+
### 验证
|
|
47
|
+
|
|
48
|
+
- 单元测试 **760 → 801 项全绿**(新增 `test/restart-overlay.test.mjs` 19 条、`test/settings-save-notice.test.mjs`、`test/pill-count-source.test.mjs`)。
|
|
49
|
+
- 两个演练仍是 exit 0:`node scripts/drill-watchdog.mjs`、`powershell -File scripts/drill-rescue.ps1`。
|
|
50
|
+
- 客户端 bundle 仍是整文件一个 IIFE(`test/client-bundle-isolation.test.mjs` 守着)。
|
|
51
|
+
|
|
3
52
|
## 0.8.2 — 2026-10-29
|
|
4
53
|
|
|
5
54
|
**线上缺陷修复:宿主起来之后没有撤销看门狗,会把好环境回滚掉。**
|
|
@@ -37,7 +86,7 @@ health 路由里那段"写 marker + 撤看门狗"的代码读的是 `stateDirOf(
|
|
|
37
86
|
|
|
38
87
|
用户反馈:"点『0 秒后重启』之后十几秒什么都不动,其实在备份 156MB,我会以为按钮没反应 / 0 秒是假的 / 有 bug。"
|
|
39
88
|
|
|
40
|
-
- **四个阶段立刻可见**:`waiting`「正在等待所有会话空闲…」→ `snapshotting`「正在备份配置和插件(预计 X 秒,已完成 Y MB
|
|
89
|
+
- **四个阶段立刻可见**:`waiting`「正在等待所有会话空闲…」→ `snapshotting`「正在备份配置和插件(预计 X 秒,已完成 Y MB)…」(0.8.3 起改为「DSH 重启前备份中(预计 X 秒,已完成 Y MB)…」)→ `restarting`「正在重启,稍后自动继续…」→ `back`「已回来,接着干」。阶段写在 checkpoint(`restartPhase`)里,点击的**同一次调用**就把 `waiting` 落盘并 persist,界面下一次轮询(2 秒一次,且点击后立即再拉一次)就能看到。
|
|
41
90
|
- **备份进度是真的**:`createBackup` 改成**文件级拷贝循环**(原来是 `fs.cpSync` 一次性拷完,既没进度也不能取消),边拷边报 `{ files, bytes, total }`,`total` 是拷之前量出来的真实总量;拷贝过程**每 120ms / 每 40 个文件让出一次事件循环**,所以取消请求能在拷贝途中被服务,进度也能在拷贝途中到界面。
|
|
42
91
|
- **备份阶段可取消**:取消后拷贝在下一个文件处停下,**半成品快照目录被删掉**(不留一个看着能还原的假备份),请求被撤回、宿主不重启;**进入 `restarting` 后取消被拒绝**(HTTP 409 + `reason: not-cancellable` + 原因),界面按钮置灰并说明"正在重启,已经不能取消了"。
|
|
43
92
|
- **两处都能读到**:`/__dsh_autorestart/health?state=1` 与 `/health` 都带 `restartPhase`(阶段、双语文字、可取消性、`slow`)和 `progress`(files/bytes/total/percent/ageMs)。
|
package/README.md
CHANGED
|
@@ -36,10 +36,13 @@ round starts, so the session goes idle and the restart can proceed. The goal is
|
|
|
36
36
|
restart and continues.
|
|
37
37
|
|
|
38
38
|
The browser shows the state: a compact "pending restart" pill on the left side of the input toolbar
|
|
39
|
-
and a small dot next to the session title in the sidebar. The pill
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
and a small dot next to the session title in the sidebar. The pill carries ONE short line (12
|
|
40
|
+
characters at most: `待重启 · 等待 2 个会话` / `pending restart · waiting for 2 session(s)`) — a
|
|
41
|
+
conversation and its own subagents count as one. Everything else lives one layer deeper: the long
|
|
42
|
+
sentence is the tooltip, the count and the way out are in the floating panel the pill opens, and the
|
|
43
|
+
**stage** of a real restart (backing up / restarting / back) is shown on a **centered overlay card in
|
|
44
|
+
the middle of the shell** — never in the composer row, where a longer sentence used to be cut off.
|
|
45
|
+
The dot breathes when the restart is about to fire.
|
|
43
46
|
|
|
44
47
|
Every blocker says **what it is**: a conversation is named by its own title, and a **subagent** is
|
|
45
48
|
named after the conversation that created it ("Subagent of *that* conversation"). A raw session id is
|
|
@@ -182,7 +185,7 @@ what it adds before you install it.
|
|
|
182
185
|
| --- | --- |
|
|
183
186
|
| Agent tools (6) | `continuum_restart`, `continuum_status`, `continuum_cancel_restart`, `continuum_park_goal`, `continuum_recover_now`, `continuum_handoff` |
|
|
184
187
|
| HTTP routes (7) | Under `<healthPath>` (default `/__dsh_autorestart`): `GET /health` (also `?state=1`, `?gate=1`, `?probeIndex=1`), `POST /park`, `POST /recover`, `POST /handoff`, `GET /sleep` and `POST /sleep` (the graceful shutdown — the desktop client and the hosted web client drive the very same route), `GET /announcements` and `POST /announcements` (the one-time new-feature announcement). Loopback or an authenticated browser only |
|
|
185
|
-
| Client slots (6) | `conversation.input.left` — the pending-restart pill (`autorestart-restart-pill`); `sidebar.session.row.leading` — the session status dot (`autorestart-restart-dot`); `conversation.input.dock` — the one-time install question (`autorestart-backup-choice`) and the one-time new-feature announcement (`autorestart-feature-announcement`); `sidebar.footer.action` — the moon button of the graceful shutdown (`autorestart-sleep-button`); `shell.overlay` —
|
|
188
|
+
| Client slots (6) | `conversation.input.left` — the pending-restart pill (`autorestart-restart-pill`); `sidebar.session.row.leading` — the session status dot (`autorestart-restart-dot`); `conversation.input.dock` — the one-time install question (`autorestart-backup-choice`) and the one-time new-feature announcement (`autorestart-feature-announcement`); `sidebar.footer.action` — the moon button of the graceful shutdown (`autorestart-sleep-button`); `shell.overlay` — the shutdown countdown card and the **centered restart-stage overlay** (`autorestart-sleep-overlay`, `autorestart-restart-overlay`); `settings.section` — the section "Auto-restart & shut down" in the settings page (`dsh-autorestart`), which also carries the save receipt inside the panel itself (no overlay slot of its own) |
|
|
186
189
|
| System prompt | One "Restart policy" section that tells the agent how to ask for a restart and what the plugin will do |
|
|
187
190
|
| Harness hooks | `agent/status` (tracks which conversations are busy), `tools/pre-execute` (blocks a shell command that would kill or relaunch DSH by hand), and the boot pass that resumes interrupted sessions |
|
|
188
191
|
| Profile row | One bundle row, `dsh-autorestart` |
|
|
@@ -198,7 +201,7 @@ what it adds before you install it.
|
|
|
198
201
|
|
|
199
202
|
## Install
|
|
200
203
|
|
|
201
|
-
Current version: **0.8.
|
|
204
|
+
Current version: **0.8.4**.
|
|
202
205
|
|
|
203
206
|
From npm — the package is published under the name `dsh-autorestart`:
|
|
204
207
|
|
|
@@ -267,11 +270,14 @@ The tool reports what happened: `cancelled` (whether the restart request itself
|
|
|
267
270
|
|
|
268
271
|
### The capsule: click it for the details and for the way out
|
|
269
272
|
|
|
270
|
-
The capsule in the composer row is 22px high and ONE line wide, so it carries
|
|
271
|
-
(`待重启 ·
|
|
272
|
-
|
|
273
|
+
The capsule in the composer row is 22px high and ONE line wide, so it carries ONE short line and
|
|
274
|
+
nothing else (`待重启 · 空闲后自动重启` / `待重启 · 等待 2 个会话`, 12 characters at most — never a
|
|
275
|
+
name and never a long sentence, because that is exactly what got cut off before). The details live
|
|
276
|
+
one layer down: the long sentence is the tooltip, the **stage** (backing up / restarting / back) is on
|
|
277
|
+
the **centered overlay card in the middle of the shell**, and the count with the way out is in the
|
|
278
|
+
panel below. Clicking it (or pressing Enter/Space on it) opens a small panel above it:
|
|
273
279
|
|
|
274
|
-
- how many
|
|
280
|
+
- how many conversations the restart is waiting for (the same number the capsule shows);
|
|
275
281
|
- how many OTHER sessions wait for the same restart;
|
|
276
282
|
- one button: **Cancel my restart**.
|
|
277
283
|
|
|
@@ -291,9 +297,28 @@ Two blocks of the settings page are worth a word, because they show facts instea
|
|
|
291
297
|
|
|
292
298
|
- **What is backed up right now** (right under the two backup switches): the HOST reads
|
|
293
299
|
`<DSH_HOME>/storages/dsh-autorestart/backups/`, so the number of copies, the **local time** of each
|
|
294
|
-
one, its size
|
|
300
|
+
one, its size, whether the installed plugins are in it and where it lives are all real. Only
|
|
295
301
|
the directory metadata is read — the contents are never walked (one copy can be 150 MB). With no
|
|
296
302
|
backup at all it says: "No backup yet; one is written before every restart."
|
|
303
|
+
Every copy is **two labelled rows**, so nothing runs into anything else:
|
|
304
|
+
|
|
305
|
+
```
|
|
306
|
+
Backup time 2026-10-29 22:08
|
|
307
|
+
Backup size 156 MB (plugins included)
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
The time is the local clock of the machine that took the copy, **to the minute and with no
|
|
311
|
+
timezone offset** (a `+08:00` only adds noise — the reader is looking at their own clock). The
|
|
312
|
+
size picks its own unit (`92 KB` / `156 MB`), keeps the tenth only when it says something
|
|
313
|
+
(`117.7 MB`, never `156.0 MB`), and the plugin scope sits in brackets right after it, because it
|
|
314
|
+
is the reason the copy is that big. Two copies are two groups with air between them.
|
|
315
|
+
- **A setting that was saved says so.** Every control writes itself the moment it is changed, so the
|
|
316
|
+
panel has to say whether the write landed: once the HOST answers `ok: true`, a green strip at the
|
|
317
|
+
**top of the settings panel itself** (inside the panel — a `sticky` row, so it stays visible while
|
|
318
|
+
the page scrolls) says **`已生效` / `Saved`** with the time (`Saved 21:40:12`) and fades after 3
|
|
319
|
+
seconds. A refused write says **`没保存成功` / `Not saved`** in red, with the reason the Host gave,
|
|
320
|
+
and it stays until the next change works or you close it. Nothing is ever announced before the
|
|
321
|
+
Host's answer arrived — rendering the page, polling it and clicking a control stay silent.
|
|
297
322
|
- **How this host was started** (hosted web only): one plain line ("How I remember you were started:
|
|
298
323
|
by your own script (the restart is its job — I stay out of it)") plus two small actions (detect
|
|
299
324
|
again / undo); the command itself is folded away under **"Technical details"** and stays closed
|
|
@@ -415,10 +440,10 @@ with its plugins is ~150 MB). The button looked dead. It is not — and now it s
|
|
|
415
440
|
|
|
416
441
|
| Stage | What the interface shows | Where the data comes from |
|
|
417
442
|
|---|---|---|
|
|
418
|
-
| `waiting` |
|
|
419
|
-
| `snapshotting` | "Backing up the
|
|
443
|
+
| `waiting` | Nothing on the overlay — the **centered overlay card does not appear at all** while the gate only waits (no backup is running, nothing happens but waiting). The capsule says it in one short line ("pending restart · waiting for N sessions"). | the idle gate's blockers |
|
|
444
|
+
| `snapshotting` | The **centered overlay card in the middle of the shell**: "Backing up before DSH restart" + a real progress bar, "12.3 MB / 40 MB" and a percentage; the settings page and the tooltip keep the long line, in the same words ("Backing up before DSH restart (about 12s, 78 MB done)…"). The card has NO minimum shown time: it lives exactly as long as the Host reports the stage (a 92 KB copy is gone in about 5 ms, a slow one stays as long as it runs); the size picks its own unit (`92 KB` / `156 MB`) so a small backup never reads "0 MB" | the REAL copy loop: files and bytes written, measured total |
|
|
420
445
|
| `restarting` | "Restarting; the work continues by itself in a moment…" | the host is on its way out |
|
|
421
|
-
| `back` | "Back — carrying on where we left off" | the new host, once it boots |
|
|
446
|
+
| `back` | "Back — carrying on where we left off", for **1.5 seconds**, then the card is gone | the new host, once it boots |
|
|
422
447
|
|
|
423
448
|
Three things make this honest rather than decorative:
|
|
424
449
|
|