Skip to content

Releases

v0.1.7 — 冒烟抓到的两处变体/方案抢占

Choose a tag to compare

@yefengliu1 yefengliu1 released this 16 Oct 09:26

UI 冒烟第一次跑,就抓到两条真问题

新增的 UI 冒烟(tests/ui-smoke.mjs,Playwright 连真机 GUI)在第一轮就报红,两条都不是测试自己的问题:

① 变体记忆被自己的看门狗抢占。 theme/change 的镜像监听会把「当前方案」回写成变体记录。启动恢复时读到的变体(宣纸)与官方偏好(夜墨 = dark,且现在会落盘)不一致,镜像立刻把 localStorage 改成 song-grid-yemo —— 用户的选择被自己改掉。实测:写入 song-grid-xuanzhi 刷新后变成 song-grid-yemo、界面停在深色。

→ 修:删掉这处镜像回写。官方偏好现在自己能落盘(loopback 入口下),明暗方案不需要插件替它记;变体记忆只负责「宋律开着没」+ 选择器行的提示。

② 启动恢复跟官方显式偏好抢方案。 原来只要记住的是变体就 setTheme(变体方案),于是「服务端偏好 = dark + 本地记住宣纸」两边互相覆盖。

→ 修:只在官方偏好是「跟随系统」时才替它决定;用户显式选过 light/dark 就尊重它。背景与方案的对应关系据此成为不变量:dark → ink-night、light → celadon —— 冒烟按这个不变量断言,而不是按「选了宣纸就必须浅色」。

新增的测试

tests/ui-smoke.mjs(11 项):用 localStorage 驱动三档(夜墨 / 宣纸 / 关),不点界面(免掉语言差异)。断言:开关挂上、山水背景已注入且与当前方案一致、侧栏填充 alpha 达标(深 ≤0.65 / 浅 ≤0.70)、关掉时背景 none 且正文字体回宿主默认,以及**「刷新后变体没被写回」这条回归守卫**。

tests/contract.mjs 同步加两条静态守卫:不得 writeLocal(variant)、只在 preference === 'system' 时替方案。跑法:npm test(34 项)/ npm run test:ui(11 项)。

完整 diff:v0.1.6...v0.1.7

v0.1.6 — 跨浏览器验证通过;入口 hostname 决定 settings 是否落盘

Choose a tag to compare

@yefengliu1 yefengliu1 released this 16 Oct 08:04

结论:跨浏览器能用了,但入口 hostname 是决定性条件

0.1.5(Config + .volatile())让宿主的 settings 服务开始服务这个命名空间:

/api/settings/describe:  19 → 20 个命名空间
  "song-grid-theme"  autoGenerate:false  applies:live  value:{theme:"system"}

但选择仍然写不进去 —— 客户端报 status=unavailable。真因在上游 @deepseek-ai/dsh-client-ui-settings:

const persistence = ctx.remote.$host.isLoopback ? "host" : "memory";

而 @deepseek-ai/dsh-client-connection 的 isLoopbackHostname() 只认 localhost / ::1 / 127.0.0.0-8 —— dsh.localhost 不算。于是整份 settings 降级成 memory:不只是本插件,官方主题偏好、语言、通知设置一样不落盘(这也解释了为什么"官方偏好刷新也会回退")。

实测(同一个代理,只换 hostname)

入口 结果
http://dsh.localhost:8080/ status=unavailable,写不进服务端
http://localhost:8080/ user:{theme:"songgrid"} revision:1,profile patch 落盘 - id: song-grid-theme + config: {theme: songgrid};清空 localStorage 刷新 → 主题从服务端恢复

所以:想让主题选择跨浏览器/跨机器记住,用 http://localhost:8080/ 打开;只想本浏览器记住,任何入口都行(插件自带 localStorage 镜像)。

本版改动

  • persist() 不再吞掉失败:命名空间未就绪 / 宿主拒绝 / 抛错都 console.warn —— 静默失败正是这个 bug 藏了两轮的原因。
  • README(en/zh)写明入口要求与降级行为。

完整 diff:v0.1.5...v0.1.6

v0.1.5 — Config 字段必须 .volatile()(0.1.4 的命名空间没被服务)

Choose a tag to compare

@yefengliu1 yefengliu1 released this 16 Oct 07:46

为什么 0.1.4 没生效:Config 字段必须标 .volatile()

0.1.4 已经把宿主面从运行时 ctx.settings.register("songgrid", …) 改成声明 Config(这是 0.2.0-rc.2 的正确机制:命名空间按宿主插件条目服务,id: ui-theme + export const Config 就是这么工作的)。但重启后 /api/settings/describe 里依然没有 song-grid-theme。

读完 dsh-settings 的枚举路径,差的是这一步:

describe() → volatileForm(schema)
  · schema.meta.volatile → 收
  · object → 只保留「子字段里能算出 volatile 的」那些
  · 叶子字段没有 meta.volatile → 返回 undefined(算「普通配置」,不是活配置)
  · 一个 volatile 子字段都没有 → 整个条目被过滤掉,命名空间不被服务

实测复刻这个判定:

Config volatileForm
z.object({ theme: z.string().default("system") }) undefined ← 0.1.4
z.object({ theme: z.string().default("system").volatile() }) { theme } ← 0.1.5

官方的 ui-theme 条目同样是 preference / fontSize 两个字段都标 .volatile() —— 照着它的形状写,还差这一笔。

这一版带来什么

命名空间 song-grid-theme 可被服务之后,主题选择会写进本 profile 的 cordis 配置:

  • 换浏览器 / 换机器 / 清缓存:第一次打开就能恢复宋律(服务端值)
  • 本浏览器仍以 localStorage 为准(切换立刻生效,不等网络),服务端只在本地没有记录时兜底
  • settings.configure({ auto: false }) 保证不会多出一个只有裸文本框的设置页

完整 diff:v0.1.4...v0.1.5

v0.1.4 — 跨浏览器持久化 + 浅色 tertiary 提亮 + 未选中零影响

Choose a tag to compare

@yefengliu1 yefengliu1 released this 16 Oct 07:28

选择改用宿主条目命名空间 —— 换浏览器/换机器也能恢复

0.2.0-rc.2 的 settings 命名空间是按宿主插件条目服务的:条目声明了 Config 才会出现在 /api/settings/describe 里(宿主自己的主题条目就是 web-app patch 里的 id: ui-theme + 包内 export const Config,命名空间名 = 条目 id)。

我们原来照 0.1.5 的写法在运行时 ctx.settings.register("songgrid", …) —— 那样登记不进去:命名空间永不被服务,客户端 configForms 的 snapshot 停在 pending,选择只能退化到浏览器 localStorage(换浏览器、清缓存就掉回原生外观)。

现在:

  • lib/index.js 声明 export const Config(字段 theme)
  • 按官方同款 settings.configure({ auto: false }) 抑制自动生成的设置页(否则设置里会多一个只有裸文本框的表单)
  • 客户端取条目 id song-grid-theme(= 本包 cordis.patch.yml 里的 id)

localStorage 仍是首选来源、服务端只在本地无记录时兜底,所以新浏览器/新机器第一次打开就能直接恢复宋律。生效需宿主重启一次。

宣纸 tertiary 提亮

#8B8478 (3.35:1) → #736E60 (4.67:1),caption 同步。宿主把消息正文、工具调用、时间戳、占位符都画在 --dsw-alias-label-tertiary 上,浅色下 3.35:1 对 13px 正文偏淡。

没选中宋律 = 零影响

排版层(正文宋体)与引用块的窑铜强调,也挂到 html[data-songgrid-theme="on"] 下。背景层自 0.1.2 起已经这样 —— 现在整个插件在未选中时对宿主 UI 的影响为零。

完整 diff:v0.1.3...v0.1.4

v0.1.3 — 夜墨文字亮度对齐宿主深色梯子

Choose a tag to compare

@yefengliu1 yefengliu1 released this 16 Oct 07:19

夜墨:三级文字对齐宿主深色梯子

问题:正文、工具调用、时间戳、占位符读起来发暗。宿主把这些文本都画在 --dsw-alias-label-tertiary 上(dsh-client-ui-chat 里 14 处),而夜墨把 secondary / tertiary 各压低了两档 —— tertiary #7A7468 落在 #10151A 上只有 4.0:1,13px 正文在这个对比度下明显发暗。

改法:对齐宿主深色自带的比例(--dsw-static-neutral-bluish-* 在深色下取 400/300/50 三档)。

token 改前 改后
label-primary #E8E3D6 · 14.4:1 不动
label-secondary #A8A193 · 6.6:1 #CFC8B8 · 11.4:1
label-tertiary #7A7468 · 4.0:1 #B0A897 · 7.8:1
label-caption #7A7468 #B0A897
label-primary-dimmed #A8A193 #CFC8B8

对照宿主深色自身的梯子:primary ≈17:1 / secondary 12.5:1 / tertiary 8.6:1 —— 改后落在同一量级,不是随手提亮。

宣纸(浅色)未改:浅色 tertiary 3.35:1 与宿主自身的浅色档(neutral-600 #81858c ≈ 3.5:1)一致,属于宿主既有约定。

完整 diff:v0.1.2...v0.1.3

v0.1.2 — 主题选择不再丢 + 夜墨「海上明月孤舟」加强

Choose a tag to compare

@yefengliu1 yefengliu1 released this 16 Oct 07:08

修复:主题选择不再丢 —— 「侧栏不透明、看不到背景」

现象:插件装着、山水背景在,但侧栏是不透明的原生色。因为选中状态活不过一次刷新(山水却无条件注入),于是留下「有背景、没配色、侧栏还是不透明」的半应用态。

根因:宿主 settings 命名空间在部分组合里不会被服务(profile 行被版本闸禁用时 host face 不加载、命名空间不注册),configForms 的 snapshot 永远停在 pending —— 选择既写不进去,也读不回来。

改法:

  • 选择同时写 localStorage 并在启动时以本地为准恢复,服务端值只在本地无记录时兜底;变体(宣纸/夜墨)也一起记住,否则刷新后明暗方案回落系统值。
  • 背景层改为只在宋律调色板挂着时生效(html[data-songgrid-theme="on"]):没启用就一点山水都不出现,不再留半应用的样子。

加强:夜墨「海上明月孤舟」

改前 改后
改前 改后

场景侧:月 r46→54 并加光晕/月华环 · 36 颗星子 · 三层山影对比整体提高、每条山脊加一道月照边光 · 月影水柱 0.6→0.78 · 水痕逐层提亮约 1.4× · 孤舟背后铺一层被月照到的水汽(原来 0.10 太淡,船体近黑压在近黑水面上等于隐形)· 船灯更亮并补三道暖色灯影。

覆层侧让路:深色对话区 0.90 → 0.80,侧栏 0.70 → 0.60。两边各让一步,夜色层次才真的落到眼睛里。

对比图只截了主内容区,避开侧栏里的会话内容。

完整 diff:v0.1.1...v0.1.2

v0.1.0

Choose a tag to compare

@yefengliu1 yefengliu1 released this 22 Sep 17:49

First public release of 宋律 · Songgrid — Song-dynasty aesthetics × Swiss International Style for the DeepSeek Harness web UI.

What's in it

  • Two variants — 宣纸 Xuanzhi (light) and 夜墨 Yemo (dark), plus follow-system
  • Two accents, two jobs — Ru celadon #3A7284 (4.91:1, passes WCAG AA) carries interactive states; kiln copper #9A6B50 is reserved for blockquotes, never for controls
  • Structure layer orthogonal to colour — 4pt spacing scale, 2/4px radii, four line-height steps, five motion durations + three curves, focus ring
  • 46 mask icons driven by currentColor

Install

dsh plugin --profile web add dsh-theme-songgrid

Verified on DSH 0.1.5-rc.2. Not affiliated with DeepSeek.