From 028bb18dc0da60178bf40838a1844cd1505084a1 Mon Sep 17 00:00:00 2001 From: john Date: Wed, 23 Sep 2026 10:07:32 +0800 Subject: [PATCH] feat(news): add single news-item page generation and early page-ready wait Scheduled tasks can finish once the expected HTML is on disk and stable, instead of waiting for Goose Finish. Adds news-item templates and scripts for generating a single-event page and committing it as a WeChat draft. Co-authored-by: Cursor --- news-item-templates.mjs | 213 ++++++++++++++++++++++++++ scheduled-task-executor.mjs | 152 +++++++++++++++++- scheduled-task-executor.test.mjs | 57 +++++++ scripts/news-item-generate-page.mjs | 128 ++++++++++++++++ scripts/news-item-wechat-commit.mjs | 79 ++++++++++ scripts/news-item-wechat-context.mjs | 220 +++++++++++++++++++++++++++ scripts/news-item-wechat-images.mjs | 184 ++++++++++++++++++++++ 7 files changed, 1029 insertions(+), 4 deletions(-) create mode 100644 news-item-templates.mjs create mode 100644 scripts/news-item-generate-page.mjs create mode 100644 scripts/news-item-wechat-commit.mjs create mode 100644 scripts/news-item-wechat-context.mjs create mode 100644 scripts/news-item-wechat-images.mjs diff --git a/news-item-templates.mjs b/news-item-templates.mjs new file mode 100644 index 0000000..fc00bce --- /dev/null +++ b/news-item-templates.mjs @@ -0,0 +1,213 @@ +/** + * 单条新闻落地页的模板契约。 + * + * 这份契约同时约束两端:Agent 按它生成 HTML,news-engine 的块解析器按它把 HTML + * 拆成可编辑的块。类名是两端唯一的接口,改动必须同步 lib/wechat-draft-blocks.mjs。 + */ + +export const NEWS_ITEM_VERSION = '2026-09-22-v4-human-voice'; + +export const NEWS_ITEM_MIN_IMAGES = 6; +export const NEWS_ITEM_MIN_SECTIONS = 5; +export const NEWS_ITEM_MIN_CHARS = 1200; + +export const NEWS_ITEM_STYLES = Object.freeze({ + 'wechat-feature': { + id: 'wechat-feature', + label: '公众号深度稿', + description: '导语 + 可选过渡 + 5~7 个小节(长短可不一,每节配图)+ 结尾编辑观点', + minImages: NEWS_ITEM_MIN_IMAGES, + minSections: NEWS_ITEM_MIN_SECTIONS, + minChars: NEWS_ITEM_MIN_CHARS, + }, + brief: { + id: 'brief', + label: '快讯图文', + description: '紧凑结构:导语 + 3~4 个小节,适合突发短讯', + minImages: 4, + minSections: 3, + minChars: 700, + }, +}); + +const BRIEF_CATEGORIES = new Set(['快讯', '突发', 'breaking']); + +export function resolveNewsItemStyle(newsItem = {}, env = process.env) { + const explicit = String(env.MEMIND_NEWS_ITEM_STYLE ?? '').trim(); + if (explicit && NEWS_ITEM_STYLES[explicit]) return explicit; + const requested = String(newsItem.layoutStyle ?? '').trim(); + if (requested && NEWS_ITEM_STYLES[requested]) return requested; + const category = String(newsItem.category ?? '').trim().toLowerCase(); + if (BRIEF_CATEGORIES.has(category)) return 'brief'; + return 'wechat-feature'; +} + +// --------------------------------------------------------------------------- +// 结构契约(写进 Agent 提示词,也是块解析器的依据) +// --------------------------------------------------------------------------- + +const STRUCTURE_CONTRACT = `【HTML 结构硬约束|类名不可改,下游要按类名解析】 +
+
+ 封面描述 +

标题

+ +
+

导语:80~140 字。从一个具体细节、问题或场景切入,不要以「近日/据报道」起笔。

+ +
+

具体的小节标题(写清本节讲什么)

+

正文段落

+
配图描述
图说
+
+ … 重复 {{MIN_SECTIONS}}~7 个 article-section,段落数可 1~5 段不等 … +
+

与题材相关的具体问题(禁止用「怎么看」「总结」)

+

2~3 段编辑判断,可出现「我们认为」「值得留意的是」。

+
+
`; + +const IMAGE_RULES = `【配图硬约束】 +1. 至少 {{MIN_IMAGES}} 张真实 :hero 1 张 + 每个 article-section 各 1 张。 +2. 先 load_skill → image-generation 生成配图,再 load_skill → static-page-publish 落盘。 +3. hero 用 hero preset;小节配图用 inline_image preset。 +4. 已有新闻原图可作为 hero 参考,但小节配图必须逐个生成,不允许复用同一张。 +5. 禁止 SVG 占位图、禁止 data: URI、禁止出现没有配图的 article-section。 +6. 必须与 hero-img 同源。`; + +const WRITING_RULES = `【写作硬约束】 +1. 正文纯文字不少于 {{MIN_CHARS}} 字(不含标签与空白)。 +2. 每个 article-section 1~5 段均可,段落长短错落;不要写成「首先/其次/最后」的要点罗列。 +3. 小节标题必须具体(写清这一节讲什么),禁止「背景」「影响」「怎么看」「总结」等空标题。 +4. 只使用