# 更新记录
## 未发布
### 新增
- **赫萝的黄昏酒馆:改成了「插件完全不带、点了才下」。**
此前是「代码随插件走、素材按需下载」,现在**整个 `tavern/` 都不进包**——
`package.json` 的 `files` 不再包含 `tavern/lesson` 与 `tavern/vendor`。
装完插件体积**不增加**,用户在设置卡片点「下载酒馆(约 4.9 MB)」才拉取。
**素材独立成一个仓库**:[`1015677515/holo-tavern-assets`](https://github.com/1015677515/holo-tavern-assets),
Release `v1.0.0` 挂 `tavern-assets.tar.gz`(4.91 MB,62 个文件)。
素材与插件版本解耦,改素材不必发插件版本。
**下载由 host 侧完成**,不是浏览器:浏览器拿到的字节存不进插件目录
(前端没有文件系统权限);host 有 `node:fs`,能直接写进 `tavern/`,
静态路由立刻就能服务这些文件。新增端点 `POST /holo-tavern-install`。
**为什么打包用 tar.gz 而不是 zip**:Node 标准库有 `zlib`(gunzip),
但没有 zip 解析器。tar 格式简单、能手工稳妥解析,本插件因此保持零第三方依赖。
解包逻辑抽在 `tavern-kit/tar.mjs`,带 zip-slip 防护(拒 `..`、绝对路径、
NUL 字节、不在 `tavern/` 下的条目)。
- **`scripts/pack-tavern.mjs`**:改完 `tavern/` 后一键重新打包并上传 Release。
`node scripts/pack-tavern.mjs --upload`。不传 `--upload` 就只出包。
### 修复
- **tar 解包的静默丢文件。** 初版解析器直接对 size 字段调 `trim()`,
但 tar 的每个字段都以 NUL 结尾,`parseInt("00001868424\0", 8)` 会在 NUL 处停下、
读成 `1`。后果是「包解开了,但只出 1 个文件、其余全丢」,且不报错。
现在先剥 NUL 再解析,并有 `_test_tar.mjs`(33 项断言)用真实包守住:
断言条目数必须是 62、`holo.glb` 必须是 1,868,424 B、glb/wav/webp 的文件头正确。
### 说明
- 未下载素材时,「前往黄昏酒馆」保持**禁用**,不会打开一个空白舞台。
- 已知边界:宿主是否允许插件运行时往自身目录写文件,**尚未实机验证**。
若被沙箱拦下,下载会返回 500 并如实报错,不会假装成功。
### 测试
- `_test_tar.mjs` 新增 33 项断言(解真实包 + 路径安全 6 例)。
- 酒馆侧另有一套:`_test_voice`(90)、`_test_stage_v2`(53)、
`_test_stage_reentry`(24)、`_test_cart`(14)等,合计 500+ 项。
**本版是骨架**:下载分支还没接真实地址(Release 附件尚未上传),
点了会如实说明「还没上传」,不伪造进度、不假装成功。
- **`/holo-tavern/` 静态路由**。与前三条路由不同,这条**不是逐文件白名单**
——酒馆有 25+ 文件且会随场景变动,逐个列举不现实。改为**目录级白名单**:
只放行 `tavern/lesson`、`tavern/vendor`、`tavern/assets` 三棵子树,
仍然经过 `resolveIn` 做穿越防护,另加 `TAVERN_DENY` 挡住压缩备份目录
(`_png_backup`)、点文件与 `..`。裸路径 `/holo-tavern` 与
`/holo-tavern/` 都落到 `lesson/index.html`。
### 变更
- **`MIME` 表补全**:原先只有图片/音视频/woff2,缺 `.html`、`.js`、`.css`、
`.json`、`.glb`、`.woff`、`.ttf`。酒馆是完整的网页应用,缺这几项会让
`index.html` 以 `application/octet-stream` 下发、浏览器直接下载而不是渲染。
补全后 `index.html` 是 `text/html; charset=utf-8`,`holo.glb` 是
`model/gltf-binary`。
### 测试
- 新增三套,共 **80 项断言**:
- `tavern_entry_test`(22 项):入口结构、按钮文案、未装时禁用「前往」、
**骨架阶段不伪造下载成功**、状态不存双份。
- `tavern_route_test`(38 项):`tavernAllowed` 的放行与拦截边界——
11 条该放行、15 条该挡住(穿越、备份、点文件、非允许目录)。
- `tavern_e2e_test`(20 项):**真起 HTTP 服务**打请求,验证 6 个资源
返回 200、4 类穿越返回 404、POST 返回 405。
穿越用例必须用 `http.request` 发原始 path —— `fetch()` 会在发出前把
`/holo-tavern/../client.js` 规范化成 `/client.js`,那样测不到 handler。
## 1.0.6 — 2026-10-27
### 新增
- **羊皮纸便笺(记录板)**:右下角一枚麦穗环徽章,点开是一张能打字、能粘图的便笺。
文字存 `localStorage`(400ms 防抖),**粘贴的图片存 IndexedDB**——图片体积大,
`localStorage` 装不下几张就超限。徽章可拖、面板可拖可调大小。
整棵子树走 `data-holo-planner*` 而不给 id:深色模式那条隐藏规则按 `[id^="holo-"]` 匹配,
用 id 会被一起收掉。面板刻意用 `role="region"` 而非 `dialog`:探头的状态机把任何
`[role=dialog]` 当作弹窗打开而让位,用 `dialog` 会让探头在便笺开着时永远缩着。
- **便笺的第二个入口**:设置里「简化写字板按钮」开启后,徽章隐藏,改在顶部工具条
「提示词」左边放一个「写字板」按钮。按钮挂在与 ErrorNotes 同一个 slot
(`conversation.session.header.utilities`),`order: 20` 小于它的 `30`,所以排在左边。
- **语音与翻译气泡**:九条台词接到按钮、探头、挂件、便笺徽章与待机画面,每条都在探头
右上角浮出中文译文。按钮类滞留「音频时长 + 3 秒」,触发类滞留「固定时长 + 3 秒」,
点气泡立即消失。新增七条语音素材(H013/H053/H112/H182/H193/H203 与 H015 之外的切片)。
- **点右栏待机画面里的立绘应答一句**(H013)。热区取画面宽度的 608×1080 比例、上部 62%,
是一块固定位置的矩形,**不按角色轮廓描**——六段待机动画可替换、她站的位置各不相同,
描轮廓在多数片子上会判错。
- **气泡跟着探头走**:显示期间每帧重算锚点,拖她、她倾斜或点头时气泡都跟着。
### 修复
- **打开图片后,点右上角 ✕ 反而播了赫萝的语音。** 图片预览是 `ImageLightbox`——
`createPortal` 到 `
` 的**文档级浮层**(`role="dialog" aria-modal="true"`),
它**不替换右栏开始页**。待机画面的点击热区浮在内容之上又只按「开始页在不在」判断,
于是盖住浮层、把 ✕ 的点击吃掉了。现在热区在文档出现
`[role="dialog"]` / `[aria-modal="true"]` 时立即隐藏,点击时再兜底确认一次。
判断**只认 dialog 与 aria-modal**,刻意不查 `role="menu"` / `role="listbox"`:
下拉打开时她本就该能点,查了会无谓让路。
- **点立绘有声音、没字幕气泡。** `createScene` 的签名改成了 `createScene(announce)`,
但 apply 里的调用点没跟着传参,`announce` 是 `undefined` 被类型判断挡掉。
现在传一个惰性闭包——该 effect 注册早于 voice-cue effect,直接传当时还是 `null`。
- **记表板压在探头之上**:记录板容器 `z-index` 由 `2147482810` 提到 `2147482998`。
- **侧栏「新会话」折叠时点不到。** 折叠态只有图标、没有可见文字,按文本匹配会失效;
新增 `ariaLabels` 字段并按 `aria-label` 回退匹配。「打开侧边栏」的 `aria-label`
实际是「打开右侧边栏」,与提示文字不同,两条都登记。
- **开始页的快捷卡片点不动,一点就播语音。** 待机画面的点击热区浮在内容之上,
高度按「栏宽 × 1080/608 × 62%」算,与卡片位置无关:底边正好压在
「工作区文件」「新建终端」等按钮上,点击被热区吃掉,落到 `onHit` 播了 H013。
因为高度跟着**栏宽**走,窗口一宽一窄,被吞掉的卡片数量还会变。
现在每次 `place()` 都实时读第一张 `[data-sidebar-right-guide-entry]` 的顶边,
把热区底边卡在它上方 6px:卡片恢复可点,热区也随卡片位置动态伸缩
(开始页的卡片是垂直居中的,窗口高度一变它们就整体移动,所以必须实时量)。
没有卡片时仍按原来的 62% 走;栏高不够时高度归零而非负值。
### 其它
- `index.js` 白名单由 18 项增至 27 项(`assets/` 18、`素材/` 3、`素材/动画/` 6)。
- **翻译气泡改羊皮纸板样式**:气泡从「径向高光 + 158° 渐变 + 双层外环 + 指向尾巴 +
圆角 9」改为「纸色填充 + 上下齿边 + 两端麦穗 + 圆角 6」,与宣传片字幕板一致。
纯 CSS,未动结构与台词逻辑。
- 测试:`scene_test` 70 → 92、`voice_bubble_test` 42 → 73、`planner_test` 57 → 88、
`src_integrity_test` 10 → 18(新增「签名与调用点一致」护栏,专防改了签名漏改调用点,
上面第二条 bug 正是这一类,原先两套测试都查不到)。
## 1.0.5 — 2026-10-25
### 新增
- **`screenshots.json`**:为插件市场声明四张展示图(整页概览、六组待机动画拼图、开场动画
末帧、侧栏麦田特写)。市场规则要求截图声明在插件自己的仓库里,路径相对、不能以 `/` 开头、
不能含 `..`;不声明则市场会从 README 自动抽图。之后换图只要推仓库,不用再提 PR。
- **`assets/icon-market.jpg`(256×256)**:插件市场卡片图标。原来的 `assets/icon.jpg` 只有
64×64,市场按约 96px 显示会被放大发糊。源图没有更高清的版本,这里是 4 倍 Lanczos 上采样
加轻量锐化(半径 2、强度 80%),不新增细节,只是把硬边磨顺。`package.json` 的 `icon`
字段同步指向新文件。
### 修复
- **README 有两处声明与代码不符,已改正。** 横幅 alt 文本和设计原则第 2 条原先写「装饰性
组件**全部可以单独关掉**」,但设置页实际只有六个开关(开场动画、偷看的她、探头语音、
黑夜模式、右栏待机动画、浮动字标显隐);**动态档案卡、日志标签、侧栏麦田**三项没有开关。
现在如实写明哪六项可关、哪三项常驻以及常驻的原因(纯展示层、不拦截点击、不占布局)。
中英双语同时改。这一条会被插件市场的人工评审对着代码逐条核,夸大是打回的主要原因。
## 1.0.4 — 2026-10-25
### 新增
- **右侧待机动画多了「关闭动画」选项。** 设置页那一栏现在有七项:前六项仍是六段动画的
文件名,最后一项 `关闭动画` 是关掉的开关。选中后右侧栏开始页不再显示待机画面,进入
开始页时连视频都不加载(不占解码器),也不用重启 —— 选回任意一段立即恢复。
### 修复
- **「关闭动画」原本只能单向。** `scene-change` 的监听原先注册在图层入场时,一旦关掉,
图层被撤、监听随之下线,再选回某个动画就没有人接手,必须重启才生效。现在监听挂在图层
的整个生命周期上,关闭与恢复都可以当场来回切。
## 1.0.3 — 2026-10-26
### 修复
- **`LICENSE` 被 GitHub 识别成 `NOASSERTION`。** 原因不是缺少许可证,而是 MIT 正文前
插了一段「适用范围(Scope)」把标准模板切断,GitHub 的 licensee 模板比对失败,于是
落到 `NOASSERTION`。现在 `LICENSE` 恢复为纯 MIT 模板(21 行),GitHub 徽章会显示
`MIT license`,依赖图与合规扫描也能正确归类;那段适用范围挪到独立的 `NOTICE.md`。
法律效力原本就与 MIT 一致,变的只是机器可识别性。
### 新增
- **`INSTALL.md`**:环境要求表、三种安装方式(`github:` 应用内安装 / 本地 `link:` +
`mklink /J`(含 Linux、macOS 的 `ln -s`)/ ZIP 解压)、装好之后的样子、自检:确认装对了
(三处特征 + 两种典型失败模式)、卸载(含清理 `localStorage` 与挂件目录)、常见问题。
- **README「界面预览」节**:一张 1600×862 的真实运行截图(余额、今日消耗、账号名已打码),
下附 5 行「位置 → 看到什么」对照表。
- **README「环境要求」节**:DSH `>=0.2.0-rc.1 <0.3.0-0`、Node `>=22`、三平台、约 16 MB、
无第三方依赖、安装需联网运行时不需要,并附 `package.json` 的 `engines` / `compatibility` 片段。
- **README「出处声明」节**:本项目由 [holoiallo](https://github.com/holoiallo) 最初创立,
[1015677515](https://github.com/1015677515) 完善更新,由 DeepSeek Harness 的 AI 智能体
协助开发;素材来自网络二创,仅供学习交流。中英双语。
- **README「相关链接」节**:INSTALL / CHANGELOG / NOTICE / Issues / Releases。
- **README 英文节**(精简版):Preview、Features 十一条、Requirements、Install、Credits、Links。
不做全文双语,只做一份能读懂「这是什么、怎么装」的摘要。
- **`NOTICE.md`**:中英双语说明 MIT 只覆盖源代码,不覆盖 `assets/` 与 `素材/` 的音视频图像;
素材不主张权利、有异议提出即移除、不得商用。
- **配图 `docs/gui-overview.png`**(1600×862)。
### 变更
- **`package.json`**:版本 `1.0.2` → `1.0.3`;`files` 补入 `INSTALL.md`、`NOTICE.md`(现 12 项);
`engines` 增加 `"dsh": ">=0.2.0-rc.1 <0.3.0-0"`;新增 `dsh.compatibility`(含 `dshReleases`
逐版本兼容表,写法与 `dsh-cost-meter` 等官方插件一致)。
- **README 安装节重写**:从 60 行压到 20 行,先给 `github:1015677515/dsh-theme-holo` 一行安装,
再指向 `INSTALL.md`;`github:` 这条标了【未验证】,解析失败请回退本地安装。
- **README 目录表**补入界面预览、环境要求、出处声明、相关链接、English 五条。
### 说明
- 本轮**没有**增加「它会动你的哪些文件」节与「运行时验证记录」表——按决定暂时跳过。
## 1.0.2 — 2026-10-25
### 文档
- **README 首屏换成主题配色的横幅图。** GitHub 会剥掉 README 里所有 `style` 与 `color`
(渲染器跑 `github/html-pipeline` 的消毒白名单,里面没有 `style`),页面底色与文字颜色
改不了,能承载配色的只有图片。因此首屏改为一张 1800×600 的横幅:米黄 `#FBF7EF` 底、
深米色 `#DCC9A8` 双线圆角外框、logo、金色 `#A2701F` 分隔线、三行正文。只做浅色一版。
- 目录改用两列表格(章节 / 功能详解的十个小节),并注明表格底色由 GitHub 主题决定。
- 新增配图 `docs/readme-banner.png`。
- 新增 FAQ「README 页面的底色和文字颜色,为什么不能也做成主题色?」,附消毒器实测对照表。
- 修正版本徽章(1.0.1 → 1.0.2),与 `package.json` 对齐。
## 1.0.1 — 2026-10-25
### 修复
- **首次安装不再落在黑夜模式。** DSH 的外观偏好出厂值是「跟随系统」,系统为深色的机器一装好
就解析成深色,再叠上「星夜麦田」,容易被误读成「装了插件就被切成黑夜模式」。现在插件在
**首次运行**时若发现宿主已解析为深色,会通过主题服务把外观偏好改回 `light` 一次,并把
`localStorage['dsh-theme-holo.dark-defaulted']` 置为 `1` 落闩;此后不再干预,只有设置卡片里的
开关能重新打开深色。本来就是浅色的机器不受影响。
- 宿主没有 theme 服务时,退化为摘掉 `body[data-ds-dark-theme]`(仅本次会话有效)。
### 文档
- **README「这是什么」重写**:顶部依次是 logo 与 75% 透明度的小麦图;首段改为
「本插件为 DeepSeek Harness 的《狼与香辛料(狼と香辛料)》主题插件……」的正式表述。
- 概览表:「浏览器半体积」改为「插件大小」(约 17 MB,其中两个脚本合计约 193 KB);
素材改为按图片 32 张 + 视频 6 组计数;配色一行标注「开发中,测试功能」;
删掉「110 个别名 token 各一套」这类实现细节。
- 新增配图目录 `docs/`(不参与运行时):`intro-final.webp`(开场动画末帧,1920×1080)、
`scene-grid.png`(六段右栏待机动画各取一帧拼成一条)、`wheat-75.png`(75% 透明的小麦)。
`package.json` 的 `files` 同步收录。
- 设置卡片的「黑夜模式」小节新增提示:**黑夜模式未完全做好适配,请谨慎打开。**
- README 新增 FAQ「安装后自动变成了黑夜模式?」,说明成因(DSH 默认跟随系统)与自查两步。
## 1.0.0 — 2026-10-24
**首个公开发布版本。** 版本号重新从 1.0.0 起算——此前的 1.1.0~1.13.2 是本机内部迭代,
功能已全部并入本版,旧记录保留在下方供追溯。
### 配色
- **浅色「麦秋晨光」**:羊皮纸底、暖棕文字、麦金点缀,全局重绘 DSH 的调色板 token。
- **深色「星夜麦田」**:夜色底、暖金高光,默认关闭,在插件设置里切换。
- 两套都只在**对应主题模式**下生效;切到没做过的那一侧时回退到出厂配色,不会出现
半深半浅的混搭。
### 装饰
- **开场动画(12 秒)**:canvas 实时渲染,不是视频;可按设置关闭,也可只在首次启动播放。
- **浮动字标**:可拖动,位置记忆在本地。
- **偷看的她**:贴在输入框上沿的探头立绘,可左右拖动且不出界、待机自动下沉、点击出声,
也可整只关闭。
- **动态档案卡**、**日志标签分类**:档案卡随数据变化,日志标签按类别上色。
- **侧栏脚下的麦田**:独立浮动层,宽度随侧栏自适应,高度到账号行中线。
- **插件详情页横幅**:仅本插件详情页可见,随内容滚动。
- **右栏待机画面**:仅在右栏自己的开始页显示,六段动画可在设置里切换,左右边缘做渐隐 +
模糊过渡。
### 联动
- **小鲸鱼挂件联动**:与 `dsh-whale-widget` 同时安装时,可一键导入「赫萝」「赫萝Q版」
两个可替换角色与一条替换语音,操作幂等。
### 安全
- **三条静态资源路由全部改为确切文件名白名单**。此前是整目录放行,`素材/` 下未修白边的
原件、封面草稿、字形切图都会跟着可访问。现在只送出 `index.js` 里 `ALLOW` 表列出的文件,
其余一律 404,子目录不可达,路径穿越仍被拦截。
### 工程
- 依赖零第三方包,只用 Node 内置模块与 `react`(由宿主注入)。
- `node --check` 与四套自测脚本全绿。
### 文档修正
- **待机画面「糊」的归因写错了插件**。此前 README 与旧版变更记录把雾化归到「小鲸鱼挂件」,
还把两个不同的包名混成一个(`dsh-whale-widget` 与 `dsh-plugin-wallpaper-engine`)。
实际雾化来自 **wallpaper 插件(`dsh-plugin-wallpaper-engine`)的液态玻璃 / 磨砂效果**,
它的 `backdrop-filter: blur()` 会把背后的待机动画一起糊掉。判断与解法:把 wallpaper 插件的
**雾化强度调低**(或关掉液态玻璃),糊度随之下降。`dsh-whale-widget` 只管角色与语音,
不碰背景滤镜。README 三处与旧版变更记录中的相关表述已一并更正。
---
以下为公开发布之前的内部迭代记录,保留供追溯。
## 1.13.2 — 2026-10-24
按试用要求,把待机画面左右边缘从「纯透明度渐隐」换成**两侧各 10% 区域做模糊**,渐隐边界同步收到 10%。
### 调整
- **新增模糊覆盖层 `.holo-scene-blur`**:`backdrop-filter: blur(14px)`,靠 mask 只保留左右各
10%,中间保持清晰;4%→10% 一段让模糊渐入,清晰/模糊之间不出现硬接缝。该层直接压在
`