Skip to content

Releases: FuriousKinght/dsh-fk-rollback

v1.5.1 — .bat 固化跟随最新 daily + 安装工具

Choose a tag to compare

@FuriousKinght FuriousKinght released this 26 Oct 04:44

本次更新

插件本体:.bat 固化副本不再「一次固化,永久冻结」

旧行为:手动固化过一次(fixedBy='user')后,启动钩子永久跳过,
.bat 一直还原那份陈旧配置 —— 用户自己都忘了。

新行为:默认跟着当天 daily 走,只有显式 pin=true 才冻结。

  • 新增 pin 字段(唯一决定是否被替换)
  • 新增 replacedFrom 记录(可追溯换掉了哪一份)
  • fix <id> --pin 钉住 / fix --unpin 取消 / fix --show 查看
  • 面板 .bat 卡片显示钉住状态 + 切换按钮
  • 补上 --help 里一直缺失的 fix 命令说明

打包与安装工具(不改插件运行逻辑)

  • 修复包内缺 package.json 导致 pnpm 装不上
  • 修复 node_modules 残留目录导致 Symlink path is the same as the target path
  • 新增 install.mjs:幂等安装/修复助手(自动清理残留、写绝对路径 link、检测 DSH 是否运行)
  • 新增 安装.bat:双击即用(内部 cd /d "%~dp0",避免在错误目录运行)
  • .bat 路径探测不再硬编码盘符,改为多级自动探测

实测

14/14 依赖链接有效
19/19 bundles 可解析
11/11 文件语法通过
CLI 全命令 exit=0

v1.5.1(2026-10-23)

修复:.bat 固化副本不再「一次固化,永久冻结」

用户指出现象:

「22号将 .bat 固化成 B 快照,23号开机自动建了当天启动快照,
这时 .bat 还会用 23号的吗?」

旧行为:不会。 因为只要手动固化过一次(fixedBy='user'),
启动钩子就永久跳过,.bat 一直还原 22 号那份陈旧配置 —— 而用户早忘了。

根因:把「操作过一次」当成「永久意图」,但该意图会随时间失效。

新行为:默认跟着当天 daily 走,只有显式 pin=true 才冻结。

  • 新增 pin 字段(默认 false)
  • 新增 replacedFrom 记录(可追溯「换掉了哪一份」)
  • fix <id> 默认不钉住;fix <id> --pin 才钉住
  • 新增 fix --pin / fix --unpin / fix --show
  • 面板 .bat 卡片显示钉住状态 + 「钉住/取消钉住」按钮

实测 5 个场景全部通过(10 项断言):

① 22号固化B(不pin)→ 23号启动 → ✅ 换成23号daily,并记录 replacedFrom
② 显式 pin B          → 23号启动 → ✅ 保持B,返回 pinned=true
③ --unpin             → 启动      → ✅ 恢复跟随,换成最新daily
④ 同一份daily二次调用             → ✅ 跳过,不重写磁盘
⑤ fix --show                      → ✅ 显示钉住状态

v1.5.1 补记(2026-10-26):打包与安装工具修复

⚠️ 插件本体无任何改动。 以下改动只涉及打包方式与安装工具,
15 个插件文件的运行逻辑与 v1.5.1 完全一致。

修复安装阻断问题(插件本体无改动)

⚠️ 说明:本次改动只涉及「打包方式」与「安装工具」,
插件本体的 15 个文件逻辑与 v1.5.1 完全一致,未做任何功能修改。

① 包内缺 package.json(致命,导致朋友装不上)

根因:npm 的 files 数组按惯例不列 package.json 自己,
      而自研打包脚本只遍历 files 数组 → 漏掉它。
后果:pnpm 不认为这是一个包,装不上。
修复:package.json 无条件打包。

② node_modules 里有残留目录 → Symlink path is the same as the target path

pnpm 源码 symlinkDir():
    if (target === path) throw new Error('Symlink path is the same as the target path')

成因:插件被解压/复制到 node_modules 里(错误位置),
      pnpm 判定为孤儿 → 挪到 .ignored → 重建链接时路径撞自己。
修复:install.mjs 自动识别并清理。

③ 在错误目录运行 → Cannot find module 'C:\install.mjs'

朋友在 C:\ 或 node_modules 里运行 node install.mjs,
当前目录没有那个文件。
修复:新增 安装.bat,双击即用(内部 cd /d "%~dp0" 先切到自身目录)。

④ 脚本在「要被删除的目录」里运行 → EPERM

Windows 不允许删除进程当前工作目录及其祖先。
修复:install.mjs 启动即 chdir 到用户主目录。

⑤ install.mjs 在 DSH 运行时留下半成品状态

DSH 运行时文件被占用,pnpm 装不上依赖,
留下「有声明、无链接」的半成品 → 下次启动报 cannot resolve profile bundle。
修复:先检测 DSH 进程,运行中则阻止(或要求 --config-only)。

新增两个安装工具(不参与插件运行)

install.mjs    命令行安装/修复器(幂等,可反复运行)
安装.bat        双击即用的包装(自动定位 node.exe 与本脚本)

v1.4.0 — 分组折叠 + client loader id 体检

Choose a tag to compare

@FuriousKinght FuriousKinght released this 21 Oct 07:26

本次更新

体检新增:client.js 模块 loader id 一致性检查

对应 2026-10-21 的真实事故:插件改名时 package.json 改了、client.js 的 __ModuleLoader__.load({ id }) 漏改,DSH 判定为两个模块注册同一 factory,抛 duplicate factory registration → 全量启动中止。

修复:分组显示「N 项」但列表为空

跨组翻页与分组冲突 —— 今天 13 项把第 1 页占满,「昨天 2 项」筛出 0 条。改为每组独立「显示更多」。

UI:所有分组都能折叠


v1.4.0(2026-10-21)

体检新增:client.js 的模块 loader id 一致性检查

对应 2026-10-21 的真实事故(OFM 插件改名不彻底):

  • package.json 的 name 改成了 dsh-fk-our-free-model
  • 但 client.js:22 的 __ModuleLoader__.load({ id: 'dsh-our-free-model' }) 漏改
  • DSH 判定为「两个模块注册同一个 factory」
  • 抛 client-modules: duplicate factory registration
  • dsh-client-modules 启动失败 → 全量启动中止,DSH 完全起不来

这类错误的特征是「静态看不出、启动才知道崩」,所以体检必须提前拦。

新增两个检查码:

码 级别 说明
client-loader-id-mismatch fatal client.js 的 id 与包名不一致 —— DSH 会启动失败
client-exports-name-mismatch warn client.js 的 exports.name 与包名风格不一致

修复:cordis.patch.yml 为 [] 时误报 YAML 语法错误

全新 profile 的 patch 可能就是一个空数组 [](或只有注释)。
之前会被判成 bad-yaml,让用户以为配置坏了。已修复。

UI:快照列表所有分组都能折叠

原来只有「更早」和「回滚记录」能折叠,今天/昨天是固定展开的。
现在四组都可以点标题折叠/展开,箭头 ▾ / ▸ 指示状态,
折叠时右侧显示「已折叠」。


修复:分组显示「N 项」但列表为空

用户反馈:「昨天显示有两项,但是不显示」

根因是 v1.4.0 加折叠时暴露的旧设计缺陷 —— 跨组翻页和分组互相冲突:

const primary = [...buckets.today, ...buckets.yesterday]   // 15 项
const pageItems = primary.slice(0, 10)                      // 第1页只取 10 项

今天有 13 项,第 1 页的 10 条全是今天的 → 「昨天」筛出 0 条,
但分组头的数字用的是全量 g.items.length = 2。
于是头显示「昨天 2 项」,下面一条都没有。

翻到第 2 页时反过来:「今天」只剩 3 项,看起来像今天只有 3 个快照。

修复方式:去掉跨组翻页,每组独立「显示更多」

分组本身就是天然的分页(今天 / 昨天 / 更早),不需要再跨组翻。

  • 每组默认显示 10 条,超出时给「显示更多(还有 N 项)」
  • 点一次加 10 条,只影响本组
  • 切换搜索词 / 筛选条件时,所有组的显示条数重置

v1.3.0 — 内置重启 + 回滚记录独立存放

Choose a tag to compare

@FuriousKinght FuriousKinght released this 20 Oct 13:56

本次更新

重启能力已内置,不再需要额外安装任何插件。

发布前的最后一个外部依赖被消除了 —— 装一个插件就完整可用。

同时:回滚前快照改为独立存放(restore-points/),并明确说明是哪次回滚的现场。


v1.3.0(2026-10-20)

重启能力已内置 —— 不再需要额外安装任何插件

发布前的最后一个外部依赖被消除了。

之前的做法是让用户再装一个 dsh-fk-restart-button,否则「立即重启」按钮用不了。
这对发布场景不可接受:装一个插件就该完整可用。

现在把重启逻辑搬进了 lib/restart.mjs + lib/relaunch-helper.cjs:

  • 零第三方依赖(只用 node:child_process / fs / os / path / url / crypto)
  • 不需要额外的 ctx 服务(和本插件一样只要 webServer)
  • Windows 桌面版可真正自动重启;其他环境明确提示手动重启

实现要点(都是实测踩出来的)

  • 用 WMI Win32_Process.Create 创建助手进程 —— 普通 spawn 会被
    taskkill /T 一起杀掉,WMI 创建的进程父级是 WmiPrvSE.exe,不在被杀的那棵树里
  • 必须传 ProcessStartupInformation { ShowWindow: 0 },否则会弹出可见终端窗口
  • 系统程序一律走绝对路径(有的机器 PATH 里没有 System32)
  • 端口从请求头动态发现,不能写死 19387(某些构建绑动态端口)

端点变化

  • GET /restart-helper → 改为探测内置能力,返回 builtin: true 与不可用原因
  • POST /restart → 直接执行内置重启,不再转发到外部插件

顺带清理

  • 去掉了转发逻辑里的超时/重试复杂度(内置实现本身是毫秒级返回)
  • 按钮 tooltip 现在显示真实的不可用原因

回滚前快照改为独立存放,并说明是哪次回滚

用户要求:「回滚后会生成一个回滚前的快照,我建议把这一栏单独存放,
并且说明是某某时间段的回滚」

  • 新增 restore-points/ 目录 —— 回滚前快照从 checkpoints/ 独立出来
  • 独立配额:保留最近 10 份,不占用手动快照的 50 个名额
  • 快照名明确写出时间:回滚前 2026-10-20 15:29
  • meta / 索引新增 restoreInfo 字段:
    { "at": 1792491043994, "targetId": "...", "targetName": "装插件前", "reason": "用户指定" }
  • 面板新增「回滚记录(每次回滚前的现场)」分组,默认折叠,排在列表最前
  • 每行副标题显示 · 回滚到「装插件前」前
  • CLI 列表同步显示 ↳ 回滚到「xxx」之前的现场

旧数据(v1.3.0 之前产生的回滚前快照)仍在 checkpoints/ 且没有 restoreInfo,
但 type 仍是 before-restore,所以照样归入「回滚记录」分组 —— 不迁移也能正常显示。


v1.2.0(2026-10-20)

修复:「立即重启 DSH」按钮永远是灰的,点不了

用户反馈:回滚完成后的结果页有「稍后重启 / 现在重启」,但「现在重启」是灰色的。

根因(两处):

  1. 探测写错了 —— /restart-helper 只在 cordis.patch.yml 文本里 grep 插件名,
    但 dsh-fk-restart-button 是通过 profile 的 bundles 注册的,patch 里
    根本没有它的名字 → 探测永远返回 false → 按钮永远渲染成禁用态。
    改为以 bundles / dependencies 为准,patch 只作兜底。

  2. 没有转发端点 —— 原来的前端直接调重启插件的地址,插件没装时静默失败。
    新增 POST /restart:由 Host 端转发到重启插件(新旧两条路由都试),
    统一给出可读错误。前端改调自己的端点。

顺带修掉一个会卡死界面的问题

转发请求原本没有超时。对端不响应时 fetch 会一直挂着,
按钮永远显示「重启中…」,用户只能强杀 DSH。
现在整个重启流程共享 8 秒总预算(不是每步各算),超时立刻中断并给出提示。

实测:最坏耗时从 20.6 秒降到 8.0 秒。

UI 改进

  • 按钮不再因探测失败而变灰 —— 永远可点,由 Host 端返回真实结果
  • 点击后显示「重启中…」,失败时明确告知「可手动关闭 DSH 再打开」
  • /restart-helper 返回 evidence 字段,说明探测依据(bundle / dependency / patch)

v1.1.0(2026-10-20)

新增:固化副本(.bat 的独立数据源)

.bat 是「DSH 完全起不来」时的最后手段,不能依赖会被自动清理的快照池。

  • 新增 fixed/bat-default/ 固化区 —— 不参与快照池的任何自动清理
  • 每次 DSH 启动自动把当天 daily 快照固化过去(fixedBy: auto-daily)
  • .bat 只读固化副本;找不到就明确报错,绝不偷偷回退到快照池
  • 面板可在任意快照上点「设为 .bat」,手动指定固化对象(fixedBy: user,不会被自动覆盖)
  • 新增命令:fix <ID> / fix --show / fix --clear / paths
  • 面板底部显示:快照目录 与 脚本目录

新增:快照来源标记

  • 区分 自动(钩子)/ AI(会话) / 手动(用户)
  • 判据:DSH_SESSION_ID 环境变量存在 → AI;否则 → 用户;钩子显式传 auto
  • 面板标签 + 筛选器 + CLI 列均支持

修复

  • apply() 被 Fiber 重复调用导致路由重复注册(每次启动写 15 条 duplicate route 错误)→ 用 WeakSet 幂等保护
  • 事件被重复订阅 3 次 → 同上
  • pickLastGood 选点偏差:原按「健康等级+最新」,会选中 before-restore 而非当天 daily → 改为 当天 daily 优先,health 为 broken 的排除
  • 时区:toISOString() 在东八区 0–8 点会误判「今天」→ 改用本地 localDateKey()
  • 自动固化被 health 过滤挡住(体检 fatal 时 daily 也不固化)→ 固化不按 health 过滤
  • 卡片展开后文字被按钮挤压成一字一行 → 卡片改纵向,按钮独立成行