Cargo.lock 🔗
@@ -416,7 +416,6 @@ dependencies = [
"serde_json",
"serde_json_lenient",
"settings",
- "shlex",
"smol",
"streaming_diff",
"task",
Hakan Ensari , Hakan Ensari , and Claude created
This fixes terminal-based authentication for external ACP agents (Claude
Code, Gemini CLI) when file paths contain spaces, like "Application
Support" on macOS and "Program Files" on Windows.
When users click authentication buttons or type `/login`, they get
errors like `Cannot find module '/Users/username/Library/Application'`
because the path gets split at the space.
The fix removes redundant `shlex::try_quote` calls from
`spawn_external_agent_login`. These were causing double-quoting since
the terminal spawning code already handles proper shell escaping.
Added a test to verify paths with spaces aren't pre-quoted.
Release Notes:
- Fixed external agent authentication failures when file paths contain
spaces
---------
Co-authored-by: Hakan Ensari <hakanensari@users.noreply.github.com>
Co-authored-by: Claude <claude@anthropic.com>
Cargo.lock | 1
crates/agent_ui/Cargo.toml | 1
crates/agent_ui/src/acp/thread_view.rs | 32 +++++++++++++++------------
3 files changed, 18 insertions(+), 16 deletions(-)
@@ -416,7 +416,6 @@ dependencies = [
"serde_json",
"serde_json_lenient",
"settings",
- "shlex",
"smol",
"streaming_diff",
"task",
@@ -80,7 +80,6 @@ serde.workspace = true
serde_json.workspace = true
serde_json_lenient.workspace = true
settings.workspace = true
-shlex.workspace = true
smol.workspace = true
streaming_diff.workspace = true
task.workspace = true
@@ -9,7 +9,7 @@ use agent_client_protocol::{self as acp, PromptCapabilities};
use agent_servers::{AgentServer, AgentServerDelegate};
use agent_settings::{AgentProfileId, AgentSettings, CompletionMode, NotifyWhenAgentWaiting};
use agent2::{DbThreadMetadata, HistoryEntry, HistoryEntryId, HistoryStore, NativeAgentServer};
-use anyhow::{Context as _, Result, anyhow, bail};
+use anyhow::{Result, anyhow, bail};
use arrayvec::ArrayVec;
use audio::{Audio, Sound};
use buffer_diff::BufferDiff;
@@ -1584,19 +1584,6 @@ impl AcpThreadView {
window.spawn(cx, async move |cx| {
let mut task = login.clone();
- task.command = task
- .command
- .map(|command| anyhow::Ok(shlex::try_quote(&command)?.to_string()))
- .transpose()?;
- task.args = task
- .args
- .iter()
- .map(|arg| {
- Ok(shlex::try_quote(arg)
- .context("Failed to quote argument")?
- .to_string())
- })
- .collect::<Result<Vec<_>>>()?;
task.full_label = task.label.clone();
task.id = task::TaskId(format!("external-agent-{}-login", task.label));
task.command_label = task.label.clone();
@@ -5680,6 +5667,23 @@ pub(crate) mod tests {
});
}
+ #[gpui::test]
+ async fn test_spawn_external_agent_login_handles_spaces(cx: &mut TestAppContext) {
+ init_test(cx);
+
+ // Verify paths with spaces aren't pre-quoted
+ let path_with_spaces = "/Users/test/Library/Application Support/Zed/cli.js";
+ let login_task = task::SpawnInTerminal {
+ command: Some("node".to_string()),
+ args: vec![path_with_spaces.to_string(), "/login".to_string()],
+ ..Default::default()
+ };
+
+ // Args should be passed as-is, not pre-quoted
+ assert!(!login_task.args[0].starts_with('"'));
+ assert!(!login_task.args[0].starts_with('\''));
+ }
+
#[gpui::test]
async fn test_notification_for_tool_authorization(cx: &mut TestAppContext) {
init_test(cx);