@topmindspace/tms-skills 0.1.19 → 0.2.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 (59) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.en.md +5 -2
  3. package/README.md +4 -1
  4. package/package.json +5 -2
  5. package/topmind-cover/README.md +40 -0
  6. package/topmind-cover/SKILL.md +66 -0
  7. package/topmind-cover/package-lock.json +16 -0
  8. package/topmind-cover/package.json +16 -0
  9. package/topmind-cover/references/cover-styles.md +40 -0
  10. package/topmind-cover/scripts/audit_css.py +39 -0
  11. package/topmind-cover/scripts/audit_docs.py +58 -0
  12. package/topmind-cover/scripts/audit_skill.py +60 -0
  13. package/topmind-cover/scripts/audit_styles.py +54 -0
  14. package/topmind-cover/scripts/crop-cover.py +69 -0
  15. package/topmind-cover/scripts/negative_tests.py +71 -0
  16. package/topmind-cover/scripts/package_skill.py +188 -0
  17. package/topmind-wechat-post/README.md +49 -0
  18. package/topmind-wechat-post/SKILL.md +208 -0
  19. package/topmind-wechat-post/assets/themes/amber-review.json +35 -0
  20. package/topmind-wechat-post/assets/themes/graphite.json +35 -0
  21. package/topmind-wechat-post/assets/themes/minimal-ink.json +35 -0
  22. package/topmind-wechat-post/assets/themes/newsprint.json +35 -0
  23. package/topmind-wechat-post/assets/themes/tech-blue.json +35 -0
  24. package/topmind-wechat-post/package-lock.json +16 -0
  25. package/topmind-wechat-post/package.json +16 -0
  26. package/topmind-wechat-post/references/design.md +50 -0
  27. package/topmind-wechat-post/references/element-spec.md +162 -0
  28. package/topmind-wechat-post/references/known-pits.md +86 -0
  29. package/topmind-wechat-post/references/theme-map.md +139 -0
  30. package/topmind-wechat-post/references/typography-rules.md +62 -0
  31. package/topmind-wechat-post/references/wechat-constraints.md +106 -0
  32. package/topmind-wechat-post/references/workflow.md +102 -0
  33. package/topmind-wechat-post/references/writing-quality.md +129 -0
  34. package/topmind-wechat-post/scripts/audit_css.py +39 -0
  35. package/topmind-wechat-post/scripts/audit_docs.py +58 -0
  36. package/topmind-wechat-post/scripts/audit_skill.py +60 -0
  37. package/topmind-wechat-post/scripts/audit_styles.py +54 -0
  38. package/topmind-wechat-post/scripts/lint-wechat.py +446 -0
  39. package/topmind-wechat-post/scripts/md2wechat.py +1602 -0
  40. package/topmind-wechat-post/scripts/negative_tests.py +65 -0
  41. package/topmind-wechat-post/scripts/new-article.py +183 -0
  42. package/topmind-wechat-post/scripts/package_skill.py +188 -0
  43. package/topmind-wechat-post/scripts/push-to-topstream.py +226 -0
  44. package/topmind-wechat-post/scripts/scan_ai_flavor.py +464 -0
  45. package/topmind-wechat-post/scripts/sync-mapping.py +220 -0
  46. package/topmind-wechat-post/scripts/sync-status.py +187 -0
  47. package/topmind-x-article/README.md +40 -0
  48. package/topmind-x-article/SKILL.md +62 -0
  49. package/topmind-x-article/package-lock.json +16 -0
  50. package/topmind-x-article/package.json +16 -0
  51. package/topmind-x-article/references/publish-checklist.md +24 -0
  52. package/topmind-x-article/references/x-format.md +24 -0
  53. package/topmind-x-article/scripts/audit_css.py +39 -0
  54. package/topmind-x-article/scripts/audit_docs.py +58 -0
  55. package/topmind-x-article/scripts/audit_skill.py +60 -0
  56. package/topmind-x-article/scripts/audit_styles.py +54 -0
  57. package/topmind-x-article/scripts/md2x.py +121 -0
  58. package/topmind-x-article/scripts/negative_tests.py +74 -0
  59. package/topmind-x-article/scripts/package_skill.py +188 -0
@@ -0,0 +1,188 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """技能分发包打包器(发布前完整性校验 + 发布清单)。
4
+
5
+ 用法:
6
+ python scripts/package_skill.py # 校验 → 打包 → 写发布清单
7
+ python scripts/package_skill.py --check # 只校验不打包(CI / 提交前自检)
8
+
9
+ 产物:
10
+ dist/<skill>.zip 分发包(解压目录名 = 技能名)
11
+ dist/<skill>.manifest.json 发布清单(版本 / 条目 / 大小 / SHA-256)
12
+
13
+ 校验(任一不过 → 退出码 1):
14
+ · SKILL.md frontmatter 含 name / description;name 与目录名一致;
15
+ description ≤ 1024 字符(平台截断阈值)
16
+ · README.md / package.json 存在;package.json name 与技能名一致
17
+ · scripts/*.py 全部可编译;references/*.md 非空
18
+ · SKILL.md 引用的 references/<file> 全部存在
19
+ · 无 scripts/_* / __pycache__ / .env 等不应进包的文件
20
+ """
21
+ from __future__ import annotations
22
+
23
+ import hashlib
24
+ import json
25
+ import re
26
+ import sys
27
+ import zipfile
28
+ from datetime import datetime, timezone
29
+ from pathlib import Path
30
+
31
+ try:
32
+ sys.stdout.reconfigure(encoding="utf-8", errors="replace")
33
+ except Exception:
34
+ pass
35
+
36
+ ROOT = Path(__file__).resolve().parent.parent
37
+ NAME = ROOT.name
38
+ OUT = ROOT / "dist" / f"{NAME}.zip"
39
+ MANIFEST = ROOT / "dist" / f"{NAME}.manifest.json"
40
+ DESC_LIMIT = 1024
41
+
42
+ INCLUDE = ["SKILL.md", "README.md", "package.json", "assets/", "references/", "scripts/", "evals/", "agents/"]
43
+ EXCLUDE_RES = [
44
+ re.compile(r"(^|/)scripts/_"),
45
+ re.compile(r"(^|/)\.env($|\.)"),
46
+ re.compile(r"(^|/)__pycache__(/|$)"),
47
+ re.compile(r"(^|/)node_modules(/|$)"),
48
+ re.compile(r"(^|/)dist(/|$)"),
49
+ ]
50
+
51
+ errors: list[str] = []
52
+
53
+
54
+ def fail(msg: str) -> None:
55
+ errors.append(msg)
56
+ print(f" ✗ {msg}")
57
+
58
+
59
+ def ok(msg: str) -> None:
60
+ print(f" ✓ {msg}")
61
+
62
+
63
+ def read_frontmatter() -> dict:
64
+ text = (ROOT / "SKILL.md").read_text(encoding="utf-8")
65
+ m = re.match(r"^---\r?\n([\s\S]*?)\r?\n---", text)
66
+ if not m:
67
+ fail("SKILL.md 缺 frontmatter")
68
+ return {}
69
+ fm = m.group(1)
70
+ name = re.search(r"^name:\s*(\S+)\s*$", fm, re.M)
71
+ desc = ""
72
+ dm = re.search(r'^description:\s*"([^"]*)"\s*$', fm, re.M)
73
+ if dm:
74
+ desc = dm.group(1).strip()
75
+ else:
76
+ dm = re.search(r"^description:\s*>\-\s*\n((?:[ \t]+.*\n?)+)", fm, re.M)
77
+ if dm:
78
+ desc = " ".join(line.strip() for line in dm.group(1).splitlines() if line.strip())
79
+ return {"name": name.group(1) if name else "", "description": desc}
80
+
81
+
82
+ def check() -> bool:
83
+ print(f"[check] {NAME}")
84
+ fm = read_frontmatter()
85
+ if fm.get("name") != NAME:
86
+ fail(f"frontmatter name={fm.get('name')!r} 与目录名 {NAME!r} 不一致")
87
+ else:
88
+ ok("name 与目录名一致")
89
+ desc = fm.get("description", "")
90
+ if not desc:
91
+ fail("description 为空")
92
+ elif len(desc) > DESC_LIMIT:
93
+ fail(f"description {len(desc)} 字符,超过 {DESC_LIMIT}")
94
+ else:
95
+ ok(f"description {len(desc)} 字符")
96
+
97
+ for f in ("README.md", "package.json"):
98
+ if not (ROOT / f).is_file():
99
+ fail(f"缺 {f}")
100
+ else:
101
+ ok(f"有 {f}")
102
+ try:
103
+ pkg = json.loads((ROOT / "package.json").read_text(encoding="utf-8"))
104
+ if pkg.get("name") != NAME:
105
+ fail(f"package.json name={pkg.get('name')!r} 与技能名不一致")
106
+ if not re.match(r"^\d+\.\d+\.\d+", str(pkg.get("version", ""))):
107
+ fail("package.json version 非 semver")
108
+ except (OSError, json.JSONDecodeError) as e:
109
+ fail(f"package.json 解析失败: {e}")
110
+
111
+ for p in ROOT.rglob("*"):
112
+ if not p.is_file() or ".git" in p.parts:
113
+ continue
114
+ rel = p.relative_to(ROOT).as_posix()
115
+ for rx in EXCLUDE_RES:
116
+ if rx.search(rel):
117
+ fail(f"不应进包的文件: {rel}")
118
+ break
119
+ ok("无禁用文件")
120
+
121
+ for py in sorted((ROOT / "scripts").glob("*.py")):
122
+ try:
123
+ compile(py.read_text(encoding="utf-8"), str(py), "exec")
124
+ except SyntaxError as e:
125
+ fail(f"{py.name} 编译失败: {e}")
126
+ ok("scripts/*.py 编译通过")
127
+
128
+ refdir = ROOT / "references"
129
+ if refdir.is_dir():
130
+ for md in sorted(refdir.glob("*.md")):
131
+ if md.stat().st_size == 0:
132
+ fail(f"references/{md.name} 为空")
133
+ skill_text = (ROOT / "SKILL.md").read_text(encoding="utf-8")
134
+ for ref in sorted(set(re.findall(r"references/([\w\-.]+\.md)", skill_text))):
135
+ if not (refdir / ref).is_file():
136
+ fail(f"SKILL.md 引用的 references/{ref} 不存在")
137
+ ok("references 完整性通过")
138
+
139
+ if errors:
140
+ print(f"\n[check] {NAME}: {len(errors)} 项失败")
141
+ return False
142
+ print(f"\n[check] {NAME}: 全部通过")
143
+ return True
144
+
145
+
146
+ def package() -> None:
147
+ if not check():
148
+ sys.exit(1)
149
+ (ROOT / "dist").mkdir(exist_ok=True)
150
+ entries: list[str] = []
151
+ with zipfile.ZipFile(OUT, "w", zipfile.ZIP_DEFLATED) as z:
152
+ for p in sorted(ROOT.rglob("*")):
153
+ if not p.is_file() or ".git" in p.parts:
154
+ continue
155
+ rel = p.relative_to(ROOT)
156
+ rel_posix = rel.as_posix()
157
+ if any(rx.search(rel_posix) for rx in EXCLUDE_RES):
158
+ continue
159
+ if not any(
160
+ rel_posix == inc.rstrip("/") or rel_posix.startswith(inc)
161
+ for inc in INCLUDE
162
+ if inc.endswith("/")
163
+ ) and rel_posix not in INCLUDE:
164
+ continue
165
+ z.write(p, arcname=f"{NAME}/{rel_posix}")
166
+ entries.append(rel_posix)
167
+ sha = hashlib.sha256(OUT.read_bytes()).hexdigest()
168
+ pkg = json.loads((ROOT / "package.json").read_text(encoding="utf-8"))
169
+ manifest = {
170
+ "name": NAME,
171
+ "version": pkg.get("version"),
172
+ "built_at": datetime.now(timezone.utc).isoformat(),
173
+ "files": len(entries),
174
+ "sha256": sha,
175
+ "entries": entries,
176
+ }
177
+ MANIFEST.write_text(json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8")
178
+ print(f"\n[package] {OUT} ({len(entries)} 文件, sha256={sha[:12]}…)")
179
+
180
+
181
+ def main() -> None:
182
+ if "--check" in sys.argv[1:]:
183
+ sys.exit(0 if check() else 1)
184
+ package()
185
+
186
+
187
+ if __name__ == "__main__":
188
+ main()
@@ -0,0 +1,49 @@
1
+ # topmind-wechat-post · 公众号创作技能
2
+
3
+ 公众号文章全生命周期:交付包、审校改写、质量三关、状态同步、微信内联排版与发布清单。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npx @topmindspace/tms-skills install topmind-wechat-post
9
+ ```
10
+
11
+ ## 用法
12
+
13
+ ```bash
14
+ export TOPMIND_WORKSPACE=/path/to/workspace # 推荐;或用 --base 指定交付包根
15
+
16
+ # 新建交付包
17
+ python3 scripts/new-article.py --slug demo --title "标题" --direction reverse
18
+
19
+ # 排版体检 + 自动修复
20
+ python3 scripts/lint-wechat.py --input <包>/公众号稿.md --fix
21
+
22
+ # 去 AI 味扫描(目标 ≥85)
23
+ python3 scripts/scan_ai_flavor.py <包>/公众号稿.md
24
+
25
+ # Markdown → 全内联 HTML(必加 --embed-images,否则粘贴丢图)
26
+ python3 scripts/md2wechat.py --input <包>/公众号稿.md --out-dir <包> --slug demo --embed-images
27
+
28
+ # 状态同步
29
+ python3 scripts/sync-status.py --set 定稿 <包> --apply
30
+ ```
31
+
32
+ 脚本纯 Python 标准库,零依赖。
33
+
34
+ ## 三条路径
35
+
36
+ - **forward**:底稿 → 公众号(审校改写)
37
+ - **reverse**:选题原创 → 公众号 → 可选回推
38
+ - **站外拉取**:在线精选站 → 按 reverse 处理
39
+
40
+ ## 质量三关
41
+
42
+ 事实(一手来源)/ 逻辑(结构一致)/ 文字(去 AI 味 ≥85)。
43
+
44
+ ## 开发
45
+
46
+ ```bash
47
+ python3 scripts/package_skill.py --check
48
+ python3 scripts/negative_tests.py
49
+ ```
@@ -0,0 +1,208 @@
1
+ ---
2
+ name: topmind-wechat-post
3
+ description: "公众号文章全生命周期技能:交付包、审校改写、质量三关(事实/逻辑/去AI味)、状态同步、微信内联排版与发布清单。Use when 写公众号、公众号排版、定稿、发公众号。Do NOT use for 只改错别字、小红书/知乎、纯网页发布。"
4
+ triggers:
5
+ - 公众号
6
+ - 微信排版
7
+ - 公众号排版
8
+ - 公众号稿
9
+ - 排版这篇文章
10
+ - 定稿
11
+ - 发公众号
12
+ - 公众号交付
13
+ - wechat
14
+ - mp format
15
+ tags: [wechat, typography, formatting, publishing, markdown, write]
16
+ author: TopMindSpace
17
+ license: MIT
18
+ homepage: https://github.com/topmindspace/tms-skills
19
+ updated: 2026-09-29
20
+ ---
21
+
22
+ # topmind-wechat-post · 公众号创作技能
23
+
24
+ **公众号专用写作技能**。管一篇公众号文章从选题/底稿到发布清单的完整生命周期。
25
+
26
+ ```
27
+ 选题/底稿 → 创作 → 质量三关 → 定稿(状态+目录) → 排版 → 发布清单 →(可选)回推 notes
28
+ ```
29
+
30
+ > 用户明确说公众号 / 微信排版时进本技能;通用长文写作不在本技能范围内。
31
+
32
+ ## 脚本(真源)
33
+
34
+ | 脚本 | 用途 |
35
+ |------|------|
36
+ | `scripts/new-article.py` | 建交付包(骨架稿 + frontmatter + images/diagrams) |
37
+ | `scripts/sync-status.py` | 状态 ⇄ 目录名 ⇄ 字数(草稿 / 定稿 / 已发布) |
38
+ | `scripts/sync-mapping.py` | 映射一致性(frontmatter + 目录 + 可选 notes + topic 总表) |
39
+ | `scripts/push-to-topstream.py` | 可选回推:公众号稿降级为纯 Markdown notes |
40
+ | `scripts/lint-wechat.py` | 排版体检 + 自动修复(中英文间距、段长、AI 腔…) |
41
+ | `scripts/md2wechat.py` | Markdown → 全内联 HTML;**必加 `--embed-images`** |
42
+ | `scripts/scan_ai_flavor.py` | 中文去 AI 味扫描(与 `qu-aiwei-zh` 同源) |
43
+
44
+ ```bash
45
+ # 路径解析:CLI --base/--workspace → env TOPMIND_WECHAT_BASE / TOPMIND_WORKSPACE / TOPSTREAM_ROOT → 惯例
46
+ export TOPMIND_WORKSPACE=/path/to/workspace # 推荐
47
+ python3 scripts/new-article.py --slug demo --title "标题" --direction reverse
48
+ python3 scripts/lint-wechat.py --input <包>/公众号稿.md --fix
49
+ python3 scripts/scan_ai_flavor.py <包>/公众号稿.md # 目标 ≥85
50
+ python3 scripts/md2wechat.py --input <包>/公众号稿.md --out-dir <包> --slug demo \
51
+ --asset-root <素材根> --embed-images
52
+ python3 scripts/sync-status.py --set 定稿 <包> --apply
53
+ ```
54
+
55
+ 细节见 [`references/workflow.md`](references/workflow.md) · [`references/known-pits.md`](references/known-pits.md)。
56
+
57
+ ## 路径默认
58
+
59
+ | 用途 | 解析 |
60
+ |------|------|
61
+ | 交付包根 | `--base` → `TOPMIND_WECHAT_BASE` → `{ws}/40-创作/2026-公众号` 或 `{ws}/20-专题/2026-公众号` |
62
+ | 工作区 | `TOPMIND_WORKSPACE` |
63
+ | 底稿/回推 | `--topstream` → `TOPSTREAM_ROOT` → 可选;不存在则跳过 notes 校验 |
64
+ | 终稿交付 | 可 `save-output` 拷贝到 role:delivery(`88-交付/`),包仍留在创作类专题 |
65
+
66
+ ## 三条路径
67
+
68
+ ### forward(底稿 → 公众号)
69
+
70
+ ```
71
+ 底稿 notes/*.md → 审校改写 → 质量三关 → 定稿 → 排版 → 发布
72
+ ```
73
+
74
+ `new-article.py --direction forward --source-file notes/xxx.md`
75
+
76
+ ### reverse(选题原创)
77
+
78
+ ```
79
+ 选题包 → 调研素材 → 多轮改稿 → 三关 → 定稿 → 排版 → 发布 →(可选)push-to-topstream
80
+ ```
81
+
82
+ `new-article.py --direction reverse`(`target_file: pending`)
83
+
84
+ ### 站外拉取(转载整合 / 在线精选站)
85
+
86
+ 源不在本工作区、也不在 topstream `notes/` 时,**仍落 `reverse` + `target_file: pending`**。
87
+ **不要用 `forward`**:它要求 `source_file` 以 `notes/` 开头且文件真实存在,站外源必然过不了 `sync-mapping.py`。
88
+
89
+ ```bash
90
+ python3 scripts/new-article.py --slug <中文短名> --title "<标题>" --direction reverse
91
+ ```
92
+
93
+ 取源坑(Next.js 站点):正文在 RSC 载荷里,优先 `GET /api/notes/<id>`;图片在 `/api/uploads/<hash>`,记 hash→本地名映射;同图双 hash 用 `md5` 去重。差异与口径写进包内 `README.md`。
94
+
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
+ ```
102
+
103
+ ## 交付包与状态
104
+
105
+ ```text
106
+ YYYY-MM-DD-<中文短名> # 草稿
107
+ YYYY-MM-DD-<中文短名>-released # 定稿 / 已发布
108
+ ├── 公众号稿.md # 唯一改稿入口
109
+ ├── <slug>-公众号版.html # 浏览器打开 → 复制正文 → 粘贴后台
110
+ ├── 图片上传清单.md
111
+ ├── images/ diagrams/
112
+ └── README.md # 包说明(可选)
113
+ ```
114
+
115
+ **frontmatter(映射真源)**
116
+
117
+ ```yaml
118
+ status: 草稿 # 草稿 | 定稿 | 已发布
119
+ direction: reverse # forward | reverse
120
+ source_file: "" # forward 填 notes/xxx.md
121
+ target_file: pending # reverse:pending | notes/xxx.md
122
+ word_count: 0 # 纯中文字数,sync-status 维护
123
+ ```
124
+
125
+ 状态与目录名**不要手改**:
126
+
127
+ ```bash
128
+ python3 scripts/sync-status.py --set 定稿 <包> --apply
129
+ ```
130
+
131
+ ## 质量三关(定稿前必过)
132
+
133
+ ### 关 1 · 事实
134
+
135
+ - 承重数字回**一手来源**;厂商口径 / 据报道 分开写
136
+ - 查不到一手来源的传闻**删**
137
+ - 改稿续写:正文已有数字**回源重核**(上一轮文本最不可信)
138
+ - 多口径(主轮/复跑)显式拆开;表格从数据源生成,禁止手抄
139
+ - 外部工具改过的稿:**先核数字再动文字**;「比值对但绝对值错」= 全段重核
140
+
141
+ ### 关 2 · 逻辑
142
+
143
+ - 单边结论旁配反方证据
144
+ - 结构前后一致;同一事实多处同值
145
+
146
+ ### 关 3 · 文字(去 AI 味)
147
+
148
+ ```bash
149
+ python3 scripts/scan_ai_flavor.py <包>/公众号稿.md # ≥85(人话)
150
+ ```
151
+
152
+ - 删套话/黑话/工程圈行话;降调段末加粗金句
153
+ - **满分 ≠ 有人味**:再查「段末金句癖 / 节奏过分整齐 / 没有场景与我 / 报告体标注」
154
+ - **口语化 ≠ 有人味**:删社交垫词(元叙述、空转过渡、姿态句)
155
+ - 判据:**这句话删掉之后,读者少知道了什么?**
156
+
157
+ 详见 [`references/writing-quality.md`](references/writing-quality.md)。
158
+
159
+ ## 排版要点(写稿时)
160
+
161
+ - 开头 150 字内钩子;单段 ≤110 字;列表项 ≤70 字
162
+ - 二级标题序号化;容器:`::: stat|pull|note|tip|warn|danger|dialogue`
163
+ - **`::: stat` 内必须是 `数值 | 说明` 管道行**,否则静默丢弃
164
+ - 评测稿:**图承担数据,正文只解读**;健康密度 **300–450 字/图**
165
+ - 个股用词红线:禁用 买入/推荐/目标价…;文末投资声明
166
+
167
+ 更多:[`references/typography-rules.md`](references/typography-rules.md) · [`references/wechat-constraints.md`](references/wechat-constraints.md)。
168
+
169
+ ## 排版与导出(必读)
170
+
171
+ ```bash
172
+ python3 scripts/md2wechat.py \
173
+ --input <包>/公众号稿.md --out-dir <包> --slug <slug> \
174
+ --asset-root <素材根> --embed-images \
175
+ [--theme assets/themes/minimal-ink.json]
176
+ ```
177
+
178
+ 1. **永远 `--embed-images`**,否则粘贴丢图(相对路径被序列化成 file://)
179
+ 2. **图片 basename 铁律**:正文引用名 = `images/` 目标名;禁止两套同名图共处
180
+ 3. 合规自检出现 `✗` 改生成器,不要手改 HTML
181
+
182
+ 坑清单:[`references/known-pits.md`](references/known-pits.md)。
183
+
184
+ ## 主题
185
+
186
+ | 文件 | 风格 | 适用 |
187
+ |------|------|------|
188
+ | `assets/themes/minimal-ink.json`(默认) | 黑白灰 + 砖红 | 深度研析 / 观点 / 随笔 |
189
+ | `assets/themes/tech-blue.json` | 科技蓝 | AI/技术 |
190
+ | `assets/themes/newsprint.json` | 报纸衬线 | 人文评论 |
191
+ | `assets/themes/graphite.json` | 石墨克制 | 严肃报告 |
192
+ | `assets/themes/amber-review.json` | 琥珀评测 | 产品评测 |
193
+
194
+ `md2wechat.py --list-themes` 看全部;`--theme genre:评测` 可按题材自动选。
195
+ 渲染规格见 [`references/element-spec.md`](references/element-spec.md) · 主题映射见 [`references/theme-map.md`](references/theme-map.md)。
196
+
197
+ **平台红线速查**(详见 [`references/wechat-constraints.md`](references/wechat-constraints.md)):禁 `div`/`pre`/`h1`/`figure`/`thead`/flex/float/gradient/shadow;表格 `table-layout` 不写 fixed;列数 ≥4 转卡片。
198
+
199
+ ## 与 Desktop「公众号创作」
200
+
201
+ 可视化工作流伴面(若有):包列表 → 改稿 → 三关 → 预览 → 导出。脚本语义以本技能为准。
202
+
203
+ ## When NOT to use
204
+
205
+ - 只想改几个句子 → 直接编辑
206
+ - 小红书 / 知乎 / 掘金 → 平台约束不同
207
+ - 通用长文交付 → 不在本技能范围
208
+ - 只去 AI 味不排版 → 中文走 `humanizer-zh`(先立保真边界)+ `qu-aiwei-zh`(再扫描定位);英文走 `humanizer`
@@ -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,16 @@
1
+ {
2
+ "name": "topmind-wechat-post",
3
+ "version": "0.1.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "topmind-wechat-post",
9
+ "version": "0.1.0",
10
+ "license": "MIT",
11
+ "engines": {
12
+ "node": ">=18"
13
+ }
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "topmind-wechat-post",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "description": "公众号文章全生命周期:交付包、审校改写、质量三关、状态同步、微信内联排版与发布清单。",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/topmindspace/tms-skills.git",
10
+ "directory": "topmind-wechat-post"
11
+ },
12
+ "type": "commonjs",
13
+ "engines": {
14
+ "node": ">=18"
15
+ }
16
+ }