Commit Graph

37 Commits

  • chore: remove codex-core public protocol/shell re-exports (#12432)
    ## Why
    
    `codex-rs/core/src/lib.rs` re-exported a broad set of types and modules
    from `codex-protocol` and `codex-shell-command`. That made it easy for
    workspace crates to import those APIs through `codex-core`, which in
    turn hides dependency edges and makes it harder to reduce compile-time
    coupling over time.
    
    This change removes those public re-exports so call sites must import
    from the source crates directly. Even when a crate still depends on
    `codex-core` today, this makes dependency boundaries explicit and
    unblocks future work to drop `codex-core` dependencies where possible.
    
    ## What Changed
    
    - Removed public re-exports from `codex-rs/core/src/lib.rs` for:
    - `codex_protocol::protocol` and related protocol/model types (including
    `InitialHistory`)
      - `codex_protocol::config_types` (`protocol_config_types`)
    - `codex_shell_command::{bash, is_dangerous_command, is_safe_command,
    parse_command, powershell}`
    - Migrated workspace Rust call sites to import directly from:
      - `codex_protocol::protocol`
      - `codex_protocol::config_types`
      - `codex_protocol::models`
      - `codex_shell_command`
    - Added explicit `Cargo.toml` dependencies (`codex-protocol` /
    `codex-shell-command`) in crates that now import those crates directly.
    - Kept `codex-core` internal modules compiling by using `pub(crate)`
    aliases in `core/src/lib.rs` (internal-only, not part of the public
    API).
    - Updated the two utility crates that can already drop a `codex-core`
    dependency edge entirely:
      - `codex-utils-approval-presets`
      - `codex-utils-cli`
    
    ## Verification
    
    - `cargo test -p codex-utils-approval-presets`
    - `cargo test -p codex-utils-cli`
    - `cargo check --workspace --all-targets`
    - `just clippy`
  • tui: preserve remote image attachments across resume/backtrack (#10590)
    ## Summary
    This PR makes app-server-provided image URLs first-class attachments in
    TUI, so they survive resume/backtrack/history recall and are resubmitted
    correctly.
    
    <img width="715" height="491" alt="Screenshot 2026-02-12 at 8 27 08 PM"
    src="https://github.com/user-attachments/assets/226cbd35-8f0c-4e51-a13e-459ef5dd1927"
    />
    
    Can delete the attached image upon backtracking:
    <img width="716" height="301" alt="Screenshot 2026-02-12 at 8 27 31 PM"
    src="https://github.com/user-attachments/assets/4558d230-f1bd-4eed-a093-8e1ab9c6db27"
    />
    
    In both history and composer, remote images are rendered as normal
    `[Image #N]` placeholders, with numbering unified with local images.
    
    ## What changed
    - Plumb remote image URLs through TUI message state:
      - `UserHistoryCell`
      - `BacktrackSelection`
      - `ChatComposerHistory::HistoryEntry`
      - `ChatWidget::UserMessage`
    - Show remote images as placeholder rows inside the composer box (above
    textarea), and in history cells.
    - Support keyboard selection/deletion for remote image rows in composer
    (`Up`/`Down`, `Delete`/`Backspace`).
    - Preserve remote-image-only turns in local composer history (Up/Down
    recall), including restore after backtrack.
    - Ensure submit/queue/backtrack resubmit include remote images in model
    input (`UserInput::Image`), and keep request shape stable for
    remote-image-only turns.
    - Keep image numbering contiguous across remote + local images:
      - remote images occupy `[Image #1]..[Image #M]`
      - local images start at `[Image #M+1]`
      - deletion renumbers consistently.
    - In protocol conversion, increment shared image index for remote images
    too, so mixed remote/local image tags stay in a single sequence.
    - Simplify restore logic to trust in-memory attachment order (no
    placeholder-number parsing path).
    - Backtrack/replay rollback handling now queues trims through
    `AppEvent::ApplyThreadRollback` and syncs transcript overlay/deferred
    lines after trims, so overlay/transcript state stays consistent.
    - Trim trailing blank rendered lines from user history rendering to
    avoid oversized blank padding.
    
    ## Docs + tests
    - Updated: `docs/tui-chat-composer.md` (remote image flow,
    selection/deletion, numbering offsets)
    - Added/updated tests across `tui/src/chatwidget/tests.rs`,
    `tui/src/app.rs`, `tui/src/app_backtrack.rs`, `tui/src/history_cell.rs`,
    and `tui/src/bottom_pane/chat_composer.rs`
    - Added snapshot coverage for remote image composer states, including
    deleting the first of two remote images.
    
    ## Validation
    - `just fmt`
    - `cargo test -p codex-tui`
    
    ## Codex author
    `codex fork 019c2636-1571-74a1-8471-15a3b1c3f49d`
  • tui: queue non-pending rollback trims in app-event order (#11373)
    ## Summary
    
    This PR fixes TUI transcript-sync behavior for
    `EventMsg::ThreadRolledBack` and makes rollback application order
    deterministic.
    
    Previously, rollback handling depended on `pending_rollback`:
    
    - if `pending_rollback` was set (local backtrack), TUI trimmed correctly
    - otherwise, replayed/external rollbacks were either ignored or could be
    applied at the wrong time relative to queued transcript inserts
    
    This change keeps the local backtrack path intact and routes non-pending
    rollbacks through the app event queue so rollback trims are applied in
    FIFO order with transcript cell inserts.
    
    ## What changed
    
    - Added/used `trim_transcript_cells_drop_last_n_user_turns(...)` for
    rollback-by-`num_turns` semantics.
    - Renamed rollback app event:
    - `AppEvent::ApplyReplayedThreadRollback` ->
    `AppEvent::ApplyThreadRollback`
    - Replay path (`ChatWidget`) now emits `ApplyThreadRollback`.
    - Live non-pending rollback path (`App::handle_backtrack_event`) now
    emits `ApplyThreadRollback` instead of trimming immediately.
    - App-level event handler applies `ApplyThreadRollback` after queued
    `InsertHistoryCell` events and schedules redraw only when a trim
    occurred.
    - When a trim occurs with an overlay open, TUI now syncs transcript
    overlay committed cells, clamps backtrack preview selection, and clears
    stale `deferred_history_lines` so closed overlays do not re-append
    rolled-back lines.
    - Clarified inline comments around the `pending_rollback` branch so
    future readers can reason about why there are two paths.
    
    ## Why queueing matters
    
    During resume/replay, transcript cells are populated via queued
    `InsertHistoryCell` app events. If a rollback is applied immediately
    outside that queue, it can run against an incomplete transcript and
    under-trim. Queueing non-pending rollbacks ensures consistent ordering
    and correct final transcript state.
    
    ## Behavior by rollback source
    
    - `pending_rollback = Some(...)` (local backtrack requested by this
    TUI):
      - use `finish_pending_backtrack()` and the stored selection boundary
    - `pending_rollback = None` (replay/external/non-local rollback):
    - enqueue `AppEvent::ApplyThreadRollback { num_turns }` and trim in
    app-event order
    
    ## Tests
    
    Added/updated tests covering ordering and semantics:
    
    -
    `app_backtrack::tests::trim_drop_last_n_user_turns_applies_rollback_semantics`
    - `app_backtrack::tests::trim_drop_last_n_user_turns_allows_overflow`
    - `app::tests::replayed_initial_messages_apply_rollback_in_queue_order`
    -
    `app::tests::live_rollback_during_replay_is_applied_in_app_event_order`
    -
    `app::tests::queued_rollback_syncs_overlay_and_clears_deferred_history`
    - `chatwidget::tests::replayed_thread_rollback_emits_ordered_app_event`
    
    Validation run:
    
    - `just fmt`
    - `cargo test -p codex-tui`
  • Persist text element ranges and attached images across history/resume (#9116)
    **Summary**
    - Backtrack selection now rehydrates `text_elements` and
    `local_image_paths` from the chosen user history cell so Esc‑Esc history
    edits preserve image placeholders and attachments.
    - Composer prefill uses the preserved elements/attachments in both `tui`
    and `tui2`.
    - Extended backtrack selection tests to cover image placeholder elements
    and local image paths.
    
    **Changes**
    - `tui/src/app_backtrack.rs`: Backtrack selection now carries text
    elements + local image paths; composer prefill uses them (removes TODO).
    - `tui2/src/app_backtrack.rs`: Same as above.
    - `tui/src/app.rs`: Updated backtrack test to assert restored
    elements/paths.
    - `tui2/src/app.rs`: Same test updates.
    
    ### The original scope of this PR (threading text elements and image
    attachments through the codex harness thoroughly/persistently) was
    broken into the following PRs other than this one:
    
    The diff of this PR was reduced by changing types in a starter PR:
    https://github.com/openai/codex/pull/9235
    
    Then text element metadata was added to protocol, app server, and core
    in this PR: https://github.com/openai/codex/pull/9331
    
    Then the end-to-end flow was completed by wiring TUI/TUI2 input,
    history, and restore behavior in
    https://github.com/openai/codex/pull/9393
    
    Prompt expansion was supported in this PR:
    https://github.com/openai/codex/pull/9518
    
    TextElement optional placeholder field was protected in
    https://github.com/openai/codex/pull/9545
  • Persist text elements through TUI input and history (#9393)
    Continuation of breaking up this PR
    https://github.com/openai/codex/pull/9116
    
    ## Summary
    - Thread user text element ranges through TUI/TUI2 input, submission,
    queueing, and history so placeholders survive resume/edit flows.
    - Preserve local image attachments alongside text elements and rehydrate
    placeholders when restoring drafts.
    - Keep model-facing content shapes clean by attaching UI metadata only
    to user input/events (no API content changes).
    
    ## Key Changes
    - TUI/TUI2 composer now captures text element ranges, trims them with
    text edits, and restores them when submission is suppressed.
    - User history cells render styled spans for text elements and keep
    local image paths for future rehydration.
    - Initial chat widget bootstraps accept empty `initial_text_elements` to
    keep initialization uniform.
    - Protocol/core helpers updated to tolerate the new InputText field
    shape without changing payloads sent to the API.
  • tui: allow forward navigation in backtrack preview (#9059)
    Fixes #9058
    
    ## Summary
    When the transcript backtrack preview is armed (press `Esc`), allow
    navigating to newer user messages with the `→` arrow, in addition to
    navigating backwards with `Esc`/`←`, before confirming with `Enter`.
    
    ## Changes
    - Backtrack preview navigation: `Esc`/`←` steps to older user messages,
    `→` steps to newer ones, `Enter` edits the selected message (clamped at
    bounds, no wrap-around).
    - Transcript overlay footer hints updated to advertise `esc/←`, `→`, and
    `enter` when a message is highlighted.
    
    ## Related
    - WSL shortcut-overlay snapshot determinism: #9359
    
    ## Testing
    - `just fmt`
    - `just fix -p codex-tui`
    - `just fix -p codex-tui2`
    - `cargo test -p codex-tui app_backtrack::`
    - `cargo test -p codex-tui pager_overlay::`
    - `cargo test -p codex-tui2 app_backtrack::`
    - `cargo test -p codex-tui2 pager_overlay::`
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • fix(tui) Defer backtrack trim until rollback confirms (#9401)
    Document the backtrack/rollback state machine and invariants between the
    transcript overlay, in-flight “live tail”, and core thread state (tui + tui2).
    
    Also adjust behavior for correctness:
    - Track a single pending rollback and block additional rollbacks until core responds.
    - Defer trimming transcript cells until ThreadRolledBack for the active session.
    - Clear the guard on ThreadRollbackFailed so the user can retry.
    - After a confirmed trim, schedule a one-shot scrollback refresh on the next draw.
    - Clear stale pending rollback state when switching sessions.
    
    ---------
    
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • Use thread rollback for Esc backtrack (#9140)
    - Swap Esc backtrack to roll back the current thread instead of forking
  • fix(tui): show in-flight coalesced tool calls in transcript overlay (#8246)
    ### Problem
    Ctrl+T transcript overlay can omit in-flight coalesced tool calls because it
    renders only committed transcript cells while the main viewport can render the
    current in-flight ChatWidget.active_cell immediately.
    
    ### Mental model
    The UI has both committed transcript cells (finalized HistoryCell entries) and
    an in-flight active cell that can mutate in place while streaming, often
    representing a coalesced exec/tool group. The transcript overlay renders
    committed cells plus a render-only live tail derived from the current active
    cell. The live tail is cached and only recomputed when its cache key changes,
    which is derived from terminal width (wrapping), active-cell revision
    (in-place mutations), stream continuation (spacing), and animation tick
    (time-based visuals).
    
    ### Non-goals
    This does not change coalescing rules, flush boundaries, or when active cells
    become committed. It does not change tool-call semantics or transcript
    persistence; it is a rendering-only improvement for the overlay.
    
    ### Tradeoffs
    This adds cache invalidation complexity: correctness depends on bumping an
    active-cell revision (and/or providing an animation tick) when the active cell
    mutates in place. The mechanism is implemented in both codex-tui and codex-tui2,
    which keeps behavior consistent but risks drift if future changes are not
    applied in lockstep.
    
    ### Architecture
    App special-cases transcript overlay draws to sync a live tail from ChatWidget
    into TranscriptOverlay. TranscriptOverlay remains the owner of committed
    transcript cells; the live tail is an optional appended renderable.
    HistoryCell::transcript_animation_tick() allows time-dependent transcript output
    (spinner/shimmer) to invalidate the cached tail without requiring data mutation.
    
    ### Observability
    Manual verification is to open Ctrl+T while an exploring/coalesced active cell
    is still in-flight and confirm the overlay includes the same in-flight tool-call
    group the main viewport shows. The overlay is kept in sync by App passing an
    active-cell key and transcript lines into TranscriptOverlay::sync_live_tail; the
    key must change when the active cell mutates or animates.
    
    ### Tests
    Snapshot tests validate that the transcript overlay renders a live tail appended
    after committed cells and that identical keys short-circuit recomputation. Unit
    tests validate that active-cell revision bumps occur on specific in-place
    mutations (e.g. unified exec wait cell command display becoming known late) so
    cached tails are invalidated.
    
    ## Documentation patches (module, type, function)
    
    ### Module-level docs (invariants + mechanisms)
    - codex-rs/tui/src/app_backtrack.rs:1
    - codex-rs/tui/src/chatwidget.rs:1
    - codex-rs/tui/src/pager_overlay.rs:1
    - codex-rs/tui/src/history_cell.rs:1
    - codex-rs/tui2/src/app_backtrack.rs:1
    - codex-rs/tui2/src/chatwidget.rs:1
    - codex-rs/tui2/src/pager_overlay.rs:1
    - codex-rs/tui2/src/history_cell.rs:1
    
    ### Type-level docs (cache key + invariants)
    - codex-rs/tui/src/chatwidget.rs (ChatWidget.active_cell_revision, ActiveCellTranscriptKey)
    - codex-rs/tui/src/pager_overlay.rs (TranscriptOverlay live tail storage model)
    - codex-rs/tui/src/history_cell.rs (HistoryCell::transcript_animation_tick, UnifiedExecWaitCell::update_command_display)
    - Mirrored in codex-rs/tui2/src/chatwidget.rs, codex-rs/tui2/src/pager_overlay.rs, codex-rs/tui2/src/history_cell.rs
    
    ### Function-level docs (why/when/guarantees/pitfalls)
    - codex-rs/tui/src/app_backtrack.rs (overlay_forward_event)
    - codex-rs/tui/src/chatwidget.rs (active_cell_transcript_key, active_cell_transcript_lines)
    - codex-rs/tui/src/pager_overlay.rs (sync_live_tail, take_live_tail_renderable)
    - codex-rs/tui/src/history_cell.rs (transcript_animation_tick, UnifiedExecWaitCell::update_command_display)
    - Mirrored in codex-rs/tui2 equivalents where present
    
    ### Validation performed
    - cd codex-rs && just fmt
    - cd codex-rs && cargo test -p codex-tui
    - cd codex-rs && cargo test -p codex-tui2
    
    ## Design inconsistencies / risks
    
    - Cache invalidation is a distributed responsibility: any future in-place active
      cell transcript mutation that forgets to bump active_cell_revision (or expose
      an animation tick) can leave the transcript overlay live tail out of sync with
      the main viewport.
    - TranscriptOverlay tail handling assumes a structural invariant that the live
      tail, when present, is exactly one trailing renderable after the committed cell
      renderables; if renderable construction changes in a way that violates that
      assumption, tail insertion/removal logic becomes incorrect.
    - codex-tui and codex-tui2 duplicate the live-tail mechanism; the documentation
      is aligned, but the implementation can still drift unless changes continue to
      be applied in lockstep.
  • chore: unify conversation with thread name (#8830)
    Done and verified by Codex + refactor feature of RustRover
  • Remove model family from tui (#8488)
    - Remove model family from tui
  • Inject SKILL.md when it's explicitly mentioned. (#7763)
    1. Skills load once in core at session start; the cached outcome is
    reused across core and surfaced to TUI via SessionConfigured.
    2. TUI detects explicit skill selections, and core injects the matching
    SKILL.md content into the turn when a selected skill is present.
  • make model optional in config (#7769)
    - Make Config.model optional and centralize default-selection logic in
    ModelsManager, including a default_model helper (with
    codex-auto-balanced when available) so sessions now carry an explicit
    chosen model separate from the base config.
    - Resolve `model` once in `core` and `tui` from config. Then store the
    state of it on other structs.
    - Move refreshing models to be before resolving the default model
  • Wire with_remote_overrides to construct model families (#7621)
    - This PR wires `with_remote_overrides` and make the
    `construct_model_families` an async function
    - Moves getting model family a level above to keep the function `sync`
    - Updates the tests to local, offline, and `sync` helper for model
    families
  • Migrate tui to use models manager (#7555)
    - This PR treats the `ModelsManager` like `AuthManager` and propagate it
    into the tui, replacing the `builtin_model_presets`
    - We are also decreasing the visibility of `builtin_model_presets`
    
    based on https://github.com/openai/codex/pull/7552
  • feat: Support listing and selecting skills via $ or /skills (#7506)
    List/Select skills with $-mention or /skills
  • feat: codex tool tips (#7440)
    <img width="551" height="316" alt="Screenshot 2025-12-01 at 12 22 26"
    src="https://github.com/user-attachments/assets/6ca3deff-8ef8-4f74-a8e1-e5ea13fd6740"
    />
  • tui: fix backtracking past /status (#6335)
    Fixes https://github.com/openai/codex/issues/4722
    
    Supersedes https://github.com/openai/codex/pull/5058
    
    Ideally we'd have a clearer way of separating history per-session than
    by detecting a specific history cell type, but this is a fairly minimal
    fix for now.
  • Keep backtrack Esc hint gated on empty composer (#5076)
    ## Summary
    - only prime backtrack and show the ESC hint when the composer is empty
    - keep the composer-side ESC hint unchanged when drafts or attachments
    exist and cover it with a regression test
    
    Fixes #5030
    
    ------
    https://chatgpt.com/codex/tasks/task_i_68e95ba59cd8832caec8e72ae2efeb55
  • tui: bring the transcript closer to display mode (#4848)
    before
    <img width="1161" height="836" alt="Screenshot 2025-10-06 at 3 06 52 PM"
    src="https://github.com/user-attachments/assets/7622fd6b-9d37-402f-8651-61c2c55dcbc6"
    />
    
    after
    <img width="1161" height="858" alt="Screenshot 2025-10-06 at 3 07 02 PM"
    src="https://github.com/user-attachments/assets/1498f327-1d1a-4630-951f-7ca371ab0139"
    />
  • fix: remove mcp-types from app server protocol (#4537)
    We continue the separation between `codex app-server` and `codex
    mcp-server`.
    
    In particular, we introduce a new crate, `codex-app-server-protocol`,
    and migrate `codex-rs/protocol/src/mcp_protocol.rs` into it, renaming it
    `codex-rs/app-server-protocol/src/protocol.rs`.
    
    Because `ConversationId` was defined in `mcp_protocol.rs`, we move it
    into its own file, `codex-rs/protocol/src/conversation_id.rs`, and
    because it is referenced in a ton of places, we have to touch a lot of
    files as part of this PR.
    
    We also decide to get away from proper JSON-RPC 2.0 semantics, so we
    also introduce `codex-rs/app-server-protocol/src/jsonrpc_lite.rs`, which
    is basically the same `JSONRPCMessage` type defined in `mcp-types`
    except with all of the `"jsonrpc": "2.0"` removed.
    
    Getting rid of `"jsonrpc": "2.0"` makes our serialization logic
    considerably simpler, as we can lean heavier on serde to serialize
    directly into the wire format that we use now.
  • update composer + user message styling (#4240)
    Changes:
    
    - the composer and user messages now have a colored background that
    stretches the entire width of the terminal.
    - the prompt character was changed from a cyan `▌` to a bold `›`.
    - the "working" shimmer now follows the "dark gray" color of the
    terminal, better matching the terminal's color scheme
    
    | Terminal + Background        | Screenshot |
    |------------------------------|------------|
    | iTerm with dark bg | <img width="810" height="641" alt="Screenshot
    2025-09-25 at 11 44 52 AM"
    src="https://github.com/user-attachments/assets/1317e579-64a9-4785-93e6-98b0258f5d92"
    /> |
    | iTerm with light bg | <img width="845" height="540" alt="Screenshot
    2025-09-25 at 11 46 29 AM"
    src="https://github.com/user-attachments/assets/e671d490-c747-4460-af0b-3f8d7f7a6b8e"
    /> |
    | iTerm with color bg | <img width="825" height="564" alt="Screenshot
    2025-09-25 at 11 47 12 AM"
    src="https://github.com/user-attachments/assets/141cda1b-1164-41d5-87da-3be11e6a3063"
    /> |
    | Terminal.app with dark bg | <img width="577" height="367"
    alt="Screenshot 2025-09-25 at 11 45 22 AM"
    src="https://github.com/user-attachments/assets/93fc4781-99f7-4ee7-9c8e-3db3cd854fe5"
    /> |
    | Terminal.app with light bg | <img width="577" height="367"
    alt="Screenshot 2025-09-25 at 11 46 04 AM"
    src="https://github.com/user-attachments/assets/19bf6a3c-91e0-447b-9667-b8033f512219"
    /> |
    | Terminal.app with color bg | <img width="577" height="367"
    alt="Screenshot 2025-09-25 at 11 45 50 AM"
    src="https://github.com/user-attachments/assets/dd7c4b5b-342e-4028-8140-f4e65752bd0b"
    /> |
  • Tui: fix backtracking (#4020)
    Backtracking multiple times could drop earlier turns. We now derive the
    active user-turn positions from the transcript on demand (keying off the
    latest session header) instead of caching state. This keeps the replayed
    context intact during repeated edits and adds a regression test.
  • Revert "refactor transcript view to handle HistoryCells" (#3614)
    Reverts openai/codex#3538
    It panics on forking first message. It also calculates the index in a
    wrong way.
  • refactor transcript view to handle HistoryCells (#3538)
    No (intended) functional change.
    
    This refactors the transcript view to hold a list of HistoryCells
    instead of a list of Lines. This simplifies and makes much of the logic
    more robust, as well as laying the groundwork for future changes, e.g.
    live-updating history cells in the transcript.
    
    Similar to #2879 in goal. Fixes #2755.
  • Change forking to read the rollout from file (#3440)
    This PR changes get history op to get path. Then, forking will use a
    path. This will help us have one unified codepath for resuming/forking
    conversations. Will also help in having rollout history in order. It
    also fixes a bug where you won't see the UI when resuming after forking.
  • Generate more typescript types and return conversation id with ConversationSummary (#3219)
    This PR does multiple things that are necessary for conversation resume
    to work from the extension. I wanted to make sure everything worked so
    these changes wound up in one PR:
    1. Generate more ts types
    2. Resume rollout history files rather than create a new one every time
    it is resumed so you don't see a duplicate conversation in history for
    every resume. Chatted with @aibrahim-oai to verify this
    3. Return conversation_id in conversation summaries
    4. [Cleanup] Use serde and strong types for a lot of the rollout file
    parsing
  • Use ConversationId instead of raw Uuids (#3282)
    We're trying to migrate from `session_id: Uuid` to `conversation_id:
    ConversationId`. Not only does this give us more type safety but it
    unifies our terminology across Codex and with the implementation of
    session resuming, a conversation (which can span multiple sessions) is
    more appropriate.
    
    I started this impl on https://github.com/openai/codex/pull/3219 as part
    of getting resume working in the extension but it's big enough that it
    should be broken out.
  • TUI: Add session resume picker (--resume) and quick resume (--continue) (#3135)
    Adds a TUI resume flow with an interactive picker and quick resume.
    
    - CLI: 
      - --resume / -r: open picker to resume a prior session
      - --continue   / -l: resume the most recent session (no picker)
    - Behavior on resume: initial history is replayed, welcome banner
    hidden, and the first redraw is suppressed to avoid flicker.
    - Implementation:
    - New tui/src/resume_picker.rs (paginated listing via
    RolloutRecorder::list_conversations)
      - App::run accepts ResumeSelection; resumes from disk when requested
    - ChatWidget refactor with ChatWidgetInit and new_from_existing; replays
    initial messages
    - Tests: cover picker sorting/preview extraction and resumed-history
    rendering.
    - Docs: getting-started updated with flags and picker usage.
    
    
    
    https://github.com/user-attachments/assets/1bb6469b-e5d1-42f6-bec6-b1ae6debda3b
  • fix transcript lines being added to diff view (#2721)
    This fixes a bug where if you ran /diff while at turn was running,
    transcript lines would be added to the end of the diff view. Also,
    refactor to make this kind of issue less likely in future.
  • do not schedule frames for Tui::Draw events in backtrack (#2692)
    this was causing continuous rerendering when a transcript overlay was
    present