* Extract error messages from Codex logs (e.g., model access blocked, cyber_policy_violation) * @param {string[]} lines - Array of log lines * @returns {{hasErrors: boolean, messages: string[], reconnectCount: number, maxReconnects: number}} Error info
(lines)
| 128 | * @returns {{hasErrors: boolean, messages: string[], reconnectCount: number, maxReconnects: number}} Error info |
| 129 | */ |
| 130 | function extractCodexErrorMessages(lines) { |
| 131 | const messages = new Set(); |
| 132 | let reconnectCount = 0; |
| 133 | let maxReconnects = 0; |
| 134 | |
| 135 | for (const line of lines) { |
| 136 | // Match: ERROR: <message> (final error after all retries exhausted) |
| 137 | const errorMatch = line.match(/^ERROR:\s*(.+)$/); |
| 138 | if (errorMatch) { |
| 139 | messages.add(errorMatch[1].trim()); |
| 140 | } |
| 141 | |
| 142 | // Match: Reconnecting... N/M (error message) - reconnect attempts with error details |
| 143 | const reconnectMatch = line.match(/^Reconnecting\.\.\.\s+(\d+)\/(\d+)\s*\((.+)\)$/); |
| 144 | if (reconnectMatch) { |
| 145 | const attempt = parseInt(reconnectMatch[1]); |
| 146 | const total = parseInt(reconnectMatch[2]); |
| 147 | if (attempt > reconnectCount) reconnectCount = attempt; |
| 148 | if (total > maxReconnects) maxReconnects = total; |
| 149 | messages.add(reconnectMatch[3].trim()); |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | return { |
| 154 | hasErrors: messages.size > 0, |
| 155 | messages: Array.from(messages), |
| 156 | reconnectCount, |
| 157 | maxReconnects, |
| 158 | }; |
| 159 | } |
| 160 | |
| 161 | /** |
| 162 | * Convert parsed Codex data to logEntries format for plain text rendering |
no test coverage detected