Repository navigation
Conversation
The dialog resolved its repo with a bare id and called updateRepo without a host. When one repo id exists on several hosts that reads whichever row matches first, so the dialog can show one host's visibility state and write the toggle to another host's row. The menu that opens it already has the full Repo in hand, so carry that host through the modal and into updateRepo — the same identity updateRepo already documents for ids that exist on multiple hosts. The host stays optional: the inbox-recovery caller only has a bare id, and that path keeps its current first-match behaviour rather than opening an empty dialog. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012ZcrKK54K7sRnSkT6a6Jut
📝 WalkthroughWalkthroughThe worktree list now passes an optional execution host ID when opening the visibility dialog. The dialog normalizes host identity, resolves repositories using settings, and preserves an ID-only fallback for host-less callers. Visibility updates now include the resolved host context. Tests cover repositories with shared IDs across hosts and host-less modal payloads. 🚥 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/renderer/src/components/sidebar/worktree-visibility-host-identity.test.tsx (1)
84-88: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAssert the host-less fallback visibility value.
The first matching fixture has
externalWorktreeVisibility: 'hide'. The fallback must therefore write'show'.expect.objectContaining({})accepts either value and cannot detect a changed repository selection.Proposed test update
expect(storeState.updateRepo).toHaveBeenCalledWith( 'repo-1', - expect.objectContaining({}), + expect.objectContaining({ externalWorktreeVisibility: 'show' }), undefined )
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 09eae381-7d26-4892-97fd-d91b25da591b
📒 Files selected for processing (3)
src/renderer/src/components/sidebar/WorktreeList.tsxsrc/renderer/src/components/sidebar/WorktreeVisibilityDialog.tsxsrc/renderer/src/components/sidebar/worktree-visibility-host-identity.test.tsx
|
Closing this as superseded by the host-scoped visibility work merged in #13652. Current main resolves the dialog target with |
Same defect class as #13071 (P1), in a different flow. No separate issue filed — happy to open one if you'd rather track it on its own.
Summary
The worktree-visibility toggle could show you one host's state and write the change to another host's project.
WorktreeVisibilityDialogresolves its repo with a bare id and then mutates without a host:updateRepo's own signature documents why that matters:So when one repo id exists on two hosts (two clones of a remote, the same repo added twice, local + SSH copies), the dialog reads whichever row matches first and writes to whichever row
updateRepoassumes. Those need not be the same row, and neither need be the one the user opened the menu on.RepositoryPane.tsx:93already passes{ hostId: selectedHostId }for exactly this reason, so the correct pattern is established in-tree.What changed
The menu that opens the dialog already has the full
Repo:Carry it through the modal data into
updateRepo, and resolve the row withfindRepoForHostso the dialog reads the same row it writes. The host is narrowed withnormalizeExecutionHostIdrather than cast.Screenshots
No visual change. The only user-visible difference is that the dialog now reflects the project you opened it on.
Testing
pnpm lintpnpm typecheckpnpm test— scoped to the touched tree, not the full suite (see below)pnpm buildpnpm typecheckandoxlintpass; 2011 tests acrosssrc/renderer/src/components/sidebar/pass. I ran the scoped suites rather than a fullpnpm buildon this branch — it is renderer-only identity plumbing with no packaging, dependency or main-process surface. Glad to run the full build if you want it on the record.New
worktree-visibility-host-identity.test.tsxrenders the real dialog with one repo id on two hosts and clicks the toggle:updateRepois called with{ hostId: 'ssh:host-a' }and the value derived from host A's stateupdateRepowith no host optionVerified non-blind: reverting the plumbing fails the first test while the second keeps passing — it pins the unchanged host-less path, so the pair distinguishes the fix from its absence rather than just exercising the component.
Note the dialog renders through a Radix portal, so
renderToStaticMarkupsees nothing; the test uses@testing-library/reactunderhappy-dom, matching the existingSelectedTextCopyMenutest.AI Review Report
Reviewed with Claude Opus 5 against the CONTRIBUTING checklist.
ssh:<target>.updateRepo's existing per-host RPC targeting is unchanged, it simply receives the host the user meant. No wire change.isGitRepoKind, unchanged.What it flagged and I acted on: making the host mandatory looked cleaner, but the review caught that the inbox-recovery caller (
onOpenRecovery) only has a bare id, andfindRepoForHostreturnsnullfor an ambiguous bare id by design — that path would have become a menu item that opens an empty dialog. The resolve now falls back to the previous first-match when no host is supplied. My own test caught the same thing independently, which is why the host-less case is pinned.Security Audit
Reviewed for input handling, command execution, path handling, auth, secrets, dependency and IPC risk.
normalizeExecutionHostId, not cast, so a malformed value falls back instead of propagating into an RPC target.updateRepo's existing channel and its already-validatedhostIdparameter are unchanged; this only populates a parameter that was already there.No follow-up needed.
Notes
This is the third site in the same family. #13117 covers the removal flow from #13071 (three sidebar sites plus the orphan purge in
worktrees.ts); this one covers the visibility toggle. A fourth remains —selectProjectGroupRemovalTargetsdiscards the host when building group-removal targets — which I left alone because it changes a shared selector's shape and its callers. Happy to take that one too if it is wanted.X: @manuaudiomix