Repository navigation
fix(worktrees): show CLI-created local worktrees in the sidebar while a remote runtime is active - #6628
Conversation
|
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 (5)
🚧 Files skipped from review as they are similar to previous changes (3)
📝 WalkthroughWalkthroughA 🚥 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 |
VerificationConcrete proof for the testing checklist above. Regression test catches the bug (before → after)The new test With the fix applied, it passes (routes to local, Full touched-suite run (with fix)Typecheck + lintThe pre-commit hook ( Not yet run
|
Visual before/after (autonomous headless E2E)Captured by a Playwright + Each run: create a control worktree (no runtime active), then activate a runtime and create a second worktree via the same CLI path. The only difference between the two images is this PR. Before (origin/main — the bug): the control worktree appears, but the worktree created while a runtime was active is missing from the sidebar. After (this PR — fixed): the runtime-active worktree now appears live, no restart. The spec is committed as a regression test ( |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: c50f1a6c-a5be-4242-9657-96570f437505
📥 Commits
Reviewing files that changed from the base of the PR and between 39b63e93392fb26fde4f971900ef611c77ebc82b and a6ef1f7d0303565f19565340db0548a3740a0c85.
📒 Files selected for processing (1)
tests/e2e/local-worktree-visibility-runtime-active.spec.ts
… runtime is active When a remote runtime is active, a local `worktrees:changed` event for an unbound repo was dropped by the renderer guard in useIpcEvents. Worktrees created outside Orca for that repo (e.g. `orca worktree create` from a CLI or automation flow) therefore stayed invisible in the sidebar until an app restart, even though their sessions were already running. The guard existed because an unbound repo's list fetch routes to the active runtime (settingsForKnownRepoOwner's unbound fall-through), so refreshing with local worktree ids could query — and purge against — the remote host. Instead of dropping the event, pin the refresh to the local host (forceLocalOwner): fetch the worktree list against the local owner and merge additively. The merge is host-scoped and the deletion-purge is skipped on this path, so it only ever adds local-host worktrees and never overwrites the active runtime's worktree state. A genuinely-removed local worktree is reclaimed by the next unguarded full refresh.
…untime is active Drives the real `orca worktree create` path: the CLI RuntimeClient calls `worktree.create` over the app's socket, registering a managed worktree and firing the `worktrees:changed` IPC the renderer listens for. Stages a remote runtime as active by injecting `activeRuntimeEnvironmentId` into the renderer store, so no real remote host is needed. Fails on the prior behavior (the worktree never appears while a runtime is active) and passes with this fix.
a6ef1f7 to
0a4c00d
Compare
|
Taking a look 👀 |
Co-authored-by: Orca <help@stably.ai>
…-active Resolve worktrees.ts fetchWorktrees conflict: keep upstream's getProjectHostSetupForRepoHost(setup) line alongside the forceLocalOwner list-fetch override.
|
Ready to review this PR? Stage has broken it down into 4 individual chapters for you:
Chapters generated by Stage for commit 7671a3f on Jun 30, 2026 8:32pm UTC. |
|
@brennanb2025 lmk if you have any questions |
…rktree-visibility-runtime-active # Conflicts: # src/renderer/src/hooks/useIpcEvents.ts # src/renderer/src/store/slices/worktree-helpers.ts # src/renderer/src/store/slices/worktrees.ts
|
Synced this branch with current Three conflicts, all in the exact area this PR touches:
Re-verified after the merge:
@brennanb2025 — following up since this has been open a few weeks; happy to answer anything if it helps get eyes on it. |
|
Really sorry for the delay! Got wrapped up in other stuff, thanks for the reminder here. 😓 |
…on runtime overlap
|
Reviewed in depth and pushed a few commits on top — the core approach here is right: pinning the refresh to the local owner instead of dropping the event keeps the remote-runtime protection intact while fixing the visibility gap. What we added during review:
Validation: typecheck/lint green, 298 unit tests across the touched suites, and the e2e spec passes on this branch while failing at exactly the target assertion with the old drop-guard restored — so the regression is genuinely guarded. Perf-audited: steady-state cost while a runtime is active now equals what the app always paid with no runtime active, with burst coalescing intact. Thanks @smk508 — clean fix for a real CLI/automation pain point. |
… a remote runtime is active (stablyai#6628) * fix(worktrees): refresh local worktrees in the sidebar while a remote runtime is active When a remote runtime is active, a local `worktrees:changed` event for an unbound repo was dropped by the renderer guard in useIpcEvents. Worktrees created outside Orca for that repo (e.g. `orca worktree create` from a CLI or automation flow) therefore stayed invisible in the sidebar until an app restart, even though their sessions were already running. The guard existed because an unbound repo's list fetch routes to the active runtime (settingsForKnownRepoOwner's unbound fall-through), so refreshing with local worktree ids could query — and purge against — the remote host. Instead of dropping the event, pin the refresh to the local host (forceLocalOwner): fetch the worktree list against the local owner and merge additively. The merge is host-scoped and the deletion-purge is skipped on this path, so it only ever adds local-host worktrees and never overwrites the active runtime's worktree state. A genuinely-removed local worktree is reclaimed by the next unguarded full refresh. * test(e2e): regression — CLI-created worktree visible while a remote runtime is active Drives the real `orca worktree create` path: the CLI RuntimeClient calls `worktree.create` over the app's socket, registering a managed worktree and firing the `worktrees:changed` IPC the renderer listens for. Stages a remote runtime as active by injecting `activeRuntimeEnvironmentId` into the renderer store, so no real remote host is needed. Fails on the prior behavior (the worktree never appears while a runtime is active) and passes with this fix. * fix(worktrees): pin local lineage refresh during runtime activity Co-authored-by: Orca <help@stably.ai> * review: trim comments to house style, normalize queue coalescing to booleans * review: sweep rename-grace expiry before early returns in worktrees:changed handler * review: document accepted workspace-space gap, drop imprecise 'additive' wording * fix(worktrees): route duplicate local repo events locally * fix(worktrees): tag local worktree events at origin, gate purge skip on runtime overlap * test: pin origin-based forceLocalOwner with a no-runtime local event assertion --------- Co-authored-by: brennanb2025 <brennankbenson@gmail.com> Co-authored-by: Orca <help@stably.ai> Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>


Summary
Worktrees created outside Orca for a local, unbound repo do not appear in the sidebar while a remote runtime is active — they only show up after an app restart, even though their sessions are already running. This is the common case for CLI/automation flows that call
orca worktree createagainst a local project while a remote runtime (SSH/runtime host) is focused.Root cause. The renderer's local
worktrees:changedhandler (useIpcEvents.ts) early-returns whenever any remote runtime is active:The guard is there for a real reason: an unbound repo's list fetch routes to the active runtime (
settingsForKnownRepoOwner's unbound fall-through), so refreshing with local worktree ids could query — and purge against — the remote host. But the cost is that all local worktree events are dropped, and there is no watcher/poller to recover them, so the only refresh is the authoritativegit worktree listscan on app restart (which also suspends running agents).Fix. Instead of dropping the event, pin the refresh to the local host (
forceLocalOwner):fetchWorktrees(repoId, { forceLocalOwner: true })lists the worktrees against the local owner (stripsactiveRuntimeEnvironmentIdfor the list fetch only), gated on a localhostIdso a repo genuinely bound to a runtime/SSH host is never force-listed locally.This touches only the renderer event path and the list-fetch owner resolution. It does not change
settingsForKnownRepoOwner(push-target / git-mutation routing is unchanged) or the IPC contract.Related prior art: #5104 / #6241 address externally-created worktrees in the no-runtime-active case; this PR is the distinct remote-runtime-active variant of the same visibility gap, which those changes leave intact (#6241 explicitly makes no renderer event-contract changes).
Screenshots
No new UI elements — the fix restores the sidebar rows that already exist for local worktrees. The change is behavioral (when the rows appear), so it is covered by unit regression tests rather than a static screenshot.
Manual repro (before this PR):
orca worktree create <local-repo> --agent ... --prompt ....Testing
pnpm lint(oxlint on the touched files; pre-commitlint-stagedran oxlint + react-doctor clean)pnpm typecheck(typecheck:web, clean)pnpm test(touched suites:worktrees.test.ts,worktree-change-refresh-queue.test.ts,useIpcEvents.test.ts— 237 passing; full suite not run locally)pnpm build(not run locally — change is confined to type-checked renderer code with no new build inputs)worktrees.test.ts→ "pins the list fetch to the local host when forceLocalOwner is set" (proves the routing fix: an unbound repo with a remote runtime active lists local instead of the runtime).worktree-change-refresh-queue.test.ts→ threadsforceLocalOwnerthrough the queue and does not coalesce a local-pinned refresh into a runtime-routed one.AI Review Report
Reviewed the diff for correctness, regression risk, and cross-platform behavior:
forceLocalOwneronly stripsactiveRuntimeEnvironmentIdwhenhostId === LOCAL_EXECUTION_HOST_ID, so a runtime/SSH-bound repo is never force-listed locally.settingsForKnownRepoOwner(push-target routing) is untouched — verified the existing "hydrates a missing linked GitHub PR push target through the active remote runtime" test still passes.mergeWorktreesForHostkeyed onhostId) and the repo-wide deletion-purge (getAuthoritativeDetectedWorktreeIds, not host-scoped) is skipped on theforceLocalOwnerpath, so a local-only scan cannot mis-read remote-host worktrees as deletions. Worst case is a deleted local worktree lingering until the next unguarded full refresh — strictly better than today's drop-everything.Security Audit
No new input handling, command execution, path handling, auth, secrets, or IPC surface.
forceLocalOwneris computed renderer-side from existing app state (isRuntimeEnvironmentActive()); theworktrees:changedIPC payload is unchanged. No dependency changes. No follow-up security work identified.Notes