Add running-task exit choices to local daemon sessions (#38447)

## What changed

When `Ctrl-C` is pressed with an empty composer while a task is running in a local daemon session, show a menu that lets the user:

- cancel the task and stay in Codex;
- exit Codex while leaving the task running; or
- stop the task and exit Codex.

Do not offer background execution for side-thread tasks or when follow-up messages are queued. Preserve existing `Ctrl-C` behavior for non-daemon sessions, drafts, paste bursts, MCP startup, and returning from an active side thread.

## Testing

Add TUI tests for each exit action, menu dismissal, side threads, queued follow-ups, composer input, MCP startup, and non-daemon sessions.

GitOrigin-RevId: 539c33d3a4ff288a015bddbe9465d2bbdbe018d0
This commit is contained in:
Eric Traut
2026-08-13 22:38:46 +00:00
committed by copyberry
parent 6344a655a5
commit ca83f7908c
9 changed files with 593 additions and 11 deletions
+14 -9
View File
@@ -496,15 +496,20 @@ impl ChatWidget {
self.bottom_pane.is_task_running() || self.review.is_review_mode
}
fn pause_active_goal_for_interrupt(&self) {
if !self.turn_lifecycle.agent_turn_running {
return;
}
if !self
.current_goal_status
.as_ref()
.is_some_and(GoalStatusState::is_active)
{
pub(crate) fn is_agent_turn_running(&self) -> bool {
self.turn_lifecycle.agent_turn_running
}
pub(crate) fn is_active_goal_turn_running(&self) -> bool {
self.turn_lifecycle.agent_turn_running
&& self
.current_goal_status
.as_ref()
.is_some_and(GoalStatusState::is_active)
}
pub(crate) fn pause_active_goal_for_interrupt(&self) {
if !self.is_active_goal_turn_running() {
return;
}
let Some(thread_id) = self.thread_id else {
+1 -1
View File
@@ -294,7 +294,7 @@ impl ChatWidget {
None
}
pub(super) fn has_queued_follow_up_messages(&self) -> bool {
pub(crate) fn has_queued_follow_up_messages(&self) -> bool {
self.input_queue.has_queued_follow_up_messages()
}