import assert from 'node:assert/strict' import { existsSync, readFileSync } from 'node:fs' import { renderToStaticMarkup } from 'react-dom/server' import { closeWorkbenchTab, collectWorkbenchArtifacts, emptyWorkbenchSession, openWorkbenchTab, reorderWorkbenchTabs, workbenchOwner, type WorkbenchTab } from '../src/renderer/src/workbuddy/workbench/workbench-state' import { useWorkbenchStore } from '../src/renderer/src/stores/workbench' import { useChatStore } from '../src/renderer/src/stores/chat' import { useSettingsStore } from '../src/renderer/src/stores/settings' import { SourceWorkbench } from '../src/renderer/src/workbuddy/workbench/SourceWorkbench' import { BrowserEntryIcon, CloseIcon } from '../src/renderer/src/workbuddy/workbench/SourceWorkbenchIcons' import { WorkbenchFileIcon } from '../src/renderer/src/workbuddy/workbench/WorkbenchFileIcon' import { convertWorkBuddyJsonl } from '../src/shared/workbuddy-import' import type { WorkspaceResource } from '../src/shared/resources' async function main() { const tab = (id: string, kind: WorkbenchTab['kind'] = 'file'): WorkbenchTab => ({ id, kind, label: id, owner: 'a' }) let state = openWorkbenchTab(emptyWorkbenchSession(), tab('blank', 'newTab')) state = openWorkbenchTab(state, tab('file-a')) assert.deepEqual(state.tabs.map(item => item.id), ['file-a'], 'replace the active blank tab in place') state = openWorkbenchTab(state, tab('file-b')) state = openWorkbenchTab(state, tab('file-c')) state = openWorkbenchTab(state, tab('file-b')) assert.equal(state.tabs.length, 3, 'repeat file selection reuses its tab') state = closeWorkbenchTab(state, 'file-b') assert.equal(state.activeTabId, 'file-c', 'closing active selects its right neighbor') state = reorderWorkbenchTabs(state, ['file-c', 'missing', 'file-c']) assert.deepEqual(state.tabs.map(item => item.id), ['file-c', 'file-a']) assert.equal(state.recent[0].id, 'file-b') assert.notEqual(workbenchOwner(null, 1), workbenchOwner(null, 2)) let resolveA!: (resource: WorkspaceResource) => void, resolveOld!: (resource: WorkspaceResource) => void const requests: Array<{ path: string; sessionId?: string }> = [] let aReads = 0 ;(globalThis as any).window = { ycode: { resources: { read: (path: string, _range: unknown, sessionId?: string) => { requests.push({ path, sessionId }) if (sessionId === 'a') return new Promise(resolve => { if (aReads++ === 0) resolveOld = resolve; else resolveA = resolve }) return Promise.resolve({ kind: 'text', path, name: 'b', content: 'B', firstLine: 1, totalLines: 1, truncated: false }) } } } } const api = useWorkbenchStore.getState() const old = api.openResource('a', 'a', 'C:\\space\\file.txt') const newer = api.openResource('a', 'a', 'c:/space/file.txt') await api.openResource('b', 'b', 'C:/space/file.txt') resolveA({ kind: 'text', path: 'c:/space/file.txt', name: 'latest', content: 'LATEST', firstLine: 1, totalLines: 1, truncated: false }) await newer resolveOld({ kind: 'text', path: 'C:/space/file.txt', name: 'old', content: 'STALE', firstLine: 1, totalLines: 1, truncated: false }) await old assert.equal(api.sessions.a, undefined, 'state snapshots are immutable') const bucketA = useWorkbenchStore.getState().sessions.a, bucketB = useWorkbenchStore.getState().sessions.b assert.equal(bucketA.tabs.length, 1) assert.equal(bucketA.tabs[0].label, 'latest') assert.equal(bucketB.tabs[0].label, 'b') assert.deepEqual(requests.map(request => request.sessionId), ['a', 'a', 'b']) api.openView('a', 'fileTree'); api.openView('a', 'fileTree') assert.equal(useWorkbenchStore.getState().sessions.a.tabs.filter(item => item.kind === 'fileTree').length, 1) api.closeOthers('a', 'fileTree:workspace') assert.deepEqual(useWorkbenchStore.getState().sessions.a.tabs.map(item => item.kind), ['fileTree']) api.close('a', 'fileTree:workspace') assert.equal(useWorkbenchStore.getState().sessions.a.tabs.length, 0) api.ensure('a') assert.equal(useWorkbenchStore.getState().sessions.a.tabs[0].kind, 'newTab') const actualPath = '.tmp/rea-workbuddy-session-export.json' if (existsSync(actualPath)) { const evidence = JSON.parse(readFileSync(actualPath, 'utf8')) const result = convertWorkBuddyJsonl(evidence.normalized_result.file.text, { sessionId: 'workbench-copy', title: 'copy', sourceSessionId: evidence.normalized_result.session_id, evidenceId: evidence.evidence_id, sourceSha256: evidence.normalized_result.file.sha256, importedAt: 5000, branchMode: 'visible' }) const data = collectWorkbenchArtifacts(result.messages, 'C:/Users/Administrator/code/YCode') assert.equal(data.artifacts.length, 13, 'observed source new-tab list has 13 distinct presented files') assert.equal(new Set(data.artifacts.map(item => item.id)).size, 13) // Visible file identities from REA ev_d6e6920ff4e47f73a182fac5312c5f02393366a035445d18c8a6733a8c8a11ed. // JSONL gives only the shared assistant timestamp for same-turn file batches; // per-artifact update times (and the three tied items' exact order) need REA evidence. assert.deepEqual(data.artifacts.map(item => item.name).sort(), ['视觉对齐实测.md', 'ycode-home.png', 'wb-home-reference.png', 'ycode-settings.png', 'ycode-notif.png', 'ycode-shell.png', '本轮汇报与决策记录.md', 'ycode-final.png', 'ycode-empty.png', 'ycode-titlebar.png', 'ycode-ui.png', 'WorkBuddy-UI复刻可行性评估.md', 'WorkBuddy-AI-复刻可行性评估.md'].sort()) assert.ok(data.artifacts.some(item => item.name === '视觉对齐实测.md')) assert.ok(data.changes.length > 0) useChatStore.setState({ currentSessionId: 'qa', sessions: [{ id: 'qa', title: 'copy', createdAt: 1, updatedAt: 1, cwd: 'C:/Users/Administrator/code/YCode' }], messages: result.messages }) useSettingsStore.setState({ workspace: 'C:/Users/Administrator/code/YCode' }) api.openView('qa', 'newTab') const markup = renderToStaticMarkup( {}} />) assert.match(markup, /sidebar-next-main-header/) assert.match(markup, /查看工作空间/) assert.doesNotMatch(markup, /打开浏览器|打开终端/, 'missing native hosts must not promise fake success') console.log(JSON.stringify({ evidenceId: evidence.evidence_id, artifacts: data.artifacts.length, historyChangeFiles: data.changes.length })) } assert.match(renderToStaticMarkup(), /M5\.5166 4\.7555/) assert.match(renderToStaticMarkup(), /viewBox="0 0 16 16"/) assert.match(renderToStaticMarkup(), /#13B2BF/) assert.match(renderToStaticMarkup(), /#30ACFF/) const sourceCss = readFileSync('src/renderer/src/workbuddy/workbench/workbench-source.css', 'utf8') assert.match(sourceCss, /@media\s*\(prefers-reduced-motion/) assert.match(sourceCss, /@container\s*\(width<=80px\)/) console.log('Workbench tab ownership, race isolation, history projection and source-shell SSR regression passed') } void main().catch(error => { console.error(error); process.exitCode = 1 })