diff --git a/codex-rs/config/src/tui_keymap.rs b/codex-rs/config/src/tui_keymap.rs index 1de9bdd5d9..4b532faa8a 100644 --- a/codex-rs/config/src/tui_keymap.rs +++ b/codex-rs/config/src/tui_keymap.rs @@ -443,6 +443,8 @@ pub struct TuiAgentsKeymap { pub rename: Option, /// Stop the selected running task. pub stop: Option, + /// Hide the selected task until explicitly resumed or the TUI restarts. + pub hide: Option, /// Toggle grouping tasks by status or project. pub toggle_grouping: Option, } diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index 9e0e2eb685..2d62cc765f 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -3993,6 +3993,7 @@ ], "default": { "agents": { + "hide": null, "new_task": null, "rename": null, "resume": null, @@ -4303,6 +4304,14 @@ "additionalProperties": false, "description": "Shortcuts specific to the shared agents overview.", "properties": { + "hide": { + "allOf": [ + { + "$ref": "#/definitions/KeybindingsSpec" + } + ], + "description": "Hide the selected task until explicitly resumed or the TUI restarts." + }, "new_task": { "allOf": [ { @@ -4808,6 +4817,7 @@ } ], "default": { + "hide": null, "new_task": null, "rename": null, "resume": null, diff --git a/codex-rs/tui/src/app/agents_overview.rs b/codex-rs/tui/src/app/agents_overview.rs index cb1ebc9252..822b932605 100644 --- a/codex-rs/tui/src/app/agents_overview.rs +++ b/codex-rs/tui/src/app/agents_overview.rs @@ -32,6 +32,8 @@ pub(crate) const AGENTS_OVERVIEW_VIEW_ID: &str = "agents-overview"; pub(super) struct AgentsOverviewState { /// Missing metadata records a local resume until the next metadata refresh. pub(super) threads: HashMap>, + /// Local visibility only; activity and metadata refreshes never reveal hidden roots. + pub(super) hidden_threads: HashSet, pub(super) last_messages: HashMap, pub(super) activity: HashMap, pub(super) initialized: bool, @@ -270,6 +272,9 @@ impl App { let Ok(thread_id) = ThreadId::from_string(&root.id) else { continue; }; + if self.agents_overview.hidden_threads.contains(&thread_id) { + continue; + } rows.push(AgentsOverviewRow { details: self.agents_overview_details(root, &children), thread: root.clone(), diff --git a/codex-rs/tui/src/app/agents_overview_actions_tests.rs b/codex-rs/tui/src/app/agents_overview_actions_tests.rs new file mode 100644 index 0000000000..afe2b05588 --- /dev/null +++ b/codex-rs/tui/src/app/agents_overview_actions_tests.rs @@ -0,0 +1,185 @@ +use super::*; +use pretty_assertions::assert_eq; + +#[tokio::test] +async fn lifecycle_shortcuts_target_filtered_task_in_any_state() { + let mut app = make_test_app().await; + let mut keymap = TuiKeymap::default(); + keymap.agents.hide = Some(KeybindingsSpec::One(KeybindingSpec("f7".into()))); + app.keymap = RuntimeKeymap::from_config(&keymap).unwrap(); + let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel(); + app.app_event_tx = AppEventSender::new(tx); + for status in [ + ThreadStatus::Idle, + ThreadStatus::NotLoaded, + ThreadStatus::Active { + active_flags: Vec::new(), + }, + ] { + app.agents_overview + .view_state + .lock() + .unwrap() + .focus_composer(); + let target = ThreadId::new(); + let mut view = app.agents_overview_view( + vec![ + overview_thread( + ThreadId::new(), + /*parent_thread_id*/ None, + "Other", + ThreadStatus::Idle, + ), + overview_thread(target, /*parent_thread_id*/ None, "Target", status), + ], + Some(target), + ); + view.handle_key_event(KeyCode::Esc.into()); + view.handle_key_event(KeyEvent::new(KeyCode::Char('f'), KeyModifiers::CONTROL)); + for character in "Target".chars() { + view.handle_key_event(KeyCode::Char(character).into()); + } + view.handle_key_event(KeyCode::F(7).into()); + assert!( + matches!(rx.try_recv(), Ok(AppEvent::HideAgentsOverviewThread { thread_id }) if thread_id == target) + ); + assert!(rx.try_recv().is_err()); + view.handle_key_event(KeyCode::Esc.into()); + } +} + +#[tokio::test] +async fn hidden_task_stays_hidden_through_activity_and_seed_until_explicit_resume() -> Result<()> { + let (mut app, mut rx, _op_rx) = crate::app::tests::make_test_app_with_channels().await; + let mut app_server = crate::start_embedded_app_server_for_picker(&app.config).await?; + let started = app_server.start_thread(&app.config).await?; + let id = started.session.thread_id; + app.enqueue_primary_thread_session(started.session, started.turns) + .await?; + let thread = overview_thread( + id, + /*parent_thread_id*/ None, + "Hidden task", + ThreadStatus::Idle, + ); + app.agents_overview.threads.insert(id, Some(thread.clone())); + let mut tui = crate::tui::test_support::make_test_tui()?; + let view = app.agents_overview_view(vec![thread.clone()], Some(id)); + app.chat_widget.show_bottom_pane_view(Box::new(view)); + app.chat_widget.handle_key_event(KeyCode::Esc.into()); + app.chat_widget + .handle_key_event(KeyEvent::new(KeyCode::Char('w'), KeyModifiers::CONTROL)); + let hide = std::iter::from_fn(|| rx.try_recv().ok()) + .find(|event| matches!(event, AppEvent::HideAgentsOverviewThread { .. })) + .expect("shortcut requests hiding the task"); + Box::pin(app.handle_event(&mut tui, &mut app_server, hide)).await?; + app.track_agents_overview_notification(&ServerNotification::ThreadStarted( + ThreadStartedNotification { + thread: thread.clone(), + }, + )); + app.track_agents_overview_notification(&ServerNotification::ThreadStatusChanged( + codex_app_server_protocol::ThreadStatusChangedNotification { + thread_id: id.to_string(), + status: ThreadStatus::Active { + active_flags: Vec::new(), + }, + }, + )); + app.track_agents_overview_notification(&ServerNotification::ThreadClosed( + ThreadClosedNotification { + thread_id: id.to_string(), + }, + )); + let request_id = Uuid::new_v4(); + app.agents_overview.initialized = false; + app.agents_overview.request_id = Some(request_id); + app.apply_agents_overview_thread_refresh( + &app_server, + request_id, + Ok(AgentsOverviewThreadRefresh { + threads: HashMap::from([(id, Some(thread.clone()))]), + last_messages: HashMap::new(), + recent_seed_complete: true, + }), + ); + assert_eq!( + app.agents_overview_view(vec![thread.clone()], /*selected_thread_id*/ None) + .thread_ids(), + Vec::::new() + ); + assert_eq!(app.primary_thread_id, Some(id)); + app.resume_target_session( + &mut tui, + &mut app_server, + SessionTarget { + thread_id: id, + path: None, + cwd: None, + history_mode: None, + }, + ) + .await?; + assert_eq!( + app.agents_overview_view(vec![thread], /*selected_thread_id*/ None) + .thread_ids(), + vec![id] + ); + app_server.shutdown().await?; + Ok(()) +} + +#[tokio::test] +async fn lifecycle_footer_keeps_custom_chords_with_labels() { + let mut app = make_test_app().await; + app.keymap = RuntimeKeymap::from_config( + &serde_json::from_value(serde_json::json!({ + "agents": { "hide": "f5 f8" } + })) + .unwrap(), + ) + .unwrap(); + let mut view = app.agents_overview_view( + vec![overview_thread( + ThreadId::new(), + /*parent_thread_id*/ None, + "Task", + ThreadStatus::Idle, + )], + /*selected_thread_id*/ None, + ); + view.handle_key_event(KeyCode::Esc.into()); + for width in [36, 48, 80] { + let area = Rect::new(/*x*/ 0, /*y*/ 0, width + 4, /*height*/ 24); + let mut buffer = ratatui::buffer::Buffer::empty(area); + view.render(area, &mut buffer); + let lines = buffer + .content() + .chunks(usize::from(area.width)) + .map(|row| { + row.iter() + .map(ratatui::buffer::Cell::symbol) + .collect::() + .trim() + .to_string() + }) + .collect::>(); + assert!( + lines + .iter() + .any(|line| line.contains("hide") && line.contains("f5")) + ); + assert!( + lines + .iter() + .all(|line| unicode_width::UnicodeWidthStr::width(line.as_str()) + <= usize::from(width)) + ); + } + app.chat_widget.show_bottom_pane_view(Box::new(view)); + insta::assert_snapshot!( + "agents_custom_lifecycle_chords", + render_bottom_popup(&app.chat_widget, /*width*/ 48) + .replace(&test_path_display("/tmp/project"), "/tmp/project") + ); +} diff --git a/codex-rs/tui/src/app/agents_overview_render.rs b/codex-rs/tui/src/app/agents_overview_render.rs index a3c2928d93..036f0c5e45 100644 --- a/codex-rs/tui/src/app/agents_overview_render.rs +++ b/codex-rs/tui/src/app/agents_overview_render.rs @@ -25,6 +25,7 @@ impl AgentsOverviewView { &self.agents_keymap.new_task, &self.agents_keymap.rename, &self.agents_keymap.stop, + &self.agents_keymap.hide, &self.agents_keymap.toggle_grouping, ] .into_iter() @@ -46,15 +47,20 @@ impl AgentsOverviewView { " " }, ); - let mut footer_spans = Vec::new(); + let mut hints: Vec> = Vec::new(); if !navigation_hint.is_empty() { - footer_spans.extend([navigation_hint.bold(), " navigate ".dim()]); + hints.push(vec![navigation_hint.bold(), " navigate".dim()].into()); } let mut add_hint = |hint: Option, label: &'static str, enabled: bool| { if let Some(hint) = hint { let key = hint.display_label().replace(" + ", "+"); - footer_spans.push(if enabled { key.bold() } else { key.dim() }); - footer_spans.push(format!(" {label} ").dim()); + hints.push( + vec![ + if enabled { key.bold() } else { key.dim() }, + format!(" {label}").dim(), + ] + .into(), + ); } }; add_hint( @@ -99,16 +105,35 @@ impl AgentsOverviewView { self.selected_row() .is_some_and(|row| matches!(row.thread.status, ThreadStatus::Active { .. })), ); + add_hint( + self.agents_keymap + .primary_hint("hide", &self.agents_keymap.hide), + "hide", + self.selected_row().is_some(), + ); add_hint(list_hint(ListAction::Cancel), "back", true); - let mut footer_line: Line = footer_spans.into(); - if footer_line.width() > usize::from(width) { - for span in &mut footer_line.spans { - if span.content.ends_with(" ") { - span.content.to_mut().pop(); + let separator = if hints.iter().map(Line::width).sum::() + + hints.len().saturating_sub(1) * 2 + <= usize::from(width) + { + " " + } else { + " " + }; + crate::footer_hint::wrap_hint_rows(hints, width, separator.len(), Line::width) + .into_iter() + .flat_map(|row| { + let mut line = Line::default(); + for hint in row { + if !line.spans.is_empty() { + line.spans.push(separator.dim()); + } + line.spans.extend(hint.spans); } - } - } - crate::wrapping::word_wrap_lines([footer_line], usize::from(width)) + // An individual custom chord may be wider than the entire terminal. + crate::wrapping::word_wrap_lines([line], usize::from(width.max(1))) + }) + .collect() } } diff --git a/codex-rs/tui/src/app/agents_overview_tests.rs b/codex-rs/tui/src/app/agents_overview_tests.rs index e2bff9b91d..0219a57531 100644 --- a/codex-rs/tui/src/app/agents_overview_tests.rs +++ b/codex-rs/tui/src/app/agents_overview_tests.rs @@ -2258,3 +2258,6 @@ async fn command_center_handles_resume_failure_and_success() -> Result<()> { server.shutdown().await?; Ok(()) } + +#[path = "agents_overview_actions_tests.rs"] +mod actions; diff --git a/codex-rs/tui/src/app/agents_overview_view.rs b/codex-rs/tui/src/app/agents_overview_view.rs index 5db8cad719..9b042d8fea 100644 --- a/codex-rs/tui/src/app/agents_overview_view.rs +++ b/codex-rs/tui/src/app/agents_overview_view.rs @@ -689,6 +689,14 @@ impl BottomPaneView for AgentsOverviewView { } return; } + if self.agents_keymap.hide.is_pressed(key) { + if let Some(row) = self.selected_row() { + self.app_event_tx.send(AppEvent::HideAgentsOverviewThread { + thread_id: row.thread_id, + }); + } + return; + } if self.agents_keymap.stop.is_pressed(key) { if let Some(row) = self.selected_row() && matches!(row.thread.status, ThreadStatus::Active { .. }) diff --git a/codex-rs/tui/src/app/event_dispatch.rs b/codex-rs/tui/src/app/event_dispatch.rs index 2ce46b43f1..60088fe4bd 100644 --- a/codex-rs/tui/src/app/event_dispatch.rs +++ b/codex-rs/tui/src/app/event_dispatch.rs @@ -2803,6 +2803,10 @@ impl App { } } } + AppEvent::HideAgentsOverviewThread { thread_id } => { + self.agents_overview.hidden_threads.insert(thread_id); + self.repaint_agents_overview(); + } AppEvent::StopAgentsOverviewThread { thread_id } => { self.stop_agents_overview_thread(app_server, thread_id) .await; diff --git a/codex-rs/tui/src/app/session_lifecycle.rs b/codex-rs/tui/src/app/session_lifecycle.rs index ef3740cdf6..98e03ab10b 100644 --- a/codex-rs/tui/src/app/session_lifecycle.rs +++ b/codex-rs/tui/src/app/session_lifecycle.rs @@ -1191,6 +1191,10 @@ impl App { target_session: SessionTarget, ) -> Result { if self.ignore_same_thread_resume(&target_session) { + self.agents_overview + .hidden_threads + .remove(&target_session.thread_id); + self.repaint_agents_overview(); tui.frame_requester().schedule_frame(); return Ok(AppRunControl::Continue); } diff --git a/codex-rs/tui/src/app/snapshots/codex_tui__app__agents_overview__tests__actions__agents_custom_lifecycle_chords.snap b/codex-rs/tui/src/app/snapshots/codex_tui__app__agents_overview__tests__actions__agents_custom_lifecycle_chords.snap new file mode 100644 index 0000000000..c24bd213a9 --- /dev/null +++ b/codex-rs/tui/src/app/snapshots/codex_tui__app__agents_overview__tests__actions__agents_custom_lifecycle_chords.snap @@ -0,0 +1,28 @@ +--- +source: tui/src/app/agents_overview_actions_tests.rs +expression: "render_bottom_popup(&app.chat_widget, 48)" +--- + Agent command center + 0 need input 0 working 1 ready + ──────────────────────────────────────────── + /tmp/project 1 + › ○ Task Ready + + + + + + + + + + + + New task + +› Describe a new task + + ↑↓ navigate ctrl+o resume → open + ctrl+n new task ctrl+f search ctrl+s group + ctrl+r rename ctrl+x stop f5 f8 hide + esc back diff --git a/codex-rs/tui/src/app/thread_routing.rs b/codex-rs/tui/src/app/thread_routing.rs index 5254d18af8..4d9ecab82c 100644 --- a/codex-rs/tui/src/app/thread_routing.rs +++ b/codex-rs/tui/src/app/thread_routing.rs @@ -1511,6 +1511,7 @@ impl App { self.recap.reset_for_new_thread(Instant::now()); } self.primary_thread_id = Some(thread_id); + self.agents_overview.hidden_threads.remove(&thread_id); self.agents_overview.threads.entry(thread_id).or_default(); self.primary_session_configured = Some(session.clone()); self.upsert_agent_picker_thread( diff --git a/codex-rs/tui/src/app_event.rs b/codex-rs/tui/src/app_event.rs index 3697ebb118..20ca588c66 100644 --- a/codex-rs/tui/src/app_event.rs +++ b/codex-rs/tui/src/app_event.rs @@ -310,6 +310,10 @@ pub(crate) enum AppEvent { StopAgentsOverviewThread { thread_id: ThreadId, }, + /// Hide a dashboard row locally without stopping its task. + HideAgentsOverviewThread { + thread_id: ThreadId, + }, /// Start the shared app-server daemon without moving the current embedded session. #[cfg(any(unix, windows))] StartAgentsDaemon, diff --git a/codex-rs/tui/src/keymap.rs b/codex-rs/tui/src/keymap.rs index 6f5fbdf8ed..4f8bb1ace0 100644 --- a/codex-rs/tui/src/keymap.rs +++ b/codex-rs/tui/src/keymap.rs @@ -411,6 +411,7 @@ pub(crate) struct AgentsKeymap { pub(crate) new_task: Vec, pub(crate) rename: Vec, pub(crate) stop: Vec, + pub(crate) hide: Vec, pub(crate) toggle_grouping: Vec, chord_hints: Arc, } @@ -1289,10 +1290,24 @@ impl RuntimeKeymap { new_task: resolve_local!(keymap, defaults, agents, new_task), rename: resolve_local!(keymap, defaults, agents, rename), stop: resolve_local!(keymap, defaults, agents, stop), + hide: resolve_local!(keymap, defaults, agents, hide), toggle_grouping: resolve_local!(keymap, defaults, agents, toggle_grouping), chord_hints: Arc::clone(&chords), }; + // The new default yields to existing user bindings in the dashboard. + if keymap.agents.hide.is_none() + && (configured_context_alias_is_used(&keymap.agents, "ctrl-w") + || configured_context_alias_is_used(&keymap.list, "ctrl-w") + || configured_context_alias_is_used(&keymap.global, "ctrl-w") + || chords.bindings.iter().any(|chord| { + chord.action.context.overlaps(KeymapContext::Agents) + && agents.hide.contains(&chord.chord.prefix) + })) + { + agents.hide.clear(); + } + let approval = ApprovalKeymap { open_fullscreen: resolve_local!(keymap, defaults, approval, open_fullscreen), open_thread: resolve_local!(keymap, defaults, approval, open_thread), @@ -1425,6 +1440,7 @@ impl RuntimeKeymap { (keymap.agents.new_task.as_ref(), &mut agents.new_task), (keymap.agents.rename.as_ref(), &mut agents.rename), (keymap.agents.stop.as_ref(), &mut agents.stop), + (keymap.agents.hide.as_ref(), &mut agents.hide), ( keymap.agents.toggle_grouping.as_ref(), &mut agents.toggle_grouping, @@ -1789,6 +1805,7 @@ impl RuntimeKeymap { new_task: default_bindings![ctrl(KeyCode::Char('n'))], rename: default_bindings![ctrl(KeyCode::Char('r'))], stop: default_bindings![ctrl(KeyCode::Char('x'))], + hide: default_bindings![ctrl(KeyCode::Char('w'))], toggle_grouping: default_bindings![ctrl(KeyCode::Char('s'))], chord_hints: Arc::default(), }, diff --git a/codex-rs/tui/src/keymap/bindings.rs b/codex-rs/tui/src/keymap/bindings.rs index bfd05b9959..e65c0bc885 100644 --- a/codex-rs/tui/src/keymap/bindings.rs +++ b/codex-rs/tui/src/keymap/bindings.rs @@ -398,6 +398,7 @@ define_runtime_action_bindings! { new_task, rename, stop, + hide, toggle_grouping, ], "approval" => Approval, approval, approval [ diff --git a/codex-rs/tui/src/keymap/conflict_tests.rs b/codex-rs/tui/src/keymap/conflict_tests.rs index aa7b034a5c..2d3ad6a0d9 100644 --- a/codex-rs/tui/src/keymap/conflict_tests.rs +++ b/codex-rs/tui/src/keymap/conflict_tests.rs @@ -37,3 +37,19 @@ See the Codex keymap documentation for supported actions and examples." config.remove(context); } } + +#[test] +fn new_agents_defaults_preserve_existing_custom_bindings() { + for context in ["agents", "list"] { + let existing = if context == "agents" { + "stop" + } else { + "move_down" + }; + let keymap: TuiKeymap = + serde_json::from_value(json!({context: {existing: "ctrl-w"}})).unwrap(); + let runtime = + RuntimeKeymap::from_config(&keymap).expect("existing configuration remains valid"); + assert!(runtime.agents.hide.is_empty()); + } +} diff --git a/codex-rs/tui/src/keymap_setup/actions.rs b/codex-rs/tui/src/keymap_setup/actions.rs index 32ce18e254..7d1818df6a 100644 --- a/codex-rs/tui/src/keymap_setup/actions.rs +++ b/codex-rs/tui/src/keymap_setup/actions.rs @@ -218,6 +218,7 @@ pub(super) const KEYMAP_ACTIONS: &[KeymapActionDescriptor] = &[ action("agents", "Agents", "new_task", "Start composing a new agent task."), action("agents", "Agents", "rename", "Rename the selected task."), action("agents", "Agents", "stop", "Stop the selected running task."), + action("agents", "Agents", "hide", "Hide the selected task until explicitly resumed."), action("agents", "Agents", "toggle_grouping", "Group tasks by status or project."), action("approval", "Approval", "open_fullscreen", "Open approval details fullscreen."), action("approval", "Approval", "open_thread", "Open the approval source thread when available."), @@ -395,6 +396,7 @@ pub(super) fn binding_slot<'a>( ("agents", "new_task") => Some(&mut keymap.agents.new_task), ("agents", "rename") => Some(&mut keymap.agents.rename), ("agents", "stop") => Some(&mut keymap.agents.stop), + ("agents", "hide") => Some(&mut keymap.agents.hide), ("agents", "toggle_grouping") => Some(&mut keymap.agents.toggle_grouping), ("approval", "open_fullscreen") => Some(&mut keymap.approval.open_fullscreen), ("approval", "open_thread") => Some(&mut keymap.approval.open_thread), diff --git a/codex-rs/tui/src/snapshots/codex_tui__app__agents_overview__tests__agents_overview_empty_narrow.snap b/codex-rs/tui/src/snapshots/codex_tui__app__agents_overview__tests__agents_overview_empty_narrow.snap index 5eff11dbb0..dbe862b406 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__app__agents_overview__tests__agents_overview_empty_narrow.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__app__agents_overview__tests__agents_overview_empty_narrow.snap @@ -18,11 +18,11 @@ expression: "render_bottom_popup(&app.chat_widget, 48)" - New task › Describe a new task - ↑↓ navigate ctrl+o resume → open ctrl+n new - task ctrl+f search ctrl+s group ctrl+r - rename ctrl+x stop esc back + ↑↓ navigate ctrl+o resume → open + ctrl+n new task ctrl+f search ctrl+s group + ctrl+r rename ctrl+x stop ctrl+w hide + esc back diff --git a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_custom.snap b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_custom.snap index 0a93ffc014..c0618d4648 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_custom.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_custom.snap @@ -5,7 +5,7 @@ expression: "render_picker(params, 120)" Keymap All configurable shortcuts. - 142 actions, 1 customized, 5 unbound. + 143 actions, 1 customized, 5 unbound. [All] Common Customized (1) Unbound (5) App Composer Editor Vim Navigation Agents Approval Debug diff --git a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_fast_mode_enabled.snap b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_fast_mode_enabled.snap index 3635d9fd3a..c3660558b4 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_fast_mode_enabled.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_fast_mode_enabled.snap @@ -5,7 +5,7 @@ expression: "render_picker(params, 120)" Keymap All configurable shortcuts. - 143 actions, 0 customized, 6 unbound. + 144 actions, 0 customized, 6 unbound. [All] Common Customized (0) Unbound (6) App Composer Editor Vim Navigation Agents Approval Debug diff --git a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_first_actions.snap b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_first_actions.snap index d7e89b0e1e..f605a3d19a 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_first_actions.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_first_actions.snap @@ -2,7 +2,7 @@ source: tui/src/keymap_setup.rs expression: snapshot --- -tab: All (142 selectable) +tab: All (143 selectable) tab: Common (20 selectable) tab: Customized (0) (0 selectable) tab: Unbound (5) (5 selectable) @@ -11,7 +11,7 @@ tab: Composer (5 selectable) tab: Editor (17 selectable) tab: Vim (69 selectable) tab: Navigation (20 selectable) -tab: Agents (6 selectable) +tab: Agents (7 selectable) tab: Approval (8 selectable) tab: Debug (1 selectable) Open Agents | unbound | Global open_agents Open Agents Open the shared agent-session overview. unbound Default diff --git a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_global_chord.snap b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_global_chord.snap index 14056821ca..6a25089305 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_global_chord.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_global_chord.snap @@ -5,7 +5,7 @@ expression: "render_picker(params, 120)" Keymap All configurable shortcuts. - 142 actions, 1 customized, 6 unbound. + 143 actions, 1 customized, 6 unbound. [All] Common Customized (1) Unbound (6) App Composer Editor Vim Navigation Agents Approval Debug diff --git a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_narrow.snap b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_narrow.snap index 67aca5fa7c..b3598ab122 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_narrow.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_narrow.snap @@ -5,7 +5,7 @@ expression: "render_picker(params, 78)" Keymap All configurable shortcuts. - 142 actions, 0 customized, 5 unbound. + 143 actions, 0 customized, 5 unbound. [All] Common Customized (0) Unbound (5) App Composer Editor Vim Navigation Agents Approval Debug diff --git a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_wide.snap b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_wide.snap index 1a36659e1c..eb492abd0b 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_wide.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_picker_wide.snap @@ -5,7 +5,7 @@ expression: "render_picker(params, 120)" Keymap All configurable shortcuts. - 142 actions, 0 customized, 5 unbound. + 143 actions, 0 customized, 5 unbound. [All] Common Customized (0) Unbound (5) App Composer Editor Vim Navigation Agents Approval Debug diff --git a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_question_actions.snap b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_question_actions.snap index db06ed85fe..b1fe73575c 100644 --- a/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_question_actions.snap +++ b/codex-rs/tui/src/snapshots/codex_tui__keymap_setup__tests__keymap_question_actions.snap @@ -5,7 +5,7 @@ expression: "render_picker(params, 120)" Keymap All configurable shortcuts. - 142 actions, 0 customized, 5 unbound. + 143 actions, 0 customized, 5 unbound. [All] Common Customized (0) Unbound (5) App Composer Editor Vim Navigation Agents Approval Debug