* Parse the Codex experimental JSONL event stream into the shared logEntries model. * Maps `item.completed` items (agent_message, reasoning, mcp_tool_call, * command_execution) and `turn.completed` usage onto the same `parsedData` * structure used by the legacy parser, so the common renderer is r
(logContent)
| 329 | * @returns {{markdown: string, logEntries: Array, mcpFailures: Array<string>, maxTurnsHit: boolean}} Parsed log data |
| 330 | */ |
| 331 | function parseCodexJsonl(logContent) { |
| 332 | const DEFAULT_STATUS_ICON = "🔧"; |
| 333 | |
| 334 | const lines = logContent.split("\n"); |
| 335 | const parsedData = []; |
| 336 | let usage = null; |
| 337 | let turnCount = 0; |
| 338 | |
| 339 | for (const line of lines) { |
| 340 | const trimmed = line.trim(); |
| 341 | if (!trimmed.startsWith("{")) continue; |
| 342 | let event; |
| 343 | try { |
| 344 | event = JSON.parse(trimmed); |
| 345 | } catch { |
| 346 | continue; |
| 347 | } |
| 348 | if (!event || typeof event !== "object") continue; |
| 349 | |
| 350 | if (event.type === "turn.completed") { |
| 351 | turnCount++; |
| 352 | if (event.usage && typeof event.usage === "object") { |
| 353 | usage = event.usage; |
| 354 | } |
| 355 | continue; |
| 356 | } |
| 357 | |
| 358 | // Only render completed items; `item.started` entries are interim duplicates. |
| 359 | if (event.type !== "item.completed" || !event.item || typeof event.item !== "object") { |
| 360 | continue; |
| 361 | } |
| 362 | |
| 363 | const item = event.item; |
| 364 | switch (item.type) { |
| 365 | case "agent_message": { |
| 366 | if (typeof item.text === "string" && item.text.trim()) { |
| 367 | parsedData.push({ type: "text", content: item.text }); |
| 368 | } |
| 369 | break; |
| 370 | } |
| 371 | case "reasoning": { |
| 372 | const reasoning = typeof item.text === "string" ? item.text : typeof item.summary === "string" ? item.summary : ""; |
| 373 | if (reasoning.trim()) { |
| 374 | parsedData.push({ type: "thinking", content: reasoning }); |
| 375 | } |
| 376 | break; |
| 377 | } |
| 378 | case "mcp_tool_call": { |
| 379 | const server = item.server || "mcp"; |
| 380 | const toolName = item.tool || "tool"; |
| 381 | const params = item.arguments != null ? JSON.stringify(item.arguments) : ""; |
| 382 | let response = ""; |
| 383 | if (item.error != null) { |
| 384 | response = typeof item.error === "string" ? item.error : JSON.stringify(item.error); |
| 385 | } else if (item.result != null) { |
| 386 | response = typeof item.result === "string" ? item.result : JSON.stringify(item.result); |
| 387 | } |
| 388 | const isError = item.status === "failed" || item.error != null; |
no test coverage detected