commit abe852a6d5092566f91c68e0ef4cd9875420c272
parent 6073de570cf90400c88d772251bcea13ee38fa10
Author: William Casarin <jb55@jb55.com>
Date: Fri, 20 Feb 2026 13:30:20 -0800
dave: clear Done indicator based on session type
The Done focus cue was never cleared because auto-steal bypasses
the SwitchTo action path. Now Done indicators are cleared by a
dedicated clear_done_indicators() step: local agentic sessions
clear when git working tree is clean, chat and remote sessions
clear when the user is viewing them.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
3 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/crates/notedeck_dave/src/focus_queue.rs b/crates/notedeck_dave/src/focus_queue.rs
@@ -129,6 +129,16 @@ impl FocusQueue {
}
}
+ /// Remove a session from the queue only if its priority is Done.
+ pub fn dequeue_done(&mut self, session_id: SessionId) {
+ if let Some(i) = self.find(session_id) {
+ if self.entries[i].priority == FocusPriority::Done {
+ self.entries.remove(i);
+ self.normalize_cursor_after_remove(i);
+ }
+ }
+ }
+
pub fn next(&mut self) -> Option<SessionId> {
if self.entries.is_empty() {
self.cursor = None;
diff --git a/crates/notedeck_dave/src/lib.rs b/crates/notedeck_dave/src/lib.rs
@@ -2416,6 +2416,9 @@ impl notedeck::App for Dave {
notedeck::platform::try_vibrate();
}
+ // Clear Done indicators whose condition is met
+ update::clear_done_indicators(&self.session_manager, &mut self.focus_queue);
+
// Suppress auto-steal while the user is typing (non-empty input)
let user_is_typing = self
.session_manager
diff --git a/crates/notedeck_dave/src/update.rs b/crates/notedeck_dave/src/update.rs
@@ -520,6 +520,38 @@ pub fn toggle_auto_steal(
new_state
}
+/// Clear Done indicators for sessions whose clearing condition is met.
+///
+/// - **Local agentic sessions**: cleared when the git working tree is clean
+/// (the user has committed or reverted changes).
+/// - **Chat and remote sessions**: cleared when the session is the active one
+/// (the user is viewing it).
+pub fn clear_done_indicators(session_manager: &SessionManager, focus_queue: &mut FocusQueue) {
+ let active_id = session_manager.active_id();
+ for session in session_manager.iter() {
+ if focus_queue.get_session_priority(session.id) != Some(FocusPriority::Done) {
+ continue;
+ }
+ let should_clear = if !session.is_remote() {
+ if let Some(agentic) = &session.agentic {
+ agentic
+ .git_status
+ .current()
+ .is_some_and(|r| r.as_ref().is_ok_and(|d| d.is_clean()))
+ } else {
+ // Chat session: clear when viewing
+ active_id == Some(session.id)
+ }
+ } else {
+ // Remote session: clear when viewing
+ active_id == Some(session.id)
+ };
+ if should_clear {
+ focus_queue.dequeue_done(session.id);
+ }
+ }
+}
+
/// Process auto-steal focus logic: switch to focus queue items as needed.
/// Returns true if focus was stolen (switched to a NeedsInput or Done session),
/// which can be used to raise the OS window.
@@ -574,8 +606,8 @@ pub fn process_auto_steal_focus(
tracing::debug!("Auto-steal: saved home session {:?}", home_session);
}
- // Jump to first Done item (keep in queue so blue dot renders;
- // cleared when user manually focuses the session)
+ // Jump to first Done item (keep in queue; cleared externally
+ // when the session's clearing condition is met)
if let Some(idx) = focus_queue.first_done_index() {
focus_queue.set_cursor(idx);
if let Some(entry) = focus_queue.current() {