dsh-fonttune 0.2.7 → 0.3.1

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 CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  All notable changes to **dsh-fonttune** are documented here. Chinese version: [CHANGELOG.md](CHANGELOG.md).
4
4
 
5
+ ## [0.3.1] - 2026-09-28
6
+
7
+ ### Fixed
8
+ - **The upper positions of the weight slider jumped to a lower number**: two of them were read as an absolute weight and converted, so the third step showed as −1 and the fourth rendered exactly like 0. A position now stays where it is put.
9
+ - **With the conversation weight at 0, the conversation still picked up the interface offset**: the two axes shared a range, so 0 carried the interface's offset as well and the 0 and +1 positions looked nearly the same. Each axis now keeps to its own scope, and 0 is DSH's own weight.
10
+ - **The line-height preview in the card was taller at 100% than at the notches above it**: the preview and the conversation did not share a base. They do now, so every notch is taller in the preview as well.
11
+
12
+ ### Changed
13
+ - **The weight slider's positions and step come from the font**: one step is one pair of neighbouring faces, and the range starts where body text and bold text can still swap faces — a family whose body text has more weights gets more positions (the range is no longer held back by the heading layer), and the heading layer stops once it is at its boldest; changing the family measures it again.
14
+
15
+ ## [0.3.0] - 2026-09-28
16
+
17
+ ### Fixed
18
+ - **Markdown headings stopped being bold once a conversation weight was set**: the weight was one value for the whole conversation, so any setting flattened the headings down to roughly body weight. The offset now adds to each element's own weight, so headings stay clearly bolder than body text at any step and bold text stays bold.
19
+ - **H1/H2 looked too small while H3 looked right once a conversation size offset was set**: the heading ladder was asymmetric under an offset, the larger headings moving further. The offset now lands once, the whole ladder follows it, and h1 > h2 > h3 > h4 holds at any offset.
20
+ - **Dragging the weight occasionally snapped the number back, and the next adjustment did not apply**: with a slow write, the previous value could cover the value being dragged. The value under the drag is now kept, and two adjustments in a row are both written.
21
+ - **A plus sign appeared in front of the number on release**: the readout while dragging and the readout after landing were written differently. They match now.
22
+
23
+ ### Changed
24
+ - **The three weight axes are one control now, and they count steps**: conversation, interface and code all take an offset on each element's own weight, and the slider is divided into the weights the current font **can actually render** — the readout is the step count (for example `-2 … +4`, 0 keeps DSH's own weights), a font with more weights offers more steps, and every notch is a visible change; changing the font measures it again.
25
+ - **An absolute weight stored by an older version is converted automatically** (400 → 0, 450 → +1), so nothing has to be set again, and changing the font never invalidates an existing setting.
26
+
5
27
  ## [0.2.7] - 2026-09-24
6
28
 
7
29
  ### Changed
package/CHANGELOG.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  **dsh-fonttune** 的重要变更都记录在这里。英文版见 [CHANGELOG.en.md](CHANGELOG.en.md)。
4
4
 
5
+ ## [0.3.1] - 2026-09-28
6
+
7
+ ### 修复
8
+ - **字重滑块偏上的档位会跳到较小的数值**:此前有两个档位会被换算成别的数值,表现为拖到第三档显示成 −1、第四档与 0 档的粗细看起来完全一样。现在拖到哪一档就停在哪一档。
9
+ - **「对话字重偏移」为 0 时,对话还是会跟着「界面字重偏移」一起变粗**:两个轴的范围互相串了,界面设了偏移时对话的 0 档也带上了那个偏移,于是 0 与 +1 两档看起来几乎一样。现在每个轴只管自己的范围,0 档就是 DSH 原样。
10
+ - **卡片里的行高预览在 100% 时比更高的档位还高**:预览与真实对话用的不是同一个基准。现在两者一致,预览里也是每一档都更高。
11
+
12
+ ### 变更
13
+ - **字重滑块的档位与档距按字体实测**:一档就是字体相邻的两张字形,范围从「正文与加粗文字都还能换到字形」的地方起算——正文字重档位多的字体给更多档位(正文能走的范围不再被标题压小),标题那一层到顶后停住;换字体会重新测量。
14
+
15
+ ## [0.3.0] - 2026-09-28
16
+
17
+ ### 修复
18
+ - **设了「对话字重」之后,Markdown 标题不再加粗**:此前字重是整段一个值,调重调轻都会把标题压到接近正文的粗细、层级被抹平。现在偏移叠加在每个元素自己的粗细上,标题在任何档位都明显粗于正文,加粗文字也仍然加粗。
19
+ - **设了「对话字号偏移」之后,H1/H2 偏小、H3 正常**:标题阶梯在偏移下不对称,越大的标题偏得越多。现在偏移只加一次,整条阶梯一起跟随,任意偏移下都保持 h1 > h2 > h3 > h4。
20
+ - **拖动字重时读数偶尔跳回旧值、紧接着的调整不生效**:写入较慢时,上一次的值会盖住正在拖动的值。现在拖动中的值保持不变,连续两次调整都会写入。
21
+ - **松手瞬间读数前面多出一个加号**:拖动过程与落定之后的读数写法不一致。现在两者一致。
22
+
23
+ ### 变更
24
+ - **三个字重轴统一,并按档调整**:对话、界面与代码都改成「在每个元素自身粗细上叠加」的偏移,滑块按当前字体**实际能渲染的粗细分档**——读数就是档数(例如 `-2 … +4`,0 表示保持 DSH 原样),字体有几档就有几档,每挪一格都是一次看得见的变化;换字体后档数会重新测量。
25
+ - **旧版本存的绝对字重会自动换算**(400 → 0、450 → +1),不需要重设;换字体也不会让已有设置失效。
26
+
5
27
  ## [0.2.7] - 2026-09-24
6
28
 
7
29
  ### 变更
package/README.en.md CHANGED
@@ -8,11 +8,11 @@
8
8
 
9
9
  - **Three typography sets** — the conversation (markdown paragraphs, tables, headings) comes first and owns every axis; the interface (settings sheet, sidebars, workspace, headings and buttons) offers **a font and a weight** and follows the conversation by default (switchable); code stays its own axis
10
10
  - **Interface / conversation / code fonts** — three independent fallback lists, Latin families first and CJK after; leaving one empty keeps DSH's own stack untouched
11
- - **Font-size offsets** — the **conversation** takes -3 ~ +6 px on top of DSH's own "conversation font size" (the official value is the base), moving paragraphs, headings and line heights together; code is its own axis at -3 ~ +6 px. **The interface has no size axis**: verified against DSH, the settings sheet, sidebars and workspace size their text in upstream CSS, and the only official size hook is the conversation one
12
- - **Font weights** — the **conversation**, the **interface** and **code** each take any integer from 300 to 600 (unset reads 400 in the UI). The interface weight is one `body, body *` rule with the whole conversation markdown subtree excluded: measured against computed styles on a live page, it takes every interface text element to the chosen weight and moves nothing inside the markdown subtree, so **changing the interface weight never touches the conversation** (its bold text and heading weights survive too)
11
+ - **Font-size offsets** — the **conversation** takes -3 ~ +6 px on top of DSH's own "conversation font size" (the official value is the base), moving paragraphs, headings and line heights together — and it is applied **once, at the source** (H1/H2/H3 all derive from the same delta, so the hierarchy holds at any offset and no heading comes out smaller than expected); code is its own axis at -3 ~ +6 px. **The interface has no size axis**: verified against DSH, the settings sheet, sidebars and workspace size their text in upstream CSS, and the only official size hook is the conversation one
12
+ - **Font-weight offsets** — the **conversation**, the **interface** and **code** all take the same **relative offset** (-100 ~ +200, unset reads 0 and the readout is signed): the offset is added to each element's **own** weight, so the heading hierarchy DSH ships (h1~h3 700, h4~h6 and bold 600, table head 500, body 400) survives in both directions — headings stay clearly bolder than body text at any setting, and bold text inside a code surface stays bold. The interface offset is one rule over `body` plus an element table, with the whole conversation markdown subtree excluded: measured against computed styles on a live page, it takes every interface text element to the target and moves nothing inside the markdown subtree, so **changing the interface weight never touches the conversation**. The slider **counts steps**: the readout is the step count (for example `-1 0 +1`) and **the font decides how many there are** — the card measures how many distinct weights the chosen family can render for body text and for bold text, so one step is one pair of neighbouring faces and the range ends where those two stop swapping faces (the heading layer stops once it is at its boldest) — every notch is a visible change and the numbers stay small. What is stored is still a weight offset (older values are converted), so changing the font never breaks a setting; a family with only regular and bold offers three positions in total, and continuous control needs a family with more weights or a variable font
13
13
  - **Line heights** — the **conversation** uses a ratio (100% ~ 160%), code an additive offset (-4 ~ +8 px); the interface has no line-height axis, for the same reason as size
14
14
  - **Code ligatures** — a three-mode switch (default / on / off; browsers enable them by default, turning them off restores `=>` and `!=` as plain characters), plus an advanced `font-feature-settings` value field
15
- - **Refuse synthetic styles** — stops the browser from faking italic and bold for CJK faces, which have neither, so marked text stays upright
15
+ - **Refuse synthetic styles** (off by default, i.e. synthesis is allowed) — turning it on stops the browser from faking italic and bold for CJK faces, which have neither, so marked text stays upright; left off, the browser synthesises by its own rules, which at least gives a visible "bold" step for a family with no bold face
16
16
  - **The interface-follows-conversation switch** — a "Follows the conversation" switch at the top of the interface section (on by default): on, the interface takes the conversation's **font and weight** and its own two controls stay hidden; off, it uses its own font and weight, independent of the conversation. Size and line height belong to the conversation only (the interface has no hooks for them)
17
17
  - **Presets** — a dropdown select right under the edit mode: five built-in presets out of the box, pick one to apply it; with a preset selected every change auto-saves into it, and "Rename / Export / Import" manage the list (export as JSON, import-merge a paste). When the clipboard is unavailable (a non-secure context, or no clipboard permission) the export does not print a truncated message: the whole JSON goes into a selected, read-only box, so the copy shortcut works, and the box puts itself away once copied. A settings write the document **refuses** is reported on the same row instead of leaving the control quietly showing the old value
18
18
  - **West / CJK split (simple mode)** — an edit-mode switch: simple mode gives just a Western and a CJK single-pick slot per set, advanced mode is the full stack editor; both views share one stack, so toggling never changes the order you set up
@@ -26,7 +26,9 @@
26
26
 
27
27
  | Plugin version | Supported DSH versions |
28
28
  | --- | --- |
29
- | **0.2.7** (latest) | 0.1.5-rc.3, 0.1.7-alpha.1 / alpha.2, 0.1.7-rc.1 / rc.2 |
29
+ | **0.3.1** (latest) | 0.1.5-rc.3, 0.1.7-alpha.1 / alpha.2, 0.1.7-rc.1 / rc.2 |
30
+ | 0.3.0 | 0.1.5-rc.3, 0.1.7-alpha.1 / alpha.2, 0.1.7-rc.1 / rc.2 |
31
+ | 0.2.7 | 0.1.5-rc.3, 0.1.7-alpha.1 / alpha.2, 0.1.7-rc.1 / rc.2 |
30
32
  | 0.2.6 | 0.1.5-rc.3, 0.1.7-alpha.1 / alpha.2, 0.1.7-rc.1 |
31
33
  | 0.2.5 | 0.1.5-rc.1 / rc.2 / rc.3, 0.1.7-alpha.1 / alpha.2 |
32
34
  | 0.2.4 | 0.1.5-rc.1 / rc.2 / rc.3, 0.1.7-alpha.1 / alpha.2 |
@@ -75,12 +77,13 @@ Restart DSH once afterwards and open the Web UI; changing settings needs no rest
75
77
  - **Pick fonts** — in simple mode click the Western/CJK slots; in advanced mode use "Add font" and the chip editor to maintain the full fallback list
76
78
  - **Tune size / weight / line height** — each slider sits inside its own section; drag and release to apply (the readout keeps its unit while dragging). Changed fields are marked and can be reset individually, with "Reset all" at the bottom of the card
77
79
  - **The conversation leads** — the conversation section sets font, size, line height and weight; the interface section shows a single "Follows the conversation" row by default, and its own font and weight controls appear once that is switched off
78
- - **Switching following off never jumps** — the moment the switch goes off, the interface writes the font and weight it was **already showing** into its own fields (that is what it was following), so nothing changes on screen and the sliders continue from there; an axis the conversation does not set clears the interface's own field instead, keeping DSH's default. "Reset" on that field goes back to DSH's own weight (the readout returns to 400)
80
+ - **Switching following off never jumps** — the moment the switch goes off, the interface writes the font and weight offset it was **already showing** into its own fields (that is what it was following), so nothing changes on screen and the sliders continue from there; an axis the conversation does not set clears the interface's own field instead, keeping DSH's default. "Reset" on that field goes back to DSH's own weight (all three weight offsets return to 0)
79
81
  - **The interface weight cannot reach the conversation** — it is the one axis that has to cover the whole page (DSH pins its small labels' weights in upstream class rules, which nothing narrower can reach), so it is implemented as a rule with the **whole conversation markdown subtree excluded**: paragraphs, headings and bold text in the conversation are untouched
80
- - **Weight readouts** — an unset weight reads 400 (DSH's own body weight, which is where the slider sits); no "unset" wording appears anywhere
82
+ - **Weight readouts** — all three weight axes read 0 when unset (the slider sits in the middle); no "unset" wording appears anywhere, and an absolute weight stored by an older version (300 ~ 600) is converted to its equivalent offset on read (400 → 0, 450 → +50), so nothing has to be set again
83
+ - **The weight slider counts steps** — the card measures how many distinct weights the current family can render for body text and for bold text, one step being one pair of neighbouring faces, and the range ending where those two stop swapping faces (the readout is the step count, e.g. `-2 … +2`), so every notch is a visible change and the numbers stay small; changing the family re-measures it
81
84
  - **Presets** — the dropdown select below the edit mode (默认配置 1 ~ 5, with the card's own chevron inside the box); picking one switches and auto-saves the edits that follow. "Rename" renames the current preset, "Export" copies JSON and "Import" merges a paste. Operation results ("copied to the clipboard") appear on the **right** of the row below and fade out by themselves after about 2.6 s, without moving any layout
82
85
  - **Preview** — expanding the conversation / interface / code section ends with that section's own preview box, rendering just that part
83
- - Settings are stored in DSH's settings document (`settings.yaml`), so they travel with your configuration
86
+ - Settings are stored in DSH's settings document (the profile's `cordis.patch.yml` from 0.1.7 on, `settings.yaml` before that), so they travel with the profile
84
87
 
85
88
  ## Development
86
89
 
@@ -91,7 +94,7 @@ Restart DSH once afterwards and open the Web UI; changing settings needs no rest
91
94
  - `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, the picker's grouping rules, the token-refresh power gate); `test/render-card.mjs` renders the card component through a mini React hooks runtime (including forced-open and forced-state renders, covering the 0.1.0 release-blocking crash class), fires **every control's callback** (an unwired handler only fails when someone actually clicks it) and **renders a second time** to cover a hook order that changes with state; `test/artifacts.mjs` proves `lib/` matches the current `src/` byte for byte (`npm run verify` runs all three). The devDependency is the **newest** schemastery (`^3.18.4`) — the alpha's dialect, whose `.volatile()` makes a resolved field a **reference** rather than a value — so these suites read values through the `plainConfigValue` the host half exports, the same path the plugin takes; at runtime the **host's own copy** is used (3.18.2 on rc.2 / rc.3, with no such modifier, a shape the live probe covers)
92
95
  - Checks that need a real page run through `npm run verify:browser -- "<url-with-token>"` (start a managed instance first: `dsh web --port 0 --no-open` prints the URL). The default group is read-only (`browser-probe` / `ui-walk` / `host-line-probe` / `style-verify`); `--writers` adds the scripts that **write the settings namespace** (`slider-walk` / `split-walk` / `split-verify` / `weight-verify`, each snapshots the user layer first and restores it before exiting), and `--only a,b` picks a subset. Every script's exit code is its verdict; `test/set-user-layer.mjs <url> '<json>'` puts the layer back after an interrupted run
93
96
  - `test/host-line-probe.mjs` is the **host-line-independent** check: it asserts only what must hold on every supported line — the page boots without errors, the plugin owns exactly ONE stylesheet element, the settings really reach the document (`DFP_EXPECT_FAMILY` / `DFP_EXPECT_WEIGHT` also assert the computed values when set), the configuration card is reachable from the settings sheet and renders (`.dfp-card`, whichever seat that line declares), and changing a control there really writes through. Run it first after switching host lines (rc ↔ alpha); set `DFP_PROBE=1` when debugging "the card's writes do not stick on the alpha" — the plugin then logs one `[dfp-probe]` line (which namespaces are served, which one was claimed, and what state the seat is in)
94
- - `test/weight-verify.mjs` measures all three weight axes (interface / conversation / code) in a live page, including that there is only one stylesheet element and that switching following off drops the followed weight without a reload; `test/split-verify.mjs` measures the conversation and code size axes plus the **retired interface size axis moving nothing**; `test/slider-walk.mjs` and `test/split-walk.mjs` drive the real card (a drag writes nothing, a release does; the simple-mode slots and the whole stack round-trip); the market-entry tooling is `test/market-pr.mjs` (status / update / refresh / reopen / open / about) and the diagnostic `test/market-inspect.mjs` (PR state, comments, CI and branch diff)
97
+ - `test/weight-verify.mjs` measures all three weight axes (interface / conversation / code) in a live page, including that there is only one stylesheet element and that switching following off drops the followed offset without a reload, and it asserts the **conversation ladder level by level** (at +180 and at −100, h2 > strong > body text, each group equal to its own base plus the offset); `test/split-verify.mjs` measures the conversation and code size axes plus the **retired interface size axis moving nothing**, and uses an h1~h4 probe to prove **every heading level takes the offset exactly once** (±3, with `h1 > h2 > h3 ≥ h4`); `test/slider-walk.mjs` and `test/split-walk.mjs` drive the real card (a drag writes nothing, a release does; the simple-mode slots and the whole stack round-trip); the market-entry tooling is `test/market-pr.mjs` (status / update / refresh / reopen / open / about) and the diagnostic `test/market-inspect.mjs` (PR state, comments, CI and branch diff)
95
98
  - `docs/` — the 0.2.0 [research](docs/research-0.2.0.md) and [specification](docs/spec-0.2.0.md) records (written during design, with the trade-offs of that moment; where they differ from what shipped, README/CHANGELOG win — see the note at the top of each). **Not part of the npm `files` list, so they are not published**
96
99
  - 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
97
100
  - Build before refreshing: `node build.mjs` (or `npm run watch`) turns `src/` into `lib/`, and the browser loads `lib/` — editing `src/client.js` without building leaves the page on the previous bundle. `npm test` only checks behaviour; `node test/artifacts.mjs` (part of `npm run verify`) proves the committed `lib/` is byte-for-byte what the current `src/` produces. Editing the host half (`src/index.mjs`) or `cordis.patch.yml` needs a DSH restart
package/README.md CHANGED
@@ -8,11 +8,11 @@
8
8
 
9
9
  - **三套排印**:对话(会话 Markdown 正文、表格与标题)排在第一位、拥有全部轴;界面(设置页、侧栏、工作区与标题按钮)提供**字体与字重**、默认跟随对话(可关);代码独立成轴
10
10
  - **界面 / 对话 / 代码字体** —— 各自独立的字体回退列表,拉丁字体在前、中文字体在后;留空表示完全沿用 DSH 的字体栈
11
- - **字号偏移** —— **对话**字号 -3 ~ +6 px,加在 DSH 自己的「对话字号」之上(官方数值是基准),段落、标题与行高一起跟随;代码字号独立成轴,-3 ~ +6 px。**界面没有字号轴**:经实测 DSH 的设置页、侧栏与工作区把字号写死在上游 CSS 里,唯一官方字号接口就是「对话字号」
12
- - **字重** —— **对话**、**界面**与**代码**各自 300 ~ 600 任意整数(未设置即 400,读数就显示 400)。界面字重是一条把对话 Markdown 整棵子树排除在外的 `body, body *` 规则:真机实测(活页面计算样式)它把界面的文本元素全部改到目标字重、对话 markdown 里的元素一个都没动,所以**改界面字重不会碰到对话**(对话的粗体、标题粗细也原样保留)
11
+ - **字号偏移** —— **对话**字号 -3 ~ +6 px,加在 DSH 自己的「对话字号」之上(官方数值是基准),段落、标题与行高一起跟随,且**只在源头加一次**(H1/H2/H3 的尺寸都由同一条 delta 派生,任意偏移下层级都不变、也不会出现某个标题偏小);代码字号独立成轴,-3 ~ +6 px。**界面没有字号轴**:经实测 DSH 的设置页、侧栏与工作区把字号写死在上游 CSS 里,唯一官方字号接口就是「对话字号」
12
+ - **字重偏移** —— **对话、界面与代码都是同一种相对偏移**(-100 ~ +200,未设置即 0、读数按 `+n` / `-n` 显示):偏移叠加在每个元素**自身的**字重上,标题仍按 DSH 的层级(h1~h3 700、h4~h6 与加粗 600、表头 500、正文 400)逐级保持"标题明显粗于正文",调重调轻都不会把层级抹平,代码块里的粗体也不会被压平。界面偏移是一条把对话 Markdown 整棵子树排除在外、只铺 `body` 与自带字重的元素表的规则:真机实测(活页面计算样式)它把界面的文本元素改到目标值、对话 markdown 里的元素一个都没动,所以**改界面字重不会碰到对话**。滑块**按档计数**:读数就是档数(例如 `-1 0 +1`),**档数由字体决定**——卡片会在页面里量出所选字体在正文与加粗文字两处实际能渲染出几种粗细,一档就是相邻的两张字形,范围也以这两处还能换到字形为限(标题那一层到顶后停住),所以每挪一格都是看得见的变化,数字也不会出现"几百几百";换字体会重新测量。文档里存的仍是字重偏移(旧值自动换算),换字体不会把设置改坏;字体只有常规与粗体两档时全范围就只有 3 档,要连续可选用字重档位多的字体或可变字体
13
13
  - **行高** —— **对话**行高用倍率(100% ~ 160%);代码行高用加法偏移(-4 ~ +8 px)。界面没有行高轴(同字号的原因)
14
14
  - **代码连字** —— 三档开关(默认 / 开启 / 关闭,浏览器默认即开启,关闭可还原 `=>`、`!=` 这类连字),高级模式另有 `font-feature-settings` 特性值输入
15
- - **拒绝合成样式** —— 禁用浏览器为中文伪造的斜体与粗体(中文字体没有斜体字形,浏览器会硬掰)
15
+ - **拒绝合成样式**(默认关闭 = 允许合成) —— 打开后禁用浏览器为中文伪造的斜体与粗体(中文字体没有斜体字形,浏览器会硬掰);关着(默认)时由浏览器按自己的规则合成,字体缺粗体字形时至少还能看出"粗体"这一档
16
16
  - **界面跟随对话开关** —— 界面分区顶部的「跟随对话设置」开关(默认开启):开启时界面沿用对话的**字体与字重**,界面自己的两个控件隐藏;关闭后界面用自己的字体与字重,与对话互不影响。字号与行高只属于对话(界面没有这两个接口)
17
17
  - **预设方案** —— 编辑模式正下方的下拉选择框:五个默认配置开箱即用,点开选一个即应用;选中方案后所有改动自动存入该方案,右侧「改名 / 导入 / 导出」管理方案(导出 JSON 分享、导入合并)。剪贴板不可用时(非安全上下文、或没有剪贴板权限)导出不会只给一段被截断的提示,而是把完整 JSON 放进一个已选中、只读的文本框,按复制快捷键即可,复制后自动收起;任何**写设置失败**(宿主拒绝、只读部署等)都会在当前行显示出来,而不是让控件悄悄弹回旧值
18
18
  - **西文 / 中文分栏(简单模式)** —— 编辑模式开关:简单模式每套字体只给「西文」「中文」两个单选格,高级模式是完整的字体栈编辑器;两种模式共用同一条栈,来回切换不改动已排好的顺序
@@ -26,7 +26,9 @@
26
26
 
27
27
  | 插件版本 | 支持的 DSH 版本 |
28
28
  | --- | --- |
29
- | **0.2.7**(最新) | 0.1.5-rc.3、0.1.7-alpha.1 / alpha.2、0.1.7-rc.1 / rc.2 |
29
+ | **0.3.1**(最新) | 0.1.5-rc.3、0.1.7-alpha.1 / alpha.2、0.1.7-rc.1 / rc.2 |
30
+ | 0.3.0 | 0.1.5-rc.3、0.1.7-alpha.1 / alpha.2、0.1.7-rc.1 / rc.2 |
31
+ | 0.2.7 | 0.1.5-rc.3、0.1.7-alpha.1 / alpha.2、0.1.7-rc.1 / rc.2 |
30
32
  | 0.2.6 | 0.1.5-rc.3、0.1.7-alpha.1 / alpha.2、0.1.7-rc.1 |
31
33
  | 0.2.5 | 0.1.5-rc.1 / rc.2 / rc.3、0.1.7-alpha.1 / alpha.2 |
32
34
  | 0.2.4 | 0.1.5-rc.1 / rc.2 / rc.3、0.1.7-alpha.1 / alpha.2 |
@@ -75,12 +77,13 @@ dsh plugin --profile web add <插件目录路径>
75
77
  - **换字体** —— 简单模式下点「西文/中文」格子选字体;高级模式下用「添加字体」与 chips 编辑器维护完整回退列表
76
78
  - **调整字号/字重/行高** —— 滑块就在各自分区里,拖动松手即生效(拖动时读数连同单位 % 一起显示);改过的字段标「已修改」并可单独重置,卡片底部有「全部重置」
77
79
  - **对话优先** —— 对话分区可以设置字体、字号、行高、字重四项;界面分区默认只有「跟随对话设置」开关(默认开启),关掉后才出现界面自己的字体与字重
78
- - **关掉跟随不会跳变** —— 关掉开关的那一刻,界面会把**正在显示的**字体与字重写成自己的值(跟随期间它本来就是这两项),所以画面零变化、滑块从当前值继续调;对话没设的那一项则清掉界面自己的字段、保持 DSH 默认。想回到 DSH 自己的粗细点该项的「重置」(读数会回到 400)
80
+ - **关掉跟随不会跳变** —— 关掉开关的那一刻,界面会把**正在显示的**字体与字重偏移写成自己的值(跟随期间它本来就是这两项),所以画面零变化、滑块从当前值继续调;对话没设的那一项则清掉界面自己的字段、保持 DSH 默认。想回到 DSH 自己的粗细点该项的「重置」(三个字重偏移读数都回到 0)
79
81
  - **界面字重不会碰到对话** —— 界面字重是唯一必须铺满整页的轴(DSH 把小标签的粗细写死在上游 CSS 的类规则里,窄规则够不到它),实现上是一条把**对话 Markdown 整棵子树排除在外**的规则,所以对话的段落、标题、粗体都不受影响
80
- - **字重读数** —— 未设置的读数显示 400(DSH 正文的就是 400,滑块也停在 400),不会出现「未设置」这类字眼
82
+ - **字重读数** —— 三个字重轴的未设置读数都显示 0(滑块停在正中);不会出现「未设置」这类字眼;旧版本存的绝对字重(300 ~ 600)会在读取时自动换算成等价偏移(400 → 0、450 → +50),无需手动重设
83
+ - **字重滑块按档计数** —— 卡片会量出当前字体在正文与加粗文字两处各能渲染出几档粗细,一档 = 相邻两张字形、上下限以这两处还能换字形为限(读数就是档数,如 `-2 … +2`),所以每挪一格都看得出变化、也不会出现"几百几百"的数字;换字体后档数会重新测量
81
84
  - **预设方案** —— 编辑模式下方的下拉选择框(默认配置 1 ~ 5,框内右侧有与卡片一致的下拉箭头),点开选择即切换并自动保存后续改动;「改名」重命名当前方案,「导出」复制 JSON,「导入」粘贴合并。操作结果(如「已复制到剪贴板」)显示在下面那行的**右侧**,约 2.6 秒后自动淡出,不会顶动任何布局
82
85
  - **预览** —— 对话 / 界面 / 代码分区展开后,各自分区末尾有一个预览框,只渲染该分区的样式
83
- - 设置保存在 DSH 的设置文档里(`settings.yaml`),跟随配置走
86
+ - 设置保存在 DSH 的设置文档里(0.1.7 起是 profile 的 `cordis.patch.yml`,更早的版本是 `settings.yaml`),跟随 profile 走
84
87
 
85
88
  ## 开发
86
89
 
@@ -91,7 +94,7 @@ dsh plugin --profile web add <插件目录路径>
91
94
  - `test/run.mjs` —— 离线检查(自建 DOM / cordis / 设置面替身、真实 schemastery schema、CSS 生成与注入、消毒对抗用例、双语文案键一致性、选字体面板的分组规则、令牌轮询的省电闸门);`test/render-card.mjs` 用 mini React hooks 运行时真实渲染卡片组件(含强制展开态与强制状态,覆盖 0.1.0 那类发布阻断崩溃),把**每个控件的回调都点一遍**(未接线的回调只有真点下去才会暴露),并**渲染第二次**覆盖「状态变化后 hook 顺序改变」这一类崩溃;`test/artifacts.mjs` 校验 `lib/` 与当前 `src/` 逐字节一致(`npm run verify` 跑全部三套)。devDependency 钉的是**最新的** schemastery(`^3.18.4`),也就是 alpha 那套方言——它带 `.volatile()`,解析出来的字段是**引用**而不是值,所以这几套检查都通过宿主半导出的 `plainConfigValue` 取值(和插件读配置同一条路);运行时用的是**宿主自带的那份**(rc.2/rc.3 是 3.18.2,没有该修饰符,那条形态由真机探针覆盖)
92
95
  - 需要真实页面的检查走 `npm run verify:browser -- "<带 token 的地址>"`(先起一个受管实例:`dsh web --port 0 --no-open`,它会打印地址)。默认只跑**只读**的几支(`browser-probe` / `ui-walk` / `host-line-probe` / `style-verify`);加 `--writers` 再跑会**写设置命名空间**的几支(`slider-walk` / `split-walk` / `split-verify` / `weight-verify`,各自先快照用户层、退出前还原),`--only a,b` 挑子集;每支的退出码就是判定。`test/set-user-layer.mjs <url> '<json>'` 是在被中断的运行之后还原用户层的工具
93
96
  - `test/host-line-probe.mjs` 是**与宿主线无关**的那一支:只断言两条线都必须成立的事——页面无报错、插件只维护**一份**样式表、设置真的作用到文档(`DFP_EXPECT_FAMILY` / `DFP_EXPECT_WEIGHT` 给了就顺带断言计算样式)、设置页里能找到并渲染出 `.dfp-card`(哪条线的座位都行)、以及从卡片上改一个值真的写进去。换宿主线(rc ↔ alpha)后先跑它;调试「alpha 上卡片写不进去」这类问题时设 `DFP_PROBE=1`,插件会往控制台打一行 `[dfp-probe]`(服务了哪些命名空间、认领了哪个、座位当前是什么状态)
94
- - `test/weight-verify.mjs` 在真实页面里量三条字重轴(界面 / 对话 / 代码)的独立性与「样式表只有一份、不刷新关掉跟随立即回落」;`test/split-verify.mjs` 量对话/代码两条字号轴的独立性,外加**退役的界面字号轴什么都不动**;`test/slider-walk.mjs` 与 `test/split-walk.mjs` 驱动真实卡片(拖动不写、松手才写;简单模式两格与整条栈的往返);另有市场条目的维护脚本 `test/market-pr.mjs`(status / update / refresh / reopen / open / about)与诊断脚本 `test/market-inspect.mjs`(PR 状态、评论、CI 与分支差异)
97
+ - `test/weight-verify.mjs` 在真实页面里量三条字重轴(界面 / 对话 / 代码)的独立性与「样式表只有一份、不刷新关掉跟随立即回落」,并**逐级断言会话字重的阶梯**(+180 与 −100 两个方向下 h2 > strong > 正文,且每组都等于自身基准 + 偏移);`test/split-verify.mjs` 量对话/代码两条字号轴的独立性、外加**退役的界面字号轴什么都不动**,并用一条 h1~h4 探针断言**每个标题级别只吃一次偏移**(±3 各验一遍,`h1 > h2 > h3 ≥ h4`);`test/slider-walk.mjs` 与 `test/split-walk.mjs` 驱动真实卡片(拖动不写、松手才写;简单模式两格与整条栈的往返);另有市场条目的维护脚本 `test/market-pr.mjs`(status / update / refresh / reopen / open / about)与诊断脚本 `test/market-inspect.mjs`(PR 状态、评论、CI 与分支差异)
95
98
  - `docs/` —— 0.2.0 的[背景调研](docs/research-0.2.0.md)与[功能规格](docs/spec-0.2.0.md)(设计阶段的记录,含当时的取舍理由;与最终实现不同的地方以 README/CHANGELOG 为准,两份文件文首都有说明)。**不在 npm `files` 清单内,不随包发布**
96
99
  - 客户端模块能 require 的只有 shell 静态表里的模块(`react`、`react/jsx-runtime`、`react-dom`、`@deepseek-ai/cordis`、`@deepseek-ai/dsh-client-*` 等);`dsh.client.inject` 只是加载顺序声明,不是 require 许可
97
100
  - 改完源码要**先构建再刷新**:`node build.mjs`(或 `npm run watch`)把 `src/` 生成到 `lib/`,浏览器加载的是 `lib/`,只改 `src/client.js` 不构建的话页面看到的还是旧包;`npm test` 只检查功能,`node test/artifacts.mjs`(在 `npm run verify` 里)专门校验 `lib/` 与当前 `src/` 逐字节一致。改宿主半(`src/index.mjs`)或 `cordis.patch.yml` 需重启 DSH