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
+78
View File
@@ -0,0 +1,78 @@
import { ApiClient, ApiSessionClient } from '@/lib';
import { MessageQueue2 } from '@/utils/MessageQueue2';
import { logger } from '@/ui/logger';
import type { EnhancedMode } from './loop';
export class CodexSession {
readonly path: string;
readonly logPath: string;
readonly api: ApiClient;
readonly client: ApiSessionClient;
readonly queue: MessageQueue2<EnhancedMode>;
readonly _onModeChange: (mode: 'local' | 'remote') => void;
sessionId: string | null;
mode: 'local' | 'remote' = 'local';
thinking: boolean = false;
private keepAliveInterval: NodeJS.Timeout | null = null;
constructor(opts: {
api: ApiClient;
client: ApiSessionClient;
path: string;
logPath: string;
sessionId: string | null;
messageQueue: MessageQueue2<EnhancedMode>;
onModeChange: (mode: 'local' | 'remote') => void;
mode?: 'local' | 'remote';
}) {
this.path = opts.path;
this.api = opts.api;
this.client = opts.client;
this.logPath = opts.logPath;
this.sessionId = opts.sessionId;
this.queue = opts.messageQueue;
this._onModeChange = opts.onModeChange;
this.mode = opts.mode ?? 'local';
this.client.keepAlive(this.thinking, this.mode);
this.keepAliveInterval = setInterval(() => {
this.client.keepAlive(this.thinking, this.mode);
}, 2000);
}
onThinkingChange = (thinking: boolean) => {
this.thinking = thinking;
this.client.keepAlive(thinking, this.mode);
};
onModeChange = (mode: 'local' | 'remote') => {
this.mode = mode;
this.client.keepAlive(this.thinking, mode);
this._onModeChange(mode);
};
onSessionFound = (sessionId: string) => {
this.sessionId = sessionId;
this.client.updateMetadata((metadata) => ({
...metadata,
codexSessionId: sessionId
}));
logger.debug(`[CodexSession] Codex session ID ${sessionId} added to metadata`);
};
sendCodexMessage = (message: unknown): void => {
this.client.sendCodexMessage(message);
};
sendSessionEvent = (event: Parameters<ApiSessionClient['sendSessionEvent']>[0]): void => {
this.client.sendSessionEvent(event);
};
stopKeepAlive = (): void => {
if (this.keepAliveInterval) {
clearInterval(this.keepAliveInterval);
this.keepAliveInterval = null;
}
};
}