Repository navigation
Conversation
RegisterSession took the session's index in SessionManager.Sessions and inserted at that index in MainViewModel.Sessions. Those are different index spaces: the model also holds dormant sessions and ones the restore loop hasn't launched yet. Restart and wake re-insert a VM whose sidebar row never moved, so the pane drifted one slot down per such session above it — often all the way to the end of the grid. Insert after the live sessions that precede it in the model instead. The rule lives in the WPF-free SessionOrder so it is unit-tested; five of the seven new tests fail against the previous logic. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR #159 fixed the same RegisterSession index-space bug with its own SessionOrder.LiveInsertIndex; this branch fixes it with InsertionIndex. Its six placement cases (dormant above, first/last, several dormant, restore in progress, nothing dormant) pass unchanged against InsertionIndex, so #159 can close without losing its coverage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX
|
Closing as superseded by #173. Both fix the same Your six placement cases (dormant above, first/last, several dormant, restore in progress, nothing dormant) are carried over unchanged as 🤖 Generated with Claude Code |
…st (#173) * fix(sidebar): drag-and-drop lands where you drop, and shows where first Reported as "the session doesn't land where I want it, and it's hard to know where it actually lands", most noticeably with groups and a PS session next to a Claude one. A faithful simulation of the old code reproduced it in 7 of 7 scenarios. There was not one cause but five, and one more mechanism that undid even correct drops. The drop was resolved to an INDEX, computed in one list and applied to two others that hold different sessions: 1. The index counted the visible rows, so a "⎇ repo (N)" worktree cluster header shifted it by one. 2. In FilterStrip mode it was an index into the FILTERED rows, applied to SessionManager's full list (every group): dropping into the middle of a group put the session at the top. 3. In inline-headers mode it was a _vm.Sessions index (live only), applied to SessionManager (live + dormant): a sleeping session above the target moved the drop. 4. The same index moved both lists, so the pane grid and the sidebar went out of step. 5. Remove-then-insert at the pre-removal index made every downward move overshoot by one. A drop now resolves to an anchor ("before session X" / "after session Y"), which is the same slot in every list. The logic is in a new WPF-free SidebarDropResolver, fed the rows as actually rendered. SessionManager.MoveSessionRelative finds the anchor after removing the moved session, and the index-based MoveSession is gone from both SessionManager and MainViewModel so the pattern can't come back. The grid is re-aligned to the sidebar order (SessionOrder.AlignTo) instead of moved by the same index, and RegisterSession inserts a woken or restarted session by relative position for the same reason. Then the part that made "PS and Claude" worse: "Open PowerShell here" creates a session in the same repo, so it counts as a worktree sibling, and ApplyClusteredOrder re-sorted EVERY sibling on any Add/Remove and whenever a repo root resolved, i.e. on every restore. A PS session dragged away from its Claude session snapped back the next time anything opened or closed, and the saved order was rewritten on every launch. It also moved SessionManager by a _vm.Sessions index (cause 3 again). It is replaced by PlaceNewSessionsInClusters: only sessions launched with restoring: false are placed, once, when their root resolves, and a drag removes a session from that set. New PS sessions still appear beside their Claude session; after that, the user's order wins. Behaviour change: siblings the user has separated are no longer pulled back together. "Hard to know where it lands": while dragging, a blue insertion line (Views/InsertionLineAdorner) shows the slot. It is computed from the same resolved target the drop applies, so it cannot disagree with the drop. It hides over group headers, which highlight themselves instead. Dropping on an inline group header now lands the session at the top of that group, rather than wherever its old global position fell among the new group's members. Tests: SidebarDropResolverTests and SessionOrderTests, plus SidebarReorderScenarioTests, which runs scenarios 1-6 end-to-end through the real SessionManager, the resolver and the grid alignment. Re-introducing the overshoot, or a grid that doesn't follow the sidebar, makes 4 tests fail each. Scenario 7 (restore) is enforced by the restoring: false gate in LaunchSessionAsync, which unit tests can't reach. Not yet tested manually. CLAUDE.md gains a "Sidebar order and drag-and-drop" section recording why no index may cross between the lists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX * test(sidebar): carry over #159's restart/wake placement cases PR #159 fixed the same RegisterSession index-space bug with its own SessionOrder.LiveInsertIndex; this branch fixes it with InsertionIndex. Its six placement cases (dormant above, first/last, several dormant, restore in progress, nothing dormant) pass unchanged against InsertionIndex, so #159 can close without losing its coverage. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NsYm9iLc2aRnRDfV2uZRQX --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Problem
After ↻ Restart (and also after waking a 💤 session), the pane sometimes jumps to the end of the terminal grid while its sidebar row stays where it was.
Root cause
MainViewModel.RegisterSessiondecides where a freshly launched session's VM goes. It found the session's index inSessionManager.Sessionsand inserted at that same index inMainViewModel.Sessions. Those are different index spaces:SessionManager.Sessionsholds live and dormant sessions, plus sessions the restore loop hasn't launched yet.MainViewModel.Sessionsholds only live sessions.Restart and wake re-insert a VM whose sidebar row never moved. The pane therefore landed one slot too far down for every dormant or not-yet-live session above it. When that ran past the end of the list, it was appended last.
Example: sidebar
A, 💤D, B, C. Restart B → its model index is 2 and the live list is[A, C]→Insert(2)→[A, C, B].With no dormant sessions the two index spaces coincide, which is why it was intermittent.
Fix
Insert after the live sessions that precede it in the model order. This lives in the new WPF-free
Services/SessionOrder.LiveInsertIndex, so it is unit-tested.The same code path also fixes wake and insert-after-parent (duplicate/worktree) when a dormant session sits above.
Tests
SessionOrderTests(7 cases: dormant above, first/last, several dormant, restore-in-progress, no dormant, unknown id).CodeShellManager.Tests: 619/619 passing (Release).Not in scope
#131's broader divergence: group sectioning that only the sidebar applies, and drag-drop index spaces. This PR fixes only the re-insert case.
🤖 Generated with Claude Code