$npx -y skills add xiaomoBoy/claude-writing-skills --skill publisher-wechatsyncUse when the user has a finished blog master draft and wants to publish it to multiple content platforms (知乎/掘金/CSDN/公众号 等) via the @wechatsync/cli tool. Handles pre-flight auth checks, platform selection, dry-run preview, and the actual sync. Do NOT use for writing, rewriting, c
| 1 | # Publisher Wechatsync |
| 2 | |
| 3 | 这个 skill 只负责一件事:把已经写完的博客母稿通过 `@wechatsync/cli` 发到多个平台的草稿箱。 |
| 4 | |
| 5 | 边界很明确: |
| 6 | |
| 7 | - 负责:预检、平台选择、dry-run、真正同步、结果汇报 |
| 8 | - 不负责:改写正文 |
| 9 | - 不负责:大陆合规脱敏 |
| 10 | - 不负责:生成平台版标题、摘要、封面图 |
| 11 | - 不负责:替换母稿里的外链 |
| 12 | - 不负责:删除或修改源文件 |
| 13 | |
| 14 | 一句话原则:这一层只做"把现有 md 送到各家草稿箱"这一段,改写是另一个 skill 的事。 |
| 15 | |
| 16 | ## Working Scope |
| 17 | |
| 18 | 适用场景: |
| 19 | |
| 20 | - 用户说"把这篇发到知乎和掘金" |
| 21 | - 用户说"同步到公众号草稿箱" |
| 22 | - 用户说"这篇母稿写完了,帮我发出去" |
| 23 | - 用户说"先 dry-run 一下看看能发到哪里" |
| 24 | |
| 25 | 不适用场景: |
| 26 | |
| 27 | - 用户说"帮我改成公众号风格" |
| 28 | - 用户说"过一下合规" |
| 29 | - 用户说"帮我补摘要/封面/标题" |
| 30 | - 用户说"从 URL 抓取正文" |
| 31 | |
| 32 | 以上任意一种都不在这个 skill 的边界内。停住,告诉用户"发布 skill 不做改写,这是另一段流程"。 |
| 33 | |
| 34 | ## Required Inputs |
| 35 | |
| 36 | 每次执行前至少要拿到: |
| 37 | |
| 38 | 1. **源文件路径**:一个已写完的 `.md` 文件路径(例如 `path/to/your-article.md`) |
| 39 | 2. **目标平台列表**:逗号分隔的平台名(例如 `zhihu,juejin,csdn`) |
| 40 | |
| 41 | 可选补充: |
| 42 | |
| 43 | - `--title`:显式覆盖标题(默认从 frontmatter 或首个 `#` 提取) |
| 44 | - `--cover`:封面图 URL 或本地路径(知乎/公众号/小红书需要) |
| 45 | |
| 46 | ## Preconditions |
| 47 | |
| 48 | 开始前必须先确认这 3 件事: |
| 49 | |
| 50 | 1. **CLI 已安装** |
| 51 | - 执行 `which wechatsync` 能拿到路径 |
| 52 | - 执行 `wechatsync --version` 不报错 |
| 53 | - 如果没装,告诉用户运行 `npm install -g @wechatsync/cli` 再回来 |
| 54 | 2. **Chrome 扩展已连通** |
| 55 | - 用户需要安装 Wechatsync Chrome 扩展,并开启「同步桥接 / MCP Connection」 |
| 56 | - 扩展里会显示一个 Token |
| 57 | - 用户把 Token 写进环境变量:`export WECHATSYNC_TOKEN="xxx"` |
| 58 | - 端口默认 9527,如果占用,用 `SYNC_WS_PORT` 覆盖 |
| 59 | 3. **目标平台已登录** |
| 60 | - 用户需要先在 Chrome 里登录目标平台(知乎、掘金、CSDN 等)的网页版 |
| 61 | - 扩展用的是当前浏览器的 Cookie,没登录就发不了 |
| 62 | - 用 `wechatsync platforms -a` 查各平台登录状态 |
| 63 | |
| 64 | 如果上面任何一条没满足,停住报错,不要试图绕过。 |
| 65 | |
| 66 | ## Output Contract |
| 67 | |
| 68 | 这个 skill 的标准输出: |
| 69 | |
| 70 | 1. 预检报告(CLI 版本、Token 是否配置、目标平台登录状态) |
| 71 | 2. dry-run 预览(将要发到哪几个平台、文件路径、标题) |
| 72 | 3. 用户确认后的真正同步结果(每个平台是否成功、草稿链接或 id) |
| 73 | 4. 一句总结,告诉用户下一步要去哪些平台后台审核 |
| 74 | |
| 75 | 不生成任何中间文件。不修改源文件。不写入仓库任何位置。 |
| 76 | |
| 77 | ## Workflow |
| 78 | |
| 79 | ### Step 1: 接收输入并自检 |
| 80 | |
| 81 | 先做这几件事: |
| 82 | |
| 83 | 1. 读 `CLAUDE.md` / `AGENTS.md`,确认当前仓库流程允许发布 |
| 84 | 2. 确认用户要发的文件确实存在 |
| 85 | 3. 运行 `which wechatsync`,确认 CLI 可用 |
| 86 | 4. 运行 `echo $WECHATSYNC_TOKEN | wc -c`,确认 Token 非空 |
| 87 | |
| 88 | 任意一条失败就停住,别继续。 |
| 89 | |
| 90 | ### Step 1.5: 规整化图片路径(预处理) |
| 91 | |
| 92 | Obsidian 写出的 markdown 默认会把图片路径 URL 编码(空格变 `%20`,中文字符也被编码),wechatsync CLI **不会自动 decode**,直接发会导致图片全部跳过。 |
| 93 | |
| 94 | 每次发布前**必须**先跑预处理: |
| 95 | |
| 96 | ```bash |
| 97 | python3 scripts/normalize_image_paths.py "<md 文件路径>" --dry-run |
| 98 | ``` |
| 99 | |
| 100 | 看预览: |
| 101 | |
| 102 | - 如果 `找不到: 0`,跑一次去掉 `--dry-run` 的版本,原地修正 |
| 103 | - 如果 `找不到` 大于 0,停住,先排查图片文件到底在哪。不要带着 broken 图去发 |
| 104 | - 如果 `已修复: 0`,说明这篇不需要预处理,直接进下一步 |
| 105 | |
| 106 | 脚本做的事: |
| 107 | - URL decode 所有 markdown 图片链接 |
| 108 | - 解析到实际文件(先按相对路径,再按仓库根) |
| 109 | - 重写为 markdown 文件所在目录的相对路径 |
| 110 | - 外链(http/https/data)不动 |
| 111 | |
| 112 | 预处理对 Obsidian 完全兼容 —— Obsidian 既接受编码路径也接受未编码路径,改完继续在 Obsidian 里看没问题。 |
| 113 | |
| 114 | ### Step 2: 列出并确认目标平台 |
| 115 | |
| 116 | 如果用户没指定平台,默认只发 `zhihu,juejin` 两个技术平台: |
| 117 | |
| 118 | - 知乎、掘金的合规门槛最低 |
| 119 | - CSDN 需要手动过审,可以加 |
| 120 | - 公众号需要提前准备封面图和摘要,要单独确认 |
| 121 | - 小红书、头条对标题和封面要求更硬,单独确认 |
| 122 | |
| 123 | 推荐分组: |
| 124 | |
| 125 | - `tech-min`: `zhihu,juejin` — 默认,合规成本最低 |
| 126 | - `tech-full`: `zhihu,juejin,csdn,segmentfault,oschina` — 技术平台全家桶 |
| 127 | - `with-wechat`: 在上面基础上加 `wechat`,但要同时传 `--cover` 和确认标题 |
| 128 | - `social`: `xiaohongshu,weibo,toutiao` — 社交向,注意平台对风格差异敏感 |
| 129 | |
| 130 | 跑一次 `wechatsync platforms -a` 把当前登录状态调出来,不要直接假设。 |
| 131 | |
| 132 | ### Step 3: 先跑 dry-run |
| 133 | |
| 134 | **必须先 dry-run,不允许直接实跑。** |
| 135 | |
| 136 | ```bash |
| 137 | wechatsync sync "path/to/your-article.md" -p zhihu,juejin --dry-run |
| 138 | ``` |
| 139 | |
| 140 | 把 dry-run 输出完整贴给用户,让用户确认: |
| 141 | |
| 142 | - 解析到的标题对不对 |
| 143 | - 目标平台列表对不对 |
| 144 | - 文件路径没搞错 |
| 145 | |
| 146 | 只要用户说"不对",停住,别修正后直接跑。先问清楚问题在哪。 |
| 147 | |
| 148 | ### Step 4: 用户确认后实跑 |
| 149 | |
| 150 | 用户明确说"可以"或"发"之后,去掉 `--dry-run` 再跑一次同样的命令: |
| 151 | |
| 152 | ```bash |
| 153 | wechatsync sync "path/to/your-article.md" -p zhihu,juejin |
| 154 | ``` |
| 155 | |
| 156 | 如果要传封面或自定义标题: |
| 157 | |
| 158 | ```bash |
| 159 | wechatsync sync "path/to/your-article.md" \ |
| 160 | -p zhihu,juejin,wechat \ |
| 161 | -t "可能改过的标题" \ |
| 162 | --cover "path/to/cover.png" |
| 163 | ``` |
| 164 | |
| 165 | ### Step 5: 汇报结果 |
| 166 | |
| 167 | 同步完成后,按每个平台列一行结果: |
| 168 | |
| 169 | - ✓ 成功:平台名 + 草稿 id 或链接 |
| 170 | - ✗ 失败:平台名 + 错误原因 |
| 171 | |
| 172 | 错误最常见的几类: |
| 173 | |
| 174 | - `未登录`:让用户去那个平台网页版登录后重试 |
| 175 | - `超时`:Chrome 扩展掉线,重启扩展或重开浏览器 |
| 176 | - `图片上传失败`:正文里有外链图片,某些平台拉不到 |
| 177 | - `内容超长/过短`:平台有字数限制 |
| 178 | |
| 179 | ### Step 6: 收尾提示 |
| 180 | |
| 181 | 给用户一句收尾话: |
| 182 | |
| 183 | - 告诉用户每个平台的草稿箱在哪里手动审核 |
| 184 | - 提醒这是草稿,需要在平台后台预览 → 配封面 → 手动点发布 |
| 185 | - **不要替用户去点「发布」按钮** |
| 186 | |
| 187 | ## Hard Constraints |
| 188 | |
| 189 | - **禁止**未经用户确认就跑非 dry-run |
| 190 | - **禁止**跳过 Step 1.5 的图片路径预处理 |
| 191 | - **禁止**发布前改写正文(那是另一个 skill 的事) |
| 192 | - 注意:预处理只改图片路径,不算改写正文 |
| 193 | - **禁止**自动补合规脱敏 |
| 194 | - **禁止**替用户在平台后台点「发布」 |
| 195 | - **禁止**跳过 `wechatsync platforms -a` 就假设平台已登录 |
| 196 | - **禁止**把失败结果悄悄吞掉,要完整透传错误 |
| 197 | |
| 198 | ## Reference Commands |
| 199 | |
| 200 | ```bash |
| 201 | # 安装 |
| 202 | npm install -g @wechatsync/cli |
| 203 | |
| 204 | # 版本检查 |
| 205 | wechatsync --version |
| 206 | |
| 207 | # 平台列表(带登录状态) |
| 208 | wechatsync platforms -a |
| 209 | |
| 210 | # 查某个平台登录状态 |
| 211 | wechatsync auth zhihu |
| 212 | |
| 213 | # 预览(dry-run,不实跑) |
| 214 | wechatsync sync article.md -p zhihu,juejin --dry-run |
| 215 | |
| 216 | # 实跑 |
| 217 | wechatsync sync article.md -p zhihu,juejin |
| 218 | |
| 219 | # 带标题和封面 |
| 220 | wechatsync sync article.md -p zhihu,juejin,wechat -t "自定义标题" --cover ./cover.png |
| 221 | |
| 222 | # 从当前浏览器页面反向抽取(不常用) |
| 223 | wechatsync extract -o out.md |
| 224 | ``` |
| 225 | |
| 226 | ## Environment Variables |
| 227 | |
| 228 | - `WECHATSYNC_TOKEN`:和 Chrome 扩展里的 Token 保持一致,**必填** |
| 229 | - `SYNC_WS_PORT`:WebSocket 端口,默认 9527,只有端口冲突时才改 |
| 230 | |
| 231 | ## Troubleshooting |
| 232 | |
| 233 | | 报错 | 原因 | 解法 | |
| 234 | |---|---|---| |
| 235 | | `已有实例正在运行但 Chrome Extension 未连接` | 扩展没开同步桥接 | 打开扩展 → 启用 MCP Connection → 确认 Token | |
| 236 | | `连接超时` | 扩展挂了 / Token 不一致 | 重启扩展,重新导出 Token,重新 `export` | |
| 237 | | `未登录 zhihu` | 当前 Chrome 没登录 | 去 zhihu.com 登录后,再跑 `wechatsync auth zhihu -r` 刷新 | |
| 238 | | `图片上传失败` | 正文外链图片拉不到 | 图片先本地化到 `assets/`,再重跑 | |
| 239 | |
| 240 | ## Workflow Position |