diff --git a/mindspace-page-tag.mjs b/mindspace-page-tag.mjs index c597dad..e3cc082 100644 --- a/mindspace-page-tag.mjs +++ b/mindspace-page-tag.mjs @@ -31,6 +31,24 @@ export function ensurePlatformBrandPageTags(html) { }); } +export function hasPlatformBrandMarker(html) { + return new RegExp( + `${MINDSPACE_PAGE_TAG_ATTR}\\s*=\\s*["']${MINDSPACE_PAGE_TAG_PLATFORM_BRAND}["']`, + 'i', + ).test(String(html ?? '')); +} + +/** Append the platform brand footer when authors omitted data-mindspace-page-tag. */ +export function ensurePlatformBrandFooter(html) { + const normalized = ensurePlatformBrandPageTags(html); + if (hasPlatformBrandMarker(normalized)) return normalized; + const footer = `

${PLATFORM_BRAND_TEXT}

`; + if (/<\/body>/i.test(normalized)) { + return normalized.replace(/<\/body>/i, `${footer}\n`); + } + return `${normalized}\n${footer}`; +} + export function prepareHtmlPageBrandMarkers(html) { return ensurePlatformBrandPageTags(html); } diff --git a/mindspace-page-tag.test.mjs b/mindspace-page-tag.test.mjs index cf989dd..c45461e 100644 --- a/mindspace-page-tag.test.mjs +++ b/mindspace-page-tag.test.mjs @@ -3,6 +3,7 @@ import test from 'node:test'; import { MINDSPACE_PAGE_TAG_ATTR, MINDSPACE_PAGE_TAG_PLATFORM_BRAND, + ensurePlatformBrandFooter, ensurePlatformBrandPageTags, normalizePlatformBrandHtml, prepareHtmlPageBrandMarkers, @@ -28,3 +29,10 @@ test('prepareHtmlPageBrandMarkers keeps existing marker', () => { const result = prepareHtmlPageBrandMarkers(html); assert.equal(result.match(new RegExp(MINDSPACE_PAGE_TAG_ATTR, 'g'))?.length, 1); }); + +test('ensurePlatformBrandFooter appends brand line when marker is missing', () => { + const html = '
content
'; + const result = ensurePlatformBrandFooter(html); + assert.match(result, /data-mindspace-page-tag="platform-brand"/); + assert.match(result, /TKMind · 智趣/); +}); diff --git a/mindspace-public-delivery.mjs b/mindspace-public-delivery.mjs index 2c366e5..5f585e7 100644 --- a/mindspace-public-delivery.mjs +++ b/mindspace-public-delivery.mjs @@ -1,6 +1,7 @@ import crypto from 'node:crypto'; import fs from 'node:fs'; import path from 'node:path'; +import { ensurePlatformBrandFooter } from './mindspace-page-tag.mjs'; const INLINE_SCRIPT_PATTERN = /]*\bsrc\b)[^>]*>([\s\S]*?)<\/script>/gi; @@ -67,6 +68,7 @@ export function decorateMindSpacePublishedHtml({ } try { + nextHtml = ensurePlatformBrandFooter(nextHtml); nextHtml = injectOgTags(nextHtml, { origin: context.origin, pageUrl: context.pageUrl, diff --git a/wechat-mp.test.mjs b/wechat-mp.test.mjs index 58c44a7..f56aeac 100644 --- a/wechat-mp.test.mjs +++ b/wechat-mp.test.mjs @@ -62,7 +62,7 @@ function inboundXml({ } function previewReadyPageHtml({ title = 'Page', subtitle = '测试页面' } = {}) { - return `${title}
${'x'.repeat(600)}
`; + return `${title}
${'x'.repeat(600)}

TKMind · 智趣

`; } function jsonEscapedPreviewReadyPageHtml(options = {}) { diff --git a/wechat/handlers/page-generate.mjs b/wechat/handlers/page-generate.mjs index 2192077..29ce593 100644 --- a/wechat/handlers/page-generate.mjs +++ b/wechat/handlers/page-generate.mjs @@ -1,6 +1,6 @@ import { buildPagePublishFailureText } from '../prompts/page-generate.mjs'; import { selectSendableHtmlArtifacts, verifyPageArtifactContent } from '../verify/page-artifact.mjs'; -import { filterSharePreviewReadyArtifacts } from '../verify/share-preview.mjs'; +import { filterSharePreviewReadyArtifacts, verifyArtifactSharePreview } from '../verify/share-preview.mjs'; export function evaluatePageGenerateSendableArtifacts({ verifiedArtifacts = [], confirmedArtifacts = [] } = {}) { const sendable = selectSendableHtmlArtifacts({ verifiedArtifacts, confirmedArtifacts }); @@ -48,10 +48,16 @@ export function resolvePageGenerateOutcome({ selectSendableHtmlArtifacts({ verifiedArtifacts, confirmedArtifacts }), ); if (previewCandidates.length === 0 && confirmedArtifacts.length > 0) { + const previewIssue = verifyArtifactSharePreview( + selectSendableHtmlArtifacts({ verifiedArtifacts, confirmedArtifacts })[0] ?? confirmedArtifacts[0], + ); return { action: 'fail', - failureText: buildPagePublishFailureText({ missingSharePreview: true }), - reason: 'missing_share_preview', + failureText: buildPagePublishFailureText({ + missingPlatformBrand: previewIssue.reason === 'missing_platform_brand', + missingSharePreview: previewIssue.reason !== 'missing_platform_brand', + }), + reason: previewIssue.reason ?? 'missing_share_preview', }; } diff --git a/wechat/prompts/page-generate.mjs b/wechat/prompts/page-generate.mjs index 684f0eb..9436931 100644 --- a/wechat/prompts/page-generate.mjs +++ b/wechat/prompts/page-generate.mjs @@ -28,7 +28,7 @@ export function buildPageGenerateAgentPrompt(intent, { wantsDocx = false } = {}) ' - ``', ' - ``', ' tag/accent/subtitle 必须与页面主题一致;有 hero 图时 cover 指向同目录 raster 图(jpg/png)。', - '6. 页脚加 `