From b478dfdf5e21a3bb5ae532d13c93b61694fdbe8f Mon Sep 17 00:00:00 2001 From: Ben Brandt Date: Tue, 24 Mar 2026 12:52:35 +0100 Subject: [PATCH] acp: Fix the spawn directory for agent servers in remote environments (#52308) We can't add a current_dir when in remote scenarios in the same place, it gets added elsewhere. Reused the same worktree selection logic, and make sure this gets passed to the RPC call instead. This fixes something that hasn't made it to preview yet. Release Notes: - N/A --- crates/agent_servers/src/acp.rs | 14 +++++++---- crates/project/src/agent_server_store.rs | 31 +++++++++++++++++++++--- crates/project/src/project.rs | 23 ++++++++++++++---- 3 files changed, 54 insertions(+), 14 deletions(-) diff --git a/crates/agent_servers/src/acp.rs b/crates/agent_servers/src/acp.rs index f7b6a59a63b02028a8b30c905c92b82805a52b33..5f452bc9c0e2e9c2322042583295894a5866b053 100644 --- a/crates/agent_servers/src/acp.rs +++ b/crates/agent_servers/src/acp.rs @@ -203,11 +203,15 @@ impl AcpConnection { builder.build_std_command(Some(command.path.display().to_string()), &command.args); child.envs(command.env.iter().flatten()); if let Some(cwd) = project.update(cx, |project, cx| { - project - .default_path_list(cx) - .ordered_paths() - .next() - .cloned() + if project.is_local() { + project + .default_path_list(cx) + .ordered_paths() + .next() + .cloned() + } else { + None + } }) { child.current_dir(cwd); } diff --git a/crates/project/src/agent_server_store.rs b/crates/project/src/agent_server_store.rs index a9003e8567e6bf57ea18f8d70619e9417a626f43..ca80fb39a526e380f2c6e4abb6c3f728843df8ba 100644 --- a/crates/project/src/agent_server_store.rs +++ b/crates/project/src/agent_server_store.rs @@ -27,6 +27,8 @@ use util::{ResultExt as _, debug_panic}; use crate::ProjectEnvironment; use crate::agent_registry_store::{AgentRegistryStore, RegistryAgent, RegistryTargetConfig}; +use crate::worktree_store::WorktreeStore; + #[derive(Deserialize, Serialize, Clone, PartialEq, Eq, JsonSchema)] pub struct AgentServerCommand { #[serde(rename = "command")] @@ -149,6 +151,7 @@ enum AgentServerStoreState { Remote { project_id: u64, upstream_client: Entity, + worktree_store: Entity, }, Collab, } @@ -231,6 +234,7 @@ impl AgentServerStore { AgentServerStoreState::Remote { project_id, upstream_client, + worktree_store, } => { let mut agents = vec![]; for (ext_id, manifest) in manifests { @@ -256,6 +260,7 @@ impl AgentServerStore { Box::new(RemoteExternalAgentServer { project_id: *project_id, upstream_client: upstream_client.clone(), + worktree_store: worktree_store.clone(), name: agent_server_name.clone(), new_version_available_tx: None, }) @@ -612,11 +617,16 @@ impl AgentServerStore { this } - pub(crate) fn remote(project_id: u64, upstream_client: Entity) -> Self { + pub(crate) fn remote( + project_id: u64, + upstream_client: Entity, + worktree_store: Entity, + ) -> Self { Self { state: AgentServerStoreState::Remote { project_id, upstream_client, + worktree_store, }, external_agents: HashMap::default(), } @@ -751,8 +761,10 @@ impl AgentServerStore { .env .map(|env| env.into_iter().collect()) .unwrap_or_default(), - // root_dir and login are no longer used, but returned for backwards compatibility - root_dir: paths::home_dir().to_string_lossy().to_string(), + root_dir: envelope + .payload + .root_dir + .unwrap_or_else(|| paths::home_dir().to_string_lossy().to_string()), login: None, }) } @@ -766,6 +778,7 @@ impl AgentServerStore { let AgentServerStoreState::Remote { project_id, upstream_client, + worktree_store, } = &this.state else { debug_panic!( @@ -810,6 +823,7 @@ impl AgentServerStore { let agent = RemoteExternalAgentServer { project_id: *project_id, upstream_client: upstream_client.clone(), + worktree_store: worktree_store.clone(), name: agent_id.clone(), new_version_available_tx: new_version_available_txs .remove(&agent_id) @@ -906,6 +920,7 @@ impl AgentServerStore { struct RemoteExternalAgentServer { project_id: u64, upstream_client: Entity, + worktree_store: Entity, name: AgentId, new_version_available_tx: Option>>, } @@ -920,8 +935,16 @@ impl ExternalAgentServer for RemoteExternalAgentServer { let project_id = self.project_id; let name = self.name.to_string(); let upstream_client = self.upstream_client.downgrade(); + let worktree_store = self.worktree_store.clone(); self.new_version_available_tx = new_version_available_tx; cx.spawn(async move |cx| { + let root_dir = worktree_store.read_with(cx, |worktree_store, cx| { + crate::Project::default_visible_worktree_paths(worktree_store, cx) + .into_iter() + .next() + .map(|path| path.display().to_string()) + }); + let mut response = upstream_client .update(cx, |upstream_client, _| { upstream_client @@ -929,7 +952,7 @@ impl ExternalAgentServer for RemoteExternalAgentServer { .request(proto::GetAgentServerCommand { project_id, name, - root_dir: None, + root_dir, }) })? .await?; diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 68a383224bcbbe99a655ab020646d4135138f14e..3dbfc6edc6ef4b2d59e028d027ebc29fc5b9f0d0 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1500,8 +1500,13 @@ impl Project { ) }); - let agent_server_store = - cx.new(|_| AgentServerStore::remote(REMOTE_SERVER_PROJECT_ID, remote.clone())); + let agent_server_store = cx.new(|_| { + AgentServerStore::remote( + REMOTE_SERVER_PROJECT_ID, + remote.clone(), + worktree_store.clone(), + ) + }); cx.subscribe(&remote, Self::on_remote_client_event).detach(); @@ -2294,8 +2299,11 @@ impl Project { self.worktree_store.read(cx).visible_worktrees(cx) } - pub fn default_path_list(&self, cx: &App) -> PathList { - let worktree_roots = self + pub(crate) fn default_visible_worktree_paths( + worktree_store: &WorktreeStore, + cx: &App, + ) -> Vec { + worktree_store .visible_worktrees(cx) .sorted_by(|left, right| { left.read(cx) @@ -2311,7 +2319,12 @@ impl Project { Some(path.to_path_buf()) } }) - .collect::>(); + .collect() + } + + pub fn default_path_list(&self, cx: &App) -> PathList { + let worktree_roots = + Self::default_visible_worktree_paths(&self.worktree_store.read(cx), cx); if worktree_roots.is_empty() { PathList::new(&[paths::home_dir().as_path()])