ralph_workflow/json_parser/codex/mod.rs
1//! Codex CLI JSON parser.
2//!
3//! Parses NDJSON output from `OpenAI` Codex CLI and formats it for display.
4//!
5//! # Streaming Output Behavior
6//!
7//! This parser implements real-time streaming output for text deltas. When content
8//! arrives in multiple chunks (via `item.started` events with `agent_message` type),
9//! the parser:
10//!
11//! 1. **Accumulates** text deltas from each chunk into a buffer
12//! 2. **Displays** the accumulated text after each chunk
13//! 3. **Uses carriage return (`\r`) and line clearing (`\x1b[2K`)** to rewrite the entire line,
14//! creating an updating effect that shows the content building up in real-time
15//! 4. **Shows prefix on every delta**, rewriting the entire line each time (industry standard)
16//!
17//! Example output sequence for streaming "Hello World" in two chunks:
18//! ```text
19//! [Codex] Hello\r (first chunk with prefix, no newline)
20//! \x1b[2K\r[Codex] Hello World\r (second chunk clears line, rewrites with accumulated)
21//! [Codex] Hello World\n (item.completed shows final result with prefix)
22//! ```
23//!
24//! # Single-Line Pattern
25//!
26//! The renderer uses a single-line pattern with carriage return for in-place updates.
27//! This is the industry standard for streaming CLIs (used by Rich, Ink, Bubble Tea).
28//!
29//! Each delta rewrites the entire line with prefix, ensuring that:
30//! - The user always sees the prefix
31//! - Content updates in-place without visual artifacts
32//! - Terminal state is clean and predictable
33
34mod event_handlers;
35
36use crate::config::Verbosity;
37use crate::logger::Colors;
38use crate::workspace::Workspace;
39use std::cell::RefCell;
40use std::io::{self, BufRead, Write};
41use std::path::PathBuf;
42use std::rc::Rc;
43
44use super::health::HealthMonitor;
45#[cfg(any(test, feature = "test-utils"))]
46use super::health::StreamingQualityMetrics;
47use super::printer::SharedPrinter;
48use super::streaming_state::StreamingSession;
49use super::terminal::TerminalMode;
50use super::types::{format_unknown_json_event, CodexEvent};
51
52use event_handlers::{
53 handle_error, handle_item_completed, handle_item_started, handle_thread_started,
54 handle_turn_completed, handle_turn_failed, handle_turn_started, EventHandlerContext,
55};
56
57include!("parser.rs");
58include!("event_parsing.rs");
59include!("stream_parsing.rs");