import type { IControllerCodexDiagnostic, TControllerCodexDiagnosticCode } from '../ts_interfaces/codex.js'; const messages: Record = { executable_missing: 'Codex could not be started. Install the Codex CLI or check its configured executable.', unsupported_platform: 'Local Codex requires a POSIX host. Connect to a remote Codex server on this platform.', startup_timeout: 'Codex did not finish connecting within the startup deadline. Retry the connection.', version_unsupported: 'This Codex server is too old. Upgrade to Codex 0.153.3 or newer.', authentication_required: 'Codex authentication failed. Check the server credential or sign in on the Codex host.', external_writer: 'This conversation is active in another Codex connection. Finish or release it there, then retry.', connection_closed: 'The Codex connection ended. Reconnect to continue.', connection_failed: 'Codex could not connect. Check the host and server configuration, then retry.', cleanup_incomplete: 'The previous Codex process has not confirmed shutdown. Restart is unavailable until cleanup succeeds.', }; /** Classify bounded untrusted failure text; return only fixed product copy. */ export const codexDiagnostic = ( errorArg: unknown, stageArg: IControllerCodexDiagnostic['stage'], ): IControllerCodexDiagnostic => { const message = errorArg instanceof Error ? errorArg.message.slice(0, 4096) : ''; const errorCode = errorArg instanceof Error && 'code' in errorArg ? errorArg.code : undefined; let code: TControllerCodexDiagnosticCode = 'connection_failed'; if (stageArg === 'cleanup') code = 'cleanup_incomplete'; else if (errorCode === 'ENOENT' || /did not provide its owned stdio process/.test(message)) code = 'executable_missing'; else if (/requires a POSIX/.test(message)) code = 'unsupported_platform'; else if (/timed out: initialize|handshake timed out/.test(message)) code = 'startup_timeout'; else if (/requires Codex app-server/.test(message)) code = 'version_unsupported'; else if (/active writer|already running a turn|outside this AGL connection/i.test(message)) code = 'external_writer'; else if (/\b401\b|\b403\b|unauthorized|authentication required|not authenticated/i.test(message)) code = 'authentication_required'; else if (/connection closed|WebSocket closed|app-server exited/i.test(message)) code = 'connection_closed'; return { code, stage: stageArg, message: messages[code], occurredAt: Date.now() }; };