Start separating authentication from connection to collab (#35471)

This pull request should be idempotent, but lays the groundwork for
avoiding to connect to collab in order to interact with AI features
provided by Zed.

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Co-authored-by: Richard Feldman <oss@rtfeldman.com>
This commit is contained in:
Antonio Scandurra 2025-08-01 19:37:38 +02:00 committed by GitHub
parent b01d1872cc
commit f888f3fc0b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 653 additions and 855 deletions

View file

@ -5,7 +5,7 @@ use agent_ui::AgentPanel;
use anyhow::{Context as _, Result};
use clap::{Parser, command};
use cli::FORCE_CLI_MODE_ENV_VAR_NAME;
use client::{Client, CloudUserStore, ProxySettings, UserStore, parse_zed_link};
use client::{Client, ProxySettings, UserStore, parse_zed_link};
use collab_ui::channel_view::ChannelView;
use collections::HashMap;
use db::kvp::{GLOBAL_KEY_VALUE_STORE, KEY_VALUE_STORE};
@ -42,7 +42,7 @@ use theme::{
ActiveTheme, IconThemeNotFoundError, SystemAppearance, ThemeNotFoundError, ThemeRegistry,
ThemeSettings,
};
use util::{ConnectionResult, ResultExt, TryFutureExt, maybe};
use util::{ResultExt, TryFutureExt, maybe};
use uuid::Uuid;
use welcome::{FIRST_OPEN, show_welcome_view};
use workspace::{
@ -457,8 +457,6 @@ pub fn main() {
language::init(cx);
languages::init(languages.clone(), node_runtime.clone(), cx);
let user_store = cx.new(|cx| UserStore::new(client.clone(), cx));
let cloud_user_store =
cx.new(|cx| CloudUserStore::new(client.cloud_client(), user_store.clone(), cx));
let workspace_store = cx.new(|cx| WorkspaceStore::new(client.clone(), cx));
language_extension::init(
@ -518,7 +516,6 @@ pub fn main() {
languages: languages.clone(),
client: client.clone(),
user_store: user_store.clone(),
cloud_user_store,
fs: fs.clone(),
build_window_options,
workspace_store,
@ -556,12 +553,7 @@ pub fn main() {
);
supermaven::init(app_state.client.clone(), cx);
language_model::init(app_state.client.clone(), cx);
language_models::init(
app_state.user_store.clone(),
app_state.cloud_user_store.clone(),
app_state.client.clone(),
cx,
);
language_models::init(app_state.user_store.clone(), app_state.client.clone(), cx);
agent_settings::init(cx);
agent_servers::init(cx);
web_search::init(cx);
@ -569,7 +561,7 @@ pub fn main() {
snippet_provider::init(cx);
inline_completion_registry::init(
app_state.client.clone(),
app_state.cloud_user_store.clone(),
app_state.user_store.clone(),
cx,
);
let prompt_builder = PromptBuilder::load(app_state.fs.clone(), stdout_is_a_pty(), cx);
@ -690,17 +682,9 @@ pub fn main() {
cx.spawn({
let client = app_state.client.clone();
async move |cx| match authenticate(client, &cx).await {
ConnectionResult::Timeout => log::error!("Timeout during initial auth"),
ConnectionResult::ConnectionReset => {
log::error!("Connection reset during initial auth")
}
ConnectionResult::Result(r) => {
r.log_err();
}
}
async move |cx| authenticate(client, &cx).await
})
.detach();
.detach_and_log_err(cx);
let urls: Vec<_> = args
.paths_or_urls
@ -850,15 +834,7 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
let client = app_state.client.clone();
// we continue even if authentication fails as join_channel/ open channel notes will
// show a visible error message.
match authenticate(client, &cx).await {
ConnectionResult::Timeout => {
log::error!("Timeout during open request handling")
}
ConnectionResult::ConnectionReset => {
log::error!("Connection reset during open request handling")
}
ConnectionResult::Result(r) => r?,
};
authenticate(client, &cx).await.log_err();
if let Some(channel_id) = request.join_channel {
cx.update(|cx| {
@ -908,18 +884,18 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
}
}
async fn authenticate(client: Arc<Client>, cx: &AsyncApp) -> ConnectionResult<()> {
async fn authenticate(client: Arc<Client>, cx: &AsyncApp) -> Result<()> {
if stdout_is_a_pty() {
if client::IMPERSONATE_LOGIN.is_some() {
return client.authenticate_and_connect(false, cx).await;
client.sign_in_with_optional_connect(false, cx).await?;
} else if client.has_credentials(cx).await {
return client.authenticate_and_connect(true, cx).await;
client.sign_in_with_optional_connect(true, cx).await?;
}
} else if client.has_credentials(cx).await {
return client.authenticate_and_connect(true, cx).await;
client.sign_in_with_optional_connect(true, cx).await?;
}
ConnectionResult::Result(Ok(()))
Ok(())
}
async fn system_id() -> Result<IdType> {