@topmindspace/tms-skills 0.2.0 → 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.
Files changed (49) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.en.md +57 -12
  3. package/README.md +56 -11
  4. package/bin/tms-skills.js +35 -5
  5. package/package.json +1 -1
  6. package/top-ppt-html/README.en.md +2 -2
  7. package/top-ppt-html/README.md +3 -3
  8. package/top-ppt-html/SKILL.md +4 -5
  9. package/top-ppt-html/references/modes.md +1 -1
  10. package/top-ppt-html/scripts/audit_docs.py +24 -0
  11. package/top-ppt-html/scripts/audit_skill.py +2 -2
  12. package/top-ppt-html/scripts/build_pptx.js +36 -0
  13. package/top-ppt-html/scripts/package_skill.py +3 -3
  14. package/topmind-cover/README.en.md +68 -0
  15. package/topmind-cover/README.md +34 -6
  16. package/topmind-cover/SKILL.md +44 -7
  17. package/topmind-cover/assets/examples/README.md +37 -0
  18. package/topmind-cover/assets/examples/big-type-wechat.png +0 -0
  19. package/topmind-cover/assets/examples/big-type.png +0 -0
  20. package/topmind-cover/assets/examples/brand-launch-wechat.png +0 -0
  21. package/topmind-cover/assets/examples/brand-launch.png +0 -0
  22. package/topmind-cover/assets/examples/gan-huo-wechat.png +0 -0
  23. package/topmind-cover/assets/examples/gan-huo.png +0 -0
  24. package/topmind-cover/assets/examples/ip-fun-wechat.png +0 -0
  25. package/topmind-cover/assets/examples/ip-fun.png +0 -0
  26. package/topmind-cover/assets/examples/magazine-wechat.png +0 -0
  27. package/topmind-cover/assets/examples/magazine.png +0 -0
  28. package/topmind-cover/assets/examples/minimal-wechat.png +0 -0
  29. package/topmind-cover/assets/examples/minimal.png +0 -0
  30. package/topmind-cover/assets/examples/news-flash-wechat.png +0 -0
  31. package/topmind-cover/assets/examples/news-flash.png +0 -0
  32. package/topmind-cover/assets/examples/overview.png +0 -0
  33. package/topmind-cover/assets/examples/tutorial-steps-wechat.png +0 -0
  34. package/topmind-cover/assets/examples/tutorial-steps.png +0 -0
  35. package/topmind-cover/references/cover-styles.md +327 -21
  36. package/topmind-cover/scripts/audit_docs.py +22 -0
  37. package/topmind-cover/scripts/crop-cover.py +1 -2
  38. package/topmind-wechat-post/README.en.md +63 -0
  39. package/topmind-wechat-post/README.md +16 -0
  40. package/topmind-wechat-post/SKILL.md +22 -13
  41. package/topmind-wechat-post/references/typography-rules.md +1 -1
  42. package/topmind-wechat-post/references/writing-quality.md +2 -2
  43. package/topmind-wechat-post/scripts/audit_docs.py +22 -0
  44. package/topmind-wechat-post/scripts/md2wechat.py +8 -1
  45. package/topmind-x-article/README.en.md +46 -0
  46. package/topmind-x-article/README.md +13 -2
  47. package/topmind-x-article/SKILL.md +13 -4
  48. package/topmind-x-article/scripts/audit_docs.py +22 -0
  49. package/topmind-x-article/scripts/md2x.py +5 -3
@@ -2,7 +2,7 @@
2
2
  """封面图裁剪:从 16:9 主图中央裁出公众号 2.35:1 版,并统一落盘命名。
3
3
 
4
4
  用法:
5
- python3 crop-cover.py <主图路径> --slug <slug> --out-dir <包>/images/
5
+ python3 crop-cover.py <主图路径> --out-dir <包>/images/
6
6
 
7
7
  产出:
8
8
  <out-dir>/00-封面.png 1200x675 (X / 公众号共用主文件)
@@ -26,7 +26,6 @@ TARGETS = {
26
26
  def main() -> None:
27
27
  ap = argparse.ArgumentParser()
28
28
  ap.add_argument("src", help="16:9 主图路径")
29
- ap.add_argument("--slug", default="cover")
30
29
  ap.add_argument("--out-dir", required=True)
31
30
  args = ap.parse_args()
32
31
 
@@ -0,0 +1,63 @@
1
+ # topmind-wechat-post · WeChat Article Authoring
2
+
3
+ **[中文](./README.md)** | English
4
+
5
+ Full lifecycle for WeChat articles: delivery package, review & rewrite, three quality gates, status sync, WeChat inline typography, and publish checklist.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npx @topmindspace/tms-skills install topmind-wechat-post
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```bash
16
+ export TOPMIND_WORKSPACE=/path/to/workspace # recommended; or point the delivery package root with --base
17
+
18
+ # Create a new delivery package
19
+ python3 scripts/new-article.py --slug demo --title "标题" --direction reverse
20
+
21
+ # Typography lint + auto-fix
22
+ python3 scripts/lint-wechat.py --input <package>/公众号稿.md --fix
23
+
24
+ # De-AI-flavor scan (target ≥ 85)
25
+ python3 scripts/scan_ai_flavor.py <package>/公众号稿.md
26
+
27
+ # Markdown → fully inline HTML (--embed-images is mandatory, or pasted images go missing)
28
+ python3 scripts/md2wechat.py --input <package>/公众号稿.md --out-dir <package> --slug demo --embed-images
29
+
30
+ # Status sync
31
+ python3 scripts/sync-status.py --set 定稿 <package> --apply
32
+ ```
33
+
34
+ Scripts use Python stdlib only — zero dependencies.
35
+
36
+ ## Three paths
37
+
38
+ - **forward**: draft → WeChat article (review & rewrite)
39
+ - **reverse**: original topic → WeChat article → optional pushback
40
+ - **curated web**: online curated sources → handled as reverse
41
+
42
+ ## Three quality gates
43
+
44
+ Facts (first-hand sources) / logic (structural consistency) / copy (de-AI-flavor ≥ 85).
45
+
46
+ ## Related skills
47
+
48
+ - Cover art → `topmind-cover` (shared X long-form / WeChat cover)
49
+ - X long-form → `topmind-x-article` (Markdown draft → one-click X publish package)
50
+
51
+ ## External dependencies
52
+
53
+ The following skills live **outside this repo** (usually provided by the user's local workbuddy environment). Missing ones degrade or disable the corresponding capability; all scripts in this repo still work fully:
54
+
55
+ - `humanizer-zh`: fidelity boundaries for Chinese de-AI-flavor; without it the "de-AI-flavor only, no typesetting" path is unavailable.
56
+ - `qu-aiwei-zh`: Chinese de-AI-flavor scan targeting; `scripts/scan_ai_flavor.py` shares its origin and can substitute when missing (scan targeting degrades).
57
+
58
+ ## Development
59
+
60
+ ```bash
61
+ python3 scripts/package_skill.py --check
62
+ python3 scripts/negative_tests.py
63
+ ```
@@ -1,5 +1,7 @@
1
1
  # topmind-wechat-post · 公众号创作技能
2
2
 
3
+ [English](./README.en.md) | 中文
4
+
3
5
  公众号文章全生命周期:交付包、审校改写、质量三关、状态同步、微信内联排版与发布清单。
4
6
 
5
7
  ## 安装
@@ -41,6 +43,20 @@ python3 scripts/sync-status.py --set 定稿 <包> --apply
41
43
 
42
44
  事实(一手来源)/ 逻辑(结构一致)/ 文字(去 AI 味 ≥85)。
43
45
 
46
+ ## 相关技能
47
+
48
+ - 封面配图 → `topmind-cover`(X 长文 / 公众号共用封面)
49
+ - X 长文 → `topmind-x-article`(Markdown 原稿一键转 X 发布包)
50
+
51
+ ## 外部依赖
52
+
53
+ 本技能工作流会路由到以下**仓库外**技能(不含于本仓库,一般随用户侧 workbuddy
54
+ 环境提供)。缺失时对应能力降级/不可用,不影响本仓库脚本的全部功能:
55
+
56
+ - `humanizer-zh`:中文去 AI 味的保真边界;缺失时「只去 AI 味不排版」路径不可用。
57
+ - `qu-aiwei-zh`:中文去 AI 味扫描定位;`scripts/scan_ai_flavor.py` 与其同源,
58
+ 缺失时可用仓库内脚本替代,扫描定位能力降级。
59
+
44
60
  ## 开发
45
61
 
46
62
  ```bash
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  name: topmind-wechat-post
3
- description: "公众号文章全生命周期技能:交付包、审校改写、质量三关(事实/逻辑/去AI味)、状态同步、微信内联排版与发布清单。Use when 写公众号、公众号排版、定稿、发公众号。Do NOT use for 只改错别字、小红书/知乎、纯网页发布。"
3
+ version: 0.1.0
4
+ description: "管一篇公众号文章从选题/底稿到发布的完整生命周期:交付包搭建、审校改写、质量三关(事实/逻辑/去AI味)、状态同步、微信内联排版与发布清单。Use when 写公众号、公众号排版、公众号定稿、发公众号。Do NOT use for 只改错别字、小红书/知乎、纯网页发布。"
5
+ action_category: write
4
6
  triggers:
5
7
  - 公众号
6
8
  - 微信排版
@@ -12,10 +14,13 @@ triggers:
12
14
  - 公众号交付
13
15
  - wechat
14
16
  - mp format
15
- tags: [wechat, typography, formatting, publishing, markdown, write]
16
- author: TopMindSpace
17
+ triggers_cn:
18
+ - 写公众号文章
19
+ - 公众号排版定稿
20
+ - 公众号发布清单
21
+ author: TopMindspace
17
22
  license: MIT
18
- homepage: https://github.com/topmindspace/tms-skills
23
+ homepage: https://github.com/topmindspace/tms-skills#readme
19
24
  updated: 2026-09-29
20
25
  ---
21
26
 
@@ -90,15 +95,9 @@ python3 scripts/sync-status.py --set 定稿 <包> --apply
90
95
  python3 scripts/new-article.py --slug <中文短名> --title "<标题>" --direction reverse
91
96
  ```
92
97
 
93
- 取源坑(Next.js 站点):正文在 RSC 载荷里,优先 `GET /api/notes/<id>`;图片在 `/api/uploads/<hash>`,记 hash→本地名映射;同图双 hash 用 `md5` 去重。差异与口径写进包内 `README.md`。
98
+ 取源坑(RSC 载荷、图片 hash 映射、`md5` 去重、截图裁切)见 `references/workflow.md`「站外拉取取源注意」;差异与口径写进包内 `README.md`。
94
99
 
95
- **回推纪律**:notes 保持纯 Markdown。`::: 容器` / 徽章 / `==高亮==` 只进公众号稿。回推**务必带 `--assets`**(否则 GitHub 上 `images/` 死链):
96
-
97
- ```bash
98
- python3 scripts/push-to-topstream.py <包> --target notes/xxx.md --assets # dry-run
99
- python3 scripts/push-to-topstream.py <包> --target notes/xxx.md --assets --apply \
100
- --asset-names "00-封面.jpg=01-cover.jpg,…"
101
- ```
100
+ **回推纪律**:notes 保持纯 Markdown(`:::` 容器 / 徽章 / `==高亮==` 只进公众号稿);回推**务必带 `--assets`**(否则 GitHub 上 `images/` 死链)。命令串见 `references/workflow.md`「收尾」。
102
101
 
103
102
  ## 交付包与状态
104
103
 
@@ -159,7 +158,7 @@ python3 scripts/scan_ai_flavor.py <包>/公众号稿.md # ≥85(人话)
159
158
  ## 排版要点(写稿时)
160
159
 
161
160
  - 开头 150 字内钩子;单段 ≤110 字;列表项 ≤70 字
162
- - 二级标题序号化;容器:`::: stat|pull|note|tip|warn|danger|dialogue`
161
+ - 二级标题不手写序号(排版层自动生成);容器:`::: stat|pull|note|tip|warn|danger|dialogue`
163
162
  - **`::: stat` 内必须是 `数值 | 说明` 管道行**,否则静默丢弃
164
163
  - 评测稿:**图承担数据,正文只解读**;健康密度 **300–450 字/图**
165
164
  - 个股用词红线:禁用 买入/推荐/目标价…;文末投资声明
@@ -200,9 +199,19 @@ python3 scripts/md2wechat.py \
200
199
 
201
200
  可视化工作流伴面(若有):包列表 → 改稿 → 三关 → 预览 → 导出。脚本语义以本技能为准。
202
201
 
202
+ ## 外部依赖
203
+
204
+ 以下技能**不在本仓库**(一般随用户侧 workbuddy 环境提供);缺失时对应路由能力不可用,
205
+ 本仓库脚本(交付包、排版、发布清单等)功能不受影响:
206
+
207
+ - `humanizer-zh`:中文去 AI 味的保真边界(「只去 AI 味不排版」路径用)。
208
+ - `qu-aiwei-zh`:中文去 AI 味扫描定位;本仓库 `scan_ai_flavor.py` 与其同源,
209
+ 缺失时可用仓库内脚本替代,扫描定位能力降级。
210
+
203
211
  ## When NOT to use
204
212
 
205
213
  - 只想改几个句子 → 直接编辑
206
214
  - 小红书 / 知乎 / 掘金 → 平台约束不同
207
215
  - 通用长文交付 → 不在本技能范围
216
+ - 封面配图 → `topmind-cover`;X 长文 → `topmind-x-article`
208
217
  - 只去 AI 味不排版 → 中文走 `humanizer-zh`(先立保真边界)+ `qu-aiwei-zh`(再扫描定位);英文走 `humanizer`
@@ -6,7 +6,7 @@
6
6
 
7
7
  1. **开头 150 字内给钩子**:结论、反差或悬念,不要背景铺垫。原文首段若是长背景,压缩或后移。
8
8
  2. **段落切分**:单段 ≤ 110 字(约 4 行手机屏)。长段按语义断点拆开,不要机械等分。
9
- 3. **小标题序号化**:二级标题统一「一、二、三」或「01 / 02」,读者能感知进度。
9
+ 3. **小标题不手写序号**:写稿时保持二级标题为纯文本,序号由排版层按 `h2_style` 自动生成(规则见 `element-spec.md`「章节编号」)。主题换编号样式时无需手改,读者仍能感知进度。
10
10
  4. **列表项 ≤ 70 字**:超长列表项改成「加粗小标题 + 短说明」的段落组。
11
11
  5. **重点加粗**:只加粗结论句和关键数据,全篇加粗密度控制在每 20 字不超过 1 处。
12
12
  6. **长句拆短**:单句 > 45 字且有逗号堆叠时,拆成两句。
@@ -44,7 +44,7 @@
44
44
  |---|---|---|
45
45
  | 中文长文 / 公众号改稿 | `humanizer-zh` + `qu-aiwei-zh` | 先立边界,再扫描定位(默认组合) |
46
46
  | 只要分数和命中清单 | `qu-aiwei-zh` | 跑脚本,不改稿 |
47
- | 随笔要「加声音」 | `qu-aiwei-zh` + `references/pan-style.md` | 用表达方式加,不编故事 |
47
+ | 随笔要「加声音」 | `qu-aiwei-zh` | 用表达方式加,不编故事 |
48
48
  | 英文文本 | `humanizer` | `humanizer-zh` 只针对中文 |
49
49
  | 清单 / 词表 / 说明书 | 都不用 E 类姿态分 | 这类文体靠列举反例,检测器会把反例当真命中 |
50
50
 
@@ -114,7 +114,7 @@ python3 scripts/scan_ai_flavor.py <稿>.md # 技能自带,与 qu-aiwei-zh
114
114
 
115
115
  有「我」、有具体场景、有具体数字与人名、有不确定性表达(「其实」「不过」「还在想」)、句子长短交替、有真实细节而不是「很多人」「大多数」。
116
116
 
117
- ⚠️ 这一段说的是**表达方式**。原文没有第一人称、没有数字时,不许靠这一条去补——那正好踩中 `humanizer-zh` 的优先级第 1 条。加声音的手段是句长节奏、设问、括号自注(见 `pan-style.md`),配合删掉元叙述和教学腔。`humanizer-zh` 里写着同一句话:「用户要求增强个人风格时,用表达方式实现,不编故事。」
117
+ ⚠️ 这一段说的是**表达方式**。原文没有第一人称、没有数字时,不许靠这一条去补——那正好踩中 `humanizer-zh` 的优先级第 1 条。加声音的手段是句长节奏、设问、括号自注,配合删掉元叙述和教学腔。`humanizer-zh` 里写着同一句话:「用户要求增强个人风格时,用表达方式实现,不编故事。」
118
118
 
119
119
  英文文本才走 `humanizer`:它的取向是 **Add soul**(主动注入个性),与中文改稿的**保真优先**方向相反,别把它的思路套到中文稿上。
120
120
 
@@ -48,6 +48,28 @@ def main() -> None:
48
48
  check(False, f"{rel} 悬空链接: {link}")
49
49
  check(True, "内部 md 链接可达")
50
50
 
51
+ # 反引号代码引用中的路径可达(审计 轻微-15 门禁盲区:之前只查 [text](path) 形式,
52
+ # `references/pan-style.md` 这类反引号引用曾漏网)。抓取反引号内的 references/*.md
53
+ # 与 scripts/* 路径并校验存在;glob/占位符写法(* ? < > |)跳过。
54
+ backtick_path_re = re.compile(r"(references|scripts)/([\w.\-/]+)")
55
+ line_suffix_re = re.compile(r":\d+(?:-\d+)?$")
56
+ backtick_bad = 0
57
+ for md in md_files:
58
+ text = md.read_text(encoding="utf-8")
59
+ rel = md.relative_to(ROOT).as_posix()
60
+ for span in set(re.findall(r"`([^`]+)`", text)):
61
+ for kind, p in backtick_path_re.findall(span):
62
+ p = line_suffix_re.sub("", p)
63
+ if not p or any(c in p for c in "*?<>|"):
64
+ continue
65
+ target = md.parent / kind / p
66
+ if not target.exists():
67
+ target = ROOT / kind / p
68
+ if not target.exists():
69
+ backtick_bad += 1
70
+ check(False, f"{rel} 反引号引用不可达: `{kind}/{p}`")
71
+ check(backtick_bad == 0, f"反引号内 references/scripts 引用可达(扫描 {len(md_files)} 个 md 文件)")
72
+
51
73
  if errors:
52
74
  print(f"\n[audit_docs] {NAME}: {len(errors)} 项失败")
53
75
  sys.exit(1)
@@ -880,6 +880,10 @@ def resolve_image(src, md_path, out_dir, assets, asset_root):
880
880
  if os.path.exists(candidate):
881
881
  abs_path = candidate
882
882
  if not os.path.exists(abs_path):
883
+ # 本地文件缺失:登记缺失记录再返回原 src(HTML 保留占位 <img>,
884
+ # embed 会跳过并提示"未内嵌",上传清单与计数也不会漏掉这一项)
885
+ assets.append({"src": src, "local": None, "remote": False,
886
+ "missing": True})
883
887
  return src
884
888
  img_dir = os.path.join(out_dir, "images")
885
889
  os.makedirs(img_dir, exist_ok=True)
@@ -1435,9 +1439,12 @@ def write_manifest(out_dir, slug, title, assets, diagrams, theme, footnotes,
1435
1439
  size = "%.0f KB" % kb if kb < 1024 else "%.1f MB" % (kb / 1024)
1436
1440
  if a.get("remote"):
1437
1441
  lines.append("| %d | %s(远程) | %s | `%s` |" % (idx, a["src"], size, a["src"]))
1442
+ elif a.get("missing"):
1443
+ lines.append("| %d | ⚠ 本地文件缺失:`%s` | — | `%s` |"
1444
+ % (idx, a["src"], a["src"]))
1438
1445
  else:
1439
1446
  lines.append("| %d | `%s` | %s | `%s` |"
1440
- % (idx, a.get("basename", ""), size, a["src"]))
1447
+ % (idx, a.get("basename") or "", size, a["src"]))
1441
1448
  lines.append("")
1442
1449
  lines.append("图片目录:`images/`(公众号单图建议 < 2 MB,宽度 1080 px 左右)")
1443
1450
  lines.append("")
@@ -0,0 +1,46 @@
1
+ # topmind-x-article · One-Click X Long-Form Publishing
2
+
3
+ **[中文](./README.md)** | English
4
+
5
+ Turn a Markdown draft into a "copy → paste → publish" X long-form (Article) package.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npx @topmindspace/tms-skills install topmind-x-article
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```bash
16
+ # 1. Draft → paste-ready plain text (the heart of one-click copying)
17
+ python3 scripts/md2x.py <draft>.md --out <package>/X发布稿.txt
18
+
19
+ # 2. Cover: generate a 1200×675 cover with topmind-cover
20
+
21
+ # 3. Follow references/publish-checklist.md item by item
22
+ ```
23
+
24
+ ## Conversion rules
25
+
26
+ The X Article editor has weak, unstable markdown support, so `md2x.py` converts to plain text per `references/x-format.md`: headings → plain text lines, horizontal rules (`---` / `***` / `___`) → blank lines, bold/italic markers removed (including `***bold-italic***`), links → `text(url)`, images → `[图N]` (image list appended at the end), tables → "item: value" lists.
27
+
28
+ Read the result through once by hand after converting.
29
+
30
+ ## Publishing
31
+
32
+ X long-form posts are currently published by hand-pasting into the X Article editor; the API does not publish long-form. After publishing, do per the checklist: pin a first comment with the extra info, fetch the full text back for verification.
33
+
34
+ ## External dependencies
35
+
36
+ The following skills are **not in this repo** (usually provided by the user's local workbuddy environment). Missing ones disable the corresponding routed capability; the core flow (draft → text, cover, publish checklist) is unaffected:
37
+
38
+ - `topmind-x`: 280-char short posts (its xurl only covers short posts, not long-form).
39
+ - `topmind-capture`: the "archive only, don't publish" routing path.
40
+
41
+ ## Development
42
+
43
+ ```bash
44
+ python3 scripts/package_skill.py --check # pre-publish check
45
+ python3 scripts/negative_tests.py # bad-input tests
46
+ ```
@@ -1,5 +1,7 @@
1
1
  # topmind-x-article · X 长文一键发布
2
2
 
3
+ [English](./README.en.md) | 中文
4
+
3
5
  把 Markdown 原稿变成"复制 → 粘贴 → 发"的 X 长文(Article)发布包。
4
6
 
5
7
  ## 安装
@@ -22,8 +24,9 @@ python3 scripts/md2x.py <原稿>.md --out <包>/X发布稿.txt
22
24
  ## 转换规则
23
25
 
24
26
  X Article 编辑器对 markdown 支持弱且不稳定,`md2x.py` 按 `references/x-format.md`
25
- 转纯文本:标题→纯文本行、加粗/斜体去标记、链接→`文字(url)`、
26
- 图片→`[图N]`(文末附配图清单)、表格→"项:值"列表。
27
+ 转纯文本:标题→纯文本行、分隔线(`---` / `***` / `___`)→空行、加粗/斜体去标记
28
+ (含 `***粗斜体***`)、链接→`文字(url)`、图片→`[图N]`(文末附配图清单)、
29
+ 表格→"项:值"列表。
27
30
 
28
31
  转完必须人工通读一遍。
29
32
 
@@ -32,6 +35,14 @@ X Article 编辑器对 markdown 支持弱且不稳定,`md2x.py` 按 `reference
32
35
  X 长文目前走人工粘贴发布(X Article 编辑器),API 不发长文。
33
36
  发布后按清单做:首条评论置顶补信息、全文抓回核对。
34
37
 
38
+ ## 外部依赖
39
+
40
+ 以下技能**不在本仓库**(一般随用户侧 workbuddy 环境提供)。缺失时对应路由能力
41
+ 不可用,不影响本技能核心流程(原稿转文本、封面、发布清单):
42
+
43
+ - `topmind-x`:280 字短推文发布(其 xurl 只覆盖短推文,不发长文)。
44
+ - `topmind-capture`:「只想存档不发布」时的收录路由。
45
+
35
46
  ## 开发
36
47
 
37
48
  ```bash
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: topmind-x-article
3
- version: 1.0.0
4
- description: "X 长文(Article)一键发布:Markdown 原稿 → 可直接粘贴的 X发布稿.txt + 封面图 + 发布清单。沉淀自实战。Use when X 长文、发 X 文章、X article、长文发 X。Do NOT use for 短推文(走推文流程)、公众号。"
3
+ version: 0.1.0
4
+ description: "X 长文(Article)一键发布:Markdown 原稿 → 可直接粘贴的 X发布稿.txt + 封面图 + 发布清单。沉淀自实战。Use when X 长文、发 X 文章、X article、长文发 X。Do NOT use for 短推文(→ topmind-x)、公众号。"
5
5
  action_category: write
6
6
  triggers:
7
7
  - X 长文
@@ -11,8 +11,9 @@ triggers:
11
11
  triggers_cn:
12
12
  - 写 X 长文
13
13
  - X 长文发布
14
- author: Muse
14
+ author: TopMindspace
15
15
  license: MIT
16
+ homepage: https://github.com/topmindspace/tms-skills#readme
16
17
  updated: 2026-09-29
17
18
  ---
18
19
 
@@ -58,5 +59,13 @@ updated: 2026-09-29
58
59
  ## When NOT to use
59
60
 
60
61
  - 280 字短推文 → `topmind-x`
61
- - 公众号 → `topmind-wechat`
62
+ - 公众号 → `topmind-wechat-post`
62
63
  - 只想存档不发布 → `topmind-capture`
64
+
65
+ ## 外部依赖
66
+
67
+ 以下技能**不在本仓库**(一般随用户侧 workbuddy 环境提供);缺失时对应路由能力不可用,
68
+ 本技能核心流程(原稿转文本、封面、发布清单)不受影响:
69
+
70
+ - `topmind-x`:280 字短推文发布(其 xurl 只覆盖短推文,不发长文)。
71
+ - `topmind-capture`:「只想存档不发布」时的收录路由。
@@ -48,6 +48,28 @@ def main() -> None:
48
48
  check(False, f"{rel} 悬空链接: {link}")
49
49
  check(True, "内部 md 链接可达")
50
50
 
51
+ # 反引号代码引用中的路径可达(审计 轻微-15 门禁盲区:之前只查 [text](path) 形式,
52
+ # `references/pan-style.md` 这类反引号引用曾漏网)。抓取反引号内的 references/*.md
53
+ # 与 scripts/* 路径并校验存在;glob/占位符写法(* ? < > |)跳过。
54
+ backtick_path_re = re.compile(r"(references|scripts)/([\w.\-/]+)")
55
+ line_suffix_re = re.compile(r":\d+(?:-\d+)?$")
56
+ backtick_bad = 0
57
+ for md in md_files:
58
+ text = md.read_text(encoding="utf-8")
59
+ rel = md.relative_to(ROOT).as_posix()
60
+ for span in set(re.findall(r"`([^`]+)`", text)):
61
+ for kind, p in backtick_path_re.findall(span):
62
+ p = line_suffix_re.sub("", p)
63
+ if not p or any(c in p for c in "*?<>|"):
64
+ continue
65
+ target = md.parent / kind / p
66
+ if not target.exists():
67
+ target = ROOT / kind / p
68
+ if not target.exists():
69
+ backtick_bad += 1
70
+ check(False, f"{rel} 反引号引用不可达: `{kind}/{p}`")
71
+ check(backtick_bad == 0, f"反引号内 references/scripts 引用可达(扫描 {len(md_files)} 个 md 文件)")
72
+
51
73
  if errors:
52
74
  print(f"\n[audit_docs] {NAME}: {len(errors)} 项失败")
53
75
  sys.exit(1)
@@ -28,8 +28,9 @@ def convert(md: str):
28
28
  for raw in md.splitlines():
29
29
  line = raw.rstrip()
30
30
 
31
- # frontmatter 直接跳过
32
- if line.strip() == "---":
31
+ # 分割线 → 空行(frontmatter 已在 main() 去除,这里只剩正文分隔线)
32
+ if re.match(r"^(\*{3,}|-{3,}|_{3,})\s*$", line):
33
+ out_lines.append("")
33
34
  continue
34
35
 
35
36
  # 代码块:去围栏,内容缩进保留
@@ -69,7 +70,8 @@ def convert(md: str):
69
70
  out_lines.append(f"{label}:{rest}" if rest else label)
70
71
  continue
71
72
 
72
- # 行内标记剥离
73
+ # 行内标记剥离(先 *** 再 ** 再 *,防残留)
74
+ line = re.sub(r"\*\*\*(.+?)\*\*\*", r"\1", line) # 粗斜体
73
75
  line = re.sub(r"\*\*(.+?)\*\*", r"\1", line) # 加粗
74
76
  line = re.sub(r"__(.+?)__", r"\1", line)
75
77
  line = re.sub(r"\*(.+?)\*", r"\1", line) # 斜体