88 lines
3.5 KiB
JavaScript
88 lines
3.5 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
const root = path.resolve(new URL('..', import.meta.url).pathname);
|
|
|
|
function read(relativePath) {
|
|
const absolutePath = path.join(root, relativePath);
|
|
assert.ok(fs.existsSync(absolutePath), `missing guarded file: ${relativePath}`);
|
|
return fs.readFileSync(absolutePath, 'utf8');
|
|
}
|
|
|
|
function assertIncludes(source, snippet, label) {
|
|
assert.ok(source.includes(snippet), `${label} must include guarded snippet: ${snippet}`);
|
|
}
|
|
|
|
function assertExcludes(source, snippet, label) {
|
|
assert.ok(!source.includes(snippet), `${label} must not regress to: ${snippet}`);
|
|
}
|
|
|
|
const useTKMindChat = read('src/hooks/useTKMindChat.ts');
|
|
assertIncludes(useTKMindChat, 'FINISH_SYNC_RETRY_DELAYS_MS', 'useTKMindChat.ts');
|
|
assertIncludes(
|
|
useTKMindChat,
|
|
'mergeConversationSnapshot(localMessages, detail.messages)',
|
|
'useTKMindChat.ts',
|
|
);
|
|
assertIncludes(useTKMindChat, 'chat-finish-sync.mjs', 'useTKMindChat.ts');
|
|
assertExcludes(
|
|
useTKMindChat,
|
|
'messagesRef.current = detail.messages;\n messageHistoryLoadedCountRef.current = detail.messages.length',
|
|
'useTKMindChat.ts Finish sync',
|
|
);
|
|
|
|
const messageTs = read('src/utils/message.ts');
|
|
assertIncludes(messageTs, 'deriveUserFacingText', 'message.ts');
|
|
assertIncludes(messageTs, 'deriveAssistantFacingText', 'message.ts');
|
|
assertIncludes(messageTs, 'chat-finish-sync.mjs', 'message.ts');
|
|
assertIncludes(
|
|
messageTs,
|
|
'deriveUserFacingText(message.metadata.displayText)',
|
|
'message.ts metadata displayText guard',
|
|
);
|
|
|
|
const conversationDisplay = read('conversation-display.mjs');
|
|
assertIncludes(conversationDisplay, 'TASK_ROUTING_HINT_RE', 'conversation-display.mjs');
|
|
assertIncludes(conversationDisplay, 'deriveUserFacingText', 'conversation-display.mjs');
|
|
assertIncludes(conversationDisplay, 'deriveAssistantFacingText', 'conversation-display.mjs');
|
|
|
|
const chatSkills = read('chat-skills.mjs');
|
|
assertIncludes(chatSkills, 'stripKnownChatSkillPrompt', 'chat-skills.mjs');
|
|
assertIncludes(chatSkills, "legacyEndMarker = '并说明后台入口与口令。'", 'chat-skills.mjs');
|
|
|
|
const chatPanel = read('src/components/ChatPanel.tsx');
|
|
assertIncludes(chatPanel, "import { VoiceInputButton } from './VoiceInputButton'", 'ChatPanel.tsx');
|
|
assertIncludes(chatPanel, '<VoiceInputButton', 'ChatPanel.tsx');
|
|
assertIncludes(chatPanel, 'onLiveTranscript={handleVoiceLiveTranscript}', 'ChatPanel.tsx');
|
|
assertIncludes(chatPanel, 'onTranscript={handleVoiceTranscript}', 'ChatPanel.tsx');
|
|
assertIncludes(chatPanel, 'setInput(mergeVoiceText(text))', 'ChatPanel.tsx voice transcript wiring');
|
|
|
|
const voiceInputButton = read('src/components/VoiceInputButton.tsx');
|
|
assertIncludes(voiceInputButton, 'useVoiceSession({', 'VoiceInputButton.tsx');
|
|
assertIncludes(voiceInputButton, 'onTranscript?.(transcript)', 'VoiceInputButton.tsx');
|
|
|
|
const server = read('server.mjs');
|
|
assertIncludes(
|
|
server,
|
|
'attachPortalSessionRoutes(api, {',
|
|
'server.mjs session route composition',
|
|
);
|
|
const portalSessionRoutes = read('server/portal-session-routes.mjs');
|
|
assertIncludes(
|
|
portalSessionRoutes,
|
|
'canUseSnapshotCache',
|
|
'portal-session-routes.mjs',
|
|
);
|
|
assertIncludes(
|
|
portalSessionRoutes,
|
|
'hintMc != null && hintUa != null',
|
|
'portal-session-routes.mjs',
|
|
);
|
|
|
|
const publicFinishSync = read('mindspace-public-finish-sync.mjs');
|
|
assertIncludes(publicFinishSync, 'applyPublicHtmlEdit', 'mindspace-public-finish-sync.mjs');
|
|
assertIncludes(publicFinishSync, 'isEditLikeHtmlTool', 'mindspace-public-finish-sync.mjs');
|
|
|
|
console.log('chat finish sync source guards ok');
|