fix(worktrees): stop surfacing prunable git worktrees as live workspaces#8409
fix(worktrees): stop surfacing prunable git worktrees as live workspaces#8409kaynansc wants to merge 1 commit into
Conversation
A worktree still registered in git but whose directory was deleted (git's `prunable` state) was enumerated as a normal workspace, producing repeated pty:spawn DaemonProtocolError / fs:readDir ENOENT loops and a blank pane. - Parse the `prunable` porcelain field (Git >= 2.36) in both the main and relay worktree-list parsers. - For Git < 2.36 (no `prunable` field), probe each linked worktree path for existence on the fallback line-block path, skipping locked registrations to mirror git's own prunable rules. - Omit prunable worktrees from the detected-workspace enumeration only; removal/cleanup flows keep seeing them. - Extend the real-binary compatibility contract with the 2.36 `prunable` boundary. Fixes stablyai#8389 Claude-Session: https://claude.ai/code/session_018Rg1Bpq4GGwmz613hq6RSD
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (14)
📝 WalkthroughWalkthroughGit worktree parsing now preserves 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
Fixes #8389.
A git worktree whose directory was deleted without
git worktree prune(git's prunable state) was still enumerated as a normal workspace. It rendered as a blank pane and produced a continuous stream ofpty:spawnDaemonProtocolError: Working directory "…" does not existandfs:readDirENOENTerrors.With this change, Orca honors git's own
prunablemarker:prunableporcelain field (git worktree list --porcelain, Git ≥ 2.36) in both the main-process and relay worktree-list parsers, keeping the reason string (prunableReason) alongside, mirroring howlocked/lockReasonare handled.prunablefield shares the 2.36 boundary withworktree list -z, so the existingworktree-list-zcapability fallback now also probes each linked worktree path for existence (bounded concurrency, following the sparse-checkout probe precedent). Locked registrations are never marked prunable, mirroring git's own prune semantics — Orca locks worktrees for active agent sessions, so this matters.buildDetectedGitWorktrees, feedingworktrees:list/worktrees:listAll). Removal, cleanup, and branch-availability flows list worktrees separately and still see prunable entries, sogit worktree remove/prune affordances keep working.Screenshots
Repro fixture: repo
payments-apiwith a live linked worktree (feature-live) and a stale registration (feature-stale) whose directory was deleted withoutgit worktree prune.Captured from a Playwright + Electron run against this branch (after) and against
main(before) with the same fixture. This is a behavior change (an entry is omitted), not a styling change, so light/dark rendering is unaffected.Testing
pnpm lintpnpm typecheckpnpm test(2717 files, 28,687 tests passing)pnpm buildNew regression coverage (all red on
main, green with the fix):parseWorktreeListprunable parsing (line and NUL-delimited porcelain) in both the main (src/main/git/worktree.test.ts) and relay (src/relay/git-handler-utils.test.ts) parsers.listWorktreesannotates a deleted-directory worktree as prunable (src/main/git/worktree-list-paths.test.ts).src/main/git/remove-worktree.test.ts).src/relay/git-handler-worktree-list.test.ts).worktrees:listAllomits prunable worktrees (src/main/ipc/worktrees.test.ts).src/shared/git-binary-compatibility.test.ts) with the 2.36prunableboundary, so the CI matrix (2.25.5 / 2.38.1 / 2.49.1) exercises both the porcelain field and the fallback expectation.Also validated end-to-end with a scratch Playwright + Electron spec (isolated userData profile): adding the fixture project on
mainsurfaces 3 workspaces including the stale one; on this branch it surfaces exactlymain+feature-live.AI Review Report
Reviewed with an AI coding agent along two axes (repo standards + issue spec) against
origin/main:translateWorktreePathhelper before the existence probe so WSL paths are stated via their Windows-accessible form. No shortcuts/labels/Electron platform surfaces touched.git.listWorktreeshandler carryprunablethrough tossh-git-provider, so SSH repos get the same filtering as local/WSL ones. The relay existence probe runs on the host that owns the filesystem, so plainstatis authoritative there.git --versionbranching), narrowisUnsupportedWorktreeListZErrorpredicate,GitCapabilityCachescoping, capability table updated indocs/reference/git-compatibility.md, CI contract extended.-zpath (git ≥ 2.36 suppliesprunablefor free). The existence probe only runs on the Git < 2.36 fallback branch, with bounded concurrency (8), following the existing sparse-checkout probe precedent.Findings applied from the review: introduced a dedicated
PRUNABLE_EXISTENCE_PROBE_CONCURRENCYconstant instead of reusing the sparse-checkout one, and trimmed new "Why:" comments to the repo's 1–2-line guideline. No unresolved findings.Security Audit
git worktree list --porcelainoutput (trusted local/remote git binary), not user-controlled strings; the reason text is stored as metadata only and never executed or interpolated into commands.fs.staton paths git itself reported; it does not follow user-supplied paths, does not delete or mutate anything, and treats onlyENOENTas a signal (other errors are ignored, preserving current behavior).Notes
prunable/prunableReasonfields.git worktree prune-style cleanup.X handle: @KaynanSampaio1