# 更新日志 dsh-undo-savepoint 的重要变更。日期为本地时间(UTC+8)。English version: [CHANGELOG.en.md](CHANGELOG.en.md) ## [0.4.9] - 2026-09-16 ### 安全 - **home 级 settings.yaml 纳入脱敏清单**。此前快照把 DSH 家目录的 settings.yaml 原文存盘, 文件里一旦出现令牌就会随快照与导出包明文扩散。现在与 .env、.credentials.yaml 同等待遇: 快照内存占位值,真实值只写进本机 vault,本机恢复从 vault 取回真值,跨机导入得到占位并明确提示。 全值脱敏沿用既有模式(键名保留、值变占位,diff 只显示结构差异)。旧快照中的明文不追溯清除, 建议清理旧快照后重建基线。 ### 修复 - **DSH_HOME 解析对齐宿主**。DSH_HOME 为空串或纯空白时,宿主按未设置回落 ~/.dsh, 插件此前会拼出相对路径;波浪号前缀(~、~/、~\)宿主会展开而插件原样拼接。 现与 @deepseek-ai/dsh-home-paths 的行为一致,家目录解析回归新增空串分支。 ### 变更 - **CI 补齐两道门禁**。路由契约 parity 检查与局外服务器冒烟此前只在本地 npm test 执行,CI 漏检,现已入列。 - **发布物清理**。移除误随包发布的空文件 tools/gui-test-out.txt(发布物 46 个文件减为 45 个), .gitignore 预防 .npmrc 误提交。 - **开发回退路径去个人化**。测试与注释里的硬编码个人路径改为用户主目录。 - **`tools/apply-dsh-patches.ps1` 补回 UTF-8 BOM**。该脚本含中文注释,中文 Windows PowerShell 5.1 按无 BOM 的 GBK 解析会破坏引号并抛解析错误;仓库里该文件长期缺 BOM,编码审计用例 25 因此判失败,本版按字节补回。 ### 测试 - smoke 增至 317 项:home 级 settings.yaml 的脱敏入库、清单登记、vault 三文件、本机恢复回真值、diff 不泄露。 - 家目录解析回归增至三分支(DSH_HOME 显式设置 / 未设置 / 空串)。 ## [0.4.8] - 2026-09-16 ### 新增 - **局外 WebUI 深色模式(#37 by @xrn1997)**。`tools/webui/index.html` 此前把 `data-theme` 写死为 `auto`,样式表只认 `dark`,脚本里没有任何解析代码,暗色配色实际不可达,系统深色的用户始终看到亮色页面。现在页面头部内联脚本在样式表之前解析偏好并写入 `data-theme=light|dark`,首帧不会闪白;`auto` 跟随系统 `prefers-color-scheme` 并监听系统切换;顶栏新增三态按钮(跟随系统 / 浅色 / 深色)并持久化到 `localStorage`;`meta[theme-color]` 与 `color-scheme` 随主题同步,原生滚动条与表单控件一并跟随。局外 WebUI 独立于 DSH 运行、读不到 DSH 的主题设置,因此跟随系统而不是跟随 DSH 应用。 - **主题 token 快照与审计(#12 / PR #13 by @chriswild1985)**。`lib/client.js` 用到的 14 个 `--dsw-*` 变量逐一比对主题包(357 个 token)后确认全部存在,快照固化为 `tools/dsw-theme-tokens.txt`,smoke 新增断言,出现主题包里不存在的变量名即失败。PR #13 是同一问题的独立修复,其结论已被 v0.3.9 的主题色变量化覆盖,此处补上缺失的回归守卫。 - **隔离实例的补丁定位闸门**。`DSH_ROOT` 指向一份 dsh 产品树(同时存在 `package.json` 与 `lib/bin.js`)时,`lib/core.mjs` 与 `tools/apply-dsh-patches.ps1` 进入严格隔离模式,只认该产品树、不再回落全局安装与用户级 node_modules,副本 DSH 因此不可能把补丁打到本体产物树。`DSH_ROOT` 原有的依赖树解析含义不受影响,测试与 CI 里指向 `/tmp/dsh-fake15`、`C:/Users/yzf` 这类目录时不触发严格模式,探测顺序与改动前逐条一致。 - **启动预检**。profile 清单带 UTF-8 BOM、`dsh.profile.bundles` 里声明的包解析不到、patch 文件里插入重复的 loader id,这三类故障都发生在任何插件挂载之前:进程内的启动自愈够不着,DSH 直接崩在 `dsh-app-boot` 的 `readProfileManifest` 与 bundle 装配检查里,0.1.5-rc.2 又不落日志文件,连崩溃原因都无从归因。三端共用的诊断因此增加启动预检段:清单 BOM / JSON / 结构、bundles 逐项解析、`patchReload` 取值、patch 文件 BOM、`link:` 依赖与 junction 落点、patch 里重复的 loader id、上次启动未完成、崩溃归因缺失。可修项标 `fixable`,全部无问题时报出「检查了多少 profile / bundle / link」的小结。junction 检查只覆盖清单里 `link:` 声明的依赖与插件自身:DSH 包树内部的软链在能正常启动的机器上也悬空,全量上报会把真问题淹没(本机实测 16 条误报)。 - **预检可修项一键修复**。修复只做有实测依据的定点操作,动手前先落一个手动快照、修完自动复查:剥掉清单与 patch 文件的 BOM、按 id 去重 loader 条目并保留最后一条、重建缺失或悬空的插件 junction。三端同源:对话工具 `undo_doctor` 新增 `fix` 参数(报告里可修项带 `[fixable]` 标记)、离线 CLI 新增 `dsh-undo.ps1 doctor [-Fix]`(`tools/doctor.mjs`,纯 Node,不依赖 DSH 能否启动)、局外 WebUI 诊断面板新增「修复可修项」按钮与 `POST /api/undo/doctor/fix`。 ### 变更 - **engines.dsh 覆盖 0.1.5-rc.2**。0.1.5-rc.2 在插件接触面上与 rc.1 无代码差异,本声明解除 rc.2 用户的安装拦截。逐包比对 183 个可比官方包的产物体积,仅 5 个包内容有变化,分别是 Web 前端产物 `dsh-web-frontend`、界面包 `dsh-client-ui-message-feedback` 与 `dsh-client-ui-deliverables`、文案包 `dsh-message-feedback` 与 `dsh-command-feedback`,均不涉及插件使用的接口。容错补丁目标 `dsh-session-persistence-jsonl` 以及工具、会话格式、会话持久化、宿主 Web 服务、客户端模块与语言包、bundle 基座、权限预设、会话、LLM 等 14 个核心包的实现产物与 rc.1 逐字节相同。 - 容错补丁清单的 0.1.5 变体说明更新为覆盖 rc.1 与 rc.2 两个版本,`tools/dsh-patches.json`。 ### 修复 - **补丁应用遇到已失效补丁时不再整批中止**。`appendBatch-selfheal` 针对的读取竞态在 DSH 0.1.5 已被官方重构消解,目标文件里既没有旧锚点也没有新锚点。apply 此前把这种状态判定为异常并整批中止,连另外两个仍然有效的补丁也没有写入。现在清单可用 `obsoletedOn` 声明某补丁在哪些版本线上已失效:`status` 与 `verify` 把它记为 obsoleted 并视为通过,`apply` 与 `remove` 跳过它、继续处理其余补丁。0.1.5-rc.2 上的实际结果为 2 个应用、1 个失效跳过,目标文件语法检查通过。 - **`tools/apply-dsh-patches.ps1` 修复中文乱码**。脚本此前保存为不带 BOM 的 UTF-8,Windows PowerShell 5.1 按 GBK 解码后中文注释与提示乱码并触发解析错误,现在统一以带 BOM 的 UTF-8 保存。 ### 测试 - 真实产物锚点验证新增 0.1.5-rc.2 产物,判定与 rc.1 完全一致(missing=2、unmatched=1),补丁应用后语法检查通过。三个产物路径支持用 `DSH_PRODUCT_TREE_RC1`、`DSH_PRODUCT_TREE_RC2`、`DSH_PRODUCT_TREE_012` 环境变量指向本地树,CI 之外也能复现。 - 声明回归守卫扩展为同时校验 0.1.2-rc.1、0.1.5-rc.1、0.1.5-rc.2 三条已实测版本线。 - smoke 增至 289 项:B4b 段新增按目标版本判定的失效补丁断言(0.1.5 上 `appendBatch-selfheal` 记为 obsoleted 并跳过、不传版本时保持保守语义、清单 `obsoletedOn` 声明守卫),真实产物锚点循环覆盖 rc.1 与 rc.2 两份产物;T1 段新增 28 项,覆盖局外 WebUI 深色模式(解析器先于样式表、三态循环、跟随系统、`data-theme` 只收 light 与 dark,并用最小 DOM 桩真跑内联脚本验证六种偏好与系统组合)、亮暗配色变量一一对应、`--dsw-*` 主题 token 允许清单审计、产品树判定边界与 PowerShell 侧同款闸门。 - smoke 增至 314 项:新增启动预检的修复闭环覆盖(可修项清单、清单 BOM / 重复 loader id / 悬空 junction 三类定点修复、修后可修项清零、二次修复幂等、修复后的 junction 指回插件安装目录,以及对话工具 `undo_doctor fix=true` 的完整闭环:干跑标 `[fixable]`、修复后 BOM 被剥掉且清单仍可解析、复查无残留可修项、第二遍修复无事可做)。同时修掉三处测试自身的竞态:启动期的固定 `sleep` 改为轮询(快照列表为空时 `undo_list` 会提前返回,崩溃横幅断言因此落空)、重复的一次 `undo_prune` 调用(断言读到了第二次的结果而不是第一次)、预检夹具在 `apply` 的异步启动态落盘之前就把它删掉。路由契约检查改为支持嵌套路径,局外独有端点增至 3 条(`GET /api/undo/doctor`、`POST /api/undo/doctor/fix`、`GET /api/undo/locale`)。 ## [0.4.7] - 2026-09-10 ### 新增 - **适配 DSH 0.1.5 线会话格式 v3(generation 命名)**。DSH 0.1.3 起 session 日志按代数命名:v0 为 `session.jsonl.zstd`,v2/v3 为 `session.v2.jsonl.zstd` / `session.v3.jsonl.zstd`,恢复历史会话会在同目录生成更高代的新文件(旧代 immutable 保留)。undo_scan 此前只识别 v0 文件名,对 v2/v3 会话完全失明。现在局内 undo_scan 与离线 `dsh-undo.ps1 scan` 均识别三代 canonical 命名,同目录多代并存时按官方 resolveGenerationInDirectory 语义取最高代(与 DSH 自身选择一致,避免分析与过时旧代)。 - **v3 事件表与迁移型日志判定**。v2/v3 物理行结构为每行单事件 `{type, seq, time, data}`,turn/step 边界事件保留,插件逐帧 seq 连续性校验与事件计数天然兼容。seeded 迁移型日志(恢复历史会话生成)首行 `session/end-seed` 的 seq 等于 inheritedEventCount,不从 0 起,此前按 0 起点的校验会误报 seq 断裂。现在首条带 seq 记录锚定基准,其后才要求严格连续。 - **容错补丁覆盖 0.1.5-rc.1 产物**。readFirstZstdLine-tolerant 与 listArtifacts-isolate 各增加 0.1.5 形态变体:0.1.5 的 listArtifacts 改走 readGenerationHeader 包装,corrupt Zstandard 错误仍会拖垮整个会话列表,新变体在其 catch 中隔离坏会话;readFirstZstdLine-tolerant 新形态不依赖 0.1.5 已移除的 parseHeaderMeta 函数(改内联 JSON 校验),0.1.2 与 0.1.5 产物通用。appendBatch-selfheal 无 0.1.5 变体,官方重构已消解该竞态 bug,0.1.5 上显示为 unmatched 软告警(不影响功能)。 ### 变更 - **engines.dsh 覆盖 0.1.5-rc.1**。npm dsh latest 已指向 0.1.5-rc.1,本声明解除安装拦截。全量测试已在 dsh 0.1.5-rc.1 依赖树(含 cordis 4.0.2)通过。 ### 测试 - smoke 259 项(新增 B7 段 10 项:v3 原生/seeded 迁移型/v2/多代并存/非 canonical 名排除/事件计数;B4b 重写为三补丁双形态断言 + 0.1.5 与 0.1.2 真实产物锚点验证);undo-server 冒烟 9 项、路由 parity、home-resolution、e2e-watch 14 项,全部在 0.1.5-rc.1 依赖树通过。离线 CLI 对 v3 与迁移型会话实测判定正确。补丁在 0.1.5 产物上替换后语法校验通过,readFirstZstdLine 三种输入(单帧多行返回 header 行、合规单行帧正常、首行非 JSON 返回 undefined)行为验证通过。体积与版本门禁通过。 ## [0.4.6] - 2026-09-08 ### 修复 - **修复 v0.4.5 引入的 web 启动失败**(PR #36 by @JameryW)。v0.4.5 把 `lib/client.js` 的 inject 声明换成全包名,但 client 容器注册的服务名是 `locale` 与 `slots` 短名,web boot 逐名解析 inject 依赖,全包名永远解析不到,插件 entry 持续 pending,web profile 启动直接失败。现在 client.js 层恢复短服务名,`package.json` 的 `dsh.client.inject` 保持全包名(模块图层按包名声明依赖边,cordis 服务层按服务名解析,两层语义不同应当拆分)。 ### 测试 - B4b 声明守卫改为断言两层拆分(package.json 全包名 + client.js 短服务名),防止回归重演。 ## [0.4.5] - 2026-09-06 ### 修复 - **undo_scan 不再误判 DSH 0.1.2 合法空会话**。DSH 0.1.2 的空会话合法落盘为单帧且仅含 header 行(0 事件),此前每次扫描都被判为单帧布局违规并提示隔离修复。现在 0 事件判 ok,局内 undo_scan 与离线 `dsh-undo.ps1 scan` 同步生效。 - **Windows 恢复 rename 竞态不再静默**。恢复快照时目标文件被占用导致 rename 失败,此前错误被吞掉且文件仍记为已恢复。现在回退为直接写入(内容一致,非原子),两次写入都失败才如实报告 skipped。 - **容错补丁未命中不再静默**。DSH 版本演进后补丁子串在产物中找不到(unmatched)时此前没有任何提示,用户会误以为补丁仍在生效。现在启动时明确告警并提示离线运行 status 查看详情,插件功能不受影响,仅容错补丁失效。 ### 变更 - **容错补丁支持多版本子串(variants)**。DSH 0.1.2-rc.1 起 `appendBatch` 签名由 meta 变为 storage,appendBatch-selfheal 补丁自带两套子串,任一形态命中即判匹配,apply 与 remove 按命中的形态精确替换。旧版 DSH 仍按原子串处理,两代产物实测各自命中。 - **engines.dsh 覆盖 0.1.2-rc.1**。npm 安装不再拦截 0.1.2-rc.1 用户。全量测试已在 dsh-tools 0.1.2-rc.1 依赖树通过。 - **客户端注入声明换全包名**。`dsh.client.inject` 与 `lib/client.js` 由短名(slots、locale)改为 `@deepseek-ai/dsh-client-locale`、`@deepseek-ai/dsh-client-ui-conversation`、`@deepseek-ai/dsh-client-ui-settings` 三个全包名。短名在 0.1.1 与 0.1.2 均从未生效(被静默跳过),全包名在 0.1.2 起按包依赖边生效。 ### 测试 - smoke 245 项(新增空会话判定、补丁多版本匹配与声明回归守卫);undo-server 冒烟 9 项、路由 parity、home-resolution、e2e-watch 14 项,全部在 0.1.2-rc.1 依赖树通过。体积与版本门禁通过。 ## [0.4.4] - 2026-08-31 ### 安全 - **导入 ZIP 校验加固**(#24 #25,PR #26 by @K1-lihongrong + 本版补充):undo_import 与局外 WebUI 导入此前把 ZIP 条目名直接拼接为文件系统路径写入,构造 blobs/.. 开头的条目可以在快照仓库外创建文件。解压没有大小限制,高压缩比条目可以耗尽内存。现在条目名必须匹配固定格式,blob 条目名必须是 40 位 sha1,快照 id 必须匹配生成格式,包含 .. 与绝对路径与盘符的条目拒绝。三类恶意构造实测全部拒绝且无文件写出,合法导入不受影响。PR #26 落地单条解压上限 64MB 与压缩包体积上限 1GB,本版补充读文件前 stat 预检(此前是读入内存后才检查,超大文件会先打进内存再拒绝)与多条目累计解压上限 4GB(1GB 压缩包理论上可塞进上万个高压缩比条目,单条上限拦不住累计量)。 - **局内与局外 REST API 增加跨源请求校验**(#27,PR #28 by @K1-lihongrong):此前任何网页都可以向本机 API 发起跨站请求触发撤销与恢复。现在请求带 Origin 且与 Host 不一致时返回 403。无 Origin 的请求放行,curl 与本机脚本不受影响。已知边界,域名解析重绑定场景(攻击者域名解析到 127.0.0.1,Origin 与 Host 同为该域名)校验会放行,默认部署是本机直连不受影响,后续改进记录。 - **消息级撤回增加改写判断**(#34):批次记录新增 afterHash 字段,记录工具执行后的内容指纹。撤回时文件当前内容与指纹不一致就跳过该文件,不覆盖不删除。撤回前把批次涉及文件的当前内容写入 blob 库,判断出错时内容仍可找回。旧批次无 afterHash 字段,行为不变。 - **敏感文件脱敏补齐形态**(#35):YAML 列表项、块标量内容、流式续行、env 引号跨行值与裸续行此前绕过行级脱敏进入快照。现在一律替换为占位符,注释与空行保留,脱敏幂等。 ### 修复 - **局外 WebUI 导出导入支持密码**(#29,PR #30 by @K1-lihongrong):局外服务器此前丢弃请求体中的密码,加密导出不生效。现在与局内一致,无密码与错误密码导入时返回明确错误。 - **README 文件名与 Linux 桌面模板**(#31,PR #32 by @K1-lihongrong):离线 CLI 示例改为实际文件名 dsh-undo.ps1,双语同步。desktop 模板改为按标准安装位置查找启动脚本。 - **watcher 覆盖 profile 根下代码文件**(#33):cordis.patch.yml 引用的代码文件变更时现在触发自动快照,reason 为 profile-code-change,恢复写入不重复触发。已知边界,profile 根目录是非递归监听,引用子目录路径时不触发,有真实用例再补。 ### 变更 - **适配 DSH 0.1.2-alpha 线**:engines.dsh 增加 `|| >=0.1.2-alpha.2`。semver 预发布匹配规则下 prerelease 版本只被相同版本号元组的比较器匹配,此前的范围声明对 0.1.2-alpha.* 判不匹配,DSH 0.1.2-alpha 用户无法安装。逐项源码核对 0.1.1-rc.2 到 0.1.2-alpha.2 的变化面,ctx.tools.register 与 defineTool 的 value-schema 平铺格式不变,tools/pre-execute 事件仍在,webServer.register 签名不变(新增 gzip 压缩为可选配置且默认关闭),resolveDshHome 无代码变化,WebUI 进程令牌认证 URL 只影响 dsh web 打印与打开的地址形态,undo_scan 对会话日志新字段的容错(0.4.2 引入)覆盖 0.1.2 的会话事件字段增减。已实装 DSH 0.1.2-alpha.2 验证,插件安装、dsh web 启动、插件 REST 面板、watcher 自动快照、Origin 校验全部正常。 ### 测试 - npm test 七环节全部通过。smoke 231 项,其中撤回守卫 10 项、脱敏形态 9 项。undo-server 冒烟 9 项。路由 parity。e2e-watch 14 项,其中 profile 代码 4 项。home-resolution。size 与 version 门禁。 - DSH 0.1.2-alpha.2 环境实测(隔离 DSH_HOME):CLI 启动、profile 组合识别插件、插件以 link 方式安装、dsh web 启动后 REST 状态与快照清单正常、启动期间 watcher 自动生成基线与配置快照、跨源请求 403、同源请求 200。 ## [0.4.3] - 2026-08-29 ### 修复 - **局外 undo-server 单实例检测从未生效**(#19):`tools/undo-server.mjs` 是 ESM,`readState()` 却误用 CommonJS 的 `require()`,抛出的 `ReferenceError` 被裸 `catch {}` 静默吞掉,状态文件永远读不到,重复启动会堆积多个服务器进程(各占随机端口、状态互相覆盖)。改用 ESM import 的 `readFileSync`,裸 catch 收窄为只吞 JSON 解析失败(损坏时告警并视为无状态)。已在 DSH 0.1.0-rc.8 环境实测:复用检测 / 陈旧 pid 兜底 / 状态文件损坏降级三场景全过。 - **三个聊天工具(undo_doctor / undo_message / undo_compact)未注册**(#20):parameters 用了 `{type:'object', properties:{...}}` 包装,dsh-tools 的 defineTool 自 0.0.1-rc.1 起只接受 value-schema 平铺格式,注册被静默跳过。改为平铺格式后三工具正常注册;smoke-test 新增 4 项注册回归检查(PR #23 by @K1-lihongrong)。 - **恢复敏感文件后强制 owner-only 权限**(#17):POSIX 默认 umask 下 `writeFile` 会把恢复的 credentials-local 写成 0644,DSH 的 `assertOwnerOnly` 拒绝启动。恢复命中 `SENSITIVE_DESTS` 的文件后 chmod 0600(PR #22 by @K1-lihongrong),并增强为写入时即带 `mode: 0o600`,彻底消除 0644 窗口。 - **局外 WebUI 补齐 `/api/undo/note` 路由**(#18):编辑快照备注/标签不再报 unknown route,与局内实现逐字一致(PR #21 by @K1-lihongrong)。 ### 新增 - **双端路由契约 parity 检查**(`tools/check-routes.mjs`,已入 npm test):局内 20 条 / 局外 19 条 REST 路由的契约固化为清单(双端 19 条 + 单端特有 3 条),任何一端新增或删除路由而未登记契约时 CI 变红,把 issue #18 类漂移拦在合并前。已知可接受的协议级差异(restore 参数名、safe-mode 请求体、status 额外字段、export/import 密码支持)在文件头注释登记。 - **局外 undo-server 冒烟测试**(`tools/undo-server-smoke.mjs`,已入 npm test):此前 undo-server 零测试覆盖(#18/#19 均由用户发现);现覆盖启动即崩、路由命中、单实例复用(exit 0 + "已在运行")、陈旧 pid 兜底、损坏状态文件降级共 9 项断言,全程 127.0.0.1 隔离沙箱。 - **undo-server 单实例检测三层兜底**:pid 存活 + URL 存活探测(对局外独有端点 `/api/undo/locale` 真实请求)双确认才复用退出,兜住 pid 被系统复用导致 `isAlive` 误判的边角情况(#19 报告者建议方向 3);状态文件改原子写(tmp + rename),进程中途被杀不再留下半截 JSON。 - **裸 catch 审计工具**(`tools/audit-bare-catch.mjs`,开发辅助):列出全部 144 处裸 catch 及上下文并按"空体/无日志"标注风险,供系统性分级治理(#19 类隐患的排查起点)。本轮已顺手收窄 undo-server 全部 5 处。 ### 测试 - DSH 0.1.0-rc.8 + 插件实测单实例检测全部场景;npm test 六环节全绿:smoke 200 项(+4)、undo-server 冒烟 9 项、路由 parity、e2e-watch 10 项、home-resolution、size/version 门禁。 ## [0.4.2] - 2026-08-27 ### 新增 - **`undo_scan` 支持 synthetic-closer seq 重叠修复**:扫描改为逐帧解码(不再把整个日志 `Buffer.concat` 到内存,避免大文件出现 `Allocation error : not enough memory`),并识别「崩溃恢复写入的 `step/end`+`turn/end` 合成关闭帧之后,续跑会话又复用旧 seq」的损坏模式;`quarantine=true` / `dsh-undo.ps1 scan --fix` 时只删除该合成关闭帧即可让日志恢复连续,保留其后全部事件(原件留 `.bak` + 隔离区副本)。 ### 修复 - **多重叠日志可一次修复**:多次崩溃恢复会留下多个 synthetic-closer 重叠帧,此前 `--fix` 每次只删第一个、重分析后仍 fixable、且抛错不写盘,形成永远修不完的死循环;现在循环删除所有匹配的重叠帧直到重分析通过(上限 1024 次),单次 `--fix` 完成修复(PR #14 后续修补)。 - **无 seq 字段的合法行不再误判 corrupt**:合法 JSON 但不含 `seq`/`seq0` 的记录行(如心跳、未来格式扩展)此前被当作 `bad JSON line` 判 corrupt,与 v0.4.1 行为相比是回归;现在这类行计为合法事件、跳过 seq 连续性校验,真正的 seq 跳跃仍判 corrupt(PR #14 后续修补)。 - **`engines.dsh` 声明修正**:`>=0.0.1` 按 semver 规则不匹配任何 prerelease 版本(如 0.1.0-rc.8 / 0.1.1-rc.2);改为 `>=0.0.1-0 || >=0.1.0-rc.2 || >=0.1.1-rc.1`,精确覆盖已实测的三条 rc 线与全部正式版。已在 dsh-tools 0.1.1-rc.2 下跑通全量 smoke(208 项)。 ## [0.4.1] - 2026-08-23 ### 修复 - **macOS 延迟投递修复(CI e2e-watch)**:restore/undo 后 `ensureMount` 重写 `cordis.patch.yml` 的内容哈希登记入 `restoredHashes`,使 watcher 的内容 echo 检测识别「这是挂载管理写、非用户变更」;避免 macOS FSEvents 延迟投递事件在 `suppressAuto` 同步窗口外被当作真实变更,产生挡住 redo 的回声快照。已在三平台 CI 验证(此前仅 macOS 失败,现 macOS/ubuntu/windows 均绿)。 ## [0.4.0] - 2026-08-22 ### 新增 - **全平台适配**:核心抽离为纯 Node、零依赖的 `lib/core.mjs`(~1900 行,约 100 导出),`lib/index.js` 转为薄主机壳;ZIP(`lib/zip.mjs`,纯 Node 实现,兼容 PowerShell)、目录/文件选择器、pnpm 调用均按平台分发(win32=PowerShell / darwin=osascript / linux=zenity→kdialog);CI 升级为三平台矩阵 `windows/ubuntu/macos × node[20,22]`(fail-fast false)。 - **局外 WebUI(跨平台,DSH 挂了也能可视化回滚)**:`tools/undo-server.mjs`(`node:http`,绑定 127.0.0.1,单实例锁)+ `tools/webui/{index.html,app.js,styles.css}` + `tools/launch-undo.{bat,command,sh,desktop}` 启动器;时间线 / 文件级 diff / 一键回滚 / 诊断 / 安全模式全都有。 - **时间线 Time Machine**:快照时间线可视化、文件级双栏 diff(新增/删除行高亮、逐文件导航、上一/下一文件)、入场动画(尊重 `prefers-reduced-motion`)。 - **一键诊断 `undo_doctor`**:核心 `runDoctor` + 对话工具 `undo_doctor` + REST `GET /api/undo/doctor` + WebUI 诊断按钮;检查 store 可写性(真实 `.doctor-probe` 写/删)、blob 缺失/孤儿、settings 健康、快照规模,输出结构化 ok/warn/err 报告与修复提示。 - **消息级撤销 `undo_message` / `undo_message_list`**:`tools/pre-execute` 旁路记录工作区文件变更(白名单 `write/edit/replace/patch`、`workspaceDirs` 范围、60s 时间窗批次),按反向序恢复 before 内容/删除新建文件;`keepMessageOps`、`fileToolWhitelist`、`workspaceDirs`、`workspaceWatch` 设于 `DEFAULT_SETTINGS` 与 cfg。 - **快照瘦身 `undo_compact`**:孤儿 blob GC(不被任何快照/消息批次引用的 blob 与残留 `.tmp`),支持 `dry_run`。 - **桌面快捷方式(新增)**:插件加载后自动在桌面创建「dsh-undo-savepoint」快捷方式,双击即打开局外工具(undo-server WebUI)。三平台分发(win32=`cmd /c launch-undo.bat`,darwin=`launch-undo.command`,linux=`launch-undo.desktop`);幂等(已存在跳过);`settings.createDesktopShortcut=false` 或 `DSH_UNDO_NO_DESKTOP=1` 可关闭;`desktopDir` 可覆盖(测试用)。 - **ZIP 互操作修复**:`readZip` 将条目名 `\` 归一为 `/`(NFC),使纯 Node 能读 PowerShell `Compress-Archive` 产出的 ZIP——双向格式互通已验证。 - **体验增强**:快照备注/标签(`undo_note` 工具 + `/api/undo/note`,WebUI 时间线可直接编辑;`undo_snapshot` 支持 `note`/`tags`);定时快照(设置 `scheduledSnapshotEnabled`/`scheduledSnapshotMs`,按间隔自动创建 auto 快照并做保留清理);目录树 diff(`/api/undo/tree` + WebUI 左栏树导航,按目录聚合、增/删/改着色);ZIP 加密导出(`node:crypto` AES-256-GCM + scrypt,`DSHUNDOENC1` magic 头;默认不加密保持 PowerShell 互通,导入带密码自动解密)。 - **可视化增强**:时间线按日期分组卡片化、备注/标签芯片、入场/过渡动效(尊重 `prefers-reduced-motion`);局内(client)头部新增「对话撤回」入口与消息级撤回面板(复用 `/api/undo/messages` + `/api/undo/message`);局内快照面板新增「加密导出/导入」密码输入(`/api/undo/export|import` 带 `password`)与「定时快照」设置(`/api/undo/settings` 的 `scheduledSnapshotEnabled/Ms`,与 WebUI 对齐)。 - **插件 Logo 与图标接线**:新增 image2.0 生成提示词 `docs/logo-prompt.md`;Web 页面(`tools/webui/index.html`)接入 favicon(`logo.svg` 跨平台占位 + `logo.png` 生成后兜底);桌面快捷方式(`createWinLnk`)在 `tools/webui/logo.ico` 存在时用自定义图标(回退 `logo.png`,再回退系统默认);新增零依赖 `tools/make-ico.mjs` 把生成的透明 PNG 转成 Windows `.ico`。 - **工作区范围可配置**:消息级撤销新增设置页字段「跟踪工作区目录」(`settings.workspaceDirs`),纳入 `publicSettings` 与 `POST /api/undo/settings`(`DEFAULT_SETTINGS.workspaceDirs` 与之动态联动);逗号/分号分隔可多选,非空时覆盖默认 `[process.cwd()]`,留空=仅当前工作目录;i18n 补 zh/en 键;局内面板(client)与局外 WebUI(app.js)的设置页已同步该字段,且面板补齐 `createDesktopShortcut`/`desktopDir` 显示,两边设置项一致。 - **Logo 换新(小体积)**:WebUI 主 favicon 用内置 `tools/webui/logo.svg`(852 B,最小);桌面快捷方式用从 `logo.svg` 经 headless Edge 栅格化的 **64×64 透明 PNG**(3.4 KB)转成 `tools/webui/logo.ico`(3.5 KB),`logo.png` 同 3.4 KB 作为兜底;现有 `.lnk` 图标原地指向新 ICO。 ### 修复 - **依赖纪律**:整个插件保持零运行时依赖(ZIP、translate、picker、server 全手写);单快照引用 ≤5MB(超限仅清单+告警)与插件体积上限(`check-size` 收紧到 5MB)两道门禁持续回归。 - 供测试回归:smoke 由 174 项扩至 189 项(消息级撤销、孤儿 GC、zip 互操、i18n 完整性、doctor),e2e、home、check-size、check-version 全绿。 ## [0.3.9] - 2026-08-22 ### 新增 - **多语言(host / CLI / WebUI 一起落地)**: - 新增 `lib/i18n/{zh,en}.json` 作为唯一词典源(140 键,覆盖 host 用户可见消息与 WebUI 全部文案);零依赖翻译器 `lib/i18n.mjs`(`t(key, vars?, lang?)`),语言优先级 `DSH_UNDO_LANG` > 本机 `Intl`/`LANG` 中文 > en 兜底 - host 端 `lib/index.js` 用户可见文案接入 `t()`:安全模式(进入/已开启/重扫/中和/补丁提示/状态/退出/损坏包拒绝)、undo/redo/restore 结果渲染、busy 拦截、快照/列表/差异/清理/导出/导入/最近回滚/版权,`smoke` 固定 `DSH_UNDO_LANG=en` 后断言保持不变 - WebUI(`lib/client.js`)沿用 `ctx.locale.register/bind`(rc8 已确认兼容),内联 zh/en 词典与 `lib/i18n` 做**单一词典源一致性断言**(client 每键在 JSON 存在且非空、zh/en 键集一致),防止两处飘移 - 离线 CLI(`dsh-undo.ps1` / `dsh-undo-savepoint-lib.ps1`):新增 `Get-UndoLanguage` / `Get-UndoText`(读 `lib/i18n/*.json`,`DSH_UNDO_LANG` / `$PSUICulture` 选择),`snapshot`、`undo` 等结果文案双语化;`.ps1` 保持 UTF-8 with BOM - **产物体积门禁缩到 5M**:新增 `tools/check-size.mjs`,扫描 `lib/` + `tools/` + 顶层 `package.json`/README/CHANGELOG/LICENSE/`cordis.patch.yml`,跳过 `node_modules/.git/.github/docs`;`npm test` 首位执行,超过 5MB 即失败。当前产物约 565KB - **主题色变量化(`--dsw-alias-*`)**:WebUI `client.js` 硬编码颜色迁移到 `--dsw-alias-bg-layer-1 / --dsw-alias-bg-mask-1 / --dsw-alias-border-l3 / --dsw-alias-state-error-primary / --dsw-alias-state-success-primary / --dsw-alias-state-business-primary`(`--dsw-specific-tip` 保留),配合主题切换 ### 测试 - smoke 174 → 180(+6 个 WebUI/词典一致性断言);`npm test` 全链(check-size → check-version → smoke → home-resolution → e2e)绿 - e2e 10/10 无回归;CLI `status` 在 `DSH_UNDO_LANG=en` 下可运行 ### 变更 - 环境变量:`DSH_UNDO_LANG`(`zh`/`en`;未设置时宿主中文环境默认中文,否则英文) ## [0.3.8] - 2026-08-21 ### 新增 - **安全模式 bundle 中和**:安全模式此前只最小化 patch 层,对「profile bundles 硬校验失败导致 DSH 起不来」完全无效。现进入安全模式时用与 dsh-app-boot `loadProfile` 相同的三项规则(可解析 / 有 `dsh.bundle.patch` / patch 文件存在)逐项校验 `dsh.profile.bundles`,剔除坏条目写回(原 `package.json` 双保险:快照 + 独立备份 `safe-mode-pkg-.json`);退出时整份恢复,消息报告中和条目数。边界:`package.json` 缺失跳过不阻断;JSON 损坏拒绝进入且绝不破坏性重写。幂等重扫:已在安全模式中再次 `on` 时只重扫报告,不重复写 - **崩溃归因 v2(crashReason)**:上次崩溃后启动时扫描日志尾部匹配已知签名,把崩溃分类为 `session-corrupt`(会话文件损坏)/ `bundle-check`(bundles 硬校验失败)/ `patch-tree`(插件挂载/加载失败)/ `unknown`,写入 `boot-state.json`(下次启动直接复用,日志滚动不丢归因);`undo_list` 崩溃横幅按分类给出处置建议(会话损坏→`undo_scan`,bundle→进安全模式),`/api/undo/status` 返回 `crashReason` 字段 - **`undo_scan` 会话健康扫描与修复**:扫描 `/sessions/**/session.jsonl.zstd`,判定 `ok` / `fixable`(单帧布局违规,8/18 崩溃根因)/ `corrupt`(无法解码 / 首行非法 header / 坏 JSON 行);`quarantine=true` 时修复 `fixable` 文件——原件复制到 `/corrupt-quarantine/` 并留 `.bak`,重编码为「header 独立帧 + 事件帧」并做三重校验(round-trip 文本一致 / 逐行 JSON / 重分析)后替换;`corrupt` 文件只隔离复制、绝不动原件。配套:`dsh-undo.ps1 scan [--fix] [-Label ]` 与离线脚本 `tools/session-scan.mjs`(DSH 起不来时也能用)。**依赖 Node ≥22.15**(`node:zlib` 的 zstd API);Node 20 下 `undo_scan` 降级为明确"不支持"提示、插件其余功能不受影响 - **dsh-session-persistence-jsonl 补丁托管**:3 处容错补丁(`appendBatch` 自愈 / `listArtifacts` 隔离 / `readFirstZstdLine` 宽容)以 `tools/dsh-patches.json` 清单托管(old = rc8 原始代码,new = rc6 已验证补丁);`tools/apply-dsh-patches.ps1 status|verify|apply|remove` 离线应用/还原(逐补丁备份 `.bak-`,未知状态中止不写);插件启动时只读校验并告警(绝不自动改文件),进入安全模式时附带提示 ### 优化 - `undo_safe_mode` 工具描述与 WebUI 确认文案同步 v0.3.8 能力(bundle 中和) ### 测试 - smoke 146 → 174(新增 5 节 28 个断言): bundle 中和往返 + 损坏 package.json 拒绝进入、 日志签名分类(session-corrupt / bundle-check 两场景)、 扫描/修复/隔离/复扫、补丁清单 old/new 与真实 rc8/rc6 目标精确匹配 - 修复:编辑后的 `.ps1` 文件重新携带 UTF-8 BOM(用例 25 编码审计回归校验) - 收尾验证:smoke 174 全绿;e2e 10/10 无回归;home-resolution 2 分支全绿 ## [0.3.7] - 2026-08-21 ### 修复 - **issue #11:快捷方式脚本编码事故**:`tools/make-desktop-shortcut.ps1` 转 UTF-8 with BOM(中文 Windows PowerShell 5.x 按 GBK 解析无 BOM 中文 → 引号被破坏 → ParserError,「DSH撤销管理器」桌面快捷方式创建失败);新增 smoke 编码审计用例(含非 ASCII 的 `.ps1/.bat` 无 BOM 即 FAIL),杜绝回归 - **安全模式自删/悬空修复(8/17 复盘补完)**: - 空备份回退:进入时 profile patch 缺失 → 备份写 `[]`(语义=无用户插件可禁用),不再留下"引用从未创建的备份"死锁 - 不变量断言:`active ⇒ 备份文件真实存在`,进入侧断言失败拒绝写状态文件 - 双级 patch:home 级 `cordis.patch.yml` 一并备份/最小化/恢复(此前安全模式只动 profile 级,home 级挂载的插件完全不受控) - home 指纹:状态记录 home 指纹(home 根 + profile + settings.yaml 统计),家目录重建/换机时残留状态自动降级为不激活并告警,绝不把旧家的安全模式带到新家 - 启动自愈:安全模式激活中若 undo 挂载丢失(profile 初始化竞态),启动时自动补挂载 - **rc8 双重挂载启动即崩(2026-08-21 现场)**: - 启动去重自愈 `dedupeMount`:扫描 bundle / profile patch(含 include 引用)/ home patch 全部挂载源,重复时只保留 canonical(bundle > profile patch > home patch),改动前先备份 `.dsh-undo-bak` - 注册防御 `registerToolOnce`:重复注册只告警跳过,绝不炸掉启动 - `safeEffect` rc8 兼容盖子(工作区既有实现)随发布版合入 ### 优化 - **单快照 ≤5MB 约束**:`pluginMaxSnapshotBytes` 10MB → 5MB;manifest 新增 `totalBytes`(快照物化体积),`undo_list` 展示体积与 `[truncated]` 标记;超限语义沿用"仅记清单+告警,不丢数据" - **快照精简固化**:新增 smoke 断言——无外部插件环境快照总字节 <100KB ### 测试 - smoke 114 → 146(新增 10 节 32 个断言):编码审计、快照精简+totalBytes、patch 缺失进出安全模式、全新 home 往返、双级 patch 备份恢复、home 指纹降级、启动自愈、5MB 截断、双重挂载去重(patch+patch / patch+bundle 两场景)、重复注册降级与 safeEffect 兜底 - 清理健壮性:`fs.rm` 统一加重试(Windows 杀软/索引器短暂占用目录句柄会偶发 ENOTEMPTY) - e2e 10/10 无回归;home-resolution 2 分支全绿;CI 在 windows-latest × node[20,22] 上执行 ## [0.3.6] - 2026-08-20 ### 修复 - **快照补齐启动关键文件**:新增 profile 级 `pnpm-lock.yaml` 与 home 级 `cordis.patch.yml`,与 `dsh plugin add/update/remove` 实际改动的状态对齐(issue #8) - **恢复后对账依赖状态**:undo/redo/restore 触及 `package.json` / `pnpm-lock.yaml` / `pnpm-workspace.yaml` 时,默认报告 `node_modules` 可能不同步并给出重建命令;显式开启同步时执行 `pnpm install --frozen-lockfile`(无 lockfile 回退普通 `pnpm install`),安装失败不回滚已还原的配置文件 - **watcher 容错(node 20 CI 暴露)**:`fs.watch` 补挂 error 处理器——被监听目录被删除/重命名时(测试清理临时目录、真实使用中卸载插件/改目录名),Windows 下 FSWatcher 异步抛 `EPERM`,此前无处理会以未捕获异常炸掉整个进程;现自动关闭该监听并告警,不再崩溃 ### 优化 - **移除 npm 安装方式**:README 删除 npm 发布版安装说明与 npm 安装地址,安装方式收敛为 GitHub 直装(方式 A)与本地源码(方式 B) ### 变更 - 离线 CLI:`dsh-undo.ps1 undo|redo|restore -SyncDeps` - 模型工具:`undo_restore` 新增 `sync_deps` 布尔参数 - REST:`/api/undo/undo|redo|restore` 接受可选 `syncDeps` ### 变更 - **CI 迁移 windows-latest**:本项目为纯 Windows 插件(`runPnpm` 走 `cmd.exe`、测试用 `.cmd` 假 pnpm、附带 `.ps1/.bat` 工具),此前 CI 误跑 ubuntu-latest,第 24 节"假 pnpm"测试必然失败(`pnpm.cmd` 在 Linux 上不生效,marker 未生成导致 ENOENT 抛崩)——现已与真实部署环境一致 - **fail-fast: false**:node 20 / 22 矩阵各自跑完、独立报告,不再互相取消 - **补跑 home-resolution-test.mjs**:CI 与 `npm test` 四脚本套件对齐(此前漏跑 issue #6 的 DSH_HOME 回归) - **smoke-test §24 诊断加固**:sync_deps 失败时打印 restore 输出尾部,marker 缺失走明确断言,不再被未捕获 ENOENT 掩盖真实失败原因 ### 测试 - smoke 106 → 114(新增 lockfile/home patch 快照、字节级还原、默认不同步、显式同步命令校验、spec.json 一致性断言) - e2e 10/10 无回归;CI 在 windows-latest × node[20,22] 全绿 ## [0.3.5] - 2026-08-17 ### 修复 - **支持 `DSH_HOME` 环境变量**(issue #6):家目录解析优先读 `DSH_HOME`,无则回退 `~/.dsh`,与 DSH 官方启动器一致。此前所有 `.dsh` 相对路径(设置文件、快照根、profile 目录)都硬编码 `~/.dsh`,使用第三方客户端(家目录非默认)时设置丢失、自定义快照目录重启后回退默认 - `lib/index.js`:新增 `DSH_HOME_DIR` 常量(`DSH_HOME` ?? `join(HOME, '.dsh')`),`LEGACY_ROOT` / `SETTINGS_FILE` / `rootDir()` / `profileDir` 全部基于它 - `tools/dsh-undo-savepoint-lib.ps1`:同步对齐,`$script:DshHome` 优先 `$env:DSH_HOME` - `tools/make-desktop-shortcut.ps1`:桌面快捷方式候选路径支持 `$DSH_HOME`(自定义家目录客户端也能自动定位插件目录) - `DSH_UNDO_ROOT` / `DSH_UNDO_SETTINGS` 显式覆盖优先级不变 - `node_modules` 发现路径保持 `HOME`(用户级,不在 `.dsh` 下) ### 优化 - **README 预览图改走 jsDelivr CDN**(`cdn.jsdelivr.net/gh/lire1131/dsh-undo-plugin@master/docs/*.png`):`raw.githubusercontent.com` 在国内网络常被阻断,此前仓库页 README 图片经常加载不出来;CDN 直连可稳定加载。图片有缓存(约 12h),需强制刷新时访问 `https://purge.jsdelivr.net/gh/lire1131/dsh-undo-plugin@master/` 清缓存 ### 测试 - smoke 106/106、e2e 10/10 全通过(无回归) - 新增 DSH_HOME 验证:设 `DSH_HOME=/tmp/fake` 后快照和设置均写入该路径,`~/.dsh` 无残留;不设时回退行为不变 - 新增自动化回归 `tools/home-resolution-test.mjs`(双分支:`DSH_HOME` 优先 / 默认回退 `~/.dsh`,验证快照捕获来源与设置文件落点),已接入 `npm test` 与 CI ## [0.3.4] - 2026-08-16 ### 新增 - **WebUI 快照入口全面增强**(替换社区 PR #4 的"两个小相机图标"方案,改为成套 UI): - 会话头部「撤销 / 恢复 / 快照」三按钮全部图标化(红色 ↶ / 绿色 ↷ / 相机,单色 `currentColor` 随主题自适应) - **快照按钮 = 一键手动快照**:点击立即存档当前配置(等价面板内「手动保存」,成功后按钮旁闪现「已存档 」),不再打开面板 - 头部新增**自动快照状态徽章**:绿点 + 「已存 N 份快照 · 最近 xx 分钟前」,30 秒自动轮询刷新(配置一改、自动快照落地,徽章即刻变化);**点击徽章 = 打开快照面板** - 快照面板头部:相机图标 + 标题 + 当前 profile 副标题(取自最新快照 manifest 的 `profile` 字段,v0.3.3 多 profile 成果的可见化) - 纯客户端改动(`lib/client.js`),host 端与快照逻辑零改动 ### 修复 - **会话运行中禁止撤销/恢复/回滚/安全模式切换**:有任何 live 会话处于 open turn(agent 正在执行)时,undo/redo/restore 与 safe-mode on/off 一律拒绝并给出明确提示(host 端安全闸 + WebUI 专属提示)。此前撤销会写回 `cordis.patch.yml`、触发 DSH 内置 HMR 热重建插件树,导致所有正在跑的会话一起中断、无法恢复(用户反馈的"误点撤销导致整个工作区崩溃");空闲时行为完全不变 ### 测试 - smoke 101 → 106(运行中守卫:open turn 拒绝且配置未被回滚 / safe-mode 拒绝且 patch 未被改写 / closed turn 放行) ## [0.3.3] - 2026-08-16 ### 新增 - **多 profile 支持**(issue #3):从 `process.argv` 解析当前 profile(`--profile mine` / `--profile=mine`,`dsh web` 回退 `web`),`config.profileName` 可显式覆盖 - `profileDir` 默认改为当前 profile 目录(此前硬编码 `web`——非 web profile 下快照读错、watcher 漏监听、恢复写错位置) - 快照仓库按 profile 隔离:`<快照根>//{auto,manual}`;兼容旧数据——profile 作用域目录不存在而旧平铺目录存在时自动回退平铺(不隐身旧快照) - manifest 增加 `profile` 字段,`undo_list` 显示当前 profile - 离线 CLI/GUI 同步:`DSH_UNDO_PROFILE` 环境变量或 settings `profileName` 指定(离线无法看到 argv) - 显式配置(`profileDir` / `manualDir` / `autoDir` / `profileName`)优先级不变 - **ps1 离线工具支持 `DSH_UNDO_ROOT` / `DSH_UNDO_SETTINGS` 环境变量**(与 Node 插件对齐;此前 ps1 只认默认路径,自定义库用户离线工具会错位) - **package.json 声明 `dsh.runtime: "host"`**(WhaleHarness 审计门槛:使用 child_process 必须声明 host runtime) ### 修复 - settings.json 默认位置迁移兼容:旧位置(如 `D:\dsh\undo\settings.json`)配置的数据不再"隐身"——新位置读取后按配置目录继续工作 ### 测试 - smoke 98 → 101(argv 解析 / manifest profile 字段 / 显式 profileName 覆盖);e2e 10/10 ## [0.3.2] - 2026-08-15 ### 新增 - **敏感信息脱敏 + 本机 vault**(默认开启):`.env` 与 `.credentials.yaml` 进快照时值替换为 `***REDACTED***`(键名/export/引号/注释/结构全保留),快照与导出 ZIP 可自由外传零泄露;真实值存本机 vault(`/env-vault/`,内容寻址),**本机回滚完整还原含值**,换机回滚得到占位 + 提示填写 - `sensitiveMode` 设置:`redact`(默认)/ `keep`(明文旧行为);旧快照自动兼容 - **diff 两侧都脱敏**(快照侧与当前侧,含旧快照明文),界面永不出现真实值 - **`.credentials.yaml` 纳入快照范围**(此前不在——DSH 真凭据文件损坏时局内外都救不了) - **局外急救补齐**(DSH 挂了也能救全): - **GUI 崩溃横幅升级**:读 boot-state.json(旧逻辑查已废弃的 .booting,v0.3 后失效已修复),显示 last-good 快照 + 一键回退到该快照 - **GUI 一键安全模式按钮**(on/off 确认框);**GUI 标题栏显示当前敏感模式** - **CLI 新增 `recent` 命令**:查看回滚日志(WebUI 的 undo_recent 对等能力) - **CLI `settings -Label "key=value;..."`**:离线修改设置(此前只读) - **CLI undo/redo/restore 输出增强**:needsRestart / 跨机 preflight 警告 / 脱敏占位 Note 提示 - **WebUI 设置独立侧栏栏目**:「快照」栏目一页展示全部设置(不再挤在"通用"里),含敏感模式下拉、插件目录白名单、目录 📁 选择 - **设置双端同步修复**:ps1 补读 keepPre/autoCleanup(此前 GUI 打开显示为空并覆盖 WebUI 值);GUI 目录选择用「浏览」按钮 - **孤儿 blob 清理**:`undo_prune` / 清理过期顺带删除"无任何快照引用"的插件代码 blob(跨机导入残留不再占空间) - **导出敏感警告**:keep 模式或旧快照含明文敏感文件时,导出(对话/WebUI/CLI)明确警告"包含真实密钥,请勿外传" - **`undo_list` 显示敏感模式**:附当前模式 + 最近快照脱敏文件数 ### 修复 - ps1 `Get-UndoBootAlert` 升级为读 boot-state.json(含 lastGoodAt),新增 `Get-UndoLastGoodId` - GUI 工具栏 11 按钮溢出被列表遮挡(两行排列 + 单实例 Mutex 防重复后台) - diff 泄露:当前文件侧明文直接显示(如 `DEEPSEEK_API_KEY: sk-...`)——两侧统一脱敏 ### 测试 - smoke 76 → 98(脱敏规则各形态 / vault 本机完整恢复 / 换机占位 / diff 双侧零泄露 / keep 明文 / 孤儿 blob 清理 / 旧快照兼容);e2e 10/10 ## [0.3.1] - 2026-08-15 ### 新增 - **跨机一致性预检**:恢复(undo/redo/restore)时自动扫描目标快照引用的插件(patch 挂载条目 + package.json bundles),本机解析不到的**明确列出并提示**"恢复后可能启动失败",建议先装插件或安全模式启动 - 多锚点探测(用户 node_modules / profile 依赖树 / 插件位置链),任一可解析即视为已装,避免 junction 布局误报 - 本地文件条目(`name: './xxx'`)不探测;预检结果写入回滚日志 - **docs/migration 双语文档**:跨机迁移行为说明(插件代码不会塞入目标机、blob 残留、patch 缺插件的坑)+ 最佳实践,中英双语 ### 修复 - `toolsRequire` 从块级作用域提升为模块级(此前外部函数引用会被 try/catch 静默吞掉 ReferenceError,预检的多锚点解析依赖它) ## [0.3.0] - 2026-08-15 ### 新增 - **崩溃归因升级**:`.booting` 标记升级为 `boot-state.json`,记录每次启动的结果与"最后正常启动时间";上次异常退出时,`undo_list` 与 WebUI 直接给出**具体的最后正常快照 id 与一键回退按钮**,不再只说"上次崩溃了" - **一键安全模式**:`undo_safe_mode` 工具(对话可直接用)+ WebUI 快照面板「安全模式」按钮 + 离线 CLI `safe-mode on|off|status`——进入时自动手动快照并备份 `cordis.patch.yml`,把 patch 最小化(只留撤销系统),保证 DSH 一定能启动;退出时恢复原配置。DSH 完全起不来时的终极兜底 - **重启联动**:undo/redo/restore 涉及插件代码或挂载配置时,报告与 WebUI 明确提示"重启 DSH 后生效",回滚日志同步记录 ## [0.2.1] - 2026-08-15 ### 新增 - **一键桌面快捷方式**:`tools/make-desktop-shortcut.bat`(双击)/ `.ps1`(命令行)自动定位插件目录,在桌面创建「DSH撤销管理器」快捷方式——解决"装完找不到局外工具" - **README 新增「局外工具在哪」章节**:写明两种安装方式的工具路径 + 一段无需先找文件的一行命令(自动定位并创建快捷方式)+ 打开工具目录命令 ### 修复 - 澄清包名/仓库名差异:安装命令写 `dsh-undo-plugin`,装好后目录名是**包名 `dsh-undo-savepoint`**——按仓库名找目录必然找不到,README 已标注 ## [0.2.0] - 2026-08-15 ### 新增 - **插件代码树快照**:自动发现用户插件(`node_modules` 下的 junction,如 `D:\dsh\plugins\*`)与 profile 本地代码文件(`cordis.patch.yml` 里 `name: './xxx'` 引用的 `router-global.mjs` 等),插件代码被改坏也能撤销——配置没变也能撤(如 whale-kit "yield* is not async iterable" 这类纯代码事故) - **体积 4 道保险**:扩展名白名单(只收 `.js/.mjs/.cjs/.ts/.json/.yml` 等代码文件,资源如 gif/png 不进快照,实测 pet 57MB→47KB)、内容寻址 blob 库去重(`<快照根>/blobs`,没变的文件零拷贝)、单文件/单快照上限(超限记录 skipped)、按引用恢复(缺失明确报告) - **插件文件 diff**:`undo_diff` 与 WebUI 差异预览显示 `plugin:xxx` / `profile:xxx` 条目 - **插件 watcher**:插件代码目录变化自动快照(`plugin-code-change`),恢复动作自身不误伤(echo 检测) - **单一清单 `lib/spec.json`**:快照范围 Node 与 PowerShell 共用一份配置,不再双写漂移 - **`pluginDirs` 设置**:可显式指定插件目录白名单(空数组 = 关闭自动发现,测试/隔离用) - **导出/导入含 blob 库**:ZIP 备份迁移后 restore 不缺内容 - 快照 manifest 记录插件名/版本/跳过项;`undo_list` 显示插件文件数;恢复报告列出未恢复项(missing) ### 修复 - 旧快照(无 plugins 字段)在 PowerShell 离线工具下被 `@($null)` 单元素数组污染状态与 diff(过滤空值) - 离线 CLI diff 分支改用统一实现(Get-UndoDiffText),支持插件文件 - ps1 文件统一 UTF-8 BOM,PowerShell 5.1 正确解析中文注释 ## [0.1.1] - 2026-08-15 ### 新增 - **回滚事件日志**:每次 undo / redo / restore 成功后追加一条 JSON 记录(时间、模式、目标快照、被回滚的文件),保留最近 100 条 - **`undo_recent` 工具**:随时查看最近的回滚操作,排查"配置怎么突然变了"——回滚可能发生在其他会话或离线工具里 - **提示词规则 7**:用户对配置状态困惑时,AI 先调 `undo_recent` 确认是否为回滚所致 ## [0.1.0] - 2026-08-14 ### 新增 - **自动快照 + 手动快照分库存储**(`manual` / `auto`):配置每次变更自动存档(1.5 秒防抖),启动生成 baseline;手动快照永不自动清理 - **undo / redo / 恢复到任意版本**:pre-restore 重做点机制,存在更新的真实变更时禁止 redo - **快照管理面板**:逐条 diff 预览、恢复前变更摘要确认、删除、清理、导出 / 导入(ZIP 备份迁移) - **WebUI 撤销/重做/快照按钮 + 全局快捷键**(Ctrl+Alt+Z / Ctrl+Alt+Y,可自定义) - **崩溃自检**:上次 DSH 未正常启动时提示,可一键回滚 - **主动告知**:配置变更后 AI 提示"已自动保存,随时可撤销" - **离线 CLI + GUI v2**:DSH 启动不了也能用(快照/撤销/回退/diff/清理/导出导入/设置/托盘) - **双语 GUI**(系统语言自动检测,`DSH_UNDO_LANG` 可覆盖) - **dsh.bundle 生态安装**:`dsh plugin add github:lire1131/dsh-undo-plugin#master` - 设置项:自动保存开关、防抖、保留数量、自动清理、快照目录(原生文件夹选择器) ### 变更 - 插件由 `dsh-undo` 更名为 **`dsh-undo-savepoint`** - 依赖解析不再硬编码作者路径(基于插件位置解析,回退 `$DSH_ROOT`) - 默认存储/设置基于用户主目录;旧版平铺存储自动迁移到分库结构 ### 修复 - 硬编码作者路径导致其他机器启动失败(issue #1) - undo/redo 被监听器自身写入的自动快照误拦(内容哈希回显检测) - prune 从未真正执行,自动快照无限堆积;保留上限现在真正生效 - 双加载 bug(社区反馈):bundle 安装不再追加手动挂载,并清理历史遗留 - README 安装命令指向错误仓库名 ## [0.0.1] - 2026-08-14 本地原型:配置变更快照 + undo / redo,后并入 0.1.0。