Skip to content

feat: git worktree isolation for split-view panes (COMP-1)#19

Merged
Wintersta7e merged 12 commits intomainfrom
feature/git-worktree-isolation
Mar 29, 2026
Merged

feat: git worktree isolation for split-view panes (COMP-1)#19
Wintersta7e merged 12 commits intomainfrom
feature/git-worktree-isolation

Conversation

@Wintersta7e
Copy link
Copy Markdown
Owner

Summary

  • Automatically isolates AI agents into git worktrees when two split-view panes target the same project
  • First pane gets the original repo path (primary), subsequent panes get isolated worktrees
  • Close flow: inspects for uncommitted/unmerged changes, prompts Keep/Discard/Cancel
  • Visual indicators: branch badge on pane topbar, "Worktree" in status bar

Architecture

  • git-port.ts — GitPort interface + WslGitPort (shells out via wsl.exe)
  • worktree-manager.ts — acquire/inspect/discard/keep/pruneOrphans + registry
  • ipc-worktree.ts — 5 IPC handlers (acquire, inspect, discard, keep, releasePrimary)
  • Renderer: spawn gating via worktree:acquire, close flow with ConfirmDialog

Security & Reliability

  • Path traversal prevention (SAFE_ID_RE validation + containment check)
  • baseOid validated as 40-char hex on registry load
  • MAX_WORKTREES=20 cap prevents unbounded creation
  • Async $HOME resolution (no main process blocking)
  • Primary slot released on close, worktree cleaned on restart
  • Cancel-during-acquire guard prevents orphaned worktrees

Thin abstraction over git operations needed for worktree isolation.
Exports parser functions and branch-name helpers for unit testing.
22 tests covering all parsers and helpers.

Co-Authored-By: Rooty
Covers all remaining WorktreeManager methods: inspect (hasChanges,
hasUnmerged, clean, unknown session), discard (success path,
pendingCleanup on removeWorktree failure, no-op for unknown),
keep (skips pruneOrphans), and pruneOrphans (no stale entries,
kept entry is skipped, pendingCleanup retry succeeds).

Co-Authored-By: Rooty
…rations

Registers worktree:acquire/inspect/discard/keep handlers in main process,
wires WorktreeManager into app.whenReady with pruneOrphans on startup,
and exposes the worktree API through preload + global.d.ts.

Co-Authored-By: Rooty
…d acquire

Add worktreePaths/setWorktreePath/clearWorktreePath to UiSlice for
per-session worktree tracking. TerminalPane now calls worktree.acquire
before pty.spawn for project sessions — bare terminals skip acquire and
spawn with projectPath directly. On acquire failure, falls back to the
original project path with a visible error. Worktree path is cleared
on session removal.

Co-Authored-By: Rooty
When closing a worktree-isolated session, inspect the worktree first.
If dirty (uncommitted changes or unmerged commits), show a 3-option
ConfirmDialog: Keep Branch, Discard, or Cancel. Clean worktrees are
discarded silently. Inspect failures fall back to normal close.

Extends ConfirmDialog with an optional extraAction prop for the third
button.

Co-Authored-By: Rooty
StatusBar shows a themed "Worktree" badge when any session has an
isolated worktree active. PaneTopbar shows a GitBranch icon + branch
short-name badge on sessions with an isolated worktree.

Co-Authored-By: Rooty
handleCloseTab was closing over a stale worktreePaths snapshot,
causing the close button to not recognize worktree sessions.
Now reads fresh state on every call.

Co-Authored-By: Rooty
… file

- Add worktree-manager.ts to git (was untracked)
- Convert Windows paths to WSL format in GitPort before git commands
- Split registry (Windows fs) from worktree dir (WSL-native)
- Resolve WSL $HOME dynamically instead of literal ~
- Use path.join (not path.posix) for registry on Windows

Co-Authored-By: Rooty
…1, WT-2)

- Add releasePrimary() to WorktreeManager — clears primary entry when
  primary session closes so next session gets primary (not worktree)
- Add worktree:releasePrimary IPC channel
- PaneTopbar restart handler discards worktree before swapping sessions
- App.tsx non-isolated close calls releasePrimary
- 3 new tests for releasePrimary

Co-Authored-By: Rooty
- Validate projectId/sessionId against SAFE_ID_RE in IPC handler (WT-3)
- Assert worktree path doesn't escape base directory (WT-3)
- Replace sync execFileSync with async execFile for $HOME (WT-5)
- Remove hardcoded /home/rooty fallback — disable isolation on fail (WT-4)
- Validate baseOid as 40-char hex on registry load (WT-6)
- Add MAX_WORKTREES=20 cap before creation (WT-7)

Co-Authored-By: Rooty
…ard (WT-9/10/11)

- keep() now removes worktree directory while preserving branch (WT-9)
- discard failure shows warning toast instead of silent swallow (WT-10)
- Cancel in-flight acquire discards worktree if already created (WT-11)
- WT-8/12/13 confirmed not-a-problem (no changes needed)

Co-Authored-By: Rooty
8 integration tests against real WSL git repos:
- 10 concurrent acquires (mutex, exactly 1 primary)
- 10 rapid acquire-discard cycles (no orphaned branches)
- Inspect uncommitted changes + committed-but-unmerged
- Keep preserves branch but removes dir
- MAX_WORKTREES cap enforcement
- releasePrimary re-election
- Non-git project graceful fallback

Also: add pruneWorktrees to GitPort, call between removeWorktree
and deleteBranch to unlock the branch ref.

Co-Authored-By: Rooty
@Wintersta7e Wintersta7e merged commit cbe2e3e into main Mar 29, 2026
1 check passed
@Wintersta7e Wintersta7e deleted the feature/git-worktree-isolation branch March 29, 2026 22:42
Wintersta7e added a commit that referenced this pull request Mar 30, 2026
Worktree isolation (PR #19) + cost/token tracking (PR #20).
614 tests.

Co-Authored-By: Rooty
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