@topmindspace/topmind-writing-skills 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +931 -0
- package/LICENSE +21 -0
- package/README.en.md +124 -0
- package/README.md +124 -0
- package/bin/topmind-writing-skills.js +388 -0
- package/package.json +56 -0
- package/topmind-briefs/CHANGELOG.md +22 -0
- package/topmind-briefs/README.en.md +41 -0
- package/topmind-briefs/README.md +37 -0
- package/topmind-briefs/SKILL.md +101 -0
- package/topmind-briefs/dist/topmind-briefs.manifest.json +21 -0
- package/topmind-briefs/dist/topmind-briefs.zip +0 -0
- package/topmind-briefs/package-lock.json +13 -0
- package/topmind-briefs/package.json +1 -0
- package/topmind-briefs/references/examples.md +131 -0
- package/topmind-briefs/references/platform-specs.md +63 -0
- package/topmind-briefs/references/style-guide.md +60 -0
- package/topmind-briefs/scripts/audit_css.py +39 -0
- package/topmind-briefs/scripts/audit_docs.py +80 -0
- package/topmind-briefs/scripts/audit_skill.py +60 -0
- package/topmind-briefs/scripts/audit_styles.py +54 -0
- package/topmind-briefs/scripts/negative_tests.py +88 -0
- package/topmind-briefs/scripts/package_skill.py +188 -0
- package/topmind-cover/README.en.md +54 -0
- package/topmind-cover/README.md +54 -0
- package/topmind-cover/SKILL.md +134 -0
- package/topmind-cover/assets/examples/README.md +34 -0
- package/topmind-cover/assets/examples/bg-blur-alt.png +0 -0
- package/topmind-cover/assets/examples/bg-blur-wechat.png +0 -0
- package/topmind-cover/assets/examples/bg-blur.png +0 -0
- package/topmind-cover/assets/examples/big-type-wechat.png +0 -0
- package/topmind-cover/assets/examples/big-type.png +0 -0
- package/topmind-cover/assets/examples/brand-launch-wechat.png +0 -0
- package/topmind-cover/assets/examples/brand-launch.png +0 -0
- package/topmind-cover/assets/examples/gan-huo-wechat.png +0 -0
- package/topmind-cover/assets/examples/gan-huo.png +0 -0
- package/topmind-cover/assets/examples/ip-fun-wechat.png +0 -0
- package/topmind-cover/assets/examples/ip-fun.png +0 -0
- package/topmind-cover/assets/examples/magazine-wechat.png +0 -0
- package/topmind-cover/assets/examples/magazine.png +0 -0
- package/topmind-cover/assets/examples/minimal-wechat.png +0 -0
- package/topmind-cover/assets/examples/minimal.png +0 -0
- package/topmind-cover/assets/examples/news-flash-wechat.png +0 -0
- package/topmind-cover/assets/examples/news-flash.png +0 -0
- package/topmind-cover/assets/examples/overview.png +0 -0
- package/topmind-cover/assets/examples/paper-collage-alt.png +0 -0
- package/topmind-cover/assets/examples/paper-collage-wechat.png +0 -0
- package/topmind-cover/assets/examples/paper-collage.png +0 -0
- package/topmind-cover/assets/examples/tutorial-steps-wechat.png +0 -0
- package/topmind-cover/assets/examples/tutorial-steps.png +0 -0
- package/topmind-cover/assets/examples/white-clean-alt-wechat.png +0 -0
- package/topmind-cover/assets/examples/white-clean-alt.png +0 -0
- package/topmind-cover/assets/examples/white-clean-wechat.png +0 -0
- package/topmind-cover/assets/examples/white-clean.png +0 -0
- package/topmind-cover/package-lock.json +16 -0
- package/topmind-cover/package.json +16 -0
- package/topmind-cover/references/cover-prompts.md +436 -0
- package/topmind-cover/references/cover-styles.md +496 -0
- package/topmind-cover/references/impact-language.md +94 -0
- package/topmind-cover/references/ref-white-clean-1.png +0 -0
- package/topmind-cover/references/ref-white-clean-2.png +0 -0
- package/topmind-cover/scripts/audit_css.py +39 -0
- package/topmind-cover/scripts/audit_docs.py +80 -0
- package/topmind-cover/scripts/audit_skill.py +60 -0
- package/topmind-cover/scripts/audit_styles.py +54 -0
- package/topmind-cover/scripts/crop-cover.py +74 -0
- package/topmind-cover/scripts/negative_tests.py +71 -0
- package/topmind-cover/scripts/package_skill.py +188 -0
- package/topmind-wechat-post/README.en.md +111 -0
- package/topmind-wechat-post/README.md +111 -0
- package/topmind-wechat-post/SKILL.md +251 -0
- package/topmind-wechat-post/assets/themes/amber-review.json +35 -0
- package/topmind-wechat-post/assets/themes/graphite.json +35 -0
- package/topmind-wechat-post/assets/themes/minimal-ink.json +35 -0
- package/topmind-wechat-post/assets/themes/newsprint.json +35 -0
- package/topmind-wechat-post/assets/themes/tech-blue.json +35 -0
- package/topmind-wechat-post/package-lock.json +16 -0
- package/topmind-wechat-post/package.json +16 -0
- package/topmind-wechat-post/references/design.md +50 -0
- package/topmind-wechat-post/references/element-spec.md +163 -0
- package/topmind-wechat-post/references/known-pits.md +85 -0
- package/topmind-wechat-post/references/theme-map.md +139 -0
- package/topmind-wechat-post/references/typography-rules.md +62 -0
- package/topmind-wechat-post/references/wechat-constraints.md +111 -0
- package/topmind-wechat-post/references/workflow.md +102 -0
- package/topmind-wechat-post/references/writing-quality.md +105 -0
- package/topmind-wechat-post/scripts/audit_css.py +39 -0
- package/topmind-wechat-post/scripts/audit_docs.py +80 -0
- package/topmind-wechat-post/scripts/audit_skill.py +60 -0
- package/topmind-wechat-post/scripts/audit_styles.py +54 -0
- package/topmind-wechat-post/scripts/lint-wechat.py +446 -0
- package/topmind-wechat-post/scripts/md2wechat.py +1792 -0
- package/topmind-wechat-post/scripts/negative_tests.py +171 -0
- package/topmind-wechat-post/scripts/new-article.py +183 -0
- package/topmind-wechat-post/scripts/package_skill.py +188 -0
- package/topmind-wechat-post/scripts/push-to-topstream.py +226 -0
- package/topmind-wechat-post/scripts/scan_ai_flavor.py +464 -0
- package/topmind-wechat-post/scripts/sync-mapping.py +220 -0
- package/topmind-wechat-post/scripts/sync-status.py +187 -0
- package/topmind-x-article/README.en.md +109 -0
- package/topmind-x-article/README.md +104 -0
- package/topmind-x-article/SKILL.md +156 -0
- package/topmind-x-article/package-lock.json +16 -0
- package/topmind-x-article/package.json +16 -0
- package/topmind-x-article/references/publish-checklist.md +31 -0
- package/topmind-x-article/references/x-format.md +27 -0
- package/topmind-x-article/references/x-html-format.md +85 -0
- package/topmind-x-article/scripts/audit_css.py +39 -0
- package/topmind-x-article/scripts/audit_docs.py +80 -0
- package/topmind-x-article/scripts/audit_skill.py +60 -0
- package/topmind-x-article/scripts/audit_styles.py +54 -0
- package/topmind-x-article/scripts/md2x-html.py +522 -0
- package/topmind-x-article/scripts/md2x.py +323 -0
- package/topmind-x-article/scripts/negative_tests.py +91 -0
- 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,111 @@
|
|
|
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
|
+
- Version: **v0.2.0** (same tag as `@topmindspace/topmind-writing-skills@0.7.1`)
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @topmindspace/topmind-writing-skills install topmind-wechat-post
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
export TOPMIND_WORKSPACE=/path/to/workspace # recommended; or point the delivery package root with --base
|
|
19
|
+
|
|
20
|
+
# Create a new delivery package
|
|
21
|
+
python3 scripts/new-article.py --slug demo --title "标题" --direction reverse
|
|
22
|
+
|
|
23
|
+
# Typography lint + auto-fix
|
|
24
|
+
python3 scripts/lint-wechat.py --input <package>/公众号稿.md --fix
|
|
25
|
+
|
|
26
|
+
# De-AI-flavor scan (target ≥ 85)
|
|
27
|
+
python3 scripts/scan_ai_flavor.py <package>/公众号稿.md
|
|
28
|
+
|
|
29
|
+
# Markdown → fully inline HTML (--embed-images is mandatory, or pasted images go missing)
|
|
30
|
+
python3 scripts/md2wechat.py --input <package>/公众号稿.md --out-dir <package> --slug demo --embed-images
|
|
31
|
+
|
|
32
|
+
# Status sync
|
|
33
|
+
python3 scripts/sync-status.py --set 定稿 <package> --apply
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Scripts use Python stdlib only — zero dependencies.
|
|
37
|
+
|
|
38
|
+
## Minimal example
|
|
39
|
+
|
|
40
|
+
Input `demo.md`:
|
|
41
|
+
|
|
42
|
+
# Title
|
|
43
|
+
|
|
44
|
+
Opening hook paragraph.
|
|
45
|
+
|
|
46
|
+
## Chapter One
|
|
47
|
+
|
|
48
|
+
Body text with **emphasis**.
|
|
49
|
+
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# first drop a real image at images/a.png next to demo.md (missing files land in the
|
|
54
|
+
# checklist as "not embedded" and will be lost on paste)
|
|
55
|
+
mkdir -p images && cp /path/to/your-image.png images/a.png
|
|
56
|
+
python3 scripts/md2wechat.py --input demo.md --out-dir demo --slug demo --embed-images
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Output `demo/demo-公众号版.html` (open in a browser → click "复制正文" → paste into the WeChat editor):
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<!-- h2 auto-numbered; closing chapters like "总结" get ∞ -->
|
|
63
|
+
<h2 ...><span ...>1</span>Chapter One</h2>
|
|
64
|
+
<!-- images inlined as base64, pasted along with the text -->
|
|
65
|
+
<img src="data:image/png;base64,iVBORw0KGgo..." ...>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Also generated: `demo/图片上传清单.md` — the upload checklist for images, mermaid diagrams, and reference links.
|
|
69
|
+
|
|
70
|
+
## md2wechat parameters
|
|
71
|
+
|
|
72
|
+
| Flag | Description |
|
|
73
|
+
|------|-------------|
|
|
74
|
+
| `--input` / `--out-dir` / `--slug` | Required: input md, output dir, filename slug |
|
|
75
|
+
| `--embed-images` | Inline images as base64 (mandatory, or pasted images go missing) |
|
|
76
|
+
| `--theme` | Theme id / Chinese name / JSON path, or `genre:<topic>` for auto-pick; `--list-themes` shows all |
|
|
77
|
+
| `--link-mode` | Link rendering: `footnote` (default: superscript `[n]` + end-of-article "参考链接") / `inline` (label normal, URL gray: `文字(url)`) / `note` (whole block gray small text: `文字(url)`) |
|
|
78
|
+
| `--asset-root` | Asset root dir, resolves `../assets/`-style image paths in the draft |
|
|
79
|
+
| `--no-toc` | Skip the auto-inserted "本文看点" reading guide |
|
|
80
|
+
| `--signature` / `--author` / `--author-bio` | Closing signature: `auto` (default, skipped if the draft has one) / `on` / `off`, name and bio |
|
|
81
|
+
| `--no-pangu` | Disable automatic CJK/Latin spacing |
|
|
82
|
+
| `--render-mermaid` | Render mermaid to PNG when mmdc is available |
|
|
83
|
+
|
|
84
|
+
## Three paths
|
|
85
|
+
|
|
86
|
+
- **forward**: draft → WeChat article (review & rewrite)
|
|
87
|
+
- **reverse**: original topic → WeChat article → optional pushback
|
|
88
|
+
- **curated web**: online curated sources → handled as reverse
|
|
89
|
+
|
|
90
|
+
## Three quality gates
|
|
91
|
+
|
|
92
|
+
Facts (first-hand sources) / logic (structural consistency) / copy (de-AI-flavor ≥ 85).
|
|
93
|
+
|
|
94
|
+
## Related skills
|
|
95
|
+
|
|
96
|
+
- Cover art → `topmind-cover` (shared X long-form / WeChat cover)
|
|
97
|
+
- X long-form → `topmind-x-article` (Markdown draft → one-click X publish package)
|
|
98
|
+
|
|
99
|
+
## External dependencies
|
|
100
|
+
|
|
101
|
+
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:
|
|
102
|
+
|
|
103
|
+
- `humanizer-zh`: fidelity boundaries for Chinese de-AI-flavor; without it the "de-AI-flavor only, no typesetting" path is unavailable.
|
|
104
|
+
- `qu-aiwei-zh`: Chinese de-AI-flavor scan targeting; `scripts/scan_ai_flavor.py` shares its origin and can substitute when missing.
|
|
105
|
+
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
python3 scripts/package_skill.py --check
|
|
110
|
+
python3 scripts/negative_tests.py
|
|
111
|
+
```
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# topmind-wechat-post · 公众号创作技能
|
|
2
|
+
|
|
3
|
+
[English](./README.en.md) | 中文
|
|
4
|
+
|
|
5
|
+
公众号文章全生命周期:交付包、审校改写、质量三关、状态同步、微信内联排版与发布清单。
|
|
6
|
+
|
|
7
|
+
- 版本:**v0.2.0**(与 `@topmindspace/topmind-writing-skills@0.7.1` 同 tag)
|
|
8
|
+
|
|
9
|
+
## 安装
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx @topmindspace/topmind-writing-skills install topmind-wechat-post
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 用法
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
export TOPMIND_WORKSPACE=/path/to/workspace # 推荐;或用 --base 指定交付包根
|
|
19
|
+
|
|
20
|
+
# 新建交付包
|
|
21
|
+
python3 scripts/new-article.py --slug demo --title "标题" --direction reverse
|
|
22
|
+
|
|
23
|
+
# 排版体检 + 自动修复
|
|
24
|
+
python3 scripts/lint-wechat.py --input <包>/公众号稿.md --fix
|
|
25
|
+
|
|
26
|
+
# 去 AI 味扫描(目标 ≥85)
|
|
27
|
+
python3 scripts/scan_ai_flavor.py <包>/公众号稿.md
|
|
28
|
+
|
|
29
|
+
# Markdown → 全内联 HTML(必加 --embed-images,否则粘贴丢图)
|
|
30
|
+
python3 scripts/md2wechat.py --input <包>/公众号稿.md --out-dir <包> --slug demo --embed-images
|
|
31
|
+
|
|
32
|
+
# 状态同步
|
|
33
|
+
python3 scripts/sync-status.py --set 定稿 <包> --apply
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
脚本纯 Python 标准库,零依赖。
|
|
37
|
+
|
|
38
|
+
## 最小示例
|
|
39
|
+
|
|
40
|
+
输入 `demo.md`:
|
|
41
|
+
|
|
42
|
+
# 标题
|
|
43
|
+
|
|
44
|
+
开头钩子段落。
|
|
45
|
+
|
|
46
|
+
## 第一章
|
|
47
|
+
|
|
48
|
+
正文文字,**重点**加粗。
|
|
49
|
+
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# 先在 demo.md 同级放一张真实图片到 images/a.png(缺图会进"未内嵌"清单,粘贴后丢图)
|
|
54
|
+
mkdir -p images && cp /path/to/你的图.png images/a.png
|
|
55
|
+
python3 scripts/md2wechat.py --input demo.md --out-dir demo --slug demo --embed-images
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
输出 `demo/demo-公众号版.html`(浏览器打开 → 点「复制正文」→ 粘贴到公众号后台):
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<!-- 二级标题自动编号;"总结"类末章编号为 ∞ -->
|
|
62
|
+
<h2 ...><span ...>1</span>第一章</h2>
|
|
63
|
+
<!-- 图片 base64 内嵌,粘贴即带图 -->
|
|
64
|
+
<img src="data:image/png;base64,iVBORw0KGgo..." ...>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
附带 `demo/图片上传清单.md`:图片 / mermaid 图表 / 参考链接的上传与核对清单。
|
|
68
|
+
|
|
69
|
+
## md2wechat 参数
|
|
70
|
+
|
|
71
|
+
| 参数 | 说明 |
|
|
72
|
+
|------|------|
|
|
73
|
+
| `--input` / `--out-dir` / `--slug` | 必填:输入 md、输出目录、文件名标识 |
|
|
74
|
+
| `--embed-images` | 图片 base64 内嵌(必加,否则粘贴丢图) |
|
|
75
|
+
| `--theme` | 主题标识 / 中文名 / JSON 路径,或 `genre:题材` 按题材自动选;`--list-themes` 查看全部 |
|
|
76
|
+
| `--link-mode` | 外链形态:`footnote`(默认:正文上标 `[n]` + 文末「参考链接」)/ `inline`(文字正常、URL 灰小字:`文字(url)`)/ `note`(整块灰小字:`文字(url)`) |
|
|
77
|
+
| `--asset-root` | 素材根目录,用于解析稿中 `../assets/` 形式的图片路径 |
|
|
78
|
+
| `--no-toc` | 不自动插入前言导读 |
|
|
79
|
+
| `--signature` / `--author` / `--author-bio` | 尾部签名区:`auto`(默认,有签名则不重复)/ `on` / `off`,署名与简介 |
|
|
80
|
+
| `--no-pangu` | 关闭中英文自动加空格 |
|
|
81
|
+
| `--render-mermaid` | 有 mmdc 时把 mermaid 渲染成 PNG |
|
|
82
|
+
|
|
83
|
+
## 三条路径
|
|
84
|
+
|
|
85
|
+
- **forward**:底稿 → 公众号(审校改写)
|
|
86
|
+
- **reverse**:选题原创 → 公众号 → 可选回推
|
|
87
|
+
- **站外拉取**:在线精选站 → 按 reverse 处理
|
|
88
|
+
|
|
89
|
+
## 质量三关
|
|
90
|
+
|
|
91
|
+
事实(一手来源)/ 逻辑(结构一致)/ 文字(去 AI 味 ≥85)。
|
|
92
|
+
|
|
93
|
+
## 相关技能
|
|
94
|
+
|
|
95
|
+
- 封面配图 → `topmind-cover`(X 长文 / 公众号共用封面)
|
|
96
|
+
- X 长文 → `topmind-x-article`(Markdown 原稿一键转 X 发布包)
|
|
97
|
+
|
|
98
|
+
## 外部依赖
|
|
99
|
+
|
|
100
|
+
本技能工作流会路由到以下**仓库外**技能(不含于本仓库,一般随用户侧 workbuddy
|
|
101
|
+
环境提供)。缺失时对应能力降级/不可用,不影响本仓库脚本的全部功能:
|
|
102
|
+
|
|
103
|
+
- `humanizer-zh`:中文去 AI 味的保真边界;缺失时「只去 AI 味不排版」路径不可用。
|
|
104
|
+
- `qu-aiwei-zh`:中文去 AI 味扫描定位;`scripts/scan_ai_flavor.py` 与其同源,缺失时可用仓库内脚本替代。
|
|
105
|
+
|
|
106
|
+
## 开发
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
python3 scripts/package_skill.py --check
|
|
110
|
+
python3 scripts/negative_tests.py
|
|
111
|
+
```
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: topmind-wechat-post
|
|
3
|
+
version: 0.2.0
|
|
4
|
+
description: "管一篇公众号文章从选题/底稿到发布的完整生命周期:交付包搭建、审校改写、质量三关(事实/逻辑/去AI味)、状态同步、微信内联排版与发布清单。Use when 写公众号、公众号排版、公众号定稿、发公众号。Do NOT use for 只改错别字、小红书/知乎、纯网页发布。"
|
|
5
|
+
action_category: write
|
|
6
|
+
triggers:
|
|
7
|
+
- 公众号
|
|
8
|
+
- 微信排版
|
|
9
|
+
- 公众号排版
|
|
10
|
+
- 公众号稿
|
|
11
|
+
- 排版这篇文章
|
|
12
|
+
- 定稿
|
|
13
|
+
- 发公众号
|
|
14
|
+
- 公众号交付
|
|
15
|
+
- wechat
|
|
16
|
+
- mp format
|
|
17
|
+
triggers_cn:
|
|
18
|
+
- 写公众号文章
|
|
19
|
+
- 公众号排版定稿
|
|
20
|
+
- 公众号发布清单
|
|
21
|
+
author: TopMindspace
|
|
22
|
+
license: MIT
|
|
23
|
+
homepage: https://github.com/topmindspace/topmind-writing-skills#readme
|
|
24
|
+
updated: 2026-09-29
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# topmind-wechat-post · 公众号创作技能
|
|
28
|
+
|
|
29
|
+
**公众号专用写作技能**。管一篇公众号文章从选题/底稿到发布清单的完整生命周期。
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
选题/底稿 → 创作 → 质量三关 → 定稿(状态+目录) → 排版 → 发布清单 →(可选)回推 notes
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> 用户明确说公众号 / 微信排版时进本技能;通用长文写作不在本技能范围内。
|
|
36
|
+
|
|
37
|
+
## 语言铁律
|
|
38
|
+
|
|
39
|
+
- **默认中文**:标题、正文、配图文案一律用中文写作,这是默认行为,不需要用户每次声明。
|
|
40
|
+
- **英文是例外**:只有用户**明确说**"写英文文章"时才用英文。用户消息里夹杂英文词、
|
|
41
|
+
给英文参考素材、引用英文原文,都不算"要求写英文"。
|
|
42
|
+
- 引用英文一手素材(官方公告、模型卡、论文标题)时保留英文原文,正文主体仍是中文,
|
|
43
|
+
必要时在旁给中文翻译。
|
|
44
|
+
|
|
45
|
+
## 脚本(真源)
|
|
46
|
+
|
|
47
|
+
| 脚本 | 用途 |
|
|
48
|
+
|------|------|
|
|
49
|
+
| `scripts/new-article.py` | 建交付包(骨架稿 + frontmatter + images/diagrams) |
|
|
50
|
+
| `scripts/sync-status.py` | 状态 ⇄ 目录名 ⇄ 字数(草稿 / 定稿 / 已发布) |
|
|
51
|
+
| `scripts/sync-mapping.py` | 映射一致性(frontmatter + 目录 + 可选 notes + topic 总表) |
|
|
52
|
+
| `scripts/push-to-topstream.py` | 可选回推:公众号稿降级为纯 Markdown notes |
|
|
53
|
+
| `scripts/lint-wechat.py` | 排版体检 + 自动修复(中英文间距、段长、AI 腔…) |
|
|
54
|
+
| `scripts/md2wechat.py` | Markdown → 全内联 HTML;**必加 `--embed-images`** |
|
|
55
|
+
| `scripts/scan_ai_flavor.py` | 中文去 AI 味扫描(与 `qu-aiwei-zh` 同源) |
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# 路径解析:CLI --base/--workspace → env TOPMIND_WECHAT_BASE / TOPMIND_WORKSPACE / TOPSTREAM_ROOT → 惯例
|
|
59
|
+
export TOPMIND_WORKSPACE=/path/to/workspace # 推荐
|
|
60
|
+
python3 scripts/new-article.py --slug demo --title "标题" --direction reverse
|
|
61
|
+
python3 scripts/lint-wechat.py --input <包>/公众号稿.md --fix
|
|
62
|
+
python3 scripts/scan_ai_flavor.py <包>/公众号稿.md # 目标 ≥85
|
|
63
|
+
python3 scripts/md2wechat.py --input <包>/公众号稿.md --out-dir <包> --slug demo \
|
|
64
|
+
--asset-root <素材根> --embed-images
|
|
65
|
+
python3 scripts/sync-status.py --set 定稿 <包> --apply
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
细节见 [`references/workflow.md`](references/workflow.md) · [`references/known-pits.md`](references/known-pits.md)。
|
|
69
|
+
|
|
70
|
+
## 路径默认
|
|
71
|
+
|
|
72
|
+
| 用途 | 解析 |
|
|
73
|
+
|------|------|
|
|
74
|
+
| 交付包根 | `--base` → `TOPMIND_WECHAT_BASE` → `{ws}/40-创作/2026-公众号` 或 `{ws}/20-专题/2026-公众号` |
|
|
75
|
+
| 工作区 | `TOPMIND_WORKSPACE` |
|
|
76
|
+
| 底稿/回推 | `--topstream` → `TOPSTREAM_ROOT` → 可选;不存在则跳过 notes 校验 |
|
|
77
|
+
| 终稿交付 | 可 `save-output` 拷贝到 role:delivery(`88-交付/`),包仍留在创作类专题 |
|
|
78
|
+
|
|
79
|
+
## 三条路径
|
|
80
|
+
|
|
81
|
+
### forward(底稿 → 公众号)
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
底稿 notes/*.md → 审校改写 → 质量三关 → 定稿 → 排版 → 发布
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`new-article.py --direction forward --source-file notes/xxx.md`
|
|
88
|
+
|
|
89
|
+
### reverse(选题原创)
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
选题包 → 调研素材 → 多轮改稿 → 三关 → 定稿 → 排版 → 发布 →(可选)push-to-topstream
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`new-article.py --direction reverse`(`target_file: pending`)
|
|
96
|
+
|
|
97
|
+
### 站外拉取(转载整合 / 在线精选站)
|
|
98
|
+
|
|
99
|
+
源不在本工作区、也不在 topstream `notes/` 时,**仍落 `reverse` + `target_file: pending`**。
|
|
100
|
+
**不要用 `forward`**:它要求 `source_file` 以 `notes/` 开头且文件真实存在,站外源必然过不了 `sync-mapping.py`。
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
python3 scripts/new-article.py --slug <中文短名> --title "<标题>" --direction reverse
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
取源坑(RSC 载荷、图片 hash 映射、`md5` 去重、截图裁切)见 `references/workflow.md`「站外拉取取源注意」;差异与口径写进包内 `README.md`。
|
|
107
|
+
|
|
108
|
+
**回推纪律**:notes 保持纯 Markdown(`:::` 容器 / 徽章 / `==高亮==` 只进公众号稿);回推**务必带 `--assets`**(否则 GitHub 上 `images/` 死链)。命令串见 `references/workflow.md`「收尾」。
|
|
109
|
+
|
|
110
|
+
## 交付包与状态
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
YYYY-MM-DD-<中文短名> # 草稿
|
|
114
|
+
YYYY-MM-DD-<中文短名>-released # 定稿 / 已发布
|
|
115
|
+
├── 公众号稿.md # 唯一改稿入口
|
|
116
|
+
├── <slug>-公众号版.html # 浏览器打开 → 复制正文 → 粘贴后台
|
|
117
|
+
├── 图片上传清单.md
|
|
118
|
+
├── images/ diagrams/
|
|
119
|
+
└── README.md # 包说明(可选)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**frontmatter(映射真源)**
|
|
123
|
+
|
|
124
|
+
```yaml
|
|
125
|
+
status: 草稿 # 草稿 | 定稿 | 已发布
|
|
126
|
+
direction: reverse # forward | reverse
|
|
127
|
+
source_file: "" # forward 填 notes/xxx.md
|
|
128
|
+
target_file: pending # reverse:pending | notes/xxx.md
|
|
129
|
+
word_count: 0 # 纯中文字数,sync-status 维护
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
**交付铁律**:发布/分享时直接用交付包里的 HTML 原文件原样呈现,
|
|
133
|
+
不临时重新生成版本;`公众号稿.md` 是唯一改稿入口,改稿后重建 HTML 再交付。
|
|
134
|
+
|
|
135
|
+
状态与目录名**不要手改**:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
python3 scripts/sync-status.py --set 定稿 <包> --apply
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 质量三关(定稿前必过)
|
|
142
|
+
|
|
143
|
+
### 关 1 · 事实
|
|
144
|
+
|
|
145
|
+
- 承重数字回**一手来源**;厂商口径 / 据报道 分开写
|
|
146
|
+
- 查不到一手来源的传闻**删**
|
|
147
|
+
- 改稿续写:正文已有数字**回源重核**(上一轮文本最不可信)
|
|
148
|
+
- 多口径(主轮/复跑)显式拆开;表格从数据源生成,禁止手抄
|
|
149
|
+
- 外部工具改过的稿:**先核数字再动文字**;「比值对但绝对值错」= 全段重核
|
|
150
|
+
|
|
151
|
+
### 关 2 · 逻辑
|
|
152
|
+
|
|
153
|
+
- 单边结论旁配反方证据
|
|
154
|
+
- 结构前后一致;同一事实多处同值
|
|
155
|
+
|
|
156
|
+
### 关 3 · 文字(去 AI 味)
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
python3 scripts/scan_ai_flavor.py <包>/公众号稿.md # ≥85(人话)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
- 删套话/黑话/工程圈行话;降调段末加粗金句
|
|
163
|
+
- **满分 ≠ 有人味**:再查「段末金句癖 / 节奏过分整齐 / 没有场景与我 / 报告体标注」
|
|
164
|
+
- **口语化 ≠ 有人味**:删社交垫词(元叙述、空转过渡、姿态句)
|
|
165
|
+
- 判据:**这句话删掉之后,读者少知道了什么?**
|
|
166
|
+
|
|
167
|
+
详见 [`references/writing-quality.md`](references/writing-quality.md)。
|
|
168
|
+
|
|
169
|
+
## 排版要点(写稿时)
|
|
170
|
+
|
|
171
|
+
- 开头 150 字内钩子;单段 ≤110 字;列表项 ≤70 字
|
|
172
|
+
- 二级标题不手写序号(排版层自动生成);容器:`::: stat|pull|note|tip|warn|danger|dialogue`
|
|
173
|
+
- **`::: stat` 内必须是 `数值 | 说明` 管道行**,否则静默丢弃
|
|
174
|
+
- 评测稿:**图承担数据,正文只解读**;健康密度 **300–450 字/图**
|
|
175
|
+
- 个股用词红线:禁用 买入/推荐/目标价…;文末投资声明
|
|
176
|
+
|
|
177
|
+
更多:[`references/typography-rules.md`](references/typography-rules.md) · [`references/wechat-constraints.md`](references/wechat-constraints.md)。
|
|
178
|
+
|
|
179
|
+
## 排版与导出(必读)
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
python3 scripts/md2wechat.py \
|
|
183
|
+
--input <包>/公众号稿.md --out-dir <包> --slug <slug> \
|
|
184
|
+
--asset-root <素材根> --embed-images \
|
|
185
|
+
[--theme assets/themes/minimal-ink.json]
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
1. **永远 `--embed-images`**,否则粘贴丢图(相对路径被序列化成 file://)
|
|
189
|
+
2. **图片 basename 铁律**:正文引用名 = `images/` 目标名;禁止两套同名图共处
|
|
190
|
+
3. 合规自检出现 `✗` 改生成器,不要手改 HTML
|
|
191
|
+
4. **配图位置铁律**(2026-10-01 九月全景教训):图片必须紧跟它证明的那段文字
|
|
192
|
+
(最多隔一段);改稿移动段落时图片行一起搬。构建后必跑:嵌入图数量=文档图数量、
|
|
193
|
+
嵌入图顺序=文档出现顺序(逐张解码与源文件比对);每张图前后 6 行做主题关键词
|
|
194
|
+
邻近检查,不通过则人工核对。
|
|
195
|
+
5. **双版一致性校验**(2026-10-01 九月全景教训 B):同一选题出 X 版后,
|
|
196
|
+
必跑 X 内嵌图序列 vs 公众号内嵌图序列的逐字节/逐像素比对(X 去掉封面后应完全一致)。
|
|
197
|
+
X 侧图片顺序必须用 `--images-from 公众号稿.md` 派生,禁止手工拼 `--images`
|
|
198
|
+
(曾因文件名排序 ≠ 文档顺序,导致 X 版从第六节起整段配图错位)。
|
|
199
|
+
|
|
200
|
+
坑清单:[`references/known-pits.md`](references/known-pits.md)。
|
|
201
|
+
|
|
202
|
+
## 主题
|
|
203
|
+
|
|
204
|
+
| 文件 | 风格 | 适用 |
|
|
205
|
+
|------|------|------|
|
|
206
|
+
| `assets/themes/minimal-ink.json`(默认) | 黑白灰 + 砖红 | 深度研析 / 观点 / 随笔 |
|
|
207
|
+
| `assets/themes/tech-blue.json` | 科技蓝 | AI/技术 |
|
|
208
|
+
| `assets/themes/newsprint.json` | 报纸衬线 | 人文评论 |
|
|
209
|
+
| `assets/themes/graphite.json` | 石墨克制 | 严肃报告 |
|
|
210
|
+
| `assets/themes/amber-review.json` | 琥珀评测 | 产品评测 |
|
|
211
|
+
|
|
212
|
+
`md2wechat.py --list-themes` 看全部;`--theme genre:评测` 可按题材自动选。
|
|
213
|
+
渲染规格见 [`references/element-spec.md`](references/element-spec.md) · 主题映射见 [`references/theme-map.md`](references/theme-map.md)。
|
|
214
|
+
|
|
215
|
+
**平台红线速查**(详见 [`references/wechat-constraints.md`](references/wechat-constraints.md)):禁 `div`/`pre`/`h1`/`figure`/`thead`/flex/float/gradient/shadow;表格 `table-layout` 不写 fixed;列数 ≥4 转卡片。
|
|
216
|
+
|
|
217
|
+
## 与 Desktop「公众号创作」
|
|
218
|
+
|
|
219
|
+
可视化工作流伴面(若有):包列表 → 改稿 → 三关 → 预览 → 导出。脚本语义以本技能为准。
|
|
220
|
+
|
|
221
|
+
## 外部依赖
|
|
222
|
+
|
|
223
|
+
以下技能**不在本仓库**(一般随用户侧 workbuddy 环境提供);缺失时对应路由能力不可用,
|
|
224
|
+
本仓库脚本(交付包、排版、发布清单等)功能不受影响:
|
|
225
|
+
|
|
226
|
+
- `humanizer-zh`:中文去 AI 味的保真边界(「只去 AI 味不排版」路径用)。
|
|
227
|
+
- `qu-aiwei-zh`:中文去 AI 味扫描定位;本仓库 `scan_ai_flavor.py` 与其同源,
|
|
228
|
+
缺失时可用仓库内脚本替代,扫描定位能力降级。
|
|
229
|
+
|
|
230
|
+
## When NOT to use
|
|
231
|
+
|
|
232
|
+
- 只想改几个句子 → 直接编辑
|
|
233
|
+
- 小红书 / 知乎 / 掘金 → 平台约束不同
|
|
234
|
+
- 通用长文交付 → 不在本技能范围
|
|
235
|
+
- 封面配图 → `topmind-cover`;X 长文 → `topmind-x-article`
|
|
236
|
+
- 只去 AI 味不排版 → 中文走 `humanizer-zh`(先立保真边界)+ `qu-aiwei-zh`(再扫描定位);英文走 `humanizer`
|
|
237
|
+
|
|
238
|
+
## 实战沉淀(2026-10-01 九月全景项目)
|
|
239
|
+
|
|
240
|
+
- **文字精炼原则**:月度盘点类文章,文字只给"看图能看清的简单结论或事实",
|
|
241
|
+
不发散论述。删掉的典型:"9 月没发生的那件事可能是最重要的"(评论腔)、
|
|
242
|
+
"是同一道题的两种解法"(比喻发散)。每段压到 1–2 句,只留时间、主体、数字、来源。
|
|
243
|
+
- **第三方客观素材优先**:官方产品截图 > 官方基准图 > 第三方榜单截图 > 自制图表。
|
|
244
|
+
自制图只用于时间线、价格对比、总结盘点。9 月项目新增:OpenAI DevDay 官方
|
|
245
|
+
Codex 四图(CLI/Cloud/Code Review/Security)、DeepSeek Harness 官方图标+
|
|
246
|
+
第三方实测截图。
|
|
247
|
+
- **模型信息核实**:Muse Spark、Step 5 Preview 等新模型,分数/价格必须回官方模型卡
|
|
248
|
+
或 Artificial Analysis 原页,不直接采用二手报告数字。榜单文字与榜单截图日期对齐
|
|
249
|
+
(如 AA 9/28 快照),分数不跨期比较。
|
|
250
|
+
- **frontmatter 状态诚实**:`status: 定稿` 必须等事实/逻辑/文字三关全过才写,
|
|
251
|
+
构建流水线跑通不等于定稿;`word_count` 用脚本实算,不手填。
|