dsh-fonttune 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,48 @@
1
+ # Changelog
2
+
3
+ All notable changes to **dsh-fonttune** are documented here. Chinese version: [CHANGELOG.md](CHANGELOG.md).
4
+
5
+ ## [0.1.2] - 2026-09-14
6
+
7
+ ### Changed
8
+ - **README rewritten**: it now covers features, install, usage, compatibility and development only — design trade-offs, implementation rationale and development pitfalls are no longer part of it. Both the Chinese and the English file were rewritten together.
9
+ - **Tighter compatibility declaration**: `engines.dsh` stays `>=0.1.5-rc.2`, while the compatibility table lists only the **latest release of the 0.1.5 line** (`0.1.5-rc.2`) — it carries every fix in that line and is the most stable build of the major version; older builds of the same major version stay compatible per semantic versioning, so they are no longer enumerated.
10
+ - **Trimmed npm description**: the "configured from Settings…" clause and the `(DSH)` parenthetical are gone, replaced by one functional sentence. Published-version metadata cannot be edited, so this takes effect from 0.1.2.
11
+ - **English card title**: `Font plus` → `Font tune`, matching the package name (the Chinese title stays 字体增强).
12
+
13
+ ## [0.1.1] - 2026-09-14
14
+
15
+ ### Added
16
+ - **English changelog**: `CHANGELOG.en.md` was added and ships inside the package.
17
+ - **GitHub Release workflow**: pushing a `v*` tag packs the plugin and creates or updates the Release with a **version-free** `dsh-fonttune.tgz` asset (the market's `tarball:` field points at it, so the link cannot rot on the next release). The release body takes the Chinese section of this file for that version and folds the English section into `<details>`.
18
+
19
+ ### Changed
20
+ - The stale offline-check count in the README and changelog was corrected (35 → 42). The running code is identical to 0.1.0.
21
+
22
+ ## [0.1.0] - 2026-09-14
23
+
24
+ First release. The architecture is a dual-half plugin (host + client): the client half owns the settings card and the style injection, the host half registers the settings namespace and ships the saved declarations with the served index.
25
+
26
+ ### Added
27
+ - **Plugin settings card**: a host settings namespace registered under `settings.plugin.item` with the key `dsh-fonttune`, so it appears in **Settings → Plugins → Plugin configuration**; saving and resetting go through DSH's own settings document (`settings.yaml`).
28
+ - **Body / code font families**: two independent CSS font-family fallback lists, each allowed to be empty (= leave DSH's own stack alone).
29
+ - **Font picker panel**: four preset groups (monospace / CJK / Latin / generic); on Chromium `queryLocalFonts()` adds an "installed on this machine" group; a name that is not in the list can be created with "use xxx"; every row renders in its own font.
30
+ - **West / CJK split (simple mode)**: a switch at the top of the card — **simple mode** splits the stack into a Western and a CJK single-pick slot (one pair for body, one for code) while keeping one stack underneath; **advanced mode** is the full chip editor. The semantics are "simple mode only touches the front": the Western slot is the first non-CJK entry (picking replaces it in place, or prepends when there is none) and the CJK slot is the first CJK entry (picking replaces it in place, or **inserts right after the Western slot** when there is none, which keeps `Western, CJK, generic` CSS semantics correct). Everything beyond the two slots keeps its order and is shown as an "other fallbacks" note. **Switching modes is a pure view switch that writes nothing.** CJK classification is name-heuristic first (a broad regex plus localized names containing CJK characters); canvas measurement only confirms names that do not look CJK, so a preset family that is not installed still lands in the CJK slot. The switch row is a label on the left and a segmented toggle on the right.
31
+ - **Drag to reorder**: the selected families are a chip list with drag reordering, plus earlier/later buttons for keyboard and touch.
32
+ - **Live preview**: mixed Chinese/English plus a code line, rendered from the current configuration.
33
+ - **Global font-size offset** (-3 ~ +6 px): rescales DSH's own size tokens (`--dsh-content-font-size`, `--dsw-font-*-font-size` / `-line-height`) with the base read live, so it **stacks** with DSH's own font-size setting instead of overriding it; the token list is discovered at runtime with a built-in fallback map.
34
+ - **Global font weight** (300 ~ 600, any integer): applied through `body, body *`; 400 and "unset" both mean "leave DSH's own weight alone".
35
+ - **Commit-on-release sliders**: dragging the size-offset or weight slider only updates a local value and its readout — the write happens once on `pointerup` / `touchend` (window capture-level listeners) or on blur/keyup, so dragging never recomputes the size tokens and rewrites the settings document per step. **The local value also stays on screen until the host confirms it**: clearing it immediately would show the old committed number for one frame ("bounces back, then settles"); a repeated `pointerup` is guarded by an "already awaiting confirmation" flag so the same value is never written twice.
36
+ - **No first-paint font flash**: the host half listens on `webserver/index-inject` and injects the same declarations, so the first paint is already correct.
37
+ - **Bilingual copy** (Chinese/English) with a Chinese fallback; `queryLocalFonts` unavailability or refusal falls back to the built-in list silently.
38
+ - **Family-name sanitizing**: names are filtered through an allowlist and then quoted as a whole (letters/digits/space/`.` `,` `_` `-` only); the host schema adds a `^[^{};<>\\]*$` pattern and a length cap. A hand-crafted CSS injection cannot close a declaration or start a rule.
39
+
40
+ ### Fixed
41
+ - **The card crashed on first render** (a release blocker): `scope.subscribe` was passed to React's `useSyncExternalStore` as a bare method reference, while the host's `SettingsScopeController.subscribe` is a prototype method reading `this.store` — called detached, `this` is undefined → the slot entry crashed silently and the card never appeared in the plugin configuration page. Fixed by wrapping the subscribe in a closure that preserves `this`. The offline tests had missed it (the double's subscribe did not depend on `this` and the React double never called subscribe); both doubles now reproduce the bug.
42
+ - **Three size-offset defects**: ① missing `!important` — the theme writes `--dsh-content-font-size` **inline on body**, and an inline declaration beats a normal stylesheet rule, so the body itself was not scaled while descendants were, splitting the page's font size in two; ② a **self-pollution compounding loop** — the 4-second token refresh re-read the plugin's own stylesheet declarations as its base and multiplied the ratio again on every cycle ("the fonts keep growing"); fixed by skipping the plugin's own tags, reading `--dsh-content-font-*` from the body inline style, and no longer using computed styles as a base source; ③ **double scaling through the `var()` chain** — DSH's derived tokens (delta/secondary/markdown) all derive from `var(--dsh-content-font-size)`, so scaling them too multiplied the ratio twice; fixed by skipping tokens whose base contains `var(` and letting the variable chain carry them.
43
+ - **Families did not reach the conversation or sidebar**: markdown and sidebar CSS declare `font-family: var(--dsw-font-family)` themselves, truncating inheritance, so a body-level `font-family` never got through. Fixed by overriding at the **variable source** (`:root,body{--dsw-font-family:…!important}` plus `--dsw-font-mono` / `--ds-font-family-code`), with the explicit `body` / `pre,code` rules kept as a second path.
44
+ - **Weight snapped to ±100**: values used to snap to 300/400/500/600, which looked like a ±100 step while dragging; the chosen integer is now written to CSS verbatim (variable fonts are fully linear, static fonts round to their nearest available weight natively) with a step of 1.
45
+ - **The sanitizer was too permissive**: `Arial"; } body { background: url(evil) }` left `:` `(` `)` behind; rewritten as an allowlist.
46
+ - **The host half importing named exports from the CJS shared module broke ESM loading** (`Named export not found`); switched to a default import.
47
+ - **The size-token regex missed `--dsh-content-font-size`** (the name has no `-font-` segment) and its `-secondary` variants.
48
+ - **Timers now go through `globalThis`** instead of assuming `window` carries them.
package/CHANGELOG.md CHANGED
@@ -1,41 +1,48 @@
1
- # Changelog
1
+ # 更新日志
2
2
 
3
- ## 0.1.0 — 2026-09-14
3
+ **dsh-fonttune** 的重要变更都记录在这里。英文版见 [CHANGELOG.en.md](CHANGELOG.en.md)。
4
4
 
5
- 首个版本(M1–M3 完成)。架构取"host + 客户端半"双半插件,而非设计文档最初设想的纯客户端插件——理由见 README「为什么不是纯客户端插件」。
5
+ ## [0.1.2] - 2026-09-14
6
6
 
7
- ### 新增
8
-
9
- - **插件配置卡片**:注册在 `settings.plugin.item`、key 为 `dsh-fonttune` host 设置命名空间,出现在 设置 → 插件 → 插件配置 里,保存/重置走 DSH 自己的设置文档(`settings.yaml`)。
10
- - **正文 / 代码字体族**:两套独立的 CSS font-family fallback 列表,可为空(= 完全不动 DSH 的字体栈)。
11
- - **选字体面板**:内置 等宽 / 中文(CJK)/ 拉丁 / 通用 四组预设;Chromium 下用 `queryLocalFonts()` 补"本机已安装"分组;搜索不到的名字给"使用 xxx"新建入口;每行用其自身字体渲染。
12
- - **中西分家(简单模式)**(2026-09-14,用户点名要 Word/docx 式的中文字体/西文字体两格):卡片顶部一个开关——**简单模式**把栈拆成「西文字体」「中文字体」两个单选格(正文/代码各一对),内部自动维护同一条栈;**高级模式**就是完整的 chips 编辑器。语义(用户拍板"简单模式只动最前面"):西文格 = 栈里第一个非中文项(通常就是第 1 位),改选原地替换、无则插到最前;中文格 = 第一个中文项,改选原地替换、无则**紧跟西文槽插入**(保证 `西文, 中文, 通用兜底` 的 CSS 语义正确);两格之外的所有项与顺序**原样保留**,并在"其余回退项"一行提示;**模式切换是纯视图切换、零写入**。中文判定 = 名字启发式优先(宽松正则 + 含 CJK 字符的本地化名),canvas 测宽只对名字不像 CJK 的字体补充确认——**未安装的预设字体也能正确落入中文槽**(实测「思源黑体」本机没装也被正确分类;测宽对未安装字体必然误判,故只作次级手段)。实测:槽位派发正确、高级模式完整列表可见、来回切换零数据变化、真实面板点选只替换对应槽、控制台干净。开关行布局(用户反馈):左侧说明文字「编辑方式」+ 右侧分段式小切换(简单 | 高级),替换原两个等宽大按钮。
13
- - **拖拽排序**:已选字体是 chip 列表,可拖拽调整回退顺序,同时保留前移/后移按钮(键盘与触屏可用)。
14
- - **实时预览**:中英混排 + 代码两行,随当前配置实时渲染。
15
- - **全局字号偏移**(-3 ~ +6 px):**等比缩放 DSH 自己的字号 token**(`--dsh-content-font-size`、`--dsw-font-*-font-size` / `-line-height`),基准值实时读自计算样式,因此与 DSH 的"字号大小"滑块叠加而非互相覆盖;token 名单运行时发现、内置兜底表。
16
- - **全局字重**(300 ~ 600):作用于 `body, body *`,400 与未设置都表示"不动"。
17
- - **滑块松手才落盘**(2026-09-14,用户反馈"动一点就马上调整很卡"):字号偏移/字重滑块拖动时只更新本地待定值与读数显示,`pointerup`/`touchend`(窗口捕获级监听)或失焦/键盘抬起时一次性提交,拖动过程零写入——不再每挪一格就全量重算字号 token + 写设置文档。**松手后保持待定值直到宿主确认值回来**(用户反馈"回弹再到位"):提交与设置文档回执之间的一拍里若立刻清本地值,滑块会闪回旧提交值再跳到新值——现以待提交值上屏、回执到达(或外部值变化)才清除,逐帧采样验证松手后读数序列无旧值闪现;重复 `pointerup` 以"已待确认"守卫挡住,不会重复写同一值。
18
- - **字重提示精简**(用户点名):改为「覆盖全局文字粗细(含标题);默认字重为400。」,删去"任意整数都生效/可变字体线性/普通字体取最近一档"的说明。
19
- - **首帧不闪字体**:host 半监听 `webserver/index-inject` 注入同款 `<style>`,客户端插件激活前首帧就是保存的字体。
20
- - **中英双语文案**,缺英文回退;`queryLocalFonts` 不可用/被拒时静默回退到内置列表。
7
+ ### 变更
8
+ - **README 重写**:只讲功能、安装、使用、兼容性与开发,设计取舍、实现原理与开发期踩坑不再写进 README。中英两份同步。
9
+ - **兼容性声明收紧**:`engines.dsh` 仍为 `>=0.1.5-rc.2`,而兼容表只列 **0.1.5 线的最新版本**(`0.1.5-rc.2`)——它包含这条线的全部修复,是同一大版本里最稳的一版;同一大版本内的旧版本按语义化版本约定向上兼容,不再逐个罗列。
10
+ - **npm 描述精简**:去掉「配置入口」一句与 `(DSH)` 括号,改为一句功能描述。已发布版本的元数据无法修改,因此这条从 0.1.2 起生效。
11
+ - **英文卡片标题**:`Font plus` `Font tune`,与包名一致(中文标题仍是「字体增强」)。
21
12
 
22
- ### 安全
13
+ ## [0.1.1] - 2026-09-14
23
14
 
24
- - 字体名按**白名单**消毒(仅保留字母/数字/空格/`.` `,` `_` `-`),消毒后再整体加引号;Host schema 另加 `^[^{};<>\\]*$` 与长度上限。手工构造的 CSS 注入无法闭合声明或规则。
15
+ ### 新增
16
+ - **英文更新日志**:新增 `CHANGELOG.en.md`,随包发布。
17
+ - **GitHub Release 工作流**:推送 `v*` 标签时自动打包并创建/更新 Release,产出**不带版本号**的 `dsh-fonttune.tgz`(供市场 `tarball:` 字段使用,不会因为下次发版而 404);Release 正文取本文件对应版本的中文段落,英文段落折叠在 `<details>` 里。
25
18
 
26
- ### 工程
19
+ ### 变更
20
+ - 订正 README 与更新日志里过期的离线检查数(35 → 42 项)。运行代码与 0.1.0 相同。
27
21
 
28
- - 纯 JavaScript 源码 + **零依赖构建脚本**(`build.mjs`):内联 shared、套 `window.__ModuleLoader__.load` 外壳、挂 `exports.apply/inject`,并强制校验"客户端 bundle 只能 require shell 预注入模块"。
29
- - `node test/run.mjs`:**35 项离线检查**全绿,含自建 DOM、cordis 替身、设置面与 slot 派发替身、真实 `@deepseek-ai/schemastery` schema 解析、CSS 生成与注入、消毒对抗用例。
30
- - **真实浏览器验证闭环**(本机可复跑,无需用户参与):受管实例(`--port 0 --no-open`,token 从 stdout 拿)→ `Invoke-WebRequest -SessionVariable` 用 token 换 cookie 后可直接 POST `/api/settings/describe`(信封 `{type:"client-request",rpcId,method:"<ns>/<method>",payload:{args:{}}}`)验证 namespace 已注册 → `test/browser-probe.mjs` / `test/ui-walk.mjs` 用**无头 Edge + CDP**(Node 内置 WebSocket)真实渲染页面:设置 → 插件 → 插件配置 → 断言卡片渲染、展开后控件齐全、控制台零报错。最终态实测:`fontCardVisible: true`,展开后 sans/mono/size/weight/preview/resetAll 全渲染、2 个滑块、控制台干净。
22
+ ## [0.1.0] - 2026-09-14
31
23
 
32
- ### 修复(开发期自查发现的真实缺陷)
24
+ 首个版本。架构取「host 半 + 客户端半」双半插件:客户端半负责设置卡片与样式注入,宿主半注册设置命名空间并把已保存的声明随首页下发。
33
25
 
34
- - **卡片首渲染即崩溃(无头浏览器实测抓到的发布阻断 bug)**:`scope.subscribe` 被以裸方法引用传给 React 的 `useSyncExternalStore`,而宿主的 `SettingsScopeController.subscribe` 是读 `this.store` 的原型方法,脱离对象调用时 `this` 为 undefined → `slot entry crashed in 'settings.plugin.item': Cannot read properties of undefined (reading 'store')` → 卡片在插件配置页里根本不出现(其他卡片正常、插件清单里能看到本插件)。修复 = 传给 React 的 subscribe 一律包闭包保住 `this`。离线测试曾漏检:替身的 subscribe 是不依赖 `this` 的闭包,且 React 替身从不调用 subscribe——现两处替身都已改成会暴露该 bug 的形态(严格 scope + 脱离式调用)。
35
- - **字号偏移三连 bug(真实浏览器实测逐个抓到)**:① `!important`——主题把 `--dsh-content-font-size` 写在 body **内联**样式上,内联声明压过普通样式表规则 body 本身不缩放、后代缩放,页面字号劈成两半;② **自我污染复利循环**(用户实测"字体一直变大")——token 刷新每 4 秒重读基准值时把本插件自己样式表里的声明当成"未触碰基准"扫回去,每轮再 ×比例;修复 = 扫描样式表时跳过自己的标签、`--dsh-content-font-*` 直接读 body 内联原值,且**计算样式不再作为基准来源**(规则生效后计算值就是缩放后的,回流即复利);③ **var 链双重缩放**——DSH 的派生 token(delta/secondary/markdown 全套)都从 `var(--dsh-content-font-size)` 派生,把它们也缩放会 ×比例×比例;修复 = 基准值含 `var(` 的 token 跳过显式缩放,经变量链自动继承。跨两个刷新周期的稳定性实测:content-size 数值不变、样式表 0 个 `var(`、控制台干净。
36
- - **字体族不铺满对话区/侧边栏**:对话 markdown 与侧栏元素的 CSS 自己声明 `font-family: var(--dsw-font-family)`,继承被截断,只写 body font-family 传不进去。修复 = 按 dsh-ui-font 的验证做法在**变量源头**覆盖:`:root,body{--dsw-font-family:<sans>!important}` 与 `--dsw-font-mono`/`--ds-font-family-code`(代码 token 全链 `var(--ds-font-family-code)`);显式 body/pre,code 规则保留作第二路径。
37
- - **字重吸附到 ±100 档**:原来把任意值 snap 300/400/500/600,拖动时看似只 ±100;现按用户所选整数原样写 CSS(可变字体全线性,普通字体内建就近取整),滑块 1 步进。
38
- - 消毒过于宽松时 `Arial"; } body { background: url(evil) }` 能残留 `:` `(` `)`,改写为白名单式。
39
- - host 半从 CJS 共享模块具名导入会让 ESM 加载失败(`Named export not found`),改为默认导入。
40
- - 字号 token 正则漏掉 `--dsh-content-font-size`(该名不含 `-font-` 前缀)与其 `-secondary` 变体。
41
- - 计时器改走 `globalThis`,不再依赖 `window` 上是否存在这两个方法。
26
+ ### 新增
27
+ - **插件配置卡片**:注册在 `settings.plugin.item`、key `dsh-fonttune` 的宿主设置命名空间,出现在 **设置插件 插件配置** 里;保存/重置走 DSH 自己的设置文档(`settings.yaml`)。
28
+ - **正文 / 代码字体族**:两套独立的 CSS font-family 回退列表,可为空(= 完全不动 DSH 的字体栈)。
29
+ - **选字体面板**:内置 等宽 / 中文(CJK)/ 拉丁 / 通用 四组预设;Chromium 下用 `queryLocalFonts()` 补「本机已安装」分组;搜索不到的名字给「使用 xxx」新建入口;每行用其自身字体渲染。
30
+ - **中西分家(简单模式)**:卡片顶部一个开关——**简单模式**把字体栈拆成「西文字体」「中文字体」两个单选格(正文/代码各一对),内部仍维护同一条栈;**高级模式**是完整的 chips 编辑器。语义为「简单模式只动最前面」:西文格 = 栈里第一个非中文项(改选原地替换、无则插到最前),中文格 = 第一个中文项(改选原地替换、无则**紧跟西文槽插入**,保证 `西文, 中文, 通用兜底` CSS 语义正确);两格之外的所有项与顺序**原样保留**并在「其余回退项」一行提示;**切换模式是纯视图切换、零写入**。中文判定以名字启发式优先(宽松正则 + 含 CJK 字符的本地化名),canvas 测宽只对名字不像 CJK 的字体补充确认——未安装的预设字体也能正确落入中文槽。开关行布局:左侧「编辑方式」说明 + 右侧分段式小切换。
31
+ - **拖拽排序**:已选字体是 chip 列表,可拖拽调整回退顺序,同时保留前移/后移按钮(键盘与触屏可用)。
32
+ - **实时预览**:中英混排 + 代码两行,随当前配置实时渲染。
33
+ - **全局字号偏移**(-3 ~ +6 px):等比缩放 DSH 自己的字号 token(`--dsh-content-font-size`、`--dsw-font-*-font-size` / `-line-height`),基准值实时读,因此与 DSH 的「字号大小」滑块**叠加**而非互相覆盖;token 名单运行时发现,内置兜底表。
34
+ - **全局字重**(300 ~ 600,任意整数):作用于 `body, body *`;400 与未设置都表示「不动」。
35
+ - **滑块松手才落盘**:字号偏移 / 字重滑块拖动时只更新本地待定值与读数,`pointerup` / `touchend`(窗口捕获级监听)或失焦、键盘抬起时才一次性提交——拖动过程零写入,不再每挪一格就重算字号 token 并写设置文档。**松手后保持待定值直到宿主确认值回来**:提交与设置文档回执之间若立刻清本地值,滑块会闪回旧值再跳到新值(「回弹再到位」),现在以待提交值上屏、回执到达(或外部值变化)才清除;重复 `pointerup` 以「已待确认」守卫挡住,不会重复写同一个值。
36
+ - **首帧不闪字体**:宿主半监听 `webserver/index-inject` 注入同款 `<style>`,客户端插件激活前首帧就是保存的字体。
37
+ - **中英双语文案**,缺英文回退中文;`queryLocalFonts` 不可用或被拒时静默回退到内置列表。
38
+ - **字体名消毒**:按白名单过滤后整体加引号(仅保留字母/数字/空格/`.` `,` `_` `-`),宿主 schema 另加 `^[^{};<>\\]*$` 与长度上限;手工构造的 CSS 注入无法闭合声明或另起规则。
39
+
40
+ ### 修复
41
+ - **卡片首渲染即崩溃(发布阻断 bug)**:`scope.subscribe` 被以裸方法引用传给 React 的 `useSyncExternalStore`,而宿主的 `SettingsScopeController.subscribe` 是读 `this.store` 的原型方法,脱离对象调用时 `this` 为 undefined → slot entry 静默崩溃、卡片在插件配置页里根本不出现。修复 = 一律包闭包保住 `this`。离线测试曾漏检(替身的 subscribe 不依赖 `this`、且 React 替身从不调用 subscribe),现两处替身都已改成会暴露该 bug 的形态。
42
+ - **字号偏移的三个缺陷**:① 缺 `!important`——主题把 `--dsh-content-font-size` 写在 body **内联**样式上,内联声明压过普通样式表规则,导致 body 本身不缩放、后代缩放,页面字号劈成两半;② **自我污染复利循环**——token 刷新每 4 秒重读基准值时把本插件样式表里的声明当成基准扫回去,每轮再乘一次比例(表现为「字体一直变大」),修复 = 扫描时跳过自己的标签、`--dsh-content-font-*` 直接读 body 内联原值、计算样式不再作为基准来源;③ **var 链双重缩放**——DSH 的派生 token(delta/secondary/markdown 等)都从 `var(--dsh-content-font-size)` 派生,把它们也缩放会乘两次比例,修复 = 基准值含 `var(` 的 token 跳过显式缩放,经变量链自动继承。
43
+ - **字体族不铺满对话区/侧边栏**:对话 markdown 与侧栏元素的 CSS 自己声明 `font-family: var(--dsw-font-family)`,继承被截断,只写 body 的 `font-family` 传不进去。修复 = 在变量源头覆盖(`:root,body{--dsw-font-family:…!important}` 与 `--dsw-font-mono` / `--ds-font-family-code`),显式 `body` / `pre,code` 规则保留作第二路径。
44
+ - **字重被吸附到 ±100 档**:原来把任意值 snap 到 300/400/500/600,拖动时看似只按 ±100 跳;现按所选整数原样写 CSS(可变字体全线性,普通字体内建就近取整),滑块步进为 1。
45
+ - **消毒过于宽松**:`Arial"; } body { background: url(evil) }` 能残留 `:` `(` `)`,改写为白名单式。
46
+ - **宿主半从 CJS 共享模块具名导入会让 ESM 加载失败**(`Named export not found`),改为默认导入。
47
+ - **字号 token 正则漏掉 `--dsh-content-font-size`**(该名不含 `-font-` 前缀)及其 `-secondary` 变体。
48
+ - **计时器改走 `globalThis`**,不再依赖 `window` 上是否存在这两个方法。
package/README.en.md CHANGED
@@ -1,78 +1,70 @@
1
1
  # dsh-fonttune
2
2
 
3
- A font enhancement plugin for the DeepSeek Harness (DSH) Web GUI: **UI & code font families + a global font-size offset + a global font weight**, configured from **Settings → Plugins → Plugin configuration** (a native settings card). Every change applies immediately — no reload.
3
+ > [中文](README.md) | **English**
4
4
 
5
- 中文文档:[README.md](README.md)
5
+ **Font plugin for DeepSeek Harness (DSH)**: set the body and code font families, a global font-size offset and a global font weight, and pick fonts per **Western / CJK** slot. Everything lives in the native card under **Settings → Plugins → Plugin configuration** and applies immediately.
6
6
 
7
- ## Why it is not a client-only plugin
7
+ ## Features
8
8
 
9
- The design doc originally planned a client-only plugin with localStorage. In practice it became a **dual-half (host + client)** plugin, for three verified reasons:
9
+ - **Body / code fonts** two independent fallback lists, Latin families first and CJK after; leaving one empty keeps DSH's own stack untouched
10
+ - **Global font-size offset** — -3 ~ +6 px, stacked on top of DSH's own font-size setting rather than replacing it; every size step scales together with its line height
11
+ - **Global font weight** — any integer from 300 to 600; unset or 400 both mean "keep DSH's own weight"
12
+ - **West / CJK split (simple mode)** — a switch at the top of the card: simple mode gives just a Western and a CJK single-pick slot (one pair for body, one for code), advanced mode is the full stack editor; both views share one stack, so toggling never changes the order you set up
13
+ - **Font picker panel** — four preset groups (monospace / CJK / Latin / generic), plus an "installed on this machine" group on Chromium; a name that is not in the list can be created with "use xxx"
14
+ - **Drag to reorder** — selected families are a chip list you can drag, with earlier / later buttons kept for keyboard and touch
15
+ - **Live preview** — a mixed Chinese/English line and a code line, rendered from the current configuration
16
+ - **Commit on release** — the size and weight sliders only update their readout while dragging; the value is written once on pointer release (or keyup / blur), so dragging stays smooth
17
+ - **No first-paint flash** — the host half ships the saved declarations with the page, so the first paint already uses your fonts
18
+ - **Bilingual** — card copy follows DSH's language (Chinese / English)
10
19
 
11
- | Client-only | Dual-half (this plugin) |
20
+ ## Compatibility
21
+
22
+ | Plugin version | Supported DSH versions |
12
23
  | --- | --- |
13
- | The card can never render — the `settings.plugin.item` slot is dispatched by the settings namespace **registered on the host**; without the host half there is no key | The card appears in the native plugin configuration page; save/reset go through DSH's own settings document |
14
- | First paint flashes the default fonts (client plugins load asynchronously) | The host half listens on `webserver/index-inject` and injects the same declarations into the served index `<head>` — **the first paint is already correct** |
15
- | Settings live in localStorage only (cleared with the cache) | Settings live in the Host settings document (`settings.yaml`) |
24
+ | **0.1.1** (latest) | 0.1.5-rc.2 |
16
25
 
17
- The doc's worry that a host half forces a restart does not hold: the web profile runs with `patchReload: "live"`. Only the install itself needs one restart (to place the package into the profile).
26
+ `engines.dsh` requires **0.1.5-rc.2** or newer, and the compatibility declaration lists only the **latest release of the 0.1.5 line**: it carries every fix in that line, which makes it the most stable build of the major version, while older builds of the same major version stay compatible per semantic versioning. Earlier or newer DSH versions are untested and not declared. On install or update, the DSH market runs a host-compatibility preflight against `engines.dsh`, `dsh.compatibility.dshReleases` and `peerDependencies` in `package.json`.
18
27
 
19
28
  ## Install
20
29
 
21
- ```powershell
22
- # from npm (after publishing)
23
- dsh plugin --profile web add dsh-fonttune
30
+ Install through the DSH CLI:
24
31
 
25
- # local development: junction into this folder and add
26
- # - id: fonttune / name: dsh-fonttune to profiles\web\cordis.patch.yml
27
- dsh plugin --profile web add link:F:\deepseek harness\dsh-fonttune
32
+ ```
33
+ dsh plugin --profile web add dsh-fonttune
28
34
  ```
29
35
 
30
- Restart DSH once after installing; after that, changing settings needs no restart.
31
-
32
- ## The four axes
33
-
34
- | Axis | Range | Default | Notes |
35
- | --- | --- | --- | --- |
36
- | Body font (`sans`) | Arbitrary fallback list | empty = untouched | Latin families first, CJK after; empty keeps DSH's own stack |
37
- | Code font (`mono`) | Same | empty = untouched | Applies to `pre/code/kbd/samp/var/tt/textarea` and CodeMirror editors |
38
- | Font-size offset | -3 ~ +6 px | 0 = untouched | Uniform proportional rescale, stacks with DSH's own font-size setting |
39
- | Font weight | 300 ~ 600, any integer | unset = untouched | 400 is DSH's own body weight and also counts as "untouched" |
40
-
41
- Both number sliders are **commit-on-release**: dragging only updates a local value, and the write happens once on pointer/touch release (or keyboard/blur) — no recomputation per pixel.
42
-
43
- ### West / CJK split (simple / advanced mode)
44
-
45
- The switch row at the top of the card (a label on the left, a segmented Simple/Advanced toggle on the right):
36
+ From GitHub:
46
37
 
47
- - **Simple mode** splits the stack into a Western and a CJK single-pick slot (one pair for body, one for code). It only manages the **front** of the stack: the Western slot replaces the first non-CJK entry in place; the CJK slot replaces the first CJK entry in place, or inserts right after the Western slot when none exists. Everything beyond the two slots keeps its order.
48
- - **Advanced mode** is the full chip editor with drag-to-reorder.
49
- - **Switching modes writes nothing** — both views share one stack, and your tuned order survives; the preference is stored in the browser.
38
+ ```
39
+ dsh plugin --profile web add github:LyaxZ/dsh-fonttune
40
+ ```
50
41
 
51
- The font picker ships with four preset groups (monospace / CJK / Latin / generic), adds "installed on this machine" via `queryLocalFonts()` on Chromium, and lets you create any name via "use xxx". Each row renders in its own font, with a mixed-script live preview below.
42
+ Or from a local directory:
52
43
 
53
- ## How the size offset works
44
+ ```
45
+ dsh plugin --profile web add <plugin directory>
46
+ ```
54
47
 
55
- DSH does not have "one font size"; it generates a set of CSS custom properties at runtime — `--dsh-content-font-size` (written **inline on `body`** by the theme package) plus one `--dsw-font-*-font-size` / `-line-height` per design-system step. Writing `font-size: calc(1em + 2px)` would compound down the DOM tree, so this plugin instead **rescales every token by one ratio** (`(16 + offset) / 16`), with the base read live — so it stacks with DSH's own slider, and each step scales its own line-height along. The token list is discovered at runtime (stylesheet declarations → computed values → built-in fallback), so future DSH token changes are followed automatically.
48
+ Restart DSH once afterwards and open the Web UI; changing settings needs no restart after that.
56
49
 
57
- ## Safety
50
+ ## Usage
58
51
 
59
- User-entered family names are sanitized with an allowlist (letters incl. CJK, digits, space, `.`, `,`, `_`, `-`); everything else is dropped and the whole name is quoted, so a name cannot close a declaration, start a rule, or reach `url()`. The host schema adds a `^[^{};<>\\]*$` pattern and a length cap on top.
52
+ - **Open the settings** Settings Plugins Plugin configuration expand the "Font tune" card
53
+ - **Pick fonts** — in simple mode click the four slots (Body · Western, Body · CJK, Code · Western, Code · CJK); in advanced mode use "Add font" and the chip editor to maintain the full fallback list
54
+ - **Tune numbers** — drag the size-offset / weight sliders; the value applies on release. Changed fields are marked and can be reset individually, with "Reset all" at the bottom of the card
55
+ - **Preview** — the mixed-script and code preview at the bottom of the card renders with the current configuration
56
+ - Settings are stored in DSH's settings document (`settings.yaml`), so they travel with your configuration
60
57
 
61
58
  ## Development
62
59
 
63
- ```powershell
64
- node build.mjs # build lib/ (zero-dependency, no bundler)
65
- node build.mjs --watch
66
- node test/run.mjs # 42 offline checks
67
- ```
68
-
69
- The sources are plain JavaScript with **no build dependencies**: `src/shared.cjs` (pure-function core), `src/index.mjs` (host half), `src/client.js` (browser half). `build.mjs` inlines the core into the client bundle, wraps it in the `window.__ModuleLoader__.load({id, factory})` shell, copies the host half, and verifies the "only shell-held modules may be required" constraint.
70
-
71
- ## Compatibility
72
-
73
- - DSH `0.1.5-rc.2` (declared in `dsh.compatibility.dshReleases`).
74
- - Do not enable other plugins that also write the `body` font family at the same time; this plugin can fully replace them.
60
+ - `src/shared.cjs` — pure-function core: family sanitizing and parsing, configuration normalization, generated stylesheet
61
+ - `src/index.mjs` host half: registers the `dsh-fonttune` settings namespace (schemastery schema with length and range validation) and ships the saved declarations into the served index through `webserver/index-inject`, so the first paint already uses them
62
+ - `src/client.js` — browser half: the settings card, the font picker panel, font enumeration and style injection
63
+ - `build.mjs` zero-dependency build: inlines the shared core, wraps the bundle in the `window.__ModuleLoader__.load({id, factory})` shell, copies the host half, and enforces that the client bundle only requires shell-held modules
64
+ - `test/run.mjs` — offline checks (hand-built DOM / cordis / settings-surface doubles, the real schemastery schema, CSS generation and injection, sanitizer adversarial cases, dictionary key parity); `test/` also holds headless-browser walk scripts that verify the card and its interactions in a real page
65
+ - The client bundle may only require modules from the shell's static table (`react`, `react/jsx-runtime`, `react-dom`, `@deepseek-ai/cordis`, `@deepseek-ai/dsh-client-*`…); `dsh.client.inject` declares load order, not require permission
66
+ - Editing `src/client.js` is enough after a page refresh (client modules are versioned by content hash and DSH's client HMR pushes reloads); editing the host half (`src/index.mjs`) or `cordis.patch.yml` needs a DSH restart
75
67
 
76
68
  ## License
77
69
 
78
- MIT
70
+ MIT © 2026 LyaxZ
package/README.md CHANGED
@@ -1,108 +1,70 @@
1
1
  # dsh-fonttune
2
2
 
3
- DeepSeek Harness(DSH)Web GUI 的字体增强插件:**正文/代码字体族 + 全局字号偏移 + 全局字重**,设置入口在 **设置 → 插件 → 插件配置**(原生的插件配置卡片),改完即时生效。
3
+ > [English](README.en.md) | **中文**
4
4
 
5
- English: [README.en.md](README.en.md)
5
+ **DeepSeek Harness(DSH)字体插件**:设置正文与代码的字体族、全局字号偏移与字重,并按「西文 / 中文」分栏挑字体;配置入口是 **设置 → 插件 → 插件配置** 里的原生卡片,改完即时生效。
6
6
 
7
- ## 为什么不是"纯客户端插件"
7
+ ## 功能
8
8
 
9
- 设计文档最初定的是纯客户端 + localStorage。实测后改成**双半(host + client)**,原因有三条,都是本机验证过的:
9
+ - **正文 / 代码字体** —— 两套独立的字体回退列表,拉丁字体在前、中文字体在后;留空表示完全沿用 DSH 的字体栈
10
+ - **全局字号偏移** —— -3 ~ +6 px,与 DSH 自己的「字号大小」叠加而不是覆盖;每一档字号连同它的行高一起等比缩放
11
+ - **全局字重** —— 300 ~ 600 任意整数;未设置或 400 都表示沿用 DSH 原本的字重
12
+ - **西文 / 中文分栏(简单模式)** —— 卡片顶部一个开关:简单模式只给「西文」「中文」两个单选格(正文/代码各一对),高级模式是完整的字体栈编辑器;两种模式共用同一条栈,来回切换不会改动已排好的顺序
13
+ - **选字体面板** —— 内置 等宽 / 中文(CJK)/ 拉丁 / 通用 四组预设,Chromium 下再补上「本机已安装」分组;搜索不到的名字可以直接「使用 xxx」新建
14
+ - **拖拽排序** —— 已选字体是 chip 列表,可拖动调整回退顺序,同时保留前移 / 后移按钮(键盘与触屏可用)
15
+ - **实时预览** —— 中英混排与代码两行,随当前配置即时渲染
16
+ - **松手才生效** —— 字号与字重滑块拖动时只更新读数,松手(或键盘抬起 / 失焦)才写入设置,拖动过程不卡
17
+ - **首帧不闪字体** —— 宿主半把已保存的声明随页面一起下发,首屏就是设置里的字体
18
+ - **中英双语** —— 卡片文字跟随 DSH 的语言(中文 / English)
10
19
 
11
- | 纯客户端 | 双半(本插件) |
20
+ ## 兼容性
21
+
22
+ | 插件版本 | 支持的 DSH 版本 |
12
23
  | --- | --- |
13
- | 插件配置页进不去——`settings.plugin.item` 这个槽是**按 host 注册的 settings namespace 派发**的(`settings-plugins` 的 slot-contract 与 `ConfigurablePluginsTab` 类型都写明这点),没有 host 半就没有 key,卡片永远不会被渲染 | 卡片出现在原生的插件配置页里,保存/重置走 DSH 自己的设置文档 |
14
- | 首帧闪一帧默认字体(客户端插件是异步加载的) | host 半监听 `webserver/index-inject`,把同样的声明塞进 index `<head>`,**首帧就是对的字体** |
15
- | 设置只存 localStorage,清缓存即丢,且不在 `settings.yaml` 里 | 存进 Host 设置文档(`settings.yaml`),与其它偏好一起 |
24
+ | **0.1.1**(最新) | 0.1.5-rc.2 |
16
25
 
17
- 而文档担心的"host 必须重启"在本机不成立:web profile `patchReload: "live"`,插件行增删热生效。真正需要重启的只有"安装那一刻"(要跑 `dsh plugin add` 把包放进 profile)。
26
+ `engines.dsh` 下限为 **0.1.5-rc.2**,兼容声明只列 **0.1.5 线的最新版本**:它包含这条线的全部修复,是同一大版本里最稳的一版,而同一大版本内的旧版本按语义化版本约定向上兼容。更早或更新的 DSH 未经验证,不作声明。安装或更新时,DSH 市场会依据 `package.json` 里的 `engines.dsh`、`dsh.compatibility.dshReleases` `peerDependencies` 做宿主兼容预检。
18
27
 
19
28
  ## 安装
20
29
 
21
- ```powershell
22
- # 发布后:直接从 npm 装(需要重启一次 DSH 让 bundle 进 boot graph)
23
- dsh plugin --profile web add dsh-fonttune
30
+ 通过 DSH CLI 安装:
24
31
 
25
- # 本机开发:junction 到源码目录,再往 profiles\web\cordis.patch.yml 的
26
- # insert 列表加一行 - id: fonttune / name: dsh-fonttune
27
- dsh plugin --profile web add link:F:\deepseek harness\dsh-fonttune
28
32
  ```
29
-
30
- 装完重启一次 `dsh web` 即可,之后改设置不再需要重启。
31
-
32
- ## 四个调节轴
33
-
34
- | 轴 | 范围 | 默认 | 说明 |
35
- | --- | --- | --- | --- |
36
- | 正文字体(sans) | 任意长度的 fallback 列表 | 空 = 不动 | 拉丁字体在前、中文字体在后;空表示完全沿用 DSH 的字体栈 |
37
- | 代码字体(mono) | 同上 | 空 = 不动 | 作用于 `pre/code/kbd/samp/var/tt/textarea` 与 CodeMirror 编辑区 |
38
- | 字号偏移 | -3 ~ +6 px | 0 = 不动 | 全局等比缩放,与 DSH 自己的"字号大小"叠加 |
39
- | 字重 | 300 ~ 600 任意整数 | 未设置 = 不动 | 400 即 DSH 原本的正文字重,同样视为"不动" |
40
-
41
- 两个数值滑块都是**拖动过程零写入**:拖动只更新本地显示,松手(`pointerup`/触屏松开,或键盘松键/失焦)才一次性提交并生效——拖到哪都不会卡,松手即到位。
42
-
43
- 选字体面板:内置 **等宽 / 中文(CJK)/ 拉丁 / 通用** 四组预设,Chromium 下再用 `queryLocalFonts()` 补上"本机已安装";搜索不到的名字可以直接"使用 xxx"新建。已选字体是 **chip 列表**,支持 **拖拽排序**(并保留 ‹ › 键盘/触屏按钮),每项用其自身字体渲染,下方还有中英混排 + 代码的实时预览。
44
-
45
- ### 中西分家(简单模式 / 高级模式)
46
-
47
- 卡片顶部的开关行(左"编辑方式"说明 + 右侧简单/高级分段切换):
48
-
49
- - **简单模式**:把栈拆成「西文字体」「中文字体」两个单选格(正文/代码各一对)。语义是"只动最前面"——西文格 = 栈里第一个非中文项,改选**原地替换**;中文格 = 第一个中文项,改选原地替换、栈里还没有中文项时**紧跟西文槽插入**;两格之外的项与顺序**原样保留**("其余回退项"一行可见)。中文判定以名字启发式优先(未安装的字体也能正确归入中文槽——canvas 测宽对没装的字体必然误判,只作补充手段)。
50
- - **高级模式**:完整的 chips 编辑器,拖拽排序。
51
- - **切换模式零写入**:两种视图共享同一条栈,来回切换不会改动你排好的顺序;视图偏好存在浏览器本地。
52
-
53
- ## 字号偏移是怎么实现的
54
-
55
- 关键点:DSH 的字号不是"一个全局字号",而是**运行时生成的一堆 CSS 自定义属性**——
56
-
57
- - `--dsh-content-font-size`:会话内容字号,由 `dsh-client-ui-theme` 写在 `body` 的**内联样式**上(设置里那个"字号大小"滑块),`--dsh-content-font-delta` 等由它派生;
58
- - `--dsw-font-*-font-size` / `-line-height`:设计系统每一档字号(`--dsw-font-s-14-*`、`--dsw-font-markdown-h1-*` …),主题插件在启动后注入。
59
-
60
- 所以直接写 `body, body * { font-size: calc(1em + 2px) !important }` 是**错的**:嵌套元素会按各自的 `1em` 反复加偏移,层级越深越大。本插件改成:
61
-
62
- ```css
63
- body, body * {
64
- --dsh-content-font-size: calc((14px) * 1.125); /* 基准值读自实时文档 */
65
- --dsw-font-s-14-font-size: calc((14px) * 1.125);
66
- --dsw-font-s-14-line-height: calc((24px) * 1.125);
67
- /* … 每个字号/行高 token 同一个比例 … */
68
- }
69
- body, body * { font-weight: 500 !important; }
33
+ dsh plugin --profile web add dsh-fonttune
70
34
  ```
71
35
 
72
- 即**把这些 token 按同一个比例重算**(`比例 = (16 + 偏移) / 16`)。好处:
73
-
74
- - 每一档字号与它自己的行高同步放大,文字不会挤进没放大的行高里;
75
- - 基准值来自 `getComputedStyle(document.body)`,所以偏移是**叠加**在 DSH 字号滑块之上的,两者不打架;
76
- - 只改 `<body>` 元素上的自定义属性,不碰 `html`,没有 `zoom` 那种视口/滚动条副作用。
77
-
78
- token 名单**不写死**:优先读同名样式表里的实际声明,再读实时计算值,最后才用内置兜底表(覆盖 0.1.5-rc.2 的全部字号 token)。判定规则是"名字以 `-font-size` / `-line-height` 结尾",所以 DSH 之后改名或增删档位也能跟上。
79
-
80
- ## 安全
36
+ 也可以从 GitHub 安装:
81
37
 
82
- 用户输入的字体名会被**按白名单消毒**:只保留字母(任意语言,含 CJK)、数字、空格、`.`、`,`、`_`、`-`,其余(引号、`{}`、`;`、`:`、`()`、`/`、`<>`、反斜杠)全部丢弃后再整体加引号。所以手输 `Arial"; } body { background: url(x) }` 只会变成家族名 `"Arial body background urlx"`,不可能闭合声明、另起规则或触达 `url()`。Host 侧 schema 另有 `^[^{};<>\\]*$` 与长度上限兜底。
38
+ ```
39
+ dsh plugin --profile web add github:LyaxZ/dsh-fonttune
40
+ ```
83
41
 
84
- ## 开发
42
+ 或以本地目录安装:
85
43
 
86
- ```powershell
87
- node build.mjs # 构建 lib/(零依赖,无需 bundler)
88
- node build.mjs --watch # 改 src 自动重建
89
- node test/run.mjs # 42 项离线检查(自建 DOM / cordis / 设置面替身)
44
+ ```
45
+ dsh plugin --profile web add <插件目录路径>
90
46
  ```
91
47
 
92
- 源码是纯 JavaScript,**没有任何构建依赖**:`src/shared.cjs`(纯函数核心)、`src/index.mjs`(host 半,ESM)、`src/client.js`(客户端半)。`build.mjs` 干三件事:把 shared 内联进客户端 bundle、套上 `window.__ModuleLoader__.load({id, factory})` 外壳并挂上 `exports.apply/inject`、拷贝 host 半——同时校验"只 require shell 预注入的模块"这条硬约束。
48
+ 安装后重启一次 DSH 并打开 Web UI;之后改设置不需要重启。
93
49
 
94
- ### 客户端模块约束(踩过的坑)
50
+ ## 使用
95
51
 
96
- - 浏览器半能 `require` 的**只有** shell 静态表里的词:`react`、`react/jsx-runtime`、`react-dom`、`react-dom/client`、`@deepseek-ai/cordis`、`@deepseek-ai/dsh-client-store`、`@deepseek-ai/dsh-client-ui-slots`、`@deepseek-ai/dsh-client-ui-primitives`、`@deepseek-ai/dsh-client-ui-dockkit`(见 `dsh-web-frontend` 里的静态表与 `dsh-client-modules` 的解析顺序:seed 已物化记录已注册 factory,**miss 直接抛错**)。
97
- - 客户端插件的 `ctx` **没有** `ctx.inject` 之外的花样:`ctx.effect / on / once / provide / timer` 是白名单动词;要拿别的服务用 `ctx.get(name)`(本插件只声明 `inject: ["slots", "locale", "settingsScope"]`)。
98
- - host 半里 `import shared from "./shared.cjs"` **必须是默认导入**:具名导入会走 Node 的 CJS 静态导出探测,`dsh-settings` 解析 namespace 时会直接抛 `Named export 'FALLBACK_TOKENS' not found`,整半起不来。
99
- - `package.json` 千万不要带 BOM(`Set-Content -Encoding UTF8` 会加),DSH 的 loader 直接 `JSON.parse` 会整树炸掉。
52
+ - **打开设置** —— 设置 插件插件配置展开「字体增强」卡片
53
+ - **换字体** —— 简单模式下点「正文 · 西文字体」「正文 · 中文字体」「代码 · 西文字体」「代码 · 中文字体」四个格子选字体;高级模式下用「添加字体」与 chips 编辑器维护完整回退列表
54
+ - **调整数值** —— 拖字号偏移 / 字重滑块,松手即生效;改过的字段标「已修改」并可单独重置,卡片底部有「全部重置」
55
+ - **预览** —— 卡片底部的中英混排与代码预览用当前配置渲染
56
+ - 设置保存在 DSH 的设置文档里(`settings.yaml`),跟随配置走
100
57
 
101
- ## 兼容性
58
+ ## 开发
102
59
 
103
- - DSH `0.1.5-rc.2`(`dsh.compatibility.dshReleases` 已声明)。
104
- - 若同时启用其它写 `body` 字体族的插件(如设计文档里提到的 `dsh-ui-font`),后加载的赢,**不要同时开**;本插件可完全替代它(多了字号/字重/中西分家/拖拽排序/中文预设)。
60
+ - `src/shared.cjs` —— 纯函数核心:字体名消毒与解析、配置归一化、注入样式的生成
61
+ - `src/index.mjs` —— 宿主半:注册 `dsh-fonttune` 设置命名空间(schemastery schema,含长度与取值范围校验),并通过 `webserver/index-inject` 把已保存的声明随首页下发,首帧即是设置里的字体
62
+ - `src/client.js` —— 浏览器半:设置卡片、选字体面板、字体枚举与样式注入
63
+ - `build.mjs` —— 零依赖构建:内联共享核心、套上 `window.__ModuleLoader__.load({id, factory})` 外壳、拷贝宿主半,并校验客户端 bundle 只 require shell 预注入的模块
64
+ - `test/run.mjs` —— 离线检查(自建 DOM / cordis / 设置面替身、真实 schemastery schema、CSS 生成与注入、消毒对抗用例、双语文案键一致性);`test/` 下另有几个无头浏览器走查脚本,用真实页面验证卡片渲染与交互
65
+ - 客户端模块能 require 的只有 shell 静态表里的模块(`react`、`react/jsx-runtime`、`react-dom`、`@deepseek-ai/cordis`、`@deepseek-ai/dsh-client-*` 等);`dsh.client.inject` 只是加载顺序声明,不是 require 许可
66
+ - 改 `src/client.js` 后刷新页面即可看到变化(客户端模块按内容哈希发版,DSH 的客户端 HMR 也会推送重载);改宿主半(`src/index.mjs`)或 `cordis.patch.yml` 需重启 DSH
105
67
 
106
- ## 许可
68
+ ## License
107
69
 
108
- MIT
70
+ MIT © 2026 LyaxZ
package/lib/client.js CHANGED
@@ -760,7 +760,7 @@ var MAX_VISIBLE_FONTS = 240;
760
760
 
761
761
  var DICTS = {
762
762
  en: {
763
- "card.title": "Font plus",
763
+ "card.title": "Font tune",
764
764
  "card.description":
765
765
  "UI and code font families, a global size offset, and font weight",
766
766
  "card.expand": "Expand",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-fonttune",
3
- "version": "0.1.0",
4
- "description": "DeepSeek Harness (DSH) Web GUI plugin: UI and code font families plus a global font-size offset and font weight, configured from Settings -> Plugins -> Plugin configuration and stored in the Host settings document",
3
+ "version": "0.1.2",
4
+ "description": "Font plugin for the DeepSeek Harness Web GUI: body and code font families, a global font-size offset, a global font weight, and a West/CJK split picker.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "exports": {
@@ -15,6 +15,7 @@
15
15
  "README.md",
16
16
  "README.en.md",
17
17
  "CHANGELOG.md",
18
+ "CHANGELOG.en.md",
18
19
  "LICENSE"
19
20
  ],
20
21
  "engines": {