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 { ensureWechatFreshPageThumbnailsAtWorkspace, prepareWechatHtmlDeliveryAtWorkspace, } from './mindspace-wechat-html-delivery.mjs'; function pageHtml({ title = 'Page', cover = '', } = {}) { const coverField = cover ? `,"cover":"${cover}"` : ''; return [ '', `${title}`, ``, '
', 'x'.repeat(600), '
', ].join(''); } function canonical(relativePath) { return `https://example.com/MindSpace/user-1/${relativePath}`; } test('MindSpace prepares WeChat HTML delivery with logical artifacts only', (t) => { const publishDir = fs.mkdtempSync( path.join( os.tmpdir(), 'mindspace-wechat-html-', ), ); t.after(() => { fs.rmSync(publishDir, { recursive: true, force: true, }); }); const content = pageHtml({ title: 'Hello', }); const result = prepareWechatHtmlDeliveryAtWorkspace({ publishDir, buildCanonicalUrl: canonical, requestStartedAt: Date.now() - 100, reply: { text: '页面完成:https://wrong.example/MindSpace/user-1/public/hello.html', messages: [ { id: 'assistant-1', role: 'assistant', content: [ { type: 'toolRequest', toolCall: { value: { name: 'write_file', arguments: { path: 'public/hello.html', content, }, }, }, }, ], }, ], }, intent: { agentText: '生成 public/hello.html', }, }); const written = fs.readFileSync( path.join( publishDir, 'public', 'hello.html', ), 'utf8', ); assert.match(written, /name="description"/); assert.match(written, /data-mindspace-page-tag="platform-brand"/); assert.equal( result.confirmedArtifacts.length, 1, ); assert.deepEqual( result.confirmedArtifacts[0], { relativePath: 'public/hello.html', url: canonical('public/hello.html'), canonicalUrl: canonical('public/hello.html'), exists: true, isStub: false, isHtmlDocument: true, sharePreview: { ok: true, reason: null, }, auxiliary: false, sizeBytes: Buffer.byteLength(written), }, ); assert.equal( Object.hasOwn( result.confirmedArtifacts[0], 'localPath', ), false, ); assert.equal(result.hasValidReplyLink, true); assert.deepEqual(result.validReplyUrls, [ 'https://wrong.example/MindSpace/user-1/public/hello.html', ]); }); test('MindSpace copies a generated root HTML file into public before delivery', (t) => { const publishDir = fs.mkdtempSync( path.join( os.tmpdir(), 'mindspace-wechat-root-html-', ), ); t.after(() => { fs.rmSync(publishDir, { recursive: true, force: true, }); }); fs.writeFileSync( path.join(publishDir, 'guide.html'), pageHtml({ title: 'Guide' }), 'utf8', ); const result = prepareWechatHtmlDeliveryAtWorkspace({ publishDir, buildCanonicalUrl: canonical, reply: { text: 'done', messages: [ { role: 'assistant', content: [ { type: 'toolRequest', toolCall: { value: { name: 'developer', arguments: { action: 'write', path: 'guide.html', }, }, }, }, ], }, ], }, intent: { agentText: '生成 guide.html', }, allowRecentArtifacts: false, }); assert.equal( fs.existsSync( path.join( publishDir, 'public', 'guide.html', ), ), true, ); assert.equal( result.publishedArtifacts[0] .relativePath, 'public/guide.html', ); }); test('MindSpace verifies and renders fresh WeChat page thumbnails without returning paths', async (t) => { const publishDir = fs.mkdtempSync( path.join( os.tmpdir(), 'mindspace-wechat-thumbnail-', ), ); t.after(() => { fs.rmSync(publishDir, { recursive: true, force: true, }); }); const relativePath = 'public/fresh.html'; const htmlPath = path.join(publishDir, relativePath); fs.mkdirSync(path.dirname(htmlPath), { recursive: true, }); fs.writeFileSync( htmlPath, pageHtml({ title: 'Fresh', cover: 'fresh.png', }), 'utf8', ); const result = await ensureWechatFreshPageThumbnailsAtWorkspace( { publishDir, buildCanonicalUrl: canonical, artifacts: [ { relativePath, exists: true, }, ], images: [ { jobId: 'job-1', purpose: 'hero', mimeType: 'image/png', htmlSrc: 'fresh.png', }, ], }, ); assert.equal(result.ok, true); assert.deepEqual( result.matchRelativePaths, [relativePath], ); assert.deepEqual( result.thumbnailRelativePaths, ['public/fresh.thumbnail.svg'], ); assert.equal( fs.existsSync( path.join( publishDir, 'public', 'fresh.thumbnail.svg', ), ), true, ); assert.equal( JSON.stringify(result).includes( publishDir, ), false, ); }); test('MindSpace falls back to workspace thumbnails when fresh image_make is missing', async (t) => { const publishDir = fs.mkdtempSync( path.join( os.tmpdir(), 'mindspace-wechat-thumbnail-fallback-', ), ); t.after(() => { fs.rmSync(publishDir, { recursive: true, force: true, }); }); const relativePath = 'public/fallback.html'; const htmlPath = path.join(publishDir, relativePath); fs.mkdirSync(path.dirname(htmlPath), { recursive: true }); fs.writeFileSync( htmlPath, pageHtml({ title: 'Fallback' }), 'utf8', ); const result = await ensureWechatFreshPageThumbnailsAtWorkspace({ publishDir, buildCanonicalUrl: canonical, artifacts: [{ relativePath, exists: true }], images: [], }); assert.equal(result.ok, true); assert.equal(result.reason, 'workspace_thumbnail_fallback'); assert.deepEqual(result.matchRelativePaths, [relativePath]); assert.equal( fs.existsSync(path.join(publishDir, 'public', 'fallback.thumbnail.svg')), true, ); }); test('MindSpace owns unambiguous cover repair before thumbnail delivery', async (t) => { const publishDir = fs.mkdtempSync( path.join( os.tmpdir(), 'mindspace-wechat-repair-', ), ); t.after(() => { fs.rmSync(publishDir, { recursive: true, force: true, }); }); const relativePath = 'public/repaired.html'; const htmlPath = path.join(publishDir, relativePath); fs.mkdirSync(path.dirname(htmlPath), { recursive: true, }); const original = pageHtml({ title: 'Repair', }); fs.writeFileSync( htmlPath, original, 'utf8', ); const result = await ensureWechatFreshPageThumbnailsAtWorkspace( { publishDir, buildCanonicalUrl: canonical, artifacts: [{ relativePath }], images: [ { jobId: 'job-repair', purpose: 'hero', mimeType: 'image/png', htmlSrc: 'repair.png', }, ], messages: [ { role: 'assistant', content: [ { type: 'toolRequest', toolCall: { value: { name: 'write_file', arguments: { path: relativePath, content: original, }, }, }, }, ], }, ], repairEnabled: true, }, ); assert.equal(result.ok, true); assert.equal(result.repair.ok, true); assert.equal( result.repair.relativePath, relativePath, ); assert.match( fs.readFileSync(htmlPath, 'utf8'), /repair\.png/, ); });