mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
8e784bba2fb795ec9248bbfd9a26fdad1b809dc6
34 Commits
-
Rename tui_app_server to tui (#16104)
This is a follow-up to https://github.com/openai/codex/pull/15922. That previous PR deleted the old `tui` directory and left the new `tui_app_server` directory in place. This PR renames `tui_app_server` to `tui` and fixes up all references.
Eric Traut ·
2026-03-28 11:23:07 -06:00 -
Remove the legacy TUI split (#15922)
This is the part 1 of 2 PRs that will delete the `tui` / `tui_app_server` split. This part simply deletes the existing `tui` directory and marks the `tui_app_server` feature flag as removed. I left the `tui_app_server` feature flag in place for now so its presence doesn't result in an error. It is simply ignored. Part 2 will rename the `tui_app_server` directory `tui`. I did this as two parts to reduce visible code churn.
Eric Traut ·
2026-03-27 22:56:44 +00:00 -
Apply argument comment lint across codex-rs (#14652)
## Why Once the repo-local lint exists, `codex-rs` needs to follow the checked-in convention and CI needs to keep it from drifting. This commit applies the fallback `/*param*/` style consistently across existing positional literal call sites without changing those APIs. The longer-term preference is still to avoid APIs that require comments by choosing clearer parameter types and call shapes. This PR is intentionally the mechanical follow-through for the places where the existing signatures stay in place. After rebasing onto newer `main`, the rollout also had to cover newly introduced `tui_app_server` call sites. That made it clear the first cut of the CI job was too expensive for the common path: it was spending almost as much time installing `cargo-dylint` and re-testing the lint crate as a representative test job spends running product tests. The CI update keeps the full workspace enforcement but trims that extra overhead from ordinary `codex-rs` PRs. ## What changed - keep a dedicated `argument_comment_lint` job in `rust-ci` - mechanically annotate remaining opaque positional literals across `codex-rs` with exact `/*param*/` comments, including the rebased `tui_app_server` call sites that now fall under the lint - keep the checked-in style aligned with the lint policy by using `/*param*/` and leaving string and char literals uncommented - cache `cargo-dylint`, `dylint-link`, and the relevant Cargo registry/git metadata in the lint job - split changed-path detection so the lint crate's own `cargo test` step runs only when `tools/argument-comment-lint/*` or `rust-ci.yml` changes - continue to run the repo wrapper over the `codex-rs` workspace, so product-code enforcement is unchanged Most of the code changes in this commit are intentionally mechanical comment rewrites or insertions driven by the lint itself. ## Verification - `./tools/argument-comment-lint/run.sh --workspace` - `cargo test -p codex-tui-app-server -p codex-tui` - parsed `.github/workflows/rust-ci.yml` locally with PyYAML --- * -> #14652 * #14651
Michael Bolin ·
2026-03-16 16:48:15 -07:00 -
Add Smart Approvals guardian review across core, app-server, and TUI (#13860)
## Summary - add `approvals_reviewer = "user" | "guardian_subagent"` as the runtime control for who reviews approval requests - route Smart Approvals guardian review through core for command execution, file changes, managed-network approvals, MCP approvals, and delegated/subagent approval flows - expose guardian review in app-server with temporary unstable `item/autoApprovalReview/{started,completed}` notifications carrying `targetItemId`, `review`, and `action` - update the TUI so Smart Approvals can be enabled from `/experimental`, aligned with the matching `/approvals` mode, and surfaced clearly while reviews are pending or resolved ## Runtime model This PR does not introduce a new `approval_policy`. Instead: - `approval_policy` still controls when approval is needed - `approvals_reviewer` controls who reviewable approval requests are routed to: - `user` - `guardian_subagent` `guardian_subagent` is a carefully prompted reviewer subagent that gathers relevant context and applies a risk-based decision framework before approving or denying the request. The `smart_approvals` feature flag is a rollout/UI gate. Core runtime behavior keys off `approvals_reviewer`. When Smart Approvals is enabled from the TUI, it also switches the current `/approvals` settings to the matching Smart Approvals mode so users immediately see guardian review in the active thread: - `approval_policy = on-request` - `approvals_reviewer = guardian_subagent` - `sandbox_mode = workspace-write` Users can still change `/approvals` afterward. Config-load behavior stays intentionally narrow: - plain `smart_approvals = true` in `config.toml` remains just the rollout/UI gate and does not auto-set `approvals_reviewer` - the deprecated `guardian_approval = true` alias migration does backfill `approvals_reviewer = "guardian_subagent"` in the same scope when that reviewer is not already configured there, so old configs preserve their original guardian-enabled behavior ARC remains a separate safety check. For MCP tool approvals, ARC escalations now flow into the configured reviewer instead of always bypassing guardian and forcing manual review. ## Config stability The runtime reviewer override is stable, but the config-backed app-server protocol shape is still settling. - `thread/start`, `thread/resume`, and `turn/start` keep stable `approvalsReviewer` overrides - the config-backed `approvals_reviewer` exposure returned via `config/read` (including profile-level config) is now marked `[UNSTABLE]` / experimental in the app-server protocol until we are more confident in that config surface ## App-server surface This PR intentionally keeps the guardian app-server shape narrow and temporary. It adds generic unstable lifecycle notifications: - `item/autoApprovalReview/started` - `item/autoApprovalReview/completed` with payloads of the form: - `{ threadId, turnId, targetItemId, review, action? }` `review` is currently: - `{ status, riskScore?, riskLevel?, rationale? }` - where `status` is one of `inProgress`, `approved`, `denied`, or `aborted` `action` carries the guardian action summary payload from core when available. This lets clients render temporary standalone pending-review UI, including parallel reviews, even when the underlying tool item has not been emitted yet. These notifications are explicitly documented as `[UNSTABLE]` and expected to change soon. This PR does **not** persist guardian review state onto `thread/read` tool items. The intended follow-up is to attach guardian review state to the reviewed tool item lifecycle instead, which would improve consistency with manual approvals and allow thread history / reconnect flows to replay guardian review state directly. ## TUI behavior - `/experimental` exposes the rollout gate as `Smart Approvals` - enabling it in the TUI enables the feature and switches the current session to the matching Smart Approvals `/approvals` mode - disabling it in the TUI clears the persisted `approvals_reviewer` override when appropriate and returns the session to default manual review when the effective reviewer changes - `/approvals` still exposes the reviewer choice directly - the TUI renders: - pending guardian review state in the live status footer, including parallel review aggregation - resolved approval/denial state in history ## Scope notes This PR includes the supporting core/runtime work needed to make Smart Approvals usable end-to-end: - shell / unified-exec / apply_patch / managed-network / MCP guardian review - delegated/subagent approval routing into guardian review - guardian review risk metadata and action summaries for app-server/TUI - config/profile/TUI handling for `smart_approvals`, `guardian_approval` alias migration, and `approvals_reviewer` - a small internal cleanup of delegated approval forwarding to dedupe fallback paths and simplify guardian-vs-parent approval waiting (no intended behavior change) Out of scope for this PR: - redesigning the existing manual approval protocol shapes - persisting guardian review state onto app-server `ThreadItem`s - delegated MCP elicitation auto-review (the current delegated MCP guardian shim only covers the legacy `RequestUserInput` path) --------- Co-authored-by: Codex <noreply@openai.com>Charley Cunningham ·
2026-03-13 15:27:00 -07:00 -
fix(tui): preserve URL clickability across all TUI views (#12067)
## Problem Long URLs containing `/` and `-` characters are split across multiple terminal lines by `textwrap`'s default hyphenation rules. This breaks terminal link detection: emulators can no longer identify the URL as clickable, and copy-paste yields a truncated fragment. The issue affects every view that renders user or agent text — exec output, history cells, markdown, the app-link setup screen, and the VT100 scrollback path. A secondary bug compounds the first: `desired_height()` calculations count logical lines rather than viewport rows. When a URL overflows its line and wraps visually, the height budget is too small, causing content to clip or leave gaps. Here is how the complete URL is interpreted by the terminal before (first line only) and after (complete URL): | Before | After | |---|---| | <img width="777" height="1002" alt="Screenshot 2026-02-17 at 7 59 11 PM" src="https://github.com/user-attachments/assets/193a89a0-7e56-49c5-8b76-53499a76e7e3" /> | <img width="777" height="1002" alt="Screenshot 2026-02-17 at 7 58 40 PM" src="https://github.com/user-attachments/assets/0b9b4c14-aafb-439f-9ffe-f6bba556f95e" /> | ## Mental model The TUI now treats URL-like tokens as atomic units that must never be split by the wrapping engine. Every call site that previously used `word_wrap_*` has been migrated to `adaptive_wrap_*`, which inspects each line for URL-like tokens and switches wrapping strategy accordingly: - **Non-URL lines** follow the existing `textwrap` path unchanged (word boundaries, optional indentation, hyphenation). - **URL-only lines** (with at most decorative markers like `│`, `-`, `1.`) are emitted unwrapped so terminal link detection works; ratatui's `Wrap { trim: false }` handles the final character wrap at render time. - **Mixed lines** (URL + substantive non-URL prose) flow through `adaptive_wrap_line` so prose wraps naturally at word boundaries while URL tokens remain unsplit. Height measurement everywhere now delegates to `Paragraph::line_count(width)`, which accounts for the visual row cost of overflowed lines. This single source of truth replaces ad-hoc line counting in individual cells. For terminal scrollback (the VT100 path that prints history when the TUI exits), URL-only lines are emitted unwrapped so the terminal's own link detector can find them. Mixed URL+prose lines use adaptive wrapping so surrounding text wraps naturally. Continuation rows are pre-cleared to avoid stale content artifacts. ## Non-goals - Full RFC 3986 URL parsing. The detector is a conservative heuristic that covers `scheme://host`, bare domains (`example.com/path`), `localhost:port`, and IPv4 hosts. IPv6 (`[::1]:8080`) and exotic schemes are intentionally excluded from v1. - Changing wrapping behavior for non-URL content. - Reflowing or reformatting existing terminal scrollback on resize. ## Tradeoffs | Decision | Upside | Downside | |----------|--------|----------| | Heuristic URL detection vs. full parser | Fast, zero-alloc on the hot path; conservative enough to reject file paths like `src/main.rs` | False negatives on obscure URL formats (they get split as before) | | Adaptive (three-path) wrapping | Non-URL lines are untouched — no behavior change, no perf cost; mixed lines wrap prose naturally while preserving URLs | Three wrapping strategies to reason about when debugging layout | | Row-based truncation with line-unit ellipsis | Accurate viewport budget; stable "N lines omitted" count across terminal widths | `truncate_lines_middle` is more complex (must compute per-line row cost) | | Unwrapped URL-only lines in scrollback | Terminal emulators detect clickable links; copy-paste gets the full URL | TUI and scrollback formatting diverge for URL-only lines | | Default `desired_height` via `Paragraph::line_count` | DRY — most cells inherit correct measurement | Cells with custom layout must remember to override | ## Architecture ```mermaid flowchart TD A["adaptive_wrap_*()"] --> B{"line_contains_url_like?"} B -- No URL tokens --> C["word_wrap_line<br/>(textwrap default)"] B -- Has URL tokens --> D{"mixed URL + prose?"} D -- "URL-only<br/>(+ decorative markers)" --> E["emit unwrapped<br/>(terminal char-wraps)"] D -- "Mixed<br/>(URL + substantive text)" --> F["adaptive_wrap_line<br/>(AsciiSpace + custom WordSplitter)"] C --> G["Paragraph::line_count(w)<br/>(single height truth)"] E --> G F --> G ``` **Changed files:** | File | Role | |------|------| | `wrapping.rs` | URL detection heuristics, mixed-line detection, `adaptive_wrap_*` functions, custom `WordSplitter` | | `exec_cell/render.rs` | Row-aware `truncate_lines_middle`, adaptive wrapping for command/output display | | `history_cell.rs` | Migrate all cell types to `adaptive_wrap_*`; default `desired_height` via `Paragraph::line_count` | | `insert_history.rs` | Three-path scrollback wrapping (unwrapped URL-only, adaptive mixed, word-wrapped text); continuation row clearing | | `app_link_view.rs` | Adaptive wrapping for setup URL; `desired_height` via `Paragraph::line_count` | | `markdown_render.rs` | Adaptive wrapping in `finish_paragraph` | | `model_migration.rs` | Viewport-aware wrapping for narrow-pane markdown | | `pager_overlay.rs` | `Wrap { trim: false }` for transcript and streaming chunks | | `queued_user_messages.rs` | Migrate to `adaptive_wrap_lines` | | `status/card.rs` | Migrate to `adaptive_wrap_lines` | ## Observability - **Ellipsis message** in truncated exec output reports omitted count in logical lines (stable across resize) rather than viewport rows (fluctuates). - URL detection is deterministic and stateless — no hidden caching or memoization to go stale. - Height mismatch bugs surface immediately as visual clipping or gaps; the `Paragraph::line_count` path is the same code ratatui uses at render time, so measurement and rendering cannot diverge. ## Tests 26 new unit tests across 7 files, covering: - **URL integrity**: assert a URL-like token appears on exactly one rendered line (not split across two). - **Height accuracy**: compare `desired_height()` against `Paragraph::line_count()` for URL-containing content. - **Row-aware truncation**: verify ellipsis counts logical lines and output fits within the row budget. - **Scrollback rendering**: VT100 backend tests confirm prefix and URL land on the same row; continuation rows are cleared; mixed URL+prose lines wrap prose while preserving URL tokens. - **Mixed URL+prose detection**: `line_has_mixed_url_and_non_url_tokens` correctly distinguishes lines with substantive non-URL text from lines with only decorative markers alongside a URL. - **Heuristic correctness**: positive matches (`https://...`, `example.com/path`, `localhost:3000/api`, `192.168.1.1:8080/health`) and negative matches (`src/main.rs`, `foo/bar`, `hello-world`). ## Risks and open items 1. **URL-like tokens in code output** (e.g. `example.com/api` inside a JSON blob) will trigger URL-preserving wrap on that line. This is acceptable — the worst case is a slightly wider line, not broken output. 2. **Very long non-URL tokens on a URL line** can only break at character boundaries (the custom splitter emits all char indices for non-URL words). On extremely narrow terminals this could overflow, but narrow terminals already degrade gracefully. 3. **No IPv6 support** — `[::1]:8080/path` will be treated as a non-URL and may get split. Can be added later without API changes. Fixes #5457
Felipe Coury ·
2026-02-21 15:31:41 -08:00 -
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`Michael Bolin ·
2026-02-20 23:45:35 -08:00 -
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`Charley Cunningham ·
2026-02-10 18:53:43 -08:00 -
feat(tui): pace catch-up stream chunking with hysteresis (#10461)
## Summary - preserve baseline streaming behavior (smooth mode still commits one line per 50ms tick) - extract adaptive chunking policy and commit-tick orchestration from ChatWidget into `streaming/chunking.rs` and `streaming/commit_tick.rs` - add hysteresis-based catch-up behavior with bounded batch draining to reduce queue lag without bursty single-frame jumps - document policy behavior, tuning guidance, and debug flow in rustdoc + docs ## Testing - just fmt - cargo test -p codex-tui
Josh McKinney ·
2026-02-03 15:01:51 -08:00 -
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>
SlKzᵍᵐ ·
2026-01-18 04:10:24 +00:00 -
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.
Chriss4123 ·
2026-01-13 03:06:11 +00:00 -
Add vim navigation keys to transcript pager (#7550)
## Summary - add vim-style pager navigation for transcript overlays (j/k, ctrl+f/b/d/u) without removing existing keys - add shift-space to page up ------ [Codex Task](https://chatgpt.com/codex/tasks/task_i_69309d26da508329908b2dc8ca40afb7)
Josh McKinney ·
2025-12-09 10:23:11 -08:00 -
Fix transcript pager page continuity (#7363)
## What Fix PageUp/PageDown behaviour in the Ctrl+T transcript overlay so that paging is continuous and reversible, and add tests to lock in the expected behaviour. ## Why Today, paging in the transcript overlay uses the raw viewport height instead of the effective content height after layout. Because the overlay reserves some rows for chrome (header/footer), this can cause: - PageDown to skip transcript lines between pages. - PageUp/PageDown not to “round-trip” cleanly (PageDown then PageUp does not always return to the same set of visible lines). This shows up when inspecting longer transcripts via Ctrl+T; see #7356 for context. ## How - Add a dedicated `PagerView::page_step` helper that computes the page size from the last rendered content height and falls back to `content_area(viewport_area).height` when that is not yet available. - Use `page_step(...)` for both PageUp and PageDown (including SPACE) so the scroll step always matches the actual content area height, not the full viewport height. - Add a focused test `transcript_overlay_paging_is_continuous_and_round_trips` that: - Renders a synthetic transcript with numbered `line-NN` rows. - Asserts that successive PageDown operations show continuous line numbers (no gaps). - Asserts that PageDown+PageUp and PageUp+PageDown round-trip correctly from non-edge offsets. The change is limited to `codex-rs/tui/src/pager_overlay.rs` and only affects the transcript overlay paging semantics. ## Related issue - #7356 ## Testing On Windows 11, using PowerShell 7 in the repo root: ```powershell cargo test cargo clippy --tests cargo fmt -- --config imports_granularity=Item ``` - All tests passed. - `cargo clippy --tests` reported some pre-existing warnings that are unrelated to this change; no new lints were introduced in the modified code. --------- Signed-off-by: muyuanjin <24222808+muyuanjin@users.noreply.github.com> Co-authored-by: Eric Traut <etraut@openai.com>
muyuanjin ·
2025-12-08 18:45:20 -08:00 -
Remove test from #7481 that doesn't add much value (#7558)
Follow-up from PR #7481
Eric Traut ·
2025-12-03 19:10:54 -08:00 -
fix: wrap long exec lines in transcript overlay (#7481)
What ----- - Fix the Ctrl+T transcript overlay so that very long exec output lines are soft‑wrapped to the viewport width instead of being rendered as a single truncated row. - Add a regression test to `TranscriptOverlay` to ensure long exec outputs are rendered on multiple lines in the overlay. Why ---- - Previously, the transcript overlay rendered extremely long single exec lines as one on‑screen row and simply cut them off at the right edge, with no horizontal scrolling. - This made it impossible to inspect the full content of long tool/exec outputs in the transcript view, even though the main TUI view already wrapped those lines. - Fixes #7454. How ---- - Update `ExecCell::transcript_lines` to wrap exec output lines using the existing `RtOptions`/`word_wrap_line` helpers so that transcript rendering is width‑aware. - Reuse the existing line utilities to expand the wrapped `Line` values into the transcript overlay, preserving styling while respecting the current viewport width. - Add `transcript_overlay_wraps_long_exec_output_lines` test in `pager_overlay.rs` that constructs a long single‑line exec output, renders the transcript overlay into a small buffer, and asserts that the long marker string spans multiple rendered lines.
muyuanjin ·
2025-12-03 16:45:08 -08:00 -
Added feature switch to disable animations in TUI (#6870)
This PR adds support for a new feature flag `tui.animations`. By default, the TUI uses animations in its welcome screen, "working" spinners, and "shimmer" effects. This animations can interfere with screen readers, so it's good to provide a way to disable them. This change is inspired by [a PR](https://github.com/openai/codex/pull/4014) contributed by @Orinks. That PR has faltered a bit, but I think the core idea is sound. This version incorporates feedback from @aibrahim-oai. In particular: 1. It uses a feature flag (`tui.animations`) rather than the unqualified CLI key `no-animations`. Feature flags are the preferred way to expose boolean switches. They are also exposed via CLI command switches. 2. It includes more complete documentation. 3. It disables a few animations that the other PR omitted.
Eric Traut ·
2025-11-20 10:40:08 -08:00 -
feat: better UI for unified_exec (#6515)
<img width="376" height="132" alt="Screenshot 2025-11-12 at 17 36 22" src="https://github.com/user-attachments/assets/ce693f0d-5ca0-462e-b170-c20811dcc8d5" />
jif-oai ·
2025-11-14 16:31:12 +01:00 -
feature: Add "!cmd" user shell execution (#2471)
feature: Add "!cmd" user shell execution This change lets users run local shell commands directly from the TUI by prefixing their input with ! (e.g. !ls). Output is truncated to keep the exec cell usable, and Ctrl-C cleanly interrupts long-running commands (e.g. !sleep 10000). **Summary of changes** - Route Op::RunUserShellCommand through a dedicated UserShellCommandTask (core/src/tasks/user_shell.rs), keeping the task logic out of codex.rs. - Reuse the existing tool router: the task constructs a ToolCall for the local_shell tool and relies on ShellHandler, so no manual MCP tool lookup is required. - Emit exec lifecycle events (ExecCommandBegin/ExecCommandEnd) so the TUI can show command metadata, live output, and exit status. **End-to-end flow** **TUI handling** 1. ChatWidget::submit_user_message (TUI) intercepts messages starting with !. 2. Non-empty commands dispatch Op::RunUserShellCommand { command }; empty commands surface a help hint. 3. No UserInput items are created, so nothing is enqueued for the model. **Core submission loop** 4. The submission loop routes the op to handlers::run_user_shell_command (core/src/codex.rs). 5. A fresh TurnContext is created and Session::spawn_user_shell_command enqueues UserShellCommandTask. **Task execution** 6. UserShellCommandTask::run emits TaskStartedEvent, formats the command, and prepares a ToolCall targeting local_shell. 7. ToolCallRuntime::handle_tool_call dispatches to ShellHandler. **Shell tool runtime** 8. ShellHandler::run_exec_like launches the process via the unified exec runtime, honoring sandbox and shell policies, and emits ExecCommandBegin/End. 9. Stdout/stderr are captured for the UI, but the task does not turn the resulting ToolOutput into a model response. **Completion** 10. After ExecCommandEnd, the task finishes without an assistant message; the session marks it complete and the exec cell displays the final output. **Conversation context** - The command and its output never enter the conversation history or the model prompt; the flow is local-only. - Only exec/task events are emitted for UI rendering. **Demo video** https://github.com/user-attachments/assets/fcd114b0-4304-4448-a367-a04c43e0b996Abhishek Bhardwaj ·
2025-10-29 00:31:20 -07:00 -
tui: show aggregated output in display (#5539)
This shows the aggregated (stdout + stderr) buffer regardless of exit code. Many commands output useful / relevant info on stdout when returning a non-zero exit code, or the same on stderr when returning an exit code of 0. Often, useful info is present on both stdout AND stderr. Also, the model sees both. So it is confusing to see commands listed as "(no output)" that in fact do have output, just on the stream that doesn't match the exit status, or to see some sort of trivial output like "Tests failed" but lacking any information about the actual failure. As such, always display the aggregated output in the display. Transcript mode remains unchanged as it was already displaying the text that the model sees, which seems correct for transcript mode.
Jeremy Rose ·
2025-10-23 08:05:08 -07:00 -
tui: /diff mode wraps long lines (#4891)
fixes a regression that stopped long lines from being wrapped when viewing `/diff`.
Jeremy Rose ·
2025-10-09 14:01:45 -07:00 -
tui: fix wrapping in user approval decisions (#5008)
before: <img width="706" height="71" alt="Screenshot 2025-10-09 at 10 20 57 AM" src="https://github.com/user-attachments/assets/ff758b77-4e64-4736-b867-7ebf596e4e65" /> after: <img width="706" height="71" alt="Screenshot 2025-10-09 at 10 20 35 AM" src="https://github.com/user-attachments/assets/6a44efc0-d9ee-40ce-a709-cce969d6e3b3" />
Jeremy Rose ·
2025-10-09 10:37:13 -07:00 -
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" />
Jeremy Rose ·
2025-10-07 16:18:48 -07:00 -
normalize key hints (#4586)
render key hints the same everywhere. | Before | After | |--------|-------| | <img width="816" height="172" alt="Screenshot 2025-10-01 at 5 15 42 PM" src="https://github.com/user-attachments/assets/f88d5db4-04bb-4e89-b571-568222c41e4b" /> | <img width="672" height="137" alt="Screenshot 2025-10-01 at 5 13 56 PM" src="https://github.com/user-attachments/assets/1fee6a71-f313-4620-8d9a-10766dc4e195" /> | | <img width="816" height="172" alt="Screenshot 2025-10-01 at 5 17 01 PM" src="https://github.com/user-attachments/assets/5170ab35-88b7-4131-b485-ecebea9f0835" /> | <img width="816" height="174" alt="Screenshot 2025-10-01 at 5 14 24 PM" src="https://github.com/user-attachments/assets/6b6bc64c-25b9-4824-b2d7-56f60370870a" /> | | <img width="816" height="172" alt="Screenshot 2025-10-01 at 5 17 29 PM" src="https://github.com/user-attachments/assets/2313b36a-e0a8-4cd2-82be-7d0fe7793c19" /> | <img width="816" height="134" alt="Screenshot 2025-10-01 at 5 14 37 PM" src="https://github.com/user-attachments/assets/e18934e8-8e9d-4f46-9809-39c8cb6ee893" /> | | <img width="816" height="172" alt="Screenshot 2025-10-01 at 5 17 40 PM" src="https://github.com/user-attachments/assets/0cc69e4e-8cce-420a-b3e4-be75a7e2c8f5" /> | <img width="816" height="134" alt="Screenshot 2025-10-01 at 5 14 56 PM" src="https://github.com/user-attachments/assets/329a5121-ae4a-4829-86e5-4c813543770c" /> |
Jeremy Rose ·
2025-10-02 18:34:47 +00:00 -
rework patch/exec approval UI (#4573)
| Scenario | Screenshot | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | | short patch | <img width="1096" height="533" alt="short patch" src="https://github.com/user-attachments/assets/8a883429-0965-4c0b-9002-217b3759b557" /> | | short command | <img width="1096" height="533" alt="short command" src="https://github.com/user-attachments/assets/901abde8-2494-4e86-b98a-7cabaf87ca9c" /> | | long patch | <img width="1129" height="892" alt="long patch" src="https://github.com/user-attachments/assets/fa799a29-a0d6-48e6-b2ef-10302a7916d3" /> | | long command | <img width="1096" height="892" alt="long command" src="https://github.com/user-attachments/assets/11ddf79b-98cb-4b60-ac22-49dfa7779343" /> | | viewing complete patch | <img width="1129" height="892" alt="viewing complete patch" src="https://github.com/user-attachments/assets/81666958-af94-420e-aa66-b60d0a42b9db" /> |
Jeremy Rose ·
2025-10-01 14:29:05 -07:00 -
Show exec output on success with trimmed display (#4113)
- Refactor Exec Cell into its own module - update exec command rendering to inline the first command line - limit continuation lines - always show trimmed output
Ahmed Ibrahim ·
2025-09-26 07:13:44 -07:00 -
Fix pager overlay clear between pages (#3952)
should fix characters sometimes hanging around while scrolling the transcript.
Jeremy Rose ·
2025-09-22 15:12:29 -07:00 -
chore: clippy on redundant closure (#4058)
Add redundant closure clippy rules and let Codex fix it by minimising FQP
jif-oai ·
2025-09-22 19:30:16 +00:00 -
Jeremy Rose ·
2025-09-18 20:55:53 +00:00 -
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.
Ahmed Ibrahim ·
2025-09-15 03:39:36 +00:00 -
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.
Jeremy Rose ·
2025-09-13 19:23:14 -07:00 -
syntax-highlight bash lines (#3142)
i'm not yet convinced i have the best heuristics for what to highlight, but this feels like a useful step towards something a bit easier to read, esp. when the model is producing large commands. <img width="669" height="589" alt="Screenshot 2025-09-03 at 8 21 56 PM" src="https://github.com/user-attachments/assets/b9cbcc43-80e8-4d41-93c8-daa74b84b331" /> also a fairly significant refactor of our line wrapping logic.
Jeremy Rose ·
2025-09-05 14:10:32 +00:00 -
tui: pager pins scroll to bottom (#3167)
when the pager is scrolled to the bottom of the buffer, keep it there. this should make transcript mode feel a bit more "alive". i've also seen some confusion about what transcript mode does/doesn't show that i think has been related to it not pinning scroll.
Jeremy Rose ·
2025-09-04 11:50:49 -07:00 -
prefer ratatui Stylized for constructing lines/spans (#3068)
no functional change, just simplifying ratatui styling and adding guidance in AGENTS.md for future.
Jeremy Rose ·
2025-09-02 23:19:54 +00:00 -
Cache transcript wraps (#2739)
Previously long transcripts would become unusable.
easong-openai ·
2025-08-26 22:20:09 -07:00 -
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.
Jeremy Rose ·
2025-08-27 00:03:11 +00:00