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"/);
});