From acf5da917270c5cedf083a56bcb4e0fb1a2e6886 Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Mon, 13 Apr 2026 19:42:33 -0700 Subject: [PATCH] Guard CLI first-run prompt with agents-v2 flag (#53839) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gates the CLI first-run prompt (from #53663) on the `agent-v2` feature flag, giving us an escape hatch if something goes wrong. ## What this does **Commit 1: Gate on agent-v2 flag** - Adds an `AgentV2FeatureFlag` check at the top of the open behavior resolution. When the flag is off, the prompt is skipped. - Refactors `maybe_prompt_open_behavior` → `resolve_open_behavior`: moves the explicit-flags guard (`-n`, `-e`, `--reuse`) to the caller and drops three parameters from the function signature, since the function was only inspecting those values to decide whether to bail early. **Commit 2: Default to new-window when flag is disabled** - When the flag is off, falls back to the pre-#53254 behavior of opening projects in a new window, rather than silently adding to the sidebar. Release Notes: - N/A --- crates/zed/src/zed/open_listener.rs | 54 +++++++++++++---------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/crates/zed/src/zed/open_listener.rs b/crates/zed/src/zed/open_listener.rs index 7094a6a6a7addcfdb5c373258a95b2f2b02d5c2b..e1a98e62a0f3384fbf003cb0705de1b0bb957d75 100644 --- a/crates/zed/src/zed/open_listener.rs +++ b/crates/zed/src/zed/open_listener.rs @@ -12,6 +12,7 @@ use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender}; use futures::channel::{mpsc, oneshot}; use futures::future; +use feature_flags::FeatureFlagAppExt as _; use futures::{FutureExt, StreamExt}; use git_ui::{file_diff_view::FileDiffView, multi_diff_view::MultiDiffView}; use gpui::{App, AsyncApp, Global, WindowHandle}; @@ -497,25 +498,23 @@ pub async fn handle_cli_connection( return; } - if let Some(behavior) = maybe_prompt_open_behavior( - open_new_workspace, - force_existing_window, - reuse, - &paths, - &app_state, - responses.as_ref(), - &mut requests, - cx, - ) - .await - { - match behavior { - settings::CliDefaultOpenBehavior::ExistingWindow => { + if open_new_workspace.is_none() && !force_existing_window && !reuse { + match resolve_open_behavior( + &paths, + &app_state, + responses.as_ref(), + &mut requests, + cx, + ) + .await + { + Some(settings::CliDefaultOpenBehavior::ExistingWindow) => { force_existing_window = true; } - settings::CliDefaultOpenBehavior::NewWindow => { + Some(settings::CliDefaultOpenBehavior::NewWindow) => { open_new_workspace = Some(true); } + None => {} } } @@ -540,34 +539,29 @@ pub async fn handle_cli_connection( } CliRequest::SetOpenBehavior { .. } => { // We handle this case in a situation-specific way in - // maybe_prompt_open_behavior + // resolve_open_behavior debug_panic!("unexpected SetOpenBehavior message"); } } } } -/// Checks whether the CLI user should be prompted to configure their default -/// open behavior. Sends `CliResponse::PromptOpenBehavior` and waits for the -/// CLI's response if all of these are true: -/// - No explicit flag was given (`-n`, `-e`, `-a`) -/// - There is at least one existing Zed window -/// - The user has not yet configured `cli_default_open_behavior` in settings +/// Resolves the CLI open behavior when no explicit flag (`-n`, `-e`, `--reuse`) +/// was given. May prompt the user interactively on first run. /// -/// Returns the user's choice, or `None` if no prompt was needed or the CLI -/// didn't respond. -async fn maybe_prompt_open_behavior( - open_new_workspace: Option, - force_existing_window: bool, - reuse: bool, +/// Returns `Some(behavior)` to override the default, or `None` if no override +/// is needed (e.g. no existing windows, paths already in a workspace, or the +/// user has already configured `cli_default_open_behavior` in settings). +async fn resolve_open_behavior( paths: &[String], app_state: &Arc, responses: &dyn CliResponseSink, requests: &mut mpsc::UnboundedReceiver, cx: &mut AsyncApp, ) -> Option { - if open_new_workspace.is_some() || force_existing_window || reuse { - return None; + let cli_prompt_enabled = cx.update(|cx| cx.has_flag::()); + if !cli_prompt_enabled { + return Some(settings::CliDefaultOpenBehavior::NewWindow); } let has_existing_windows = cx.update(|cx| {