import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import test from 'node:test'; import { injectOgTags } from '../mindspace-og-tags.mjs'; import { materializeMissingPublicHtmlWrites } from '../mindspace-public-finish-sync.mjs'; import { buildVisionPayload } from '../tkmind-proxy.mjs'; function toolMessage(name, args) { return { role: 'assistant', content: [{ type: 'toolRequest', toolCall: { value: { name, arguments: args } } }], metadata: { userVisible: true, agentVisible: true }, }; } function imagePageHtml() { return ` 晚霞城市

晚霞城市

城市艺术节 · 2026

暖金色、安静、适合移动端阅读。

`; } test('IMGPG-01..04 recorded vision/tool replay creates responsive OCR-aware ordered image page', async () => { const urls = [ 'https://m.tkmind.cn/MindSpace/user-fixture/public/images/first.jpg', 'https://m.tkmind.cn/MindSpace/user-fixture/public/images/second.jpg', ]; let observedOrder = []; const vision = await buildVisionPayload({ userId: 'user-fixture', publishLayout: { publicUrl: 'https://m.tkmind.cn/MindSpace/user-fixture/' }, userMessage: { content: [{ type: 'text', text: '按上传顺序做成暖金色响应式页面,并保留图片文字' }], metadata: { imageUrls: urls }, }, fetchImpl: async (url) => { observedOrder.push(String(url)); return new Response(Buffer.from('fixture'), { status: 200, headers: { 'Content-Type': 'image/jpeg' }, }); }, llmProviderService: { analyzeImagesWithVision: async () => '图片1是宝塔,图片2是晚霞;OCR:城市艺术节 · 2026。', }, }); assert.deepEqual(observedOrder, urls); assert.match(vision.userMessage.content[0].text, /图片1是宝塔,图片2是晚霞/); assert.match(vision.userMessage.content[0].text, /城市艺术节/); const root = fs.mkdtempSync(path.join(os.tmpdir(), 'image-page-replay-')); try { const replay = materializeMissingPublicHtmlWrites({ publishDir: root, messages: [toolMessage('write_file', { path: 'public/image-story.html', content: imagePageHtml(), })], }); assert.deepEqual(replay.materialized, ['public/image-story.html']); const html = fs.readFileSync(path.join(root, 'public/image-story.html'), 'utf8'); assert.match(html, /name="viewport"/); assert.match(html, /@media\(max-width:640px\)/); assert.ok(html.indexOf('images/first.jpg') < html.indexOf('images/second.jpg')); assert.match(html, /data-vision="ocr">城市艺术节 · 2026/); assert.match(html, /暖金色、安静/); } finally { fs.rmSync(root, { recursive: true, force: true }); } }); test('IMGPG-05..07 delivery keeps safe assets, OG/share metadata, image identity and page address', () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'image-page-delivery-')); try { const pagePath = path.join(root, 'public/image-story.html'); fs.mkdirSync(path.dirname(pagePath), { recursive: true }); fs.writeFileSync(pagePath, imagePageHtml()); const first = injectOgTags(fs.readFileSync(pagePath, 'utf8'), { origin: 'https://m.tkmind.cn', pageUrl: 'https://m.tkmind.cn/MindSpace/user-fixture/public/image-story.html', pageDirUrl: 'https://m.tkmind.cn/MindSpace/user-fixture/public/', }); fs.writeFileSync(pagePath, first); assert.match(first, /og:image/); assert.match(first, /images\/first\.jpg/); assert.doesNotMatch(first, /(?:\/Users\/|\/home\/|localhost|127\.0\.0\.1)/); const patch = materializeMissingPublicHtmlWrites({ publishDir: root, messages: [toolMessage('edit_file', { path: 'public/image-story.html', old_str: '暖金色、安静、适合移动端阅读。', new_str: '暖金色、充满活力、适合移动端阅读。', })], }); assert.deepEqual(patch.materialized, ['public/image-story.html']); const updated = fs.readFileSync(pagePath, 'utf8'); assert.match(updated, /images\/first\.jpg/); assert.match(updated, /images\/second\.jpg/); assert.match(updated, /充满活力/); } finally { fs.rmSync(root, { recursive: true, force: true }); } }); test('IMGPG-08 unreadable or unauthorized image fails closed without invented vision text', async () => { let visionCalled = false; const result = await buildVisionPayload({ userId: 'user-fixture', publishLayout: { publicUrl: 'https://m.tkmind.cn/MindSpace/user-fixture/' }, userMessage: { content: [{ type: 'text', text: '识别这张无权限图片' }], metadata: { imageUrls: ['/api/mindspace/v1/assets/denied/download?inline=1'] }, }, fetchImpl: async () => new Response('forbidden', { status: 403 }), llmProviderService: { analyzeImagesWithVision: async () => { visionCalled = true; return '不应出现的伪造识别'; }, }, }); assert.equal(visionCalled, false); assert.doesNotMatch(result?.userMessage?.content?.[0]?.text ?? '', /不应出现的伪造识别/); assert.equal(result?.billableImageCount ?? 0, 0); }); test('PAGE-11 recorded daily composite page requires every section, citations, disclosure and artifact', () => { const html = ` 每日资讯

当日新闻

国务院来源

天气

中央气象台

市场 / 股票

上交所

知识卡片

市盈率基础知识

`; const required = ['news', 'weather', 'market', 'knowledge', 'compliance']; for (const kind of required) assert.match(html, new RegExp(`data-kind="${kind}"`)); assert.equal((html.match(/href="https:\/\//g) ?? []).length, 3); assert.match(html, /不构成投资建议/); assert.match(html, /name="viewport"/); });