# 设计:TiddlyWiki 一键发布到微信公众号 - 日期:2026-09-17 - 状态:待评审 - 来源:会话调研(dsh-tiddlywiki 工作区) - 用户选定:**唤醒 agent** + **草稿 + 自动点发表(完整发布)** ## 1. 问题与约束(调研结论) ### 1.1 为什么不能走官方 API 公众号发布的服务端链路是 `access_token → draft/add → freepublish/submit`。但: - **2025 年 7 月起,官方回收「发布能力」接口对个人主体、企业未认证、不支持认证账号的调用权限**([发布能力文档](https://developers.weixin.qq.com/doc/subscription/guide/product/publish.html) 原文注)。个人主体无法做微信认证,故 `freepublish/submit` 不可用。 - 草稿箱 `draft/add` 文档未列该限制,但 48001/`api unauthorized` 是常见返回,不能假定可用。 - 即便可用,还叠加:**必须把本机公网出口 IP 加入 API IP 白名单**(否则 61004/40164)、封面 `thumb_media_id` 必须是**永久素材**、正文图片必须是 `media/uploadimg` 产出的 mmbiz 地址(外链被过滤)。 **结论:纯 API 路线对个人号不可行。** ### 1.2 为什么浏览器路线可行 后台网页端(`mp.weixin.qq.com`)的**发表/群发从未受 API 回收影响**——这是所有个人号日常发文的方式。因此「驱动后台网页」= 完整发布能力。 ### 1.3 硬约束:发表需要管理员扫码 多份实操文档一致表明:后台点「发表」后**需要公众号管理员微信扫码确认**([135编辑器流程](https://www.135editor.com/books/chapter/1/797.html):「点【发布】,扫码验证身份后文章即发布成功」)。 **这是本设计的中心约束**:不存在「完全无人值守的一键发布」。 「一键」的真实含义是——**agent 完成素材、排版、上传、填表、进草稿箱,直到人工只需扫一次码**。 另需区分两个操作(易混): | 操作 | 是否推送粉丝 | 是否占群发额度 | 扫码 | |---|---|---|---| | **发表** | 否(仅生成永久链接) | 否,不限次数 | 是 | | **群发** | 是 | 个人订阅号 1 天 1 次 | 是 | 本设计默认走**发表**(不打扰粉丝、不吃每日额度),群发作为显式可选。 ## 2. 现状与可复用资产(已实测) - 本机 `opencli` 已升级 **1.7.4 → 1.8.7**,`D:\npm-global` 下有 `puppeteer-core@24.38.0`,Chrome 位于 `C:/Program Files/Google/Chrome/Application/chrome.exe`。 - **opencli 内置 `weixin` 适配器**(`clis/weixin/`): | 命令 | 作用 | access | |---|---|---| | `weixin create-draft` | 建图文草稿 | write | | `weixin drafts` | 列草稿箱 | read | | `weixin download` / `search` | 下文章 / 搜狗微信搜索 | read | `create-draft` 走 `Strategy.COOKIE` + `mp.weixin.qq.com` 登录态:打开后台 → 从 URL 取 `token=(\d+)` → 进 `appmsg_edit_v2` → 填 `textarea#title`/`input#author`/`textarea#js_description` → 图片经 CDP `setFileInput` 上传 → 点「保存为草稿」。 - **三个缺口**(本次要补): 1. **无「发表」命令** —— 发布段需自建。 2. **正文写的是纯文本**(`execCommand('insertText')`),HTML/排版会被当字面文字。 3. 长正文走命令行位置参数,Windows 下有转义/长度风险。 ### 阻塞前提 `opencli doctor` 实测:daemon 正常(19825),但 **`[MISSING] Extension: not connected`**,Chrome 未运行。**Browser Bridge 扩展不在 npm 包里**,须从 [Chrome Web Store](https://chromewebstore.google.com/detail/opencli/ildkmabpimmkaediidaifkhjpohdnifk) 安装,或 GitHub Releases 下载 zip 后 `chrome://extensions` → 开发者模式 → 加载已解压的扩展程序。装好且 Chrome 登录 `mp.weixin.qq.com` 后方可用。 ## 3. 架构 ``` TW 笔记(Markdown,含附件图) │ ① 工具栏按钮「发布到公众号」 ▼ 发送给 Agent(复用既有链路:pick 会话 / 新建会话 → POST /agent/send) │ ② 消息体 = 发布任务指令 + 笔记正文 + 指向发布 SOP ▼ Agent 会话 │ ③ 读 [[公众号发布流程]] SOP,排版 + 选配图 + 校验 ▼ 执行 opencli(复用 Chrome 登录态,无需二次扫码) │ ④ weixin create-draft(或自建富文本版) ▼ 草稿箱 mp.weixin.qq.com │ ⑤ 自建 weixin/publish-draft:找到草稿 → 点「发表」 ▼ ⚠️ 管理员扫码确认(人工,预期内)→ 发布成功 → agent 回报链接 ``` ### 组件 | # | 组件 | 位置 | 说明 | |---|---|---|---| | 1 | 「发布到公众号」按钮 | `scripts/bundle/send-to-agent/button-publish.tid`(新) | toolbar 按钮,`message="dsh-publish-to-wechat"` | | 2 | 事件处理 | `scripts/bundle/send-to-agent/startup.js` | 新增 `dsh-publish-to-wechat` 监听,构造发布任务消息,复用现有 picker | | 3 | 发布 SOP | `src/host/seed-wechat-publish.ts`(新 seed,`dsh-docs` 标签) | 排版规范 + opencli 命令 + 扫码处理 + 失败回退;agent 读它执行 | | 4 | 发布 adapter | `~/.opencli/clis/weixin/publish-draft.js`(用户机) | 草稿箱 → 发表 → 扫码等待 → 验证;**沉淀型资产**,不进本仓库 | | 5 | 富文本正文(可选) | 自建 `weixin/create-article.js` | 用 `insertHTML` 写微信内联样式 HTML,替代纯文本 | ### 为什么按钮走「唤醒 agent」而不是主机直调 opencli - 与你既有「发送给 Agent」链路同构,**复用 picker、会话创建、消息注入**全部现成代码。 - agent 能做确定性代码做不了的事:按公众号风格改写、挑配图、检查敏感词、按需调整排版。 - 代价:每次发布消耗一次会话(可接受,发布本就是低频重活)。 ## 4. 富文本转换规范(首版即做,已确认) ### 4.0 已实测验证的结论(2026-09-17,链路已跑通) 自建 adapter `~/.opencli/clis/weixin/create-article.js` 已实跑成功,后台 `list_ex` 核对: | 实现 | 封面 | digest | |---|---|---| | 内置 `weixin create-draft` | 无 | `# 一级标题这是一段**加粗**与*斜体*测试。` ← Markdown 原样(纯文本) | | 自建 `create-article` | `mmbiz.qlogo.cn/...` | `富文本排版验证这是一段带内联样式的正文测试。…` ← **HTML 已解析** | **三个关键技术事实**(推翻/修正了本节早先的假设): 1. **正文写入用 `execCommand('insertHTML')`**——编辑器是 **ProseMirror**(非 UEditor iframe),实测内联样式完整保留。 2. **图片上传必须用 DataTransfer 注入,不能用 `page.setFileInput`**——后者依赖 CDP `Page.fileChooserOpened`,本机(CLI 1.8.7 + 扩展 v1.0.24 + Edge)稳定失败([issue #1582](https://github.com/jackwener/OpenCLI/issues/1582) 佐证版本不匹配问题)。DataTransfer 在页面上下文直接塞 `input.files` 并派发 `change`,实测图片真进 `mmbiz.qpic.cn`。代价:字节以 base64 过 evaluate,**限 8MB**。 3. **所有 weixin 命令必须带 `--trace retain-on-failure`**——否则稳定报 `Navigation rejected`(trace 开 5/5 成功,关 8/8 失败)。 其余踩坑:图片下拉必须**按文案**点「本地上传」(`items[0]` 无效);正文是最后一个 contenteditable;回读校验须**忽略所有空白**(innerText 会插空白/转 nbsp,否则假阴性);保存按钮兜底文案**不含「发表」**以防误点。 ### 4.1 微信编辑器的硬限制 | 限制 | 后果 | 对策 | |---|---|---| | `