Skip to content

feat: mobile worktree creation, PR-remote association, and close+delete worktree#185

Merged
PureWeen merged 7 commits intomainfrom
feat/mobile-worktree-sessions
Feb 23, 2026
Merged

feat: mobile worktree creation, PR-remote association, and close+delete worktree#185
PureWeen merged 7 commits intomainfrom
feat/mobile-worktree-sessions

Conversation

@PureWeen
Copy link
Owner

Summary

Enables mobile users to create worktrees and sessions via the bridge protocol (previously failed because mobile tried to run git locally). Also fixes PR-remote association on all platforms and adds a "Close & Delete Worktree" UI option.

Changes

Mobile Worktree Creation via Bridge

  • Added CreateWorktree, RemoveWorktree, WorktreeCreated, WorktreeRemoved, WorktreeError bridge messages
  • Server handles git operations for mobile; mobile delegates via bridge in remote mode
  • Fixed silent rejection: server now sends ErrorEvent when WorkingDirectory is invalid

PR-Remote Association (Desktop + Mobile)

  • Discovers actual PR branch name via gh pr view (falls back to pr-N if unavailable)
  • Sets upstream tracking (git branch --set-upstream-to) so push/pull work in PR worktrees
  • Handles branch collisions (branch already checked out in another worktree)
  • Sets GIT_DIR for bare repos so gh CLI discovers remotes correctly

Close & Delete Worktree UI

  • Session context menu: "Close & Delete Worktree" (shown when session has a worktree)
  • Group context menu: "Delete Team/Group & Worktree" (shown when group has a worktree)
  • Shared worktree guard: won't delete if other sessions/groups still reference it
  • Checks both org metadata and live sessions by working directory path

Review Fixes (3 rounds, 13 models)

  • Fixed git refspec (was creating wrong ref namespace)
  • Fixed RunGhAsync deadlock (concurrent stdout/stderr reads) + process orphan on cancel
  • Wrapped OnReposListReceived in InvokeOnUI (background thread crash risk)
  • Made RemoveWorktree request/response with proper RequestId correlation
  • Fixed critical bug: IsWorktreeInUse always returned true due to debounced save
  • Cancel pending worktree RPCs on bridge disconnect
  • RemoveWorktree now non-blocking (Task.Run like CreateWorktree)
  • Stale worktree reconciliation on mobile reconnect

Testing

  • All 1145 tests passing
  • Verified on Android: created PR worktree, confirmed remote association, closed+deleted worktree successfully

PureWeen and others added 7 commits February 22, 2026 15:01
Mobile was calling local RepoManager directly to create worktrees,
which fails on iOS/Android (no git binary). Also, the server silently
dropped session creation when WorkingDirectory didn't exist.

Changes:
- Add create_worktree/remove_worktree bridge commands with payloads
- Server handles worktree creation via RepoManager on desktop
- Client awaits WorktreeCreated response (2min timeout)
- Include worktrees in ReposListPayload so mobile picker shows them
- CreateSessionForm delegates to bridge in remote mode
- Request repos/worktrees on initial bridge connect
- Send error to client on invalid WorkingDirectory (was silent break)
- RepoManager.AddRemoteWorktree/AddRemoteRepo for in-memory tracking

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When creating a worktree from a PR (desktop or mobile):
- Use gh CLI to discover the PR's actual head branch name
- Fetch into that branch name instead of generic 'pr-N'
- Set upstream tracking (branch --set-upstream-to) so push/pull work
- Store the remote name in WorktreeInfo for UI display
- Gracefully falls back if gh is unavailable (uses pr-N naming)

Also adds Remote field to bridge protocol (WorktreeSummary,
WorktreeCreatedPayload) so mobile receives the association.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds UI options to close a session and simultaneously delete its
associated worktree. Works in both desktop (local) and remote (mobile)
modes.

Changes:
- SessionListItem.razor: Add 'Close & Delete Worktree' menu item
  (shown only when session has a WorktreeId)
- SessionSidebar.razor: Add CloseSessionAndDeleteWorktree handler
  that closes session then removes worktree via RepoManager or bridge
- SessionSidebar.razor: Add 'Delete Team/Group & Worktree' options
  for groups with associated worktrees
- Add DeleteGroupAndWorktree handler for group-level cleanup

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes from Opus 4.6, Sonnet 4.6, Sonnet 4.5, and Opus 4.5 reviews:

1. Fix git refspec: use simple fetch (bare clone refspec handles mapping)
   instead of explicit refspec that created wrong ref namespace
2. Fix RunGhAsync deadlock: read stdout/stderr concurrently with
   Task.WhenAll to prevent pipe buffer deadlock
3. Guard shared worktree deletion: check if other sessions/groups
   reference the worktree before deleting (prevents breaking multi-agent
   teams that share a worktree)
4. Send error response for RemoveWorktree failures: server now sends
   WorktreeError back to client instead of silently swallowing
5. Reconcile stale worktrees on reconnect: OnReposListReceived now
   removes entries absent from server response, not just adds new ones
6. Add RemoveRemoteWorktree/RemoveRemoteRepo methods to RepoManager

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…handling

- Set GIT_DIR env var when running gh from bare repos so it discovers remotes
- Use force-fetch (+refspec) to update existing branch refs
- Detect branch already checked out in another worktree, fall back to pr-N naming
- All 1145 tests passing

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes from 2× Opus 4.6, 2× Sonnet 4.6, 2× Codex 5.3, 1× Gemini 3 Pro:

1. Remove duplicate psi.WorkingDirectory assignment in RunGhAsync (all 7)
2. Fix branch collision check: use exact line matching instead of substring
   Contains to avoid false positives on prefix-matching branch names (Opus 4.6)
3. Wrap OnReposListReceived in InvokeOnUI to prevent Collection-modified
   crash when Blazor enumerates RepoManager lists (Opus 4.6 #2)
4. Make RemoveWorktree request/response with proper RequestId correlation:
   - Add RequestId to RemoveWorktreePayload
   - Add WorktreeRemoved message type for success confirmation
   - Client now awaits response with 30s timeout
   - WorktreeError routes to both create and remove pending requests
   (Opus 4.6 #1, Sonnet 4.6 #1/#2, Codex 5.3 #1)
5. Strengthen IsWorktreeInUse guard: also checks live non-hidden sessions
   by working directory path, not just organization metadata (Codex 5.3)
6. Kill orphaned gh process on CancellationToken fire (Sonnet 4.6 #1)

Deferred (pre-existing, out of scope):
- RepoManager state pollution with remote data (Gemini)
- Hardcoded PATH overwrite on non-Windows (Gemini, pre-existing)
- Server-side shared worktree guard (Gemini, defense-in-depth)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes from final review (Opus 4.6, Sonnet 4.6, Codex 5.3):

1. CRITICAL: IsWorktreeInUse always returned true due to debounced save
   - CloseSessionAsync triggers SaveActiveSessionsToDisk (2s debounce)
   - ReconcileOrganization reads stale file, keeps closed session metadata
   - IsWorktreeInUse now accepts excludeSession/excludeSessions params
   - CloseSessionAndDeleteWorktree passes just-closed session name
   - DeleteGroupAndWorktree collects group sessions before deletion

2. RemoveWorktree now runs in Task.Run (like CreateWorktree) to avoid
   blocking the WebSocket message pump during slow git operations

3. Cancel pending worktree create/remove RPCs on bridge disconnect
   to prevent 30s-2min hangs when connection drops mid-operation

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@PureWeen PureWeen merged commit eda75d0 into main Feb 23, 2026
@PureWeen PureWeen deleted the feat/mobile-worktree-sessions branch February 23, 2026 01:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant