From 8a7a723dcd670fed88c4a7363b397e3303faf26d Mon Sep 17 00:00:00 2001 From: Joe Savona Date: Tue, 10 Nov 2026 23:19:10 +0000 Subject: [PATCH] Keep TUI status content separate from composer hints (#60680) ## Why Composer hints could replace configured status content, and mode indicators and warnings reduced the width available to status extensions. ## What changed - Give enabled status content a dedicated area below the composer in both inline and fullscreen layouts, preserving it during transient hint states. - Keep shortcuts, queue hints, mode indicators, and warnings in the hint row. - Measure extension status content at the full available width, allowing up to four rows while yielding space to the composer when height is limited. - Suppress composer hints behind centered dialogs. ## Testing Update layout assertions and snapshots for status persistence, extension resizing and clipping, warning placement, and reasoning-effort transitions. GitOrigin-RevId: f11c2e4fb53c35b69c2fbdbe80cef31bb28faca4 --- ...tests__automatic_thread_title_pending.snap | 3 +- ...s__manual_rename_cancels_thread_title.snap | 3 +- .../src/app/tests/active_reconnect_tests.rs | 5 +- .../src/app/tests/agents_navigation_tests.rs | 2 +- .../tui/src/app/tests/disconnect_tests.rs | 6 +- .../tui/src/app/tests/new_session_tests.rs | 5 +- ...s__active_reconnect__reconnect_failed.snap | 3 +- ...tive_reconnect__restored_conversation.snap | 3 +- ..._tests__backend_banner_after_fallback.snap | 1 + ...__backend_banner_fallback_unavailable.snap | 1 + ...sts__command_center_new_draft_handoff.snap | 4 +- ...ers_after_returning_to_a_running_turn.snap | 1 + ...app__tests__disconnect__offline_draft.snap | 1 + ...onnect__rejected_startup_reconnecting.snap | 1 + ...partial_completed_after_thread_switch.snap | 2 + ...cle_requests__cloud_composer_receipts.snap | 6 +- .../src/app/tests/startup_defaults_tests.rs | 3 +- codex-rs/tui/src/bottom_pane/chat_composer.rs | 47 ++--- .../chat_composer/composer_layout.rs | 36 ++-- .../bottom_pane/chat_composer/footer_state.rs | 29 ++- .../chat_composer/mentions_layout_tests.rs | 4 +- ...nd_hides_retained_command_suggestions.snap | 5 +- ...e__tests__transcript_find_copy_footer.snap | 1 + ...tests__mention_scopes_overlay_history.snap | 2 +- ...ft_by_the_mode_indicator_after_resize.snap | 10 - ...ce__tests__fullscreen_plan_cycle_hint.snap | 4 +- ...tests__persistent_status_and_messages.snap | 16 +- ...rface__tests__slash_popup_footer_wide.snap | 4 +- .../chat_composer/status_surface.rs | 192 ++++++------------ .../chat_composer/status_surface_tests.rs | 132 ++++++------ .../chat_composer/warning_notice.rs | 2 +- .../bottom_pane/chat_composer_effort_tests.rs | 20 +- codex-rs/tui/src/bottom_pane/footer.rs | 12 +- .../src/bottom_pane/footer/footer_content.rs | 15 +- codex-rs/tui/src/bottom_pane/mod.rs | 4 +- ..._transition_keeps_the_full_footer_row.snap | 3 +- ...oser__tests__agents_navigation_status.snap | 4 +- ...ooter_mode_shell_command_absorbs_bang.snap | 4 +- ...shell_command_escape_exits_empty_mode.snap | 3 +- .../realtime/recording_controls_tests.rs | 1 - ..._renders_the_main_conversation_states.snap | 6 + ..._review_denied_renders_denied_request.snap | 2 +- ...w_timed_out_renders_timed_out_request.snap | 2 +- ...artup_failure_renders_warning_history.snap | 2 +- ...exec_and_status_layout_vt100_snapshot.snap | 4 +- ...i__chatwidget__tests__chatwidget_tall.snap | 2 +- ...compact_queues_user_messages_snapshot.snap | 2 +- ...chatwidget__tests__compaction_running.snap | 1 + ...get__tests__compaction_running_narrow.snap | 1 + ...h_output_flushes_immediately_snapshot.snap | 2 + ...hook_output_survives_restart_snapshot.snap | 1 + ...eted_turn_clears_visible_running_hook.snap | 2 + ...__tests__connector_scope_invalidation.snap | 1 + ...custom_model_display_name_status_line.snap | 1 + ...hidden_after_provider_settings_change.snap | 3 +- ..._tests__daybreak_refusal_parent_owned.snap | 1 + ...dget__tests__declined_tool_suggestion.snap | 1 + ...sts__esc_interrupt_goal_paused_footer.snap | 3 +- ..._interrupt_goal_paused_footer@windows.snap | 3 +- ..._approved_exec_is_hidden_from_history.snap | 2 +- ...issions_clears_status_without_history.snap | 2 +- ...ec_renders_warning_and_denied_request.snap | 2 +- ...goal_continuation_drops_stale_reviews.snap | 1 + ...allel_reviews_render_aggregate_status.snap | 1 + ...renders_warning_and_timed_out_request.snap | 2 +- ...s__guardian_write_stdin_review_status.snap | 1 + ...ts__hidden_shell_paste_queued_preview.snap | 1 + ..._hook_runs_while_exec_active_snapshot.snap | 3 + ...tests__image_preparation_disconnected.snap | 1 + ...pted_turn_clears_visible_running_hook.snap | 2 + ...ng_hook_below_background_activity_row.snap | 2 + ...s__manual_thread_name_status_surfaces.snap | 3 +- ...et__tests__mcp_startup_header_booting.snap | 1 + ...isalignment_turn_end_cleared_composer.snap | 1 + ...g_hooks_share_background_activity_row.snap | 2 + ...__overlapping_hook_live_cell_snapshot.snap | 4 + ...atwidget__tests__quick_dial_shortcuts.snap | 2 + ...et__tests__quick_dial_shortcuts_empty.snap | 2 + ...t__tests__quick_dial_shortcuts_narrow.snap | 2 + ...a_restores_recreated_status_indicator.snap | 1 + ..._tests__reasoning_shortcut_max_footer.snap | 1 + ...s__reasoning_shortcut_max_plan_footer.snap | 3 +- ...t__tests__renamed_thread_footer_title.snap | 1 + ...get__tests__replayed_in_progress_turn.snap | 1 + ..._review_queues_user_messages_snapshot.snap | 2 +- ...g_hooks_share_background_activity_row.snap | 2 + ...get__tests__session_end_hook_activity.snap | 3 + ...ion_end_hook_activity_without_message.snap | 3 + ...e_context_label_preserves_status_line.snap | 3 +- ..._side_context_label_shows_hidden_side.snap | 3 +- ...ide_context_label_shows_parent_status.snap | 1 + ...ine_final_answer_hides_working_status.snap | 2 +- ...e_partial_answer_keeps_working_status.snap | 2 +- ...rked_side_question_while_task_running.snap | 3 +- ...tus_line_estimated_thread_cost_footer.snap | 1 + ...__tests__status_line_fast_mode_footer.snap | 1 + ..._line_goal_active_token_budget_footer.snap | 3 +- ...tus_line_goal_complete_elapsed_footer.snap | 3 +- ...th_reasoning_context_remaining_footer.snap | 1 + ...line_model_with_reasoning_fast_footer.snap | 1 + ...model_with_reasoning_plan_mode_footer.snap | 3 +- ...atwidget__tests__status_widget_active.snap | 1 + ...ed_exec_begin_restores_working_status.snap | 1 + ...renders_command_in_single_details_row.snap | 1 + ...sts__voice_live_transcript_and_stream.snap | 1 + ...ests__voice_partial_transcript_hidden.snap | 1 + ...ts__windows_sandbox_setup_fresh_clock.snap | 1 + codex-rs/tui/src/chatwidget/tests/guardian.rs | 10 +- codex-rs/tui/src/chatwidget/tests/helpers.rs | 2 +- .../src/chatwidget/tests/quick_dials_tests.rs | 1 + codex-rs/tui/src/chatwidget/tests/side.rs | 5 +- .../src/chatwidget/tests/slash_commands.rs | 6 +- ...ackend_banner_information_dismissible.snap | 1 + ...ests__backend_banner_information_only.snap | 1 + ...rs_tests__backend_banner_notification.snap | 1 + ...sage_tests__luna_reserve_usage_narrow.snap | 2 +- ...age_tests__luna_reserve_usage_running.snap | 3 +- ..._usage_tests__luna_reserve_usage_wide.snap | 2 +- ...uestion_turn_end_keeps_history_search.snap | 1 + ...up_tests__security_setup_after_cutoff.snap | 1 + ...s__security_setup_after_persona_grace.snap | 1 + ...ty_setup_tests__security_setup_banner.snap | 1 + ..._security_setup_dismissed_after_usage.snap | 1 + ...ash_commands__transcript_copy_success.snap | 1 + ...commands__transcript_copy_unconfirmed.snap | 1 + .../src/chatwidget/tests/status_and_layout.rs | 6 +- ..._tests__selected_unloaded_subagent_V1.snap | 3 +- ..._tests__selected_unloaded_subagent_V2.snap | 3 +- ...ver_session__tests__resumed_plan_mode.snap | 3 +- ...__layout__tests__owned_startup_layout.snap | 4 +- 130 files changed, 405 insertions(+), 382 deletions(-) delete mode 100644 codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__extension_layout_uses_the_width_left_by_the_mode_indicator_after_resize.snap diff --git a/codex-rs/tui/src/app/snapshots/codex_tui__app__thread_title__tests__automatic_thread_title_pending.snap b/codex-rs/tui/src/app/snapshots/codex_tui__app__thread_title__tests__automatic_thread_title_pending.snap index 79485985f2..81b1335186 100644 --- a/codex-rs/tui/src/app/snapshots/codex_tui__app__thread_title__tests__automatic_thread_title_pending.snap +++ b/codex-rs/tui/src/app/snapshots/codex_tui__app__thread_title__tests__automatic_thread_title_pending.snap @@ -7,4 +7,5 @@ terminal title: project footer: › Ask Codex to do anything - gpt-5.2 default · /tmp/project · ← for agents + gpt-5.2 default · /tmp/project + ← for agents · ? for shortcuts diff --git a/codex-rs/tui/src/app/snapshots/codex_tui__app__thread_title__tests__manual_rename_cancels_thread_title.snap b/codex-rs/tui/src/app/snapshots/codex_tui__app__thread_title__tests__manual_rename_cancels_thread_title.snap index 5e686a7669..8820294820 100644 --- a/codex-rs/tui/src/app/snapshots/codex_tui__app__thread_title__tests__manual_rename_cancels_thread_title.snap +++ b/codex-rs/tui/src/app/snapshots/codex_tui__app__thread_title__tests__manual_rename_cancels_thread_title.snap @@ -5,4 +5,5 @@ expression: normalize_snapshot_paths(popup) --- › Ask Codex to do anything - gpt-5.2 default · /tmp/project · Keep this title · ← for agents + gpt-5.2 default · /tmp/project · Keep this title + ← for agents · ? for shortcuts diff --git a/codex-rs/tui/src/app/tests/active_reconnect_tests.rs b/codex-rs/tui/src/app/tests/active_reconnect_tests.rs index ab0dfe0fab..e6d3e5cc52 100644 --- a/codex-rs/tui/src/app/tests/active_reconnect_tests.rs +++ b/codex-rs/tui/src/app/tests/active_reconnect_tests.rs @@ -662,7 +662,10 @@ async fn reconnect_exhaustion_and_unknown_initial_thread_stay_offline() -> Resul "reconnect_failed", format!( "{error}\n{}", - render_bottom_popup(&app.chat_widget, /*width*/ 80) + super::disconnect::normalize_reconnect_status(&render_bottom_popup( + &app.chat_widget, + /*width*/ 80 + )) ) ); tokio::time::resume(); diff --git a/codex-rs/tui/src/app/tests/agents_navigation_tests.rs b/codex-rs/tui/src/app/tests/agents_navigation_tests.rs index 5337998121..bc1f0a6e58 100644 --- a/codex-rs/tui/src/app/tests/agents_navigation_tests.rs +++ b/codex-rs/tui/src/app/tests/agents_navigation_tests.rs @@ -30,7 +30,7 @@ async fn agents_navigation_opens_the_command_center_on_every_target() -> Result< let composer = render_bottom_popup(&app.chat_widget, /*width*/ 96); let footer = composer.lines().last().expect("composer footer").trim(); insta::allow_duplicates! { - insta::assert_snapshot!(normalize_snapshot_paths(footer), @"GPT-5.6-Sol default · /tmp/project · ← for agents"); + insta::assert_snapshot!(normalize_snapshot_paths(footer), @"← for agents · ? for shortcuts"); } app.handle_tui_event( &mut tui, diff --git a/codex-rs/tui/src/app/tests/disconnect_tests.rs b/codex-rs/tui/src/app/tests/disconnect_tests.rs index f59ee4c25d..bf811ff6f0 100644 --- a/codex-rs/tui/src/app/tests/disconnect_tests.rs +++ b/codex-rs/tui/src/app/tests/disconnect_tests.rs @@ -17,10 +17,10 @@ use serde_json::json; use tokio::net::TcpListener; use tokio_tungstenite::tungstenite::Message; -fn normalize_reconnect_status(popup: &str) -> String { +pub(super) fn normalize_reconnect_status(popup: &str) -> String { let status = - regex_lite::Regex::new(r"(?m)^[•◦] (Reconnecting to server… )\([\dhms ]+\)").unwrap(); - status.replace(popup, "• ${1}()").into_owned() + regex_lite::Regex::new(r"(?m)^[•◦] (Reconnecting to server…|Reconnect failed — check the endpoint, then relaunch) \([\dhms ]+\)").unwrap(); + normalize_snapshot_paths(status.replace(popup, "• ${1} ()").into_owned()) } #[tokio::test] diff --git a/codex-rs/tui/src/app/tests/new_session_tests.rs b/codex-rs/tui/src/app/tests/new_session_tests.rs index 3d229fa491..5da939cd71 100644 --- a/codex-rs/tui/src/app/tests/new_session_tests.rs +++ b/codex-rs/tui/src/app/tests/new_session_tests.rs @@ -500,10 +500,11 @@ async fn replacement_uses_server_defaults_and_preserves_explicit_launch_settings if explicit == "saved" { let rendered = render_bottom_popup(&app.chat_widget, /*width*/ 140) .replace(&server_config.cwd.display().to_string(), ""); - insta::assert_snapshot!(rendered, @r" + insta::assert_snapshot!(rendered, @" › Ask Codex to do anything - server-model high · · ← for agents + server-model high · + ← for agents · ? for shortcuts "); } if explicit.starts_with("profile_summary") { diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__active_reconnect__reconnect_failed.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__active_reconnect__reconnect_failed.snap index 634c3201d2..12fd1d5ed5 100644 --- a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__active_reconnect__reconnect_failed.snap +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__active_reconnect__reconnect_failed.snap @@ -3,9 +3,10 @@ source: tui/src/app/tests/active_reconnect_tests.rs expression: "format!(\"{error}\\n{}\", render_bottom_popup(&app.chat_widget, 80))" --- Automatic reconnect timed out while connecting to the server. -• Reconnect failed — check the endpoint, then relaunch (0s) +• Reconnect failed — check the endpoint, then relaunch () › Ask Codex to do anything + GPT-5.6-Sol default · /tmp/project ⌃c quit diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__active_reconnect__restored_conversation.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__active_reconnect__restored_conversation.snap index df0ee6c0a1..e97ad3986b 100644 --- a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__active_reconnect__restored_conversation.snap +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__active_reconnect__restored_conversation.snap @@ -4,4 +4,5 @@ expression: "render_bottom_popup(&app.chat_widget, 80)" --- › kept draft - gpt-test default Plan mode (⇧tab to cycle) + gpt-test default + Plan mode (⇧tab to cycle) diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__backend_banner_fallback_tests__backend_banner_after_fallback.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__backend_banner_fallback_tests__backend_banner_after_fallback.snap index 210166676e..3b39591d0d 100644 --- a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__backend_banner_fallback_tests__backend_banner_after_fallback.snap +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__backend_banner_fallback_tests__backend_banner_after_fallback.snap @@ -12,3 +12,4 @@ expression: normalize_snapshot_paths(rendered) › Ask Codex to do anything gpt-5.6-terra medium · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__backend_banner_fallback_tests__backend_banner_fallback_unavailable.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__backend_banner_fallback_tests__backend_banner_fallback_unavailable.snap index bb2bcc2ec1..582b353d19 100644 --- a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__backend_banner_fallback_tests__backend_banner_fallback_unavailable.snap +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__backend_banner_fallback_tests__backend_banner_fallback_unavailable.snap @@ -5,3 +5,4 @@ expression: normalize_snapshot_paths(rendered) › Ask Codex to do anything gpt-5.5 default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__background_task_defaults_tests__command_center_new_draft_handoff.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__background_task_defaults_tests__command_center_new_draft_handoff.snap index 790734914a..0e9dda54bb 100644 --- a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__background_task_defaults_tests__command_center_new_draft_handoff.snap +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__background_task_defaults_tests__command_center_new_draft_handoff.snap @@ -11,16 +11,16 @@ startup: attached: - › draft during startup GPT-6.1-Sol default · /tmp/project + owned=true startup: -› draft during startup +› draft during startup attached: diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__buffered_replay__steers_after_returning_to_a_running_turn.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__buffered_replay__steers_after_returning_to_a_running_turn.snap index 0c93d9a304..f5daac9265 100644 --- a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__buffered_replay__steers_after_returning_to_a_running_turn.snap +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__buffered_replay__steers_after_returning_to_a_running_turn.snap @@ -16,3 +16,4 @@ expression: "normalize_snapshot_paths(render_bottom_popup(&app.chat_widget, 80)) › Ask Codex to do anything gpt-test default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__disconnect__offline_draft.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__disconnect__offline_draft.snap index a3c7c90a91..0da6cc0638 100644 --- a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__disconnect__offline_draft.snap +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__disconnect__offline_draft.snap @@ -14,4 +14,5 @@ expression: "format!(\"{}\\n{}\",\nlines_to_single_string(&app.transcript_cells. › keep this draft! + gpt-test default · /tmp/project ⌃c quit diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__disconnect__rejected_startup_reconnecting.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__disconnect__rejected_startup_reconnecting.snap index 2323fc8472..47b3ce02c7 100644 --- a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__disconnect__rejected_startup_reconnecting.snap +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__disconnect__rejected_startup_reconnecting.snap @@ -7,4 +7,5 @@ expression: "reconnect_status.replace(&render_bottom_popup(&app.chat_widget, 80) › startup draft + GPT-5.6-Sol default · /tmp/project ⌃c quit diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__realtime_requests__voice_partial_completed_after_thread_switch.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__realtime_requests__voice_partial_completed_after_thread_switch.snap index bfd8b46a63..2cee857aa8 100644 --- a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__realtime_requests__voice_partial_completed_after_thread_switch.snap +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__realtime_requests__voice_partial_completed_after_thread_switch.snap @@ -6,6 +6,7 @@ Other task: › Ask Codex to do anything gpt-test default · /tmp/project + ? for shortcuts Restored owner: voice ● listening f9 mute /voice stop mic ▁▁▁▁▁▁ codex ▁▁▁▁▁▁ @@ -13,6 +14,7 @@ Restored owner: › Ask Codex to do anything gpt-test default · /tmp/project + ? for shortcuts >_ OpenAI Codex (v0.0.0) /tmp/project diff --git a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__session_lifecycle_requests__cloud_composer_receipts.snap b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__session_lifecycle_requests__cloud_composer_receipts.snap index b3bda716d2..159cb37685 100644 --- a/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__session_lifecycle_requests__cloud_composer_receipts.snap +++ b/codex-rs/tui/src/app/tests/snapshots/codex_tui__app__tests__session_lifecycle_requests__cloud_composer_receipts.snap @@ -13,6 +13,7 @@ expression: "rendered_receipts.join(\"\\n\\n\")" › Ask Codex to do anything gpt-test default · /tmp/project + ? for shortcuts ── Steered ── ■ Conversation interrupted - use /feedback if something went wrong @@ -31,6 +32,7 @@ expression: "rendered_receipts.join(\"\\n\\n\")" › Ask Codex to do anything gpt-test default · /tmp/project + ? for shortcuts ── Rejected ── ■ reply stream closed before submission @@ -39,7 +41,8 @@ expression: "rendered_receipts.join(\"\\n\\n\")" › follow up - tab to queue message 100% context left + gpt-test default · /tmp/project + tab to queue message ── Duplicate ── ■ Conversation interrupted - use /feedback if something went wrong @@ -50,3 +53,4 @@ expression: "rendered_receipts.join(\"\\n\\n\")" › Ask Codex to do anything gpt-test default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/app/tests/startup_defaults_tests.rs b/codex-rs/tui/src/app/tests/startup_defaults_tests.rs index 5f9c1271c6..349a732708 100644 --- a/codex-rs/tui/src/app/tests/startup_defaults_tests.rs +++ b/codex-rs/tui/src/app/tests/startup_defaults_tests.rs @@ -729,10 +729,11 @@ async fn fresh_startup_reads_destination_and_cleared_model_uses_catalog() -> Res if !remote { let rendered = render_bottom_popup(&app.chat_widget, /*width*/ 80) .replace(&destination.path().display().to_string(), ""); - insta::assert_snapshot!(rendered, @r" + insta::assert_snapshot!(rendered, @" › Ask Codex to do anything GPT-6.1-Sol high · + ? for shortcuts "); } let expected_cwd = if override_cwd { diff --git a/codex-rs/tui/src/bottom_pane/chat_composer.rs b/codex-rs/tui/src/bottom_pane/chat_composer.rs index 56d426bcf0..2ac6da93ac 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer.rs @@ -360,7 +360,6 @@ use super::footer::footer_height; use super::footer::footer_hint_items_width; use super::footer::footer_line_width; use super::footer::inset_footer_hint_area; -use super::footer::max_left_width_for_right; use super::footer::passive_footer_status_line; use super::footer::render_context_right; use super::footer::render_footer_from_props; @@ -371,7 +370,6 @@ use super::footer::side_conversation_context_line; use super::footer::single_line_footer_layout; use super::footer::status_line_right_indicator_line; use super::footer::toggle_shortcut_mode; -use super::footer::uses_passive_footer_status_layout; use super::mention_usage::MentionUsage; use super::mentions_v2::MentionV2Popup; use super::mentions_v2::MentionV2Selection; @@ -397,7 +395,6 @@ use crate::render::RectExt; use crate::render::renderable::Renderable; use crate::slash_command::SlashCommand; use crate::style::user_message_style; -use crate::ui_consts::FOOTER_INDENT_COLS; use codex_protocol::ThreadId; use codex_protocol::user_input::ByteRange; use codex_protocol::user_input::MAX_USER_INPUT_TEXT_CHARS; @@ -911,12 +908,13 @@ impl ChatComposer { let style = IgnitionStyle::random(self.effort_animation_style); self.effort_ignition = Some(EffortIgnition::new(tier, style)); self.effort_animation_style = Some(style); - if self.footer.status_line_enabled - && let Some(FooterContent::HyperlinkLine(previous)) = - passive_footer_status_line(&self.footer_props()) + if let Some(previous) = self.status_surface_content() + && !matches!(previous.as_ref(), FooterContent::Extension { .. }) { - self.effort_status_line_transition = - Some(EffortStatusLineTransition::new(tier, previous)); + self.effort_status_line_transition = Some(EffortStatusLineTransition::new( + tier, + previous.into_owned().into_hyperlink_line(), + )); } if let Some(frame_requester) = &self.frame_requester { frame_requester.schedule_frame(); @@ -4727,7 +4725,7 @@ impl ChatComposer { self.render_transcript_footer(transcript_hint_area, buf, footer, warning_area); } None if self.shortcuts_above_composer(options) => { - let props = self.hint_footer_props(options); + let props = self.hint_footer_props(); super::shortcut_overlay::render(&props, inset_footer_hint_area(popup_rect), buf); super::shortcut_overlay::close_hint(&props, transcript_hint_area.width) .render(transcript_hint_area, buf); @@ -4738,24 +4736,23 @@ impl ChatComposer { input.render(inset_footer_hint_area(hint_rect), buf); } else if let Some(line) = self.history_search_footer_line() { render_footer_line(hint_rect, buf, line); - } else if self.shows_shared_status(options) { - self.render_status_surface(hint_rect, buf, options); } else { - let footer_props = self.hint_footer_props(options); - let show_cycle_hint = !self.has_separate_status(options) + let footer_props = self.hint_footer_props(); + let show_cycle_hint = !self.popup_active() + && !self.blocks_direct_input + && self.draft.input_enabled && !footer_props.is_task_running && self.footer.collaboration_mode_indicator.is_some(); let show_shortcuts_hint = footer_props.mode == FooterMode::ComposerEmpty && !self.is_in_paste_burst(); let show_queue_hint = footer_props.mode == FooterMode::ComposerHasDraft && footer_props.is_task_running; - let status_line_active = uses_passive_footer_status_layout(&footer_props); - let left_mode_indicator = - if status_line_active || self.has_separate_status(options) { - None - } else { - self.footer.collaboration_mode_indicator - }; + let status_line_active = self.footer.status_line_enabled; + let left_mode_indicator = if status_line_active { + None + } else { + self.footer.collaboration_mode_indicator + }; let active_footer_hint_override = self.footer.hint_override.as_ref(); let left_width = if self.footer.flash_visible() { self.footer @@ -4779,8 +4776,6 @@ impl ChatComposer { Some(side_conversation_context_line(label)) } else if let Some(line) = self.shell_mode_footer_line() { Some(line) - } else if self.has_separate_status(options) { - None } else if status_line_active { let full = self.mode_indicator_line(show_cycle_hint); let compact = self.mode_indicator_line(/*show_cycle_hint*/ false); @@ -4798,7 +4793,7 @@ impl ChatComposer { can_show_left_with_context(hint_rect, left_width, right_width); let has_override = self.footer.flash_visible() || active_footer_hint_override.is_some(); - let single_line_layout = if has_override || status_line_active { + let single_line_layout = if has_override { None } else { match footer_props.mode { @@ -4823,7 +4818,9 @@ impl ChatComposer { | FooterMode::ShortcutOverlay => None, } }; - let show_right = if matches!( + let show_right = if has_override && status_line_active { + can_show_left_and_context + } else if matches!( footer_props.mode, FooterMode::EscHint | FooterMode::HistorySearch @@ -4867,7 +4864,7 @@ impl ChatComposer { hint_rect, buf, &footer_props, - self.footer.collaboration_mode_indicator, + left_mode_indicator, show_cycle_hint, show_shortcuts_hint, show_queue_hint, diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/composer_layout.rs b/codex-rs/tui/src/bottom_pane/chat_composer/composer_layout.rs index bf5cffc9cb..8d90ef234b 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/composer_layout.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer/composer_layout.rs @@ -41,26 +41,16 @@ impl ChatComposer { area: Rect, options: ComposerRenderOptions<'_>, ) -> ComposerLayout { - let mut footer_hint_height = self.footer_hint_height(area.width, options); - let mut status_height = self.status_surface_height(area.width, options); - let shared = footer_hint_height > 1 && self.shows_shared_status(options); - if shared || status_height > 1 { - // Extra status rows yield to the draft, voice strip and other composer surfaces. - let desired = - self.height_with_rows(area.width, options, footer_hint_height, status_height); - let rows = if shared { - &mut footer_hint_height - } else { - &mut status_height - }; - *rows = rows - .saturating_sub(desired.saturating_sub(area.height)) - .max(1); - } - let status_height = status_height.min( - area.height - .saturating_sub(footer_hint_height.saturating_add(/*rhs*/ 3)), - ); + let footer_hint_height = self.footer_hint_height(area.width, options); + let wanted = self.status_surface_height(area.width, /*available*/ 4, options); + let desired = self.height_with_rows(area.width, options, footer_hint_height, wanted); + let status_height = wanted + .saturating_sub(desired.saturating_sub(area.height)) + .max(wanted.min(1)) + .min( + area.height + .saturating_sub(footer_hint_height.saturating_add(3)), + ); let status = Rect { y: area .bottom() @@ -90,7 +80,7 @@ impl ChatComposer { let shortcuts_above = self.shortcuts_above_composer(options); let (composer_rect, popup_rect, mut footer_rect) = if shortcuts_above { let [shortcuts, composer, footer] = Layout::vertical([ - Constraint::Max(footer_height(&self.hint_footer_props(options), area.width)), + Constraint::Max(footer_height(&self.hint_footer_props(), area.width)), Constraint::Min(3 + voice_rows), Constraint::Length(footer_hint_height), ]) @@ -213,7 +203,7 @@ impl ChatComposer { width, options, self.footer_hint_height(width, options), - self.status_surface_height(width, options), + self.status_surface_height(width, /*available*/ 4, options), ) } @@ -241,7 +231,7 @@ impl ChatComposer { remote_images_separator, status_height, if self.shortcuts_above_composer(options) { - footer_height(&self.hint_footer_props(options), width) + footer_height(&self.hint_footer_props(), width) } else { 0 }, diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/footer_state.rs b/codex-rs/tui/src/bottom_pane/chat_composer/footer_state.rs index b70e740c3c..3a6479e823 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/footer_state.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer/footer_state.rs @@ -80,8 +80,10 @@ pub(crate) struct ComposerRenderOptions<'a> { pub(crate) working_tip: Option<&'a crate::turn_tip::TurnTip>, pub(crate) warning_count: usize, pub(crate) textarea_right_reserve: u16, - /// Keep configured status below the composer while hints occupy the final row. + /// The host is using the separate fullscreen transcript layout. pub(crate) separate_status_line: bool, + /// A centered dialog owns input while the composer is painted behind it. + pub(crate) is_dialog_backdrop: bool, /// Topmost frame row available for suggestions overlaying the transcript. pub(crate) overlay_top: u16, /// The workspace paints the open Presets menu over the completed frame. @@ -284,8 +286,8 @@ impl super::ChatComposer { } pub(super) fn footer_hint_height(&self, width: u16, options: ComposerRenderOptions<'_>) -> u16 { - if self.shows_shared_status(options) { - return self.status_line_height(width, options); + if options.is_dialog_backdrop { + return 0; } if self.show_warning_notice(options) || self.shortcuts_above_composer(options) { return 1; @@ -295,7 +297,7 @@ impl super::ChatComposer { .map_or_else( || { self.custom_footer_height() - .unwrap_or_else(|| footer_height(&self.hint_footer_props(options), width)) + .unwrap_or_else(|| footer_height(&self.hint_footer_props(), width)) }, |footer| footer.text.height().try_into().unwrap_or(u16::MAX), ) @@ -310,7 +312,11 @@ impl super::ChatComposer { warning_area: Option, ) { let hint_area = warning_notice::before_warning(hint_area, warning_area); + if hint_area.is_empty() { + return; + } let mut text = footer.text.clone(); + text.lines.truncate(usize::from(hint_area.height)); if footer.cursor_column.is_none() && self.footer.flash_visible() && let Some(flash) = &self.footer.flash @@ -335,6 +341,17 @@ impl super::ChatComposer { line.extend(shortcuts.spans); } } + if self.footer.status_line_enabled + && let Some(mode) = self.mode_indicator_line(/*show_cycle_hint*/ false) + && let Some(row) = text + .lines + .get(usize::from(hint_area.height.saturating_sub(1))) + && crate::line_truncation::line_width(row) + 1 + mode.width() + <= usize::from(hint_area.width) + && let Some(bottom_row) = hint_area.rows().next_back() + { + mode.right_aligned().render(bottom_row, buf); + } Paragraph::new(text).render(hint_area, buf); } @@ -365,8 +382,8 @@ pub(super) struct FooterState { pub(super) goal_status_indicator: Option, pub(super) ide_context_active: bool, pub(super) status_line_value: Option, - // Available width and occupied height, shared by layout and cursor placement. - pub(super) measured_status_line: std::cell::Cell>, + // Measurement bounds and occupied height, shared by layout and cursor placement. + pub(super) measured_status_line: std::cell::Cell>, pub(super) status_line_enabled: bool, pub(super) side_conversation_context_label: Option, pub(super) active_agent_label: Option, diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/mentions_layout_tests.rs b/codex-rs/tui/src/bottom_pane/chat_composer/mentions_layout_tests.rs index 897f662f61..6aef24d7bb 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/mentions_layout_tests.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer/mentions_layout_tests.rs @@ -176,10 +176,10 @@ fn mention_menu_reserves_height_above_composer_and_owns_cursor_over_interactive_ composer: surface, textarea, popup, - footer, + status, .. } = composer.layout_with_options(area, options); - assert_eq!((popup.bottom(), surface.bottom()), (surface.y, footer.y)); + assert_eq!((popup.bottom(), surface.bottom()), (surface.y, status.y)); assert_eq!( composer.cursor_pos_with_options(area, options), Some((3, textarea.y)) diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__footer_state__tests__find_hides_retained_command_suggestions.snap b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__footer_state__tests__find_hides_retained_command_suggestions.snap index b0436bc381..826b17fcb8 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__footer_state__tests__find_hides_retained_command_suggestions.snap +++ b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__footer_state__tests__find_hides_retained_command_suggestions.snap @@ -1,6 +1,5 @@ --- source: tui/src/bottom_pane/chat_composer/footer_state_tests.rs -assertion_line: 231 expression: "frames.join(\"\\n\\n\")" --- 60x8, cursor Some((10, 6)) @@ -9,7 +8,7 @@ expression: "frames.join(\"\\n\\n\")" - + MODEL STATUS Find: needle Enter next · Esc close @@ -19,7 +18,7 @@ expression: "frames.join(\"\\n\\n\")" - + MODEL STATUS Find: needle Enter next · Esc close diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__footer_state__tests__transcript_find_copy_footer.snap b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__footer_state__tests__transcript_find_copy_footer.snap index fc52d4617d..1cc9f31ee6 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__footer_state__tests__transcript_find_copy_footer.snap +++ b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__footer_state__tests__transcript_find_copy_footer.snap @@ -5,5 +5,6 @@ expression: text(&buffer) › Ask Codex + MODEL STATUS Find: needle Copied selection to clipboard diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__mentions_layout_tests__mention_scopes_overlay_history.snap b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__mentions_layout_tests__mention_scopes_overlay_history.snap index 966c47dd65..d1ace4fb43 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__mentions_layout_tests__mention_scopes_overlay_history.snap +++ b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__mentions_layout_tests__mention_scopes_overlay_history.snap @@ -12,7 +12,6 @@ Transcript row 06: behind the menu Transcript row 07: behind the menu Transcript row 08: behind the menu Transcript row 09: behind the menu -Transcript row 10: behind the menu Mentions Files, directories, plugins, skills and tasks @@ -33,4 +32,5 @@ Transcript row 10: behind the menu › @ + MODEL STATUS TRANSCRIPT STATUS diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__extension_layout_uses_the_width_left_by_the_mode_indicator_after_resize.snap b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__extension_layout_uses_the_width_left_by_the_mode_indicator_after_resize.snap deleted file mode 100644 index b71c9c9963..0000000000 --- a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__extension_layout_uses_the_width_left_by_the_mode_indicator_after_resize.snap +++ /dev/null @@ -1,10 +0,0 @@ ---- -source: tui/src/bottom_pane/chat_composer/status_surface_tests.rs -expression: shared ---- -16 | Ready PR 12345 -15 | Ready -15 | PR 12345 -16 | Ready PR 12345 -25 | Ready -25 | PR 12345 Plan mode diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__fullscreen_plan_cycle_hint.snap b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__fullscreen_plan_cycle_hint.snap index 833484264f..5b4ce76525 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__fullscreen_plan_cycle_hint.snap +++ b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__fullscreen_plan_cycle_hint.snap @@ -13,5 +13,5 @@ expression: wide › Ask Codex - MODEL · ~/project · Context 20% used Plan mode (⇧tab to cycle) - ? for shortcuts + MODEL · ~/project · Context 20% used + ? for shortcuts Plan mode (⇧tab to cycle) diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__persistent_status_and_messages.snap b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__persistent_status_and_messages.snap index c35c2d93e5..e987e51a51 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__persistent_status_and_messages.snap +++ b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__persistent_status_and_messages.snap @@ -13,8 +13,8 @@ expression: "states.join(\"\\n---\\n\")" › Ask Codex - MODEL · ~/project · Context 20% used Plan mode - ? for shortcuts + MODEL · ~/project · Context 20% used + ? for shortcuts Plan mode (⇧tab to cycle) --- @@ -27,8 +27,8 @@ expression: "states.join(\"\\n---\\n\")" › Ask Codex - MODEL · ~/project · Context 20% used Plan mode - Copied selection + MODEL · ~/project · Context 20% used + Copied selection Plan mode (⇧tab to cycle) --- @@ -41,8 +41,8 @@ expression: "states.join(\"\\n---\\n\")" › Ask Codex - MODEL · ~/project · Context 20% used Plan mode - Ctrl+X waiting for chord + MODEL · ~/project · Context 20% used + Ctrl+X waiting for chord Plan mode (⇧tab to cycle) --- @@ -55,5 +55,5 @@ expression: "states.join(\"\\n---\\n\")" › Continue the task - MODEL · ~/project · Context 20% used Plan mode - tab to queue message + MODEL · ~/project · Context 20% used + tab to queue message Plan mode diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__slash_popup_footer_wide.snap b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__slash_popup_footer_wide.snap index bb446cf9e1..9e9f659dcb 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__slash_popup_footer_wide.snap +++ b/codex-rs/tui/src/bottom_pane/chat_composer/snapshots/codex_tui__bottom_pane__chat_composer__status_surface__tests__slash_popup_footer_wide.snap @@ -1,10 +1,9 @@ --- source: tui/src/bottom_pane/chat_composer/status_surface_tests.rs -assertion_line: 344 expression: "format!(\"{buf:?}\")" --- Buffer { - area: Rect { x: 0, y: 0, width: 80, height: 8 }, + area: Rect { x: 0, y: 0, width: 80, height: 9 }, content: [ " /model choose what model and reasoning effort to use ", "› /memories configure memory use and generation ", @@ -14,6 +13,7 @@ Buffer { "› /m ", " ", " model · high · fast ", + " ", ], styles: [ x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE, diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/status_surface.rs b/codex-rs/tui/src/bottom_pane/chat_composer/status_surface.rs index e735f0fa2c..80ed155772 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/status_surface.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer/status_surface.rs @@ -3,9 +3,8 @@ //! Shortcut help grows above the input, preserving status and close rows below it even when clipped. use super::*; -use ratatui::layout::Size; -const MAX_FOOTER_ROWS: u16 = 4; +use std::borrow::Cow; impl ChatComposer { pub(crate) fn set_status_line(&mut self, status_line: Option) -> bool { @@ -36,61 +35,45 @@ impl ChatComposer { true } - pub(super) fn has_separate_status(&self, options: ComposerRenderOptions<'_>) -> bool { - options.separate_status_line && self.footer.status_line_enabled - } - - pub(super) fn shows_shared_status(&self, options: ComposerRenderOptions<'_>) -> bool { - !options.separate_status_line - && options.footer.is_none() - && self.custom_footer_height().is_none() - && self.footer.status_line_enabled - && self.footer_mode().shows_passive_line(self.is_task_running) - } - pub(super) fn status_surface_height( &self, width: u16, + available: u16, options: ComposerRenderOptions<'_>, ) -> u16 { - if self.has_separate_status(options) { - self.status_line_height(width, options) + // The unfocused composer paints only the raw status, as one dim line. + let (available, status) = if options.unfocused { + let raw = self + .status_line_content() + .filter(|_| self.footer.status_line_enabled); + (available.min(1), raw.map(Cow::Borrowed)) } else { - 0 - } - } - - pub(super) fn status_line_height(&self, width: u16, options: ComposerRenderOptions<'_>) -> u16 { - // The unfocused composer paints one dim status line. - if options.unfocused { - return 1; - } - let Some(FooterContent::Extension { content }) = &self.footer.status_line_value else { - return 1; + (available, self.status_surface_content()) }; - let mut area = Rect::new(/*x*/ 0, /*y*/ 0, width, /*height*/ 1); - if !options.separate_status_line { - let warning = self.warning_notice_layout(inset_footer_hint_area(area), options); - area = warning_notice::before_warning(area, warning.map(|(rect, _)| rect)); + let bounds = inset_footer_hint_area(Rect::new(0, 0, width, available)).as_size(); + if bounds.width == 0 || bounds.height == 0 { + return 0; } - let (_, width) = self.status_line_layout(area, options, content.measure_natural().width); - let cache = &self.footer.measured_status_line; - if let Some((previous_width, height)) = cache.get() - && previous_width == width - { - return height; + match status.as_deref() { + Some(FooterContent::Extension { content }) => { + let cache = &self.footer.measured_status_line; + if let Some((previous, height)) = cache.get() + && previous == bounds + { + return height; + } + let height = content.measure(bounds).height; + cache.set(Some((bounds, height))); + height + } + Some(line) => u16::from(line.width() > 0), + None => 0, } - let height = content - .measure(Size::new(width, MAX_FOOTER_ROWS)) - .height - .max(1); - cache.set(Some((width, height))); - height } - pub(super) fn hint_footer_props(&self, options: ComposerRenderOptions<'_>) -> FooterProps { + pub(super) fn hint_footer_props(&self) -> FooterProps { let mut props = self.footer_props(); - if self.has_separate_status(options) { + if props.status_line_enabled { props.status_line_enabled = false; props.status_line_value = None; props.active_agent_label = None; @@ -98,64 +81,21 @@ impl ChatComposer { props } - fn status_line_layout( - &self, - area: Rect, - options: ComposerRenderOptions<'_>, - left_width: u16, - ) -> (Option>, u16) { - let show_cycle_hint = !self.is_task_running - && if options.separate_status_line { - !self.blocks_direct_input - && self.draft.input_enabled - && !self.popup_active() - && matches!( - self.footer_mode(), - FooterMode::ComposerEmpty | FooterMode::ComposerHasDraft - ) - && options.footer.is_none_or(|footer| !footer.is_interactive) - } else { - self.footer.collaboration_mode_indicator.is_some() - }; - let right = if !options.separate_status_line - && let Some(label) = &self.footer.side_conversation_context_label + pub(super) fn status_surface_content(&self) -> Option> { + if !self.footer.status_line_enabled { + return None; + } + let status = self.footer.status_line_value.as_ref(); + if matches!(status, Some(FooterContent::Extension { .. })) + || self.footer.active_agent_label.is_none() { - Some(side_conversation_context_line(label)) - } else if !options.separate_status_line - && let Some(shell) = self.shell_mode_footer_line() - { - Some(shell) - } else if !options.separate_status_line - && self - .effort_status_line_transition - .as_ref() - .is_some_and(|transition| !transition.is_finished()) - { - None - } else { - let full = self.mode_indicator_line(show_cycle_hint); - let full_fits = full.as_ref().is_none_or(|right| { - let right_width = right.width() as u16; - (!options.separate_status_line || right_width <= inset_footer_hint_area(area).width) - && can_show_left_with_context(area, left_width, right_width) - }); - if full_fits { - full - } else { - self.mode_indicator_line(/*show_cycle_hint*/ false) - } - }; - let right_width = right - .as_ref() - .map_or(/*default*/ 0, |line| line.width() as u16); - let width = max_left_width_for_right(area, right_width).unwrap_or_else(|| { - if options.separate_status_line { - inset_footer_hint_area(area).width - } else { - area.width.saturating_sub(FOOTER_INDENT_COLS as u16) - } - }); - (right, width) + return status.map(Cow::Borrowed); + } + let mut props = self.footer_props(); + // The viewed agent belongs to native status even during a transient composer hint. + props.mode = FooterMode::ComposerHasDraft; + props.is_task_running = false; + passive_footer_status_line(&props).map(Cow::Owned) } pub(super) fn render_status_surface( @@ -177,42 +117,24 @@ impl ChatComposer { } return; } - let mut props = self.footer_props(); - if options.separate_status_line { - // Persistent context is independent of help, queue, search, and quit modes. - props.mode = FooterMode::ComposerHasDraft; - props.is_task_running = false; - } - let line = passive_footer_status_line(&props); - let left_width = line.as_ref().map_or(/*default*/ 0, FooterContent::width); - let (right, width) = self.status_line_layout(area, options, left_width); - let transition = self + let area = inset_footer_hint_area(area); + let line = self.status_surface_content(); + if let Some(transition) = self .effort_status_line_transition .as_ref() - .filter(|transition| !transition.is_finished()); - let content = if let Some(transition) = transition { - transition - .render_line(line.map(FooterContent::into_hyperlink_line), width) - .map(FooterContent::HyperlinkLine) - } else { - line - }; - if let Some(content) = content { - content.render( - Rect { - width, - ..inset_footer_hint_area(area) - }, - buf, - ); - } - if let Some(right) = right { - render_context_right(area, buf, &right); - } - if transition.is_some() - && let Some(frame_requester) = &self.frame_requester + .filter(|transition| !transition.is_finished()) { - frame_requester.schedule_frame_in(EFFORT_STATUS_LINE_FRAME_TICK); + if let Some(frame) = transition.render_line( + line.map(|line| line.into_owned().into_hyperlink_line()), + area.width, + ) { + FooterContent::HyperlinkLine(frame).render(area, buf); + } + if let Some(requester) = &self.frame_requester { + requester.schedule_frame_in(EFFORT_STATUS_LINE_FRAME_TICK); + } + } else if let Some(line) = line { + line.into_owned().render(area, buf); } } } diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/status_surface_tests.rs b/codex-rs/tui/src/bottom_pane/chat_composer/status_surface_tests.rs index acce3a30f1..705c363948 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/status_surface_tests.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer/status_surface_tests.rs @@ -78,22 +78,29 @@ fn extension_status_line_clips_links_to_footer_layout() { let (output, _) = render(&composer, /*width*/ 40, /*footer*/ None); assert!(output.contains("plain"), "{output}"); assert!(!output.contains("bot"), "{output}"); + + composer.set_status_line(/*status_line*/ None); + let agent_rows = [false, true].map(|unfocused| { + let options = ComposerRenderOptions { + separate_status_line: true, + unfocused, + ..Default::default() + }; + render_status(&composer, Rect::new(0, 0, 40, 8), options).1 + }); + assert_eq!(agent_rows, [vec!["bot".to_string()], vec![]]); } -fn status_rows( +fn render_status( composer: &ChatComposer, area: Rect, options: ComposerRenderOptions<'_>, -) -> Vec { +) -> (Buffer, Vec) { let layout = composer.layout_with_options(area, options); - let status = if options.separate_status_line { - layout.status - } else { - layout.footer - }; + let status = layout.status; let mut buf = Buffer::empty(area); composer.render_with_options(area, &mut buf, /*mask_char*/ None, options); - (status.y..status.bottom()) + let rows = (status.y..status.bottom()) .map(|y| { (status.x..status.right()) .map(|x| buf[(x, y)].symbol()) @@ -101,11 +108,12 @@ fn status_rows( .trim() .to_owned() }) - .collect() + .collect(); + (buf, rows) } #[test] -fn extension_layout_uses_the_width_left_by_the_mode_indicator_after_resize() { +fn extension_uses_the_full_width_after_resize() { let mut composer = composer(); composer.footer.show_warnings_key = None; let tree: crate::ui_tree::UiTree = @@ -120,46 +128,31 @@ fn extension_layout_uses_the_width_left_by_the_mode_indicator_after_resize() { .chars() .map(|digit| osc8_hyperlink("https://example.com/pr/12345", &digit.to_string())) .collect(); - let [shared, separate] = [false, true].map(|separate_status_line| { - let mut frames = Vec::new(); - for (width, mode, warning_count) in [ - (16, None, 0), - (15, None, 0), - (16, None, 0), - (25, Some(CollaborationModeIndicator::Plan), 0), - (19, None, 1), + for fullscreen in [false, true] { + for (width, mode, expected_rows) in [ + (16, None, 1), + (15, None, 2), + (16, None, 1), + (27, Some(CollaborationModeIndicator::Plan), 1), + (19, Some(CollaborationModeIndicator::Plan), 1), ] { composer.set_collaboration_mode_indicator(mode); let options = ComposerRenderOptions { - separate_status_line, - warning_count, + separate_status_line: fullscreen, + warning_count: 1, ..Default::default() }; let height = composer.desired_height_with_options(width, options); - let area = Rect::new(/*x*/ 0, /*y*/ 0, width, height); - let rows = status_rows(&composer, area, options); + let (buffer, rows) = render_status(&composer, Rect::new(0, 0, width, height), options); + assert_eq!(rows.len(), expected_rows); for row in &rows { - let text = strip_osc8(row); - assert_eq!(*row, text.replace("12345", &linked_number)); - if warning_count == 0 { - frames.push(format!("{width} | {text}")); - } - } - if warning_count > 0 { - assert_eq!( - composer.footer.warning_notice_area.get().unwrap().bottom(), - height - ); - assert_eq!(rows.len(), if separate_status_line { 1 } else { 2 }); - let last = strip_osc8(rows.last().unwrap()); - assert!(last.contains("PR 12345")); - assert_eq!(last.contains("⚠ 1"), !separate_status_line); + assert_eq!(*row, strip_osc8(row).replace("12345", &linked_number)); } + let warning = composer.footer.warning_notice_area.get().unwrap(); + assert_eq!(buffer[(warning.x, warning.y)].symbol(), "⚠"); + assert_eq!((warning.right(), warning.y), (width - 1, height - 1)); } - frames.join("\n") - }); - assert_eq!(shared, separate); - insta::assert_snapshot!(shared); + } } #[test] @@ -173,17 +166,11 @@ fn status_rows_yield_to_the_composer_and_shared_footer_overrides() { separate_status_line, ..Default::default() }; - let short = if separate_status_line { - "one…" - } else { - "one\ntwo…" - }; - for (height, expected) in [(12, "one\ntwo\nthree\nfour…"), (7, short)] { + for (height, expected) in [(12, "one\ntwo\nthree\nfour…"), (7, "one…")] { let area = Rect::new(/*x*/ 0, /*y*/ 0, /*width*/ 7, height); - assert_eq!(status_rows(&composer, area, options).join("\n"), expected); + let (buffer, rows) = render_status(&composer, area, options); + assert_eq!(rows.join("\n"), expected); let input = composer.layout_with_options(area, options).textarea; - let mut buffer = Buffer::empty(area); - composer.render_with_options(area, &mut buffer, /*mask_char*/ None, options); assert!(input.height >= 3); let draft = [0, 1, 2].map(|dy| buffer[(input.x, input.y + dy)].symbol()); assert_eq!(draft, ["a", "b", "c"]); @@ -205,7 +192,7 @@ fn status_rows_yield_to_the_composer_and_shared_footer_overrides() { composer.set_status_line(Some(FooterContent::from(tree))); assert_eq!( composer.footer_hint_height(/*width*/ 7, ComposerRenderOptions::default()), - 2 + 1 ); composer.show_footer_flash("Copied".into(), Duration::from_secs(/*secs*/ 3)); assert_eq!( @@ -227,7 +214,9 @@ fn sidebar_focus_collapses_extension_status_to_its_dim_line() { ..Default::default() }; let height = composer.desired_height_with_options(/*width*/ 40, options); - status_rows(&composer, Rect::new(0, 0, 40, height), options).join("\n") + render_status(&composer, Rect::new(0, 0, 40, height), options) + .1 + .join("\n") }); insta::assert_snapshot!(frames.join("\n---\n"), @" one @@ -307,7 +296,7 @@ fn extension_status_keeps_its_rows_when_effort_changes() { /*x*/ 0, /*y*/ 0, /*width*/ 7, /*height*/ 12, ); assert_eq!( - status_rows(&composer, area, options), + render_status(&composer, area, options).1, ["one", "two", "three"] ); } @@ -401,8 +390,14 @@ fn fullscreen_plan_indicator_keeps_the_cycle_hint_when_it_fits() { composer.set_status_line(Some(status.into())); composer.set_active_agent_label(Some("reviewer".to_string())); let (narrow, _) = render(&composer, /*width*/ 37, /*footer*/ None); - let row = narrow.lines().rev().nth(1).expect("persistent status row"); - insta::assert_snapshot!(strip_osc8(row).trim(), @"project · PR #42 · rev… Plan mode"); + assert!( + strip_osc8(&narrow).contains("project · PR #42 · reviewer"), + "{narrow}" + ); + assert!( + narrow.lines().last().unwrap().contains("Plan mode"), + "{narrow}" + ); composer.set_active_agent_label(/*active_agent_label*/ None); composer.set_task_running(/*running*/ true); @@ -417,15 +412,16 @@ fn fullscreen_plan_indicator_keeps_the_cycle_hint_when_it_fits() { is_interactive: true, }; let (search, _) = render(&composer, /*width*/ 100, Some(&footer)); + assert!(search.contains("Search: verify"), "{search}"); assert!(search.contains("Plan mode"), "{search}"); assert!(!search.contains("⇧tab"), "{search}"); // Configured items such as git-branch can have no value outside a repository. composer.set_status_line(/*status_line*/ None); let (empty_narrow, _) = render(&composer, /*width*/ 24, /*footer*/ None); - assert_eq!( - empty_narrow.lines().rev().nth(1).map(str::trim), - Some("Plan mode") + assert!( + empty_narrow.lines().last().unwrap().contains("Plan mode"), + "{empty_narrow}" ); let (empty_wide, _) = render(&composer, /*width*/ 100, /*footer*/ None); assert!( @@ -435,16 +431,16 @@ fn fullscreen_plan_indicator_keeps_the_cycle_hint_when_it_fits() { composer.set_input_enabled(/*enabled*/ false, /*placeholder*/ None); let (read_only, _) = render(&composer, /*width*/ 100, /*footer*/ None); - assert_eq!( - read_only.lines().rev().nth(1).map(str::trim), - Some("Plan mode") + assert!( + read_only.lines().last().unwrap().contains("Plan mode"), + "{read_only}" ); composer.set_input_enabled(/*enabled*/ true, /*placeholder*/ None); composer.set_parent_owned_thread(); let (parent_owned, _) = render(&composer, /*width*/ 100, /*footer*/ None); - assert_eq!( - parent_owned.lines().rev().nth(1).map(str::trim), - Some("Plan mode") + assert!( + parent_owned.lines().last().unwrap().contains("Plan mode"), + "{parent_owned}" ); } @@ -687,14 +683,14 @@ fn slash_popup_preserves_footer_and_selection_style() { composer: surface, textarea, popup, - footer, + status, .. } = composer.layout_with_options(area, ComposerRenderOptions::default()); assert_eq!(popup.bottom(), surface.y); - assert_eq!(surface.bottom(), footer.y); + assert_eq!(surface.bottom(), status.y); assert_eq!(composer.cursor_pos(area), Some((4, textarea.y))); - let footer_text: String = (0..width).map(|x| buf[(x, height - 1)].symbol()).collect(); - assert!(footer_text.contains("model · high · fast")); + let status_text: String = (0..width).map(|x| buf[(x, status.y)].symbol()).collect(); + assert!(status_text.contains("model · high · fast")); if !clipped && width == 80 { insta::assert_snapshot!("slash_popup_footer_wide", format!("{buf:?}")); } diff --git a/codex-rs/tui/src/bottom_pane/chat_composer/warning_notice.rs b/codex-rs/tui/src/bottom_pane/chat_composer/warning_notice.rs index e9a98b71d5..ded2aa942f 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer/warning_notice.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer/warning_notice.rs @@ -1,5 +1,5 @@ //! Fit warning counts and the configured warnings shortcut into the existing passive hint row. -//! Interactive hints retain priority. Shared status content wraps beside the warning. +//! Interactive hints retain priority. Warnings occupy the trailing edge of the hints row. //! Only the count and warning label receive an amber accent; surrounding hints stay muted. use super::*; diff --git a/codex-rs/tui/src/bottom_pane/chat_composer_effort_tests.rs b/codex-rs/tui/src/bottom_pane/chat_composer_effort_tests.rs index 2af5dac0cf..0ce308d510 100644 --- a/codex-rs/tui/src/bottom_pane/chat_composer_effort_tests.rs +++ b/codex-rs/tui/src/bottom_pane/chat_composer_effort_tests.rs @@ -67,7 +67,7 @@ fn extension_content_skips_the_effort_transition_in_both_directions() { fn effort_transition_does_not_queue_a_missing_outgoing_status_line() { let (mut composer, _rx) = new_test_composer(); composer.set_status_line_enabled(/*enabled*/ true); - composer.set_status_line(Some(Line::from("gpt-5.4 high · main").into())); + composer.set_status_line(/*status_line*/ None); composer.set_task_running(/*running*/ true); composer.set_text_content("queued draft".to_string(), Vec::new(), Vec::new()); composer.set_active_reasoning_effort( @@ -171,13 +171,17 @@ fn effort_transition_keeps_the_full_footer_row() { ); let mut buf = Buffer::empty(area); composer.render(area, &mut buf); - let footer = (0..area.width) - .map(|column| buf[(column, area.bottom() - 1)].symbol()) - .collect::(); - - assert!(footer.contains("gpt-5.4 high · feature-branch")); - assert!(!footer.contains("Plan mode")); - insta::assert_snapshot!("effort_transition_keeps_the_full_footer_row", footer); + let rows = [area.bottom() - 2, area.bottom() - 1].map(|y| { + (0..area.width) + .map(|column| buf[(column, y)].symbol()) + .collect::() + .trim_end() + .to_owned() + }); + insta::assert_snapshot!( + "effort_transition_keeps_the_full_footer_row", + rows.join("\n") + ); } #[test] diff --git a/codex-rs/tui/src/bottom_pane/footer.rs b/codex-rs/tui/src/bottom_pane/footer.rs index 9718304228..8d35084714 100644 --- a/codex-rs/tui/src/bottom_pane/footer.rs +++ b/codex-rs/tui/src/bottom_pane/footer.rs @@ -877,15 +877,6 @@ impl FooterMode { } } -/// Whether callers should reserve the dedicated status-line layout for a contextual footer row. -/// -/// The dedicated layout exists for the configurable `/statusline` row. An agent label by itself -/// can be rendered by the standard footer flow, so this only becomes `true` when the status line -/// feature is enabled and the current mode allows contextual footer content. -pub(crate) fn uses_passive_footer_status_layout(props: &FooterProps) -> bool { - props.status_line_enabled && props.mode.shows_passive_line(props.is_task_running) -} - pub(crate) fn footer_line_width( props: &FooterProps, collaboration_mode_indicator: Option, @@ -1070,7 +1061,8 @@ mod tests { | FooterMode::ShortcutOverlay | FooterMode::EscHint => false, }; - let status_line_active = uses_passive_footer_status_layout(props); + let status_line_active = props.status_line_enabled + && props.mode.shows_passive_line(props.is_task_running); let passive_status_line = if status_line_active { passive_footer_status_line(props) .map(|content| content.into_hyperlink_line().line) diff --git a/codex-rs/tui/src/bottom_pane/footer/footer_content.rs b/codex-rs/tui/src/bottom_pane/footer/footer_content.rs index d05dc651e1..e74199951a 100644 --- a/codex-rs/tui/src/bottom_pane/footer/footer_content.rs +++ b/codex-rs/tui/src/bottom_pane/footer/footer_content.rs @@ -1,10 +1,9 @@ -//! The composer measures the natural width before allocating the left column, then renders -//! the selected content in the allotted rectangle. +//! Native and extension status content measured and painted inside the status rectangle. +use crate::line_truncation::line_width; use ratatui::buffer::Buffer; use ratatui::layout::Rect; use ratatui::text::Line; -use ratatui::widgets::Widget; use std::sync::Arc; use crate::line_truncation::truncate_line_with_ellipsis_if_overflow; @@ -13,7 +12,7 @@ use crate::terminal_hyperlinks::HyperlinkLine; use crate::ui_tree::PreparedUiTree; use crate::ui_tree::UiTree; -/// Owned content for the footer's negotiated left-hand area. +/// Owned status content displayed below the composer. #[derive(Clone, Debug, PartialEq)] pub(crate) enum FooterContent { Line(Line<'static>), @@ -30,10 +29,10 @@ impl From for FooterContent { } impl FooterContent { - /// Natural display width, before the footer allocates space for the right indicator. + /// Natural display width in terminal cells. pub(crate) fn width(&self) -> u16 { let width = match self { - Self::Line(line) => line.width(), + Self::Line(line) => line_width(line), Self::HyperlinkLine(line) => line.width(), Self::Extension { content } => return content.measure_natural().width, }; @@ -43,11 +42,11 @@ impl FooterContent { /// Paint only inside the final area supplied by the parent. pub(crate) fn render(self, area: Rect, buf: &mut Buffer) { match self { - Self::Line(line) => Widget::render(line, area, buf), Self::Extension { content } => { with_syntax_theme(|theme| content.render(area, theme, buf)); } - Self::HyperlinkLine(mut line) => { + native => { + let mut line = native.into_hyperlink_line(); let area = Rect { height: area.height.min(1), ..area diff --git a/codex-rs/tui/src/bottom_pane/mod.rs b/codex-rs/tui/src/bottom_pane/mod.rs index 4cec9e466a..a165ca11b9 100644 --- a/codex-rs/tui/src/bottom_pane/mod.rs +++ b/codex-rs/tui/src/bottom_pane/mod.rs @@ -2445,9 +2445,10 @@ impl BottomPane { pub(crate) fn backdrop_with_options<'a>( &'a self, - options: ComposerRenderOptions<'a>, + mut options: ComposerRenderOptions<'a>, ) -> RenderableItem<'a> { let views = if self.centered_dialog().is_some() { + options.is_dialog_backdrop = true; &self.view_stack[..self.view_stack.len() - 1] } else { &self.view_stack @@ -2598,6 +2599,7 @@ impl BottomPane { && options.warning_count == 0 && options.footer.is_none() && !options.separate_status_line + && !options.is_dialog_backdrop && options.command_popup_placement == CommandPopupPlacement::AboveComposer { RenderableItem::Borrowed(&self.composer) diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__effort_tests__effort_transition_keeps_the_full_footer_row.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__effort_tests__effort_transition_keeps_the_full_footer_row.snap index e02e49dced..396209ddb3 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__effort_tests__effort_transition_keeps_the_full_footer_row.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__effort_tests__effort_transition_keeps_the_full_footer_row.snap @@ -1,5 +1,6 @@ --- source: tui/src/bottom_pane/chat_composer_effort_tests.rs -expression: footer +expression: "rows.join(\"\\n\")" --- gpt-5.4 high · feature-branch + ? for shortcuts Plan mode diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__agents_navigation_status.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__agents_navigation_status.snap index eddb4ae501..adf9113329 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__agents_navigation_status.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__agents_navigation_status.snap @@ -9,5 +9,5 @@ expression: terminal.backend() " " " " " " -" " -" model · project · ← for agents " +" model · project " +" ← for agents · ? for shortcuts " diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shell_command_absorbs_bang.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shell_command_absorbs_bang.snap index 0b09860b59..6c23176560 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shell_command_absorbs_bang.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shell_command_absorbs_bang.snap @@ -9,5 +9,5 @@ expression: terminal.backend() " " " " " " -" " -" gpt-5.4 high fast · ~/code/codex-1 · Context 0% used Shell mode " +" gpt-5.4 high fast · ~/code/codex-1 · Context 0% used " +" Shell mode " diff --git a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shell_command_escape_exits_empty_mode.snap b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shell_command_escape_exits_empty_mode.snap index dac77a38da..3032873cd0 100644 --- a/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shell_command_escape_exits_empty_mode.snap +++ b/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__chat_composer__tests__footer_mode_shell_command_escape_exits_empty_mode.snap @@ -1,6 +1,5 @@ --- source: tui/src/bottom_pane/chat_composer.rs -assertion_line: 4485 expression: terminal.backend() --- " " @@ -10,5 +9,5 @@ expression: terminal.backend() " " " " " " -" " " gpt-5.4 high fast · ~/code/codex-1 · Context 0% used " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/realtime/recording_controls_tests.rs b/codex-rs/tui/src/chatwidget/realtime/recording_controls_tests.rs index f0efff94d2..81acef34aa 100644 --- a/codex-rs/tui/src/chatwidget/realtime/recording_controls_tests.rs +++ b/codex-rs/tui/src/chatwidget/realtime/recording_controls_tests.rs @@ -605,7 +605,6 @@ async fn clipped_voice_composer_keeps_the_draft_and_cursor_visible() { insta::assert_snapshot!(layouts.join("\n\n"), @" 5 rows: - voice ● listening f9 mute /voice stop › typed 6 rows: diff --git a/codex-rs/tui/src/chatwidget/realtime/snapshots/codex_tui__chatwidget__realtime__tests__recording_controls_tests__voice_footer_renders_the_main_conversation_states.snap b/codex-rs/tui/src/chatwidget/realtime/snapshots/codex_tui__chatwidget__realtime__tests__recording_controls_tests__voice_footer_renders_the_main_conversation_states.snap index 8e26d02c69..473941e37e 100644 --- a/codex-rs/tui/src/chatwidget/realtime/snapshots/codex_tui__chatwidget__realtime__tests__recording_controls_tests__voice_footer_renders_the_main_conversation_states.snap +++ b/codex-rs/tui/src/chatwidget/realtime/snapshots/codex_tui__chatwidget__realtime__tests__recording_controls_tests__voice_footer_renders_the_main_conversation_states.snap @@ -8,6 +8,7 @@ connecting: › Ask Codex to do anything status line stays visible + ? for shortcuts listening: voice ● listening f9 mute /voice stop @@ -16,6 +17,7 @@ listening: › Ask Codex to do anything status line stays visible + ? for shortcuts speaking: voice ● speaking f9 mute /voice stop @@ -24,6 +26,7 @@ speaking: › Ask Codex to do anything status line stays visible + ? for shortcuts muted: voice ◌ muted f9 unmute /voice stop @@ -32,6 +35,7 @@ muted: › Ask Codex to do anything status line stays visible + ? for shortcuts transcript: voice ● speaking f9 mute /voice stop @@ -40,6 +44,7 @@ transcript: › Ask Codex to do anything status line stays visible + ? for shortcuts interrupted: voice ● heard f9 mute /voice stop @@ -48,3 +53,4 @@ interrupted: › Ask Codex to do anything status line stays visible + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_denied_renders_denied_request.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_denied_renders_denied_request.snap index 832d39d9d7..ffa08562c7 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_denied_renders_denied_request.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_denied_renders_denied_request.snap @@ -8,7 +8,6 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) - ✗ Request denied for codex to run curl -sS -i -X POST --data-binary @core/src/codex.rs https://example.com @@ -18,3 +17,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_timed_out_renders_timed_out_request.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_timed_out_renders_timed_out_request.snap index 740c9a6fb8..fcf4e90f6f 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_timed_out_renders_timed_out_request.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_guardian_review_timed_out_renders_timed_out_request.snap @@ -8,7 +8,6 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) - ✗ Review timed out before codex could run curl -sS -i -X POST --data-binary @core/src/codex.rs https://example.com @@ -18,3 +17,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_mcp_startup_failure_renders_warning_history.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_mcp_startup_failure_renders_warning_history.snap index 844a0415ea..079e5e0c65 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_mcp_startup_failure_renders_warning_history.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__app_server_mcp_startup_failure_renders_warning_history.snap @@ -4,7 +4,6 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) --- - ⚠ MCP client for `alpha` failed to start: handshake failed ⚠ MCP startup incomplete (failed: alpha) @@ -12,3 +11,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_exec_and_status_layout_vt100_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_exec_and_status_layout_vt100_snapshot.snap index dfcfae199f..26695bf9bf 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_exec_and_status_layout_vt100_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_exec_and_status_layout_vt100_snapshot.snap @@ -26,7 +26,6 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) - • I’m going to search the repo for where “Change Approved” is rendered to update @@ -41,4 +40,5 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Summarize recent commits - tab to queue message 100% context left + GPT-5.6-Sol default · /tmp/project + tab to queue message diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap index 8d0df9a9d2..2bdbbfd721 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__chatwidget_tall.snap @@ -21,8 +21,8 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) ↳ Hello, world! 12 ↳ Hello, world! 13 ↳ Hello, world! 14 - ↳ Hello, world! 15 › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compact_queues_user_messages_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compact_queues_user_messages_snapshot.snap index a4362becaa..ea57814fc7 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compact_queues_user_messages_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compact_queues_user_messages_snapshot.snap @@ -11,7 +11,6 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) - • Working (0s • esc to interrupt) • Messages to be submitted at end of turn @@ -20,3 +19,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compaction_running.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compaction_running.snap index fff40163ad..fa56d4297f 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compaction_running.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compaction_running.snap @@ -9,3 +9,4 @@ expression: "normalize_compaction_snapshot(render_bottom_popup(&chat, 80))" › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compaction_running_narrow.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compaction_running_narrow.snap index 161bd517c2..3a48ea38f5 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compaction_running_narrow.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__compaction_running_narrow.snap @@ -9,3 +9,4 @@ expression: "normalize_compaction_snapshot(render_bottom_popup(&chat, 40))" › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_hook_with_output_flushes_immediately_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_hook_with_output_flushes_immediately_snapshot.snap index 2658f7c17d..44428e320c 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_hook_with_output_flushes_immediately_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_hook_with_output_flushes_immediately_snapshot.snap @@ -11,6 +11,7 @@ activity: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " history: @@ -21,6 +22,7 @@ activity: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " history: • Blocked by hook └ command blocked by policy diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_same_id_hook_output_survives_restart_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_same_id_hook_output_survives_restart_snapshot.snap index 9fe87abc0f..b276445cb4 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_same_id_hook_output_survives_restart_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_same_id_hook_output_survives_restart_snapshot.snap @@ -11,6 +11,7 @@ activity: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " history: • Hook stopped └ continue with more context diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_turn_clears_visible_running_hook.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_turn_clears_visible_running_hook.snap index 749ed94a51..d60d1a591c 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_turn_clears_visible_running_hook.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__completed_turn_clears_visible_running_hook.snap @@ -10,9 +10,11 @@ before completion: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " after completion: " " " " "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__connector_scope_invalidation.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__connector_scope_invalidation.snap index 47a411cbf9..741316aad0 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__connector_scope_invalidation.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__connector_scope_invalidation.snap @@ -17,3 +17,4 @@ After account change: › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__custom_model_display_name_status_line.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__custom_model_display_name_status_line.snap index cd133ee3c5..2707068ac8 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__custom_model_display_name_status_line.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__custom_model_display_name_status_line.snap @@ -7,3 +7,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " GPT-5.6 Luna · GPT-5.6 Luna high " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__daybreak_hidden_after_provider_settings_change.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__daybreak_hidden_after_provider_settings_change.snap index 83accb757d..cee8d742e7 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__daybreak_hidden_after_provider_settings_change.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__daybreak_hidden_after_provider_settings_change.snap @@ -5,4 +5,5 @@ expression: popup --- › /daybreak - profile: work · provider: server-updated Plan mode (⇧tab to cycle) + profile: work · provider: server-updated + Plan mode (⇧tab to cycle) diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__daybreak_refusal_parent_owned.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__daybreak_refusal_parent_owned.snap index 77622343e0..0ec0288569 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__daybreak_refusal_parent_owned.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__daybreak_refusal_parent_owned.snap @@ -11,3 +11,4 @@ expression: "format!(\"{}\\n{}\", lines_to_single_string(cells.last().unwrap()), › Viewing sub-agent — direct input is disabled GPT-6.1-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__declined_tool_suggestion.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__declined_tool_suggestion.snap index b3e42a7486..5f390b1327 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__declined_tool_suggestion.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__declined_tool_suggestion.snap @@ -6,3 +6,4 @@ expression: popup › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__esc_interrupt_goal_paused_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__esc_interrupt_goal_paused_footer.snap index d9aaa4e578..221f32acbc 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__esc_interrupt_goal_paused_footer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__esc_interrupt_goal_paused_footer.snap @@ -8,4 +8,5 @@ expression: snapshot " " "› Ask Codex to do anything " " " -" GPT-5.6-Sol default · /tmp/project Goal paused (/goal resume) " +" GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts Goal paused (/goal resume) " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__esc_interrupt_goal_paused_footer@windows.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__esc_interrupt_goal_paused_footer@windows.snap index b2b296cb6f..221f32acbc 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__esc_interrupt_goal_paused_footer@windows.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__esc_interrupt_goal_paused_footer@windows.snap @@ -8,4 +8,5 @@ expression: snapshot " " "› Ask Codex to do anything " " " -" GPT-5.6-Sol default · /tmp/project Goal paused (/goal resume) " +" GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts Goal paused (/goal resume) " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_exec_is_hidden_from_history.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_exec_is_hidden_from_history.snap index 489c81b4f4..0232420e74 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_exec_is_hidden_from_history.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_exec_is_hidden_from_history.snap @@ -9,7 +9,7 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) - › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_request_permissions_clears_status_without_history.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_request_permissions_clears_status_without_history.snap index 9e552010ac..4e984596a8 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_request_permissions_clears_status_without_history.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_approved_request_permissions_clears_status_without_history.snap @@ -6,10 +6,10 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) - • Working (0s • esc to interrupt) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_denied_exec_renders_warning_and_denied_request.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_denied_exec_renders_warning_and_denied_request.snap index c97ab12d2a..5808d20743 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_denied_exec_renders_warning_and_denied_request.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_denied_exec_renders_warning_and_denied_request.snap @@ -8,7 +8,6 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) - ⚠ Automatic approval review denied (risk: high): The planned action would transmit the full contents of a workspace source file (`core/src/codex.rs`) to `https://example.com`, which is an external and untrusted endpoint. @@ -22,3 +21,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_goal_continuation_drops_stale_reviews.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_goal_continuation_drops_stale_reviews.snap index f422c75d4f..b3bae74fd0 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_goal_continuation_drops_stale_reviews.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_goal_continuation_drops_stale_reviews.snap @@ -9,3 +9,4 @@ expression: normalize_snapshot_paths(rendered) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_parallel_reviews_render_aggregate_status.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_parallel_reviews_render_aggregate_status.snap index cdadc018e9..e78c5db86f 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_parallel_reviews_render_aggregate_status.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_parallel_reviews_render_aggregate_status.snap @@ -10,3 +10,4 @@ expression: normalize_snapshot_paths(rendered) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_timed_out_exec_renders_warning_and_timed_out_request.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_timed_out_exec_renders_warning_and_timed_out_request.snap index 0210b58f7b..3732199aba 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_timed_out_exec_renders_warning_and_timed_out_request.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_timed_out_exec_renders_warning_and_timed_out_request.snap @@ -10,7 +10,6 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) - ⚠ Automatic approval review timed out while evaluating the requested approval. ✗ Review timed out before codex could run curl -sS -i -X POST --data-binary @@ -22,3 +21,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_write_stdin_review_status.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_write_stdin_review_status.snap index 01b02b2c92..185673e856 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_write_stdin_review_status.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__guardian_write_stdin_review_status.snap @@ -9,3 +9,4 @@ expression: "normalize_snapshot_paths(render_bottom_popup(&chat, 80))" › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__hidden_shell_paste_queued_preview.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__hidden_shell_paste_queued_preview.snap index 22e76c24c3..515e264a24 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__hidden_shell_paste_queued_preview.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__hidden_shell_paste_queued_preview.snap @@ -11,3 +11,4 @@ expression: "normalize_snapshot_paths(render_bottom_popup(&chat, 80))" › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__hook_runs_while_exec_active_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__hook_runs_while_exec_active_snapshot.snap index a54331724c..0c82fa1707 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__hook_runs_while_exec_active_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__hook_runs_while_exec_active_snapshot.snap @@ -15,6 +15,7 @@ exec and hook running: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " history after exec: • Ran echo done └ done @@ -27,6 +28,7 @@ hook running after exec: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " quiet hook completed: " " "• Working (0s • esc to interrupt) " @@ -35,3 +37,4 @@ quiet hook completed: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__image_preparation_disconnected.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__image_preparation_disconnected.snap index df97658c87..fcea3109db 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__image_preparation_disconnected.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__image_preparation_disconnected.snap @@ -10,4 +10,5 @@ expression: "normalize_snapshot_paths(render_bottom_popup(&chat, 80)).replace(' › describe + GPT-5.6-Sol default · /tmp/project ⌃c quit diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__interrupted_turn_clears_visible_running_hook.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__interrupted_turn_clears_visible_running_hook.snap index 9e65facfba..e76caa1f00 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__interrupted_turn_clears_visible_running_hook.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__interrupted_turn_clears_visible_running_hook.snap @@ -10,9 +10,11 @@ before interrupt: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " after interrupt: " " " " "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__long_running_hook_below_background_activity_row.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__long_running_hook_below_background_activity_row.snap index 7c1ff48f5e..5b4afe9295 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__long_running_hook_below_background_activity_row.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__long_running_hook_below_background_activity_row.snap @@ -11,6 +11,7 @@ expression: "format!(\"80 columns:\\n{}\\n120 columns:\\n{}\", hook_status_frame "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " 120 columns: " " "• Working (0s • esc to interrupt) · 1 background terminal running · /ps to view · /stop to close " @@ -20,3 +21,4 @@ expression: "format!(\"80 columns:\\n{}\\n120 columns:\\n{}\", hook_status_frame "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__manual_thread_name_status_surfaces.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__manual_thread_name_status_surfaces.snap index bff7d27f4f..e6d8610b2a 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__manual_thread_name_status_surfaces.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__manual_thread_name_status_surfaces.snap @@ -1,6 +1,6 @@ --- source: tui/src/chatwidget/tests/app_server.rs -expression: "format!(\"transcript:\\n{transcript}\\nfooter:\\n{footer}\\ntitle: {title}\")" +expression: "normalize_snapshot_paths(format!(\"transcript:\\n{transcript}\\nfooter:\\n{footer}\\ntitle: {title}\"))" --- transcript: @@ -8,4 +8,5 @@ footer: › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project · review-fix + ? for shortcuts title: review-fix | project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mcp_startup_header_booting.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mcp_startup_header_booting.snap index f7988ba639..7e05057e38 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mcp_startup_header_booting.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mcp_startup_header_booting.snap @@ -7,3 +7,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__misalignment_turn_end_cleared_composer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__misalignment_turn_end_cleared_composer.snap index 37aff5b7ac..02ce9c0808 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__misalignment_turn_end_cleared_composer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__misalignment_turn_end_cleared_composer.snap @@ -5,4 +5,5 @@ expression: "normalize_snapshot_paths(render_bottom_popup(&chat, 80))" --- › Ask Codex to do anything + GPT-5.6-Sol default · /tmp/project esc esc to edit previous message diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mixed_running_hooks_share_background_activity_row.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mixed_running_hooks_share_background_activity_row.snap index f8f8b45f20..8328b081a2 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mixed_running_hooks_share_background_activity_row.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__mixed_running_hooks_share_background_activity_row.snap @@ -11,6 +11,7 @@ expression: "format!(\"80 columns:\\n{}\\n120 columns:\\n{}\", hook_status_frame "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " 120 columns: " " "• Working (0s • esc to interrupt) · 1 background terminal running · /ps to view · /stop to close · Running hooks " @@ -19,3 +20,4 @@ expression: "format!(\"80 columns:\\n{}\\n120 columns:\\n{}\", hook_status_frame "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__overlapping_hook_live_cell_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__overlapping_hook_live_cell_snapshot.snap index 25e7c7a13e..2277c5c41e 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__overlapping_hook_live_cell_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__overlapping_hook_live_cell_snapshot.snap @@ -11,6 +11,7 @@ activity: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " history: @@ -23,6 +24,7 @@ activity: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " history: @@ -35,6 +37,7 @@ activity: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " history: @@ -47,5 +50,6 @@ activity: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " history: diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts.snap index e1f10e1f9c..d90cd8e490 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts.snap @@ -16,3 +16,5 @@ expression: "render_bottom_popup(&chat, 100)" › Review the current changes for safety + + GPT-5.5 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts_empty.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts_empty.snap index 72c8899875..135661d788 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts_empty.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts_empty.snap @@ -10,3 +10,5 @@ expression: "render_bottom_popup(&chat, 100)" › Ask Codex to do anything + + GPT-5.5 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts_narrow.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts_narrow.snap index fc6b4be116..9d2de2c235 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts_narrow.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__quick_dial_shortcuts_narrow.snap @@ -20,3 +20,5 @@ expression: "render_bottom_popup(&chat, 48)" › Review the current changes for safety + + GPT-5.5 default · /tmp/project diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_delta_restores_recreated_status_indicator.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_delta_restores_recreated_status_indicator.snap index 6303a9dd29..06325835d7 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_delta_restores_recreated_status_indicator.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_delta_restores_recreated_status_indicator.snap @@ -10,3 +10,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_shortcut_max_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_shortcut_max_footer.snap index 34012bf8b1..18d761f43a 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_shortcut_max_footer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_shortcut_max_footer.snap @@ -7,3 +7,4 @@ expression: snapshot "› Ask Codex to do anything " " " " GPT-5.5 max " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_shortcut_max_plan_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_shortcut_max_plan_footer.snap index fb661e522f..632b104ffc 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_shortcut_max_plan_footer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__reasoning_shortcut_max_plan_footer.snap @@ -6,4 +6,5 @@ expression: snapshot " " "› Ask Codex to do anything " " " -" GPT-5.5 max Plan mode (⇧tab to cycle) " +" GPT-5.5 max " +" ? for shortcuts Plan mode (⇧tab to cycle) " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__renamed_thread_footer_title.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__renamed_thread_footer_title.snap index 536edffead..ef4a5a6b37 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__renamed_thread_footer_title.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__renamed_thread_footer_title.snap @@ -7,3 +7,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " gpt-5.2 high · Roadmap cleanup " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__replayed_in_progress_turn.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__replayed_in_progress_turn.snap index 126e67cc09..97555e47f2 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__replayed_in_progress_turn.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__replayed_in_progress_turn.snap @@ -8,3 +8,4 @@ expression: "timer.replace_all(&normalize_snapshot_paths(render_bottom_popup(&ch › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap index 7f11c14a0c..4d2de23279 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__review_queues_user_messages_snapshot.snap @@ -11,7 +11,6 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) - • Working (0s • esc to interrupt) • Messages to be submitted at end of turn @@ -20,3 +19,4 @@ expression: normalize_snapshot_paths(term.backend().vt100().screen().contents()) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__running_hooks_share_background_activity_row.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__running_hooks_share_background_activity_row.snap index 57e161155a..f847b5f91e 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__running_hooks_share_background_activity_row.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__running_hooks_share_background_activity_row.snap @@ -11,6 +11,7 @@ expression: "format!(\"80 columns:\\n{}\\n120 columns:\\n{}\", hook_status_frame "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " 120 columns: " " "• Working (0s • esc to interrupt) · 1 background terminal running · /ps to view · /stop to close " @@ -20,3 +21,4 @@ expression: "format!(\"80 columns:\\n{}\\n120 columns:\\n{}\", hook_status_frame "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__session_end_hook_activity.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__session_end_hook_activity.snap index ea69dee671..8724f93b1f 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__session_end_hook_activity.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__session_end_hook_activity.snap @@ -8,6 +8,7 @@ before reveal: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " running: " " "• Saving session summary " @@ -16,9 +17,11 @@ running: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " completed: " " " " "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__session_end_hook_activity_without_message.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__session_end_hook_activity_without_message.snap index 9a05181d30..ff88de32b9 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__session_end_hook_activity_without_message.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__session_end_hook_activity_without_message.snap @@ -8,6 +8,7 @@ before reveal: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " running: " " "• Running hook " @@ -16,9 +17,11 @@ running: "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " completed: " " " " "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_preserves_status_line.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_preserves_status_line.snap index 2729a2ce3e..b2b0785abf 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_preserves_status_line.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_preserves_status_line.snap @@ -6,4 +6,5 @@ expression: terminal.backend() " " "› Ask a follow-up question " " " -" GPT-5.6-Sol Side from main thread · ctrl+/ to switch · ctrl+c to close " +" GPT-5.6-Sol " +" ? for shortcuts Side from main thread · ctrl+/ to switch · ctrl+c to close " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_hidden_side.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_hidden_side.snap index 51133a16e5..14ce412d6f 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_hidden_side.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_hidden_side.snap @@ -6,4 +6,5 @@ expression: terminal.backend() " " "› Ask Codex to do anything " " " -" GPT-5.6-Sol ctrl+/ for side " +" GPT-5.6-Sol " +" ? for shortcuts ctrl+/ for side " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_parent_status.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_parent_status.snap index 47258c1616..510298d575 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_parent_status.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__side_context_label_shows_parent_status.snap @@ -6,4 +6,5 @@ expression: terminal.backend() " " "› Ask a follow-up question " " " +" GPT-5.6-Sol default · /tmp/project " " Side from main thread · main needs input · ctrl+/ to switch · ctrl+c to close " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__single_line_final_answer_hides_working_status.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__single_line_final_answer_hides_working_status.snap index dfa6b7a09b..6d5ff85b99 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__single_line_final_answer_hides_working_status.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__single_line_final_answer_hides_working_status.snap @@ -2,7 +2,6 @@ source: tui/src/chatwidget/tests/status_and_layout.rs expression: normalize_snapshot_paths(terminal.backend().vt100().screen().contents()) --- - › count to 1 @@ -12,3 +11,4 @@ expression: normalize_snapshot_paths(terminal.backend().vt100().screen().content › Ask Codex to do anything gpt-5 default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__single_line_partial_answer_keeps_working_status.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__single_line_partial_answer_keeps_working_status.snap index f5b6cdd6e1..d7392d79ac 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__single_line_partial_answer_keeps_working_status.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__single_line_partial_answer_keeps_working_status.snap @@ -3,7 +3,6 @@ source: tui/src/chatwidget/tests/status_and_layout.rs expression: normalize_snapshot_paths(terminal.backend().vt100().screen().contents()) --- - • 1 • Working (0s • esc to interrupt) @@ -12,3 +11,4 @@ expression: normalize_snapshot_paths(terminal.backend().vt100().screen().content › Ask Codex to do anything gpt-5 default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_side_requests_forked_side_question_while_task_running.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_side_requests_forked_side_question_while_task_running.snap index 558a9e05b2..acf5d1f0e4 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_side_requests_forked_side_question_while_task_running.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__slash_side_requests_forked_side_question_while_task_running.snap @@ -8,4 +8,5 @@ expression: normalized_backend_snapshot(terminal.backend()) " " "› Ask Codex to do anything " " " -" GPT-5.6-Sol default Side starting... " +" GPT-5.6-Sol default " +" ? for shortcuts Side starting... " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_estimated_thread_cost_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_estimated_thread_cost_footer.snap index d0d6e6d874..8dc69ab022 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_estimated_thread_cost_footer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_estimated_thread_cost_footer.snap @@ -7,3 +7,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " GPT-5.6-Sol default · 5.2 credits · ~$0.21 " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_fast_mode_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_fast_mode_footer.snap index 5c97c9c829..353b046537 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_fast_mode_footer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_fast_mode_footer.snap @@ -7,3 +7,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " gpt-5.2 high · Standard " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_goal_active_token_budget_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_goal_active_token_budget_footer.snap index d7fddce123..8661334554 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_goal_active_token_budget_footer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_goal_active_token_budget_footer.snap @@ -6,4 +6,5 @@ expression: normalized_backend_snapshot(terminal.backend()) " " "› Ask Codex to do anything " " " -" GPT-5.5 Pursuing goal (40K / 50K) " +" GPT-5.5 " +" ? for shortcuts Pursuing goal (40K / 50K) " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_goal_complete_elapsed_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_goal_complete_elapsed_footer.snap index 10e1d6409b..20845e0b55 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_goal_complete_elapsed_footer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_goal_complete_elapsed_footer.snap @@ -6,4 +6,5 @@ expression: normalized_backend_snapshot(terminal.backend()) " " "› Ask Codex to do anything " " " -" GPT-5.5 Goal achieved (2d 23h 42m) " +" GPT-5.5 " +" ? for shortcuts Goal achieved (2d 23h 42m) " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_context_remaining_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_context_remaining_footer.snap index 6200fdf108..baae0f2524 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_context_remaining_footer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_context_remaining_footer.snap @@ -7,3 +7,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " gpt-5.4 xhigh fast · Context 100% left · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_fast_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_fast_footer.snap index 2ac794d2f0..13f6fa58a7 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_fast_footer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_fast_footer.snap @@ -7,3 +7,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " gpt-5.4 xhigh fast · Context 0% used · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_plan_mode_footer.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_plan_mode_footer.snap index 2bbd73de7b..eb9d618e8e 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_plan_mode_footer.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_line_model_with_reasoning_plan_mode_footer.snap @@ -6,4 +6,5 @@ expression: normalized_backend_snapshot(terminal.backend()) " " "› Ask Codex to do anything " " " -" gpt-5.2 medium Plan mode (⇧tab to cycle) " +" gpt-5.2 medium " +" ? for shortcuts Plan mode (⇧tab to cycle) " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_active.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_active.snap index 0bbc057620..7b89d08f31 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_active.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__status_widget_active.snap @@ -9,3 +9,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_begin_restores_working_status.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_begin_restores_working_status.snap index 68835e4e77..f5b5ab1d9d 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_begin_restores_working_status.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_begin_restores_working_status.snap @@ -9,3 +9,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_wait_status_renders_command_in_single_details_row.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_wait_status_renders_command_in_single_details_row.snap index 980874d998..1a4f31b322 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_wait_status_renders_command_in_single_details_row.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__unified_exec_wait_status_renders_command_in_single_details_row.snap @@ -9,3 +9,4 @@ expression: normalize_snapshot_paths(rendered) › Ask Codex to do anything GPT-5.6-Sol default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__voice_live_transcript_and_stream.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__voice_live_transcript_and_stream.snap index bf09f278df..9e18dc93aa 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__voice_live_transcript_and_stream.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__voice_live_transcript_and_stream.snap @@ -15,3 +15,4 @@ expression: rendered "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__voice_partial_transcript_hidden.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__voice_partial_transcript_hidden.snap index bacf72efc6..cee7824943 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__voice_partial_transcript_hidden.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__voice_partial_transcript_hidden.snap @@ -11,3 +11,4 @@ expression: normalized_backend_snapshot(terminal.backend()) "› Ask Codex to do anything " " " " GPT-5.6-Sol default · /tmp/project " +" ? for shortcuts " diff --git a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__windows_sandbox_setup_fresh_clock.snap b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__windows_sandbox_setup_fresh_clock.snap index 87abf3dba8..7e4845a680 100644 --- a/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__windows_sandbox_setup_fresh_clock.snap +++ b/codex-rs/tui/src/chatwidget/snapshots/codex_tui__chatwidget__tests__windows_sandbox_setup_fresh_clock.snap @@ -10,3 +10,4 @@ expression: "setup.replace(&chat.config.cwd.display().to_string(), \"[CWD]\")" › Input disabled until setup completes. GPT-5.6-Sol default · [CWD] + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/tests/guardian.rs b/codex-rs/tui/src/chatwidget/tests/guardian.rs index 9046781c79..75ce2e316d 100644 --- a/codex-rs/tui/src/chatwidget/tests/guardian.rs +++ b/codex-rs/tui/src/chatwidget/tests/guardian.rs @@ -320,7 +320,7 @@ async fn guardian_denied_exec_renders_warning_and_denied_request() { assert_chatwidget_snapshot!( "guardian_denied_exec_renders_warning_and_denied_request", - normalize_snapshot_paths(term.backend().vt100().screen().contents()) + normalize_working_snapshot(term.backend().vt100().screen().contents()) ); } @@ -462,7 +462,7 @@ async fn guardian_approved_request_permissions_clears_status_without_history() { assert_chatwidget_snapshot!( "guardian_approved_request_permissions_clears_status_without_history", - normalize_snapshot_paths(term.backend().vt100().screen().contents()) + normalize_working_snapshot(term.backend().vt100().screen().contents()) ); } @@ -536,7 +536,7 @@ async fn guardian_timed_out_exec_renders_warning_and_timed_out_request() { assert_chatwidget_snapshot!( "guardian_timed_out_exec_renders_warning_and_timed_out_request", - normalize_snapshot_paths(term.backend().vt100().screen().contents()) + normalize_working_snapshot(term.backend().vt100().screen().contents()) ); } @@ -655,7 +655,7 @@ async fn app_server_guardian_review_denied_renders_denied_request_snapshot() { assert_chatwidget_snapshot!( "app_server_guardian_review_denied_renders_denied_request", - normalize_snapshot_paths(term.backend().vt100().screen().contents()) + normalize_working_snapshot(term.backend().vt100().screen().contents()) ); } @@ -736,7 +736,7 @@ async fn app_server_guardian_review_timed_out_renders_timed_out_request_snapshot assert_chatwidget_snapshot!( "app_server_guardian_review_timed_out_renders_timed_out_request", - normalize_snapshot_paths(term.backend().vt100().screen().contents()) + normalize_working_snapshot(term.backend().vt100().screen().contents()) ); } diff --git a/codex-rs/tui/src/chatwidget/tests/helpers.rs b/codex-rs/tui/src/chatwidget/tests/helpers.rs index 048952e363..8fce9e01a2 100644 --- a/codex-rs/tui/src/chatwidget/tests/helpers.rs +++ b/codex-rs/tui/src/chatwidget/tests/helpers.rs @@ -45,7 +45,7 @@ pub(crate) fn normalize_working_snapshot(text: String) -> String { let text = normalize_snapshot_paths(text) .replace("◦ Working", "• Working") .replace("◦ Wor…", "• Wor…"); - regex_lite::Regex::new(r"(?m)^• Working \(\d+s") + regex_lite::Regex::new(r"• Working \(\d+s") .expect("valid working timer pattern") .replace_all(&text, "• Working (0s") .into_owned() diff --git a/codex-rs/tui/src/chatwidget/tests/quick_dials_tests.rs b/codex-rs/tui/src/chatwidget/tests/quick_dials_tests.rs index c53b1f5075..bcebc5a99b 100644 --- a/codex-rs/tui/src/chatwidget/tests/quick_dials_tests.rs +++ b/codex-rs/tui/src/chatwidget/tests/quick_dials_tests.rs @@ -143,6 +143,7 @@ async fn saved_quick_dials_save_and_clear_picker_snapshots() { let (mut chat, mut events, _ops) = make_chatwidget_manual(/*model_override*/ Some("gpt-5.5")).await; chat.thread_id = Some(ThreadId::new()); + chat.set_status_line(Some("GPT-5.5 default · /tmp/project".into())); chat.open_quick_dial_menu(); assert_chatwidget_snapshot!( "quick_dial_shortcuts_empty", diff --git a/codex-rs/tui/src/chatwidget/tests/side.rs b/codex-rs/tui/src/chatwidget/tests/side.rs index a7d793f15d..25d5fda1d8 100644 --- a/codex-rs/tui/src/chatwidget/tests/side.rs +++ b/codex-rs/tui/src/chatwidget/tests/side.rs @@ -329,7 +329,10 @@ async fn side_context_label_shows_parent_status_snapshot() { terminal .draw(|f| chat.render(f.area(), f.buffer_mut())) .expect("draw side conversation footer"); - assert_chatwidget_snapshot!("side_context_label_shows_parent_status", terminal.backend()); + assert_chatwidget_snapshot!( + "side_context_label_shows_parent_status", + normalized_backend_snapshot(terminal.backend()) + ); } #[tokio::test] diff --git a/codex-rs/tui/src/chatwidget/tests/slash_commands.rs b/codex-rs/tui/src/chatwidget/tests/slash_commands.rs index 5432000898..36b7ffeae0 100644 --- a/codex-rs/tui/src/chatwidget/tests/slash_commands.rs +++ b/codex-rs/tui/src/chatwidget/tests/slash_commands.rs @@ -3869,14 +3869,14 @@ async fn transcript_copy_feedback_stays_in_the_footer_without_history_or_interru assert!(operations.try_recv().is_err()); insta::assert_snapshot!( "transcript_copy_success", - render_bottom_popup(&chat, /*width*/ 80) + normalize_snapshot_paths(render_bottom_popup(&chat, /*width*/ 80)) ); chat.show_selection_copy_result(Ok(crate::clipboard_copy::CopyStatus::Unconfirmed)); assert_eq!(drain_insert_history(&mut events).len(), 0); assert!(operations.try_recv().is_err()); insta::assert_snapshot!( "transcript_copy_unconfirmed", - render_bottom_popup(&chat, /*width*/ 80) + normalize_snapshot_paths(render_bottom_popup(&chat, /*width*/ 80)) ); chat.open_warnings(&[Arc::new(history_cell::new_warning_event( "selected café".into(), @@ -3886,7 +3886,7 @@ async fn transcript_copy_feedback_stays_in_the_footer_without_history_or_interru assert!(operations.try_recv().is_err()); insta::assert_snapshot!( "transcript_copy_failure", - render_bottom_popup(&chat, /*width*/ 80) + normalize_snapshot_paths(render_bottom_popup(&chat, /*width*/ 80)) ); } diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_information_dismissible.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_information_dismissible.snap index dd73e1cfe1..b080cee340 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_information_dismissible.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_information_dismissible.snap @@ -12,3 +12,4 @@ expression: rendered › Ask Codex to do anything test-model-a default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_information_only.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_information_only.snap index af451575ef..f1f3714bf7 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_information_only.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_information_only.snap @@ -10,3 +10,4 @@ expression: rendered › Ask Codex to do anything test-model-a default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_notification.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_notification.snap index eecda45a89..dc95e5bb47 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_notification.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__backend_banners_tests__backend_banner_notification.snap @@ -12,3 +12,4 @@ expression: "normalize_snapshot_paths(render_bottom_popup(&chat, 70))" › Ask Codex to do anything test-model-a default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_narrow.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_narrow.snap index 0644d12b6f..29adb8aee7 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_narrow.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_narrow.snap @@ -2,7 +2,7 @@ source: tui/src/chatwidget/tests/luna_reserve_usage_tests.rs expression: "render_bottom_popup(&chat, 34)" --- - › Ask Codex to do anything Luna Reserve default · /tmp/pro… + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_running.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_running.snap index 4f4664d17a..de903fdb74 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_running.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_running.snap @@ -7,4 +7,5 @@ expression: rendered › x - tab to queue message 100% context left + Luna Reserve default · /tmp/project + tab to queue message diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_wide.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_wide.snap index d6537e354d..d0d2d70ff2 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_wide.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__luna_reserve_usage_tests__luna_reserve_usage_wide.snap @@ -2,7 +2,7 @@ source: tui/src/chatwidget/tests/luna_reserve_usage_tests.rs expression: rendered --- - › Ask Codex to do anything Luna Reserve default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__question_turn_end_tests__question_turn_end_keeps_history_search.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__question_turn_end_tests__question_turn_end_keeps_history_search.snap index 73904dfd0a..32a9c7ebb3 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__question_turn_end_tests__question_turn_end_keeps_history_search.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__question_turn_end_tests__question_turn_end_keeps_history_search.snap @@ -5,4 +5,5 @@ expression: "normalize_snapshot_paths(render_bottom_popup(&chat, 80))" --- › earlier prompt + GPT-5.6-Sol default · /tmp/project reverse-i-search: e enter accept · esc cancel diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_after_cutoff.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_after_cutoff.snap index 00a6396097..fbb7e1bb93 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_after_cutoff.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_after_cutoff.snap @@ -18,3 +18,4 @@ expression: "normalize_snapshot_paths(render_bottom_popup(&chat, 48))" › Ask Codex to do anything test-model-a default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_after_persona_grace.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_after_persona_grace.snap index 849c8a09a3..97b31038b0 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_after_persona_grace.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_after_persona_grace.snap @@ -17,3 +17,4 @@ expression: "normalize_snapshot_paths(render_bottom_popup(&chat, 48))" › Ask Codex to do anything test-model-a default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_banner.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_banner.snap index bff2ed1194..5c4697d5ab 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_banner.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_banner.snap @@ -15,3 +15,4 @@ expression: rendered › Ask Codex to do anything test-model-a default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_dismissed_after_usage.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_dismissed_after_usage.snap index 77b7fbd67f..7dc1d10ba1 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_dismissed_after_usage.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__security_setup_tests__security_setup_dismissed_after_usage.snap @@ -5,3 +5,4 @@ expression: rendered › Ask Codex to do anything test-model-a default · /tmp/project + ? for shortcuts diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__slash_commands__transcript_copy_success.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__slash_commands__transcript_copy_success.snap index 073cd11c19..6c7bcc6a2c 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__slash_commands__transcript_copy_success.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__slash_commands__transcript_copy_success.snap @@ -4,4 +4,5 @@ expression: "render_bottom_popup(&chat, 80)" --- › Ask Codex to do anything + GPT-5.6-Sol default · /tmp/project Copied selection to clipboard diff --git a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__slash_commands__transcript_copy_unconfirmed.snap b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__slash_commands__transcript_copy_unconfirmed.snap index 51efc1d5e0..1799a4bd2a 100644 --- a/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__slash_commands__transcript_copy_unconfirmed.snap +++ b/codex-rs/tui/src/chatwidget/tests/snapshots/codex_tui__chatwidget__tests__slash_commands__transcript_copy_unconfirmed.snap @@ -4,4 +4,5 @@ expression: "render_bottom_popup(&chat, 80)" --- › Ask Codex to do anything + GPT-5.6-Sol default · /tmp/project Copy unconfirmed; /export saves chat diff --git a/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs b/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs index 15498ec20e..3491d386b4 100644 --- a/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs +++ b/codex-rs/tui/src/chatwidget/tests/status_and_layout.rs @@ -2950,12 +2950,12 @@ async fn ambient_pet_reduces_stream_width_and_composer_text_width() { .set_composer_text(draft, Vec::new(), Vec::new()); let mut with_pet_terminal = - Terminal::new(TestBackend::new(/*width*/ 80, /*height*/ 6)).expect("create terminal"); + Terminal::new(TestBackend::new(/*width*/ 80, /*height*/ 8)).expect("create terminal"); with_pet_terminal .draw(|f| with_pet.render(f.area(), f.buffer_mut())) .expect("draw pet-enabled chat"); let mut disabled_terminal = - Terminal::new(TestBackend::new(/*width*/ 80, /*height*/ 6)).expect("create terminal"); + Terminal::new(TestBackend::new(/*width*/ 80, /*height*/ 8)).expect("create terminal"); disabled_terminal .draw(|f| disabled.render(f.area(), f.buffer_mut())) .expect("draw disabled-pet chat"); @@ -5977,7 +5977,7 @@ fn hook_status_frame(chat: &ChatWidget, width: u16) -> String { .expect("render hook activity frame"); // Windows path normalization drops Display's final newline; make composed // frames independent of that platform difference. - normalized_backend_snapshot(terminal.backend()) + normalize_working_snapshot(normalized_backend_snapshot(terminal.backend())) .trim_end() .to_string() } diff --git a/codex-rs/tui/src/snapshots/codex_tui__app__tests__selected_unloaded_subagent_V1.snap b/codex-rs/tui/src/snapshots/codex_tui__app__tests__selected_unloaded_subagent_V1.snap index 9e40dcd3a5..c6b4662a4b 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__app__tests__selected_unloaded_subagent_V1.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__app__tests__selected_unloaded_subagent_V1.snap @@ -5,4 +5,5 @@ expression: "render_bottom_popup(&app.chat_widget, 80)" --- › Ask Codex to do anything - GPT-6.1-Sol default · /tmp/project · child-0 [worker] · ← for agents + GPT-6.1-Sol default · /tmp/project · child-0 [worker] + ← for agents · ? for shortcuts diff --git a/codex-rs/tui/src/snapshots/codex_tui__app__tests__selected_unloaded_subagent_V2.snap b/codex-rs/tui/src/snapshots/codex_tui__app__tests__selected_unloaded_subagent_V2.snap index f99b38fb4e..57f244c41f 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__app__tests__selected_unloaded_subagent_V2.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__app__tests__selected_unloaded_subagent_V2.snap @@ -5,4 +5,5 @@ expression: "render_bottom_popup(&app.chat_widget, 80)" --- › Viewing sub-agent — direct input is disabled - GPT-6.1-Sol default · /tmp/project · child-1 [worker] · ← for agents + GPT-6.1-Sol default · /tmp/project · child-1 [worker] + ← for agents · ? for shortcuts diff --git a/codex-rs/tui/src/snapshots/codex_tui__app_server_session__tests__resumed_plan_mode.snap b/codex-rs/tui/src/snapshots/codex_tui__app_server_session__tests__resumed_plan_mode.snap index cf58c4def2..32097c55f3 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__app_server_session__tests__resumed_plan_mode.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__app_server_session__tests__resumed_plan_mode.snap @@ -4,4 +4,5 @@ expression: "crate::chatwidget::tests::helpers::render_bottom_popup(&chat, 40)" --- › Ask Codex to do anything - GPT-5.5 default · /tmp/pr… Plan mode + GPT-5.5 default · /tmp/project + ? for shortcuts Plan mode diff --git a/codex-rs/tui/src/snapshots/codex_tui__startup_draft__layout__tests__owned_startup_layout.snap b/codex-rs/tui/src/snapshots/codex_tui__startup_draft__layout__tests__owned_startup_layout.snap index 6065eb8406..ce2aa2af97 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__startup_draft__layout__tests__owned_startup_layout.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__startup_draft__layout__tests__owned_startup_layout.snap @@ -2,7 +2,7 @@ source: tui/src/startup_draft_layout_tests.rs expression: "format!(\"cursor={:?}\\n{frame}\",\nlayout.cursor_pos(area)).replace(crate::version::CODEX_CLI_VERSION,\n\"\")" --- -cursor=Some((13, 12)) +cursor=Some((13, 13)) >_ OpenAI Codex (v) loading @@ -14,8 +14,8 @@ cursor=Some((13, 12)) + › first line second line - Waiting for startup · esc cancel