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, '