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:
weishu
2025-12-22 19:14:47 +08:00
parent 0c16b7b215
commit 4290f539bd
15 changed files with 1606 additions and 661 deletions
+67
View File
@@ -0,0 +1,67 @@
import { MessageQueue2 } from '@/utils/MessageQueue2';
import { logger } from '@/ui/logger';
import { CodexSession } from './session';
import { codexLocalLauncher } from './codexLocalLauncher';
import { codexRemoteLauncher } from './codexRemoteLauncher';
import { ApiClient, ApiSessionClient } from '@/lib';
export type PermissionMode = 'default' | 'read-only' | 'safe-yolo' | 'yolo';
export interface EnhancedMode {
permissionMode: PermissionMode;
model?: string;
}
interface LoopOptions {
path: string;
startingMode?: 'local' | 'remote';
onModeChange: (mode: 'local' | 'remote') => void;
messageQueue: MessageQueue2<EnhancedMode>;
session: ApiSessionClient;
api: ApiClient;
onSessionReady?: (session: CodexSession) => void;
}
export async function loop(opts: LoopOptions): Promise<void> {
const logPath = logger.getLogPath();
const session = new CodexSession({
api: opts.api,
client: opts.session,
path: opts.path,
sessionId: null,
logPath,
messageQueue: opts.messageQueue,
onModeChange: opts.onModeChange,
mode: opts.startingMode ?? 'local'
});
if (opts.onSessionReady) {
opts.onSessionReady(session);
}
let mode: 'local' | 'remote' = opts.startingMode ?? 'local';
while (true) {
logger.debug(`[codex-loop] Iteration with mode: ${mode}`);
if (mode === 'local') {
const reason = await codexLocalLauncher(session);
if (reason === 'exit') {
return;
}
mode = 'remote';
session.onModeChange(mode);
continue;
}
if (mode === 'remote') {
const reason = await codexRemoteLauncher(session);
if (reason === 'exit') {
return;
}
mode = 'local';
session.onModeChange(mode);
continue;
}
}
}