From f0169a97f12b0e84dc5adb6cfd2ae651af4fbc1b Mon Sep 17 00:00:00 2001 From: Johnny Huynh <27847622+johnnyhuy@users.noreply.github.com> Date: Sat, 14 Nov 2026 02:32:51 +0700 Subject: [PATCH 1/5] feat: show current Git status before resuming history Co-authored-by: OpenAI Codex --- README.md | 2 + src/renderer/App.tsx | 13 ++-- src/renderer/components/WorkspaceStatus.tsx | 9 ++- src/renderer/workbench.css | 1 + tests/e2e/workspace-status.test.ts | 71 +++++++++++++++++++-- tests/integration/WorkspaceStatus.test.tsx | 7 ++ 6 files changed, 91 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9bb33be..8738de8 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,8 @@ Session history shows source/fork relationships and an entry tree with selected Saved history includes a collapsible summary of the selected path, with the latest request and reply, message counts and tool outcomes. Unfinished tool calls carry a reminder to review the workspace before retrying. Selecting another branch or an earlier entry updates the summary. +History also shows the root's current Git branch and changed-file counts before you resume or fork. Saved history does not restore files or switch Git branches. Use **Review workspace changes** to inspect the current diff, then return to Sessions with the selected history entry and continuation draft preserved. + Use **Copy context** in History to put the selected path's Markdown handoff on the clipboard, or **Export** to save it as a file. Both include the original root, model, messages, thinking and tool input/output. Open the destination root and paste the context into a new session there. This transfers context; saved history and Resume stay with the original root. To prepare that handoff directly, select a history branch or entry and open **Continue in another root**. Choose a registered destination and **Prepare draft** to add the selected history to its new-session composer. Existing draft text is kept. Review and send it when ready. Files and session archives stay in their original root; this starts a separate session in the destination. diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index c539764..b7f73f0 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -613,13 +613,14 @@ function App() { : ''}

- b.navigate('changes')} - > - Review changes - + b.navigate('changes')} + /> {preview.tree?.warning && (

{preview.tree.warning} diff --git a/src/renderer/components/WorkspaceStatus.tsx b/src/renderer/components/WorkspaceStatus.tsx index 432d5dc..deabf7f 100644 --- a/src/renderer/components/WorkspaceStatus.tsx +++ b/src/renderer/components/WorkspaceStatus.tsx @@ -6,11 +6,13 @@ export function WorkspaceStatus({ details, ready, onReview, + context = 'new', }: { workspace: WorkspaceInfo; details: WorkspaceDetails; ready: boolean; onReview: () => void; + context?: 'new' | 'history'; }) { const unavailable = workspace.availability !== 'available'; const changes = details.changes; @@ -32,7 +34,12 @@ export function WorkspaceStatus({ return (

-

Workspace changes

+

{context === 'history' ? 'Current workspace changes' : 'Workspace changes'}

+ {context === 'history' && ( +

+ Saved history does not restore files or switch Git branches. +

+ )}

{message}

{inspected && (

diff --git a/src/renderer/workbench.css b/src/renderer/workbench.css index 42d862e..68c42b4 100644 --- a/src/renderer/workbench.css +++ b/src/renderer/workbench.css @@ -391,6 +391,7 @@ html[data-reduced-motion='true'] .wb-shell *::after { } .wb-workspace-status { display: flex; + flex-shrink: 0; align-items: center; justify-content: space-between; gap: 12px; diff --git a/tests/e2e/workspace-status.test.ts b/tests/e2e/workspace-status.test.ts index 44fa91f..033de28 100644 --- a/tests/e2e/workspace-status.test.ts +++ b/tests/e2e/workspace-status.test.ts @@ -11,15 +11,26 @@ let page: Page; let fixture: string; let project: string; let clean: string; +let source: string; +let rpcLog: string; const errors: string[] = []; const git = (cwd: string, ...args: string[]) => execFileSync('git', args, { cwd, stdio: 'pipe' }); const status = () => page.getByRole('region', { name: 'Workspace Git status' }); async function capture(name: string) { for (const directory of ['.tmp/proof', 'test-results/workspace-status']) { await fs.mkdir(path.join(ROOT, directory), { recursive: true }); - await page.screenshot({ path: path.join(ROOT, directory, name) }); + await page.screenshot({ scale: 'css', path: path.join(ROOT, directory, name) }); } } +async function resizeWindow(width: number, height: number) { + const window = await app.browserWindow(page); + await window.evaluate((window, size) => window.setContentSize(size.width, size.height), { width, height }); + const [actualWidth, actualHeight] = await window.evaluate((window) => window.getContentSize()); + await page.waitForFunction( + ({ width, height }) => innerWidth === width && innerHeight === height, + { width: actualWidth, height: actualHeight }, + ); +} async function select(name: string) { await page.getByLabel('Workspace group').selectOption({ label: name }); await page.getByRole('heading', { name: 'Start a session', exact: true }).waitFor(); @@ -33,7 +44,19 @@ describe('workspace status in Electron', () => { const plain = path.join(fixture, 'plain'); const userData = path.join(fixture, 'user-data'); await Promise.all([project, clean, plain, userData].map((dir) => fs.mkdir(dir))); - await fs.mkdir(path.join(fixture, 'sessions')); + const archives = path.join(fixture, 'sessions/workspace'); + await fs.mkdir(archives, { recursive: true }); + source = path.join(archives, 'source.jsonl'); + rpcLog = path.join(fixture, 'rpc.jsonl'); + const message = (id: string, parentId: string | null, role: string, text: string) => ({ + type: 'message', id, parentId, message: { role, content: [{ type: 'text', text }] }, + }); + await fs.writeFile(source, [ + { type: 'session', version: 3, id: 'source', cwd: project, timestamp: new Date().toISOString() }, + message('task', null, 'user', 'Review saved parser work'), + message('old-tip', 'task', 'assistant', 'The streaming approach needs review.'), + message('new-tip', 'task', 'assistant', 'The buffered approach is ready.'), + ].map((record) => JSON.stringify(record)).join('\n') + '\n'); for (const cwd of [project, clean]) { git(cwd, 'init', '-b', 'main'); await fs.writeFile(path.join(cwd, 'app.ts'), 'export const value = 1;\n'); @@ -53,11 +76,12 @@ describe('workspace status in Electron', () => { PIDEX_E2E_RENDERER_URL: inject('rendererUrl'), PIDEX_E2E_USER_DATA: userData, PIDEX_SESSIONS_ROOT: path.join(fixture, 'sessions'), PIDEX_PI: path.join(ROOT, 'tests/fixtures/pi-rpc.cjs'), + PIDEX_RPC_LOG: rpcLog, }, }); page = await app.firstWindow(); page.on('pageerror', (error) => errors.push(error.message)); - await page.setViewportSize({ width: 1440, height: 1000 }); + await resizeWindow(1280, 900); await page.getByRole('heading', { name: 'Start a session', exact: true }).waitFor(); await select('project'); }); @@ -72,14 +96,14 @@ describe('workspace status in Electron', () => { await page.getByLabel('Message pi').fill('Review the existing changes before editing.'); await page.evaluate(() => document.fonts.ready); await capture('workspace-status.png'); - await page.setViewportSize({ width: 760, height: 900 }); + await resizeWindow(900, 700); await status().scrollIntoViewIfNeeded(); const bounds = await status().boundingBox(); const button = await status().getByRole('button').boundingBox(); if (!bounds || !button) throw new Error('Workspace status is not visible.'); expect(button.x + button.width).toBeLessThanOrEqual(bounds.x + bounds.width); await capture('workspace-status-narrow.png'); - await page.setViewportSize({ width: 1440, height: 1000 }); + await resizeWindow(1280, 900); await status().getByRole('button', { name: 'Review workspace changes' }).click(); await page.getByRole('heading', { name: 'Changes review', exact: true }).waitFor(); expect(await page.getByLabel('Message pi').inputValue()).toBe('Review the existing changes before editing.'); @@ -89,6 +113,43 @@ describe('workspace status in Electron', () => { expect(await page.locator('.wb-sidebar .wb-session-item').filter({ hasText: 'this window' }).count()).toBe(0); }); + it('reviews current changes from saved history without losing the selected entry or continuation draft', async () => { + const original = await fs.readFile(source, 'utf8'); + await page.getByRole('button', { name: /^Sessions/ }).click(); + await page.getByRole('tree', { name: 'Session archives', exact: true }) + .getByRole('treeitem', { name: /Review saved parser work/ }).click(); + await page.getByLabel('Branch tip').selectOption('old-tip'); + await page.locator('.wb-transcript').getByText('The streaming approach needs review.').waitFor(); + await expect.poll(() => status().textContent()).toContain('2 changed files'); + expect(await status().textContent()).toContain('feature/workspace-status · 1 staged · 1 unstaged · 1 untracked'); + await status().getByText('Saved history does not restore files or switch Git branches.').waitFor(); + await page.getByLabel('Message pi').fill('Check the current files before continuing this branch.'); + + await resizeWindow(1280, 900); + await page.evaluate(() => document.fonts.ready); + await capture('history-workspace-status.png'); + await status().getByRole('button', { name: 'Review workspace changes' }).click(); + await page.getByRole('heading', { name: 'Changes review', exact: true }).waitFor(); + await page.getByLabel('Commit message').waitFor(); + await page.getByRole('button', { name: /^Sessions/ }).click(); + expect(await page.getByLabel('Branch tip').inputValue()).toBe('old-tip'); + expect(await page.getByLabel('Message pi').inputValue()).toBe('Check the current files before continuing this branch.'); + expect(await page.getByRole('button', { name: 'Resume in new fork', exact: true }).isEnabled()).toBe(true); + expect(await page.locator('.wb-transcript').textContent()).not.toContain('The buffered approach is ready.'); + + await fs.writeFile(path.join(project, 'notes.txt'), 'A newer edit outside the saved conversation.\n'); + git(project, 'add', 'notes.txt'); + await page.evaluate(() => window.dispatchEvent(new Event('focus'))); + await expect.poll(() => status().textContent()).toContain('2 staged · 1 unstaged · 0 untracked'); + await capture('history-workspace-status-refreshed.png'); + git(project, 'reset', '--', 'notes.txt'); + expect(await fs.readFile(source, 'utf8')).toBe(original); + expect(await fs.readFile(rpcLog, 'utf8').catch(() => '')).toBe(''); + expect(await page.locator('.wb-sidebar .wb-session-item').filter({ hasText: 'this window' }).count()).toBe(0); + expect(errors).toEqual([]); + await page.getByRole('button', { name: 'New session', exact: true }).click(); + }); + it('refreshes changed counts on focus and keeps clean and detached roots distinct', async () => { await fs.unlink(path.join(project, 'notes.txt')); git(project, 'add', 'app.ts'); diff --git a/tests/integration/WorkspaceStatus.test.tsx b/tests/integration/WorkspaceStatus.test.tsx index 1a8ed7f..48b9e48 100644 --- a/tests/integration/WorkspaceStatus.test.tsx +++ b/tests/integration/WorkspaceStatus.test.tsx @@ -14,6 +14,13 @@ const change: GitChange = { afterEach(cleanup); describe('workspace Git status', () => { + it('distinguishes current files from saved conversation history', () => { + render(); + expect(screen.getByRole('heading', { name: 'Current workspace changes' })).toBeVisible(); + expect(screen.getByText('Saved history does not restore files or switch Git branches.')).toBeVisible(); + expect(screen.getByRole('status')).toHaveTextContent('No changes in this root'); + }); + it('counts a partially staged file once overall and in both change groups', () => { const onReview = vi.fn(); render( Date: Sat, 14 Nov 2026 02:33:28 +0700 Subject: [PATCH 2/5] test: allow model discovery while checking history review Co-authored-by: OpenAI Codex --- tests/e2e/workspace-status.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/e2e/workspace-status.test.ts b/tests/e2e/workspace-status.test.ts index 033de28..1cfae7f 100644 --- a/tests/e2e/workspace-status.test.ts +++ b/tests/e2e/workspace-status.test.ts @@ -144,7 +144,9 @@ describe('workspace status in Electron', () => { await capture('history-workspace-status-refreshed.png'); git(project, 'reset', '--', 'notes.txt'); expect(await fs.readFile(source, 'utf8')).toBe(original); - expect(await fs.readFile(rpcLog, 'utf8').catch(() => '')).toBe(''); + const commands = (await fs.readFile(rpcLog, 'utf8').catch(() => '')) + .split('\n').filter(Boolean).map((line) => JSON.parse(line)); + expect(commands.every((command) => command.type === 'get_available_models')).toBe(true); expect(await page.locator('.wb-sidebar .wb-session-item').filter({ hasText: 'this window' }).count()).toBe(0); expect(errors).toEqual([]); await page.getByRole('button', { name: 'New session', exact: true }).click(); From 8a5c596af8db839983d6dcea529ef2a4d8368b2e Mon Sep 17 00:00:00 2001 From: Johnny Huynh <27847622+johnnyhuy@users.noreply.github.com> Date: Sat, 14 Nov 2026 02:41:00 +0700 Subject: [PATCH 3/5] fix: keep history Git status compact for short windows Co-authored-by: OpenAI Codex --- README.md | 2 +- src/renderer/App.tsx | 14 ++++++------ src/renderer/components/WorkspaceStatus.tsx | 24 +++++++++++++++++---- src/renderer/workbench.css | 24 +++++++++++++++++++++ tests/e2e/workspace-status.test.ts | 11 +++++++++- tests/integration/WorkspaceStatus.test.tsx | 4 +++- 6 files changed, 65 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 8738de8..f226aac 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Session history shows source/fork relationships and an entry tree with selected Saved history includes a collapsible summary of the selected path, with the latest request and reply, message counts and tool outcomes. Unfinished tool calls carry a reminder to review the workspace before retrying. Selecting another branch or an earlier entry updates the summary. -History also shows the root's current Git branch and changed-file counts before you resume or fork. Saved history does not restore files or switch Git branches. Use **Review workspace changes** to inspect the current diff, then return to Sessions with the selected history entry and continuation draft preserved. +History also shows the root's current Git branch and changed-file counts before you resume or fork. Open **Current workspace changes**, then use **Review workspace changes** to inspect the current diff. Return to Sessions with the selected history entry and continuation draft preserved. Saved history does not restore files or switch Git branches. Use **Copy context** in History to put the selected path's Markdown handoff on the clipboard, or **Export** to save it as a file. Both include the original root, model, messages, thinking and tool input/output. Open the destination root and paste the context into a new session there. This transfers context; saved history and Resume stay with the original root. diff --git a/src/renderer/App.tsx b/src/renderer/App.tsx index b7f73f0..114efc3 100644 --- a/src/renderer/App.tsx +++ b/src/renderer/App.tsx @@ -613,14 +613,14 @@ function App() { : ''}

+ b.navigate('changes')} + /> - b.navigate('changes')} - /> {preview.tree?.warning && (

{preview.tree.warning} diff --git a/src/renderer/components/WorkspaceStatus.tsx b/src/renderer/components/WorkspaceStatus.tsx index deabf7f..49fcbdf 100644 --- a/src/renderer/components/WorkspaceStatus.tsx +++ b/src/renderer/components/WorkspaceStatus.tsx @@ -31,10 +31,10 @@ export function WorkspaceStatus({ : 'No changes in this root'; const inspected = !unavailable && ready && !details.gitError; - return ( -

+ const content = ( + <>
-

{context === 'history' ? 'Current workspace changes' : 'Workspace changes'}

+ {context === 'new' &&

Workspace changes

} {context === 'history' && (

Saved history does not restore files or switch Git branches. @@ -50,6 +50,22 @@ export function WorkspaceStatus({ Review workspace changes -

+ ); + if (context === 'history') { + return ( +
+
+ + Current workspace changes + + {inspected && `${details.branch || 'Detached HEAD'} · `}{message} + + +
{content}
+
+
+ ); + } + return
{content}
; } diff --git a/src/renderer/workbench.css b/src/renderer/workbench.css index 68c42b4..d68d2c2 100644 --- a/src/renderer/workbench.css +++ b/src/renderer/workbench.css @@ -937,6 +937,30 @@ html[data-reduced-motion='true'] .wb-shell *::after { .wb-history-heading .wb-meta { margin-top: 8px; } +.wb-history-workspace-status { + flex: 0 1 280px; + min-width: 0; + max-width: 50%; + font-size: 12px; + border: 1px solid var(--line); + border-radius: 4px; +} +.wb-history-workspace-status summary { + cursor: pointer; + padding: 8px 10px; +} +.wb-history-workspace-status summary .wb-meta { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + margin-top: 4px; +} +.wb-history-workspace-status .wb-workspace-status { + border: 0; + border-top: 1px solid var(--line); + padding: 10px; +} .wb-fork-actions { display: flex; gap: 16px; diff --git a/tests/e2e/workspace-status.test.ts b/tests/e2e/workspace-status.test.ts index 1cfae7f..f722fd4 100644 --- a/tests/e2e/workspace-status.test.ts +++ b/tests/e2e/workspace-status.test.ts @@ -122,12 +122,14 @@ describe('workspace status in Electron', () => { await page.locator('.wb-transcript').getByText('The streaming approach needs review.').waitFor(); await expect.poll(() => status().textContent()).toContain('2 changed files'); expect(await status().textContent()).toContain('feature/workspace-status · 1 staged · 1 unstaged · 1 untracked'); - await status().getByText('Saved history does not restore files or switch Git branches.').waitFor(); await page.getByLabel('Message pi').fill('Check the current files before continuing this branch.'); await resizeWindow(1280, 900); await page.evaluate(() => document.fonts.ready); await capture('history-workspace-status.png'); + await status().locator('summary').click(); + await status().getByText('Saved history does not restore files or switch Git branches.').waitFor(); + await capture('history-workspace-status-expanded.png'); await status().getByRole('button', { name: 'Review workspace changes' }).click(); await page.getByRole('heading', { name: 'Changes review', exact: true }).waitFor(); await page.getByLabel('Commit message').waitFor(); @@ -141,7 +143,14 @@ describe('workspace status in Electron', () => { git(project, 'add', 'notes.txt'); await page.evaluate(() => window.dispatchEvent(new Event('focus'))); await expect.poll(() => status().textContent()).toContain('2 staged · 1 unstaged · 0 untracked'); + await status().locator('summary').click(); await capture('history-workspace-status-refreshed.png'); + await status().locator('summary').click(); + await resizeWindow(900, 600); + expect(await page.locator('.wb-transcript').evaluate((el) => el.clientHeight)).toBeGreaterThan(40); + expect(await page.evaluate(() => document.body.scrollWidth <= innerWidth)).toBe(true); + await capture('history-workspace-status-narrow.png'); + await resizeWindow(1280, 900); git(project, 'reset', '--', 'notes.txt'); expect(await fs.readFile(source, 'utf8')).toBe(original); const commands = (await fs.readFile(rpcLog, 'utf8').catch(() => '')) diff --git a/tests/integration/WorkspaceStatus.test.tsx b/tests/integration/WorkspaceStatus.test.tsx index 48b9e48..c360699 100644 --- a/tests/integration/WorkspaceStatus.test.tsx +++ b/tests/integration/WorkspaceStatus.test.tsx @@ -16,7 +16,9 @@ afterEach(cleanup); describe('workspace Git status', () => { it('distinguishes current files from saved conversation history', () => { render(); - expect(screen.getByRole('heading', { name: 'Current workspace changes' })).toBeVisible(); + expect(screen.getByText('feature/status · No changes in this root')).toBeVisible(); + expect(screen.getByRole('button', { name: 'Review workspace changes', hidden: true })).not.toBeVisible(); + fireEvent.click(screen.getByText('Current workspace changes')); expect(screen.getByText('Saved history does not restore files or switch Git branches.')).toBeVisible(); expect(screen.getByRole('status')).toHaveTextContent('No changes in this root'); }); From 21ee2c326840411ad2ef1d5f6ee30494bf20fbac Mon Sep 17 00:00:00 2001 From: Johnny Huynh <27847622+johnnyhuy@users.noreply.github.com> Date: Sat, 14 Nov 2026 02:41:59 +0700 Subject: [PATCH 4/5] fix: wrap expanded history workspace details Co-authored-by: OpenAI Codex --- src/renderer/workbench.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/workbench.css b/src/renderer/workbench.css index d68d2c2..3fadbd1 100644 --- a/src/renderer/workbench.css +++ b/src/renderer/workbench.css @@ -934,7 +934,7 @@ html[data-reduced-motion='true'] .wb-shell *::after { -webkit-line-clamp: 2; overflow: hidden; } -.wb-history-heading .wb-meta { +.wb-history-heading > div > .wb-meta { margin-top: 8px; } .wb-history-workspace-status { @@ -1728,7 +1728,7 @@ html[data-reduced-motion='true'] .wb-shell *::after { border-bottom: 1px solid #ffffff12; color: #b9c7bd; } -.wb-history-heading .wb-meta { +.wb-history-heading > div > .wb-meta { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; From 633cc4874d090b31aa9dade1039a1a51631f434d Mon Sep 17 00:00:00 2001 From: Johnny Huynh <27847622+johnnyhuy@users.noreply.github.com> Date: Sat, 14 Nov 2026 02:45:25 +0700 Subject: [PATCH 5/5] fix: preserve history reading space at minimum window height Co-authored-by: OpenAI Codex --- src/renderer/components/WorkspaceStatus.tsx | 3 +- src/renderer/workbench.css | 39 +++++++++++++++++++-- tests/integration/WorkspaceStatus.test.tsx | 4 +-- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/renderer/components/WorkspaceStatus.tsx b/src/renderer/components/WorkspaceStatus.tsx index 49fcbdf..2d7e4f5 100644 --- a/src/renderer/components/WorkspaceStatus.tsx +++ b/src/renderer/components/WorkspaceStatus.tsx @@ -59,7 +59,8 @@ export function WorkspaceStatus({ Current workspace changes - {inspected && `${details.branch || 'Detached HEAD'} · `}{message} + {inspected && {details.branch || 'Detached HEAD'}} + {inspected && ' · '}{message}
{content}
diff --git a/src/renderer/workbench.css b/src/renderer/workbench.css index 3fadbd1..8e5921a 100644 --- a/src/renderer/workbench.css +++ b/src/renderer/workbench.css @@ -920,7 +920,7 @@ html[data-reduced-motion='true'] .wb-shell *::after { } .wb-history-heading { display: flex; - align-items: center; + align-items: start; gap: 16px; } .wb-history-heading > div { @@ -950,11 +950,22 @@ html[data-reduced-motion='true'] .wb-shell *::after { padding: 8px 10px; } .wb-history-workspace-status summary .wb-meta { - display: block; + display: flex; + min-width: 0; + margin-top: 4px; +} +.wb-history-workspace-status summary .wb-meta > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - margin-top: 4px; +} +.wb-history-status-branch { + flex: 1; + min-width: 0; +} +.wb-history-workspace-status summary .wb-meta > span:last-child { + flex-shrink: 0; + max-width: 100%; } .wb-history-workspace-status .wb-workspace-status { border: 0; @@ -1880,4 +1891,26 @@ html[data-reduced-motion='true'] .wb-shell *::after { padding-bottom: 12px; gap: 8px; } + .wb-history-heading h2 { + font-size: 20px; + line-height: 24px; + } + .wb-history-heading > div > .wb-meta { + margin-top: 4px; + } + .wb-history-workspace-status summary { + padding: 6px 8px; + font-size: 11px; + } + .wb-history-conversation > .wb-branch-notice { + padding: 6px 10px; + } + .wb-history-conversation .wb-composer { + padding: 12px; + min-height: 128px; + } + .wb-history-conversation .wb-composer textarea { + height: 40px; + min-height: 40px; + } } diff --git a/tests/integration/WorkspaceStatus.test.tsx b/tests/integration/WorkspaceStatus.test.tsx index c360699..c57ce55 100644 --- a/tests/integration/WorkspaceStatus.test.tsx +++ b/tests/integration/WorkspaceStatus.test.tsx @@ -15,8 +15,8 @@ afterEach(cleanup); describe('workspace Git status', () => { it('distinguishes current files from saved conversation history', () => { - render(); - expect(screen.getByText('feature/status · No changes in this root')).toBeVisible(); + const { container } = render(); + expect(container.querySelector('summary')).toHaveTextContent('feature/status · No changes in this root'); expect(screen.getByRole('button', { name: 'Review workspace changes', hidden: true })).not.toBeVisible(); fireEvent.click(screen.getByText('Current workspace changes')); expect(screen.getByText('Saved history does not restore files or switch Git branches.')).toBeVisible();