@topmindspace/topmind-skills 4.13.0

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 (68) hide show
  1. package/INSTALL.md +295 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +162 -0
  4. package/README.md +162 -0
  5. package/README.zh-CN.md +162 -0
  6. package/bin/install-skills.mjs +693 -0
  7. package/evals/evals.json +236 -0
  8. package/install-targets/claude-code.json +62 -0
  9. package/install-targets/codex.json +60 -0
  10. package/install-targets/hermes.json +60 -0
  11. package/install-targets/opencode.json +63 -0
  12. package/integrations/codex/README.md +20 -0
  13. package/integrations/hermes/README.md +19 -0
  14. package/integrations/opencode/README.md +33 -0
  15. package/integrations/opencode/commands/topmind-capture.md +15 -0
  16. package/integrations/opencode/commands/topmind-doctor.md +11 -0
  17. package/integrations/opencode/opencode.example.json +20 -0
  18. package/integrations/opencode/plugins/topmind-plugin.ts +17 -0
  19. package/integrations/opencode/tests/opencode-config-shape.test.mjs +63 -0
  20. package/package.json +70 -0
  21. package/scripts/build-pack.mjs +463 -0
  22. package/shared/capability-degradation.md +82 -0
  23. package/shared/document-ingest.md +117 -0
  24. package/shared/host-loading.md +140 -0
  25. package/shared/long-url-capture.md +60 -0
  26. package/shared/output-language.md +32 -0
  27. package/shared/project-model-brief.md +132 -0
  28. package/shared/trigger-disambiguation.md +58 -0
  29. package/shared/writeback-receipt.md +73 -0
  30. package/skills.md +39 -0
  31. package/topmind/SKILL.md +170 -0
  32. package/topmind/references/connector-resolution.md +11 -0
  33. package/topmind/references/multi-intent.md +17 -0
  34. package/topmind/references/template-categories.md +45 -0
  35. package/topmind-capture/SKILL.md +148 -0
  36. package/topmind-ledger/SKILL.md +86 -0
  37. package/topmind-loop/DESIGN.md +82 -0
  38. package/topmind-loop/SKILL.md +111 -0
  39. package/topmind-loop/references/scopes-and-walk.md +56 -0
  40. package/topmind-loop/references/state-file.md +52 -0
  41. package/topmind-maintain/SKILL.md +104 -0
  42. package/topmind-memory/SKILL.md +117 -0
  43. package/topmind-organize/SKILL.md +144 -0
  44. package/topmind-pack.json +418 -0
  45. package/topmind-wechat/DESIGN.md +50 -0
  46. package/topmind-wechat/SKILL.md +218 -0
  47. package/topmind-wechat/assets/themes/amber-review.json +35 -0
  48. package/topmind-wechat/assets/themes/graphite.json +35 -0
  49. package/topmind-wechat/assets/themes/minimal-ink.json +35 -0
  50. package/topmind-wechat/assets/themes/newsprint.json +35 -0
  51. package/topmind-wechat/assets/themes/tech-blue.json +35 -0
  52. package/topmind-wechat/references/element-spec.md +162 -0
  53. package/topmind-wechat/references/known-pits.md +86 -0
  54. package/topmind-wechat/references/theme-map.md +139 -0
  55. package/topmind-wechat/references/typography-rules.md +62 -0
  56. package/topmind-wechat/references/wechat-constraints.md +106 -0
  57. package/topmind-wechat/references/workflow.md +102 -0
  58. package/topmind-wechat/references/writing-quality.md +129 -0
  59. package/topmind-wechat/scripts/lint-wechat.py +446 -0
  60. package/topmind-wechat/scripts/md2wechat.py +1599 -0
  61. package/topmind-wechat/scripts/new-article.py +183 -0
  62. package/topmind-wechat/scripts/push-to-topstream.py +226 -0
  63. package/topmind-wechat/scripts/scan_ai_flavor.py +464 -0
  64. package/topmind-wechat/scripts/sync-mapping.py +220 -0
  65. package/topmind-wechat/scripts/sync-status.py +187 -0
  66. package/topmind-weread/SKILL.md +97 -0
  67. package/topmind-write/SKILL.md +116 -0
  68. package/topmind-x/SKILL.md +97 -0
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "amber-review",
3
+ "name": "琥珀评测",
4
+ "genre": ["评测", "模型评测", "数据对比", "榜单", "速览"],
5
+ "accent": "#B45309",
6
+ "accent_light": "#E8C79A",
7
+ "accent_soft": "#FBF2E4",
8
+ "text": "#3A3226",
9
+ "text_strong": "#231A0E",
10
+ "text_muted": "#8A7A62",
11
+ "text_light": "#A3927A",
12
+ "surface": "#FAF6EF",
13
+ "border": "#EADFCB",
14
+ "code_bg": "#2B2620",
15
+ "code_text": "#EFE7DA",
16
+ "code_scheme": "mono",
17
+ "c_note": "#C7B9A2",
18
+ "c_tip": "#4F8763",
19
+ "c_warn": "#C98A2B",
20
+ "c_danger": "#BC4F3E",
21
+ "radius": "6px",
22
+ "font_size": "16px",
23
+ "line_height": "1.75",
24
+ "para_gap": "22px",
25
+ "align": "left",
26
+ "h2_style": "number",
27
+ "toc": true,
28
+ "toc_max": 5,
29
+ "toc_min_h2": 4,
30
+ "toc_min_chars": 2000,
31
+ "table_max_cols": 3,
32
+ "img_border": "#EDE2D0",
33
+ "font_stack": "-apple-system,BlinkMacSystemFont,'Helvetica Neue','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif",
34
+ "mono_stack": "Menlo,Monaco,Consolas,'Courier New',monospace"
35
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "graphite",
3
+ "name": "石墨灰阶",
4
+ "genre": ["技术说明", "专业评论", "方法", "原理"],
5
+ "accent": "#52525B",
6
+ "accent_light": "#52525B",
7
+ "accent_soft": "#EFEFF1",
8
+ "text": "#3A3A3A",
9
+ "text_strong": "#1C1C1C",
10
+ "text_muted": "#7A7A7A",
11
+ "text_light": "#9E9E9E",
12
+ "surface": "#F4F4F4",
13
+ "border": "#E2E2E2",
14
+ "code_bg": "#262626",
15
+ "code_text": "#E4E4E4",
16
+ "code_scheme": "mono",
17
+ "c_note": "#BDBDBD",
18
+ "c_tip": "#6E7F6E",
19
+ "c_warn": "#A08B5E",
20
+ "c_danger": "#9C5B52",
21
+ "radius": "0px",
22
+ "font_size": "16px",
23
+ "line_height": "1.75",
24
+ "para_gap": "22px",
25
+ "align": "left",
26
+ "h2_style": "underline",
27
+ "toc": true,
28
+ "toc_max": 5,
29
+ "toc_min_h2": 4,
30
+ "toc_min_chars": 2000,
31
+ "table_max_cols": 3,
32
+ "img_border": "#EAEAEA",
33
+ "font_stack": "-apple-system,BlinkMacSystemFont,'Helvetica Neue','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif",
34
+ "mono_stack": "'SF Mono',Menlo,Consolas,'Courier New',monospace"
35
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "minimal-ink",
3
+ "name": "极简黑白灰",
4
+ "genre": ["默认", "观点", "深度分析", "随笔"],
5
+ "accent": "#A6524A",
6
+ "accent_light": "#E3BAB3",
7
+ "accent_soft": "#FAF0EE",
8
+ "text": "#333333",
9
+ "text_strong": "#1A1A1A",
10
+ "text_muted": "#888888",
11
+ "text_light": "#999999",
12
+ "surface": "#F7F7F7",
13
+ "border": "#E8E8E8",
14
+ "code_bg": "#2C2C2C",
15
+ "code_text": "#E8E8E8",
16
+ "code_scheme": "mono",
17
+ "c_note": "#C9C9C9",
18
+ "c_tip": "#5B8C5A",
19
+ "c_warn": "#C08A3E",
20
+ "c_danger": "#B5544C",
21
+ "radius": "4px",
22
+ "font_size": "16px",
23
+ "line_height": "1.75",
24
+ "para_gap": "22px",
25
+ "align": "left",
26
+ "h2_style": "number",
27
+ "toc": true,
28
+ "toc_max": 5,
29
+ "toc_min_h2": 4,
30
+ "toc_min_chars": 2000,
31
+ "table_max_cols": 3,
32
+ "img_border": "#F0F0F0",
33
+ "font_stack": "-apple-system,BlinkMacSystemFont,'Helvetica Neue','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif",
34
+ "mono_stack": "Menlo,Monaco,Consolas,'Courier New',monospace"
35
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "newsprint",
3
+ "name": "报纸纸感",
4
+ "genre": ["复盘", "特稿", "行业观察", "长文"],
5
+ "accent": "#8C5A3C",
6
+ "accent_light": "#D8C0A8",
7
+ "accent_soft": "#F3E9DE",
8
+ "text": "#2B2B2B",
9
+ "text_strong": "#14110E",
10
+ "text_muted": "#7A7268",
11
+ "text_light": "#9C938A",
12
+ "surface": "#F5F3EE",
13
+ "border": "#E2DDD2",
14
+ "code_bg": "#2E2B27",
15
+ "code_text": "#EDE8DF",
16
+ "code_scheme": "mono",
17
+ "c_note": "#B4AEA2",
18
+ "c_tip": "#5F7A55",
19
+ "c_warn": "#B07C33",
20
+ "c_danger": "#A24B3C",
21
+ "radius": "0px",
22
+ "font_size": "16px",
23
+ "line_height": "1.8",
24
+ "para_gap": "24px",
25
+ "align": "left",
26
+ "h2_style": "center",
27
+ "toc": true,
28
+ "toc_max": 5,
29
+ "toc_min_h2": 4,
30
+ "toc_min_chars": 2000,
31
+ "table_max_cols": 3,
32
+ "img_border": "#E5E1D8",
33
+ "font_stack": "'Songti SC','Noto Serif CJK SC','Source Han Serif SC',Georgia,'Times New Roman',serif",
34
+ "mono_stack": "'SF Mono',Menlo,Consolas,'Courier New',monospace"
35
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "id": "tech-blue",
3
+ "name": "科技蓝",
4
+ "genre": ["教程", "实操", "工具测评", "建站"],
5
+ "accent": "#185FA5",
6
+ "accent_light": "#A9C9E8",
7
+ "accent_soft": "#EAF2FA",
8
+ "text": "#333333",
9
+ "text_strong": "#12233A",
10
+ "text_muted": "#6B7C93",
11
+ "text_light": "#96A3B4",
12
+ "surface": "#F2F6FB",
13
+ "border": "#DCE6F2",
14
+ "code_bg": "#1B2733",
15
+ "code_text": "#DCE6F2",
16
+ "code_scheme": "mono",
17
+ "c_note": "#A8B8C8",
18
+ "c_tip": "#3F8F6A",
19
+ "c_warn": "#C08A3E",
20
+ "c_danger": "#C0554A",
21
+ "radius": "6px",
22
+ "font_size": "16px",
23
+ "line_height": "1.75",
24
+ "para_gap": "22px",
25
+ "align": "left",
26
+ "h2_style": "number",
27
+ "toc": true,
28
+ "toc_max": 5,
29
+ "toc_min_h2": 4,
30
+ "toc_min_chars": 2000,
31
+ "table_max_cols": 3,
32
+ "img_border": "#E4EDF7",
33
+ "font_stack": "-apple-system,BlinkMacSystemFont,'Helvetica Neue','PingFang SC','Hiragino Sans GB','Microsoft YaHei',sans-serif",
34
+ "mono_stack": "Menlo,Monaco,Consolas,'Courier New',monospace"
35
+ }
@@ -0,0 +1,162 @@
1
+ # 元素渲染规范
2
+
3
+ `md2wechat.py` 把 Markdown 转成公众号内联样式 HTML 的**唯一依据**。
4
+ 改渲染逻辑或新增语法时,先改本文件再改代码;`audit_inline()` 是本文件的自动校验版本。
5
+
6
+ 合规分级(贯穿全篇):
7
+
8
+ | 级别 | 含义 | 处理原则 |
9
+ |---|---|---|
10
+ | **S** 安全 | 内联纯色/边框/字号,不会静默失效 | 可以放心依赖 |
11
+ | **D** 降级 | 可能被丢弃,但丢了不破坏结构与可读性 | 可用,但**不得作为唯一区分手段** |
12
+ | **X** 禁用 | 会静默失效或整段被吞 | 一律不用;`audit_inline` 判 ERROR |
13
+
14
+ ---
15
+
16
+ ## 一、块级元素
17
+
18
+ | Markdown | 产物 | 级 | 说明 |
19
+ |---|---|---|---|
20
+ | `# 标题` | `<p style="20px/700/center">` | S | 不用 `<h1>`(微信按标题语义覆盖字号) |
21
+ | `## 标题` | `<h2 style="18px/700;color:text_strong">` + 自动编号 | S | 见下方「章节编号」 |
22
+ | `### 标题` | `<h3 style="16px/600">` | S | |
23
+ | `#### 标题` | `<h4 style="15px/600">` | S | |
24
+ | 段落 | `<p style="margin:0 0 {para_gap};line-height:{line_height};letter-spacing:0.5px;text-align:left;word-break:break-word">` | S | `text-align` 只允许 left/center/right |
25
+ | `---` | `<p style="center"><span style="display:inline-block;width:12%;height:2px;background:accent">` | D | 短横线依赖 `inline-block`;丢了会退化成一条不可见的行内元素 |
26
+ | `> 引用` | `<section>` + `background:surface` + `border-left:3px solid accent` | S | **不用 `<blockquote>`**:微信有原生引用样式会覆盖我们的配色 |
27
+ | `- 项` / `1. 项` | `<ul>`/`<ol>` + `<li>`,支持嵌套 | S | 圆点颜色取 accent |
28
+ | ```` ```lang ```` | `<section background:code_bg>` → 语言标签 `<section>` → 代码体 `<section style="white-space:pre-wrap;word-break:break-all">` | S | **不用 `<pre>`**;详见「代码块」 |
29
+ | 表格(≤3 列) | `<table style="width:100%">`,表头行是首个 `<tr>` | S | **不写 `table-layout:fixed`**,**不用 `thead/tbody/colgroup`** |
30
+ | 表格(≥4 列) | 自动转卡片:每行一张 `<section>`,首列作标题、其余「列名 + 值」成对 | S | 公众号列数 >4 必然横向溢出,卡片化是唯一稳的解法 |
31
+ | `![说明](src)` | `<section>` → `<p center>` → `<img style="max-width:100%;height:auto;display:block;margin:0 auto">` | S | **不用 `width:100%`**(小图被拉满变糊);**不用 `<figure>`** |
32
+ | `*图注*`(紧随图片) | `<p style="13px;color:text_light;center">` | S | 独立 `<p>`,不嵌在图片块里 |
33
+
34
+ ---
35
+
36
+ ## 二、行内元素
37
+
38
+ | Markdown | 产物 | 级 | 视觉层级 |
39
+ |---|---|---|---|
40
+ | `**文字**` | `<strong style="font-weight:600;color:text_strong">` | S | **锚点层**,全文 ≤5 处 |
41
+ | `*文字*` | `<em style="font-style:normal;color:text_muted">` | S | 弱化 |
42
+ | `` `代码` `` | `<code style="background:surface;color:accent;font-family:mono">` | S | |
43
+ | `==文字==` | `<strong>` + `background:accent_soft` | S | 容器层(高亮) |
44
+ | `++文字++` 或 `<u>文字</u>` | `<span style="border-bottom:2px solid accent_light;font-weight:600;color:text_strong">` | S | **标记层**,每段 1–3 个 |
45
+ | `~~文字~~` | `<span style="background:accent_soft;font-weight:600">` | S | 半高亮 |
46
+ | `[!文字]` | `<span style="11px;color:accent;background:accent_soft;padding:1px 6px">` | S | 徽章;不用 `inline-block` |
47
+ | `[文字](url)` | 正文 `文字` + 上标 `[n]`,文末「参考链接」块 | S | 公众号正文不支持可点外链 |
48
+
49
+ ### 视觉层级(三层,写稿时的标记纪律)
50
+
51
+ | 层 | 手段 | 频率 | 用错会怎样 |
52
+ |---|---|---|---|
53
+ | **锚点层** | `**加粗**` | 全文 **≤5 处** | 到处加粗 = 没有重点 |
54
+ | **标记层** | `++下划线++` | **覆盖 ≥60% 的正文段落**,每段 1–3 个 4–15 字短语 | 缺失 = 正文变成一堵灰墙,读者无处落脚 |
55
+ | **容器层** | `==高亮==`、`::: 容器`、引用块 | 按需 | 堆太多会显得花 |
56
+
57
+ 标记层是**出现频率最高**的一层,也是最容易被漏掉的一层。
58
+
59
+ `lint-wechat.py` 分两层判:**标记覆盖率 ≥60%**(带标记的正文段落数 ÷ 正文段落数,低于就报「跳读时没有落点」)+ **锚点加粗 ≤5 处**(超出就报「把标记当锚点用」)。
60
+
61
+ **不用「强调占比」这个口径**——它把两层合成一个数,会同时掩盖两种病:锚点爆表(加粗 123 处)和标记归零(下划线 0 处)能算出相近的占比,但修法完全不同。占比还容易凑:35 段里只标 5 段、每段标 20 字也能到 10%,而整段划线等于没标。覆盖率对应的是「还有几段没标」这个可执行动作。
62
+
63
+ ---
64
+
65
+ ## 三、容器
66
+
67
+ `:::` 是自研中间标记(公众号不认 Markdown,由 `md2wechat.py` 转成内联样式 HTML)。
68
+
69
+ | 写法 | 产物 | 用在哪 |
70
+ |---|---|---|
71
+ | `::: note` | 灰边说明块 | 补充说明 |
72
+ | `::: tip` | 绿边提示块 | 实操建议 |
73
+ | `::: warn` | 琥珀边注意块 | 风险提醒 |
74
+ | `::: danger` | 红边警告块 | 严重风险 |
75
+ | `::: pull` | 上下框线 + 居中金句 | 全文点睛,1–2 处 |
76
+ | `::: stat` | 浅底卡片 + 大号 accent 数字 | 关键数据(`数值 \| 说明` 每行一条) |
77
+ | `::: dialogue` | 说话人 + 气泡 | 访谈、问答 |
78
+ | `::: toc` | 前言导读卡 | 一般不用手写,见「自动导读」 |
79
+ | `::: sign` | 尾部签名区 | 一般不用手写,见「自动签名」 |
80
+
81
+ 容器名拼错会**静默降级成 note**——`lint-wechat.py` 会报未知容器。
82
+ 别名(`info`/`memo`→note,`success`/`ok`→tip,`quote`/`golden`→pull,`data`/`metric`→stat,
83
+ `chat`/`talk`→dialogue)等价。
84
+
85
+ ---
86
+
87
+ ## 四、三段自动行为
88
+
89
+ ### 章节编号
90
+
91
+ - 标题里**手写的序号会被剥离**:`## 一、官方总表` → `01 官方总表`
92
+ - 剥离规则:中文序号(`一、`/`第一、`)、阿拉伯序号(`1.`/`01 `)
93
+ - 带负向断言保护:`## 3.4× 成本` **不会**被误剥成 `4× 成本`
94
+ - 编号由 `h2_style` 决定:`number`(01 + 左竖条,默认)/ `bar`(仅左竖条)/
95
+ `underline`(下划线)/ `center`(上下框线)/ `plain`(无装饰)
96
+ - **末章若为收束类用 `∞` 而不是顺延数字**:标题匹配
97
+ 总结/结语/小结/尾声/后记/写在最后/写在后面/收尾/结尾/余论 时,编号取 `∞`
98
+ (`number` 样式下生效)。理由:数字编号暗示"还有下一节",与收束章的定位打架。
99
+ 实测 `## 六、总结` → `∞ 总结`,其余仍为 `01`…`05`。
100
+ - **写稿时不要手写序号**:手写后序号变成不可编程的字符串,
101
+ 换编号样式、加引用、做导航都得手改一遍
102
+
103
+ ### 前言导读
104
+
105
+ - 触发条件(满足任一,且 `toc` 未被 `--no-toc` 关闭):
106
+ - 章节数 ≥ `toc_min_h2`(默认 4)
107
+ - 章节数 ≥ 3 且正文 ≥ `toc_min_chars`(默认 2000 中文字)
108
+ - 位置:**首个正文段落之后**(不是标题与封面图之间)
109
+ - 内容:最多 `toc_max`(默认 5)条,超出时附注「……共 N 节」
110
+ ——**不假装全文只有这几节**
111
+ - **导读的标记必须与正文标题一致**:
112
+ - 标题带编号(`number`)→ 导读也编号,末章收束类同为 `∞`
113
+ - 标题不带编号(`center`/`underline`/`plain`)→ 导读用中性圆点 `·`,
114
+ **不能凭空造出 01/02**(否则读者在正文里找不到对应的编号)
115
+ - 显式 `::: toc` 优先于自动插入
116
+
117
+ ### 尾部签名
118
+
119
+ `--signature` 三态:
120
+
121
+ | 值 | 行为 |
122
+ |---|---|
123
+ | `auto`(默认) | 稿件末尾**已自带**签名/CTA 则不再追加,避免出现两处签名区 |
124
+ | `on` | 无条件追加 |
125
+ | `off` | 只在显式写了 `::: sign` 时渲染 |
126
+
127
+ - 署名用占位 `{{作者名}}`,**不替用户编造人名**;`--author` / `--author-bio` 可填
128
+ - 判定「已自带」的口径:正文末尾 8 个非空段落内出现
129
+ `点赞 / 在看 / 三连 / 点个关注 / 欢迎关注 / 关注「 / 扫码 / 分享给 / 我是…,`
130
+
131
+ ---
132
+
133
+ ## 五、代码块
134
+
135
+ - **不用 `<pre>`**:公众号端不自动换行,窄屏横向溢出,且格式检测会标风险项
136
+ - 用 `<section>` + `white-space:pre-wrap` + `word-break:break-all`
137
+ - 缩进与换行由代码自身提供:**HTML 源码里不在 pre-wrap 容器内插入任何格式化换行**
138
+ (插了就会渲染出伪空行和大左缩进)
139
+ - **色板跟随主题**(`code_scheme`):
140
+ - `mono`(默认):只用「主色 + 明暗层级」。注释最暗、字符串次之、
141
+ 关键字取主色的提亮版、其余用 `code_text`
142
+ - `palenight`:Material Palenight 的 16 色,**已不推荐**——
143
+ 天蓝/翠绿/橙红与砖红、琥珀等主色毫无关系,一篇文章里会出现两套色彩语言
144
+ - 语言标签显示在代码体上方,字号 11px,颜色取 accent
145
+
146
+ ---
147
+
148
+ ## 六、`audit_inline()` 检查清单
149
+
150
+ 每次生成 HTML 后自动跑,`ERROR` 必须清零。检查项已按本文件分级:
151
+
152
+ **ERROR**:`<div>` `<figure>` `<figcaption>` `<pre>` `<thead>` `<tbody>` `<colgroup>`
153
+ `<h1>` `<iframe>` `<video>` `<script>` `<style>`;`text-align` 非标准值;
154
+ px 固定宽度;`white-space:pre/nowrap`;`position/float/transform/opacity`;
155
+ `display:flex/grid`;`-webkit-*`;`linear-gradient`;`box-shadow`;`rgba()/hsla()`;
156
+ `var(--)`;`@media/@keyframes`;`class` 属性;Markdown 标记残留(`==`、`**`)
157
+
158
+ **WARN**:`table-layout:fixed`(列宽均分)、`display:inline-block`(非常规 display 值)、
159
+ `border-radius`(可能被丢,属优雅降级)、图片 `width:100%`、`id` 属性、
160
+ `<img width="...">` 属性
161
+
162
+ WARN 不是「可以忽略」,而是「已知风险,需确认是否可接受」。
@@ -0,0 +1,86 @@
1
+ # 已知坑(实测踩过,写入质检与操作纪律)
2
+
3
+ ## 1. `--embed-images` 不加 = 粘贴丢图
4
+
5
+ 链路:HTML `src="images/xx.png"` → 浏览器复制序列化成 `file://` → 公众号后台取不到 → **整张 `<img>` 消失**(不是裂图)。
6
+
7
+ **修法**:`md2wechat.py --embed-images`(base64 内嵌)。`images/` 仍导出作占位符兜底。
8
+
9
+ 自检:
10
+
11
+ ```bash
12
+ grep -c 'src="images/' <包>/*-公众号版.html # 期望 0
13
+ grep -c 'src="data:image/' <包>/*-公众号版.html # 期望 = 正文图数
14
+ ```
15
+
16
+ ## 2. 图片 basename 撞名 → 链式全挂
17
+
18
+ `resolve_image()` 按 **basename** 复制到 `images/`。`images/bare/01.png` 与 `images/01.png` 同名 → 产出 `01-1.png` → 删副本 = HTML 图全挂。
19
+
20
+ **铁律**:
21
+
22
+ - 正文只引用 `images/XX.png`,包内只放正文那一套
23
+ - 多套用不同前缀(`full-` / `bare-`),不要靠子目录区分
24
+ - `-1` 副本不是垃圾,是 HTML 正在引用的文件
25
+
26
+ 自检:
27
+
28
+ ```bash
29
+ find <包> -name "*-1.*" # 不应有任何结果
30
+ ```
31
+
32
+ ## 3. 同一文件并行 Edit 只落盘一部分
33
+
34
+ 同一条消息多个 Edit:工具可能都回 Successfully,**只有部分落盘**。
35
+
36
+ **纪律**:改完必须 `grep` 关键词复核;多处改动合成一个脚本一次写完,或串行分轮。
37
+
38
+ ## 4. `::: stat` 非管道行被静默丢弃
39
+
40
+ 容器内每行必须 `数值 | 说明`。不带 `|` 的行整块消失且无报错。生成 HTML 后抽查容器内容。
41
+
42
+ ## 5. 表格单元格 `|` 要转义
43
+
44
+ 生成 markdown 表时 `.replace(/\|/g, '\\|')`。JS 模板字符串里写 `\\\\|` 才得到 `\\|`。
45
+
46
+ ## 6. 代码块长行被 `break-all` 词中切断
47
+
48
+ JSON 示例行宽压到 ~55 字符;真实节选注明「节选」,字段值不得改写。
49
+
50
+ ## 7. 图文两套同名 + 清理 `bare/`
51
+
52
+ 完整版与纯图形版共处包内必撞名。完整版放研究层;交付包只留正文用的一套。
53
+
54
+ ## 8. 外部工具改稿的数字漂移
55
+
56
+ 「比值对但绝对值错」= 从别的口径倒推。先脚本回溯 `results/*.json`,再改文字。
57
+
58
+ ## 9. 表格手抄必漂移
59
+
60
+ 从数据源生成(脚本直出)。同一文档两份拷贝时 `md5` 比对;派生汇总字段也是数据,要回填。
61
+
62
+ ## 10. qu-aiwei 误报别改坏
63
+
64
+ - 「排比三段式」可能误报数据变化(从 A 到 B)→ **保留**
65
+ - 专有名词「复盘」→ 不改;动词套话 → 改
66
+
67
+ ## 11. 满分仍「太 AI」
68
+
69
+ 词面 100 分只证明无套话。再查四症状:段末金句癖 / 节奏过分整齐 / 没有「我」与场景 / 报告体标注。
70
+
71
+ ## 12. 加「人味」用力过猛
72
+
73
+ 社交垫词(「先说个好消息」「说白了」)不是人味。判据:删掉后读者少知道了什么?
74
+
75
+ ## 13. 长文零容器 = 视觉窒息
76
+
77
+ 每 1500–2500 字至少一个 `::: stat` 或 `::: pull`。8000 字纯段落反面教材。
78
+
79
+ ## 14. 复制依赖 `execCommand`
80
+
81
+ Safari 可能失败 → 手动全选复制。Desktop/移动端提供按钮 + 失败提示。
82
+
83
+ ## 15. 合规自检误报
84
+
85
+ - 正文 `<h2>` 是有意设计(不用 h1)
86
+ - `pre` 会命中英文单词;只在 `<article>` 内按标签形式匹配
@@ -0,0 +1,139 @@
1
+ # 题材 → 主题映射
2
+
3
+ 「按题材分主题」的规约。主题文件在 `assets/themes/*.json`,
4
+ 命令行 `--theme` 选主题,`--list-themes` 看全部,`genre:题材` 按题材自动选。
5
+
6
+ ## 已注册主题
7
+
8
+ | 主题 | 标识 | 主色 | 标题样式 | 圆角 | 适用题材 |
9
+ |---|---|---|---|---|---|
10
+ | 极简黑白灰 | `minimal-ink` | `#A6524A` 砖红 | number | 4px | **默认**、观点、深度分析、随笔 |
11
+ | 科技蓝 | `tech-blue` | `#185FA5` 蓝 | number | 6px | 教程、实操、工具测评、建站 |
12
+ | 石墨灰阶 | `graphite` | `#52525B` 石墨 | underline | 0px | 技术说明、专业评论、方法、原理 |
13
+ | 报纸纸感 | `newsprint` | `#8C5A3C` 棕(衬线) | center | 0px | 复盘、特稿、行业观察、长文 |
14
+ | 琥珀评测 | `amber-review` | `#B45309` 琥珀 | number | 6px | 评测、模型评测、数据对比、榜单、速览 |
15
+
16
+ ```bash
17
+ # 看清单
18
+ python3 scripts/md2wechat.py --list-themes
19
+
20
+ # 指定主题(三种写法都可以)
21
+ --theme amber-review # 标识
22
+ --theme 琥珀评测 # 中文名
23
+ --theme genre:评测 # 按题材自动选
24
+ ```
25
+
26
+ ## 选题材的原则
27
+
28
+ **一句话**:主题跟着**题材**走,不跟着心情走。同一个题材永远用同一套主题,
29
+ 读者才能形成视觉记忆。换题材时才换主题。
30
+
31
+ | 判断依据 | 走哪个主题 |
32
+ |---|---|
33
+ | 有大量数据对比、榜单、多维评分 | 琥珀评测 |
34
+ | 有步骤、命令、可复现的操作过程 | 科技蓝 |
35
+ | 讲原理、讲机制、专业观点输出,需要克制 | 石墨灰阶 |
36
+ | 讲一个完整案例的来龙去脉、时间跨度长 | 报纸纸感 |
37
+ | 观点表达、行业观察、随笔,没有明显题材特征 | 极简黑白灰(默认) |
38
+
39
+ **题材交叉时**(如"带步骤的模型评测"):看**读者来干什么**。
40
+ 来抄操作步骤的 → 科技蓝;来看结论和数据的 → 琥珀评测。
41
+
42
+ ## 主题之间必须一致的东西
43
+
44
+ 换主题**只换色彩与标题形态**,以下参数在所有主题间保持一致,不要随手改:
45
+
46
+ | 参数 | 统一值 | 理由 |
47
+ |---|---|---|
48
+ | 正文字号 | 16px | 公众号长文阅读舒适区 |
49
+ | 行高 | 1.75(报纸纸感 1.8) | 低于 1.7 会挤 |
50
+ | 段间距 | 22px(报纸纸感 24px) | 与行高成比例 |
51
+ | 对齐 | `left` | 中文 `justify` 会产生「河流」并触发格式告警 |
52
+ | 章节编号 | 全部由排版层生成 | 见 `element-spec.md`「章节编号」;末章收束类用 `∞` |
53
+ | 视觉层级规则 | 锚点层 ≤5 / 标记层每段 1–3 | 与主题无关,是阅读规律 |
54
+
55
+ **这些是阅读规律,不是审美偏好**,任何主题都不该改。
56
+
57
+ ## 每套主题必须提供的字段
58
+
59
+ 新增主题时字段缺一个,就会继承默认主题的值——**这正是历史 bug 的成因**:
60
+ `tech-blue` 当年只写了 14 个字段,`mark_bg` 落到默认主题的砖红浅底 `#FAF0EE`,
61
+ 一套蓝色主题里冒出砖红高亮,于是从来没人敢用它。现在 `load_theme()` 会按各自主色
62
+ 自动派生 `accent_light` / `accent_soft`,但**其余字段仍需显式写全**。
63
+
64
+ ```jsonc
65
+ {
66
+ "id": "标识(英文,命令行用)",
67
+ "name": "中文名",
68
+ "genre": ["题材1", "题材2"], // `--theme genre:题材` 按此匹配,也用于 --list-themes 展示
69
+
70
+ // 主色三件套:派生色可不写(自动按 accent 算),写了则以文件为准
71
+ "accent": "#______", // 唯一强调色
72
+ "accent_light": "#______", // 关键词下划线(标记层)
73
+ "accent_soft": "#______", // 高亮底 / 徽章底
74
+
75
+ // 文字四级
76
+ "text": "#______", // 正文
77
+ "text_strong": "#______", // 加粗、标题
78
+ "text_muted": "#______", // 斜体、脚注
79
+ "text_light": "#______", // 图注、数值说明、导读截断提示
80
+
81
+ // 面与线
82
+ "surface": "#______", // 卡片底(stat/引用/签名/导读共用)
83
+ "border": "#______", // 表格线、金句上下框线
84
+ "img_border": "#______", // 图片描边
85
+
86
+ // 代码块:色板按 accent 自动生成,配色方案二选一
87
+ "code_bg": "#______",
88
+ "code_text": "#______",
89
+ "code_scheme": "mono", // mono(推荐,只用主色+明暗)| palenight(不推荐)
90
+
91
+ // 四种语义色(容器左边框)
92
+ "c_note": "#______", "c_tip": "#______",
93
+ "c_warn": "#______", "c_danger": "#______",
94
+
95
+ // 形态
96
+ "radius": "0px | 4px | 6px", // 全主题统一圆角;直角最保守
97
+ "h2_style": "number | bar | underline | center | plain",
98
+ "line_height": "1.75",
99
+ "para_gap": "22px",
100
+ "align": "left",
101
+ "font_size": "16px",
102
+
103
+ // 结构组件
104
+ "toc": true, "toc_max": 5, "toc_min_h2": 4, "toc_min_chars": 2000,
105
+ "table_max_cols": 3, // 超过就转卡片化
106
+
107
+ "font_stack": "...", "mono_stack": "..."
108
+ }
109
+ ```
110
+
111
+ ## 加一套新主题的步骤
112
+
113
+ 1. 在 `assets/themes/` 写 `{id}.json`,字段按上表写全
114
+ 2. 跑 `python3 scripts/md2wechat.py --list-themes` 确认能被列出
115
+ 3. 用一篇真实稿跑一遍,确认 `合规自检` 为 0 ERROR:
116
+ `python3 scripts/md2wechat.py --input 稿.md --out-dir /tmp/t --slug t --theme {id}`
117
+ 4. 在本文件的主题表里登记一行
118
+ 5. 目视核对:**下划线色、高亮底、代码块关键字色是否都跟本主题主色同源**
119
+ (不同源 = 又出现了色彩外溢)
120
+
121
+ ## 主题与视觉层级的配合
122
+
123
+ 三层标记手段在所有主题下的表现:
124
+
125
+ | 层 | 手段 | 主题相关性 |
126
+ |---|---|---|
127
+ | 锚点层 | 主色加粗 / 深色底白字引用 | 用 `text_strong`,**不用 accent**——浅色主题下 accent 加粗不够重 |
128
+ | 标记层 | 下划线 `accent_light` | 浅色主题用浅色调(砖红→`#E3BAB3`);深色主题用主色本身(石墨→`#52525B`) |
129
+ | 容器层 | 底色 `surface` + 左边框 `accent` | 全主题统一结构,只换色 |
130
+
131
+ 石墨灰阶的下划线特意用主色本身而不是浅色调:灰色主题里浅灰下划线几乎看不见,
132
+ 起不到标记作用。**下划线色的选择标准是「能不能看见」,不是「够不够淡」。**
133
+
134
+ ### `h2_style` 会连带影响导读
135
+
136
+ 导读(前言看点)的标记跟随 `h2_style`:带编号的主题(`minimal-ink`/`tech-blue`/`amber-review`)
137
+ 导读也编号,末章收束类同为 `∞`;不带编号的主题(`graphite` 下划线 / `newsprint` 上下框线)
138
+ 导读只能用中性圆点。**换主题时导读会自动跟着变,不用手改**——但如果发现"导读有 01、正文没编号",
139
+ 那是渲染器 bug,不是主题配置问题。
@@ -0,0 +1,62 @@
1
+ # 公众号改稿规则(Stage 1 执行标准)
2
+
3
+ 从技术博客 Markdown 到公众号稿,改的是**阅读节奏**,不是技术事实。事实、数据、链接一律不动。
4
+
5
+ ## 必须做
6
+
7
+ 1. **开头 150 字内给钩子**:结论、反差或悬念,不要背景铺垫。原文首段若是长背景,压缩或后移。
8
+ 2. **段落切分**:单段 ≤ 110 字(约 4 行手机屏)。长段按语义断点拆开,不要机械等分。
9
+ 3. **小标题序号化**:二级标题统一「一、二、三」或「01 / 02」,读者能感知进度。
10
+ 4. **列表项 ≤ 70 字**:超长列表项改成「加粗小标题 + 短说明」的段落组。
11
+ 5. **重点加粗**:只加粗结论句和关键数据,全篇加粗密度控制在每 20 字不超过 1 处。
12
+ 6. **长句拆短**:单句 > 45 字且有逗号堆叠时,拆成两句。
13
+ 7. **图注统一**:`*▲ 图 N:说明*`,图注要说出「看什么」,不要只重复图片名。
14
+ 8. **外链处理**:保留可点性无意义,改为「来源:XXX(URL)」的灰色小字或直接写机构名。
15
+ 9. **结尾三段式**:一句总结结论 → 一句抛出问题/邀请讨论 → 引导关注语。
16
+
17
+ ## 不要做
18
+
19
+ - 不改技术事实、不改数据、不改评测结论
20
+ - 不删代码块(公众号读者需要可复制的配置/命令)
21
+ - 不把「我」改成「笔者」「作者」等腔调词,第一人称是这类文章的信任来源
22
+ - 不加「随着...的发展」「在当今时代」这类 AI 腔 / 八股开场
23
+ - 不加 emoji 堆砌的小标题
24
+ - 不为了凑字数注水,公众号长文 3000-6000 字是合理区间
25
+ - 中英文/数字之间忘了空格没关系(lint --fix 会补),但**别手动在代码和链接里加**
26
+
27
+ ## 容器语法使用时机(v2)
28
+
29
+ | 时机 | 用法 |
30
+ |---|---|
31
+ | 一句话核心观点、想让它从版面上跳出来 | `::: pull` 金句容器(大字居中,前后留白) |
32
+ | 关键数据对比(如「62.7% vs 99.9%」) | `::: stat` 数据卡(大数字 + 注释) |
33
+ | 补充但不打断主线的信息 | `::: note` 灰色提示框 |
34
+ | 操作建议、经验窍门 | `::: tip` 绿色提示框 |
35
+ | 容易踩的坑、官方风险提示 | `::: warn` 橙色 / `::: danger` 红色 |
36
+ | 观点交锋、问答式段落(A: B:) | `::: dialogue` 对话容器 |
37
+ | 版本号、状态标签、关键词打标 | `[!新特性]` 行内徽章 |
38
+ | 全文最重要的 1-3 句 | `==高亮==`(节制使用) |
39
+
40
+ 原则:**每 800 字最多 1 个容器**,容器是调味料不是主菜;连续两种容器相邻会显得杂乱。
41
+
42
+ ## 去 AI 腔检查点
43
+
44
+ - 排比三连句("不是 A,不是 B,而是 C")出现超过 2 次 → 改写
45
+ - 「值得注意的是」「综上所述」「不难看出」→ 删
46
+ - 每段都以「首先/其次/最后」开头 → 打散
47
+ - 形容词堆叠("极其轻巧稳定的架构")→ 留一个
48
+
49
+ ## 排版参数基线(调研印证的通用规范)
50
+
51
+ - 正文 16px、行距 1.75、字间距 0、左对齐(不用 justify,会被格式检测判为非标准值)
52
+ - 段间距 22px 代替首行缩进(手机端惯例)
53
+ - 正文色 #333(纯黑 #000 在白底上过刺眼),辅助文字 #888
54
+ - 代码块深底浅字(浅灰底代码块在部分安卓机型上对比度不足)
55
+
56
+ ## 交付前自检
57
+
58
+ ```bash
59
+ python3 scripts/lint-wechat.py --input 公众号稿.md --fix
60
+ ```
61
+
62
+ 错误项(长段 > 200 字 / 图片缺失/过大)必须清零;警告项逐条判断是否接受。