Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
136 commits
Select commit Hold shift + click to select a range
ed2af03
ep: Stratify by cursor_path by default (#50111)
osyvokon Feb 25, 2026
3c8f302
agent: Improve SpawnAgentTool instructions for clarity (#50114)
benbrandt Feb 25, 2026
ecbfc2b
git_graph: Polish UX (#50123)
Anthony-Eid Feb 25, 2026
136105c
docs: Remove Preview callouts for stable release (#50119)
morgankrey Feb 25, 2026
d2b1b6a
docs: Apply preview release suggestions (#50118)
morgankrey Feb 25, 2026
c6571ec
Add GPT-5.3-Codex BYOK model under the OpenAI provider (#50122)
rtfeldman Feb 25, 2026
3caf807
docs: Fix content in some AI pages (#50129)
danilo-leal Feb 25, 2026
beb0fb9
Show assistant namespace in command palette regardless of agent panel…
rtfeldman Feb 25, 2026
a5b34a0
Add thread target selector UI + worktree labels in history
rtfeldman Feb 13, 2026
4a7b540
Review fixes: persist thread target, restore-thread validation, model…
rtfeldman Feb 19, 2026
805f909
Fix CI: remove unused import and non-existent agents_panel_dock field
rtfeldman Feb 19, 2026
1ae8a5e
Fix test: only validate thread existence in DB for NativeAgent threads
rtfeldman Feb 19, 2026
e965a30
Fix inconsistent is_via_collab check in thread target selector
rtfeldman Feb 19, 2026
537697a
Extract shared format_relative_time to eliminate duplication
rtfeldman Feb 19, 2026
50bcaf4
Add iteration guard to set_selected_index to prevent potential hang
rtfeldman Feb 19, 2026
4640807
Persist thread target selection on change
rtfeldman Feb 19, 2026
9210b5e
Derive Serialize/Deserialize on ThreadTarget directly
rtfeldman Feb 19, 2026
307a02d
Validate thread target on deserialization
rtfeldman Feb 19, 2026
71403f8
Add test and TODO for set_active worktree creation guard
rtfeldman Feb 19, 2026
641caf4
Fix test: initialize GlobalFs for set_active worktree creation test
rtfeldman Feb 19, 2026
25a881d
Fix test: use StubAgentServer instead of triggering full agent infra
rtfeldman Feb 19, 2026
3694392
Add visual tests for thread target selector, worktree status banner, …
rtfeldman Feb 19, 2026
7862eb7
Add visual test for thread target selector dropdown open state
rtfeldman Feb 19, 2026
6e39661
Create git worktrees on first prompt when New Worktree target is sele…
rtfeldman Feb 20, 2026
7da5677
Create worktree on first prompt when NewWorktree target is selected
rtfeldman Feb 20, 2026
7902681
Replace needs_worktree_creation flag with FirstSendRequested event
rtfeldman Feb 20, 2026
e2b0ba0
Clone dock state and open files into new worktree workspace
rtfeldman Feb 20, 2026
5582af4
Prevent nested git worktree creation
rtfeldman Feb 20, 2026
15cb24f
Gate New Worktree dropdown behind agent-git-worktrees feature flag
rtfeldman Feb 20, 2026
5b56b02
Create worktree workspace in background before activating
rtfeldman Feb 20, 2026
55252ce
Fix code review issues in agent_ui
rtfeldman Feb 21, 2026
5df4ed8
Remove plan.md
rtfeldman Feb 25, 2026
5834d6c
Remove fix-plan.md
rtfeldman Feb 25, 2026
d40b79f
wip
rtfeldman Feb 25, 2026
f6c4a02
Add worktree creation success screenshot
rtfeldman Feb 25, 2026
a80a6cb
Add worktree creation succeeded visual test
rtfeldman Feb 25, 2026
e8dafc2
Remove debug investigation document from repo
rtfeldman Feb 25, 2026
f6086f4
Rename _external_thread to create_external_thread
rtfeldman Feb 25, 2026
a2533ae
Add missing git repository check for ExistingWorktree target
rtfeldman Feb 25, 2026
8310371
Move inline use statements to top-level imports
rtfeldman Feb 25, 2026
dc3aa2c
zeta2: Send snapshot event (#50126)
probably-neb Feb 25, 2026
88e234d
docs: Add small fix to the MCP page (#50134)
danilo-leal Feb 25, 2026
e1a4723
Address code review issues for thread target selector UI
rtfeldman Feb 25, 2026
79394ab
extension_ci: Shorten SHA length in PR titles (#50135)
MrSubidubi Feb 25, 2026
4d4836d
agent: Implement streaming for edit file tool (#50004)
bennetbo Feb 25, 2026
f185f5f
multiworkspace: Disable sidebar if disable_ai is enabled (#50137)
Anthony-Eid Feb 25, 2026
4130daa
repl: Fix duplicate output inside notebooks (#48616)
MostlyKIGuess Feb 25, 2026
39d3ceb
multi_workspace: Move up action handler and modal rendering from work…
Anthony-Eid Feb 25, 2026
27bb25e
Edit prediction: add some typescript evals, fix a teacher model failu…
maxbrunsfeld Feb 25, 2026
662be1c
Fix and improve docs automation scripts (#50120)
morgankrey Feb 26, 2026
1368eb0
Fix Windows remote server (#50152)
reflectronic Feb 26, 2026
777768f
lsp_button: Improve UI for LS submenu (#50160)
danilo-leal Feb 26, 2026
aace380
Fix panic in diff hunk rendering (#50163)
ConradIrwin Feb 26, 2026
66db09b
ssh: Fix IPv6 address formatting in port forward `-L` arguments (#49032)
chenwuji2000-cyber Feb 26, 2026
caaeb8d
agent: Detect overlapping edits in StreamingEditFileTool (#50181)
bennetbo Feb 26, 2026
b0f7d26
markdown_preview: Fix panic in mermaid diagram renderer (#50176)
smitbarmase Feb 26, 2026
5a630f4
Side by side diff spacer polish (#50182)
cameron1024 Feb 26, 2026
e021291
agent: Stream content in `StreamingEditFileTool` (#50187)
bennetbo Feb 26, 2026
f4bab6c
vim: Add configurable yank highlight background color (#49517)
kaspernyhus Feb 26, 2026
a01fa7b
agent_servers: Migrate all built-in agents to go via registry (#50094)
benbrandt Feb 26, 2026
8290e40
agent_ui: Unify ui elements (#50201)
benbrandt Feb 26, 2026
73b30e5
editor: Fix JoinLines with selection to end-of-line (#48035)
jrobsonchase Feb 26, 2026
e521acd
dev: Add Tree-sitter tokens and resolved theme keys in highlights tre…
ozacod Feb 26, 2026
117bfed
outline: Refactor outline render_item to reuse existing TextStyle (#4…
cppcoffee Feb 26, 2026
23bdf89
ui: Fix modals not using UI font and text color (#50208)
Anthony-Eid Feb 26, 2026
c5f2bb3
Duplicates bot v2: focus on root cause, larger issue body preview (#5…
zelenenka Feb 26, 2026
f3a89c2
git: Fix a panic when searching the split diff (#50211)
cole-miller Feb 26, 2026
58aa7fe
Get collab test suite passing (#50214)
Anthony-Eid Feb 26, 2026
503437e
Fix `Collapse All Files` button being limited to the current buffer (…
0x2CA Feb 26, 2026
62e8cc8
language_selector: Auto-select current language when opening (#48475)
cppcoffee Feb 26, 2026
8776995
Start removing callers of legacy excerpt APIs (#50144)
cole-miller Feb 26, 2026
f6e2023
agent: Simplify subagent tool and handle (#50230)
benbrandt Feb 26, 2026
f6bc229
gpui: Fix `send_file_drop_event` holding mutex during event callback …
Albab-Hasan Feb 26, 2026
ef63818
Handle empty match list and do safe vector selection instead of slici…
KyleBarton Feb 26, 2026
09d37fb
languages: Add `.prettierrc` to JSON `path_suffixes` (#50156)
yeskunall Feb 26, 2026
a306608
GPUI on the web (#50228)
Veykril Feb 26, 2026
e72fdb5
settings: Remove unused `file_finder.git_status` setting (#49889)
yeskunall Feb 26, 2026
42a0cf7
Add fast mode toggle in agent panel (#49714)
tomhoule Feb 26, 2026
43cd578
agent: Rename run_turn to send in subagent handle (#50242)
benbrandt Feb 26, 2026
ecc8876
acp: Fix stale ACP reasoning-effort options when model switch keeps s…
nikhil-pandey Feb 26, 2026
56ad548
Replace first-send bypass with policy enum on AcpThreadView
rtfeldman Feb 26, 2026
90ac597
Add folder_paths for project grouping (#50249)
mikayla-maki Feb 26, 2026
362a531
Add Vercel AI gateway provider integration (#50207)
dancer Feb 26, 2026
db58e47
Revert "outline: Refactor outline render_item to reuse existing TextS…
SomeoneToIgnore Feb 26, 2026
66ff32b
Add edit prediction evals that test related excerpt usage (#50256)
maxbrunsfeld Feb 26, 2026
e515f95
Include optional model version with EP acceptance and rejection messa…
maxbrunsfeld Feb 27, 2026
c602cc3
languages: Reorder type identifier highlights in JavaScript (#49325)
yeskunall Feb 27, 2026
d074aa4
docs: Point to the right Bash extension repository (#50271)
yeskunall Feb 27, 2026
1515a0b
Relax device limits for WGPU (#50270)
reflectronic Feb 27, 2026
09974bb
Improve GPU selection on Linux (#50274)
reflectronic Feb 27, 2026
0b2c74d
gpui: Reduce amount of wasm cfgs in gpui (#50278)
Veykril Feb 27, 2026
c10f03d
agent_ui: Add more improvements to the subagent UI (#50260)
danilo-leal Feb 27, 2026
e1a89fb
markdown_preview: Fix mermaid diagrams failing to render with empty s…
smitbarmase Feb 27, 2026
6f1a14d
Fix Cmd+click navigating to file instead of definition (#49012)
chenwuji2000-cyber Feb 27, 2026
d7f0ee1
Fix version reporting for duplicates bot (#50286)
zelenenka Feb 27, 2026
b4f2382
Decrease review needs of the duplicate bot (#50289)
zelenenka Feb 27, 2026
183395b
agent: Stream `new_text` in `StreamingEditFileTool` (#50240)
bennetbo Feb 27, 2026
078d056
ep: Heuristic to apply patches to files without trailing newline (#50…
osyvokon Feb 27, 2026
8f0f345
agent_ui: Registry follow-ups (#50287)
benbrandt Feb 27, 2026
ba7cd2d
Format Tree-sitter queries with `ts_query_ls` (#50138)
MrSubidubi Feb 27, 2026
820f860
Add PR 50138 to `.git-blame-ignore-revs` (#50293)
MrSubidubi Feb 27, 2026
7b1673f
docs: Add footer with links to pages (#50296)
danilo-leal Feb 27, 2026
ae2168e
Revert "sidebar: Zoom temporarily hides sidebar (#50088)" (#50297)
Anthony-Eid Feb 27, 2026
c53a356
gpui: Gate Linux screen capture APIs behind feature flag (#50300)
Anthony-Eid Feb 27, 2026
e4d4557
ci: Add check for formatting of query files (#50140)
MrSubidubi Feb 27, 2026
09ae0e9
agent: Allow jumping from diff to actual file (#50292)
bennetbo Feb 27, 2026
46ce90b
agent: Render subagent labels as they stream in (#50306)
benbrandt Feb 27, 2026
7bf65bc
Merge remote-tracking branch 'origin/main' into AI-34/thread-target-s…
rtfeldman Feb 27, 2026
9dd9c84
Merge remote-tracking branch 'origin/main' into AI-34/thread-target-s…
rtfeldman Feb 27, 2026
307fbc1
collab: Include original repo path in repository updates
rtfeldman Feb 27, 2026
bddc671
Update Workspace::new_local test calls
rtfeldman Feb 27, 2026
0b132d8
Merge remote-tracking branch 'origin/main' into AI-34/thread-target-s…
rtfeldman Feb 27, 2026
0d3970c
Default thread target to LocalProject when worktree flag is off
rtfeldman Feb 27, 2026
bbab700
Continue worktree target fixes and update implementation plan
rtfeldman Feb 28, 2026
b8978bd
Fix remaining code review issues #3, #8, #9, #10, #11
rtfeldman Feb 28, 2026
40b2786
Merge remote-tracking branch 'origin/main' into AI-34/thread-target-s…
rtfeldman Feb 28, 2026
1e95ad7
Remove redundant clone calls in visual test runner
rtfeldman Feb 28, 2026
d992fbb
Restore cfg attribute on run_thread_target_selector_visual_tests
rtfeldman Feb 28, 2026
ca875ff
Merge remote-tracking branch 'origin/main' into AI-34/thread-target-s…
rtfeldman Mar 2, 2026
47574da
Remove planning doc from branch
rtfeldman Mar 2, 2026
fb4108c
Remove FirstSendPolicy; always emit FirstSendRequested on first send
rtfeldman Mar 2, 2026
7850a7f
Add comments explaining first-send interception for New Worktree
rtfeldman Mar 2, 2026
100b3b8
Revise a comment
rtfeldman Mar 2, 2026
ea5924d
Extract resolve_message_contents helper in ThreadView
rtfeldman Mar 2, 2026
0a8235a
Rename ThreadTarget to StartThreadIn
rtfeldman Mar 2, 2026
0009ecc
Remove unused ExistingWorktree variant
rtfeldman Mar 2, 2026
e2ed796
Add AgentType::is_native() helper
rtfeldman Mar 2, 2026
c84c472
Add comment explaining thread view subscription in set_active_view
rtfeldman Mar 2, 2026
1409f22
Defer is_via_collab and has_git_repo checks in set_start_thread_in
rtfeldman Mar 2, 2026
4396d09
Remove plan.md.local
rtfeldman Mar 2, 2026
c1fe436
Fix remaining code review issues and revert unrelated changes
rtfeldman Mar 2, 2026
6293a08
Replace SetStartThreadIn and StartThreadInKind with StartThreadIn
rtfeldman Mar 2, 2026
51ec104
Add doc comments to worktree creation helpers
rtfeldman Mar 2, 2026
920c9a6
Merge remote-tracking branch 'origin/main' into AI-34/thread-target-s…
rtfeldman Mar 3, 2026
dd5c88d
Fix clippy clone-on-copy and redundant clone warnings
rtfeldman Mar 3, 2026
3b6cb5a
Only intercept first send for new worktree threads
rtfeldman Mar 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/agent_ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ feature_flags.workspace = true
file_icons.workspace = true
fs.workspace = true
futures.workspace = true
git.workspace = true
fuzzy.workspace = true
gpui.workspace = true
gpui_tokio.workspace = true
Expand Down
1,507 changes: 1,357 additions & 150 deletions crates/agent_ui/src/agent_panel.rs

Large diffs are not rendered by default.

16 changes: 15 additions & 1 deletion crates/agent_ui/src/agent_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ use std::any::TypeId;
use workspace::Workspace;

use crate::agent_configuration::{ConfigureContextServerModal, ManageProfilesModal};
pub use crate::agent_panel::{AgentPanel, AgentPanelEvent, ConcreteAssistantPanelDelegate};
pub use crate::agent_panel::{
AgentPanel, AgentPanelEvent, ConcreteAssistantPanelDelegate, WorktreeCreationStatus,
};
use crate::agent_registry_ui::AgentRegistryPage;
pub use crate::inline_assistant::InlineAssistant;
pub use agent_diff::{AgentDiffPane, AgentDiffToolbar};
Expand Down Expand Up @@ -222,6 +224,18 @@ impl ExternalAgent {
}
}

/// Sets where new threads will run.
#[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema, Action,
)]
#[action(namespace = agent)]
#[serde(rename_all = "snake_case", tag = "kind")]
pub enum StartThreadIn {
#[default]
LocalProject,
NewWorktree,
}

/// Content to initialize new external agent with.
pub enum AgentInitialContent {
ThreadSummary(acp_thread::AgentSessionInfo),
Expand Down
16 changes: 12 additions & 4 deletions crates/agent_ui/src/connection_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ use fs::Fs;
use futures::FutureExt as _;
use gpui::{
Action, Animation, AnimationExt, AnyView, App, ClickEvent, ClipboardItem, CursorStyle,
ElementId, Empty, Entity, FocusHandle, Focusable, Hsla, ListOffset, ListState, ObjectFit,
PlatformDisplay, ScrollHandle, SharedString, Subscription, Task, TextStyle, WeakEntity, Window,
WindowHandle, div, ease_in_out, img, linear_color_stop, linear_gradient, list, point,
pulsating_between,
ElementId, Empty, Entity, EventEmitter, FocusHandle, Focusable, Hsla, ListOffset, ListState,
ObjectFit, PlatformDisplay, ScrollHandle, SharedString, Subscription, Task, TextStyle,
WeakEntity, Window, WindowHandle, div, ease_in_out, img, linear_color_stop, linear_gradient,
list, point, pulsating_between,
};
use language::Buffer;
use language_model::LanguageModelRegistry;
Expand Down Expand Up @@ -295,6 +295,12 @@ impl Conversation {
}
}

pub enum AcpServerViewEvent {
ActiveThreadChanged,
}

impl EventEmitter<AcpServerViewEvent> for ConnectionView {}

pub struct ConnectionView {
agent: Rc<dyn AgentServer>,
agent_server_store: Entity<AgentServerStore>,
Expand Down Expand Up @@ -386,6 +392,7 @@ impl ConnectionView {
if let Some(view) = self.active_thread() {
view.focus_handle(cx).focus(window, cx);
}
cx.emit(AcpServerViewEvent::ActiveThreadChanged);
cx.notify();
}
}
Expand Down Expand Up @@ -524,6 +531,7 @@ impl ConnectionView {
}

self.server_state = state;
cx.emit(AcpServerViewEvent::ActiveThreadChanged);
cx.notify();
}

Expand Down
93 changes: 69 additions & 24 deletions crates/agent_ui/src/connection_view/thread_view.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use acp_thread::ContentBlock;
use cloud_api_types::{SubmitAgentThreadFeedbackBody, SubmitAgentThreadFeedbackCommentsBody};
use editor::actions::OpenExcerpts;

use crate::StartThreadIn;
use gpui::{Corner, List};
use language_model::{LanguageModelEffortLevel, Speed};
use settings::update_settings_file;
Expand Down Expand Up @@ -191,6 +193,12 @@ impl DiffStats {
}
}

pub enum AcpThreadViewEvent {
FirstSendRequested { content: Vec<acp::ContentBlock> },
}

impl EventEmitter<AcpThreadViewEvent> for ThreadView {}

pub struct ThreadView {
pub id: acp::SessionId,
pub parent_id: Option<acp::SessionId>,
Expand Down Expand Up @@ -518,6 +526,24 @@ impl ThreadView {
.thread(acp_thread.session_id(), cx)
}

/// Resolves the message editor's contents into content blocks. For profiles
/// that do not enable any tools, directory mentions are expanded to inline
/// file contents since the agent can't read files on its own.
fn resolve_message_contents(
&self,
message_editor: &Entity<MessageEditor>,
cx: &mut App,
) -> Task<Result<(Vec<acp::ContentBlock>, Vec<Entity<Buffer>>)>> {
let expand = self.as_native_thread(cx).is_some_and(|thread| {
let thread = thread.read(cx);
AgentSettings::get_global(cx)
.profiles
.get(thread.profile())
.is_some_and(|profile| profile.tools.is_empty())
});
message_editor.update(cx, |message_editor, cx| message_editor.contents(expand, cx))
}

pub fn current_model_id(&self, cx: &App) -> Option<String> {
let selector = self.model_selector.as_ref()?;
let model = selector.read(cx).active_model(cx)?;
Expand Down Expand Up @@ -731,6 +757,46 @@ impl ThreadView {
}

let message_editor = self.message_editor.clone();

// Intercept the first send so the agent panel can capture the full
// content blocks — needed for "Start thread in New Worktree",
// which must create a workspace before sending the message there.
let intercept_first_send = self.thread.read(cx).entries().is_empty()
&& !message_editor.read(cx).is_empty(cx)
&& self
.workspace
.upgrade()
.and_then(|workspace| workspace.read(cx).panel::<AgentPanel>(cx))
.is_some_and(|panel| {
panel.read(cx).start_thread_in() == &StartThreadIn::NewWorktree
});

if intercept_first_send {
let content_task = self.resolve_message_contents(&message_editor, cx);

cx.spawn(async move |this, cx| match content_task.await {
Ok((content, _tracked_buffers)) => {
if content.is_empty() {
return;
}

this.update(cx, |_, cx| {
cx.emit(AcpThreadViewEvent::FirstSendRequested { content });
})
.ok();
}
Err(error) => {
this.update(cx, |this, cx| {
this.handle_thread_error(error, cx);
})
.ok();
}
})
.detach();

return;
}

let is_editor_empty = message_editor.read(cx).is_empty(cx);
let is_generating = thread.read(cx).status() != ThreadStatus::Idle;

Expand Down Expand Up @@ -794,18 +860,7 @@ impl ThreadView {
window: &mut Window,
cx: &mut Context<Self>,
) {
let full_mention_content = self.as_native_thread(cx).is_some_and(|thread| {
// Include full contents when using minimal profile
let thread = thread.read(cx);
AgentSettings::get_global(cx)
.profiles
.get(thread.profile())
.is_some_and(|profile| profile.tools.is_empty())
});

let contents = message_editor.update(cx, |message_editor, cx| {
message_editor.contents(full_mention_content, cx)
});
let contents = self.resolve_message_contents(&message_editor, cx);

self.thread_error.take();
self.thread_feedback.clear();
Expand Down Expand Up @@ -1140,21 +1195,11 @@ impl ThreadView {
let is_idle = self.thread.read(cx).status() == acp_thread::ThreadStatus::Idle;

if is_idle {
self.send_impl(message_editor.clone(), window, cx);
self.send_impl(message_editor, window, cx);
return;
}

let full_mention_content = self.as_native_thread(cx).is_some_and(|thread| {
let thread = thread.read(cx);
AgentSettings::get_global(cx)
.profiles
.get(thread.profile())
.is_some_and(|profile| profile.tools.is_empty())
});

let contents = message_editor.update(cx, |message_editor, cx| {
message_editor.contents(full_mention_content, cx)
});
let contents = self.resolve_message_contents(&message_editor, cx);

cx.spawn_in(window, async move |this, cx| {
let (content, tracked_buffers) = contents.await?;
Expand Down
3 changes: 2 additions & 1 deletion crates/collab/src/db/queries/projects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ impl Database {
repositories.push(proto::UpdateRepository {
project_id: db_repository_entry.project_id.0 as u64,
id: db_repository_entry.id as u64,
abs_path: db_repository_entry.abs_path,
abs_path: db_repository_entry.abs_path.clone(),
entry_ids,
updated_statuses,
removed_statuses: Vec::new(),
Expand All @@ -1015,6 +1015,7 @@ impl Database {
stash_entries: Vec::new(),
remote_upstream_url: db_repository_entry.remote_upstream_url.clone(),
remote_origin_url: db_repository_entry.remote_origin_url.clone(),
original_repo_abs_path: Some(db_repository_entry.abs_path),
});
}
}
Expand Down
3 changes: 2 additions & 1 deletion crates/collab/src/db/queries/rooms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -791,13 +791,14 @@ impl Database {
head_commit_details,
project_id: project_id.to_proto(),
id: db_repository.id as u64,
abs_path: db_repository.abs_path,
abs_path: db_repository.abs_path.clone(),
scan_id: db_repository.scan_id as u64,
is_last_update: true,
merge_message: db_repository.merge_message,
stash_entries: Vec::new(),
remote_upstream_url: db_repository.remote_upstream_url.clone(),
remote_origin_url: db_repository.remote_origin_url.clone(),
original_repo_abs_path: Some(db_repository.abs_path),
});
}
}
Expand Down
10 changes: 10 additions & 0 deletions crates/feature_flags/src/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ impl FeatureFlag for AgentSharingFeatureFlag {
const NAME: &'static str = "agent-sharing";
}

pub struct AgentGitWorktreesFeatureFlag;

impl FeatureFlag for AgentGitWorktreesFeatureFlag {
const NAME: &'static str = "agent-git-worktrees";

fn enabled_for_staff() -> bool {
false
}
}

pub struct DiffReviewFeatureFlag;

impl FeatureFlag for DiffReviewFeatureFlag {
Expand Down
48 changes: 48 additions & 0 deletions crates/git/src/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,26 @@ pub const GRAPH_CHUNK_SIZE: usize = 1000;
/// Default value for the `git.worktree_directory` setting.
pub const DEFAULT_WORKTREE_DIRECTORY: &str = "../worktrees";

/// Given the git common directory (from `commondir()`), derive the original
/// repository's working directory.
///
/// For a standard checkout, `common_dir` is `<work_dir>/.git`, so the parent
/// is the working directory. For a git worktree, `common_dir` is the **main**
/// repo's `.git` directory, so the parent is the original repo's working directory.
///
/// Falls back to returning `common_dir` itself if it doesn't end with `.git`
/// (e.g. bare repos or unusual layouts).
pub fn original_repo_path_from_common_dir(common_dir: &Path) -> PathBuf {
if common_dir.file_name() == Some(OsStr::new(".git")) {
common_dir
.parent()
.map(|p| p.to_path_buf())
.unwrap_or_else(|| common_dir.to_path_buf())
} else {
common_dir.to_path_buf()
}
}

/// Resolves the configured worktree directory to an absolute path.
///
/// `worktree_directory_setting` is the raw string from the user setting
Expand Down Expand Up @@ -4272,6 +4292,34 @@ mod tests {
);
}

#[test]
fn test_original_repo_path_from_common_dir() {
// Normal repo: common_dir is <work_dir>/.git
assert_eq!(
original_repo_path_from_common_dir(Path::new("/code/zed5/.git")),
PathBuf::from("/code/zed5")
);

// Worktree: common_dir is the main repo's .git
// (same result — that's the point, it always traces back to the original)
assert_eq!(
original_repo_path_from_common_dir(Path::new("/code/zed5/.git")),
PathBuf::from("/code/zed5")
);

// Bare repo: no .git suffix, returns as-is
assert_eq!(
original_repo_path_from_common_dir(Path::new("/code/zed5.git")),
PathBuf::from("/code/zed5.git")
);

// Root-level .git directory
assert_eq!(
original_repo_path_from_common_dir(Path::new("/.git")),
PathBuf::from("/")
);
}

#[test]
fn test_validate_worktree_directory() {
let work_dir = Path::new("/code/my-project");
Expand Down
4 changes: 2 additions & 2 deletions crates/git_ui/src/worktree_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,9 @@ impl WorktreeListDelegate {
.git
.worktree_directory
.clone();
let work_dir = repo.work_directory_abs_path.clone();
let original_repo = repo.original_repo_abs_path.clone();
let directory =
validate_worktree_directory(&work_dir, &worktree_directory_setting)?;
validate_worktree_directory(&original_repo, &worktree_directory_setting)?;
let new_worktree_path = directory.join(&branch);
let receiver = repo.create_worktree(branch.clone(), directory, commit);
anyhow::Ok((receiver, new_worktree_path))
Expand Down
Loading