dsh-autorestart 0.7.0 → 0.8.0

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/docs/README.zh.md CHANGED
@@ -12,6 +12,8 @@
12
12
 
13
13
  ## 它解决什么问题
14
14
 
15
+ **0.7.0 新增**:它会先认出自己是怎么被启动的——桌面客户端、别人的守护(脚本 / systemd / 容器 / pm2 / Windows 计划任务),还是没人管的裸跑。**有人管就只优雅退出,认不出就什么都不做**,绝不在运行中的 DSH 旁边再开一个。设置页能看到「现在备份了什么」(份数、本地时间、大小、路径),还有一个「报告问题」入口:一键复制诊断信息并打开预填好的 GitHub 问题页(诊断信息不含访问令牌、不含密钥)。
16
+
15
17
  - DeepSeek Harness 在装插件、升级、崩溃、或关掉重开时,正在跑的任务会被打断。这个插件把"重启"变成一件可恢复的事,不再需要你事后补一句"继续":
16
18
  - 等所有对话都空闲了才重启:不会在你或别的会话正在跑的时候把应用关掉;
17
19
  - 重启后自动接着干:被打断的会话自动恢复,目标(goal)会重新武装继续跑;
@@ -69,7 +71,12 @@
69
71
 
70
72
  ### DSH 起不来了
71
73
 
72
- 双击插件目录里的 `scripts/emergency-disable.cmd` —— 它会把这个插件安全地摘掉并留一份备份;然后重新打开 DSH 就行(细节见下面的「起不来怎么办」)。
74
+ 插件目录的 `scripts/` 里有两个脚本,分工不一样(**Windows 用 `.cmd`,Linux/WSL 用 `.sh`**):
75
+
76
+ - **`restore-profile.cmd` / `restore-profile.sh` —— 回到上一次好状态**:把最新的一份带 manifest 的快照放回 profile;坏掉的那份**挪走而不是删掉**,留成 `profile.broken-<时间戳>`。它**不会替你重启 DSH**,重新打开 DSH 是你自己的事。
77
+ - **`emergency-disable.cmd` / `emergency-disable.sh` —— 只把这个插件摘掉**:其余一切原样不动(只从 bundles 里拿掉这一个名字,并留一份文件备份)。
78
+
79
+ **怎么选**:「想整个回到上一个好状态」用前一个;「只怀疑这个插件」用后一个。边界(目标 profile 必须已存在、必须有带 manifest 的快照、不会自动重启、`broken-` 目录会留着)写在 [`scripts/README.md`](../scripts/README.md) 里。每个平台到底有什么、没有什么,看 [平台能力矩阵](platform-matrix.md)。
73
80
 
74
81
  ### 实测状态表(哪些真机验过,哪些只有单元测试)
75
82
 
@@ -97,7 +104,7 @@
97
104
  - 主按钮「**复制诊断信息并去 GitHub 提问题**」:点一下,诊断信息进剪贴板,同时打开一个**已经填好标题和提纲**的新 issue 页 —— 把剪贴板里的诊断信息粘贴进去就行。
98
105
  - 诊断信息里**没有**你的访问令牌,也**没有**任何密钥:它只有插件版本、平台、是不是桌面客户端、启动方式(连同判断依据)、监管器、重启模式,以及上一次重启的结果(失败时还有失败的那几项自检)。
99
106
  - 浏览器不让你用剪贴板时(不是安全上下文、或没给权限),插件会把诊断信息显示在一个**可以全选**的文本框里,并提示你手动复制 —— 报告不会因为浏览器说"不"就没了。
100
- - 没有 GitHub 账号?同一组里有一行小字给出邮箱(252170229@qq.com),外加一个「复制诊断信息」按钮和对应的邮件链接(主题已填好,正文提示粘贴)。
107
+ - 没有 GitHub 账号?同一组里有一行小字给出邮箱(252170229@qq.com),外加一个「复制诊断信息」按钮。
101
108
 
102
109
  ## 适合谁 / 不适合谁
103
110
 
@@ -143,10 +150,45 @@ session resume on boot, durable-goal re-arm, and an agent-callable idle-aware gr
143
150
  - 下次启动时 `continuum_status` 会报 `lastRollback`(时间、等了多久、是否回滚、**失败原因**、快照路径、崩溃日志名与尾部摘要)。
144
151
  - 开关:`backupOnRestart`(默认 `true`)、`backupIncludePlugins`(默认 `true`,关掉就只备配置文件)、`maxBackups`(默认 `2`)、`rollbackTimeoutMs`(默认 `90000`)、`restartCommandTimeoutMs`(默认 `30000`)、`rollbackCopyTimeoutMs`(默认 `120000`)。
145
152
 
153
+ ### 这台电脑不让建计划任务时(自动回滚就没了)
154
+
155
+ 上面那张安全网挂在一个**一次性计划任务**上:把宿主拉回来的看护脚本,是一分钟后才触发的一次性任务。有的机器**建不了**这种任务(公司策略、锁死的账号、没有权限),那么这张网就是**悄悄没有**的。
156
+
157
+ 所以插件**只查一次**(第一次在这台机器上跑的时候),然后在设置页里如实说:
158
+
159
+ - `自动回滚:可用` —— 网在。
160
+ - `自动回滚:**不可用**` —— 并且说清**会丢什么**:*重启后 DSH 起不来时不会自动恢复*。这一行直接指向「出事了怎么办」里的还原脚本,那就是出路。
161
+
162
+ **这里有意不做的事:**
163
+
164
+ - **不做降级链路**:没有「那改用启动文件夹」「那改用 systemd timer」这类备用机制,也没有"第一个不行就试第二个"。
165
+ - **不绕过策略**:插件不会去找"别的办法绕过去"。机器说不行,就是不行,答案只有"不可用"这一句。
166
+
167
+ **检测失败绝不等于安装失败**:插件照常工作,缺的只是那张安全网。检测本身是无害的:注册一个两分钟后触发、什么都不干的任务(`cmd /c exit 0`),回读校验,删掉,再回读一次确认它真的没了。它**只跑一次**(不是每次打开设置页都跑),而且**不留任何任务**(哪怕中间某一步失败也会清理干净)。
168
+
146
169
  ### 重启后的访问链接(token 是一次性的)
147
170
 
148
171
  `dsh web` 的 boot token **每个进程都不一样**,重启后浏览器手里那条旧链接会 401,用户就被挡在门外。所以插件把当前实例的访问链接写进 `storages/dsh-autorestart/access.json`(权限 `0600`,里面是密钥),并在 `continuum_status` 与日志里报出来;前端发现手里那条链接过期时,会自己跟到新链接上。
149
172
 
173
+ ### 看门狗:三种触发方式
174
+
175
+ 上面的回滚需要有人**等**:宿主被重启了,得有个一次性的东西发现新宿主一直没起来。那个东西就是**看门狗**(`scripts/watchdog.mjs`)。而"怎么让它稍后跑起来"是各台机器最不一样的地方,所以插件挑这台机器有的最好方式,并且**说清楚挑的是哪一种**:
176
+
177
+ | 档 | 机制 | 用在哪 |
178
+ |---|---|---|
179
+ | `scheduled-task` | 一次性 Windows 计划任务(建完**回读校验**,之后**完全删掉**) | 桌面客户端、Windows 上的 `dsh web` |
180
+ | `systemd-run` | systemd 用户定时器(`systemd-run --user --on-active=…`),结束后 `reset-failed` 清掉 | Linux 上的 `dsh web`、有 systemd 的 WSL |
181
+ | `detached-process` | 自建后台进程(`setsid nohup sh -c 'sleep …; …'`),pid 写在 stateDir 里 | 容器、没有 systemd 的 WSL |
182
+ | `none` | 这台机器上什么都没有 | 那就**没有自动回滚**,设置页会明说 |
183
+
184
+ **由一个函数决定**(`lib/watchdog-tier.js`),设置页、diagnostics 和看门狗自己问的都是这同一个函数 —— 所以"这台机器没有自动回滚"这句警告**不可能**和插件实际做的事对不上。
185
+
186
+ 三档跑的是**同一套**流程(`lib/watchdog.js`):等新宿主写下 ready 标记 → **再问一次**(起得慢不等于死了)→ 有实例活着吗(活着就没什么好还原的)→ 抢共用的锁(`rollback.lock`,保证只有一个在还原)→ 还原快照 → **再拉起宿主** → 再等一次 ready。最多**一次**还原 + **一次**拉起;然后看门狗停下,把结果写进 `<stateDir>/last-watchdog-report.json`(用的是哪一档、为什么)。
187
+
188
+ **同一时刻只有一个监护者。** 插件里还有一版旧的看门狗(只还原快照、**不拉起**宿主)。两者抢同一把锁,同时开反而更糟:抢不到锁的那个会放弃 —— 要是新版抢输了,结果就是**配置还原了,但没有任何东西在跑**。所以插件只在一个地方做这个决定(`lib/watchdog-arbiter.js`):**新版能用就是新版接管**(v2),新版用不了(这台机器没有档位、看门狗被关掉、或者注册失败)才**回落旧版**(v1)。报告里写着当时是谁在监护(`arbiter: "v2"` 或 `"v1"`),一眼就能看出来。
189
+
190
+ `watchdogEnabled: false` 可以整个关掉它。
191
+
150
192
  ### 开机自启:插件自带的守护
151
193
 
152
194
  手动启动的托管实例(`dsh web`)挂掉之后不会自己回来——没人拉起来的重启,就等于要用户自己再启动一次。插件可以装一个**守护**:一个独立的小进程,负责拉起宿主、看住它、它掉了再拉起。
@@ -286,7 +328,7 @@ agent/status(running) ──► 写 checkpoint(<DSH_HOME>\storages\dsh-autores
286
328
 
287
329
  ## 安装
288
330
 
289
- 当前版本:**0.7.0**。
331
+ 当前版本:**0.8.0**。
290
332
 
291
333
  ```powershell
292
334
  # 在 dsh 里(或对 Agent 说):把工作区里的这个包安装为 profile bundle
@@ -299,11 +341,22 @@ dsh plugin --profile desktop add C:\path\to\dsh-autorestart
299
341
 
300
342
  ## 起不来怎么办(装了插件之后 DSH 打不开)
301
343
 
344
+ **先分清是哪种情况**:整个环境坏了(改了配置、装了别的插件、升级崩了)→ 先回到上一次好状态;**只有这个插件可疑** → 直接走下面三步,把这个插件摘掉就够了。(两个脚本各自的边界见 [`scripts/README.md`](../scripts/README.md)。)
345
+
346
+ **用你自己平台的脚本** —— Linux 机器上没有 `.cmd`,Windows 机器上也没有 `.sh`:
347
+
348
+ | 你的机器 | 回到上一次好状态 | 摘掉本插件 |
349
+ |---|---|---|
350
+ | **Windows**(桌面客户端、Windows 上的 `dsh web`) | 双击 `scripts\restore-profile.cmd` | 双击 `scripts\emergency-disable.cmd` |
351
+ | **Linux / WSL / macOS**(托管端) | `sh scripts/restore-profile.sh` | `sh scripts/emergency-disable.sh` |
352
+
353
+ 每个平台到底有什么、没有什么,看 [平台能力矩阵](platform-matrix.md);设置页的「出事了怎么办」只显示**你这台机器上真有的**那两个路径。
354
+
302
355
  **不用等 DSH 跑起来**就能把这个插件摘掉 —— 插件目录里带了一个一键开关:
303
356
 
304
- 1. **双击 `scripts\emergency-disable.cmd`** —— 弹出的黑窗口里会写清楚做了什么,按任意键关掉;
357
+ 1. **Windows**:双击 `scripts\emergency-disable.cmd`;**Linux/WSL**:`sh scripts/emergency-disable.sh` —— 它会写清楚做了什么;
305
358
  2. **重启 DSH**(关掉再打开)——这次没有这个插件,DSH 就起得来;
306
- 3. 以后想再试它:在同一个目录里按住 Shift 右键 →「在终端中打开」,运行 `powershell -NoProfile -ExecutionPolicy Bypass -File .\emergency-toggle.ps1 -Action enable`,然后再重启 DSH。
359
+ 3. 以后想再试它:Windows 用 `powershell -NoProfile -ExecutionPolicy Bypass -File .\scripts\emergency-toggle.ps1 -Action enable`,Linux/WSL 用 `sh scripts/emergency-disable.sh --action enable`,然后再重启 DSH。
307
360
 
308
361
  它只动**一个文件**里**一个数组**:profile 的 `package.json` 里的 `dsh.profile.bundles`(就是「插件启用列表」那几行)。写之前先备份成 `package.json.bak-emergency-<时间戳>`,写完重新解析一遍 JSON 校验;校验不过就用备份回滚,并如实报错。**重复运行没有副作用**:本来就没启用时只会告诉你「已经禁用」,不会失败。
309
362
 
@@ -502,6 +555,31 @@ restart gate: action=wait reason=agents-busy-within-soft-window busyCount=1 quie
502
555
 
503
556
  **点一下就够了。** 月亮按钮按下就武装:宿主等所有忙会话收工,在角落里倒数 **20 秒**(浮动卡片,不遮挡界面),然后关掉整台机器。**再点一下**(或点卡片上的「算了,别关」)就取消。除此之外什么都不用用户做:没有确认框、不用点第二次。
504
557
 
558
+ ### 关机:关掉的是哪台机器?
559
+
560
+ 插件会先看自己跑在哪台机器上,然后关掉**那台机器**;设置页里那行字(`host.label`)写的就是它,不会让人猜:
561
+
562
+ | DSH 跑在哪 | 关机按下去会关掉什么 | 界面上的原话 |
563
+ |---|---|---|
564
+ | Windows 桌面客户端 | 这台 Windows 电脑 | 「关掉这台 Windows 电脑」 |
565
+ | Windows 上的 `dsh web` | 这台 Windows 电脑 | 「关掉这台 Windows 电脑」 |
566
+ | Linux 主机上的 `dsh web` | 那台 Linux 主机 | 「关闭这台 Linux 主机」 |
567
+ | **WSL 里的 `dsh web`** | **整台 Windows 主机**(不是那个 WSL 小环境!) | 「WSL 里的 DSH → 关掉整台 Windows」 |
568
+ | 容器 | 什么都不会(命令是空的) | 「这台机器没有可靠的关机方式」 |
569
+
570
+ > ⚠️ **在 WSL 里看到关机倒数,意味着你的整台机器会关机** —— 不是只停那个 Web 服务。
571
+ > WSL 是 Windows 里的一个 Linux 小环境,关掉它只会停掉那个发行版;要让**主机**关机,
572
+ > 插件走的是挂载盘里的 `shutdown.exe`(`/mnt/c/Windows/System32/shutdown.exe /s /f /t 0`),
573
+ > 备选是 `powershell.exe -Command "Stop-Computer -Force"` 与
574
+ > `cmd.exe /c shutdown.exe /s /f /t 0`。也就是说:**关的是主机**。
575
+
576
+ **验到什么程度**:**计划层**每个平台都验过了(`test/sleep-plan-posix.test.mjs`:WSL 的
577
+ 计划必须走「关整台 Windows」那条分支;纯 Linux 的计划里不许出现任何 Windows 命令;
578
+ 不支持的平台命令为空、**什么都不执行**)。**Windows 真关电已验**;**POSIX 有意没有真关电**
579
+ —— 为一条常识证据把所有人的会话都断掉不划算。
580
+
581
+ 每个平台的完整能力见 [平台能力矩阵](platform-matrix.md)。
582
+
505
583
  ### 关机和重启谁先谁后
506
584
 
507
585
  **一句话版本。** 点月亮按钮的意思是「**等活干完了再关电脑**」,不是「现在就算还有别的在跑也关掉」。所以:
@@ -0,0 +1,92 @@
1
+ # 跨环境能力矩阵
2
+
3
+ 这张表回答一个具体的问题:**「我这套环境到底能做什么?」**
4
+
5
+ 插件装在哪台机器上,就只有那台机器的答案 —— 所以每一行能力都按平台分开写,
6
+ 而且每一格都要能在代码里找到对应实现,或者明确写「不支持」。
7
+
8
+ - **Windows 桌面**:DeepSeek Harness 桌面客户端(`restartMode: app`)。
9
+ - **Windows web**:托管在 Windows 上的 `dsh web`。
10
+ - **Linux web**:托管在 Linux 上的 `dsh web`。
11
+ - **WSL web**:托管在 WSL(Windows 里的 Linux)上的 `dsh web`。
12
+ - **容器**:Docker / CI 里的容器。
13
+
14
+ 图例:✅ 能用 | ⚠️ 能用但有条件(**每一格都写清「用户会看到什么」**)| ❌ 不支持(为什么在最后一列)
15
+
16
+ ## 能力矩阵
17
+
18
+ | 能力 | Windows 桌面 | Windows web | Linux web | WSL web | 容器 | 说明(实现在哪) |
19
+ |---|---|---|---|---|---|---|
20
+ | 重启(DSH 自己把自己重启起来) | ✅ | ✅ | ✅ | ✅ | ✅ | `lib/restart.js`:桌面用当前 exe,托管用配置的 `restartCommand` |
21
+ | 会话续接(重启后接着干活) | ✅ | ✅ | ✅ | ✅ | ✅ | `lib/checkpoint.js` + `lib/lifecycle.js`:checkpoint 落在 `<DSH_HOME>/storages/dsh-autorestart/` |
22
+ | 重启前备份(profile 快照) | ✅ | ✅ | ✅ | ✅ | ✅ | `lib/backup.js`:快照目录 `<stateDir>/backups/`,默认留 2 份 |
23
+ | **自动回滚(看门狗)** | ✅ 计划任务 | ✅ 计划任务 | ✅ systemd 定时器 | ✅ systemd(有 systemd 时)/ ⚠️ 自建后台进程:没有 systemd 时,用户在设置页会看到「看门狗的触发方式:自建后台进程」 | ⚠️ 自建后台进程:用户会看到「看门狗的触发方式:自建后台进程」(容器里没有 systemd 定时器可依赖) | `lib/watchdog-tier.js` 选档,`lib/watchdog-schedule.js` 注册,`lib/watchdog.js` 跑流程;**同一时刻只有一个监护者**(`lib/watchdog-arbiter.js`:v2 能用就是 v2,v2 用不了才回落 v1) |
24
+ | 自动回滚的**能力检测**(能不能建任务) | ✅ | ✅ | ✅ | ✅ | ✅ | `lib/scheduler-capability.js`:真注册一次任务再回读、删掉、确认没了 |
25
+ | 自动回滚被拒时的降级链路 | ❌ | ❌ | ❌ | ❌ | ❌ | **有意不做**:被禁就是被禁,只告知(`README.md` 的「当机器不允许创建计划任务时」) |
26
+ | 手动还原(出事了自己救) | ✅ `restore-profile.cmd` | ✅ `restore-profile.cmd` | ✅ `restore-profile.sh` | ✅ `restore-profile.sh` | ✅ `restore-profile.sh` | `scripts/restore-profile.ps1` / `scripts/restore-profile.sh` |
27
+ | 摘掉本插件(急救开关) | ✅ `emergency-disable.cmd` | ✅ `emergency-disable.cmd` | ✅ `emergency-disable.sh` | ✅ `emergency-disable.sh` | ✅ `emergency-disable.sh` | `scripts/emergency-toggle.ps1` / `scripts/emergency-disable.sh` |
28
+ | 设置页「出事了怎么办」 | ✅ | ✅ | ✅ | ✅ | ✅ | 只显示**这台机器上真有的**脚本路径(`lib/rescue-paths.js` 按平台给 `.cmd` / `.sh`) |
29
+ | 桌面快捷方式(双击即救) | ✅ | ✅ | ❌ | ❌ | ❌ | 快捷方式是 Windows 的 `.cmd`;别的平台没有可双击的东西,就不显示这个按钮 |
30
+ | 关机倒数 | ✅ 关这台 Windows | ✅ 关这台 Windows | ✅ 关这台 Linux | ✅ **关掉整台 Windows**(不是关 WSL!) | ⚠️ 容器里没有意义:用户会看到「这台机器没有可靠的关机方式」,命令是空的、什么都不会执行 | 计划层已验证(`test/sleep-plan-posix.test.mjs`);Windows 真关电已验,**POSIX 未真关电**(用户决定不真关:一条常识证据不值得断开所有会话) |
31
+ | 开机自启建议 | ✅ | ✅ | ✅ | ✅ | ⚠️ 容器里没有 systemd 用户会话:用户会看到「这里不能开机自启」的说明,插件只会给建议、不会去改系统 | `lib/autostart-advice.js` + `lib/supervisor-install.js`:Windows 用计划任务或启动文件夹,Linux 用 systemd user unit |
32
+ | 问题反馈(诊断信息) | ✅ | ✅ | ✅ | ✅ | ✅ | `lib/diagnostics.js`;设置页复制,诊断信息里也带 watchdog 档位 |
33
+
34
+ ## 关机:会关掉哪台机器?
35
+
36
+ 这一格必须说清楚 —— 猜错了代价太大。
37
+
38
+ | 你在哪 | 关机倒数按下去会关掉什么 | 界面上的原话(`host.label`) |
39
+ |---|---|---|
40
+ | Windows 桌面 | **这台 Windows 电脑** | 「关掉这台 Windows 电脑」 |
41
+ | Windows 上的 `dsh web` | **这台 Windows 电脑** | 「关掉这台 Windows 电脑」 |
42
+ | Linux 主机上的 `dsh web` | **那台 Linux 主机** | 「关闭这台 Linux 主机」 |
43
+ | **WSL 里的 `dsh web`** | **整台 Windows 主机**(不是那个 WSL 小环境!) | 「WSL 里的 DSH → 关掉整台 Windows」 |
44
+ | 容器 | 什么都没有(命令是空的) | 「这台机器没有可靠的关机方式」 |
45
+
46
+ > ⚠️ **在 WSL 里看到关机倒数,意味着你的整台机器会关机** —— 不是只停那个 Web 服务。
47
+ > WSL 是 Windows 上的一个 Linux 小环境,关掉它只会停掉那个发行版;要让**主机**关机,
48
+ > 插件走的是挂载盘里的 `shutdown.exe`(`/mnt/c/Windows/System32/shutdown.exe /s /f /t 0`),
49
+ > 备选是 `powershell.exe -Command "Stop-Computer -Force"` 和
50
+ > `cmd.exe /c shutdown.exe /s /f /t 0`。也就是说:**关的是主机**。
51
+
52
+ **验到什么程度**:计划层已验证(`test/sleep-plan-posix.test.mjs`:WSL 的计划必须走
53
+ 「关整台 Windows」那条分支、纯 Linux 的计划里不许出现任何 Windows 命令、不支持的
54
+ 平台命令为空且**什么都不执行**)。**Windows 真关电已验**;**POSIX 没有真关电** ——
55
+ 用户决定不真关:为一条常识证据把所有人的会话都断掉不划算。
56
+
57
+ ## 三档调度是怎么选的
58
+
59
+ `lib/watchdog-tier.js` 里的 `pickWatchdogTier()` 是**唯一**决定档位的地方
60
+ (设置页的警告、diagnostics 里的说明、真正注册看门狗,问的都是它):
61
+
62
+ | 档 | 机制 | 什么机器 |
63
+ |---|---|---|
64
+ | `scheduled-task` | 一次性 Windows 计划任务(建完回读校验、用完全删、`IgnoreNew`、`EndBoundary` 必填) | Windows(桌面与 web) |
65
+ | `systemd-run` | `systemd-run --user --on-active=<秒>s --unit=dsh-autorestart-watchdog`,结束后 `systemctl --user reset-failed` | Linux、WSL(有 systemd 时) |
66
+ | `detached-process` | `setsid nohup sh -c 'sleep <秒>; <看门狗>' >/dev/null 2>&1 &`,pid 写进 stateDir 并回读确认还活着 | 容器、WSL(没有 systemd 时) |
67
+ | `none` | 没有可用机制 → **看门狗不注册**,`tier: 'none'`,设置页与 diagnostics 都明说「没有自动回滚」 | 被策略禁用的机器 |
68
+
69
+ ## 手工还原脚本在每个平台上做什么
70
+
71
+ 两个版本是**同一套规则**(`scripts/restore-profile.ps1` 与 `scripts/restore-profile.sh`):
72
+
73
+ 1. 默认取 `<stateDir>/backups/` 里**最新带 manifest** 的快照;
74
+ 2. 还原前把现在的 profile 整份挪到 `<profileDir>.broken-<UTC 时间戳>`(**不删**);
75
+ 3. 还原后回读校验:`package.json` 能解析、`dsh.profile.bundles` 非空、
76
+ **声明了 `dsh-autorestart` 就必须能在 `node_modules` 里读到版本号**;
77
+ 4. 路径闸门:只接受 `<DSH_HOME>/profiles/*` 或显式指定的隔离路径;
78
+ 拒绝 `/`、`/usr`、`/etc`、`$HOME` 本身、别人的家目录;
79
+ 5. **不自动重启 DSH**;`--dry-run`(Windows `-DryRun`)可以先看会发生什么。
80
+
81
+ 中文文案都来自 `scripts/rescue-strings.zh.json`(UTF-8 **无 BOM**);没有 node 的
82
+ 机器上退回英文。
83
+
84
+ ## 怎么自己验一遍
85
+
86
+ | 平台 | 命令 |
87
+ |---|---|
88
+ | Windows | `powershell -NoProfile -ExecutionPolicy Bypass -File scripts/drill-rescue.ps1` |
89
+ | Linux / WSL | `sh scripts/drill-rescue.sh` |
90
+
91
+ 演练在**自己的临时目录**里造假 profile、故意弄坏、还原、断言,然后清理干净 ——
92
+ 它不碰任何正在用的 profile。