import { mkdtempSync, readFileSync, rmSync } from 'node:fs' import { tmpdir } from 'node:os' import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' import { turnController } from '../app/turnController.js' import { getTurnState, resetTurnState } from '../app/turnStore.js' import { patchUiState, resetUiState } from '../app/uiStore.js' import { hydrateLiveSessionInflight, liveSessionInflightMessages, writeActiveSessionFile } from '../app/useSessionLifecycle.js' describe('writeActiveSessionFile', () => { let dir = '' afterEach(() => { if (dir) { rmSync(dir, { force: true, recursive: true }) dir = '' } }) it('writes the actual resumed session id for the shell exit summary', () => { dir = mkdtempSync(join(tmpdir(), 'hermes-tui-active-')) const path = join(dir, 'active.json') writeActiveSessionFile('actual_session', path) expect(JSON.parse(readFileSync(path, 'utf8'))).toEqual({ session_id: 'actual_session' }) }) }) describe('live session activation in-flight state', () => { beforeEach(() => { resetUiState() resetTurnState() turnController.fullReset() patchUiState({ streaming: true }) }) it('keeps the in-flight user prompt in history and hydrates partial assistant text', () => { const inflight = { assistant: 'partial answer', streaming: true, user: 'write a long answer' } expect(liveSessionInflightMessages(inflight)).toEqual([{ role: 'user', text: 'write a long answer' }]) hydrateLiveSessionInflight(inflight) expect(turnController.bufRef).toBe('partial answer') expect(getTurnState().streaming).toBe('partial answer') }) it('ignores empty in-flight payloads', () => { expect(liveSessionInflightMessages({ assistant: '', streaming: false, user: ' ' })).toEqual([]) hydrateLiveSessionInflight({ assistant: '', streaming: false, user: '' }) expect(turnController.bufRef).toBe('') expect(getTurnState().streaming).toBe('') }) })