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.
- package/CHANGELOG.en.md +48 -0
- package/CHANGELOG.md +39 -32
- package/README.en.md +44 -52
- package/README.md +44 -82
- package/lib/client.js +1 -1
- package/package.json +3 -2
package/CHANGELOG.en.md
ADDED
|
@@ -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
|
-
#
|
|
1
|
+
# 更新日志
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**dsh-fonttune** 的重要变更都记录在这里。英文版见 [CHANGELOG.en.md](CHANGELOG.en.md)。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## [0.1.2] - 2026-09-14
|
|
6
6
|
|
|
7
|
-
###
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
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
|
-
|
|
3
|
+
> [中文](README.md) | **English**
|
|
4
4
|
|
|
5
|
-
|
|
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
|
-
##
|
|
7
|
+
## Features
|
|
8
8
|
|
|
9
|
-
|
|
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
|
-
|
|
20
|
+
## Compatibility
|
|
21
|
+
|
|
22
|
+
| Plugin version | Supported DSH versions |
|
|
12
23
|
| --- | --- |
|
|
13
|
-
|
|
|
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
|
-
|
|
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
|
-
|
|
22
|
-
# from npm (after publishing)
|
|
23
|
-
dsh plugin --profile web add dsh-fonttune
|
|
30
|
+
Install through the DSH CLI:
|
|
24
31
|
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
```
|
|
39
|
+
dsh plugin --profile web add github:LyaxZ/dsh-fonttune
|
|
40
|
+
```
|
|
50
41
|
|
|
51
|
-
|
|
42
|
+
Or from a local directory:
|
|
52
43
|
|
|
53
|
-
|
|
44
|
+
```
|
|
45
|
+
dsh plugin --profile web add <plugin directory>
|
|
46
|
+
```
|
|
54
47
|
|
|
55
|
-
|
|
48
|
+
Restart DSH once afterwards and open the Web UI; changing settings needs no restart after that.
|
|
56
49
|
|
|
57
|
-
##
|
|
50
|
+
## Usage
|
|
58
51
|
|
|
59
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
3
|
+
> [English](README.en.md) | **中文**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**DeepSeek Harness(DSH)字体插件**:设置正文与代码的字体族、全局字号偏移与字重,并按「西文 / 中文」分栏挑字体;配置入口是 **设置 → 插件 → 插件配置** 里的原生卡片,改完即时生效。
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## 功能
|
|
8
8
|
|
|
9
|
-
|
|
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
|
-
|
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
38
|
+
```
|
|
39
|
+
dsh plugin --profile web add github:LyaxZ/dsh-fonttune
|
|
40
|
+
```
|
|
83
41
|
|
|
84
|
-
|
|
42
|
+
或以本地目录安装:
|
|
85
43
|
|
|
86
|
-
```
|
|
87
|
-
|
|
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
|
-
|
|
48
|
+
安装后重启一次 DSH 并打开 Web UI;之后改设置不需要重启。
|
|
93
49
|
|
|
94
|
-
|
|
50
|
+
## 使用
|
|
95
51
|
|
|
96
|
-
-
|
|
97
|
-
-
|
|
98
|
-
-
|
|
99
|
-
-
|
|
52
|
+
- **打开设置** —— 设置 → 插件 → 插件配置 → 展开「字体增强」卡片
|
|
53
|
+
- **换字体** —— 简单模式下点「正文 · 西文字体」「正文 · 中文字体」「代码 · 西文字体」「代码 · 中文字体」四个格子选字体;高级模式下用「添加字体」与 chips 编辑器维护完整回退列表
|
|
54
|
+
- **调整数值** —— 拖字号偏移 / 字重滑块,松手即生效;改过的字段标「已修改」并可单独重置,卡片底部有「全部重置」
|
|
55
|
+
- **预览** —— 卡片底部的中英混排与代码预览用当前配置渲染
|
|
56
|
+
- 设置保存在 DSH 的设置文档里(`settings.yaml`),跟随配置走
|
|
100
57
|
|
|
101
|
-
##
|
|
58
|
+
## 开发
|
|
102
59
|
|
|
103
|
-
-
|
|
104
|
-
-
|
|
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
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-fonttune",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "DeepSeek Harness
|
|
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": {
|