From 5c228e0b7a76db82b5d2d0f5afa4bf000c66a2f3 Mon Sep 17 00:00:00 2001 From: Amol Kapoor Date: Sun, 18 Jan 2026 19:26:30 -0500 Subject: [PATCH] feat(tui): Refresh git branch marker on transcript activity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The branch marker in the footer was only set at session start and never updated. Now it refreshes when the user submits a message or when an agent task completes, catching branch changes made in another terminal. πŸ€– Generated with [Nori](https://nori.ai) Co-Authored-By: Nori --- codex-rs/tui/docs.md | 9 +++++ codex-rs/tui/src/chatwidget.rs | 15 ++++++++ codex-rs/tui/src/chatwidget/tests.rs | 57 ++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) diff --git a/codex-rs/tui/docs.md b/codex-rs/tui/docs.md index bc90b7dcf..e8cc8bcdf 100644 --- a/codex-rs/tui/docs.md +++ b/codex-rs/tui/docs.md @@ -573,6 +573,15 @@ The ACP protocol sets CWD at session creation and it is immutable. However, when β”‚ ChatWidget β”‚ ─────────────────────────▢│ BottomPane β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` +*Transcript Activity Refresh:* + +In addition to CWD tracking, system info refreshes on transcript activity to catch branch changes that occur outside the agent's operations (e.g., user switching branches in another terminal): + +- **User message submission**: `submit_user_message()` sends `RefreshSystemInfoForDirectory(config.cwd)` when the user submits a new message +- **Task completion**: `on_task_complete()` sends `RefreshSystemInfoForDirectory(config.cwd)` when an agent turn finishes + +These triggers use the session CWD (not the effective CWD from tracking) since they detect changes made by the user rather than by agent operations. + *Git Worktree Detection:* `SystemInfo` includes an `is_worktree: bool` field that indicates whether the current directory is a git worktree (not the main repository). Detection works by comparing `git rev-parse --git-common-dir` with `--git-dir` - in a worktree, these paths differ. diff --git a/codex-rs/tui/src/chatwidget.rs b/codex-rs/tui/src/chatwidget.rs index e03b594f9..2a21228d2 100644 --- a/codex-rs/tui/src/chatwidget.rs +++ b/codex-rs/tui/src/chatwidget.rs @@ -619,6 +619,13 @@ impl ChatWidget { self.last_unified_wait = None; self.request_redraw(); + // Refresh system info (including git branch) on task completion. + // This catches any branch changes that occurred during the agent's turn. + self.app_event_tx + .send(AppEvent::RefreshSystemInfoForDirectory( + self.config.cwd.clone(), + )); + // If there is a queued user message, send exactly one now to begin the next turn. self.maybe_send_next_queued_input(); // Emit a notification when the turn completes (suppressed if focused). @@ -1996,6 +2003,14 @@ impl ChatWidget { // Track user message for session statistics self.session_stats.record_user_message(); + // Refresh system info (including git branch) on user message submission. + // This catches branch changes that happened between interactions + // (e.g., user switched branches in another terminal). + self.app_event_tx + .send(AppEvent::RefreshSystemInfoForDirectory( + self.config.cwd.clone(), + )); + // Check if there's a pending agent switch - if so, send the message through // the App to trigger the switch first if let Some(pending) = self.pending_agent.take() { diff --git a/codex-rs/tui/src/chatwidget/tests.rs b/codex-rs/tui/src/chatwidget/tests.rs index 888dfeda8..edc88f8ef 100644 --- a/codex-rs/tui/src/chatwidget/tests.rs +++ b/codex-rs/tui/src/chatwidget/tests.rs @@ -3799,3 +3799,60 @@ mod strip_ansi_codes_tests { assert_eq!(strip_ansi_codes("\x1b[2Jtext\x1b[H"), "text"); } } + +/// Submitting a user message triggers a system info refresh to update the branch marker. +/// This ensures the branch marker in the footer is updated on every transcript activity, +/// catching branch changes that happened between interactions (e.g., user switched +/// branches in another terminal). +#[test] +fn user_message_submission_triggers_system_info_refresh() { + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(); + + // Drain any events from widget construction + drain_refresh_system_info_events(&mut rx); + + // Submit a user message + chat.bottom_pane + .set_composer_text("test message".to_string()); + chat.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)); + + // Verify that RefreshSystemInfoForDirectory was sent + let refresh_dirs = drain_refresh_system_info_events(&mut rx); + assert!( + !refresh_dirs.is_empty(), + "expected RefreshSystemInfoForDirectory event after user message submission" + ); +} + +/// Task completion triggers a system info refresh to update the branch marker. +/// This ensures any branch changes that occurred during the agent's turn are reflected. +#[test] +fn task_complete_triggers_system_info_refresh() { + let (mut chat, mut rx, _op_rx) = make_chatwidget_manual(); + + // Start a task + chat.handle_codex_event(Event { + id: "task-start".into(), + msg: EventMsg::TaskStarted(TaskStartedEvent { + model_context_window: None, + }), + }); + + // Drain any events from task start + drain_refresh_system_info_events(&mut rx); + + // Complete the task + chat.handle_codex_event(Event { + id: "task-complete".into(), + msg: EventMsg::TaskComplete(TaskCompleteEvent { + last_agent_message: Some("Done".to_string()), + }), + }); + + // Verify that RefreshSystemInfoForDirectory was sent + let refresh_dirs = drain_refresh_system_info_events(&mut rx); + assert!( + !refresh_dirs.is_empty(), + "expected RefreshSystemInfoForDirectory event after task completion" + ); +}