Detailed changes
@@ -12,6 +12,7 @@ use gpui::{
};
use notifications::status_toast::{StatusToast, ToastIcon};
use project::{AgentId, AgentRegistryStore, AgentServerStore};
+use remote::RemoteConnectionOptions;
use ui::{
Checkbox, KeyBinding, ListItem, ListItemSpacing, Modal, ModalFooter, ModalHeader, Section,
prelude::*,
@@ -436,19 +437,28 @@ fn find_threads_to_import(
let mut wait_for_connection_tasks = Vec::new();
for store in stores {
+ let remote_connection = store
+ .read(cx)
+ .project()
+ .read(cx)
+ .remote_connection_options(cx);
+
for agent_id in agent_ids.clone() {
let agent = Agent::from(agent_id.clone());
let server = agent.server(<dyn Fs>::global(cx), ThreadStore::global(cx));
let entry = store.update(cx, |store, cx| store.request_connection(agent, server, cx));
- wait_for_connection_tasks
- .push(entry.read(cx).wait_for_connection().map(|s| (agent_id, s)));
+
+ wait_for_connection_tasks.push(entry.read(cx).wait_for_connection().map({
+ let remote_connection = remote_connection.clone();
+ move |state| (agent_id, remote_connection, state)
+ }));
}
}
let mut session_list_tasks = Vec::new();
cx.spawn(async move |cx| {
let results = futures::future::join_all(wait_for_connection_tasks).await;
- for (agent, result) in results {
+ for (agent_id, remote_connection, result) in results {
let Some(state) = result.log_err() else {
continue;
};
@@ -457,18 +467,25 @@ fn find_threads_to_import(
};
let task = cx.update(|cx| {
list.list_sessions(AgentSessionListRequest::default(), cx)
- .map(|r| (agent, r))
+ .map({
+ let remote_connection = remote_connection.clone();
+ move |response| (agent_id, remote_connection, response)
+ })
});
session_list_tasks.push(task);
}
let mut sessions_by_agent = Vec::new();
let results = futures::future::join_all(session_list_tasks).await;
- for (agent_id, result) in results {
+ for (agent_id, remote_connection, result) in results {
let Some(response) = result.log_err() else {
continue;
};
- sessions_by_agent.push((agent_id, response.sessions));
+ sessions_by_agent.push(SessionByAgent {
+ agent_id,
+ remote_connection,
+ sessions: response.sessions,
+ });
}
Ok(collect_importable_threads(
@@ -478,12 +495,23 @@ fn find_threads_to_import(
})
}
+struct SessionByAgent {
+ agent_id: AgentId,
+ remote_connection: Option<RemoteConnectionOptions>,
+ sessions: Vec<acp_thread::AgentSessionInfo>,
+}
+
fn collect_importable_threads(
- sessions_by_agent: Vec<(AgentId, Vec<acp_thread::AgentSessionInfo>)>,
+ sessions_by_agent: Vec<SessionByAgent>,
mut existing_sessions: HashSet<acp::SessionId>,
) -> Vec<ThreadMetadata> {
let mut to_insert = Vec::new();
- for (agent_id, sessions) in sessions_by_agent {
+ for SessionByAgent {
+ agent_id,
+ remote_connection,
+ sessions,
+ } in sessions_by_agent
+ {
for session in sessions {
if !existing_sessions.insert(session.session_id.clone()) {
continue;
@@ -501,6 +529,7 @@ fn collect_importable_threads(
created_at: session.created_at,
folder_paths,
main_worktree_paths: PathList::default(),
+ remote_connection: remote_connection.clone(),
archived: true,
});
}
@@ -538,9 +567,10 @@ mod tests {
let existing = HashSet::from_iter(vec![acp::SessionId::new("existing-1")]);
let paths = PathList::new(&[Path::new("/project")]);
- let sessions_by_agent = vec![(
- AgentId::new("agent-a"),
- vec![
+ let sessions_by_agent = vec![SessionByAgent {
+ agent_id: AgentId::new("agent-a"),
+ remote_connection: None,
+ sessions: vec![
make_session(
"existing-1",
Some("Already There"),
@@ -550,7 +580,7 @@ mod tests {
),
make_session("new-1", Some("Brand New"), Some(paths), None, None),
],
- )];
+ }];
let result = collect_importable_threads(sessions_by_agent, existing);
@@ -564,13 +594,14 @@ mod tests {
let existing = HashSet::default();
let paths = PathList::new(&[Path::new("/project")]);
- let sessions_by_agent = vec![(
- AgentId::new("agent-a"),
- vec![
+ let sessions_by_agent = vec![SessionByAgent {
+ agent_id: AgentId::new("agent-a"),
+ remote_connection: None,
+ sessions: vec![
make_session("has-dirs", Some("With Dirs"), Some(paths), None, None),
make_session("no-dirs", Some("No Dirs"), None, None, None),
],
- )];
+ }];
let result = collect_importable_threads(sessions_by_agent, existing);
@@ -583,13 +614,14 @@ mod tests {
let existing = HashSet::default();
let paths = PathList::new(&[Path::new("/project")]);
- let sessions_by_agent = vec![(
- AgentId::new("agent-a"),
- vec![
+ let sessions_by_agent = vec![SessionByAgent {
+ agent_id: AgentId::new("agent-a"),
+ remote_connection: None,
+ sessions: vec![
make_session("s1", Some("Thread 1"), Some(paths.clone()), None, None),
make_session("s2", Some("Thread 2"), Some(paths), None, None),
],
- )];
+ }];
let result = collect_importable_threads(sessions_by_agent, existing);
@@ -603,20 +635,22 @@ mod tests {
let paths = PathList::new(&[Path::new("/project")]);
let sessions_by_agent = vec![
- (
- AgentId::new("agent-a"),
- vec![make_session(
+ SessionByAgent {
+ agent_id: AgentId::new("agent-a"),
+ remote_connection: None,
+ sessions: vec![make_session(
"s1",
Some("From A"),
Some(paths.clone()),
None,
None,
)],
- ),
- (
- AgentId::new("agent-b"),
- vec![make_session("s2", Some("From B"), Some(paths), None, None)],
- ),
+ },
+ SessionByAgent {
+ agent_id: AgentId::new("agent-b"),
+ remote_connection: None,
+ sessions: vec![make_session("s2", Some("From B"), Some(paths), None, None)],
+ },
];
let result = collect_importable_threads(sessions_by_agent, existing);
@@ -640,26 +674,28 @@ mod tests {
let paths = PathList::new(&[Path::new("/project")]);
let sessions_by_agent = vec![
- (
- AgentId::new("agent-a"),
- vec![make_session(
+ SessionByAgent {
+ agent_id: AgentId::new("agent-a"),
+ remote_connection: None,
+ sessions: vec![make_session(
"shared-session",
Some("From A"),
Some(paths.clone()),
None,
None,
)],
- ),
- (
- AgentId::new("agent-b"),
- vec![make_session(
+ },
+ SessionByAgent {
+ agent_id: AgentId::new("agent-b"),
+ remote_connection: None,
+ sessions: vec![make_session(
"shared-session",
Some("From B"),
Some(paths),
None,
None,
)],
- ),
+ },
];
let result = collect_importable_threads(sessions_by_agent, existing);
@@ -679,13 +715,14 @@ mod tests {
let existing =
HashSet::from_iter(vec![acp::SessionId::new("s1"), acp::SessionId::new("s2")]);
- let sessions_by_agent = vec![(
- AgentId::new("agent-a"),
- vec![
+ let sessions_by_agent = vec![SessionByAgent {
+ agent_id: AgentId::new("agent-a"),
+ remote_connection: None,
+ sessions: vec![
make_session("s1", Some("T1"), Some(paths.clone()), None, None),
make_session("s2", Some("T2"), Some(paths), None, None),
],
- )];
+ }];
let result = collect_importable_threads(sessions_by_agent, existing);
assert!(result.is_empty());
@@ -10,31 +10,37 @@ use anyhow::Context as _;
use chrono::{DateTime, Utc};
use collections::{HashMap, HashSet};
use db::{
+ kvp::KeyValueStore,
sqlez::{
bindable::Column, domain::Domain, statement::Statement,
thread_safe_connection::ThreadSafeConnection,
},
sqlez_macros::sql,
};
-use futures::{FutureExt as _, future::Shared};
+use fs::Fs;
+use futures::{FutureExt, future::Shared};
use gpui::{AppContext as _, Entity, Global, Subscription, Task};
use project::AgentId;
+use remote::RemoteConnectionOptions;
use ui::{App, Context, SharedString};
use util::ResultExt as _;
-use workspace::PathList;
+use workspace::{PathList, SerializedWorkspaceLocation, WorkspaceDb};
use crate::DEFAULT_THREAD_TITLE;
+const THREAD_REMOTE_CONNECTION_MIGRATION_KEY: &str = "thread-metadata-remote-connection-backfill";
+
pub fn init(cx: &mut App) {
ThreadMetadataStore::init_global(cx);
- migrate_thread_metadata(cx);
+ let migration_task = migrate_thread_metadata(cx);
+ migrate_thread_remote_connections(cx, migration_task);
}
/// Migrate existing thread metadata from native agent thread store to the new metadata storage.
/// We skip migrating threads that do not have a project.
///
/// TODO: Remove this after N weeks of shipping the sidebar
-fn migrate_thread_metadata(cx: &mut App) {
+fn migrate_thread_metadata(cx: &mut App) -> Task<anyhow::Result<()>> {
let store = ThreadMetadataStore::global(cx);
let db = store.read(cx).db.clone();
@@ -60,6 +66,7 @@ fn migrate_thread_metadata(cx: &mut App) {
created_at: entry.created_at,
folder_paths: entry.folder_paths,
main_worktree_paths: PathList::default(),
+ remote_connection: None,
archived: true,
})
})
@@ -104,6 +111,84 @@ fn migrate_thread_metadata(cx: &mut App) {
let _ = store.update(cx, |store, cx| store.reload(cx));
anyhow::Ok(())
})
+}
+
+fn migrate_thread_remote_connections(cx: &mut App, migration_task: Task<anyhow::Result<()>>) {
+ let store = ThreadMetadataStore::global(cx);
+ let db = store.read(cx).db.clone();
+ let kvp = KeyValueStore::global(cx);
+ let workspace_db = WorkspaceDb::global(cx);
+ let fs = <dyn Fs>::global(cx);
+
+ cx.spawn(async move |cx| -> anyhow::Result<()> {
+ migration_task.await?;
+
+ if kvp
+ .read_kvp(THREAD_REMOTE_CONNECTION_MIGRATION_KEY)?
+ .is_some()
+ {
+ return Ok(());
+ }
+
+ let recent_workspaces = workspace_db.recent_workspaces_on_disk(fs.as_ref()).await?;
+
+ let mut local_path_lists = HashSet::<PathList>::default();
+ let mut remote_path_lists = HashMap::<PathList, RemoteConnectionOptions>::default();
+
+ recent_workspaces
+ .iter()
+ .filter(|(_, location, path_list, _)| {
+ !path_list.is_empty() && matches!(location, &SerializedWorkspaceLocation::Local)
+ })
+ .for_each(|(_, _, path_list, _)| {
+ local_path_lists.insert(path_list.clone());
+ });
+
+ for (_, location, path_list, _) in recent_workspaces {
+ match location {
+ SerializedWorkspaceLocation::Remote(remote_connection)
+ if !local_path_lists.contains(&path_list) =>
+ {
+ remote_path_lists
+ .entry(path_list)
+ .or_insert(remote_connection);
+ }
+ _ => {}
+ }
+ }
+
+ let mut reloaded = false;
+ for metadata in db.list()? {
+ if metadata.remote_connection.is_some() {
+ continue;
+ }
+
+ if let Some(remote_connection) = remote_path_lists
+ .get(&metadata.folder_paths)
+ .or_else(|| remote_path_lists.get(&metadata.main_worktree_paths))
+ {
+ db.save(ThreadMetadata {
+ remote_connection: Some(remote_connection.clone()),
+ ..metadata
+ })
+ .await?;
+ reloaded = true;
+ }
+ }
+
+ let reloaded_task = reloaded
+ .then_some(store.update(cx, |store, cx| store.reload(cx)))
+ .unwrap_or(Task::ready(()).shared());
+
+ kvp.write_kvp(
+ THREAD_REMOTE_CONNECTION_MIGRATION_KEY.to_string(),
+ "1".to_string(),
+ )
+ .await?;
+ reloaded_task.await;
+
+ Ok(())
+ })
.detach_and_log_err(cx);
}
@@ -121,6 +206,7 @@ pub struct ThreadMetadata {
pub created_at: Option<DateTime<Utc>>,
pub folder_paths: PathList,
pub main_worktree_paths: PathList,
+ pub remote_connection: Option<RemoteConnectionOptions>,
pub archived: bool,
}
@@ -715,8 +801,8 @@ impl ThreadMetadataStore {
let agent_id = thread_ref.connection().agent_id();
+ let project = thread_ref.project().read(cx);
let folder_paths = {
- let project = thread_ref.project().read(cx);
let paths: Vec<Arc<Path>> = project
.visible_worktrees(cx)
.map(|worktree| worktree.read(cx).abs_path())
@@ -724,12 +810,9 @@ impl ThreadMetadataStore {
PathList::new(&paths)
};
- let main_worktree_paths = thread_ref
- .project()
- .read(cx)
- .project_group_key(cx)
- .path_list()
- .clone();
+ let project_group_key = project.project_group_key(cx);
+ let main_worktree_paths = project_group_key.path_list().clone();
+ let remote_connection = project_group_key.host();
// Threads without a folder path (e.g. started in an empty
// window) are archived by default so they don't get lost,
@@ -747,6 +830,7 @@ impl ThreadMetadataStore {
updated_at,
folder_paths,
main_worktree_paths,
+ remote_connection,
archived,
};
@@ -801,6 +885,7 @@ impl Domain for ThreadMetadataDb {
PRIMARY KEY (session_id, archived_worktree_id)
) STRICT;
),
+ sql!(ALTER TABLE sidebar_threads ADD COLUMN remote_connection TEXT),
];
}
@@ -817,7 +902,7 @@ impl ThreadMetadataDb {
/// List all sidebar thread metadata, ordered by updated_at descending.
pub fn list(&self) -> anyhow::Result<Vec<ThreadMetadata>> {
self.select::<ThreadMetadata>(
- "SELECT session_id, agent_id, title, updated_at, created_at, folder_paths, folder_paths_order, archived, main_worktree_paths, main_worktree_paths_order \
+ "SELECT session_id, agent_id, title, updated_at, created_at, folder_paths, folder_paths_order, archived, main_worktree_paths, main_worktree_paths_order, remote_connection \
FROM sidebar_threads \
ORDER BY updated_at DESC"
)?()
@@ -847,11 +932,17 @@ impl ThreadMetadataDb {
} else {
(Some(main_serialized.paths), Some(main_serialized.order))
};
+ let remote_connection = row
+ .remote_connection
+ .as_ref()
+ .map(serde_json::to_string)
+ .transpose()
+ .context("serialize thread metadata remote connection")?;
let archived = row.archived;
self.write(move |conn| {
- let sql = "INSERT INTO sidebar_threads(session_id, agent_id, title, updated_at, created_at, folder_paths, folder_paths_order, archived, main_worktree_paths, main_worktree_paths_order) \
- VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10) \
+ let sql = "INSERT INTO sidebar_threads(session_id, agent_id, title, updated_at, created_at, folder_paths, folder_paths_order, archived, main_worktree_paths, main_worktree_paths_order, remote_connection) \
+ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11) \
ON CONFLICT(session_id) DO UPDATE SET \
agent_id = excluded.agent_id, \
title = excluded.title, \
@@ -861,7 +952,8 @@ impl ThreadMetadataDb {
folder_paths_order = excluded.folder_paths_order, \
archived = excluded.archived, \
main_worktree_paths = excluded.main_worktree_paths, \
- main_worktree_paths_order = excluded.main_worktree_paths_order";
+ main_worktree_paths_order = excluded.main_worktree_paths_order, \
+ remote_connection = excluded.remote_connection";
let mut stmt = Statement::prepare(conn, sql)?;
let mut i = stmt.bind(&id, 1)?;
i = stmt.bind(&agent_id, i)?;
@@ -872,7 +964,8 @@ impl ThreadMetadataDb {
i = stmt.bind(&folder_paths_order, i)?;
i = stmt.bind(&archived, i)?;
i = stmt.bind(&main_worktree_paths, i)?;
- stmt.bind(&main_worktree_paths_order, i)?;
+ i = stmt.bind(&main_worktree_paths_order, i)?;
+ stmt.bind(&remote_connection, i)?;
stmt.exec()
})
.await
@@ -1005,6 +1098,8 @@ impl Column for ThreadMetadata {
Column::column(statement, next)?;
let (main_worktree_paths_order_str, next): (Option<String>, i32) =
Column::column(statement, next)?;
+ let (remote_connection_json, next): (Option<String>, i32) =
+ Column::column(statement, next)?;
let agent_id = agent_id
.map(|id| AgentId::new(id))
@@ -1035,6 +1130,12 @@ impl Column for ThreadMetadata {
})
.unwrap_or_default();
+ let remote_connection = remote_connection_json
+ .as_deref()
+ .map(serde_json::from_str::<RemoteConnectionOptions>)
+ .transpose()
+ .context("deserialize thread metadata remote connection")?;
+
Ok((
ThreadMetadata {
session_id: acp::SessionId::new(id),
@@ -1044,6 +1145,7 @@ impl Column for ThreadMetadata {
created_at,
folder_paths,
main_worktree_paths,
+ remote_connection,
archived,
},
next,
@@ -1087,6 +1189,7 @@ mod tests {
use gpui::TestAppContext;
use project::FakeFs;
use project::Project;
+ use remote::WslConnectionOptions;
use std::path::Path;
use std::rc::Rc;
@@ -1126,19 +1229,37 @@ mod tests {
created_at: Some(updated_at),
folder_paths,
main_worktree_paths: PathList::default(),
+ remote_connection: None,
}
}
fn init_test(cx: &mut TestAppContext) {
+ let fs = FakeFs::new(cx.executor());
cx.update(|cx| {
let settings_store = settings::SettingsStore::test(cx);
cx.set_global(settings_store);
+ <dyn Fs>::set_global(fs, cx);
ThreadMetadataStore::init_global(cx);
ThreadStore::init_global(cx);
});
cx.run_until_parked();
}
+ fn clear_thread_metadata_remote_connection_backfill(cx: &mut TestAppContext) {
+ let kvp = cx.update(|cx| KeyValueStore::global(cx));
+ smol::block_on(kvp.delete_kvp("thread-metadata-remote-connection-backfill".to_string()))
+ .unwrap();
+ }
+
+ fn run_thread_metadata_migrations(cx: &mut TestAppContext) {
+ clear_thread_metadata_remote_connection_backfill(cx);
+ cx.update(|cx| {
+ let migration_task = migrate_thread_metadata(cx);
+ migrate_thread_remote_connections(cx, migration_task);
+ });
+ cx.run_until_parked();
+ }
+
#[gpui::test]
async fn test_store_initializes_cache_from_database(cx: &mut TestAppContext) {
let first_paths = PathList::new(&[Path::new("/project-a")]);
@@ -1340,6 +1461,7 @@ mod tests {
created_at: Some(now - chrono::Duration::seconds(10)),
folder_paths: project_a_paths.clone(),
main_worktree_paths: PathList::default(),
+ remote_connection: None,
archived: false,
};
@@ -1397,8 +1519,7 @@ mod tests {
cx.run_until_parked();
}
- cx.update(|cx| migrate_thread_metadata(cx));
- cx.run_until_parked();
+ run_thread_metadata_migrations(cx);
let list = cx.update(|cx| {
let store = ThreadMetadataStore::global(cx);
@@ -1450,6 +1571,7 @@ mod tests {
created_at: Some(existing_updated_at),
folder_paths: project_paths.clone(),
main_worktree_paths: PathList::default(),
+ remote_connection: None,
archived: false,
};
@@ -1478,8 +1600,7 @@ mod tests {
save_task.await.unwrap();
cx.run_until_parked();
- cx.update(|cx| migrate_thread_metadata(cx));
- cx.run_until_parked();
+ run_thread_metadata_migrations(cx);
let list = cx.update(|cx| {
let store = ThreadMetadataStore::global(cx);
@@ -1490,6 +1611,82 @@ mod tests {
assert_eq!(list[0].session_id.0.as_ref(), "existing-session");
}
+ #[gpui::test]
+ async fn test_migrate_thread_remote_connections_backfills_from_workspace_db(
+ cx: &mut TestAppContext,
+ ) {
+ init_test(cx);
+
+ let folder_paths = PathList::new(&[Path::new("/remote-project")]);
+ let updated_at = Utc::now();
+ let metadata = make_metadata(
+ "remote-session",
+ "Remote Thread",
+ updated_at,
+ folder_paths.clone(),
+ );
+
+ cx.update(|cx| {
+ let store = ThreadMetadataStore::global(cx);
+ store.update(cx, |store, cx| {
+ store.save(metadata, cx);
+ });
+ });
+ cx.run_until_parked();
+
+ let workspace_db = cx.update(|cx| WorkspaceDb::global(cx));
+ let workspace_id = workspace_db.next_id().await.unwrap();
+ let serialized_paths = folder_paths.serialize();
+ let remote_connection_id = 1_i64;
+ workspace_db
+ .write(move |conn| {
+ let mut stmt = Statement::prepare(
+ conn,
+ "INSERT INTO remote_connections(id, kind, user, distro) VALUES (?1, ?2, ?3, ?4)",
+ )?;
+ let mut next_index = stmt.bind(&remote_connection_id, 1)?;
+ next_index = stmt.bind(&"wsl", next_index)?;
+ next_index = stmt.bind(&Some("anth".to_string()), next_index)?;
+ stmt.bind(&Some("Ubuntu".to_string()), next_index)?;
+ stmt.exec()?;
+
+ let mut stmt = Statement::prepare(
+ conn,
+ "UPDATE workspaces SET paths = ?2, paths_order = ?3, remote_connection_id = ?4, timestamp = CURRENT_TIMESTAMP WHERE workspace_id = ?1",
+ )?;
+ let mut next_index = stmt.bind(&workspace_id, 1)?;
+ next_index = stmt.bind(&serialized_paths.paths, next_index)?;
+ next_index = stmt.bind(&serialized_paths.order, next_index)?;
+ stmt.bind(&Some(remote_connection_id as i32), next_index)?;
+ stmt.exec()
+ })
+ .await
+ .unwrap();
+
+ clear_thread_metadata_remote_connection_backfill(cx);
+ cx.update(|cx| {
+ migrate_thread_remote_connections(cx, Task::ready(Ok(())));
+ });
+ cx.run_until_parked();
+
+ let metadata = cx.update(|cx| {
+ let store = ThreadMetadataStore::global(cx);
+ store
+ .read(cx)
+ .entry(&acp::SessionId::new("remote-session"))
+ .cloned()
+ .expect("expected migrated metadata row")
+ });
+
+ assert_eq!(
+ metadata.remote_connection,
+ Some(RemoteConnectionOptions::Wsl(WslConnectionOptions {
+ distro_name: "Ubuntu".to_string(),
+ user: Some("anth".to_string()),
+ }))
+ );
+ }
+
#[gpui::test]
async fn test_migrate_thread_metadata_archives_beyond_five_most_recent_per_project(
cx: &mut TestAppContext,
@@ -1538,8 +1735,7 @@ mod tests {
cx.run_until_parked();
}
- cx.update(|cx| migrate_thread_metadata(cx));
- cx.run_until_parked();
+ run_thread_metadata_migrations(cx);
let list = cx.update(|cx| {
let store = ThreadMetadataStore::global(cx);
@@ -245,6 +245,7 @@ fn save_thread_metadata(
folder_paths,
main_worktree_paths,
archived: false,
+ remote_connection: None,
};
ThreadMetadataStore::global(cx).update(cx, |store, cx| store.save_manually(metadata, cx));
});
@@ -813,6 +814,7 @@ async fn test_visible_entries_as_strings(cx: &mut TestAppContext) {
updated_at: Utc::now(),
created_at: Some(Utc::now()),
archived: false,
+ remote_connection: None,
},
icon: IconName::ZedAgent,
icon_from_external_svg: None,
@@ -836,6 +838,7 @@ async fn test_visible_entries_as_strings(cx: &mut TestAppContext) {
updated_at: Utc::now(),
created_at: Some(Utc::now()),
archived: false,
+ remote_connection: None,
},
icon: IconName::ZedAgent,
icon_from_external_svg: None,
@@ -853,6 +856,7 @@ async fn test_visible_entries_as_strings(cx: &mut TestAppContext) {
metadata: ThreadMetadata {
session_id: acp::SessionId::new(Arc::from("t-3")),
agent_id: AgentId::new("zed-agent"),
+ remote_connection: None,
folder_paths: PathList::default(),
main_worktree_paths: PathList::default(),
title: "Error thread".into(),
@@ -872,10 +876,12 @@ async fn test_visible_entries_as_strings(cx: &mut TestAppContext) {
diff_stats: DiffStats::default(),
}),
// Thread with WaitingForConfirmation status, not active
+ // remote_connection: None,
ListEntry::Thread(ThreadEntry {
metadata: ThreadMetadata {
session_id: acp::SessionId::new(Arc::from("t-4")),
agent_id: AgentId::new("zed-agent"),
+ remote_connection: None,
folder_paths: PathList::default(),
main_worktree_paths: PathList::default(),
title: "Waiting thread".into(),
@@ -895,10 +901,12 @@ async fn test_visible_entries_as_strings(cx: &mut TestAppContext) {
diff_stats: DiffStats::default(),
}),
// Background thread that completed (should show notification)
+ // remote_connection: None,
ListEntry::Thread(ThreadEntry {
metadata: ThreadMetadata {
session_id: acp::SessionId::new(Arc::from("t-5")),
agent_id: AgentId::new("zed-agent"),
+ remote_connection: None,
folder_paths: PathList::default(),
main_worktree_paths: PathList::default(),
title: "Notified thread".into(),
@@ -2197,6 +2205,7 @@ async fn test_focused_thread_tracks_user_intent(cx: &mut TestAppContext) {
folder_paths: PathList::default(),
main_worktree_paths: PathList::default(),
archived: false,
+ remote_connection: None,
},
&workspace_a,
false,
@@ -2253,6 +2262,7 @@ async fn test_focused_thread_tracks_user_intent(cx: &mut TestAppContext) {
folder_paths: PathList::default(),
main_worktree_paths: PathList::default(),
archived: false,
+ remote_connection: None,
},
&workspace_b,
false,
@@ -3692,6 +3702,7 @@ async fn test_activate_archived_thread_with_saved_paths_activates_matching_works
folder_paths: PathList::new(&[PathBuf::from("/project-b")]),
main_worktree_paths: PathList::default(),
archived: false,
+ remote_connection: None,
},
window,
cx,
@@ -3757,6 +3768,7 @@ async fn test_activate_archived_thread_cwd_fallback_with_matching_workspace(
folder_paths: PathList::new(&[std::path::PathBuf::from("/project-b")]),
main_worktree_paths: PathList::default(),
archived: false,
+ remote_connection: None,
},
window,
cx,
@@ -3820,6 +3832,7 @@ async fn test_activate_archived_thread_no_paths_no_cwd_uses_active_workspace(
folder_paths: PathList::default(),
main_worktree_paths: PathList::default(),
archived: false,
+ remote_connection: None,
},
window,
cx,
@@ -3875,6 +3888,7 @@ async fn test_activate_archived_thread_saved_paths_opens_new_workspace(cx: &mut
folder_paths: path_list_b,
main_worktree_paths: PathList::default(),
archived: false,
+ remote_connection: None,
},
window,
cx,
@@ -3929,6 +3943,7 @@ async fn test_activate_archived_thread_reuses_workspace_in_another_window(cx: &m
folder_paths: PathList::new(&[PathBuf::from("/project-b")]),
main_worktree_paths: PathList::default(),
archived: false,
+ remote_connection: None,
},
window,
cx,
@@ -4006,6 +4021,7 @@ async fn test_activate_archived_thread_reuses_workspace_in_another_window_with_t
folder_paths: PathList::new(&[PathBuf::from("/project-b")]),
main_worktree_paths: PathList::default(),
archived: false,
+ remote_connection: None,
},
window,
cx,
@@ -4086,6 +4102,7 @@ async fn test_activate_archived_thread_prefers_current_window_for_matching_paths
folder_paths: PathList::new(&[PathBuf::from("/project-a")]),
main_worktree_paths: PathList::default(),
archived: false,
+ remote_connection: None,
},
window,
cx,
@@ -6006,6 +6023,7 @@ async fn test_legacy_thread_with_canonical_path_opens_main_repo_workspace(cx: &m
folder_paths: PathList::new(&[PathBuf::from("/project")]),
main_worktree_paths: PathList::default(),
archived: false,
+ remote_connection: None,
};
ThreadMetadataStore::global(cx).update(cx, |store, cx| store.save_manually(metadata, cx));
});
@@ -6361,6 +6379,7 @@ mod property_test {
folder_paths: path_list,
main_worktree_paths,
archived: false,
+ remote_connection: None,
};
cx.update(|_, cx| {
ThreadMetadataStore::global(cx)
@@ -7094,6 +7113,7 @@ async fn test_remote_project_integration_does_not_briefly_render_as_separate_pro
folder_paths: PathList::new(&[PathBuf::from("/project-wt-1")]),
main_worktree_paths,
archived: false,
+ remote_connection: None,
};
ThreadMetadataStore::global(cx).update(cx, |store, cx| store.save_manually(metadata, cx));
});