From e2e1d77b98ce89b60579923fed1d3a6be649f25b Mon Sep 17 00:00:00 2001 From: Wes Date: Sat, 18 Jul 2026 11:45:16 -0600 Subject: [PATCH] Fix Claude onboarding terminal popup Route both supported Claude subscription auth method IDs through the existing headless login process so first launch opens the browser without exposing a terminal. Keep non-subscription terminal methods unchanged and cover both adapter payloads. Co-authored-by: Pinky <44b8e82baa6e0e254e0208d68f335c283c94e7b78dd1fa10d5a49d3f13dd0435@sprout-oss.stage.blox.sqprod.co> Signed-off-by: Wes --- desktop/src-tauri/src/commands/agent_auth.rs | 46 +++++++++++++++++--- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/desktop/src-tauri/src/commands/agent_auth.rs b/desktop/src-tauri/src/commands/agent_auth.rs index b6598b5497..c23263de7e 100644 --- a/desktop/src-tauri/src/commands/agent_auth.rs +++ b/desktop/src-tauri/src/commands/agent_auth.rs @@ -88,8 +88,8 @@ fn connect_acp_runtime_blocking( .ok_or_else(|| "auth method is no longer advertised by this adapter".to_string())?; if uses_terminal_auth(method)? { - if method.id == "claude-login" && terminal_auth_meta_command(method)?.is_some() { - run_claude_login(&request.runtime_id, method)?; + if is_claude_subscription_login(&request.runtime_id, method) { + run_claude_subscription_login(&request.runtime_id, method)?; } else { launch_terminal_auth(&request.runtime_id, method)?; } @@ -215,7 +215,11 @@ fn command_error(label: &str, output: &std::process::Output) -> String { } } -fn run_claude_login(runtime_id: &str, method: &AcpAuthMethod) -> Result<(), String> { +fn is_claude_subscription_login(runtime_id: &str, method: &AcpAuthMethod) -> bool { + runtime_id == "claude" && matches!(method.id.as_str(), "claude-login" | "claude-ai-login") +} + +fn run_claude_subscription_login(runtime_id: &str, method: &AcpAuthMethod) -> Result<(), String> { let runtime = known_acp_runtime_exact(runtime_id) .ok_or_else(|| format!("unknown ACP runtime: {runtime_id}"))?; let argv = adapter_terminal_argv(runtime.label, method, "")?; @@ -453,8 +457,9 @@ fn shell_escape(arg: &str) -> String { #[cfg(test)] mod tests { use super::{ - adapter_terminal_argv, append_inherited_path, run_buzz_acp_auth_command_with_paths, - shell_escape, shell_join, uses_terminal_auth, windows_terminal_args, AcpAuthMethod, + adapter_terminal_argv, append_inherited_path, is_claude_subscription_login, + run_buzz_acp_auth_command_with_paths, shell_escape, shell_join, uses_terminal_auth, + windows_terminal_args, AcpAuthMethod, }; /// Windows regression: the augmented PATH there holds only Buzz-managed @@ -588,6 +593,37 @@ mod tests { assert_eq!(method.command[0], "claude"); } + #[test] + fn claude_subscription_methods_run_without_a_visible_terminal() { + for id in ["claude-login", "claude-ai-login"] { + let method = AcpAuthMethod { + id: id.into(), + name: "Claude Subscription".into(), + description: None, + method_type: Some("terminal".into()), + args: vec![], + command: vec![], + meta: None, + }; + assert!(is_claude_subscription_login("claude", &method)); + assert!(!is_claude_subscription_login("codex", &method)); + } + } + + #[test] + fn other_claude_terminal_methods_remain_visible() { + let method = AcpAuthMethod { + id: "console-login".into(), + name: "Anthropic Console".into(), + description: None, + method_type: Some("terminal".into()), + args: vec![], + command: vec![], + meta: None, + }; + assert!(!is_claude_subscription_login("claude", &method)); + } + #[test] fn claude_terminal_meta_routes_around_unimplemented_authenticate() { let raw = r#"{"_meta":{"terminal-auth":{"args":["/tmp/claude-cli.js"],"command":"node","label":"Claude Login"}},"description":"Run `claude /login` in the terminal","id":"claude-login","name":"Log in with Claude"}"#;