name: extract-excerpt
description: Use this skill to fill the excerpt field in translated Chinese Markdown articles when the article had no subtitle. Trigger on requests like "提取 excerpt", "补 excerpt", "extract excerpt", "给文章补 excerpt", or a fully-spec'd handoff prompt with slugs + target_root. This is a leaf executor—it owns the semantic judgment of "which candidate paragraph is the real opening body text" but does NOT decide paths: target_root comes from the caller. If the caller didn't provide it, stop and ask. Does not translate, does not register results into site navigation, does not orchestrate batches.
version: 3.0.0
Extract-Excerpt 文章摘要执行器
为已翻译的中文 Markdown 文章填 frontmatter 的 excerpt 字段。
业务语义:excerpt 是文章的"开篇摘要",两个来源:
- 作者写了副标题 → medium-fetch / substack-fetch 在抓取时已写入;translate 透传并译成中文。这种情况本 skill 一看 excerpt 已存在 → 跳过。
- 作者没写副标题 → 上游不写 excerpt。本 skill 从正文里挑首段、语义判断后写入 excerpt 字段。
这是一个 leaf executor skill——只负责单篇文章的 excerpt 提取与写入,不决定路径、不决定日期、不做批量调度、不翻译、不接入站点导航。这些决策属于调用方(典型是 material-pipeline)。
机械的部分(跳过标题/图片/代码块等、收集候选段落、剥离行内标记、超长截断、frontmatter 的 YAML 转义与按位插入)由 helper 脚本 excerpt-prepare.js 完成。本 skill 唯一的职责是那个语义判断:在脚本给出的候选段落里,选出真正的"开篇正文"。
调用契约
调用方在 prompt 中必须显式提供:
| 字段 | 必填 | 含义 |
|---|
slugs | 是 | 要处理的 slug 列表(≥1 条;每个 slug 对应 <target_root>/<slug>.md) |
target_root | 是 | 文章根目录绝对路径 |
max_chars | 否 | excerpt 字符长度上限,默认 200 |
overwrite | 否 | frontmatter 已有 excerpt 时是否覆盖,默认 false(跳过) |
缺 slugs 或 target_root → 停下问清楚,不要凭记忆/历史路径填默认值。max_chars / overwrite 缺省时用默认值,无需追问。
适用场景
- 调用方给出明确的
slugs + target_root
- 为翻译流水线产出的译文补
excerpt(仅对没有副标题的文章生效)
- 为存量文章批量回填
excerpt
helper 脚本
本 skill 自带 scripts/excerpt-prepare.js(仅依赖 Node 内置模块,无需 npm install),两个模式:
node <skill 目录>/scripts/excerpt-prepare.js <file> --max-chars 200
node <skill 目录>/scripts/excerpt-prepare.js <file> --write --index <n> --max-chars 200
prepare 输出形如:
{
"frontmatter": { "present": true, "hasExcerpt": false },
"candidates": [
{ "index": 1, "kind": "italic", "chars": 66, "text": "...", "truncated": null },
{ "index": 2, "kind": "plain", "chars": 76, "text": "...", "truncated": null }
]
}
frontmatter.hasExcerpt:译文是否已有 excerpt 字段。
true → 已有副标题来的 excerpt,跳过(除非调用方传 overwrite)。
false → 作者没写副标题,需要走候选段流程。
kind:plain 普通段落 / italic 整段斜体(多为导语)/ quote blockquote
truncated:超过 max_chars 时脚本预先算好的截断文本,否则 null
- 脚本只做机械跳过、不替你下结论:导语、作者注、CTA 等都会作为候选列出来,由你判断
write 模式的写入位置:插在 translated 之后、tags 之前(与 translate-verify 的 expectedOrder 对齐:title / author / url / translated / excerpt / tags)。
语义判断:怎么选候选
从 candidates 里选出第一段真正的开篇正文,跳过下列"看起来在正文位置、实则不是正文"的候选:
- 导语 / teaser:通常是
kind: italic,整段斜体、内容是对全文的概述或副标题式引导。例:cloud-ant-colonies 的候选 1 是斜体导语,应选候选 2 的正文段落。
- 作者注 / 译者说明 / 免责声明:如"作者注:本文使用合成数据……"。
- 订阅 / 付费墙 CTA:如"被防火墙挡住了?免费阅读本文……"。
- 异常开篇:订阅卡片、广告、与正文无关的导航性文字。
保留为有效正文:
kind: quote 的 blockquote 算有效正文——有些文章开篇就是引用块形式的正文/译者引言。
- 普通的第一段叙述性文字。
找不到有效正文
candidates 为空,或全部是导语/CTA/作者注一类、没有任何真正正文段落 → 不写 excerpt,在完成回复里把该 slug 记为"无有效正文"。不要硬塞导语或图注当 excerpt。
工作流程
1. 校验调用契约
读 slugs / target_root(必填)+ max_chars / overwrite(可选)。必填项缺失或 target_root 非绝对路径 → 停下问清楚。不自行扫描 target_root 决定处理哪些文件——slug 由调用方给定。
2. 逐篇处理
对每个 slug,文件路径 = <target_root>/<slug>.md:
- 跑
node <skill 目录>/scripts/excerpt-prepare.js <file> --max-chars <max_chars>
- 看
frontmatter:
present: false → 跳过该篇,记为"无 frontmatter"
hasExcerpt: true 且 overwrite = false → 跳过该篇,记为"已有副标题 excerpt"
- 按「语义判断」从
candidates 选出开篇正文的 index;选不出 → 记为"无有效正文",跳过
- 跑
node <skill 目录>/scripts/excerpt-prepare.js <file> --write --index <选中 index> --max-chars <max_chars>(如需覆盖加 --overwrite)
- 脚本会自动取该候选(超长则用预算好的截断文本)、做 YAML 转义、按位插入或替换 frontmatter 的
excerpt 行
通常无需 Read 整篇文章——prepare 输出的候选清单已经够做语义判断。只有候选都不对、怀疑脚本误跳了正文时,才 Read 原文复核。
3. 自检
确认每篇 excerpt 已写入、是纯文本、长度 ≤ max_chars、正文未被改动(脚本只动 frontmatter)。
完成回复要求
- 每个 slug 的处理结果:✓ 已写入(附 excerpt 文本与字数)/ · 已有副标题 excerpt 跳过 / · 无 frontmatter 跳过 / ⚠ 无有效正文
- 汇总:成功 N 篇 / 跳过 M 篇 / 无内容 K 篇
这个 skill 不做的事
- 不决定路径 / 日期——
target_root 必须由调用方提供
- 不挑选文件——
slugs 由调用方给定,不自行扫目录
- 不翻译——只处理已是中文的文章
- 不改正文——只往 frontmatter 加
excerpt 一个字段
- 不动其它 frontmatter 字段——title / author / url / translated / tags 原样保留
- 不写
_meta.json / 不接入站点导航——excerpt 同步进站点 _meta.json 由 material-pipeline 负责:日更流水线在 publish 步骤自动写入,存量 backfill 用 sync-meta.js
- 不做批量调度——一次调用处理传入的 slug 列表;多 agent 并行由编排者决策
- 不修改 medium-sub / medium-fetch / translate / material-pipeline 的脚本(
scripts/excerpt-prepare.js 是本 skill 自带的 helper,可与本 skill 一起演进)