6a88b98044
Co-authored-by: Cursor <cursoragent@cursor.com>
139 lines
4.2 KiB
JavaScript
139 lines
4.2 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* 推送今日 Agent 生成的 news002 页面到微信草稿箱(非样例 preview)。
|
||
*/
|
||
import process from 'node:process';
|
||
import mysql from 'mysql2/promise';
|
||
import { loadH5Environment } from './load-env.mjs';
|
||
import { loadWechatMpConfig } from '../wechat-mp-config.mjs';
|
||
import { createWechatNewsMorningDraftService } from '../wechat-news-morning-draft.mjs';
|
||
import { getLocalParts, normalizeTimezone } from '../schedule-time.mjs';
|
||
|
||
loadH5Environment(import.meta.dirname);
|
||
|
||
const DEFAULT_TANG_USER_ID = 'a70ff537-8908-486e-9b6c-042e07cc25db';
|
||
|
||
function buildDraftTitle(now = Date.now(), timezone = normalizeTimezone()) {
|
||
const parts = getLocalParts(now, timezone);
|
||
return `[news002] 每日新闻早报 · ${parts.year}年${parts.month}月${parts.day}日`;
|
||
}
|
||
|
||
async function ensureDraftConfig(service) {
|
||
const current = await service.getConfig();
|
||
if (current.sourceUserId && current.enabled) return current;
|
||
const userId = String(process.env.H5_WECHAT_NEWS_MORNING_DRAFT_USER_ID ?? DEFAULT_TANG_USER_ID).trim();
|
||
return service.updateConfig({
|
||
enabled: true,
|
||
sourceUserId: userId,
|
||
autoPushEnabled: current.autoPushEnabled ?? false,
|
||
autoGenerateEnabled: current.autoGenerateEnabled ?? false,
|
||
}, { updatedBy: 'news002-live-push' });
|
||
}
|
||
|
||
async function main() {
|
||
const dryRun = process.argv.includes('--dry-run');
|
||
if (!process.env.DATABASE_URL) {
|
||
console.error('DATABASE_URL missing');
|
||
process.exit(1);
|
||
}
|
||
|
||
const mpConfig = loadWechatMpConfig(process.env);
|
||
if (!mpConfig.enabled) {
|
||
console.error('微信服务号未启用');
|
||
process.exit(1);
|
||
}
|
||
|
||
const pool = mysql.createPool({ uri: process.env.DATABASE_URL, connectionLimit: 2 });
|
||
const h5Root = process.env.H5_ROOT?.trim() || process.cwd();
|
||
const service = createWechatNewsMorningDraftService(pool, {
|
||
mpConfig,
|
||
h5Root,
|
||
memindLibRoot: process.env.MEMIND_LIB_ROOT?.trim() || h5Root,
|
||
env: process.env,
|
||
logger: console,
|
||
});
|
||
|
||
const config = await ensureDraftConfig(service);
|
||
const draftTitle = buildDraftTitle();
|
||
|
||
console.log(JSON.stringify({
|
||
dryRun,
|
||
sourceUserId: config.sourceUserId,
|
||
templateId: config.templateId ?? null,
|
||
draftTitle,
|
||
h5Root,
|
||
}, null, 2));
|
||
|
||
const preview = await service.pushDraft({
|
||
dryRun: true,
|
||
requireToday: true,
|
||
triggeredBy: 'news002-live',
|
||
articleTitleOverride: draftTitle,
|
||
});
|
||
|
||
const htmlPath = preview.preview?.page?.slug
|
||
? `${h5Root}/MindSpace/${config.sourceUserId}/public/${preview.preview.page.slug}.html`
|
||
: null;
|
||
let hasMasthead = false;
|
||
let cardCount = 0;
|
||
if (htmlPath) {
|
||
try {
|
||
const fs = await import('node:fs');
|
||
const html = fs.readFileSync(htmlPath, 'utf8');
|
||
hasMasthead = html.includes('class="masthead"');
|
||
cardCount = (html.match(/data-event-key=/g) ?? []).length;
|
||
} catch {
|
||
// ignore
|
||
}
|
||
}
|
||
|
||
console.log('\n[preview]');
|
||
console.log(JSON.stringify({
|
||
pageSlug: preview.preview?.page?.slug ?? null,
|
||
pageUrl: preview.preview?.page?.publicUrl ?? null,
|
||
title: preview.preview?.article?.title ?? null,
|
||
contentLength: preview.preview?.article?.content?.length ?? 0,
|
||
hasMasthead,
|
||
eventKeyCount: cardCount,
|
||
}, null, 2));
|
||
|
||
if (!hasMasthead) {
|
||
console.error('\n[blocked] 今日页面仍是 news001 或尚未生成 news002(缺少 .masthead)');
|
||
await pool.end();
|
||
process.exit(2);
|
||
}
|
||
|
||
if (dryRun) {
|
||
console.log('\ndry-run:未调用微信 draft/add');
|
||
await pool.end();
|
||
return;
|
||
}
|
||
|
||
const result = await service.pushDraft({
|
||
requireToday: true,
|
||
triggeredBy: 'news002-live',
|
||
articleTitleOverride: draftTitle,
|
||
});
|
||
|
||
console.log('\n[success]');
|
||
console.log(JSON.stringify({
|
||
draftMediaId: result.draftMediaId,
|
||
pageSlug: result.preview?.page?.slug ?? null,
|
||
pageUrl: result.preview?.page?.publicUrl ?? null,
|
||
title: result.preview?.article?.title ?? null,
|
||
coverSource: result.cover?.source ?? null,
|
||
runId: result.run?.id ?? null,
|
||
eventKeyCount: cardCount,
|
||
}, null, 2));
|
||
|
||
await pool.end();
|
||
}
|
||
|
||
main().catch((error) => {
|
||
console.error('\n[failed]', error instanceof Error ? error.message : error);
|
||
if (error?.run) {
|
||
console.error(JSON.stringify(error.run, null, 2));
|
||
}
|
||
process.exit(1);
|
||
});
|