# CHANGELOG ## 0.2.1 — 2026-10-26 一个 Windows 专有的拖动缺陷。只动了一处 CSS,没有功能变化。 ### 修复:拖桌宠会把整个窗口拖走 **现象**:桌宠拖到窗口顶部时,拖它反而把整个窗口拖走了。 **根因**:桌面端在 Windows 下用一个 `::before` 伪元素铺满窗口顶部当作**系统拖动区** (选择器是 `[data-windows-titlebar] .frame:before`,声明了 `-webkit-app-region: drag`)。 桌宠是 `document.body` 的直接子元素、`position: fixed`,拖到那块区域上方时,指针事件 被系统当成窗口拖动吞掉——`pointerdown` 根本到不了 JS,所以桌宠自己的拖动逻辑 (`setPointerCapture` + 改 `left`/`top`)一次都没跑。 macOS 侧宿主对 `body` 里不在 `#root` 内的元素统一兜底成 `no-drag`,**Windows 没有 这条兜底**,所以这是 Windows 专有的坑。同 profile 的 `dsh-theme-tarkov` 桌宠也没处理。 **修法**: ```css #dsh-tu-pet, #dsh-tu-pet * { -webkit-app-region: no-drag; app-region: no-drag; } ``` 子树必须单独声明:`-webkit-app-region` **不是继承属性**,Electron 的拖动区判定按 「指针下那个元素」自己的样式算——只写根上的话,落在标题栏文字或工作区 chip 上的 按下仍会被当成拖窗口。 **测试**:`client.smoke.mjs` 加三条源码级断言(根规则有 `-webkit-app-region: no-drag`、 有标准名 `app-region: no-drag`、子树规则存在)。 ⚠️ 这三条只锁「声明存在」这个必要前提——无头环境没有真实的窗口拖动行为,拿不到 现象本身。真机验证仍要手工:把桌宠拖到窗口顶边再拖一次,窗口不应移动。 ## 0.2.0 — 2026-10-24 桌宠从「只讲全时累计」变成「也讲这次对话」,并修掉一处统计口径分叉。五块改动。 ### 1. 桌宠重构:移除三个统计读数 桌宠原先有「今日 / 速度 / 昨日」三个读数。它们都回答「过去怎么样」,而常驻在 角落的小面板该回答「现在有没有事」。 保留的两样: - **池**(全时累计块数)——插件的身份读数,只增不减; - **进度条**——先把 DOM/CSS 重构成可替换结构,语义后续再议(见第 5 条)。 顺带纠正一处口径混淆:早先「今日」既当仪表行主读数、又当大数字的备选 scope, 同一件事在两个位置各说一遍。`scope` 状态因此一并移除。 ### 2. 修复:`/workspaces` 未使用运行时统计口径 `/workspaces` 读的是部署期 `config.includeSubagents` / `config.includeAuxiliary`, 而 `/today` 与 `/summary` 走运行时 prefs。后果是设置页关掉「含子会话」后, 方块墙/桌宠的累计(读 `/today`)立刻变小,而旁边的**工作区分布**纹丝不动—— 同一块界面两个矛盾的数字。 这是 `/today` 当年那个 bug 的同款,只是漏在了第三条路径上。补 3 条回归测试, 并让它也接受 `includeSub` / `includeAux` 查询参数(桌宠与主面板轮询时会带上)。 ### 3. 新增:桌宠显示当前会话用量 - **本会话**:大数字。数据来自宿主 `tokenUsage` 投影(权威),退到我们自己的 增量折叠。 - **本轮**:实时在涨。**这是 harness 做不到的**——它只在轮次结束后才显示用量。 - **上一轮**:进「本轮」的 tooltip。它是「本轮这个数算大还是算小」的参照, 属于按需信息,常显会把这小块版面挤爆。 - **折叠态自适应**:接近压缩(≥ 80%)时显示上下文百分比,平时显示本会话量。 配套: - 新增 `lib/turns.js`:逐轮折叠纯函数。**容错**(缺边界也能起算)而不是 harness 那套全有全无语义;状态只在内存(有界 Map,最近 64 个会话)。 - 新增 `SessionBridge`:只写不画的 session-scope 组件,把 `sessionId` 推给 模块级 `focusStore`。桌宠是 root scope 命令式 DOM,问不出当前会话,host 也 不知道——这是唯一可靠来源。它用自己独立的 id、且**不受任何 prefs 控制** (`statusBar` 默认 false,接在受控组件里会静默失效)。 - `/today` 支持 `?session=`:三级降级(活会话投影 → `sessionQuery.observeSession` 冷读 → 显示 `—`),**任何一级都不把「读不到」伪装成 0**。 - 新增 `tools/cross-validate-turns.mjs`:拿真实会话日志把折叠结果与宿主自己 持久化的 `tokenUsage` 投影比对(本机 116/116 一致)。 ### 4. 新增:补充读数(上下文 / 缓存命中率 / 今日) 反馈是「只有三个数字太单调」。三个补充读数住在最下面一行,字号更小、颜色更弱—— 主读数仍然只有「本会话」和进度条。 - **上下文**:`projectedTokens / contextWindow`。唯一**有后果**的读数(快满会被 压缩),60% 起转黄、85% 起转红。 - **缓存命中率** = 缓存读取 / 计费输入。这是成本的主要驱动(实测本会话 119.89M 里 118.63M 是缓存读取),而它一直只藏在 harness 的详情弹窗里。 ⚠️ 分母**不能**含 `outputTokens`:命中率是输入侧概念,混进输出会随回复长度漂移。 - **今日量**:`/today` 本来就下发,桌宠不下发是白丢。 「今日」是第 1 条移除、现在以**补充读数**身份回来的。移除不等于永不再加—— 关键是它不再当主读数。 ### 5. 进度条语义:块进度,不是上下文百分比 第 4 条最初把进度条换成了上下文占用,实测后**改回来**了。 原因不是「哪个数字更有用」,而是**量纲**:进度条这个形状在用户心里对应「还差多少 攒满一块」,和池是同一个量纲。换成窗口占用后,条和池成了两个不相干的量——用户 看到 49% 会先问「49% 的什么?」,而旁边的「383 块」并不解释它。 所以职责分清:条 = 块内进度,池 = 块数,上下文 = 窗口占用(一个读数)。 上下文的告警能力保留,只是从「给条染色」改成「给那一格数字染色」。给条染色还有 额外坏处:条变红会让人以为「块要炸了」,而块攒满其实是好事。 这条值得单独记,因为它是一次「改错了又改回来」——一个 UI 形状承载的量纲, 比它显示哪个数字更重要。`blocks-cross.test.mjs` 现在同时锁两件事:进度条 == `blockWall().progress`,且上下文百分比**不**影响它。 ## 0.1.3 — 2026-10-24 这一版修的是一个**只在重启时才炸**的发布阻塞缺陷,并加上防止它复发的检查。 一句话概括:**包名改了,bundle 里注册的 id 没改,用户一开 App 整个界面就起不来。** --- ### 1. 修复:注册 id 与包名不一致导致 Web boot 整体失败 `package.json` 的 `name` 从 `dsh-token-usage` 改成 `dsh-token-wall` 时 (commit `b29fcac`,因 npm 上重名),`client.js` 里的 ```js window.__ModuleLoader__.load({ id: 'dsh-token-usage', ... }) ``` 没跟着改。宿主的 client-modules 模块表**按包名索引**,浏览器按包名 `dsh-token-wall` 去取 bundle,脚本执行后却注册成 `dsh-token-usage`: 1. 这一行永远解析不到 → 宿主按「缺失行单独重试」再请求一次同一脚本 2. 第二次执行触发 `duplicate factory registration for "dsh-token-usage"` 3. Web boot 自检把它算作「1 entry did not activate」,**整个启动判失败** 真实日志(`%APPDATA%\@deepseek-ai\dsh-desktop\logs\crash-*-web-boot.log`): ``` Error: web boot: 1 entry did not activate dsh-token-wall: import failed (see console for the import error) Uncaught Error: client-modules: duplicate factory registration for "dsh-token-usage" ``` 这个缺陷**延迟了约 25 小时才暴露**:改名当时宿主进程没重启,模块图早建好了, 所以统计照常记录;10/24 02:00 重启才是第一次重新扫描包名。 修法:`client.js` 的注册 id 改为 `dsh-token-wall`。 路由前缀 `/dsh-token-usage`、存储目录、localStorage key、`PKG_NAME` 全部不变, **已有数据不受影响**。 ### 2. 新增 `tools/check-boot-identity.mjs`:让这类缺陷进不了发布 把「宿主启动时用来索引这个插件的名字」三处对齐检查,并挂进 `npm run check` (因此也挂在 `prepublishOnly` 上): - `client.js` 注册 id === `package.json` 的 `name` - `exports["./client"]` 指向的文件存在,且**在 `files` 白名单内** (不在白名单 = 用户装下来没有 browser 半,症状和本故障一模一样) - `files` 白名单每个条目都存在 - `exports["."]` 与 `dsh.bundle.patch` 指向的文件存在 带 `--profile