import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import {
hasRecentOwnPublicHtmlReference,
isStubPublicHtmlContent,
collectOwnPublicHtmlArtifactRefs,
collectOwnPublicHtmlRelativePaths,
materializeMissingPublicHtmlWrites,
materializePublicHtmlWritesFromSessionEvent,
syncPublicDocxDownloads,
syncPublicHtmlAfterFinish,
} from './mindspace-public-finish-sync.mjs';
const CURRENT_USER = { id: 'a6fb1e97-2b0f-447b-b138-4561d8e5c53e', username: 'john' };
test('detects a recent own public html link', () => {
const messages = [
{
role: 'assistant',
content: [
{
type: 'text',
text: '[Hello](https://m.tkmind.cn/MindSpace/a6fb1e97-2b0f-447b-b138-4561d8e5c53e/public/hello.html)',
},
],
metadata: { userVisible: true },
},
];
assert.equal(hasRecentOwnPublicHtmlReference(messages, CURRENT_USER), true);
});
test('detects a recent public html tool write hint without a full url', () => {
const messages = [
{
role: 'user',
content: [
{
type: 'toolResponse',
toolResult: {
value: {
content: [{ type: 'text', text: '已写入 public/guizhou-guide.html(862 行)' }],
},
},
},
],
metadata: { userVisible: true, displayText: '已写入 public/guizhou-guide.html(862 行)' },
},
];
assert.equal(hasRecentOwnPublicHtmlReference(messages, CURRENT_USER), true);
});
test('detects a public html tool request even when the message has no text', () => {
const messages = [
{
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'sandbox-fs__write_file',
arguments: {
path: 'public/winter-melon-soup-recipe.html',
content: '
Winter melon soup',
},
},
},
},
],
metadata: { userVisible: true },
},
];
assert.equal(hasRecentOwnPublicHtmlReference(messages, CURRENT_USER), true);
});
test('detects public html references beyond the old eight message window', () => {
const messages = [
{
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'sandbox-fs__write_file',
arguments: {
path: 'public/long-flow.html',
content: 'Long flow',
},
},
},
},
],
},
...Array.from({ length: 12 }, (_, index) => ({
role: index % 2 === 0 ? 'assistant' : 'user',
content: [{ type: 'text', text: `validation step ${index + 1}` }],
})),
];
assert.equal(hasRecentOwnPublicHtmlReference(messages, CURRENT_USER), true);
});
test('ignores other users public html links', () => {
const messages = [
{
role: 'assistant',
content: [
{
type: 'text',
text: '[Hello](https://m.tkmind.cn/MindSpace/other-user/public/hello.html)',
},
],
metadata: { userVisible: true },
},
];
assert.equal(hasRecentOwnPublicHtmlReference(messages, CURRENT_USER), false);
});
test('materializeMissingPublicHtmlWrites writes html from sandbox write_file tool calls', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
const messages = [
{
id: 'msg-public-1',
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'sandbox-fs__write_file',
arguments: {
path: 'public/summer-essay.html',
content: 'Summer',
},
},
},
},
],
metadata: { userVisible: true },
},
];
const result = materializeMissingPublicHtmlWrites({ messages, publishDir });
assert.deepEqual(result.materialized, ['public/summer-essay.html']);
assert.equal(
fs.readFileSync(path.join(publishDir, 'public/summer-essay.html'), 'utf8'),
'Summer',
);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('syncPublicHtmlAfterFinish forwards session source to workspace sync', async () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
const calls = [];
const messages = [
{
id: 'msg-public-1',
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'write_file',
arguments: {
path: 'public/session-page.html',
content: 'Session page',
},
},
},
},
],
},
];
const result = await syncPublicHtmlAfterFinish({
messages,
currentUser: CURRENT_USER,
publishDir,
sessionId: 'session-1',
syncWorkspaceAssets: async (...args) => {
calls.push(args);
},
});
assert.equal(result.synced, true);
assert.deepEqual(calls, [[
CURRENT_USER.id,
{
categoryCode: 'public',
sourceSessionId: 'session-1',
sourceMessageId: 'msg-public-1',
onlyRelativePaths: ['public/session-page.html'],
},
]]);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('syncPublicHtmlAfterFinish registers existing public html artifacts for the session', async () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
fs.mkdirSync(path.join(publishDir, 'public'), { recursive: true });
fs.writeFileSync(path.join(publishDir, 'public/123.html'), '一二三');
const calls = [];
const messages = [
{
id: 'msg-public-1',
role: 'assistant',
content: [
{
type: 'text',
text: `[一二三](https://m.tkmind.cn/MindSpace/${CURRENT_USER.id}/public/123.html)`,
},
],
},
];
const result = await syncPublicHtmlAfterFinish({
messages,
currentUser: CURRENT_USER,
publishDir,
sessionId: 'session-1',
syncWorkspaceAssets: async () => {},
registerPublicHtmlArtifacts: async (...args) => {
calls.push(args);
},
});
assert.deepEqual(result.publicHtmlRelativePaths, ['public/123.html']);
assert.deepEqual(calls, [
[
CURRENT_USER.id,
{
sessionId: 'session-1',
relativePaths: ['public/123.html'],
artifactRefs: [{ relativePath: 'public/123.html', messageId: 'msg-public-1' }],
},
],
]);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('syncPublicHtmlAfterFinish materializes private image assets into public html files', async () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-assets-'));
const publishDir = path.join(root, 'MindSpace', CURRENT_USER.id);
const storageRoot = path.join(root, 'storage');
const assetId = '55555555-5555-4555-8555-555555555555';
const storageKey = `users/${CURRENT_USER.id}/assets/${assetId}/versions/v1`;
fs.mkdirSync(path.dirname(path.join(storageRoot, storageKey)), { recursive: true });
fs.writeFileSync(path.join(storageRoot, storageKey), Buffer.from([0xff, 0xd8, 0xff, 0xd9]));
try {
fs.mkdirSync(path.join(publishDir, 'public'), { recursive: true });
fs.writeFileSync(
path.join(publishDir, 'public/tea.html'),
`
`,
);
const messages = [
{
id: 'msg-tea-1',
role: 'assistant',
content: [
{
type: 'text',
text: `[茶馆](https://m.tkmind.cn/MindSpace/${CURRENT_USER.id}/public/tea.html)`,
},
],
},
];
const pool = {
query: async () => [
[{ id: assetId, mime_type: 'image/jpeg', original_filename: 'tea.jpg', storage_key: storageKey }],
],
};
const result = await syncPublicHtmlAfterFinish({
messages,
currentUser: CURRENT_USER,
publishDir,
sessionId: 'session-tea',
pool,
storageRoot,
h5Root: root,
syncWorkspaceAssets: async () => {},
});
assert.equal(result.assetMaterialization.materialized.length, 1);
const saved = fs.readFileSync(path.join(publishDir, 'public/tea.html'), 'utf8');
assert.match(saved, /\.tmp-images\/55555555-5555-4555-8555-555555555555\.jpg/);
assert.ok(fs.existsSync(path.join(publishDir, 'public/.tmp-images', `${assetId}.jpg`)));
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
test('collectOwnPublicHtmlArtifactRefs includes source message ids when available', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
fs.mkdirSync(path.join(publishDir, 'public'), { recursive: true });
fs.writeFileSync(path.join(publishDir, 'public/own.html'), 'Own');
const refs = collectOwnPublicHtmlArtifactRefs({
publishDir,
currentUser: CURRENT_USER,
messages: [
{
id: 'assistant-msg-1',
content: [
{
type: 'text',
text: `https://m.tkmind.cn/MindSpace/${CURRENT_USER.id}/public/own.html`,
},
],
},
],
});
assert.deepEqual(refs, [{ relativePath: 'public/own.html', messageId: 'assistant-msg-1' }]);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('collectOwnPublicHtmlRelativePaths ignores missing and other-user public html links', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
fs.mkdirSync(path.join(publishDir, 'public'), { recursive: true });
fs.writeFileSync(path.join(publishDir, 'public/own.html'), 'Own');
const paths = collectOwnPublicHtmlRelativePaths({
publishDir,
currentUser: CURRENT_USER,
messages: [
{
content: [
{
type: 'text',
text: [
`https://m.tkmind.cn/MindSpace/${CURRENT_USER.id}/public/own.html`,
`https://m.tkmind.cn/MindSpace/${CURRENT_USER.id}/public/missing.html`,
'https://m.tkmind.cn/MindSpace/other-user/public/other.html',
].join('\n'),
},
],
},
],
});
assert.deepEqual(paths, ['public/own.html']);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('materializeMissingPublicHtmlWrites writes html from developer write tool calls', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
const messages = [
{
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'write',
arguments: {
path: 'public/guizhou-guide.html',
content: 'Guizhou',
},
},
},
},
],
},
];
const result = materializeMissingPublicHtmlWrites({ messages, publishDir });
assert.deepEqual(result.materialized, ['public/guizhou-guide.html']);
assert.equal(
fs.readFileSync(path.join(publishDir, 'public/guizhou-guide.html'), 'utf8'),
'Guizhou',
);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('materializeMissingPublicHtmlWrites replaces stub placeholder html', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
const stubPath = path.join(publishDir, 'public/guide.html');
fs.mkdirSync(path.dirname(stubPath), { recursive: true });
fs.writeFileSync(stubPath, '根据你的要求临时补出的简版页面', 'utf8');
assert.equal(isStubPublicHtmlContent(fs.readFileSync(stubPath, 'utf8')), true);
const messages = [
{
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'write_file',
arguments: {
path: 'public/guide.html',
content: 'Real GuideFull page',
},
},
},
},
],
},
];
const result = materializeMissingPublicHtmlWrites({ messages, publishDir });
assert.deepEqual(result.materialized, ['public/guide.html']);
assert.match(fs.readFileSync(stubPath, 'utf8'), /Real Guide/);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('syncPublicDocxDownloads copies newer complete oa docx into public download targets', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-docx-sync-'));
try {
const oaDir = path.join(publishDir, 'oa');
const publicDir = path.join(publishDir, 'public');
fs.mkdirSync(oaDir, { recursive: true });
fs.mkdirSync(publicDir, { recursive: true });
fs.writeFileSync(path.join(oaDir, 'latest-plan.docx'), 'x'.repeat(9000));
fs.writeFileSync(path.join(publicDir, 'download.html'), 'download');
fs.writeFileSync(path.join(publicDir, 'old-plan.docx'), 'stub');
const result = syncPublicDocxDownloads({ publishDir, minCompleteSize: 8000 });
assert.deepEqual(result.synced, ['public/old-plan.docx']);
assert.equal(result.source, 'latest-plan.docx');
assert.equal(fs.readFileSync(path.join(publicDir, 'old-plan.docx'), 'utf8').length, 9000);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('syncPublicDocxDownloads skips public docx that is already up to date', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-docx-sync-'));
try {
const oaDir = path.join(publishDir, 'oa');
const publicDir = path.join(publishDir, 'public');
fs.mkdirSync(oaDir, { recursive: true });
fs.mkdirSync(publicDir, { recursive: true });
fs.writeFileSync(path.join(oaDir, 'latest-plan.docx'), 'x'.repeat(9000));
fs.writeFileSync(path.join(publicDir, 'download.html'), 'download');
fs.writeFileSync(path.join(publicDir, 'old-plan.docx'), 'x'.repeat(9000));
const result = syncPublicDocxDownloads({ publishDir, minCompleteSize: 8000 });
assert.deepEqual(result.synced, []);
assert.deepEqual(result.skipped, ['public/old-plan.docx']);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('syncPublicDocxDownloads copies same-named oa docx even when it is small', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-docx-sync-'));
try {
const oaDir = path.join(publishDir, 'oa');
const publicDir = path.join(publishDir, 'public');
fs.mkdirSync(oaDir, { recursive: true });
fs.mkdirSync(publicDir, { recursive: true });
fs.writeFileSync(path.join(oaDir, 'industry-distribution-report.docx'), 'x'.repeat(3294));
fs.writeFileSync(
path.join(publicDir, 'industry-distribution-report.html'),
'download',
);
const result = syncPublicDocxDownloads({ publishDir, minCompleteSize: 1024 });
assert.deepEqual(result.synced, ['public/industry-distribution-report.docx']);
assert.deepEqual(result.missing, []);
assert.equal(result.source, 'industry-distribution-report.docx');
assert.equal(
fs.readFileSync(path.join(publicDir, 'industry-distribution-report.docx'), 'utf8').length,
3294,
);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('syncPublicDocxDownloads reports missing public docx when no safe source exists', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-docx-sync-'));
try {
const oaDir = path.join(publishDir, 'oa');
const publicDir = path.join(publishDir, 'public');
fs.mkdirSync(oaDir, { recursive: true });
fs.mkdirSync(publicDir, { recursive: true });
fs.writeFileSync(path.join(oaDir, '暑假计划.docx'), 'x'.repeat(4084));
fs.writeFileSync(path.join(oaDir, '韩国旅游攻略.docx'), 'x'.repeat(5889));
fs.writeFileSync(
path.join(publicDir, 'industry-distribution-report.html'),
'download',
);
const result = syncPublicDocxDownloads({ publishDir, minCompleteSize: 1024 });
assert.deepEqual(result.synced, []);
assert.deepEqual(result.missing, ['public/industry-distribution-report.docx']);
assert.equal(
fs.existsSync(path.join(publicDir, 'industry-distribution-report.docx')),
false,
);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('materializeMissingPublicHtmlWrites replaces existing real html when content changed', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
const htmlPath = path.join(publishDir, 'public/guide.html');
fs.mkdirSync(path.dirname(htmlPath), { recursive: true });
fs.writeFileSync(htmlPath, 'Existing', 'utf8');
const result = materializeMissingPublicHtmlWrites({
messages: [
{
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'write_file',
arguments: {
path: 'public/guide.html',
content: 'Replacement',
},
},
},
},
],
},
],
publishDir,
});
assert.deepEqual(result.materialized, ['public/guide.html']);
assert.deepEqual(result.skipped, []);
assert.match(fs.readFileSync(htmlPath, 'utf8'), /Replacement/);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('materializeMissingPublicHtmlWrites skips existing real html when content is unchanged', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
const htmlPath = path.join(publishDir, 'public/guide.html');
const html = 'Existing';
fs.mkdirSync(path.dirname(htmlPath), { recursive: true });
fs.writeFileSync(htmlPath, html, 'utf8');
const result = materializeMissingPublicHtmlWrites({
messages: [
{
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'write_file',
arguments: {
path: 'public/guide.html',
content: html,
},
},
},
},
],
},
],
publishDir,
});
assert.deepEqual(result.materialized, []);
assert.deepEqual(result.skipped, ['public/guide.html']);
assert.match(fs.readFileSync(htmlPath, 'utf8'), /Existing/);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('detects a recent edit_file tool request on an existing public html page', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
const htmlPath = path.join(publishDir, 'public/guide.html');
fs.mkdirSync(path.dirname(htmlPath), { recursive: true });
fs.writeFileSync(htmlPath, '一二三', 'utf8');
const messages = [
{
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'edit_file',
arguments: {
path: 'public/guide.html',
old_str: '一二三',
new_str: '二三四',
},
},
},
},
],
metadata: { userVisible: true },
},
];
assert.equal(hasRecentOwnPublicHtmlReference(messages, CURRENT_USER, { publishDir }), true);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('materializeMissingPublicHtmlWrites applies edit_file patches onto existing public html', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
const htmlPath = path.join(publishDir, 'public/guide.html');
fs.mkdirSync(path.dirname(htmlPath), { recursive: true });
fs.writeFileSync(htmlPath, 'Existing一二三', 'utf8');
const result = materializeMissingPublicHtmlWrites({
messages: [
{
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'edit_file',
arguments: {
path: 'public/guide.html',
old_str: '一二三',
new_str: '二三四',
},
},
},
},
],
},
],
publishDir,
});
assert.deepEqual(result.materialized, ['public/guide.html']);
assert.match(fs.readFileSync(htmlPath, 'utf8'), /二三四/);
assert.doesNotMatch(fs.readFileSync(htmlPath, 'utf8'), /一二三/);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('materializeMissingPublicHtmlWrites chains multiple edit_file patches for the same html', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-finish-sync-'));
try {
const htmlPath = path.join(publishDir, 'public/guide.html');
fs.mkdirSync(path.dirname(htmlPath), { recursive: true });
fs.writeFileSync(htmlPath, '一 · 二三', 'utf8');
const result = materializeMissingPublicHtmlWrites({
messages: [
{
role: 'assistant',
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'edit_file',
arguments: {
path: 'public/guide.html',
old_str: '一',
new_str: '二',
},
},
},
},
{
type: 'toolRequest',
toolCall: {
value: {
name: 'edit_file',
arguments: {
path: 'public/guide.html',
old_str: '二三',
new_str: '三四',
},
},
},
},
],
},
],
publishDir,
});
assert.deepEqual(result.materialized, ['public/guide.html']);
assert.match(fs.readFileSync(htmlPath, 'utf8'), /二 · 三四/);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});
test('materializePublicHtmlWritesFromSessionEvent writes public html from message event before finish', () => {
const publishDir = fs.mkdtempSync(path.join(os.tmpdir(), 'public-event-sync-'));
try {
const result = materializePublicHtmlWritesFromSessionEvent(
{
type: 'Message',
message: {
id: 'assistant-1',
role: 'assistant',
metadata: { userVisible: true },
content: [
{
type: 'toolRequest',
toolCall: {
value: {
name: 'write',
arguments: {
path: 'public/shenwu-gate.html',
content: '神口门',
},
},
},
},
],
},
},
{ publishDir },
);
assert.deepEqual(result.materialized, ['public/shenwu-gate.html']);
assert.match(
fs.readFileSync(path.join(publishDir, 'public/shenwu-gate.html'), 'utf8'),
/神口门/,
);
} finally {
fs.rmSync(publishDir, { recursive: true, force: true });
}
});