wjs-syndicating-articles
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesewjs-syndicating-articles
wjs-syndicating-articles
每天把最新一篇还没分发过的公众号文章,扇出(syndicate)到各社交平台。一套文案走天下,有 API 的真发,没 API 的备好待发件箱让你手动粘。
每天把最新一篇还没分发过的公众号文章,分发(syndicate)到各社交平台。一套文案走天下,有API的平台自动发布,没有API的平台备好待发件箱供你手动粘贴。
Core Principles
核心原则
- 稳定第一:每个平台是独立步骤,一个失败绝不影响其它。
- 幂等去重:按
state/history.jsonl记录;重复跑只补发没成功的,永不重复发。(slug, platform) - 凭证降级:API 平台缺/过期凭证 → 自动转 outbox(手动),不报错。
- 署名 / CTA 用「王建硕」(用户全局偏好),不写营销腔、不堆 hashtag/@/emoji(除非原文有)。
- 稳定第一:每个平台的操作是独立步骤,一个平台失败绝不影响其他平台。
- 幂等去重:按
state/history.jsonl记录分发情况;重复运行只会补发未成功的内容,绝不会重复发布。(slug, platform) - 凭证降级:API平台缺少/过期凭证时→自动转为待发件箱(手动发布),不会报错。
- 署名 / CTA 使用「王建硕」(用户全局偏好),不写营销话术、不堆砌 hashtag/@/emoji(除非原文已有)。
Inputs
调用指令
/wjs-syndicating-articles # 选最新未分发文章,走完整流程(默认/定时用)
/wjs-syndicating-articles <article-folder># 显式指定文章
/wjs-syndicating-articles --open # 交互模式:打开手动平台 web 页 + 文案进剪贴板
/wjs-syndicating-articles --dry-run # 只草拟,不发、不写 history
/wjs-syndicating-articles --mark <slug> <platform> # 手动标记某平台已发SKILL_DIR = ~/.claude/skills/wjs-syndicating-articles/wjs-syndicating-articles # 选择最新未分发文章,执行完整流程(默认/定时任务使用)
/wjs-syndicating-articles <article-folder># 显式指定要分发的文章文件夹
/wjs-syndicating-articles --open # 交互模式:打开手动平台的网页发布界面 + 将文案复制到剪贴板
/wjs-syndicating-articles --dry-run # 仅生成草稿,不发布、不记录分发历史
/wjs-syndicating-articles --mark <slug> <platform> # 手动标记某篇文章已在指定平台发布SKILL_DIR = ~/.claude/skills/wjs-syndicating-articlesWorkflow (default / scheduled run)
工作流程(默认/定时运行)
Step 0: --mark short-circuit
步骤0:--mark 短路逻辑
若调用是 : 然后告诉用户已标记,结束。
--mark <slug> <platform>bash $SKILL_DIR/scripts/history.sh record <slug> <platform> posted若调用指令为 :执行 后告知用户已标记完成,流程结束。
--mark <slug> <platform>bash $SKILL_DIR/scripts/history.sh record <slug> <platform> postedStep 1: 选文章
步骤1:选择文章
bash
bash $SKILL_DIR/scripts/pick-next-article.sh- 显式指定了 则跳过此脚本,直接用它。
<article-folder> - 输出为空 → 最近文章都分发完了,今天 rest day,结束。
- 记 ,
FOLDER。SLUG=$(basename "$FOLDER")
bash
bash $SKILL_DIR/scripts/pick-next-article.sh- 若显式指定了 ,则跳过此脚本,直接使用指定的文件夹。
<article-folder> - 若脚本输出为空→最近的文章已全部分发完成,今日无需操作,流程结束。
- 记录 ,
FOLDER。SLUG=$(basename "$FOLDER")
Step 2: 抽一套核心文案(你来做,不是脚本)
步骤2:提取核心文案(由你执行,而非脚本)
读 和 。抽出一段最 quotable 的核心句/小段,≤120 字(保证塞进 X 的 280 字符;中文每字算 2),保留王建硕语气。再加一行软 CTA + 文章链接(公众号链接,没有就用 里信息+ )。
$FOLDER/article.md$FOLDER/meta.jsonmeta.jsonarticle_url_base把最终文案写进 (先 )。。
$SKILL_DIR/outbox/<date>-<SLUG>/post.txtmkdir -p<date>=$(date +%F)--dry-run读取 和 。提取一段最适合引用的核心语句/小段,≤120字(确保能容纳进X的280字符限制;中文每个字按2字符计算),保留王建硕的语气风格。再添加一行软CTA + 文章链接(优先使用公众号链接,若无则使用 中的信息 + )。
$FOLDER/article.md$FOLDER/meta.jsonmeta.jsonarticle_url_base将最终文案写入 (需先执行 创建目录)。。
$SKILL_DIR/outbox/<date>-<SLUG>/post.txtmkdir -p<date>=$(date +%F)若使用 参数:打印post.txt内容 + 各平台的“待发布内容”,不继续执行步骤3及以后,流程结束。
--dry-runStep 3: API 平台(逐个 try/catch,真发)
步骤3:API平台发布(逐个尝试捕获异常,真实发布)
对 各跑一次(按 config 里 mode==api 的):
x bluesky threads linkedinbash
undefined对 逐个执行(仅处理config中mode==api的平台):
x bluesky threads linkedinbash
undefined先去重:tweeting skill 也可能发过 X
先去重:tweeting skill 可能已发布过X平台内容
if [[ "$P" == "x" ]]; then
TW_HIST="$HOME/.claude/skills/wjs-tweeting-from-articles/state/history.jsonl"
if [[ -f "$TW_HIST" ]] && jq -e --arg s "$SLUG" 'select(.slug==$s and .status=="posted")' "$TW_HIST" >/dev/null 2>&1; then
bash $SKILL_DIR/scripts/history.sh record "$SLUG" x skipped; continue
fi
fi
if bash $SKILL_DIR/scripts/history.sh has "$SLUG" "$P"; then continue; fi # already done
OUT="$(bash $SKILL_DIR/scripts/post-$P.sh "$POST_TXT")"; CODE=$?
case $CODE in
0) URL="$(echo "$OUT" | sed -n 's/^url=//p')"; PID="$(echo "$OUT" | sed -n 's/^post_id=//p')"
bash $SKILL_DIR/scripts/history.sh record "$SLUG" "$P" posted "$URL" "$PID" ;;
3) bash $SKILL_DIR/scripts/history.sh record "$SLUG" "$P" queued "" "" no_creds ;; # degrade -> outbox
*) bash $SKILL_DIR/scripts/history.sh record "$SLUG" "$P" failed ;; # retry next run
esac
undefinedif [[ "$P" == "x" ]]; then
TW_HIST="$HOME/.claude/skills/wjs-tweeting-from-articles/state/history.jsonl"
if [[ -f "$TW_HIST" ]] && jq -e --arg s "$SLUG" 'select(.slug==$s and .status=="posted")' "$TW_HIST" >/dev/null 2>&1; then
bash $SKILL_DIR/scripts/history.sh record "$SLUG" x skipped; continue
fi
fi
if bash $SKILL_DIR/scripts/history.sh has "$SLUG" "$P"; then continue; fi # 已发布过,跳过
OUT="$(bash $SKILL_DIR/scripts/post-$P.sh "$POST_TXT")"; CODE=$?
case $CODE in
0) URL="$(echo "$OUT" | sed -n 's/^url=//p')"; PID="$(echo "$OUT" | sed -n 's/^post_id=//p')"
bash $SKILL_DIR/scripts/history.sh record "$SLUG" "$P" posted "$URL" "$PID" ;;
3) bash $SKILL_DIR/scripts/history.sh record "$SLUG" "$P" queued "" "" no_creds ;; # 降级为待发件箱
*) bash $SKILL_DIR/scripts/history.sh record "$SLUG" "$P" failed ;; # 下次运行时重试
esac
undefinedStep 4: 手动平台 → 待发件箱
步骤4:手动平台→待发件箱
bash
OUTBOX="$SKILL_DIR/outbox/$(date +%F)-$SLUG"
bash $SKILL_DIR/scripts/build-outbox.sh "$FOLDER" "$POST_TXT" "$OUTBOX"
for P in facebook xiaohongshu jike zhihu; do
bash $SKILL_DIR/scripts/history.sh has "$SLUG" "$P" || bash $SKILL_DIR/scripts/history.sh record "$SLUG" "$P" queued
done(degrade 到 outbox 的 API 平台同理已在 history 记为 queued;它们的文案就在同一个 OPEN.md 里。)
bash
OUTBOX="$SKILL_DIR/outbox/$(date +%F)-$SLUG"
bash $SKILL_DIR/scripts/build-outbox.sh "$FOLDER" "$POST_TXT" "$OUTBOX"
for P in facebook xiaohongshu jike zhihu; do
bash $SKILL_DIR/scripts/history.sh has "$SLUG" "$P" || bash $SKILL_DIR/scripts/history.sh record "$SLUG" "$P" queued
done(降级到待发件箱的API平台同样会在历史记录中标记为queued;它们的文案会放在同一个OPEN.md文件中。)
Step 5: 通知 + 汇总
步骤5:通知 + 汇总
打印一张表:每个平台 status(posted+URL / queued(outbox) / failed / skipped)。
无人值守(定时)跑:发一条 PushNotification,例:「✅ X、Bluesky 已发;📋 Facebook/小红书/即刻/知乎 在 outbox 待粘:$OUTBOX」。
不要在 Step 5 自动开浏览器——那是 的事。
--open打印一张状态表:每个平台的分发状态(已发布+链接 / 待发(待发件箱) / 发布失败 / 已跳过)。
无人值守(定时任务)运行时:发送一条PushNotification,示例:「✅ X、Bluesky 已发布;📋 Facebook/小红书/即刻/知乎 待粘贴发布,待发件箱路径:$OUTBOX」。
不要在步骤5自动打开浏览器——这是模式的功能。
--open--open mode(交互,发手动平台时)
--open模式(交互模式,用于手动发布平台)
- 找到今天的 outbox:(或最新一个)。
$SKILL_DIR/outbox/$(date +%F)-<SLUG> - (文案进剪贴板)。
cat OUTBOX/post.txt | pbcopy - 用 skill 打开 config 里 facebook、jike、zhihu 的
/browse。web_compose - 小红书:(Finder 弹出),提示用户 AirDrop 到手机、文案已在剪贴板。
open "$OUTBOX/image.png" - 逐个提示:粘贴 → 发布。用户发完某个可 。
--mark <slug> <platform>
- 找到今日的待发件箱:(或最新的待发件箱)。
$SKILL_DIR/outbox/$(date +%F)-<SLUG> - 执行 (将文案复制到剪贴板)。
cat OUTBOX/post.txt | pbcopy - 使用技能打开config中facebook、jike、zhihu的
/browse页面。web_compose - 小红书:执行(弹出Finder窗口),提示用户通过AirDrop传到手机、文案已在剪贴板。
open "$OUTBOX/image.png" - 逐个提示:粘贴文案 → 发布。用户发布完成某个平台后可使用标记已发布。
--mark <slug> <platform>
File Layout
文件结构
$SKILL_DIR/
├── SKILL.md config.json secrets.json(gitignored)
├── scripts/ lib.sh history.sh pick-next-article.sh post-*.sh build-outbox.sh
├── outbox/<date>-<slug>/ post.txt image.png OPEN.md
└── state/history.jsonl$SKILL_DIR/
├── SKILL.md config.json secrets.json(gitignored)
├── scripts/ lib.sh history.sh pick-next-article.sh post-*.sh build-outbox.sh
├── outbox/<date>-<slug>/ post.txt image.png OPEN.md
└── state/history.jsonl配置 API 平台(可选,配了才真发)
配置API平台(可选,配置后才会自动发布)
拷 → ,按需填 bluesky / threads / linkedin。不填的平台自动走 outbox。
secrets.json.examplesecrets.json复制 → ,按需填写bluesky / threads / linkedin的凭证。未配置的平台自动转为待发件箱模式。
secrets.json.examplesecrets.jsonDaily 自动化
每日自动化设置
/schedule daily 10:00 /wjs-syndicating-articles/schedule daily 10:00 /wjs-syndicating-articles