# dsh-hub 打包记录(合订本) > 全部版本的打包记录,按时间顺序合订(原逐版本文件已合并于此)。 > 最新版本在最下;每节含版本/产物/SHA256、本版内容、验证与注意事项。 > 逐版细节亦可对照 git tag(`v0.0.2-rc.17`、`v0.1.0`…)与 [关键踩坑记录.md](关键踩坑记录.md)。 | 版本 | 日期 | 要点 | |---|---|---| | rc8 | 2026-08-24 | 全量修复(审查 A-E 五轨)+ 终端自定义 Shell + 用户 bug 修复 | | rc9 | 2026-08-27 | fresh-machine 装配自愈 + 分支策略 | | rc10 | 2026-08-27 | i18n 批量 + 皮肤 Reasonix 系列 + 设置卡官方化 | | rc11 | 2026-08-28 | 右键菜单/皮肤/快捷方式/图标链路 + npm latest 同步 | | rc12 | 2026-08-28 | 插件 output.render 契约崩溃修复(content.some) | | rc13 | 2026-08-28 | permission-guard 只读工具死锁修复 | | rc14 | 2026-08-28 | 权限策略档位(follow/strict/read-only)+ 设置/chip UI | | rc15 | 2026-08-29 | 快捷方式仅安装时创建 + 会话预热 + content-visibility | | rc16 | 2026-08-29 | 桌面快捷方式图标跟随修复 | | rc17 | 2026-08-29 | 壳内 HTML5 拖放恢复 + 用量统计 500/透图修复 | | rc18 | 2026-08-30 | 图标 current.ico 锚点 + Splash 皮肤配色 + 任务栏缓存刷新 | | 0.1.0 | 2026-08-30 | **首个正式版**(npm latest/rc = 0.1.0;tag v0.1.0) | | 0.1.1 | 2026-08-31 | 标题栏会话标签视觉边界(layer-3 抬升面);npm latest/rc = 0.1.1 | | 0.1.2 | 2026-08-31 | 设置页迁移一级页 + 三折叠分组;npm latest/rc = 0.1.2 | | 0.1.3 | 2026-09-01 | 设置卡改官方插件页风格(三独立卡片+描述+gap10px)+ 默认折叠;npm latest/rc = 0.1.3 | | 0.1.4 | 2026-09-01 | 三轮质量审查 P0/P1/P2 全量修复 + 激活标签对比 v5 + CI/hooks/性能;npm latest/rc = 0.1.4 | --- ## 打包记录 rc.8(2026-08-24) ## 版本与产物 - 版本:0.0.2-rc.8(package.json / tauri.conf.json / package-lock 三处一致;Cargo.toml 恒 0.0.0) - 产物:`build/0.0.2-rc.8/DeepSeek Harness Hub_0.0.2-rc.8_x64-setup.exe` - 大小:10.4 MB(较 rc.7 7.1MB +3.3MB——node-pty resources 随包) - SHA256:`e627b28440686d86fddd3f0370095675c7030bd9dbfd8ab6b2064cb2adc5f875`(三次打包——含右键菜单 + killPty 修复) ## 本版新增(相对 rc.7,M1-M5 落地 + 隔离测试修复) - 会话标签栏(C41:状态点/右键/拖拽/重命名/脉冲/归档移除 + F1-F8 修复) - 交互终端(node-pty PowerShell + xterm dock + Ctrl+J + 危险命令拦截 + taskkill 无孤儿) - rail 数据源修复(时间窗真实 kind——修 #35 turn-tail 死代码) - notify focus-session(toast 点击跳会话) - S0 安全(Origin 白名单 + 进程级 token + 错误脱敏) - 工作区(dialog:allow-open + workspace/open) - 右侧栏工作区右键菜单 + 工作区打开入口(PR39/40 最后未落地功能) - killPty pid=0 守卫修复(快速连续 close 残留——taskkill /PID 0 无效 → fallback pty.kill(),隔离复测 4/4→0) - 4 插件装配修复(dsh.bundle/patch 格式/name scoped/Config schema——隔离启动暴露) ## 打包过程(BUILD.md 一键) - 工具链:Node 24.19 / npm 11.17 / cargo 1.97.1 / rustup msvc / MSVC vcvars64 ✓ - 前置构建:tsc + tsdown(xterm 已 bundle 916KB)✓ - 完整性预检:12 文件 + 3 目录 + 17 通配非空 ✓ - lib 零漂移 ✓ - Tauri release 编译 1m21s + NSIS 打包 ✓ ## 隔离测试(两轮,3080 未碰) - 终端工作流:create/write/stream(真实回显)/resize/多标签/拦截/close 无孤儿 ✓ - 配置持久化/pins 读写/安全回归(401/403/403)/静态资源/插件树 ✓ ## 下一步 - 真机安装 BUILD.md §5.2 验证清单(首启 → dsh UI → 标签栏/终端/Ctrl+J/托盘) - 不发布 npm(仅打包分发) --- # 打包记录 rc.8 —— 第四次打包(2026-08-25,全量修复版) ## 版本与产物 - 版本:0.0.2-rc.8(package.json / tauri.conf.json 双端一致,未 bump——rc.8 未发布 npm) - 产物:`build/0.0.2-rc.8/DeepSeek Harness Hub_0.0.2-rc.8_x64-setup.exe` - 大小:10.5 MB(node-pty resources 随包) - SHA256:`a3fabdbfc45c8de548fb5a5ff8e8c6298bfb476ed13b25e71989301ae30b3b01` ## 本版内容(相对第三次打包 e627b284,四轮审查全量修复 + E 轨根因修复) - 审查 A-E 五轨全部落地:多实例门禁 fail-closed(P0)、workspace/open 限工作区根、config 单点化、 PTY 配额、管道协议类型面、插件 npm 轨 files 补 patch、verify-plugin / verify-tauri-release(P1-P9) / verify-protocol 三新门禁、client 灰度→token、文档 rc.7→rc.8 同步 - **E 轨根因修复(rc.8 初始化卡死)**:`assemble-profile.mjs` 新增 `scrubLegacyPatch`—— 旧 profile 的 cordis.patch.yml 残留 legacy `id: dsh-hub`(裸名)loader 行与包 patch 构成 duplicate loader entry → dsh web 启动即崩卡初始化;现装配时自动清除(保留用户自定义 patch)。 隔离环境端到端验证通过(污染 profile 首启正常进 dsh UI)。踩坑记录 #75。 - AGENTS.md 铁律 8 数据安全红线(防 home 目录误删)+ 8 处文档漂移修复 ## 打包过程 - 工具链:Node 24.19 / npm 12.0.2 / cargo 1.97.1 MSVC(vcvars64:D:\Tools\Microsoft Visual Studio\18\Community)/ NSIS(D:\Tools\NSIS,PATH 注入) - 完整性预检 ✓ / host 依赖守卫 ✓ / lib 零漂移 ✓ / verify-release ALL PASS(P1-P4) - Tauri release 编译 59.85s + NSIS 打包 ✓ ## 真机冒烟(BUILD.md §5.2 清单) - 首启 → 占位页 → READY → 自动进 dsh UI(不弹浏览器)✓(隔离环境已验证) - 含 legacy 污染 profile 的旧机器升级 → 自动 scrub → 正常首启(E 轨验证项) - 标签栏/终端/Ctrl+J/托盘/通知跳会话:待真机确认 --- # 打包记录 rc.8 —— 第五次打包(2026-08-25 晚,4 用户 bug + 终端布局修复) ## 版本与产物 - 版本:0.0.2-rc.8(未 bump) - 产物:`build/0.0.2-rc.8/DeepSeek Harness Hub_0.0.2-rc.8_x64-setup.exe`(10.5 MB) - SHA256:`a045d6ff6892f8edbf1e41861b3dadc109ec6ddd53d411bbb594d16028f5c3e1` ## 本版新增(相对第四次 a3fabdbf) - **Bug1 终端无响应**:空 cwd → 宿主回退 homedir,任意入口打开终端都有可用 PowerShell(真实 UI 复现+验证:空 cwd 200 + C:\Users\MarecGents) - **Bug2 右键路径引用白字**:严格限定 [data-composer-seat] textarea + 原型 setter + InputEvent(React 受控 textarea 同路径同步) - **Bug3 任务栏图标延迟**:apply_all 重排 shell 面(AUMID IconUri)先行 + 定向 SHCNE_UPDATEITEM 快路径 - **Bug4 会话页过短**:固定 180px + flex-shrink 压缩(minWidth 60)+ 溢出隐藏(浏览器式) - **Bug5 终端盖住 composer/最后一行**:dsh composerSeat 为 sticky bottom:0,padding 抬不动 → 改对 [data-conversation-scroll] 加 margin-bottom 缩滚动视口(实测会话列高 768→519,恰好在 dock 顶部上方结束) ## 门禁 tsc / build:client / cargo check / clippy 零告警;verify-release P1/P2/P4 PASS;隔离环境 UI 冒烟通过(终端创建+提示符+xterm 输入框聚焦+dock 几何正确) --- # 打包记录 rc.8 —— 第六次打包(2026-08-25 深夜,终端实时输出断链修复) ## 版本与产物 - 版本:0.0.2-rc.8(未 bump) - 产物:`build/0.0.2-rc.8/DeepSeek Harness Hub_0.0.2-rc.8_x64-setup.exe`(10.5 MB) - SHA256:`b60c6030922cdfaae23e6bd5e4e614f3be69c1c0944fb554ff00783e59eecb46` ## 本版新增(相对第五次 a045d6ff) - **Bug1 终端无提示符/无法输入的真正 client 根因**:pty-store `appendOutput` 只更新 store 状态、从不调用 dataSubs(xterm 写入订阅)→ xterm 永远拿不到实时输出(SSE/宿主均正常,纯 client 分发断链)。修复:appendOutput fan-out 到 dataSubs。**CDP 端到端验证通过**:xterm 屏幕真实显示 `PS E:\Workdata\DeepSeekHarness>` 提示符 + `Write-Output` 输入回显 + 命令输出。 - **BugA 打开工作区文件夹双动作**:原实现先弹目录选择器+添加工作区,取消/异常后才打开 Explorer;改为直接打开当前工作区目录(openCurrentWorkspaceFolder)。 - **BugB2 终端最大化后无法还原**:100vh dock 盖住 42px 标题栏导致按钮不可点;修复 dock top=42px、height=calc(100vh-42px)。 ## 门禁 tsc / build:client 零 error;cargo 未改动;CDP 端到端终端验证 PASS。 --- # 打包记录 rc.8 —— 第七次打包(2026-08-26,打开工作区文件夹修复) ## 版本与产物 - 版本:0.0.2-rc.8(未 bump) - 产物:`build/0.0.2-rc.8/DeepSeek Harness Hub_0.0.2-rc.8_x64-setup.exe`(10.5 MB) - SHA256:`d17af1f02c64a31c112c086d67b10ef8d623e8c7bc9ede37cd7141bb4eddf0a9` ## 本版新增(相对第六次 b60c6030) - **打开工作区文件夹彻底失效修复**(双根因): ① 按钮改用侧栏三级解析的 `effectivePath`(原只读 `__mgGetCurrentWorkspace()`,可能 null → no-op); ② open 路由放行「任意目录」(open/xdg-open/explorer 打开目录仅为文件管理器、无执行; 工作区外**文件**仍 403——任意文件执行的安全边界保留),消除宿主未跟踪会话 cwd 时的静默 403。 - 验证:无 activeCwd 时 POST open 目录 → HTTP 200。 ## 门禁 tsc / build:client 零 error;cargo 未改动;路由级验证 PASS。 --- # 打包记录 rc.8 —— 第八次打包(2026-08-26,终端自定义 Shell) ## 版本与产物 - 版本:0.0.2-rc.8(未 bump) - 产物:`build/0.0.2-rc.8/DeepSeek Harness Hub_0.0.2-rc.8_x64-setup.exe`(10.5 MB) - SHA256:`06aafc728cf778104fd000fa81704cc9a73b2874a615e8e731da735952a65a25` ## 本版新增(相对第七次 d17af1f0) - **终端自定义 Shell**:bash / cmd / PowerShell 5.1 / pwsh 可选。 - 探测:`detectShells()`(系统 PS5/cmd 固定路径 + pwsh/bash 走 PATH where/which), **未安装的不列出**(本机 pwsh 未装 → unavailable,不出现); - 创建:`createPty(shell)` 白名单映射(PS `Set-Location`、cmd `/K cd /d`、bash 继承 cwd), 未安装 shell 创建 → 400 shell-unavailable; - client:设置面板 Shell 选择器(仅列可用项)+ 默认 shell 持久化(terminal-prefs)+ 状态栏显示实际 shell + ptyRetarget 按 shell 语法发 cd。 - 验证:探测列表正确(ps5/cmd/bash 可用、pwsh unavailable);三 shell 创建 200 各自启动;pwsh 创建 400。 ## 门禁 tsc / build:client 零 error;cargo 未改动;端到端验证 PASS。 --- # 打包记录 rc.8 —— 第九次打包(2026-08-26,会话标签页样式) ## 版本与产物 - 版本:0.0.2-rc.8(未 bump) - 产物:`build/0.0.2-rc.8/DeepSeek Harness Hub_0.0.2-rc.8_x64-setup.exe`(10.5 MB) - SHA256:`f626a6a9e9126c2328600cb7bad6fb8af7b656c1ac086e258b2192347daf0a7e` ## 本版新增(相对第八次 06aafc72) - 会话标签页样式:文字居中、关闭 × 贴标签最右、字号 12→13(大一号) - 实现:标题 span flex:1 + textAlign center(居中并推动 × 到右缘);TAB fontSize 13 ## 门禁 tsc / build:client 零 error;cargo 未改动;编译产物验证(fontSize 13 / textAlign center / 180px)通过。 --- # 打包记录 rc.8 —— 第十次打包(2026-08-26,pwsh 探测修复) ## 版本与产物 - 版本:0.0.2-rc.8(未 bump) - 产物:`build/0.0.2-rc.8/DeepSeek Harness Hub_0.0.2-rc.8_x64-setup.exe`(10.5 MB) - SHA256:`4e0ab8c4305cfb0c6096394e910b0cee6ec9d0d128203ca9b2cd9032361f20e0` ## 本版新增(相对第九次 f626a6a9) - **pwsh 探测漏检修复**:pwsh 装在自定义目录(D:\Tools\PowerShell\7)且仅机器 PATH 可见时 识别不到——探测改为扫「进程 PATH + 机器 PATH(注册表 Session Manager\Environment)」, %SystemRoot% 展开。验证:pwsh 7.6.5 available=true + 创建 200。 ## 门禁 tsc 零 error;cargo 未改动;端到端验证 PASS(4 shell 全探测 + pwsh 创建成功)。 --- # 打包记录 rc.8 —— 第十一次打包(2026-08-27,5 个 UI/功能修复) ## 版本与产物 - 版本:0.0.2-rc.8(未 bump) - 产物:`build/0.0.2-rc.8/DeepSeek Harness Hub_0.0.2-rc.8_x64-setup.exe`(10.5 MB) - SHA256:`753b0fbd28c6647477b4b0e40b27e19815316cd6909ff2f85609a8df48a68691` ## 本版新增(相对第十次 4e0ab8c4) - **标签页高度**:标签撑满 42px 标题栏,下边贴标题栏下边界 - **默认浏览器右键菜单禁用**:替换为自定义仅「刷新」菜单(返回/另存为移除,刷新保留) - **文件树「打开」对文件生效**:open 路由 Windows 放行任意已存在路径(explorer 不执行文件;macOS/Linux 件仍限工作区内) - **右键菜单不透明**:背景注入透明规则排除 .mg-rs-menu - **轨迹页透明**:背景规则补 [data-conversation-composer-overlay] 75%(与对话页一致 25% 透出) ## 门禁 tsc / build:client 零 error;verify-release ALL PASS;cargo 未改动。 --- ## 打包记录 rc.9(2026-08-27) ## 版本与产物 - 版本:**0.0.2-rc.9**(package.json / package-lock.json / tauri.conf.json 三处一致;Cargo.toml 恒 0.0.0) - 产物:`build/0.0.2-rc.9/DeepSeek Harness Hub_0.0.2-rc.9_x64-setup.exe` - 大小:10.4 MB(较 rc.8 的 10.5MB 略小——release profile 优化生效) - SHA256:`2817484eb09387521e8e23e3e575a64f805029af0bcbc7317d33cc5230cc6dbc` ## 本版内容(相对 rc.8 第十一次打包 753b0fbd) ### rust-skills 三轮审查全量修复(commit 93885d1) - **约束文档**:src-tauri/src/AGENTS.md 新增红线 15-20(unsafe SAFETY / 纯函数单测 / release profile / 禁静默吞错 / COM 匹配 / 英文注释);根 AGENTS.md §4.7;PROCESS_QUALITY 迁移门禁升级 - **P0**:release profile(lto=thin + codegen-units=1 + strip=symbols,exe 13.3MB→12.5MB);全部 unsafe 补 `// SAFETY:` - **P1**:18 个单元测试(parse_dsh_ready_port 当场修复真实 off-by-one、BGRA/AND 掩码、normalize_path、多实例 fail-closed 判定表);`.github/workflows/rust.yml` CI;关键路径补 warn - **P2**:winutil.rs(wide() 单实现 + ComInit RAII)、quit_and_exit 统一退出、node.rs spawn 去重(~70 行)、移除死代码 os_theme.rs ### 门禁 - `cargo fmt` / `clippy --all-targets -D warnings` 零告警;`cargo test --lib` 18/18 通过;`cargo build --release` 成功 - verify-release P1-P4 ALL PASS(rc.9 版本一致) ## 实机验证要点(BUILD.md §5 清单) 1. 首启 → 占位页 → 自动进 dsh UI(不弹浏览器) 2. 终端:自定义 Shell(PS5/pwsh/cmd/Bash)创建、输入回显、提示符正常 3. 标签栏:固定 180px、居中、×贴右、多标签压缩 4. 右键:空白处仅「刷新」菜单;文件树右键菜单不透明、文件「打开」用默认应用 5. 轨迹页背景 25% 透出;工作区文件夹直接打开 --- ## 第二次打包(2026-08-27 晚,3 个用户 bug 修复) - 产物:`build/0.0.2-rc.9/DeepSeek Harness Hub_0.0.2-rc.9_x64-setup.exe`(10.4 MB) - SHA256:`41446d09066705bd5fee2d0cf2e4373efbd71ff9eac53c7c99c3f9d3b0645ad1` - 修复(commit 3482f8c): 1. **终端输入对比度**:xterm 补 16 色 ANSI 调色板(VS Code 浅/深双套)——PowerShell 彩 token 输入在浅色模式不再白/黄不可读 2. **rail 对话定位条**:hover 黑框(tooltip 文字改固定浅色,适配全皮肤恒深色底色)+ 点击失效(findScrollContainer 只在实际滚动时优先 data-conversation-scroll,否则取真实滚动容器) 3. **文件树右键「在资源管理器中打开」**:文件夹打开自身、文件 explorer /select 定位(宿主 open 路由新增 reveal;macOS -R / Linux 父目录兜底);验证 HTTP 200 --- ## 第三次打包(2026-08-27 深夜,3 个回归 bug 修复) - 产物:`build/0.0.2-rc.9/DeepSeek Harness Hub_0.0.2-rc.9_x64-setup.exe`(10.4 MB) - SHA256:`d02bc3170cd25038fb0a84b44218267bcf201fe37001ae34cb61cbe0386b863b` - 修复(commit b6ee886): 1. **在资源管理器中打开落到「文档」**:explorer `/select` 需单参且路径带引号(`/select,""`)——无引号歧义落到文档库 2. **rail 点击/当前轮次高亮失效**:scrollContainer 惰性重解——boot 时内容未溢出得到 null 后永不再试;改 ensureScrollContainer 在点击/滚动时刻按需重解(此时内容必已溢出) 3. **终端设置不保存**:根因 = dsh web `--port 0` 每次随机端口 → web origin(含端口)变化 → localStorage 每次启动清空。改**宿主持久化**:`$DSH_HOME/dsh-hub/terminal-prefs.json`(GET/POST `/api/dsh-hub/pty/prefs`,字段 sanitize),client 装配 syncHostPrefs + 每次 save POST;验证 POST→GET 一致、文件落地 --- ## 第四次打包(2026-08-27,Bug1 深审根因修复) - 产物:`build/0.0.2-rc.9/DeepSeek Harness Hub_0.0.2-rc.9_x64-setup.exe`(10.4 MB) - SHA256:`b5f9459c0fcc65889535573c9ce8f376b830ae3217059074d5ec9b2893751ea2` - **深审修正(commit 6caf346)**:第三次打包的「引号修复」不彻底——三路并行审查(客户端链路/宿主 spawn 实证/explorer 形态矩阵)锁定真根因: - Node `spawn` 未设 `windowsVerbatimArguments` 时会把内嵌引号转义成 `\"`,explorer 实际收到 `"/select,\"E:\...\""`;explorer 解析自身原始命令行(不走 CommandLineToArgvW)不认识 `\"` → 回落「文档」(对无空格路径同样失败)。 - 修复:`windowsVerbatimArguments: reveal` 让 `/select,""` **原样送达** explorer(B 窗口级 4/4、C 含空格/逗号/中文路径 n05/x04/x10 全部选中);openInOs 补 `[dsh-hub] workspace open` 日志(platform/reveal/args + spawn 错误)消除故障不可见。 --- ## 第五次打包(2026-08-27,卸载残留根因修复 —— 测试机「卡在启动中」+ `dsh web` 独立启动失败) - 产物:`build/0.0.2-rc.9/DeepSeek Harness Hub_0.0.2-rc.9_x64-setup.exe`(10.4 MB) - SHA256:`e218bcaf22d5600da703c28d4bc57f70a7289b183ebaf7e00827b13123343112` - 修复(commit a9596c9) ### 诊断结论(测试机两份故障同源) 1. **卸载残留的插件配置**:旧 NSI 卸载兜底只从 bundles 移除 `@marecgents/dsh-hub`,`@dsh-external/*`(4 个插件)的 bundle 注册与 junction 全部残留(`.dsh` 不被删是设计如此,但 dsh-hub 相关条目清不净)。 2. **残留 → 崩溃链**:dsh 的 `resolveBundleDir` 对无法解析的 bundle 直接抛错(`cannot resolve profile bundle …`)→ 卸载后裸 `dsh web` 实例化失败(「dsh web 无法单独开启」);残留 junction 指向已随卸载删除的安装目录(悬空)→ 新装 dsh-hub 在启动中间态反复报错/无法完成 Init(「一直卡在启动中」)。本机正常是因从未卸载过旧的带插件安装。 3. **dsh 源码调研结论**:dsh CLI **没有**面向 junction 型 bundle 的卸载命令(`dsh plugin remove` 只管 pnpm 管理的依赖;`profile.ts` 无 remove API)。因此卸载清理只能由安装器侧实现。 ### 修复(两层,均只清 dsh-hub 自有条目、绝不删 `.dsh`) - **`scripts/uninstall-cleanup.ps1`(新,随包安装到 `_up_\scripts\`)**:遍历 `$DSH_HOME/profiles/*`,从 `dsh.profile.bundles` 过滤 hub + `@dsh-external/*`;删除 hub 与 4 插件的 junction(只删链接点,不递归目标,悬空链接同样可删);删空 `@dsh-external` 目录;JSON 无 BOM 回写(PS5.1 `Set-Content -Encoding UTF8` 的 BOM 会破坏 dsh 的 `JSON.parse` → 引入已知崩溃,明确规避)。CRLF 行尾(PS5.1 对 LF-only 脚本解析 bug)。 - **NSI hooks**:`PREUNINSTALL` 在删除 `_up_` **之前**执行 packaged ps1(保证脚本文件此刻仍存在);`POSTUNINSTALL` 兜底单行(兼容旧安装无此脚本)扩展为同样的全清理 + 无 BOM,两路等价。 ### 验证 - 隔离 DSH_HOME 沙箱复现残留态(bundles 含 hub+4 插件 + 5 条真实 junction)→ 清理后 bundles 仅剩无关保留项、5 条链接全部消失、JSON 无 BOM → 此前已确认 `dsh web` 恢复正常启动、重新安装可完整 Init 还原 hub+插件。 - PS5.1 真实执行:packaged ps1 与 NSI 兜底一行各跑一份沙箱,exit 0、断言全过(含「无关 package 保留」)。 - 门禁:`npm run build`(tsc)零错误;makensis 编译 hook 通过;lib/ 零漂移;host 依赖守卫通过;产物复制 SHA256 校验一致。 --- ## 打包记录 rc.10(2026-08-27) ## 版本与产物 - 版本:**0.0.2-rc.10**(package.json / package-lock.json / tauri.conf.json 三处一致;Cargo.toml 恒 0.0.0) - 分支:dev-v2(未推送,全部提交留在本地;用户指示「不说推送不推」) - 产物:`build/0.0.2-rc.10/DeepSeek Harness Hub_0.0.2-rc.10_x64-setup.exe` - 大小:10.5 MB - SHA256:`e761d3f969c57e83c69d618f465a3be22ac2a85c01c36a8907246d37fced43f9` ## 本版内容(相对 rc.9 第五次打包 e218bcaf,dev-v2 上 17 个提交) ### UI 美化(皮肤册 15 套 + 通道 C/D + 微交互) - **皮肤移植**:Reasonix 官方 8 套(rx-*:黑金/绯红地平线/青蓝舞台/熔炉金红/玫瑰晨光/鼠尾草微风/火花笔记/紫罗兰星光)+ opencode 2 套(oc-*:经典/石墨)——统一推导规则生成器产出(直映射+混合+dimmed 夹取 ≥3.5:1),对比度脚本实测(全局最小 ≥4.98:1),每套独立 `docs/skins/*.md`;册子 15 套(+内置 5) - **红线执行**:撤销自造网格布局,设置卡皮肤选择器回退官方 Setting-Cell + Menu(菜单项/pill 带皮肤浅|深色块预览);皮肤切换 150ms 全局色过渡(P6) - **通道 C/D**:会话标签激活 2px 品牌指示条(随皮肤)、启动页浅色变体(`prefers-color-scheme`,壳表面早于 dsh UI 无法读 token) ### 全量 i18n(zh/en,跟随 dsh 设置语言) - `src/client/locale.ts`:zh/en flat 词典(~120 键)+ `t()` 插值 + `` 订阅(官方 locale 插件写入,dsh 设置→General→Language)+ `useLocaleLang` - 覆盖:设置卡全部文案、会话/工作区菜单、皮肤名与描述(15 套双语)、空白右键菜单等 - **usage-stats 插件**:provider 名与全部文案双语(SenseNova/Moonshot/Zhipu GLM/Baidu Qianfan/Alibaba Bailian 等),独立加载插件同样跟随 dsh 语言 ### 右键菜单语义(Bug3 根因级修复) - WebView2 原生右键菜单 Rust 侧禁用(`SetAreDefaultContextMenusEnabled(false)`,日志成功锚点);DOM 单一刷新源 - 对象行(会话/工作区)→ 各自专属菜单(工作区行新增:新建任务/打开工作区;会话行全功能菜单,preventDefault + stopPropagation 双保险) - 豁免最小集:对象行 treeitem + 文本编辑要素;**其余空白(含左栏空态)均可右键刷新** - 临时 ctx-trace 探针(Host→Rust 日志取证通道)已移除 ### 稳定性修复 - **usage-stats 装载期崩溃**:i18n 改写时 zhDict 误生成 `t(...)` 调用 → 模块顶层 TDZ(`Cannot access 't' before initialization`)→ 词典重建为纯字符串,loader 装载模拟验证通过 - **标题栏启动图标空白**:`apply_titlebar_face` 去重缓存让启动早期失败永久化(异 id 永不再注入)→ 移除去重 + tb-icon `onerror` 品牌圆点兜底 ## 门禁 - `node scripts/verify-release.mjs` **ALL PASS**(含 rc.10 新机装配冒烟) - npm `build`(tsc)/ `build:client`(tsdown)零错误;lib 零漂移 - Rust:fmt / clippy `-D warnings` 零告警、`cargo test --lib` 18/18(uninstall 清理、ctx 禁用链等) - NSIS makensis 编译通过(installer-hooks.nsi 含卸载清理钩子) ## 实机验证要点(BUILD.md §5 清单 + 本版重点) 1. 皮肤:设置→界面皮肤 15 套切换(浅/深)+ 语言切换(General→Language)皮肤名/描述随语言 2. 右键:对象行→专属菜单;空白(含左栏)→刷新;输入框→无菜单 3. 标题栏启动图标立现(不再空白) 4. 卸载后再装/裸 `dsh web` 正常(uninstall-cleanup 保留) 5. 终端/rail/标签栏回归 ## 待办 - 推送 dev-v2 → 合并 main → npm 发布(latest/rc → 0.0.2-rc.10)→ GitHub Release(按用户指示逐项执行) --- ## 打包记录 rc.11(2026-08-28) ## 版本与产物 - 版本:**0.0.2-rc.11**(package.json / package-lock.json / tauri.conf.json 三处一致) - 产物:`build/0.0.2-rc.11/DeepSeek Harness Hub_0.0.2-rc.11_x64-setup.exe`(10.5 MB) - SHA256:`3d09ba1a6a40590fbc87e96e8a2223aa838803cf332f5cff9cb748a61f488975` - npm:`@marecgents/dsh-hub@0.0.2-rc.11`(tag `rc`;`latest` 保持 `0.0.2-rc.9`——rc 流程,未设 latest) ## 本版内容(dev-v2 全量工作;相对上一 npm 发布 rc.9) ### UI / 皮肤(15 套) - 皮肤册 15 套:内置 5 + Reasonix 官方 8(rx-*)+ opencode 2(oc-*),统一推导规则生成器产出(直映射+混合+dimmed 夹取 ≥3.5:1,对比度实测 ≥4.98:1),每套浅/深 × 33 token + `docs/skins/*.md` - 设置卡皮肤选择器:官方 Setting-Cell + Menu(菜单项/pill 带皮肤浅|深色块预览);皮肤切换 150ms 全局色过渡 - 通道 C/D:会话标签 2px 品牌指示条、启动页浅色变体 ### i18n(全量双语,跟随 dsh 设置语言) - `src/client/locale.ts`(zh/en 词典 + `` 订阅 + t());设置卡/会话与工作区菜单/皮肤名/空白右键全部词典化 - usage-stats 插件:provider 名与文案双语(SenseNova/Moonshot/Zhipu GLM/Baidu Qianfan/Alibaba Bailian…),独立加载同样跟随 dsh 语言 - 修复:i18n 改写引发的 usage-stats 装载期 TDZ(词典误生成函数调用)——词典纯数据 + loader 装载模拟验证 ### 右键菜单语义(根因级) - WebView2 原生右键菜单 Rust 层禁用(`SetAreDefaultContextMenusEnabled(false)`) - DOM 全量接管:对象行(会话/工作区)→ 各自专属菜单(工作区:新建任务/打开工作区);空白处(含左栏空态)→ 刷新菜单;输入框等文本编辑要素不干预;单一刷新源(无重复注册) ### 稳定性 / 体验修复 - 标题栏启动图标时序竞态(titlebar 去重 → 早期失败永久化)——移除去重 + img 兜底 - 会话右键「重命名任务」:官方 ⋯ 弹层本环境不可用(实测)→ 菜单内嵌改名表单 + 官方 `session.rename` 同源(数据联动左右栏/标签),五轮审查 + 全流程事件模拟后落地 ### 工程 / 文档 - 发布门禁:verify-release ALL PASS(rc.11 新机装配冒烟);tsc / client / Rust(fmt/clippy/test 18/18) 全绿;lib 零漂移 - 新增 `BUG_FIX_SOP.md`(缺陷修复标准作业程序);AGENTS 铁律 9 / PROCESS_QUALITY / REFERENCE / FUNCTIONS / BUILD 同步沉淀(à docs 提交) ## 真机验证要点 1. 皮肤 15 套切换(浅/深)+ 语言切换(General→Language)全量双语 2. 右键三态:对象行→对象菜单;空白(含左栏)→刷新;输入框→无菜单 3. 会话行右键「重命名任务」→ 内嵌表单改名→树与标签联动 4. 标题栏图标启动立现 5. 卸载重装/裸 `dsh web` 正常(uninstall-cleanup 保留) --- ## 打包记录 rc.12(2026-08-28) ## 版本与产物 - 版本:**0.0.2-rc.12**(package.json / package-lock.json / tauri.conf.json 三处一致) - 产物:`build/0.0.2-rc.12/DeepSeek Harness Hub_0.0.2-rc.12_x64-setup.exe`(10.5 MB) - SHA256:`5ab97b9b28be3a44a855e48e4d7300b405f57209573469ee4f0dcd6603258d2f` - npm:`@marecgents/dsh-hub@0.0.2-rc.12`(tag `rc` + `latest` 均已指向 rc.12,registry 直查确认) - git:main = dev-v2 = `939589b`;tag `v0.0.2-rc.12` 已推送;dev-v2 已 ff 回灌 main ## 本版内容(相对 rc.11:插件工具输出契约 bug 修复) ### 根因(真实事故:两个论文会话「本轮运行失败 content.some is not a function」) `dsh-permission-guard`(`permission_status` / `permission_reload`)与 `dsh-findings-ledger`(`findings_baseline` / `findings_record` / `findings_report`)的 `output.render` 返回**字符串**而非官方契约要求的 `ContentBlock[]` 数组 → 字符串写入会话日志的 tool-result block → 下一轮 LLM 请求重建时 provider adapter 的图片检查 `contentHasImage()` 递归进入该块对字符串调 `.some()` → 整轮 error(code UNKNOWN)。 ### 修复 - 5 处 render 全部改为返回 `[{ type: 'text', text: … }]` 数组(permission-guard 2 + findings-ledger 3) - 核查其余插件:`dsh-project-memory` 已是数组写法;`dsh-usage-stats` 无工具注册;host half(src/)无工具定义——无同类残留 - 防御方向(建议 dsh 官方):`snapshotProjection` 对 render 结果做数组校验,隔离畸形插件而非毒化会话(已记入踩坑记录 #86) ### 工程 / 文档 - 发布门禁:verify-release **ALL PASS**(P1–P4,含全新环境装配冒烟) - 踩坑记录追加 **#86**(现象/根因链/正确做法/教训,含 zstd 解码黄金路径) - README / FUNCTIONS.md 版本与说明同步 ## 注意事项 - 已损坏会话(历史 tool-result block 为字符串)无法自愈,需新开会话;插件修复后新会话不再受影响 - 安装前建议手动清理 ~/.dsh 下 dsh-hub 插件注册信息与代码包(见交付说明清理清单),再安装 rc.12 --- ## 打包记录 rc.13(2026-08-28) ## 版本与产物 - 版本:**0.0.2-rc.13**(package.json / package-lock.json / tauri.conf.json 三处一致) - 产物:`build/0.0.2-rc.13/DeepSeek Harness Hub_0.0.2-rc.13_x64-setup.exe`(10.5 MB) - SHA256:`7403b88f99f9fd4d9624d75861bf869b8f6e0bb96d7dae57cbbd0c64a2f9fa00` - npm:`@marecgents/dsh-hub@0.0.2-rc.13`(tag `rc` + `latest` 均已指向 rc.13) - git:main = dev-v2(merge 后);tag `v0.0.2-rc.13` ## 本版内容(相对 rc.12:permission-guard 只读工具死锁修复) ### 根因(真实事故:两个论文会话最新轮次全部卡死) `dsh-permission-guard` 的默认白名单把**只读/无副作用工具**也放进 confirm 层:`permission_reload`(重新读取配置,让新放行条目生效的机制)被 confirm 拦截 → 配置更新永远无法生效;`ask_user_question`(confirm 机制本身的人工确认通道)被拦 → 模型连「征求用户确认」都做不到。模型写文件被拦(write 默认 confirm,预期)后尝试 reload 解锁 → 连环死锁,只能总结「全部被拦截」后结束(踩坑 #89)。 ### 修复 - `DEFAULT_CONFIG.tiers.auto` 增加 `permission_reload`、`ask_user_question`(附注释:只读无副作用工具永不 confirm) - GUIDANCE 更新:reload 为只读 auto 放行;用户改配置后先 reload 再重试被拦截操作 - 守卫模拟验证:新装默认 reload/ask_user_question=auto、write=confirm(预期);**注意合并语义**——用户已有 `tiers.auto` 时整体覆盖默认,存量用户需手动补条目或删配置重建(已在报告与 #89 说明) ### 工程 / 文档 - 发布门禁:verify-release **ALL PASS**(P1–P4,含全新环境装配冒烟) - 踩坑记录 #89(只读工具死锁 + 配置覆盖语义) - README 版本同步 rc.13 ## 注意事项 - 已安装 rc.12 的用户:本版插件默认修复仅对「无 tiers.auto 配置」或删配置重建生效;现有 `~/.dsh/permission-guard.json` 需手动在 auto 补 `permission_reload`、`ask_user_question`(如需模型自动写文件再加 `write`,属用户权限决策) --- ## 打包记录 rc.14(2026-08-28) ## 版本与产物 - 版本:**0.0.2-rc.14**(package.json / package-lock.json / tauri.conf.json 三处一致) - 产物:`build/0.0.2-rc.14/DeepSeek Harness Hub_0.0.2-rc.14_x64-setup.exe` - npm:`@marecgents/dsh-hub@0.0.2-rc.14`(tag `rc` + `latest` 同步) - git:main = dev-v2(merge 后);tag `v0.0.2-rc.14` ## 本版内容(相对 rc.13:permission-guard 联动官方预设 + 权限策略 UI 融合) ### 背景根因(交叉调研,踩坑 #89 续) dsh 官方权限管线 `pre-execute → approval → guards` 中,permission-guard 插件的 guard 挂在最后,只看自己的 `permission-guard.json`、不读会话官方 preset/sandbox/approval——`danger-full-access`(Full Access)与官方确认都过不了插件层(会话实测:Paper1 六次 write 全被拦,含切 Full Access 后)。 ### 插件(dsh-permission-guard) - **策略档位**(`permission-guard.json` 顶层 `policy`,默认 `follow`): - `follow`:跟随会话官方 preset——`danger-full-access`(sandbox=danger-full-access 或 approval=never)→ 除 never 红线外全部放行;`read-only` → 只放行只读;`workspace-write` → 四级白名单 - `strict`:始终按四级白名单拦截,不跟随 preset - `read-only`:无条件只放行只读操作 - **guard 联动**:`exec.agent.session.events` 折叠 sandbox/approval(零依赖);never 红线任何档位都生效 - **webServer route**:`GET/POST /api/dsh-permission-guard/policy`(loopback Host/Origin 校验,参照 hub host-guard) - GUIDANCE / README 同步 ### hub(桌面壳) - **设置卡**:新增「权限策略」section(Menu pill 三档,选中即保存) - **会话左下角**:`conversation.input.left` slot 注册权限策略 chip(官方权限 chip 旁,复刻其 button+Menu 模式,档位色点区分) - i18n zh/en 词典新增键 ### 验证 - guard 决策矩阵模拟 **ALL PASS**(3 档 × preset 场景:follow+Full Access 放行 write、never 红线全档位拦 rm -rf、strict 不跟随、read-only 无条件只读) - tsc + client build 绿;verify-release **ALL PASS**(含全新环境装配冒烟) ## 注意事项 - 装后生效链路:用户用官方权限菜单选 Full Access(或设置卡/左下角 chip 切档位)→ 插件 guard 下次工具调用即按新档位决策(配置 mtime 自动检测,无需重启) - 存量 `~/.dsh/permission-guard.json` 无 `policy` 字段 → 默认 `follow`(不需要手动加) --- ## 打包记录 rc.15(2026-08-29) ## 版本与产物 - 版本:**0.0.2-rc.15**(package.json / package-lock.json / tauri.conf.json 三处一致) - 产物:`build/0.0.2-rc.15/DeepSeek Harness Hub_0.0.2-rc.15_x64-setup.exe`(10.5 MB) - SHA256:`f096f268e3b425e0734ec9be12e04088bcfff9fd0dd55b1d62a800eaa38e74df` - npm:`@marecgents/dsh-hub@0.0.2-rc.15`(tag `rc` + `latest` 同步) - git:**仅 dev-v2**(`6c44206`)——按用户指示**未 merge main、未打 tag**;main 仍为 rc.14(`9a32e26`) ## 本版内容(相对 rc.14,dev-v2 全部改动) ### 1. 左栏会话行右键/⋯ 菜单修复(2026-08-29 反馈) - 根因:`mapRowByContent` 按 `displayTitle` 匹配,同工作区无标题会话标题相同(cwd basename)→ 整组歧义跳过 → 右键/⋯ 失效回退官方菜单(实测真实环境 Paper1 17 会话/Paper2 23 会话同标题) - 修复:歧义选最近 updatedAt 候选(被操作的行几乎总是最近活跃) ### 2. 标题栏拖动修复(2026-08-29 反馈) - 根因:SessionTabs portal 进标题栏拖拽区且整体 no-drag 覆盖 42px 标题栏 - 修复:标签栏容器 drag(空白处可拖窗口)、每个 tab/按钮/输入框 no-drag(可交互) ### 3. 桌面快捷方式改进(2026-08-28 改进点) - 启动不再创建/检查桌面 lnk(用户可能已移走);仅 NSIS 安装完成页按钮创建(GUI);静默/被动安装自动创建 ### 4. 长会话载入优化(2026-08-29 反馈) - 测量:冷开 2057ms vs 缓存命中 947ms(host 解码仅 105ms;瓶颈=dsh 投影 fold 等不可改) - host 预热 `session-warmup.ts`:启动 8s 后台 inspect 最近 3 会话(LRU 容量 5)+ `session/disposed` 后重预热 → 实测预热后打开 **225ms(~9x)** - client `content-visibility` 注入(`[data-chat-flow]` 行):长历史 DOM 屏外行跳过布局/绘制 - 全程不碰 dsh(可选服务调用 + 样式注入) ### 5. 工程 - verify-release **ALL PASS**(含全新环境装配冒烟) - 踩坑 #92(标题歧义)、#91(测试并行);RC 记录同步 ## 注意事项 - **未 merge main**:main 保持 rc.14;待用户确认后合入(PR)再打 tag - 预热 8s 内首次打开长会话仍冷开(~2s);之后命中缓存(~0.2s) --- ## 打包记录 rc.16(2026-08-29) ## 版本与产物 - 版本:**0.0.2-rc.16**(package.json / package-lock.json / tauri.conf.json 三处一致) - 产物:`build/0.0.2-rc.16/DeepSeek Harness Hub_0.0.2-rc.16_x64-setup.exe`(10.5 MB) - SHA256:`c345c42f3d48430fa5bb45e1a2491bd8bed596122b8a1dd5a5b6717159887808` - npm:**本次不发布**(保持 rc.15 的 latest/rc) - git:**仅 dev-v2**(`7c8e0ef`)——不 merge main、不 tag;main 仍 rc.14 ## 本版内容(rc.15 基础上新增 1 项修复) ### 图标跟随修复(2026-08-29 反馈) - 现象:桌面快捷方式图标不跟随自定义图标设置(rc.15 的快捷方式改进引入) - 根因:`update_shell_icon_sources` 误删「桌面 lnk **存在才更新**图标」+ `known_desktop_path` 被删——安装时创建、未移走的桌面快捷方式图标不再更新 - 修复:恢复 `theme::known_desktop_path` + `update_shell_icon_sources` 恢复「存在才更新」(不创建,创建仍仅 NSIS 安装器);`create_toast_shortcuts` 保持不创建桌面 - 标题栏面独立链路实测跟随正常(`titlebar face applied (whale-girl-duo)`);踩坑 #93 沉淀 ## 验证 - verify-release **ALL PASS**(含全新环境装配冒烟) - Rust fmt + clippy + 18/18 测试 - 隔离实例实测:标题栏/AUMID/开始菜单 lnk 跟随自定义图标;桌面无 lnk 正确跳过 ## 注意事项 - 未 merge main(保持 rc.15 惯例);npm 未发布(保持 rc.15 的 latest/rc) - rc.15 内容(右键菜单/标题栏拖动/快捷方式安装时创建/长会话预热)均包含在本版 --- ## 打包记录 rc.17(2026-08-29) ## 版本与产物 - 版本:**0.0.2-rc.17**(package.json / package-lock.json / tauri.conf.json 三处一致) - 产物:`build/0.0.2-rc.17/DeepSeek Harness Hub_0.0.2-rc.17_x64-setup.exe`(10.5 MB) - SHA256:`0370be3ab3301ae45001855832d5a0097faf1d40975fd3c38de04b64eac46b4d` - npm:**已发布**(`latest` / `rc` 均为 `0.0.2-rc.17`;registry 直查确认) - git:**仅 dev-v2**——不 merge main;tag `v0.0.2-rc.17` 已打在 dev-v2 HEAD(`1d729fa`)并推送;main 仍 rc.14 ## 本版内容(rc.16 基础上新增 2 项修复) ### 壳内 HTML5 拖拽全灭修复(用户对照反馈定案:浏览器可拖、壳内不能拖) - 现象:官方左侧栏工作区行拖拽排序在壳内完全失效("被固定住");同一 dsh 页面在普通浏览器正常 - **主根因(壳层)**:Tauri 2.x `dragDropEnabled` 默认 true → wry `DragDropController` 对每个 WebView2 子 HWND `RevokeDragDrop` + `RegisterDragDrop`(只认文件 CF_HDROP + `SetAllowExternalDrop(false)`)——页内 HTML5 DnD 事件链在 OS 层被整体截走。Tauri 官方文档自认"Windows 上用 HTML5 DnD 必须禁用";Rust 手工建窗不受 tauri.conf.json 配置影响(tauri#13761),同型 issue #2014/#15138 - 修复三层(不改官方 dsh 源码): 1. `window.rs` builder 加 **`.disable_drag_drop_handler()`**——恢复 WebView2 默认 IDropTarget,页内 DnD 行为回归 Chrome;壳不消费任何 tauri drag-drop 事件,零功能损失 2. `shell-init.js` **Files-only 拖放兜底**(document capture 阶段 dragover/drop preventDefault)——撤覆盖后拖文件到输入区 = 官方附件上传(新行为,见注意事项);无 drop 处理器的空窗期兜住,杜绝拖入文件被当 file:// 导航 3. `src/client/workspace-drag-guard.ts` **精简**:撤掉上一轮误判根因时加的 dragover 拦截(会让"拖到最前"失去官方顶部插入线),保留 watchdog 合成 dragend 自愈(兜底官方 flip-OFF 重建吞 dragend 的次生缺陷)+ 拖拽时收缩置顶区 - 踩坑 #94 改判重写:主根因=壳层 IDropTarget 覆盖;"官方无 key 重建 → dragend 丢失"降级为浏览器侧次生缺陷(壳内 dragover 都不派发,轮不到触发) - **方法学教训**:合成 DragEvent 不经过 OS IDropTarget/wry 拦截层——上一轮用 CDP 合成事件验证得到假阳性;真实鼠标拖拽壳内 vs 浏览器对照才是判据 ## 验证 - verify-release **ALL PASS**(含全新环境装配冒烟,P3 lib 零漂移) - Rust 门禁:cargo fmt ✓ / clippy -D warnings ✓ / cargo test **18/18** - **真实鼠标拖拽实测(隔离 DSH_HOME + WebView2 CDP 探针,isTrusted 判据)**: - 工作区行拖拽:dragstart → dragenter → dragover×N → drop → dragend **全链 trusted=true**(修复前 dragstart 之后全部缺失) - 排序提交并持久化(workspace.json 顺序变化落盘) - 守卫状态干净(拖拽结束 mg-drag-active 移除) - shell-init 兜底生效(`__mgFilesDndFallbackInstalled === true`) - 会话行拖拽不误伤、右键菜单正常(合成事件回归) ### 用量统计修复(用户反馈"用量统计失效") - 现象:设置页用量统计卡片"无法读取";`GET /dsh-usage-stats/api/overview` 500 `loadPrices is not defined` - 根因:PR #34 三插件落地(`3698dfb`)时 `loadPrices`/`savePrices` 被调用但从未定义——overview 自落地第一天就 500,扫描/聚合链路一直正常写盘,掩盖了读取断裂(踩坑 #95) - 修复:补上两个缺失函数(价格文件读写 + 缺失/损坏回退默认 `{modelPrices:{}, exchangeRate:7.2}`);隔离实测 overview 200(45 会话/116M tokens 完整返回)、POST /prices 200 落盘、强制刷新路径正常 - 重新打包:本记录的 SHA256 已更新为含此修复的产物(第一版 4e37f3e6… 的安装包作废) ### 用量统计读取修复(用户反馈"用量统计失效") - 现象:设置页用量统计卡片"无法读取";`GET /dsh-usage-stats/api/overview` 500 `loadPrices is not defined` - 根因:PR #34 三插件落地(`3698dfb`)时 `loadPrices`/`savePrices` 被调用但从未定义——overview 自落地第一天就 500,扫描/聚合链路一直正常写盘,掩盖了读取断裂(踩坑 #95) - 修复:补上两个缺失函数(价格文件读写 + 缺失/损坏回退默认);隔离实测 overview 200(45 会话/116M tokens)、POST /prices 200 落盘 ### 用量统计表格透出背景皮肤图片修复(用户反馈,截图定案) - 现象:各模型用量的模型卡片网格与按天统计日期表格直接显示背景皮肤图片,其他卡片正常 - 根因:`backgrounds.ts` 的 frame 背景图选择器 `#root div[style*="grid-template-columns"]` 是后代选择器,误命中面板内所有 inline grid 元素(usage-stats 的模型信息网格/按天表头/行),`!important` 强加背景图(踩坑 #96) - 修复:usage-stats 三处网格改 `