@@ -847,10 +847,6 @@ impl Sidebar {
// Merge live info into threads and update notification state
// in a single pass.
- let is_active_workspace = active_workspace
- .as_ref()
- .is_some_and(|active| active == workspace);
-
for thread in &mut threads {
let session_id = &thread.session_info.session_id;
@@ -865,16 +861,23 @@ impl Sidebar {
thread.diff_stats = info.diff_stats;
}
+ let is_thread_workspace_active = match &thread.workspace {
+ ThreadEntryWorkspace::Open(thread_workspace) => active_workspace
+ .as_ref()
+ .is_some_and(|active| active == thread_workspace),
+ ThreadEntryWorkspace::Closed(_) => false,
+ };
+
if thread.is_background && thread.status == AgentThreadStatus::Completed {
notified_threads.insert(session_id.clone());
} else if thread.status == AgentThreadStatus::Completed
- && !is_active_workspace
+ && !is_thread_workspace_active
&& old_statuses.get(session_id) == Some(&AgentThreadStatus::Running)
{
notified_threads.insert(session_id.clone());
}
- if is_active_workspace && !thread.is_background {
+ if is_thread_workspace_active && !thread.is_background {
notified_threads.remove(session_id);
}
}
@@ -5304,6 +5307,121 @@ mod tests {
);
}
+ #[gpui::test]
+ async fn test_absorbed_worktree_completion_triggers_notification(cx: &mut TestAppContext) {
+ agent_ui::test_support::init_test(cx);
+ cx.update(|cx| {
+ cx.update_flags(false, vec!["agent-v2".into()]);
+ ThreadStore::init_global(cx);
+ SidebarThreadMetadataStore::init_global(cx);
+ language_model::LanguageModelRegistry::test(cx);
+ prompt_store::init(cx);
+ });
+
+ let fs = FakeFs::new(cx.executor());
+
+ fs.insert_tree(
+ "/project",
+ serde_json::json!({
+ ".git": {
+ "worktrees": {
+ "feature-a": {
+ "commondir": "../../",
+ "HEAD": "ref: refs/heads/feature-a",
+ },
+ },
+ },
+ "src": {},
+ }),
+ )
+ .await;
+
+ fs.insert_tree(
+ "/wt-feature-a",
+ serde_json::json!({
+ ".git": "gitdir: /project/.git/worktrees/feature-a",
+ "src": {},
+ }),
+ )
+ .await;
+
+ fs.with_git_state(std::path::Path::new("/project/.git"), false, |state| {
+ state.worktrees.push(git::repository::Worktree {
+ path: std::path::PathBuf::from("/wt-feature-a"),
+ ref_name: "refs/heads/feature-a".into(),
+ sha: "aaa".into(),
+ });
+ })
+ .unwrap();
+
+ cx.update(|cx| <dyn fs::Fs>::set_global(fs.clone(), cx));
+
+ let main_project = project::Project::test(fs.clone(), ["/project".as_ref()], cx).await;
+ let worktree_project =
+ project::Project::test(fs.clone(), ["/wt-feature-a".as_ref()], cx).await;
+
+ main_project
+ .update(cx, |p, cx| p.git_scans_complete(cx))
+ .await;
+ worktree_project
+ .update(cx, |p, cx| p.git_scans_complete(cx))
+ .await;
+
+ let (multi_workspace, cx) = cx.add_window_view(|window, cx| {
+ MultiWorkspace::test_new(main_project.clone(), window, cx)
+ });
+
+ let worktree_workspace = multi_workspace.update_in(cx, |mw, window, cx| {
+ mw.test_add_workspace(worktree_project.clone(), window, cx)
+ });
+
+ let worktree_panel = add_agent_panel(&worktree_workspace, &worktree_project, cx);
+
+ multi_workspace.update_in(cx, |mw, window, cx| {
+ mw.activate_index(0, window, cx);
+ });
+
+ let sidebar = setup_sidebar(&multi_workspace, cx);
+
+ let connection = StubAgentConnection::new();
+ open_thread_with_connection(&worktree_panel, connection.clone(), cx);
+ send_message(&worktree_panel, cx);
+
+ let session_id = active_session_id(&worktree_panel, cx);
+ let wt_paths = PathList::new(&[std::path::PathBuf::from("/wt-feature-a")]);
+ save_test_thread_metadata(&session_id, wt_paths, cx).await;
+
+ cx.update(|_, cx| {
+ connection.send_update(
+ session_id.clone(),
+ acp::SessionUpdate::AgentMessageChunk(acp::ContentChunk::new("working...".into())),
+ cx,
+ );
+ });
+ cx.run_until_parked();
+
+ assert_eq!(
+ visible_entries_as_strings(&sidebar, cx),
+ vec![
+ "v [project]",
+ " [+ New Thread]",
+ " Hello {wt-feature-a} * (running)",
+ ]
+ );
+
+ connection.end_turn(session_id, acp::StopReason::EndTurn);
+ cx.run_until_parked();
+
+ assert_eq!(
+ visible_entries_as_strings(&sidebar, cx),
+ vec![
+ "v [project]",
+ " [+ New Thread]",
+ " Hello {wt-feature-a} * (!)",
+ ]
+ );
+ }
+
#[gpui::test]
async fn test_clicking_worktree_thread_opens_workspace_when_none_exists(
cx: &mut TestAppContext,