notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit be140bc70563f6eeb6d30a90d48e3f092ce6535a
parent fc4b673e7f1aede2432a6b0ceb2ddde64fabf812
Author: William Casarin <jb55@jb55.com>
Date:   Mon, 16 Feb 2026 15:38:18 -0800

auto-focus Done sessions in the focus queue

Done sessions were being silently added to the queue but never
auto-focused, making it easy to miss completed work. Now auto-steal
focuses Done sessions after NeedsInput, returning home only when
neither remain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Diffstat:
Mcrates/notedeck_dave/src/focus_queue.rs | 14++++++++++++++
Mcrates/notedeck_dave/src/update.rs | 36++++++++++++++++++++++++++++++++++--
2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/crates/notedeck_dave/src/focus_queue.rs b/crates/notedeck_dave/src/focus_queue.rs @@ -255,6 +255,20 @@ impl FocusQueue { .any(|e| e.priority == FocusPriority::NeedsInput) } + /// Find the first entry with Done priority and return its index + pub fn first_done_index(&self) -> Option<usize> { + self.entries + .iter() + .position(|e| e.priority == FocusPriority::Done) + } + + /// Check if there are any Done items in the queue + pub fn has_done(&self) -> bool { + self.entries + .iter() + .any(|e| e.priority == FocusPriority::Done) + } + pub fn ui_info(&self) -> Option<(usize, usize, FocusPriority)> { let entry = self.current()?; Some((self.current_position()?, self.len(), entry.priority)) diff --git a/crates/notedeck_dave/src/update.rs b/crates/notedeck_dave/src/update.rs @@ -534,7 +534,7 @@ pub fn toggle_auto_steal( } /// Process auto-steal focus logic: switch to focus queue items as needed. -/// Returns true if focus was stolen (switched to a NeedsInput session), +/// Returns true if focus was stolen (switched to a NeedsInput or Done session), /// which can be used to raise the OS window. pub fn process_auto_steal_focus( session_manager: &mut SessionManager, @@ -549,6 +549,7 @@ pub fn process_auto_steal_focus( } let has_needs_input = focus_queue.has_needs_input(); + let has_done = focus_queue.has_done(); if has_needs_input { // There are NeedsInput items - check if we need to steal focus @@ -581,8 +582,39 @@ pub fn process_auto_steal_focus( } } } + } else if has_done { + // No NeedsInput but there are Done items - auto-focus those + let current_session = session_manager.active_id(); + let current_priority = current_session.and_then(|id| focus_queue.get_session_priority(id)); + let already_on_done = current_priority == Some(FocusPriority::Done); + + if !already_on_done { + // Save current session before stealing (only if we haven't saved yet) + if home_session.is_none() { + *home_session = current_session; + tracing::debug!("Auto-steal: saved home session {:?}", home_session); + } + + // Jump to first Done item + if let Some(idx) = focus_queue.first_done_index() { + focus_queue.set_cursor(idx); + if let Some(entry) = focus_queue.current() { + session_manager.switch_to(entry.session_id); + if show_scene { + scene.select(entry.session_id); + if let Some(session) = session_manager.get(entry.session_id) { + if let Some(agentic) = &session.agentic { + scene.focus_on(agentic.scene_position); + } + } + } + tracing::debug!("Auto-steal: switched to Done session {:?}", entry.session_id); + return true; + } + } + } } else if let Some(home_id) = home_session.take() { - // No more NeedsInput items - return to saved session + // No more NeedsInput or Done items - return to saved session session_manager.switch_to(home_id); if show_scene { scene.select(home_id);