mirror of
https://github.com/wu736139669/hapi.git
synced 2026-10-26 22:30:50 +00:00
refactor(codex): extract session management and launcher logic into separate modules
Reorganized runCodex.ts to improve maintainability by extracting: - CodexSession class for session lifecycle management - CodexLocalLauncher and CodexRemoteLauncher for mode-specific initialization - CodexEventConverter for MCP message handling and UI buffer updates - CodexSessionScanner for resume file discovery - emitReadyIfIdle utility for ready event emission Added codexSessionId field to metadata schema for session tracking. Updated UI components to work with refactored architecture.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
import { mkdir, writeFile, appendFile, rm } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { createCodexSessionScanner } from './codexSessionScanner';
|
||||
import type { CodexSessionEvent } from './codexEventConverter';
|
||||
|
||||
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
describe('codexSessionScanner', () => {
|
||||
let testDir: string;
|
||||
let sessionsDir: string;
|
||||
let sessionFile: string;
|
||||
let originalCodexHome: string | undefined;
|
||||
let scanner: Awaited<ReturnType<typeof createCodexSessionScanner>> | null = null;
|
||||
let events: CodexSessionEvent[] = [];
|
||||
|
||||
beforeEach(async () => {
|
||||
testDir = join(tmpdir(), `codex-scanner-${Date.now()}`);
|
||||
sessionsDir = join(testDir, 'sessions', '2025', '12', '22');
|
||||
await mkdir(sessionsDir, { recursive: true });
|
||||
|
||||
originalCodexHome = process.env.CODEX_HOME;
|
||||
process.env.CODEX_HOME = testDir;
|
||||
|
||||
events = [];
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
if (scanner) {
|
||||
await scanner.cleanup();
|
||||
scanner = null;
|
||||
}
|
||||
|
||||
if (originalCodexHome === undefined) {
|
||||
delete process.env.CODEX_HOME;
|
||||
} else {
|
||||
process.env.CODEX_HOME = originalCodexHome;
|
||||
}
|
||||
|
||||
if (existsSync(testDir)) {
|
||||
await rm(testDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it('emits only new events after startup', async () => {
|
||||
const sessionId = 'session-123';
|
||||
sessionFile = join(sessionsDir, `codex-${sessionId}.jsonl`);
|
||||
|
||||
const initialLines = [
|
||||
JSON.stringify({ type: 'session_meta', payload: { id: sessionId } }),
|
||||
JSON.stringify({ type: 'event_msg', payload: { type: 'agent_message', message: 'hello' } })
|
||||
];
|
||||
|
||||
await writeFile(sessionFile, initialLines.join('\n') + '\n');
|
||||
|
||||
scanner = await createCodexSessionScanner({
|
||||
sessionId,
|
||||
onEvent: (event) => events.push(event)
|
||||
});
|
||||
|
||||
await wait(150);
|
||||
expect(events).toHaveLength(0);
|
||||
|
||||
const newLine = JSON.stringify({
|
||||
type: 'response_item',
|
||||
payload: { type: 'function_call', name: 'Tool', call_id: 'call-1', arguments: '{}' }
|
||||
});
|
||||
await appendFile(sessionFile, newLine + '\n');
|
||||
|
||||
await wait(200);
|
||||
expect(events).toHaveLength(1);
|
||||
expect(events[0].type).toBe('response_item');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user