Streamline session+worktree creation: quick-create and inline branch input#205
Merged
Streamline session+worktree creation: quick-create and inline branch input#205
Conversation
0c12d88 to
547e7d8
Compare
…e branch input - Add CreateSessionWithWorktreeAsync() to CopilotService: single atomic call that creates worktree, creates session, links them, organizes into repo group, and optionally sends initial prompt. Includes rollback on session creation failure. - Add WorktreeId property to AgentSessionInfo for first-class session-to-worktree relationship (previously only tracked via path string and SessionMeta). - Add Quick Session button (lightning bolt) to repo group context menu: one-click to auto-generate branch, create worktree+session, and switch to it. - Add New Branch + Session button to repo group context menu: opens inline input below group header where user types branch name (or #PR number) and presses Enter to atomically create worktree+session. Replaces the 7-step form flow. - Refactor HandleCreateSession to use atomic API when worktreeId is provided, eliminating scattered linking/organizing logic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Clarifies that both options create a branch — the difference is whether you name it yourself or get an auto-generated name. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Previously opacity:0 and only visible on hover — easy to miss. Now shows at 0.7 opacity on repo groups (0.5 on regular groups), brightens to full on hover. Uses text-secondary color instead of control-border for better contrast. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a session resumes with IsProcessing=true (mid-turn when app died),
ProcessingPhase was left at default 0 ('Sending') even though the session
was actively running tools. The phase only updated when a NEW event arrived
from the SDK, leaving a potentially long window of incorrect status display.
Now sets ProcessingPhase based on the last event in events.jsonl:
- If last activity was a tool call → phase 3 (Working)
- Otherwise → phase 2 (Thinking)
Also sets ProcessingStartedAt so elapsed time displays correctly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add MoveSessionToWorktree() to CopilotService: updates WorkingDirectory, WorktreeId, git branch, worktree link, and repo group membership in one call - Add submenu in SessionListItem showing all available worktrees (grouped by repo name / branch) with the current worktree excluded - Wire OnMoveToWorktree callback through SessionSidebar Users can now reassign any session to a different worktree via the session's ... menu without recreating the session. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaces the previous 'list existing worktrees' submenu with a single 'Move to New Worktree...' menu item that opens an inline input below the session. User types a branch name (or #PR) and the session is moved to the new worktree while preserving the Copilot session and conversation history. - MoveSessionToNewWorktreeAsync() creates a new worktree, updates the session's WorkingDirectory/WorktreeId/GitBranch/meta/group, then sends a message to the agent notifying it of the directory change. - Inline input supports repo selector when multiple repos exist. - Session history and SDK session are fully preserved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The SDK doesn't support changing a session's working directory at runtime, so moving a session to a different worktree can't reliably redirect the agent's file operations. Removed entirely rather than shipping a half-measure. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds WorktreeStrategy enum with three options: - Shared: all sessions use one worktree (existing default) - OrchestratorIsolated: orchestrator gets its own, workers share a separate one - FullyIsolated: every session gets its own worktree Implementation: - WorktreeStrategy enum added to SessionOrganization.cs - SessionGroup.WorktreeStrategy persists the chosen strategy - GroupPreset.DefaultWorktreeStrategy sets per-preset defaults - PR Review Squad defaults to FullyIsolated (workers checkout different PRs) - CreateGroupFromPresetAsync auto-creates worktrees based on strategy: - FullyIsolated: creates N worker worktrees in parallel via Task.WhenAll - OrchestratorIsolated: creates 1 orchestrator + 1 shared worker worktree - Shared: no change from current behavior - Orchestrator planning prompt now includes worktree paths for each worker - Worker prompts include worktree awareness note when isolated - DeleteGroup now cleans up all per-session worktrees (previously leaked) All 113 multi-agent tests + 19 organization tests pass. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Since worktrees are now auto-created based on WorktreeStrategy, the 'Select worktree for team' step is replaced with 'Select repository for team'. Users pick a repo, then a preset — worktrees are created automatically (FullyIsolated creates one per agent, etc). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Two fixes: 1. Added a dropdown to select worktree strategy (FullyIsolated / OrchestratorIsolated / Shared) when creating multi-agent groups. Defaults to FullyIsolated. 2. Fixed session creation failure: parallel git worktree creation caused lock contention on bare repos. Now does one fetch upfront then creates worktrees sequentially with skipFetch flag. Also fixed two callers of CreateWorktreeAsync that broke when the skipFetch parameter was added (positional CancellationToken arg). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Wrap all worktree creation calls in try-catch so that if git worktree add fails (e.g., lock contention, disk issues, large repos), session creation still proceeds with the fallback shared working directory. Previously, a single worktree failure would abort the entire CreateGroupFromPresetAsync, leaving an empty group with no sessions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Added a bordered card with header '🌿 Worktree Isolation' around the strategy dropdown so it's clearly visible between the team name input and the preset list. Previously it was a subtle inline element that was easy to miss. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New WorktreeStrategyTests.cs covers: - FullyIsolated: unique worktree per session, skip-fetch optimization - OrchestratorIsolated: 2 worktrees, workers share one - Shared: no worktrees created - StrategyOverride: UI override takes precedence over preset default - Error resilience: sessions still created when worktrees fail - Session correctness: right count, orchestrator pinned, group wt ID Also: - Made RepoManager.CreateWorktreeAsync/FetchAsync virtual for testing - Added diagnostic logs showing worktree strategy, directories, and per-worker worktree assignments for debugging Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…reation) Root cause: 'PR Review Squad' has spaces, which are invalid in git branch names. CreateWorktreeAsync silently failed for all workers because 'git worktree add -b PR Review Squad-worker-1-xxxx' was rejected by git. Only the orchestrator appeared to succeed (fell back to an existing branch). Fix: sanitize team name by replacing non-alphanumeric chars with dashes before using it in branch names. 'PR Review Squad' becomes 'PR-Review-Squad'. Added 2 tests for branch name sanitization (spaces and special chars). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
RemoveWorktreeAsync now wraps Directory.Delete and git worktree prune in try-catch so a failure in either doesn't prevent state cleanup. Also handles the case where the repo is gone but the directory exists. Previously, if git worktree remove failed AND prune threw, the worktree entry was never removed from state and the directory leaked. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The repo group context menu showed 'Remove Repo' even for multi-agent teams created on that repo. This is confusing and dangerous — removing the repo would orphan the team. Now hidden when group.IsMultiAgent. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When git worktree add fails mid-operation, it can leave an empty or partial directory behind. This directory isn't tracked by git's worktree list, so RemoveWorktreeAsync can't clean it up later. Now CreateWorktreeAsync wraps the git call in try-catch and deletes the partial directory before re-throwing, preventing directory leaks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
RemoveWorktreeAsync now deletes the worktree branch after removing the directory. Previously, branches like PR-Review-Squad-worker-1-xxxx accumulated in the bare repo (30+ stale branches found). Also cleaned up 31 stale branches and pruned worktree references. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add CreatedWorktreeIds list to SessionGroup that records every worktree created during squad setup. DeleteGroup now uses this authoritative list for cleanup, preventing leaks when session creation fails after worktree creation succeeds. Adds 4 tests covering tracking across all strategies. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ee strategy Replace the hidden nested worktree picker with a flat, repo-first design matching the multi-agent squad creation flow: - Mode chips: Repo | Directory | Empty (Repo default when repos exist) - Worktree segment: Auto | Branch | PR | Existing - Auto mode generates branch name from session name (zero-config) - Auto-naming: session name fills from branch/PR input - Removed Options > Select worktree nesting (now all visible by default) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the two separate 'Close Session' and 'Close & Delete Worktree' menu items with a single '🗑 Close Session…' item that shows an inline confirmation panel. When the session has an associated worktree, a checkbox appears to optionally delete the worktree and branch too. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pass null working directory for Empty mode sessions instead of falling back to ProjectDir. The SDK accepts null - the agent works without a codebase context. Directory mode still falls back to ProjectDir when the input is blank. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Create a unique temp folder under polypilot-sessions/ for each scratch session so the agent has a clean workspace without access to any existing codebase. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace inline confirmation with centered modal dialog popup. Add separate checkboxes for 'Delete worktree' and 'Delete branch', both checked by default when session has a worktree. RemoveWorktreeAsync now accepts deleteBranch parameter to support keeping the branch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the modal overlay to the root level of the component (outside the session-item div) so it renders above all sidebar content. Also fix stray closing brace and bump z-index. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Three-model code review identified these bugs: 1. deleteBranch=true default silently changed all existing callers to delete branches (Sonnet). Fixed: default to false, explicit true where intended. 2. RemoveWorktreeAsync deletes arbitrary dirs when repo lookup fails (Opus). Fixed: validate path is under WorktreesDir before recursive delete. 3. Empty branchPrefix from sanitization produces invalid git names like '-worker-1-xxxx' (Sonnet+Codex). Fixed: fallback to 'team'/'session'. 4. Delete branch checkbox is silently no-op without delete worktree (all 3). Fixed: disable checkbox + dim when worktree unchecked, auto-uncheck. 5. DeleteGroup fire-and-forget can abort cleanup loop on first failure (Codex). Fixed: per-item try/catch with debug logging. 6. Session name dedup collides within same minute (Opus). Fixed: use incrementing counter loop instead of HHmm timestamp. 7. Empty session temp dirs leak forever (Opus+Codex). Fixed: cleanup polypilot-sessions/ temp dirs on CloseSessionAsync (path-validated). 8. CreateSessionWithWorktreeAsync broken in remote mode (Opus). Fixed: throw NotSupportedException with clear message. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tion) CloseSessionIconTests: Updated to reflect intentional change from ✕ to 🗑 icon — SessionListItem's close now opens a dialog with destructive options (delete worktree/branch), so the trash icon is appropriate. InputSelectionTests: Updated CSS class references after CreateSessionForm rewrite (wt-branch-input → ns-name, removed ns-input since the directory input uses @Bind not @onkeyup). Verified: remaining 7 DiffParser+ServerManager failures also fail on origin/main (pre-existing Windows line-ending and flaky network issues). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…w:hidden Root cause: The close dialog overlay rendered inside SessionListItem which is nested in sidebar > sidebar-content > session-list, all with overflow:hidden. Even though the overlay used position:fixed, the overflow clipping on ancestor elements prevented it from being visible outside the 280px sidebar. Fix: After the dialog renders, use JS interop to move (portal) the overlay element to document.body, escaping the overflow:hidden containment chain. Also improved dialog styling: darker overlay (0.7 opacity), brighter dialog background (#2a2a3e), purple accent border with glow shadow, white title text. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
QuickCreateSessionForRepo errors were swallowed silently because createError is only displayed in CreateSessionForm (which isn't open during quick-create). Added quickCreateError/quickCreateErrorRepoId fields that render a dismissible error bar under the relevant group. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…load If Load() throws (e.g. corrupted JSON), _state becomes empty but _loaded=true prevents re-loading. Any subsequent Save() (from worktree operations etc.) would overwrite repos.json with empty state, silently destroying all repo entries. Added _loadedSuccessfully flag that Save() checks before writing empty state. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1a14fc6 to
dfad27d
Compare
Critical: - Fix DOM portal orphaned overlays: HideCloseConfirm and ConfirmClose now remove the portaled element from document.body before Blazor diffs - Fix async void ShowCloseConfirm → async Task - Remove dead needsPortal variable Moderate: - Remove dead deleteBranch-without-deleteWorktree code path - Add PR number validation in CommitQuickBranch (reject #0, #abc) - Fix null! suppression: use args.RepoId! (already null-checked) - Set WorktreeId on AgentSessionInfo in CreateGroupFromPresetAsync (was only set on SessionMeta, inconsistent with CreateSessionWithWorktreeAsync) - Fix race condition in DeleteGroup: add _stateLock to RepoManager for thread-safe List<T> access (Repositories/Worktrees getters return copies) - Fix shared strategy creating temp dirs: auto-create shared worktree when repo is set but no workingDirectory/worktreeId provided - Fix _loadedSuccessfully gap: set flag true on first successful Save() so subsequent removes persist correctly Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…eeId New tests: - Save_AfterFailedLoad_DoesNotOverwriteWithEmptyState: verifies the _loadedSuccessfully guard prevents wiping repos.json after a parse error - Save_AfterSuccessfulLoad_PersistsEmptyState: normal remove-all-repos works - Repositories_ReturnsCopy_ThreadSafe: verifies .ToList() snapshot isolation - Shared_WithRepoButNoWorkDir_CreatesSharedWorktree: verifies auto-create when no workingDirectory is provided (was creating temp dirs before fix) - Shared_WithExistingWorkDir_CreatesNoWorktree: existing behavior preserved - FullyIsolated_WorktreeIdSetOnAgentSessionInfo: verifies WorktreeId is set on AgentSessionInfo (not just SessionMeta) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Critical: - IAsyncDisposable on SessionListItem: removes portaled overlay on dispose to prevent permanent UI-blocking dark backdrop - Scoped data-dialog-id selector: each instance uses a unique ID instead of global .close-dialog-overlay, preventing cross-instance interference Moderate: - Shared strategy workers use orchWorkDir: fallback chain is now workerWorkDirs[i] ?? orchWorkDir ?? workingDirectory (was skipping orchWorkDir) - Consistent _stateLock on all Add/Remove paths in RepoManager - Git -- separator added to worktree add and branch -D commands - args.RepoId derived from worktree when only WorktreeId is set - Quick-branch input sanitized with Regex (matching CreateSessionForm) Tests: - Shared_WithRepoButNoWorkDir now verifies all sessions share same directory Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This was referenced Feb 26, 2026
This was referenced Feb 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Streamlines the session + worktree creation flow, reducing it from a 7-step process to 1-2 clicks.
Changes
Foundation: Atomic \CreateSessionWithWorktreeAsync()\ API
*Foundation: \WorktreeId\ on \AgentSessionInfo*
UX: ⚡ Quick Session button
UX: ⑂ New Branch + Session inline input
Before vs After
Testing
cc @PureWeen