@chengzhao-dev/dsh-quarto-book 0.6.3 → 0.6.5

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.
Files changed (44) hide show
  1. package/README.en.md +3 -3
  2. package/README.md +5 -3
  3. package/lib/index.js +49 -7
  4. package/lib/tools/pass-report.js +12 -12
  5. package/lib/tools/render-check.js +253 -65
  6. package/lib/workspace.js +1 -0
  7. package/locale/en.json +1 -1
  8. package/locale/zh.json +1 -1
  9. package/package.json +9 -6
  10. package/skills/designing-theme/SKILL.md +1 -1
  11. package/skills/designing-theme/assets/theme/css/content.css +31 -8
  12. package/skills/designing-theme/references/theme-spine.md +1 -1
  13. package/skills/designing-theme/scripts/checking-layout.py +11 -3
  14. package/skills/designing-theme/scripts/measuring-pages.mjs +2 -2
  15. package/skills/writing-quarto/SKILL.md +11 -2
  16. package/skills/writing-quarto/examples/03-block-after.md +29 -0
  17. package/skills/writing-quarto/examples/03-excerpt-lead.md +10 -0
  18. package/skills/writing-quarto/examples/03-qmd-elements.md +29 -2
  19. package/skills/writing-quarto/examples/04-paragraph-cases.md +13 -0
  20. package/skills/writing-quarto/examples/07-layout-list.md +34 -0
  21. package/skills/writing-quarto/quarto/authoring.md +5 -4
  22. package/skills/writing-quarto/quarto/basics.md +1 -0
  23. package/skills/writing-quarto/quarto/coords.md +2 -1
  24. package/skills/writing-quarto/quarto/figures.md +49 -0
  25. package/skills/writing-quarto/quarto/mermaid.md +2 -2
  26. package/skills/writing-quarto/quarto/refactor.md +1 -1
  27. package/skills/writing-quarto/quarto/render.md +4 -4
  28. package/skills/writing-quarto/quarto/tables.md +79 -0
  29. package/skills/writing-quarto/references/book-journey.md +38 -0
  30. package/skills/writing-quarto/references/token-budget.md +26 -0
  31. package/skills/writing-quarto/scripts/checking-callouts.py +2 -2
  32. package/skills/writing-quarto/scripts/checking-dom.py +12 -6
  33. package/skills/writing-quarto/scripts/checking-links.py +70 -13
  34. package/skills/writing-quarto/scripts/checking-names.py +3 -1
  35. package/skills/writing-quarto/scripts/checking-output.py +3 -3
  36. package/skills/writing-quarto/scripts/checking-prose.py +11 -7
  37. package/skills/writing-quarto/scripts/testing-content.py +68 -1
  38. package/skills/writing-quarto/scripts/verifying-content.py +187 -35
  39. package/skills/writing-quarto/steps/02-structure.md +1 -1
  40. package/skills/writing-quarto/steps/03-blocks.md +19 -6
  41. package/skills/writing-quarto/steps/04-paragraphs.md +1 -0
  42. package/skills/writing-quarto/steps/06-wording.md +17 -0
  43. package/skills/writing-quarto/steps/07-layout.md +5 -1
  44. package/skills/writing-quarto/steps/08-reread.md +1 -1
@@ -7,7 +7,7 @@ Node、Playwright 与 Edge 可用时,measuring-pages.mjs 验证真实几何。
7
7
  规范出处:本技能 `references/theme-system.md`。
8
8
 
9
9
  用法:python checking-layout.py [--root .] [--book-dir _book] [--browser]
10
- 退出码:0 = 关键令牌全部存在,1 = 有缺失。
10
+ 退出码:0 = 关键令牌全部存在,1 = 有缺失,2 = 渲染产物目录缺失,3 = 请求了 --browser 但运行时不可用。
11
11
  """
12
12
 
13
13
  import argparse
@@ -348,7 +348,12 @@ def resolve_node():
348
348
 
349
349
 
350
350
  def resolve_playwright_root():
351
- candidates = [os.environ.get("BOARD_GAMES_NODE_PATH"), os.environ.get("NODE_PATH")]
351
+ candidates = [
352
+ os.environ.get("BOARD_GAMES_NODE_PATH"),
353
+ os.environ.get("NODE_PATH"),
354
+ str(THEME_DIR.parents[1] / "node_modules"),
355
+ str(ROOT / "node_modules"),
356
+ ]
352
357
  cache = Path.home() / ".cache" / "codex-runtimes"
353
358
  if cache.is_dir():
354
359
  candidates.extend(
@@ -838,7 +843,7 @@ def main():
838
843
  book_dir = ROOT / book_dir
839
844
  if not book_dir.is_dir():
840
845
  print(f"BookDir not found: {book_dir}. Run 'quarto render' first.")
841
- return 1
846
+ return 2
842
847
 
843
848
  css_texts = [
844
849
  p.read_text(encoding="utf-8", errors="ignore")
@@ -1024,6 +1029,9 @@ def main():
1024
1029
 
1025
1030
  print()
1026
1031
  if fail == 0:
1032
+ if args.browser and browser_note:
1033
+ print(f"SKIP browser-layout {browser_note}")
1034
+ return 3
1027
1035
  if browser_note:
1028
1036
  print(f"PASS theme-static;SKIP browser-layout {browser_note}")
1029
1037
  else:
@@ -6,7 +6,7 @@
6
6
  import { mkdir, readdir, writeFile } from "node:fs/promises";
7
7
  import { createRequire } from "node:module";
8
8
  import { existsSync } from "node:fs";
9
- import { dirname, join, relative, resolve, sep } from "node:path";
9
+ import { delimiter, dirname, join, relative, resolve, sep } from "node:path";
10
10
  import { pathToFileURL } from "node:url";
11
11
 
12
12
  const argv = process.argv.slice(2);
@@ -79,7 +79,7 @@ function loadPlaywright() {
79
79
  try {
80
80
  return require("playwright");
81
81
  } catch (error) {
82
- for (const directory of (process.env.NODE_PATH || "").split(sep).filter(Boolean)) {
82
+ for (const directory of (process.env.NODE_PATH || "").split(delimiter).filter(Boolean)) {
83
83
  const candidate = join(directory, "playwright", "index.js");
84
84
  if (existsSync(candidate)) {
85
85
  return require(candidate);
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: writing-quarto
3
- description: 润色与重构 Quarto Book 章节:任务与结构、术语与中英混排、检查与渲染;不用于改主题样式
3
+ description: 写作、布局、排版与润色 Quarto Book 章节:任务与结构、内容块与表格、段落与句子、中英混排与术语、检查与渲染;不用于改主题样式
4
4
  metadata:
5
5
  short-description: 润色中文 Quarto 图书章节
6
6
  ---
@@ -16,6 +16,12 @@ metadata:
16
16
  - 项目带有 `.agents/skills/quarto-book-project/SKILL.md` 时,读完本技能再读它,并只按它指向的 `writing/` 文件读章节对照;没有就跳过,不要凭猜测补书名、章节名和术语。书内 `context/` 下的旧通用副本不再打开,写法以本技能为准。
17
17
  - 书仓库根目录的 `README.md` 只走第 5–8 步:它是仓库说明页,不是章节;不套第 1–4 步的任务与结构骨架,不写「常见错误」「自测问题」,不调 `quarto_render_check`。第 8 步发现问题只退回第 5、6、7 步。`README.en.md` 同样处理;`CHANGELOG.md`、`LICENSE`、`AGENTS.md` 不在写作范围。这条只在书仓库里适用(技能本身由 Book 门禁触发)。
18
18
 
19
+ ## 整书走法
20
+
21
+ 改多章或排目录时,先读 `references/book-journey.md`:先定全书主线与章节次序,再逐章走九步,最后做全书一致性回读。只润色一章时不读它。
22
+
23
+ 单章与整书共用同一套九步,不另造一套章节规则;项目有章节表时以项目表为准。技能文件体量受 `references/token-budget.md` 约束,新增整书规则只写进 `book-journey.md`。
24
+
19
25
  ## 两种走法
20
26
 
21
27
  增量润色沿九步走,只改判为不合格的地方,其余保持原样。全章重构仍是这九步,但第 1–2 步先定删留、不动句子,第 3–4 步只拆块和段,第 5–7 步才逐句改。
@@ -26,9 +32,12 @@ metadata:
26
32
 
27
33
  ## 九步
28
34
 
35
+ 九步按四个写作域分:写作 1–2,布局 3–4 与 7,润色 5–6 与 8,排版归主题技能;第 9 步是检查与渲染。跨域改动按「写作 → 布局 → 润色」的顺序推进,前一步落定再进下一步。
36
+
29
37
  1. 定任务:写出读者做完能完成的那件事,再列这一章要覆盖的任务。规则在 `steps/01-task.md`。
30
38
  2. 定结构:排页面骨架、二级标题和篇幅预算,只定删留、标题与章题对齐。规则在 `steps/02-structure.md`。
31
- 3. 排列内容块:导语、围栏、收束与 Callout 的次序,一个围栏只放正在讲的那一块。规则在 `steps/03-blocks.md`。
39
+ 3. 排列内容块:导语、围栏、收束与 Callout 的次序,一个围栏只放正在讲的那一块。规则在 `steps/03-blocks.md`,表格写法见 `quarto/tables.md`。
40
+ 图注写在图下、图前只写引出关系;三类图的统一写法见 `quarto/figures.md`。
32
41
  4. 定段落:一段一个对象,段间衔接落在话题切换处。规则在 `steps/04-paragraphs.md`。
33
42
  5. 定句子:主语选执行者,对象先行,一句一动作。规则在 `steps/05-sentences.md`。
34
43
  6. 定用词:统一术语、主动语态和语气。规则在 `steps/06-wording.md`。
@@ -41,6 +41,35 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
41
41
  读取和写入都先检查坐标,两种失败分开处理:出界坐标说明调用方算错了,读取直接抛出 `std::out_of_range`,没有可返回的格子。格子被占用在流程里随时会发生,写入返回 `false`,状态面板保持不变,调用方再选别的格子就行。完整的 `@param`、`@returns`、`@throws` 注释写在 `state.h` 里。
42
42
  ````
43
43
 
44
+ 块后把函数契约拆成条款列表,是同一禁令的另一种写法。以 井字棋 落子校验节改稿前为对照:
45
+
46
+ ````text
47
+ 不佳(头文件注释已写清三个拒绝条件,块后仍逐条复述并解释返回值):
48
+ `PlaceCell` 返回 `true` 表示放置成功,返回 `false` 表示拒绝。
49
+
50
+ - **放置被拒**:返回 `false`,棋盘保持原样。坐标越界或格子已被占用时换一个坐标;传入的类型是空格子时换一个非空类型。
51
+ - **放置成功**:返回 `true`,新棋子当场能从 `GetCellType` 读回来。
52
+
53
+ 改写(注释覆盖契约,块后只留读者要做的判断):
54
+ `PlaceCell` 用返回值报告结果,三种拒绝都不改棋盘;调用方检查返回值就能决定下一步,不必比较落子前后的棋盘。
55
+ ````
56
+
57
+ 判定信号:块后列表项与 `@param`、`@return` 一一对应,删掉列表注释仍完整;返回值语义被正文重复解释两遍以上。允许保留的是注释没写的调用方策略:谁该重试、谁该结束、界面要显示什么。
58
+
59
+ ## 块后交代注释布局
60
+
61
+ 块后正文不交代「类说明没有逐个列出成员」「每个成员的用法写在行尾注释里」这类注释安排:它讲作者怎么组织注释,不讲程序做什么。读者需要的事实直接陈述。以 井字棋 棋盘类型节改稿前为对照:
62
+
63
+ ````text
64
+ 不佳(块后说明注释怎么分工,没有程序信息):
65
+ 类说明没有逐个列出成员的用途,只说清这个类管什么、棋盘为什么可以随便拷贝。每个成员的用法写在各成员自己的注释里,两处不重复。
66
+
67
+ 改写(整句删掉,前后段落已经交代了棋盘做什么):
68
+ (无块后段落)
69
+ ````
70
+
71
+ 判定信号:句子主语是「类说明」「注释」「行尾注释」而不是程序里的对象;删掉后读者对代码的理解不变。
72
+
44
73
  ## 块后悬空指代
45
74
 
46
75
  块后第一次提到代码块里的常量怎么写:点名标识符,不用「这 N 个 X」。块后段落首次提及围栏里的实体时点名标识符;先行词只出现在代码围栏里、不在任何句中时,「这 N 个 X」「它们」式省称没有可依的先行词,计数指代还容易盖错范围。条文见 `steps/03-blocks.md`「内容块前后的闭环」。以 示例章定义坐标范围节改稿前为对照:
@@ -171,3 +171,13 @@ constexpr bool IsInRange(Position position) {
171
171
  改写(两句:第一句接住上文对象,第二句沿用注释的动词和对象,位置写「定义在 state.h 里」):
172
172
  操作写进状态面板之后,要知道这一步有没有分出胜负。`HasPlayerLine` 检查状态面板上是否已形成三连获胜线,定义在 `state.h` 里:
173
173
  ```
174
+
175
+ ```text
176
+ 不佳(章引言一口气挂三个章节链接,读者还没读正文先被导航到别的页):
177
+ [程序结构](viewing-program.qmd) 把棋盘、对局和终端连成一份程序。棋盘是 3 行 3 列。接口写在 [board.h](…),实现放在 [board.cpp](…)。两个文件都在 [工程结构](02-mapping-layout.qmd) 一章。
178
+
179
+ 改写(引言只留本章主源文件;跨章链接下沉到正文真正会用到它的句子):
180
+ 井字棋棋盘是 3 行 3 列,共九个棋盘格子。`Board` 保存这些棋盘格子,并提供写入与读出的接口;接口写在 [board.h](…),实现放在 [board.cpp](…)。
181
+ ```
182
+
183
+ 判定信号:章引言(第一个 `##` 之前)出现两个及以上 `.qmd` 链接;除承接上一章的那一个之外,其余都在正文有对应的「首次真正用到」的句子可以迁入。`verifying-content.py` 对引言多余章节链接直接报错。
@@ -48,8 +48,8 @@ constexpr bool IsInRange(Position position) { … }
48
48
  不佳(图前图例句复述图注的方位信息,一段三句三个主题):
49
49
  `Position` 把坐标交给 `Board`,负数和行列为 `3` 的位置都会被拒绝。下面的图标出可用的 `(row, col)`。左上角是 `(0, 0)`,行向下增加,列向右增加。
50
50
 
51
- 改写(方位与图例由 fig-cap 独自承载,正文只留行为句与桥接句):
52
- 调用方把 `Position` 交给 `Board`,行列出现负数或 `3` 都会被拒绝。下面的图标出可用的 `(row, col)`。
51
+ 改写(方位与图例由 fig-cap 独自说明,正文只留行为句与桥接句):
52
+ 调用方把 `Position` 交给 `Board`,行列出现负数或 `3` 都会被拒绝。图列出可用的 `(row, col)`,桥接句不再交代图面方位。
53
53
  ```
54
54
 
55
55
  判定信号:两个围栏之间只有空行;图后直接进入与图无关的下一块;块前引语同时推进多个对象(如 `Position` 与 `IsInRange` 各讲一句);图注已写明的方位与图例信息,桥接段或图后正文再讲一遍。
@@ -78,6 +78,33 @@ constexpr bool IsInRange(Position position) { … }
78
78
 
79
79
  判定信号:图后句删掉任一分句中心仍成立;图注或桥接句已写明的信息在图后再讲一遍。图后正文只给图注讲不完的新结论,图后对照与句段侧的冒号分号堆叠见 `examples/04-paragraph-opening.md`「冒号后堆叠分号解释」。
80
80
 
81
+ ## 原生 SVG 图注对照
82
+
83
+ `{=html}` 围栏里的 SVG 不会被 Quarto 包成 figure;图注必须自己用 `<figure>` 和 `<figcaption>` 放在图下,不要在图前留一句“下图标出……”。
84
+
85
+ ````text
86
+ 不佳(图注占图前正文,SVG 裸放):
87
+ 下图标出这块棋盘上可用的 (row, col)。
88
+
89
+ ```{=html}
90
+ <svg class="coords-grid" role="img" aria-label="棋盘坐标。">…</svg>
91
+ ```
92
+ ````
93
+
94
+ ````text
95
+ 改写(图注在图下,正文只留引出关系的一句):
96
+ 代码给出行列上限和坐标字段,图把行列编号落到棋盘格子上。
97
+
98
+ ```{=html}
99
+ <figure class="book-figure">
100
+ <svg class="coords-grid" role="img" aria-label="棋盘坐标。">…</svg>
101
+ <figcaption>棋盘坐标图:3 行 3 列,每格标出 (row, col);行向下、列向右,左上角是 (0, 0)。</figcaption>
102
+ </figure>
103
+ ```
104
+ ````
105
+
106
+ 判定信号:`<svg>` 是否在 `<figure>` 内、`<figcaption>` 是否在 `svg` 之后;图前是否还有只交代图面的句子;图注与图后正文是否逐句重复。
107
+
81
108
  ## 块后解释先于图对照
82
109
 
83
110
  同一小节既有代码块项目解释又有图时,解释紧跟代码块,桥接句与图在后;图后不再回头讲代码项。
@@ -99,3 +99,16 @@
99
99
  ```
100
100
 
101
101
  判定信号:章首或 `##` 首句的主语是下游对象(格子、对局、终端),而不是标题对象;把主语换成标题对象后句子仍成立,说明原句已经漂移。
102
+ ## 重复交代可数事实
103
+
104
+ 以棋盘章成员与接口节的一段为对照。引言已经写过「3 行 3 列,共九个棋盘格子」,类注释又写「3×3 个格子……格子数量不会改变」,块后散文再讲两遍「九个棋盘格子」「数量从开局到终局不变」「编译期就能确定」,读者读到的是一件事的三种说法:
105
+
106
+ ```text
107
+ 不佳(同一事实讲三遍,第二句和第三句还互相重复):
108
+ `Board()` 构造之后就是一张空棋盘。出界坐标不会写入棋盘;`Board` 保存九个棋盘格子的类型,数量从开局到终局不变。九个棋盘格子的数量编译期就能确定,所以 `cells_` 用二维 `std::array` 存放。
109
+
110
+ 改写(只保留块后必须新给的实现事实:存放方式与下标含义):
111
+ `Board()` 构造出来是空棋盘。格子数在编译期确定,`cells_` 用二维 `std::array` 存放:外层是行,内层是列,`cells_[row][col]` 对应坐标 `(row, col)`。
112
+ ```
113
+
114
+ 自查:删掉重复句后,读者还缺哪一条事实?只补缺的那条;「数量不变」「出界不写入」若已在类注释或 `IsInRange` 的契约里写过,就不再复述。
@@ -180,3 +180,37 @@ enable_testing() 开启 CTest……。add_test 用 NAME 和 COMMAND……。set_
180
180
  ```
181
181
 
182
182
  判定信号:删掉任一项后其余照常成立,那一项只把上句拆短;三项里有一项与另一项同义或只为对齐,读者从列表里取不到三条独立信息。
183
+
184
+ ## 规则条件不编号
185
+
186
+ 以“落子输入校验”为对照(规则见 `steps/07-layout.md`「列表选择」):
187
+
188
+ ```text
189
+ 不佳(三个并列条件写成编号步骤,读者以为要按顺序检查):
190
+ 落子失败时:
191
+
192
+ 1. 行列越界;
193
+ 2. 目标棋盘格子已被占用;
194
+ 3. 输入格式错误。
195
+
196
+ 改写(规则条件写成一段,只有执行动作才编号):
197
+ 行列越界、目标棋盘格子已被占用或输入格式错误时,程序说明原因,棋盘保持不变,随后要求重新输入。
198
+ ```
199
+
200
+ ```text
201
+ 不佳(把规则句塞进流程编号,一步里同时讲条件和动作):
202
+ 1. 如果行列越界、格子已占用或格式错误,就提示;
203
+ 2. 否则写入;
204
+ 3. 重画棋盘。
205
+
206
+ 改写(规则先成段,流程单独编号):
207
+ 落子前先检查行列范围、目标格子和输入格式;任一项不通过就说明原因,棋盘不变并重新输入。
208
+
209
+ 一轮落子:
210
+
211
+ 1. 读入行号和列号;
212
+ 2. 检查这次输入;
213
+ 3. 写入棋盘格子,重画棋盘。
214
+ ```
215
+
216
+ 判定信号:编号项之间可以互换顺序而意思不变,说明它是并列条件而不是步骤;列表项以“如果 / 当 / 越界 / 占用”开头,或一项里同时出现条件和动作。规则、条件、允许和禁止用段落;只有“先做什么、再做什么”才是编号列表。
@@ -28,7 +28,7 @@
28
28
 
29
29
  局部删除或移动内容后必须回读切口,并为后文仍引用的动作保留「触发时机 → 状态变化及原因 → 可观察结果 → 下一步」的最短闭环。后文出现悬空的「然后、因此、此时、重启、再次」等承接时必须重写切口,不能只按表面冗余删除过渡句。
30
30
 
31
- 改标题等于改锚点。改完运行 `scripts/verifying-content.py` 与 `quarto render` 核对交叉引用。
31
+ 改标题等于改锚点。改完运行 `scripts/verifying-content.py`,再用 `quarto_render_check` 核对交叉引用;只有人工复现问题才在仓库根裸跑 `quarto render`。
32
32
 
33
33
  ## 配置文件与构建脚本
34
34
 
@@ -76,8 +76,9 @@ README 遵循 GitHub Markdown。根目录 `README.md` 是在线阅读链接的
76
76
 
77
77
  项目解释不得插队到图之后:禁止「导语 → 代码 → 图 → 再解释代码项」,图后正文不再回头讲代码块内的对象。代码块与图之间只有空行、或图后不接结论直接进入与图无关的下一块,都视为堆叠;结论已并入桥接段的小节收尾图除外。反例与改写对照见 `steps/03-blocks.md` 与 `quarto/coords.md`。
78
78
 
79
- 图的放置另有三条边界:
79
+ 图的放置另有四条边界:
80
80
 
81
+ - **图注与正文分工**:图注写图面内容与读法,图前句写这张图核对哪条关系;图前不写“下图标出……”这类只交代图面的句子,图注落在图下。三类图的图注写法见 `quarto/figures.md`。
81
82
  - **一图一事**:一张图只核对一条已讲清的关系。图需要同时表达两条关系时,拆成多张图,或按关系拆成多个 `###`,每节一图。
82
83
  - **同主题相邻**:代码块与图必须是同一对象的两种呈现。下一块与图主题不同时,先用一句正文收束本对象,再另起 `###`;禁止「代码 A → 一句拐弯 → 图讲 B → 再贴代码 C」的同节混排。
83
84
  - **图不承载正文未写的新信息**:图中的每个框、箭头或标记都能在图前正文找到对应对象与关系;读者需要新概念才能读懂的图,先在正文补出该概念,再放图。
@@ -121,11 +122,11 @@ Callout 个数见 `steps/02-structure.md`,本段不写数字;`warning` 只
121
122
  ```
122
123
 
123
124
  - 只有读者可以先自行回答、再核对结论的内容才折叠。定义、命令和必经判据留在正文。
124
- - `.answer` 由 `scripts/answering-disclosure.lua` 渲染为默认收起的原生 `details.answer-disclosure`,摘要固定为「查看答案」。正文不手写这段 HTML。
125
+ - `.answer` 由书内 `filters/answering-disclosure.lua` 渲染为默认收起的原生 `details.answer-disclosure`,摘要固定为「查看答案」。正文不手写这段 HTML。
125
126
  - 答案只使用本章已经讲解的概念,内部不使用 `h1`–`h6`。
126
127
 
127
128
  ### 交叉引用
128
129
 
129
130
  交叉引用使用真实标题生成的锚点,引用前确认目标页面存在。本项目不手写英文 `{#id}`,标题锚点由中文标题派生;跨章节引用用章节标题链接,不用「第 N 章」。
130
131
 
131
- 需要渲染与链接依据时,读 `quarto/render.md` 与 `quarto/mermaid.md`。
132
+ 需要渲染与链接依据时,读 `quarto/render.md` 与 `quarto/mermaid.md`;图注、原生 SVG 与图前句的分工读 `quarto/figures.md`。
@@ -126,5 +126,6 @@ title: "章节标题"
126
126
  ## 延伸
127
127
 
128
128
  - 正文结构、代码块/终端约定与文档元素:`quarto/authoring.md`
129
+ - 图、图注与图前句的分工:`quarto/figures.md`
129
130
  - 外观配置与渲染排错:`quarto/render.md`
130
131
  - 页面宽度与视觉依据:`steps/02-structure.md`
@@ -12,12 +12,13 @@
12
12
 
13
13
  - 页面 frontmatter 开 `engine: jupyter`,只给含图页面开启,避免全书每次渲染都起 kernel。
14
14
  - 坐标图单元用 ```` ```{python} ```` 围栏,块首写 `#| echo: false`、`#| warning: false`,再写 `#| fig-cap: "图 N:…"` 与 `#| fig-align: center`;图注文字概括图意,不与图后正文逐句重复,也不用 `>` 引用块另起一套图注。
15
+ - 没有执行环境或页面保持静态时,允许直接写原生 HTML/SVG;图必须用 `<figure class="book-figure">` 包住,`<figcaption>` 在图后。三类图的统一图注约定见 `quarto/figures.md`,不要把图注留成图前的独立段落。
15
16
  - 单元内从当前目录向上定位含 `_quarto.yml` 的书根,按路径加载本技能 `scripts/diagrams/rendering-coords.py`,绑定名仍是 `coords_grid`,用 `IPython.display.HTML` 输出保持 SVG 内联。不要换成 `IPython.display.SVG`:image/svg+xml 输出会被 Quarto 外置成 `<img>` 文件引用,无法继承站点 `data-bs-theme` 明暗与文档字体(书内字体退回系统字体)。
16
17
  - 图注讲不完的读图要点写在图后正文(一两句),不复述图注已写明的信息。
17
18
 
18
19
  ## 上游代码与图的桥接
19
20
 
20
- 坐标图不孤立出现:引出图的代码块与图之间必须有桥接句,说明图核对代码的哪部分契约(如「下面的图标出每个数据项的 (row, col),与 `IsValid` 接受的范围一致」);图后先给从图带走的结论,再进入下一块;小节以图收尾时,从图带走的结论可并入桥接段(如 示例章先给 `row` 为 `3` 或 `col` 为 `-1` 这类反例再上图),不在图后孤悬一句。代码块与图之间只有空行视为堆叠,固定序列见 `writing-quarto` 技能 `quarto/authoring.md`「代码与图的桥接」与 `steps/03-blocks.md`。
21
+ 坐标图不孤立出现:引出图的代码块与图之间必须有桥接句,说明图核对代码的哪部分契约(如「图核对 `IsValid` 接受的范围」);图后先给从图带走的结论,再进入下一块;小节以图收尾时,从图带走的结论可并入桥接段(如 示例章先给 `row` 为 `3` 或 `col` 为 `-1` 这类反例再上图),不在图后孤悬一句。代码块与图之间只有空行视为堆叠,固定序列见 `writing-quarto` 技能 `quarto/authoring.md`「代码与图的桥接」与 `steps/03-blocks.md`;图注与图前句的分工见 `quarto/figures.md`。
21
22
 
22
23
  坐标图单元计入盒子密度(口径见 `steps/03-blocks.md`):同一 `###` 内坐标图与代码块相邻出现时,桥接句就是盒子之间的承接正文;`verifying-content.py` 对两围栏之间无正文给出 WARN 提示,人审与对照案例仍是主检查。
23
24
 
@@ -0,0 +1,49 @@
1
+ # 图与图注
2
+
3
+ 图由图像、`{mermaid}`、`{python}` 坐标图和原生 HTML/SVG 共同遵守这一份约定。图注负责读图信息,正文负责图与上下文的关系;两者不互相复述。
4
+
5
+ ## 位置与归属
6
+
7
+ - 图注默认在图下,图整体居中。Quarto 的 `fig-cap` 默认就是图下题注;不要把图注写成图前独立段落。
8
+ - `{mermaid}` 用 `%%| fig-cap`,`{python}` 坐标图用 `#| fig-cap`,原生 HTML/SVG 用 `<figure>` 内的 `<figcaption>`。三者都落在图下。
9
+ - 图前只写引出关系的一句:为什么这里出现这张图、它核对哪条已讲清的契约。图前不写“下图标出……”这类只交代图面内容的句子;这种句子属于图注。
10
+ - 图后只写从图带走的结论或图外新信息。图注已写明的坐标、方位、图例、成员取舍不再复述。
11
+
12
+ ## 图注写法
13
+
14
+ 图注是一句完整的读者句,至少包含“这张图画的是什么”和“读图要看的那条关系”。不手写“图 1:”,Quarto 按 `lang: zh` 自动编号。
15
+
16
+ - 不佳:下图标出这块棋盘上可用的 `(row, col)`。
17
+ - 改写(图下):`棋盘坐标图:3 行 3 列,每格标出 (row, col);行向下、列向右,左上角是 (0, 0)。`
18
+ - 原句只是图面说明,移入 `<figcaption>`,不再占据图前正文。
19
+ - 不佳:总览图为什么不列成员?
20
+ - 改写(删除;图注写“总览只画类型与关系”即可)。
21
+
22
+ 图注只解释图本身,不承担章节过渡,也不替读者总结整节。
23
+
24
+ ## 原生 HTML/SVG
25
+
26
+ 原生 HTML/SVG 图用 `<figure>` 包住,图注用 `<figcaption>`,图注必须是 `figure` 的最后一个子元素:
27
+
28
+ ```html
29
+ <figure class="book-figure">
30
+ <svg class="coords-grid" role="img" aria-label="棋盘坐标:3 行 3 列,左上角为 (0, 0)。">…</svg>
31
+ <figcaption>棋盘坐标图:3 行 3 列,每格标出 (row, col);行向下、列向右,左上角是 (0, 0)。</figcaption>
32
+ </figure>
33
+ ```
34
+
35
+ - `role="img"` 与 `aria-label` 给读屏软件一个短名称;`figcaption` 给视觉读者完整图注。
36
+ - 主题用 `.book-figure` 统一居中、限制最大宽度,并让 `figcaption` 落在图下;不要另写行内样式。
37
+ - 图注内需要行内代码时写 `<code>`,不要写 Markdown 反引号——`{=html}` 围栏按原样输出。
38
+
39
+ ## 与其他图类的关系
40
+
41
+ - Mermaid 的方向、节点预算与线型约定见 `quarto/mermaid.md`;它的 `fig-cap` 同样遵守本文件。
42
+ - 坐标图优先用 `quarto/coords.md` 的 `{python}` 助手;没有执行环境时,允许静态 HTML/SVG,但必须按本文件包 `<figure>` 与 `<figcaption>`,不能把图注留在图前。
43
+ - 代码到图的固定序列见 `quarto/authoring.md`「代码与图的桥接」与 `steps/03-blocks.md`;桥接句讲关系,图注解图面,两者分工不同。
44
+
45
+ ## 自检
46
+
47
+ - 图前是否还有“下图 / 图中 / 本图”这类只交代图面的句子?有就移入图注或删除。
48
+ - 图注是否重复了图后正文?重复就删正文或删图注,只留一处。
49
+ - 原生 SVG 是否在 `figure` 内,`figcaption` 是否在 `svg` 之后、`</figure>` 之前?
@@ -8,7 +8,7 @@ Mermaid 只承担流程图、分层图与调用链;坐标轴类网格图(状
8
8
 
9
9
  Quarto 只执行 ` ```{mermaid} ` 属性围栏;plain 的 ` ```mermaid ` 围栏被当作普通代码块,渲染结果是语法高亮的源码而不是图。`verifying-content.py` 在禁用词扫描中拦截 plain 围栏。
10
10
 
11
- 渲染核对方法:`quarto render` 后检查 `_book` 中对应 HTML 应出现 mermaid 图表容器(`mermaid-js` 或 `quarto-diagram` 类名),不应出现 `sourceCode mermaid` 高亮代码块。
11
+ 渲染核对方法:调用 `quarto_render_check`,在返回的 `html_report` 对应 HTML 中应出现 mermaid 图表容器(`mermaid-js` 或 `quarto-diagram` 类名),不应出现 `sourceCode mermaid` 高亮代码块。
12
12
 
13
13
  ## 块首固定 init 指令
14
14
 
@@ -64,4 +64,4 @@ mermaid 用 init 指令中的字体测量标签宽度,页面 CSS 按 `--ui-fon
64
64
 
65
65
  每个 `{mermaid}` 图块在围栏开头、init 之前写一行 `%%| fig-cap: "程序结构总览。实线箭头表示调用或依赖,……"`。`fig-cap` 只写图意和读图约定,不手写“图 1:”这类编号;Quarto 按 `lang: zh` 自动在正文中排成“图 1:”。图注紧跟图块开头、落在图下。线型、箭头方向、读图范围这类说明只写进该图的图注,图后正文不再复述;图后只补图外的新信息或从图带走的结论,不点名被省略的成员,也不写“其余成员见某章”。`fig-cap` 是 Quarto 对 Mermaid 的单元选项语法,`%%|` 必须直接写在围栏开头、init 之前(Quarto 只解析块首选项;写在 init 之后会被当成 Mermaid 注释原样渲染),不能改成 `#|` 或图后引用块。
66
66
 
67
- 图注文字概括图意,不与图后正文逐句重复;需要交叉引用时同时写 `label: fig-...`,正文用 `@fig-...` 引用。
67
+ 图注文字概括图意,不与图后正文逐句重复;需要交叉引用时同时写 `label: fig-...`,正文用 `@fig-...` 引用。图注与图前句的统一分工、原生 HTML/SVG 的图注写法见 `quarto/figures.md`。
@@ -14,6 +14,6 @@
14
14
 
15
15
  ## 收尾
16
16
 
17
- 全仓重构后,核对导航与路由表、标题层级、章节链接、源码摘录、命令和输出。先运行增量验证定位问题,再对所有 QMD 执行全量 `verifying-content.py`/`verifying-content.py`,最后在仓库根目录渲染 Book。按章推进时,每一章的出口是 `verifying-content.py --paths` 该文件;全部章节通过之后才 `render`。涉及知识库时同步索引、健康检查和评测;涉及代码时用实际构建、CTest 或示例验证核对文档。
17
+ 全仓重构后,核对导航与路由表、标题层级、章节链接、源码摘录、命令和输出。先运行增量验证定位问题,再对所有 QMD 执行全量 `verifying-content.py`,最后在仓库根目录渲染 Book。按章推进时,每一章的出口是 `verifying-content.py --root <书根> --paths <该章>`;全部章节通过之后才 `render`。涉及知识库时同步索引、健康检查和评测;涉及代码时用实际构建、CTest 或示例验证核对文档。
18
18
 
19
19
  ## 本项目边界
@@ -14,18 +14,18 @@
14
14
  |---|---|---|
15
15
  | `theme` | `light: [cosmo, theme/palettes/flexoki/theme-light.scss]` + `dark: [darkly, theme/palettes/flexoki/theme-dark.scss]` | 内置主题与项目样式叠加,顺序决定覆盖关系;Flexoki 是编译默认 |
16
16
  | `highlight-style` | `light:`/`dark:` 指向 `theme/palettes/flexoki/highlight-light.theme` / `highlight-dark.theme` | 明暗分别指定,与 `palettes/flexoki/meta.md` 同步;Solarized 的语法色由 `theme/palettes/solarized/syntax.css` 在 `html[data-palette="solarized"]` 下覆盖,不改这里 |
17
- | `filters` | `scripts/answering-disclosure.lua`(顶层 `filters:`) | 将正文 `.answer` 转为默认收起的原生 `details` |
17
+ | `filters` | `filters/answering-disclosure.lua`(顶层 `filters:`,书内副本) | 将正文 `.answer` 转为默认收起的原生 `details` |
18
18
  | `toc` / `toc-depth` / `toc-location` | `true` / `3` / `right` | 右侧目录最多到 H3,窄屏会折叠,不作唯一定位手段 |
19
19
  | `number-sections` | `false` | 因此标题不手填序号,见 `quarto/basics.md` |
20
20
  | `code-copy` / `code-overflow` | `true` / `wrap` | 长行换行,不让读者横向拖动 |
21
- | `grid` | sidebar 300 / body 800 / margin 272 / gutter 1rem | 正文列约 50 个汉字;四值是最大基准值,窄视口由 Quarto 响应缩放 |
21
+ | `grid` | sidebar 300 / body 872 / margin 272 / gutter 1rem | 正文列 840px,约 50 个汉字;四值是最大基准值,窄视口由 Quarto 响应缩放 |
22
22
  | `lang` | `zh` | 影响部分 HTML 行为与提示框默认词 |
23
23
 
24
24
  本书**不开启**代码行号(`code-line-numbers`)与代码折叠(`code-fold`)。站点 QMD 代码块使用 `{.语言 filename="标题"}`;Quarto 会把标题渲染为 `.code-with-filename`,外观与复制按钮位置由主题统一控制。filename 缺失由 `verifying-content.py` 拦截,内容语义与篇幅由 `verifying-content.py` 负责。
25
25
 
26
26
  ### 改动约定
27
27
 
28
- 1. 改 `format: html:` 任何取值都属于主题级改动,会触发整本渲染,先确认代价再走 `quarto render`。
28
+ 1. 改 `format: html:` 任何取值都属于主题级改动,会触发整本渲染,先确认代价,再用 `quarto_render_check` 渲染。
29
29
  2. 新增或删减主题样式表(`.agents/skills/designing-theme/assets/theme/css/**` 或书内 `theme/css/**`)时,同步修改配置里的样式表清单,否则新样式不参与渲染。
30
30
  3. 页面视觉问题(提示符配色、文件名条、术语色)改 `.agents/skills/designing-theme/assets/theme/**` 或书内 `theme/**` 与设计令牌,不在文档里内联样式,也不改高亮配置。主题系统详见 `../designing-theme/references/theme-system.md`。
31
31
  4. 流程图使用 `{mermaid}` 属性围栏,配色由主题样式控制。配置里不指定图表主题名;围栏与 init 指令细则见 `quarto/mermaid.md`。
@@ -151,7 +151,7 @@
151
151
 
152
152
  - include 路径相对于 qmd 文件所在目录解析(`content/<part>/` 下用 `../../src/...` 指向仓库根的 `src/`)。
153
153
  - 语言标注决定语法高亮:Python 用 `python`,C++ 用 `cpp`,Shell 用 `bash`。
154
- - 新增或修改 include 后必须 `quarto render` 并检查 `_book` 中对应 HTML:嵌入内容应出现在 `<pre class="sourceCode ...">` 代码块中,而不是 `<p>` 段落里。
154
+ - 新增或修改 include 后必须用 `quarto_render_check` 渲染,并核对返回的 `html_report`:嵌入内容应出现在 `<pre class="sourceCode ...">` 代码块中,而不是 `<p>` 段落里。
155
155
  - include 展示的是 `src/` 下真实源文件,渲染问题只修 qmd 的包裹方式,不改被引用的源文件。
156
156
 
157
157
  ## 链接使用约定
@@ -0,0 +1,79 @@
1
+ # 表格
2
+
3
+ 表格只回答「多个对象按同一组属性怎么比较」。并列步骤用有序列表,两个对象两三条区别用句子;表格一旦只装一两列信息,读者会把它当成大号列表读。
4
+
5
+ ## 何时写表
6
+
7
+ - **保留**:三个及以上对象、且每条对象都有两项以上可比属性;属性在各行里位置相同,读者能纵向对照。
8
+ - **改列表或句子**:只有一两列、或右侧大量留白;对象之间没有共同属性,只是并列罗列。
9
+ - **不重复代码**:接口表只写签名读不出的差异(返回什么、边界怎么处理),不把 `@param`、`@return` 再抄一遍。
10
+
11
+ ## 固定写法
12
+
13
+ 一张表由三段构成,缺一段就是块悬空:
14
+
15
+ 1. **表前导语**:一句完整的话,点名要比较的对象与属性,说明为什么此刻看这张表。不写「如下表」「见下表」式空引导,不写「N 个接口」式元计数。
16
+ 2. **表格本体**:表头写属性名,首列写被比较的对象;一行一个对象。
17
+ 3. **表后结论**:一句读者该取走的判断,如共同约定、例外或分类依据。不复述格子里的字面值。
18
+
19
+ 代码块、图、列表与表格之间不能直接相接:中间至少隔一段正文,写清两者关系(代码块给出定义,表格归纳接口差异)。连续两个盒子会让读者分不清边界,也只能靠滚动定位。
20
+
21
+ ## 表头与列宽
22
+
23
+ - 表头由主题统一加粗、加浅底色:`.table thead th` 已设 `font-weight: 700`。正文不写 `**接口**` 式加粗,也不写「表头加粗」说明。
24
+ - 列宽只给**相对比例**,不给像素:
25
+
26
+ ```markdown
27
+ | 接口 | 返回 | 边界 |
28
+ | --- | --- | --- |
29
+ | `GetCellType` | 坐标处的 `CellType` | 越界时抛出 `std::out_of_range` |
30
+ : {tbl-colwidths="[24,30,46]"}
31
+ ```
32
+
33
+ 比例按内容分配:名称与接口列 18–26,返回列 22–32,说明列 34–50,三项合计 100。三列以上时最长列不超过 55,避免其余列被挤成一条线。
34
+ - 不写固定宽度(`{width=...}`、`style="width:..."`)。窄屏下整张表横向滚动,列宽仍随内容分配;`table-layout: auto` 是主题默认值,不要覆盖成 `fixed`。
35
+ - 长单元格先改文案:删重复修饰,把条件与结果按「条件 + 结果」排成一句。仍长时允许格内折行,`overflow-wrap: break-word` 已由主题处理。
36
+
37
+ ## 单元格
38
+
39
+ - 一格一个事实,对象先行。不写「名词:一句」的伪列表,列已经分出属性名。
40
+ - 行内代码只放读者要输入的标识符或类型名;一格最多两个,多了会把列撑宽,也让比较点被代码淹没。
41
+ - 空值与未知写「无」或「不判断」,不写 `-`、`N/A`。
42
+ - 数字右对齐、文本左对齐由主题按列决定;不要在单元格里手动空格对齐。
43
+ - 中英混排留半角空格,标点用全角,规则见 `quarto/prose.md`。
44
+
45
+ ## 表题与引用
46
+
47
+ - 需要正文引用时加表题:表格下一行写 `: 表 3-1 棋盘接口的返回与边界 {#tbl-board-api}`,表题随主题显示在表上方、小一号。
48
+ - 表题只写对象与内容,不写「如下表」「本表说明」。
49
+ - 同一页表题编号连续;正文引用写「表 3-1」,不写「下表」。
50
+
51
+ ## 正反例
52
+
53
+ **反例**(代码块后直接接表,表前没有过渡):
54
+
55
+ ```markdown
56
+ | 接口 | 返回 | 边界 |
57
+ | --- | --- | --- |
58
+ ```
59
+
60
+ **正例**:
61
+
62
+ ```markdown
63
+ 三个只读接口都只回答棋盘状态,区别在返回什么、越界怎么处理:
64
+
65
+ | 接口 | 返回 | 边界 |
66
+ | --- | --- | --- |
67
+ | `GetCellType` | 坐标处的棋盘格子类型 | 越界时抛出 `std::out_of_range` |
68
+ | `IsCellEmpty` | 空格子返回 `true` | 越界或已有棋子时返回 `false` |
69
+
70
+ 需要提前判空的调用方用 `IsCellEmpty`,已经做过范围检查的调用方用 `GetCellType`。
71
+ ```
72
+
73
+ ## 检查清单
74
+
75
+ - [ ] 表前有导语、表后有一句结论,两句都不复述格子内容。
76
+ - [ ] 代码块、图、列表与表之间隔了一段正文。
77
+ - [ ] 表头没有手写加粗;列宽是相对比例,最长列不超过 55%。
78
+ - [ ] 一格一个事实,没有「名词:说明」和手动空格对齐。
79
+ - [ ] 短表已改回句子或列表。
@@ -0,0 +1,38 @@
1
+ # 整本书的写作次序
2
+
3
+ 单章润色看一章;整书重构先看这本书要带读者完成什么,再决定章节次序。本文件只定整书层的判断,单章规则仍在 `steps/`。
4
+
5
+ ## 先定一条主线
6
+
7
+ 把目录写成一句可验收的话:读者从什么基础出发,按顺序做完哪些事,最后能独立交付什么。主线要落到一个可运行、可检查的产物;章节是这条主线上的阶段,不是互不相干的 API 清单。
8
+
9
+ 写目录前先删掉三类章:同一对象拆成多章、只罗列类型而没有阶段结果、前后章可以任意交换。保留下来的章,每一章只回答一个关键问题,并在开头接住上一章的结果、结尾交出下一章需要的输入。
10
+
11
+ ## 三遍走
12
+
13
+ 1. **骨架遍**:先排章节次序与每章关键,确认读者按顺序能完成主线;此时不写句子,不补代码。
14
+ 2. **章节遍**:每章按 `steps/01-task.md` 到 `steps/09-check.md` 走九步,只改这一章;章与章的接口在章首、章末对齐。
15
+ 3. **全书遍**:从头回读,检查术语、项目名、图注、链接与前后承诺;只改跨章不一致,不在这一遍重写单章。
16
+
17
+ 骨架遍改次序,章节遍改正文,全书遍改一致性;三遍不混做。
18
+
19
+ ## 以井字棋书为例
20
+
21
+ | 阶段 | 章节 | 交给下一章的结果 |
22
+ | --- | --- | --- |
23
+ | 规则 | 对局规则 | 一局怎样算结束 |
24
+ | 结构 | 工程结构、程序结构 | 文件与类的整体形状 |
25
+ | 数据 | 棋盘、对局 | 格子、坐标、落子后的状态 |
26
+ | 决策 | 电脑落子 | 电脑怎样选一格 |
27
+ | 交互 | 终端程序、程序入口 | 人怎样下一局 |
28
+ | 质量 | 调试、测试、构建与运行 | 改动后怎样确认没坏 |
29
+ | 收束 | 局面快照 | 一局怎样保存与还原 |
30
+
31
+ 这张表只是示例。项目有自己的章节表时,以 `.agents/skills/quarto-book-project/writing/chapter-map.md` 为准;没有就按上面的阶段顺序推,不猜项目事实。
32
+
33
+ ## 插件层怎么配合
34
+
35
+ - 整书规划先读本文件与项目章节表,再逐章加载 `steps/`;不要一次读完九步。
36
+ - 单章判不准时才开 `examples/`;排图、查渲染或全仓重构才开 `quarto/`。
37
+ - 全仓检查用 `scripts/`,渲染验收用 `quarto_render_check`;两件事都放在最后一遍,不在骨架遍执行。
38
+ - 文件体量受 `references/token-budget.md` 约束;新增整书规则只写进本文件,不复制到各步。
@@ -0,0 +1,26 @@
1
+ # 技能文件的 token 预算
2
+
3
+ 本文件约束技能 Markdown 的体量。它只管加载成本,不替代 `docs/writing-quarto-layout.md` 的分层规则。
4
+
5
+ ## 预算
6
+
7
+ 估算口径:一个 CJK 字符按 1 token,其余字符按 4 字符 1 token 计。`scripts/checking-skill-budget.mjs` 用同一口径检查,`npm run check` 会执行。
8
+
9
+ | 目录或文件 | 单文件上限 |
10
+ | --- | --- |
11
+ | `writing-quarto/SKILL.md`、`designing-theme/SKILL.md` | 2000 |
12
+ | `steps/02-structure.md`、`steps/03-blocks.md`、`steps/05-sentences.md` | 12000 |
13
+ | 其余 `steps/*.md` | 8000 |
14
+ | `examples/*.md` | 5000 |
15
+ | `quarto/*.md` | 5000 |
16
+ | `designing-theme/references/theme-system.md` | 8000 |
17
+ | 其余 `references/*.md`、`knowledge/*.md` | 6000 |
18
+ | `assets/**/meta.md` | 2000 |
19
+ | 全部技能 Markdown 合计 | 140000 |
20
+
21
+ ## 怎么用
22
+
23
+ - 新增规则先判断属于哪一层,再写进已有文件;同一判定只成文一处,其他位置写引用。
24
+ - 文件将超限时,先删重复、合并同源条目,再考虑拆成同目录的新文件;拆文件后同步入口和 `scripts/checking-skill-links.mjs`。
25
+ - 单章润色只加载 `SKILL.md` 与当前一步;不要为了省 token 把整本书的规则塞进 `SKILL.md`。
26
+ - 预算不是目标:没必要的条文直接删,不靠缩写把句子压成暗语。
@@ -6,7 +6,7 @@ Quarto 只认内置 5 类 callout(note/tip/warning/important/caution)。未
6
6
  <section> 没有提示框样式。它还混进右侧目录。本脚本在 _book/**/*.html 里抓这一回归。
7
7
 
8
8
  用法:python checking-callouts.py [--root .] [--book-dir _book]
9
- 退出码:0 = 全部正常,1 = 发现退化的 callout。
9
+ 退出码:0 = 全部正常,1 = 发现退化的 callout,2 = 渲染产物目录缺失。
10
10
  """
11
11
 
12
12
  import argparse
@@ -71,7 +71,7 @@ def main():
71
71
  book_dir = root / book_dir
72
72
  if not book_dir.is_dir():
73
73
  print(f"未找到渲染产物目录:{book_dir};请先执行 quarto render。")
74
- return 1
74
+ return 2
75
75
 
76
76
  html_files = sorted(book_dir.rglob("*.html"))
77
77
  bad_pages = 0