Repository navigation
feat(sidebar): consolidate same-branch workspaces across hosts - #14
Merged
Merged
Conversation
Add a Workspace options setting, "Group by branch" (on by default, shown only in Project grouping), that merges workspaces in one project which sit on the same git branch on two or more hosts into a single card. The merged card carries a host dropdown in line with the title, one row per host. Picking a host swaps which workspace backs the card — status, branch, PR, agents, tabs and activation all follow it — and until the user picks one, the card follows the active workspace. There is no cross-host aggregation: a consolidated card always shows exactly one host. Only a branch that maps to exactly one worktree per host and spans at least two hosts is merged; pinned, lineage, detached-HEAD and single-host rows are left untouched, so turning the setting off restores today's list. The host choice lives in an in-memory branchGroupHostByKey slice field so it survives sidebar virtualization, and the branch-group derivation is shared between the sidebar merge and the card so the two cannot disagree.
7 of 9 tasks
nplez1
pushed a commit
that referenced
this pull request
Oct 30, 2026
…tablyai#32355) (stablyai#36031) * fix(native-chat): keep a huge unbroken paste from freezing the chat A long run with no whitespace ("xxxx…", "0000…", "abab…") wrapped with kerning makes Chromium reshape it at every line, quadratic in run length: 128 KiB stalls 2.4 s, 1 MiB 19 s, 5 MiB never finishes. ProseMirror forces that layout on paste and on each keystroke, so the composer freezes in every terminal-backed chat, including paired servers and WSL. A sent message stalls the transcript the same way: its fold clips the text but still lays it all out (128 KiB: 2.5 s). Runs over 256 characters now render with font-kerning: none, so prose of any length and Shift+Enter lines keep kerning: - composer: inline decorations, updated only for the lines a transaction touches (a keystroke beside 8,000 decorated lines ~1 ms, not ~190 ms) - user messages in the transcript and expanded queued cards: the whole text when it holds such a run Text, drafts and what is sent are unchanged. After: 1 MiB single line 84 ms, 5 MiB 312 ms (keystroke 248 ms), 1 MiB of 4000-char lines 50 ms (was 2.3 s), transcript 128 KiB 80 ms. Worst case left kerned, 256-char runs: 1 MiB 242 ms, 5 MiB 1.2 s, like 1 MiB of short lines (291 ms). Fixes stablyai#32355 Co-authored-by: Manan Chataut <mananchataut@gmail.com> * fix(native-chat): keep kerning on long CJK and Thai paragraphs These scripts have no spaces but Chromium can break between their characters, so a long paragraph is not one unbreakable run. Count ideographs, kana, Hangul and Thai as break opportunities so such text keeps kerning. Co-authored-by: Manan Chataut <mananchataut@gmail.com> * fix(native-chat): rescan only the edited run, and wait out IME compositions Splitting one run inside a block of thousands replaced every decoration in that block, and ProseMirror's removal is quadratic: 1,411 ms for one space in a paragraph of 8,000 long runs. A change now rescans only from the run edge before it to the run edge after it, and removes only the decorations that overlap: ~1 ms for the same edit. Decorations are only mapped while an IME composition is in progress, so the composing text node is not re-rendered. The deferred range is rescanned with the next non-composing change, or on compositionend when none follows. The keystroke-timing test is replaced by deterministic ones: unaffected decorations are reused and the result equals a full scan; a composition defers the rescan and compositionend runs it. Co-authored-by: Manan Chataut <mananchataut@gmail.com> * fix(native-chat): never split a CJK code point, and treat NBSP as glue A supplementary ideograph (U+20000-U+3FFFF) broke a run at its high surrogate only, so the decoration began on the low surrogate and split the pair across elements. Both the run scan and the leftward edge scan now treat the pair as one break. NBSP joins words for Chromium's line breaker (UAX #14 class GL), so an NBSP-joined paste is one unbreakable run and must lose kerning; drop it from the break set. No other non-breaking characters were in it. Drop a composer test whose coverage the decoration reuse test already has. Co-authored-by: Manan Chataut <mananchataut@gmail.com> * fix(native-chat): classify surrogate pairs whole at a rescan's edge Two lone-surrogate edge cases made the incremental rescan disagree with a full scan: - an edit completing a pair at the window start (a lone high surrogate, then a pasted low surrogate and run) began the decoration on the low surrogate; the window now widens past the whole pair - a lone low surrogate after any break counted as a pair end, dropping it from the run; that now requires a preceding high surrogate A seeded fuzz also found inclusive decoration edges mapping across a joined block's boundary, where ProseMirror cannot remove them; the decorations are no longer inclusive. Co-authored-by: Manan Chataut <mananchataut@gmail.com> --------- Co-authored-by: Manan Chataut <mananchataut@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ELI5
If the same project is checked out on two computers and both have a workspace on the same git branch, Orca used to show two separate cards in the sidebar. With the new "Group by branch" setting (on by default), those become one card with a small dropdown to switch between the computers.
What Changed
Before: workspaces from one project on two hosts rendered as one card per host. When a project spanned hosts, each card carried a host chip, but nothing tied the two same-branch cards together.
After: in Project grouping, workspaces in one project that sit on the same branch on two or more hosts render as a single card. The card header has a host dropdown (one row per host, local first). Selecting a host swaps which workspace backs the card — status, branch, PR, agents, tabs and activation all follow it. Until the user picks one, the card follows whichever host is currently active. A new Workspace options checkbox, "Group by branch", controls this; it appears only in Project grouping, is on by default, and turning it off restores today's list exactly.
Mechanism:
mergeSameBranchRows) collapses depth-0, non-lineage rows in the same project section that share a branch, but only when the branch maps to exactly one worktree per host and spans at least two hosts. If a host has two checkouts of the branch, the whole branch is left unmerged rather than hiding one behind the dropdown.branchGroup(host-ordered members) and a stablebranchGroupKey. The card renders the selected member's worktree, so every existing per-worktree behavior — activation, agent rows, tabs, context menu — works unchanged.branchGroupHostByKeyslice field keyed by the branch-group key, so it survives sidebar virtualization. It is deliberately not persisted.getBranchGroupKeyForWorktree/getBranchGroupMembersForWorktree) is shared, so the sidebar merge and the card cannot disagree.Why
The alternatives were a per-host selector on every card regardless of grouping, or a separate "grouped" view. Merging only when the branch is unambiguous (one checkout per host) and only in Project grouping keeps the change local to the row model and the card, and makes the setting a pure presentation toggle with no data migration.
Cross-host aggregation on a single card — showing every host's agents or tabs at once — was explored and deliberately dropped. It requires a cross-host tab model the tab store does not have (
unifiedTabsByWorktreeis keyed by bareworktreeId, and host resolution ignorestab.executionHostId), so it is a separate, much larger change. None of that work is in this PR.Linked Issue
nplez1/orcahas GitHub Issues disabled, so there is no issue to link and none was requested upstream. This is a fork-only enhancement.Visual Proof
Not attached. Reproducing the merged card needs the same project checked out on two hosts, and this environment has no multi-host fixture and no Orca Electron CDP capture tooling. A real-Radix render test listed under Testing exercises the dropdown opening in a portal; a before/after capture should be added by a reviewer who has two hosts configured.
Testing
pnpm tc,pnpm lint, the changed-code quality gate,pnpm run build:electron-vite, andverify:localization-extractionall pass.branch-groups.test.ts), the host dropdown against mocked and real Radix primitives (twoWorktreeBranchHostSelecttests), hydration defaults (ui-hydration-view-layout.test.ts), the persisted-UI write baseline, and the reveal lookup for a merged row.Platforms: verified on macOS only (typecheck, tests, lint, build). No platform-specific code was added; the change is renderer-only and host-agnostic.
AI Disclosure
Implemented by an AI coding agent (pi, model deepseek-flash) on behalf of the fork author.
Review
Agent skill upstream boundary
docs/reference/agent-skill-sharing-upstream-boundary.mdand copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.Notes
mergeSameBranch,WorktreeBranchHostSelect.label) will need coverage when the translation pipeline next runs.Checklist
pnpm lint,pnpm typecheck, andpnpm testpass (build covered bybuild:electron-vite)