Defer live table tails during stream consolidation so their provisional
render is not inserted before the canonical markdown cell is rebuilt.
Use the stronger combined scrollback and visible-screen clear path during
transcript reflow so tmux does not preserve stale viewport table output.
Pass cwd arguments through test-only markdown constructors after the
rebase so the TUI test target builds against the cwd-aware renderer
APIs.
Keep the formatter output from the required post-rebase `just fmt`
run in the same follow-up change.
Capture formatter-only import ordering updates in two TUI files to keep the
working tree clean after recent core changes.
No behavior changes are included in this commit.
Pin `syntect` to `=5.3.0` and add explicit review dates to the
existing `RUSTSEC-2024-0320` and `RUSTSEC-2025-0141` exceptions in
`deny.toml` so dependency risk review stays deliberate.
Fix grammar in `core/src/agent/builtins/monitor.toml` developer
instructions and add a realtime conversation test that returns `None`
when a message item is missing `content`.
Ignore empty or whitespace-only realtime transcript input so we do not
create no-op user turns from blank transcriptions.
Move realtime text mirroring off the `send_event` hot path and add
bounded truncation for mirrored patch output and file lists, while
adding a serde alias for `background_terminal_timeout` compatibility.
Adjust table column classification in `markdown_render.rs` so token-heavy,
low-word-density columns are treated as Structured instead of Narrative.
This keeps URL-heavy link columns from being first in the shrink order,
reducing rare but severe narrow-column wrapping in rendered tables.
Disable table holdback for `PlanStreamController` by adding a
per-stream `TableHoldbackMode` in `StreamCore`. Agent streams keep
holdback enabled, while plan streams now enqueue table lines
incrementally.
Also treat plan live tail as active in `stream_controllers_idle()` and
add regression coverage in `codex-rs/tui/src/streaming/controller.rs`
and `codex-rs/tui/src/chatwidget/tests.rs` to prevent premature
`StopCommitAnimation` and preserve streaming behavior.
Improve resize reflow scheduling so due reflows request an immediate frame
instead of waiting for unrelated redraws, and clear queued stream output on
`Op::Interrupt` so stale lines stop rendering immediately.
Harden markdown/table parsing by treating tab indentation as 4-column
whitespace in `strip_line_indent` and ignoring escaped-only pipes in
`parse_table_segments` unless explicit outer pipes are present.
Replace clone with mem::take in finalize(), return Cow from
unwrap_markdown_fences for zero-copy on fence-free messages, use
index-based iteration in reflow loop, add #[inline] on ~20 hot-path
functions, add with_capacity hints on hot Vecs/Strings, box large
ActiveFence variant, and eliminate minor allocations (into_iter,
Span::from for literals, write!-based plain_text, redundant .max(1)).
Remove accumulated duplication and dead code across the md-table
branch: extract shared helpers (trailing_run_start<T>, strip_line_indent,
compute_target_stable_len, reset_history_emission_state,
maybe_finish_stream_reflow, is_blockquote_active, active_cell_is_stream_tail),
collapse redundant conditionals (normalize_row, FenceTracker Option state,
merged match arms), delete duplicate methods and tests, and fix stale
doc comments. No behavioral changes; -86 net lines.
Strip blockquote prefixes during table detection only when the fence
itself is inside a blockquote, preventing false unwrapping of fences
that contain blockquoted table examples as illustration content.
- tick_batch(0) now returns empty instead of silently draining one line
- has_live_tail avoids Vec allocation via field comparison
- Convert 15 sync-only controller tests from tokio::test to #[test]
Address reviewer concerns about self-referential test coverage:
- Column-metrics: 6 tests for TableColumnKind classification,
preferred_column_floor caps, and next_column_to_shrink priority.
- Spillover detection: 6 tests for is_spillover_row covering each
heuristic branch and negative cases.
Add module-level, type-level, and function-level documentation across
the table rendering pipeline: table_detect, width, markdown,
markdown_render, and streaming/controller. Separate spillover lines
from table grid output via RenderedTableLines so spillover prose
routes through normal word wrapping instead of bypassing it.
Add module, type, and function-level doc comments across the table
rendering change. Fix typos ("taht", "mirros", "stabe", "durin").
Expand streaming controller module docs to cover holdback and resize
handling. Document width allocation, spillover detection, consolidation,
and prewrapped line rendering contracts. No runtime behavior changes
in documentation edits; also includes extracted draw helpers in app.rs
and a fence-detection fix in markdown.rs.
Wire the Unicode box-drawing table renderer into the live streaming
path with holdback-aware commit logic, post-stream cell consolidation,
and debounced resize reflow.
Key additions:
- StreamCore: shared bookkeeping deduplicating Stream/PlanStreamController
- Table holdback: fence-aware state machine keeps buffer mutable during table detection
- AgentMarkdownCell: stores raw markdown source, re-renders at any width on demand
- ConsolidateAgentMessage: backward-walk replaces streamed cells with single consolidated cell
- Resize reflow: debounced (75ms) re-render of all transcript cells after terminal resize
Add proper table rendering to the markdown renderer using Unicode
box-drawing characters (┌─┬┐│├─┼┤└─┴┘) instead of raw pipe syntax.
Supports column alignment, cell wrapping at narrow widths, tables
inside blockquotes, escaped pipes, and styled inline content.
Addresses #16622
Problem: bare local file links in TUI markdown render percent-encoded
path bytes literally, unlike file:// links.
Solution: decode bare path targets before local-path expansion and add
regression coverage for spaces and Unicode.
Problem: The resume picker used awkward "Created at" and "Updated at"
headers, and its relative timestamps changed while navigating because
they were recomputed on each redraw.
Solution: Rename the headers to "Created" and "Updated", and anchor
relative timestamp formatting to the picker load time so the displayed
ages stay stable while browsing.
Addresses #16781
Problem: `codex exec --ephemeral` backfilled empty `turn/completed`
items with `thread/read(includeTurns=true)`, which app-server rejects
for ephemeral threads.
This is a regression introduced in the recent conversion of "exec" to
use app server rather than call the core directly.
Solution: Skip turn-item backfill for ephemeral exec threads while
preserving the existing recovery path for non-ephemeral sessions.