Install
$ agentstack add skill-zizhanovo-doubaoya-community-wechat-draft-publish ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
公众号草稿发布(都爆鸭)
本鸭帮你把一篇已经写好的图文存进你自己公众号的草稿箱——只存草稿,绝不群发/推送。存完给你一个 mediaId,你再去公众号后台亲眼确认、手动群发。
> ⚠️ 这是一个「写入」能力:跟本鸭那些只读的选题 / 搜索类技能不同,这个技能会写到你自己的公众号后台。所以它比读类技能更谨慎——只做「存草稿」这一步,最终群发的手一定在你自己。
> 走 doubaoya.com 一条线,鉴权用你自己的密钥(环境变量 DOUBAOYA_API_KEY,形如 dyh_…)。
它做什么 / 不做什么
- ✅ 把
{标题 + 公众号风格 HTML 正文}存进公众号草稿箱。 - ✅ 正文里的外链图片(``)会被自动搬运成公众号图床地址(mmbiz);个别图搬运失败会跳过,不影响整篇。
- ✅ 封面(thumb)不指定时会自动兜底一张。
- ✅ 免费能力、不扣点——存草稿这一步不消耗你的点数(写稿、生图那些能力才扣)。
- ❌ 绝不群发 / 不推送 / 不定时发——只落草稿。群发这一步永远由你在公众号后台手动完成。
- ❌ 不能替你绑定公众号——得你先在 doubaoya.com 授权。
几条要诚实告诉用户的约束
contentHtml是公众号风格的 HTML 正文(不是 markdown)。若用户给的是 markdown,先转成公众号 HTML 再发。- 正文里的外链图片(
http(s):///mmbiz)会被服务端自动搬运成公众号图床地址;个别搬运失败会被跳过、不影响整篇。 - 本地图片(`
、./a.jpg、file://…)和**本地封面**服务端读不到,直接发会被静默丢弃——必须先在客户端**预上传**再发(见下文「本地图片必须先客户端预上传」;有本地图/封面时用scripts/preprocess-and-publish.mjs`)。 - 只存草稿,绝不群发。
- 需要先在 doubaoya.com → 公众号 页面把公众号授权绑定,否则没有可发布的公众号(这一步是个 OAuth 授权,本技能做不了)。
工作流(3 步)
1. 先看有哪些已绑定的公众号
GET https://doubaoya.com/api/wechat/status
Authorization: Bearer $DOUBAOYA_API_KEY
成功信封:
{
"success": true,
"requestId": "req_...",
"data": {
"accounts": [
{
"authorizerAppid": "wx1234567890abcdef",
"nickname": "本鸭运营笔记",
"headImgUrl": "https://...",
"status": "authorized",
"principalName": "某某科技有限公司",
"createdAt": "2026-06-01T..."
}
]
},
"error": null
}
> 可靠字段以 nickname / authorizerAppid 为准。
按 data.accounts 的数量决定下一步:
- 恰好 1 个 → 直接用它的
authorizerAppid。 - 多个 → 把
{nickname, authorizerAppid}列给用户,问他发哪个,别替他猜。 - 0 个 → 告诉用户:先去 doubaoya.com → 公众号 页面把公众号授权绑定,本技能没法替他绑。
2. 存草稿
POST https://doubaoya.com/api/wechat/publish
Authorization: Bearer $DOUBAOYA_API_KEY
Content-Type: application/json
{
"authorizerAppid": "wx1234567890abcdef", // 必填,来自第 1 步
"title": "标题", // 必填
"contentHtml": "公众号风格 HTML 正文", // 必填,不是 markdown
"digest": "一句话摘要" // 可选
}
可选字段还有 thumbMediaId / author / sourceUrl(都可不传)。
成功信封(注意结果键是 mediaId,驼峰,不是 media_id):
{
"success": true,
"requestId": "req_...",
"data": { "mediaId": "xxxxxxxxxxxxxxxx" },
"error": null
}
3. 报告结果
拿到 data.mediaId 后,明确告诉用户:
> 「已存入公众号草稿箱,去公众号后台确认后手动群发」,并把 mediaId 报给他。
别自作主张说「已发布 / 已推送」——它只是草稿。
⚠️ 本地图片必须先「客户端预上传」再发
服务端的 POST /api/wechat/publish 会自动把正文里的外链图片(http(s):// 与 mmbiz 图床)搬运到公众号图床——但它跑在服务器上,读不到你本机的文件。所以如果正文 HTML 里含有本地图片(例如 `、./imgs/a.jpg、file://...`),或你有一张本地封面图,直接发布会让这些图被静默丢弃。
正确做法:由能读到本机文件的客户端先把本地图片上传到公众号图床,改写 HTML 后再发布。
判定哪些是「本地图片」
扫描 contentHtml 里所有 ``,对每个唯一 src:
- 本地(需预上传):绝对路径
/Users/...、相对路径./a.jpg/../a.jpg、裸相对路径、file://...、Windows 盘符路径。 - 外链(原样保留):
http:///https://开头、data:开头、或已是公众号图床mmbiz.qpic.cn/mmbiz.qlogo.cn。这些交给服务端处理,不要动。
上传接口 POST /api/wechat/media/upload
POST {baseUrl}/api/wechat/media/upload
Authorization: Bearer $DOUBAOYA_API_KEY
Content-Type: application/json
{
"authorizerAppid": "wx1234567890abcdef", // 必填
"dataBase64": "", // 必填
"filename": "x.jpg", // 可选
"purpose": "image" // "image"(正文图)| "thumb"(封面)
}
purpose: "image"→ 返回{ "url": "https://mmbiz.qpic.cn/..." },把这个url替换正文里该本地 src 的所有出现。purpose: "thumb"→ 返回{ "mediaId": "...", "url": "..." },把mediaId作为发布时的thumbMediaId。
> 微信限制:正文图片 ≤ 1MB。 超过 1MB 的本机图片要先压缩/缩放再上传,否则接口会拒绝(信封 error.message 会是 1MB 相关中文提示)。压缩可用 sharp(若已装),或 macOS 自带的 sips: > ``bash > sips -Z 1600 --setProperty formatOptions 70 in.png --out out.jpg > ``
完整流程
- 扫
contentHtml,挑出本地图片 src。 - 逐张:读文件字节 → base64 →
POST /api/wechat/media/upload(purpose:"image")→ 用返回url替换该 src 的所有出现。 - 有本地封面:
POST .../media/upload(purpose:"thumb")→ 拿mediaId当thumbMediaId。 POST /api/wechat/publish,正文用改写后的 HTML(此时图片都是 mmbiz 外链,服务端搬运逻辑原样放过)。
一键脚本 scripts/preprocess-and-publish.mjs(Node,零依赖)
替代 publish_draft.py 用于正文含本地图 / 有本地封面的场景。只用 Node 内置模块 + 全局 fetch(需 Node ≥ 18),sharp 为可选依赖(缺失时自动回退 sips)。它一条命令走完「解析公众号 → 预上传本地图 → 改写 HTML → 发布草稿」。
# 正文含本地图片
node "$SKILL_PATH/scripts/preprocess-and-publish.mjs" \
--html article.html --title "标题"
# 带本地封面
node "$SKILL_PATH/scripts/preprocess-and-publish.mjs" \
--html article.html --title "标题" --cover cover.png --digest "一句话摘要"
# 绑定了多个公众号时指定 appid
node "$SKILL_PATH/scripts/preprocess-and-publish.mjs" \
--html a.html --title "标题" --appid wx1234567890abcdef
# 只扫描本地图、不上传不发布(自检用,不需要密钥)
node "$SKILL_PATH/scripts/preprocess-and-publish.mjs" --html a.html --dry-run
- 相对路径的图片相对正文 HTML 文件所在目录解析。
- 读
DOUBAOYA_API_KEY与DOUBAOYA_BASE_URL(默认https://doubaoya.com)自环境变量。 - 出错按信封
error.code/error.message打印中文原因,退出码非 0。
> 正文没有本地图片、也没有本地封面时,用更轻的 publish_draft.py 即可(见上文);两者可任选。
curl 速查
# 1. 看已绑定公众号
curl -sS https://doubaoya.com/api/wechat/status \
-H "Authorization: Bearer $DOUBAOYA_API_KEY"
# 2. 存草稿
curl -sS https://doubaoya.com/api/wechat/publish \
-H "Authorization: Bearer $DOUBAOYA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"authorizerAppid": "wx1234567890abcdef",
"title": "本鸭的第一篇草稿",
"contentHtml": "正文 HTML,不是 markdown。",
"digest": "一句话摘要"
}'
运行脚本 scripts/publish_draft.py
零依赖(Python 3 标准库 urllib),一条命令走完「查绑定 → 存草稿」全流程。
# 正文直接传(公众号风格 HTML)
python3 "$SKILL_PATH/scripts/publish_draft.py" \
--title "本鸭的第一篇草稿" \
--content "正文 HTML,不是 markdown。"
# 正文从文件读(推荐,长文更稳)
python3 "$SKILL_PATH/scripts/publish_draft.py" \
--title "本鸭的第一篇草稿" \
--content-file article.html \
--digest "一句话摘要"
# 绑定了多个公众号时,指定用哪个
python3 "$SKILL_PATH/scripts/publish_draft.py" \
--title "标题" --content-file article.html --appid wx1234567890abcdef
脚本行为:
- 先
GET /api/wechat/status:若恰好 1 个绑定 → 自动选用(会在 stderr 提示选了哪个);多个且没给--appid→ 列出让你重跑指定;0 个 → 提示先去绑定。 - 再
POST /api/wechat/publish,成功后打印mediaId和「已存入公众号草稿箱,去公众号后台确认后手动群发」的提醒。 - 出错时按信封
error.code/error.message打印,退出码非 0。 - 参数:
--title(必填)、--content或--content-file(二选一必填)、--appid(可选)、--digest(可选)。
拿钥匙(密钥)
- 打开 doubaoya.com → 登录
- 进 密钥中心 → 生成密钥(形如
dyh_…)
配置到环境变量(脚本只认这个):
export DOUBAOYA_API_KEY="dyh_你的密钥"
铁律:密钥绝不打印、绝不写进文件、绝不回显给用户。 脚本本身也从不输出密钥。所有请求只发往 doubaoya.com,不要把密钥带去任何其他域名。
错误处理
先看信封 success:为 true 才读 data;否则读 error.code / error.message。常见错误码:
| HTTP | error.code | 含义 | 你该怎么办 | |------|------------|------|-----------| | 401 | UNAUTHORIZED | 密钥无效 / 会话失效 | 检查 DOUBAOYA_API_KEY,去密钥中心撤销并重新生成 | | 403 | FORBIDDEN | 这个公众号不属于当前密钥背后的用户 | 说明用的是别人绑定的公众号,或密钥与绑定账号对不上——换成本人绑定该号的密钥 | | 400 | VALIDATION_ERROR | 缺 authorizerAppid / title / contentHtml | 按 message 补齐必填项 | | 502 | WECHAT_PUBLISH_FAILED / WECHAT_COVER_FAILED | 微信侧拒收 | 不要无脑重试——先读 error.message,见下节「微信侧错误码」 | | 503 | WECHAT_NOT_CONFIGURED | 平台侧公众号能力未配置 | 非用户能自解,提示这是平台配置问题,稍后再试 / 联系 doubaoya.com |
> 若 GET /api/wechat/status 的 accounts 为空 → 不是错误码问题,是还没绑定公众号:让用户先去 doubaoya.com → 公众号 页面绑定,本技能替不了他绑。
微信侧错误码(WECHAT_PUBLISH_FAILED 的真实成因)
⚠️ 502 不等于「稍后重试就好」。 绝大多数 WECHAT_PUBLISH_FAILED 是正文/参数本身不合规, 微信每次都会以同样的理由拒收——重试一百次也不会成功,只会浪费用户的时间。只有限流(45009) 是真正该重试的那一类。
服务端已经把这些码翻成中文放进 error.message(末尾附 errcode=… errmsg=… 原文,便于排障)。 请直接把 error.message 转述给用户,不要自己改写成「上游失败,请重试」。
| errcode | 含义 | 重试有用吗 | 该怎么办 | |---------|------|-----------|---------| | 45166 | 正文里有失效的公众号文章链接(mp.weixin.qq.com/s/… 指向的文章已删除或从不存在)。只要有一条,整篇草稿就建不成 | ❌ 永远不会好 | 逐条点开正文里的公众号文章链接,删掉或换成有效的。error.message 会把嫌疑链接列出来。站外链接不会触发此错误(只会被微信剥成纯文本) | | 45002 | 正文超过草稿体积上限。实测真边界是 695,000 ✅ / 700,000 ❌ 字节(UTF-8)——官方文档在这块同时写着「不超过 2kb」和「小于 1M」,两个都不对。服务端在扣点前就按 680,000 字节前置拦截(给发布时图片 URL 改写留余量),所以你通常拿到的是 VALIDATION_ERROR 而不是 45002 | ❌ | 删减正文或拆成多篇 | | 45003 | 标题超长:上限 64 个汉字(128 字节,ASCII 算 1、汉字算 2) | ❌ | 缩短标题 | | 45004 | 摘要 digest 超长:上限 120 个汉字(240 字节) | ❌ | 缩短摘要,或干脆不传让微信自动截取 | | 45110 | 作者 author 超长:上限只有 8 个汉字(16 个 ASCII 字符) | ❌ | 缩短署名 | | 40007 | 封面 media_id 无效:不属于该号 / 已删除 / 不是永久素材 | ❌ | 去掉 thumbMediaId 用默认封面,或重新上传封面拿新 id | | 45028 | 公众号草稿箱已满 | ❌ | 让用户去公众号后台清理草稿 | | 48001 | 该公众号没有草稿箱接口权限。草稿箱要求已通过微信认证的号,未认证的订阅号/服务号调不通 | ❌ | 先在公众号后台完成微信认证 | | 61023 | 授权已失效(refresh_token 过期或被解绑) | ❌ | 去 doubaoya.com → 公众号 页面重新扫码授权 | | 40164 | 服务器出口 IP 不在微信白名单 | ❌ 用户改不了 | 平台侧配置问题,联系 doubaoya.com 并附上 requestId | | 45009 | 打微信接口太频繁,被限流 | ✅ 这一类才该重试 | 等几分钟再重试 |
> 重试安全性(不会建出重复草稿)和重试有用性是两回事:同标题同正文的重试会被去重, > 所以重试不会把草稿箱搞乱;但上表里标 ❌ 的码,重试只是把同一个错误再拿一遍。
目录结构
wechat-draft-publish/
├── SKILL.md # 本文件
└── scripts/
├── publish_draft.py # 零依赖脚本(urllib):查绑定 → 存草稿(无本地图片时用)
└── preprocess-and-publish.mjs # Node 脚本:预上传本地正文图/封面 → 改写 HTML → 存草稿
关于响应里的 notice 字段
调用本 skill 对应的 doubaoya API 后,如果返回的 JSON 顶层出现 notice 字段,请把这句话原样转达给用户——这是关于本 skill 有更新的提示,不影响本次调用结果,不需要重试或改变行为。
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: zizhanovo
- Source: zizhanovo/doubaoya-community
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.