feat(wechat): require share preview meta before page link delivery

Block service-account page links when HTML lacks mindspace-cover and
description so WeChat forwards always get TKMind branding and thumbnail.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-07-04 14:00:26 +08:00
parent 031c6e086a
commit 31fb0e02cf
4 changed files with 146 additions and 3 deletions
+55
View File
@@ -14,6 +14,12 @@ import { guardScheduleConfirmationReply, looksLikeScheduleConfirmation } from '.
import { resolvePageGenerateOutcome } from './handlers/page-generate.mjs';
import { buildGreetingText, resolveSyncReply } from './handlers/sync-replies.mjs';
import { buildWechatAgentPrompt } from './prompts/chat-general.mjs';
import {
hasMindspaceCoverMeta,
hasShareDescription,
verifyArtifactSharePreview,
verifySharePreviewMeta,
} from './verify/share-preview.mjs';
test('classifyWechatIntent detects page.generate', () => {
const intent = classifyWechatIntent({
@@ -113,3 +119,52 @@ test('verifyPageArtifactContent rejects small stub files', () => {
assert.equal(verifyPageArtifactContent(artifact).ok, false);
assert.equal(filterSendableHtmlArtifacts([artifact]).length, 0);
});
function writePreviewReadyHtml(file, { withCover = true } = {}) {
const coverMeta = withCover
? '<meta name="mindspace-cover" content=\'{"tag":"旅行","accent":"#ff6b35","accent2":"#24243e","subtitle":"测试页面"}\'>'
: '';
fs.writeFileSync(
file,
`<!doctype html><html><head>
<meta name="description" content="一句话摘要">
${coverMeta}
</head><body><main>${'x'.repeat(600)}</main></body></html>`,
'utf8',
);
}
test('verifySharePreviewMeta requires mindspace-cover and description', () => {
const withBoth = '<meta name="description" content="摘要"><meta name="mindspace-cover" content=\'{"tag":"旅行"}\'>';
assert.equal(verifySharePreviewMeta(withBoth).ok, true);
assert.equal(verifySharePreviewMeta('<meta name="description" content="摘要">').ok, false);
assert.equal(hasMindspaceCoverMeta(withBoth), true);
assert.equal(hasShareDescription(withBoth), true);
});
test('resolvePageGenerateOutcome fails when html lacks share preview meta', () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'wechat-preview-'));
const file = path.join(dir, 'page.html');
writePreviewReadyHtml(file, { withCover: false });
const outcome = resolvePageGenerateOutcome({
reply: { text: '页面已生成 https://m.tkmind.cn/MindSpace/u/public/page.html' },
confirmedArtifacts: [{ localPath: file, relativePath: 'public/page.html' }],
});
assert.equal(outcome.action, 'fail');
assert.equal(outcome.reason, 'missing_share_preview');
assert.match(outcome.failureText, /预览元数据/);
});
test('resolvePageGenerateOutcome sends when share preview meta is present', () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'wechat-preview-ok-'));
const file = path.join(dir, 'page.html');
writePreviewReadyHtml(file);
const artifact = { localPath: file, relativePath: 'public/page.html' };
assert.equal(verifyArtifactSharePreview(artifact).ok, true);
const outcome = resolvePageGenerateOutcome({
reply: { text: '页面已生成' },
confirmedArtifacts: [artifact],
});
assert.equal(outcome.action, 'send');
assert.equal(outcome.artifacts.length, 1);
});