Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions codex-rs/tui/docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
15 changes: 15 additions & 0 deletions codex-rs/tui/src/chatwidget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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() {
Expand Down
57 changes: 57 additions & 0 deletions codex-rs/tui/src/chatwidget/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
);
}
Loading