feat(app): pin worktrees to the top of the sidebar
Merged
JO
2d ago+256+256+012345678901234567890123456789-15-15-01234567890123456789
The sidebar gets long once a few projects have many worktrees. You can now pin the ones you keep coming back to, and they sit at the top.
What changes
- Pin to top in a worktree's right-click or ⋯ menu moves it into a Pinned list above the projects.
- Pinned worktrees are listed in the order you pinned them. Each row shows its project name, plus its box chip when you have more than one box.
- It leaves its project's list while pinned, so it isn't shown twice. Worktrees handed off from it stay nested under the project.
- Unpin puts it back. Archiving or removing a worktree drops its pin.
- Pins are kept on this computer (
berth.pinnedWorktreesin localStorage), by box and path. Another window's changes are picked up through thestorageevent.
Screenshots
| Before | Menu | Pinned |
|---|---|---|
![]() | ![]() | ![]() |
![]() | ![]() | ![]() |
Code
app/src/lib/pinned-worktrees.ts: the pin store, pluspinnedFirst, which puts rows in pin order.app/src/components/sidebar/projects.tsx:PinnedWorktreesabove both groupings (project and box).useRepoTreeanduseProjectTreeleave pinned rows out of their project, with a newpinnedApartargument. The two-column and rail layouts (columns.tsx,rail-layout.tsx) passfalse, because they have no Pinned list.WorktreeRowgets an optionalprojectlabel.app/src/components/sidebar/actions.tsx: the Pin to top / Unpin items.app/src/lib/remove-worktree.ts: the pin goes once the box says the worktree went (removeWorktreeOnBoxandworktreeGone), so a failed archive keeps it.
Checks
- After merging
main:pnpm typecheck:plugins,check:titles,check:csp,pnpm test(604 pass, including the newpinned-worktrees.test.ts),pnpm build,npx tsc -p e2eand the docs build all pass. - Browser tests: every
sidebar-*.spec.ts, plus the layout specs that use the sidebar (93 tests). All pass except 3 that fail the same way on a cleanmain:sidebar-fleet.spec.ts"300 worktrees…" and "projects fold and open…" (expected 310 rows, got 322), andsidebar-quiet.spec.ts.sidebar-pinned.spec.tscovers pinning, its order, a reload, unpinning, and the pin going when its worktree is removed. - I didn't run the Go or cargo checks because no Go or Rust code changed.
Not in this PR
- Dragging to reorder pins.
- Pinning a project's main checkout.
🤖 Generated with Claude Code





