Compare commits

...

2 Commits

Author SHA1 Message Date
Eric Traut
9bef8e6cb1 Fix same-thread resume noop test 2026-03-28 23:21:15 -06:00
Eric Traut
8de7d89cc7 Prevent same-thread resume from disconnecting the TUI 2026-03-28 23:19:09 -06:00
4 changed files with 61 additions and 11 deletions

View File

@@ -1656,6 +1656,21 @@ impl App {
self.active_thread_id.or(self.chat_widget.thread_id())
}
fn ignore_same_thread_resume(
&mut self,
target_session: &crate::resume_picker::SessionTarget,
) -> bool {
if self.current_displayed_thread_id() != Some(target_session.thread_id) {
return false;
}
self.chat_widget.add_info_message(
format!("Already viewing {}.", target_session.display_label()),
/*hint*/ None,
);
true
}
/// Mirrors the visible thread into the contextual footer row.
///
/// The footer sometimes shows ambient context instead of an instructional hint. In multi-agent
@@ -3682,6 +3697,10 @@ impl App {
.await?
{
SessionSelection::Resume(target_session) => {
if self.ignore_same_thread_resume(&target_session) {
tui.frame_requester().schedule_frame();
return Ok(AppRunControl::Continue);
}
let current_cwd = self.config.cwd.to_path_buf();
let resume_cwd = if self.remote_app_server_url.is_some() {
current_cwd.clone()
@@ -6020,6 +6039,41 @@ mod tests {
);
}
#[tokio::test]
async fn ignore_same_thread_resume_reports_noop_for_current_thread() {
let mut app = make_test_app().await;
let thread_id = ThreadId::new();
let session = test_thread_session(thread_id, PathBuf::from("/tmp/project"));
app.chat_widget.handle_thread_session(session);
app.active_thread_id = Some(thread_id);
let ignored = app.ignore_same_thread_resume(&crate::resume_picker::SessionTarget {
path: Some(PathBuf::from("/tmp/project")),
thread_id,
});
assert!(ignored);
assert_eq!(app.current_displayed_thread_id(), Some(thread_id));
}
#[tokio::test]
async fn ignore_same_thread_resume_allows_switching_threads() {
let mut app = make_test_app().await;
let current_thread_id = ThreadId::new();
let other_thread_id = ThreadId::new();
let session = test_thread_session(current_thread_id, PathBuf::from("/tmp/current"));
app.chat_widget.handle_thread_session(session);
app.active_thread_id = Some(current_thread_id);
let ignored = app.ignore_same_thread_resume(&crate::resume_picker::SessionTarget {
path: Some(PathBuf::from("/tmp/other")),
thread_id: other_thread_id,
});
assert!(!ignored);
assert!(app.transcript_cells.is_empty());
}
#[tokio::test]
async fn enqueue_primary_thread_session_replays_buffered_approval_after_attach() -> Result<()> {
let (mut app, mut app_event_rx, _op_rx) = make_test_app_with_channels().await;

View File

@@ -1,6 +1,6 @@
---
source: tui/src/chatwidget/tests.rs
assertion_line: 9607
assertion_line: 9745
expression: popup
---
Update Model Permissions

View File

@@ -0,0 +1,6 @@
---
source: tui/src/chatwidget/tests.rs
assertion_line: 10414
expression: "lines_to_single_string(&cells[0])"
---
• Permissions updated to Guardian Approvals

View File

@@ -1,10 +0,0 @@
---
source: tui/src/chatwidget/tests.rs
assertion_line: 12789
expression: combined
---
• Running UserPromptSubmit hook: checking go-workflow input policy
UserPromptSubmit hook (stopped)
warning: go-workflow must start from PlanMode
stop: prompt blocked