feat(desktop): worktree-aware sidebar grouping + composer/sidebar UX fixes#45273
Merged
Conversation
…fixes Group recents as parent-repo → worktree → sessions using local git metadata (probed over IPC, with a path-name heuristic fallback for remote backends). Single-worktree repos collapse to one level. Sessions order by creation time and never reshuffle on new messages. Also: fuse the status stack to the composer border, restore icon actions in the queue panel, fix sidebar label truncation and drag styling, hide sticky-message attachments while pinned, and bump the terminal font.
Contributor
🔎 Lint report:
|
| Rule | Count |
|---|---|
invalid-assignment |
1 |
First entries
tests/run_agent/test_credits_notices_toggle.py:76: [invalid-assignment] invalid-assignment: Object of type `None` is not assignable to attribute `_credits_session_start_micros` of type `int`
✅ Fixed issues (2):
| Rule | Count |
|---|---|
unresolved-attribute |
2 |
First entries
run_agent.py:2891: [unresolved-attribute] unresolved-attribute: Object of type `Self@get_credits_spent_micros` has no attribute `_credits_session_start_micros`
tests/run_agent/test_credits_notices_toggle.py:76: [unresolved-attribute] unresolved-attribute: Unresolved attribute `_credits_session_start_micros` on type `AIAgent`
Unchanged: 5704 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
Mirror the session row: the repo/worktree header's leading glyph (repo mark, or a new git-branch mark for worktrees) swaps to a grabber on hover/drag instead of carrying a separate handle on the right — freeing header width for the label and + button.
… rows The repo and worktree header rows were ~identical after the handle move. Fold them into one WorkspaceHeader (emphasis flag for the repo level) plus a small WorkspaceAddButton, so the toggle/handle/count/+ wiring lives in one place.
…rderableList Every reorderable surface (repos, worktrees, sessions, pins) now drops in a single ReorderableList that owns its own DndContext, so a drag only ever collides with that list's own items — nesting "just works" without leaking into the lists around or inside it. This replaces the shared DndContext + id-prefix dispatch (parent:/group:) whose closestCenter collisions resolved to a different-typed droppable and silently no-op'd worktree/repo drags. - Delete groupDndId/parentDndId/parse* helpers and the monolithic handleAgentDragEnd/handlePinnedDragEnd; each list persists its new id order via a direct typed write (reorderParents/reorderWorktree/reorderSessions/ reorderPinned). - Sessions inside repos/worktrees are date-ordered and static (no drag), matching the "never reorder on new messages" rule. - Add setPinnedSessionOrder; drop now-unused reorderPinnedSession.
The terminal looked soft/heavy on every platform because the xterm Terminal was built with allowTransparency: true, which drops the WebGL renderer's opaque fast-path and bakes glyphs as grayscale-alpha coverage for compositing over a see-through canvas. Our surface (--ui-bg-chrome) is opaque and withSurface already paints it, so transparency was pure blur for no benefit — VS Code keeps it off too. Also drop the Medium (500) base weight for normal/bold (400/700) to match VS Code's metrics, and remove the now-unused JetBrains Mono Medium face + woff2.
…idebar-workspace-dedup
…w user bubble Streaming auto-follow chased content growth while parked at the bottom, which rubber-banded — the tail pin and the virtualizer's own measurement adjustments fought for scrollTop. Drop it; the one-time new-turn jump already lands a fresh message in view and the viewport stays put after. Attachments rendered inside the editable user bubble and were collapsed via an IntersectionObserver + [data-stuck] CSS hack while the bubble was pinned. Render them as a flow sibling BELOW the sticky bubble instead, so they scroll away behind it naturally — no observer, no collapse. Image refs still render as thumbnails, file refs as chips; no border. Removes the now-unused useStuckToTop hook and its CSS.
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.
Summary
Reworks desktop recents grouping and fixes a batch of composer/sidebar/thread UX papercuts.
Worktree-aware grouping — recents now nest as
parent repo → worktree → sessions. Git identity is probed locally over a newhermes:fs:worktreesIPC (reads.gitmetadata directly, dedup'd per cwd), so the main checkout and its linked worktrees collapse under one repo regardless of directory naming. Unresolved cwds (remote backends, non-git dirs) fall back to a path-name heuristic. A repo with a single worktree collapses to one level instead of showing a redundant header.Stable session order — rows order by creation time (
started_at) and never reshuffle when a new message lands. New repos/worktrees surface at the top; vanished ones drop out of the persisted order.Main-checkout labeling — the main worktree is labeled by its directory, not its transient current branch (which would misattribute past sessions to whatever's checked out now). Linked worktrees keep their branch label.
Generic drag-reorder — every sidebar list (repos, worktrees, sessions, pinned) reorders through one nesting-safe
ReorderableListthat owns its ownDndContext, so collision detection can't cross levels. Drag handle replaces the leading icon; dragged rows are opaque, unscaled, shadowless, and vertical-only.Thread fixes
scrollTop. The one-time new-turn jump still lands a fresh message in view; the viewport stays put after.[data-stuck]collapse hack. Image refs stay thumbnails, file refs stay chips; no border.Terminal
allowTransparencywas forcing the WebGL renderer off its opaque fast-path (grayscale-alpha glyphs → soft on every platform). VS Code keeps it off; our surface is opaque anyway. Base weight back tonormal/bold(was Medium); dropped the now-unused Medium face + woff2.Other fixes
grid-cols-[minmax(0,1fr)]) so+/drag controls stay reachable.Test plan
npm run typecheck(clean)npx vitest run src/app/chat/sidebar/workspace-groups.test.ts(heuristic + git-authoritative grouping, disambiguation, main-checkout labeling)