Toggle any pane wherever you put it, and keep the header hidden - #75848
Merged
Conversation
Dragging the terminal to the bottom stacks logs into its zone, and every tool-panel toggle broke in that stack. Boot revealed instead of leaving the tree alone: bindPaneCollapse ran setPaneCollapsed(id, !open), and `false` there fronts the pane. Logs binds last, so it stole the active tab from the persisted tree. Ctrl-` then asked to collapse a terminal that was no longer the active tab, the shared-zone branch declined by design, and the key did nothing until the stack was broken up. Boot now only ever collapses. The toggles also asked the wrong question. !$terminalTakeover.get() flips a boolean that has no idea what is on screen, so once anything else moved the pane the press spent itself re-asserting a value the store already held. toggleToolPane derives from the tree instead, and ctrl-`, Cmd+J's terminal fallback, the statusbar button and the logs palette row all route through it. The terminal cycle/close keys drop the same stale boolean. bindPaneCollapse moves into the tree store as bindToolPaneCollapse so the boot rule is testable against the real function rather than a copy.
Two independent clobbers threw the choice away, so "hide header" never survived a close/reopen cycle. normalize() deleted headerHidden whenever a zone dropped to one pane, on the grounds that a lone zone is headerless by default. It is — but the flag is the user's standing preference for that zone, not a redundant value, and dropping it meant the bar returned the moment a pane rejoined (close the stacked logs pane, toggle it back). Re-adoption then pinned headerHidden false unconditionally. That is right for a pane arriving somewhere new, where zero chrome leaves no handle to drag or close, and wrong for a zone whose bar the user deliberately hid. Adoption now carries the destination zone's own setting, read before the insert since insertAtGroup pins the flag itself on a center drop.
The terminal and logs carried a 7.5rem minHeight, so dragging the seam down jammed against a floor with a sliver of unusable terminal still showing. Tool-panel zones now floor at COLLAPSED_ZONE_PX (the h-7 header strip) instead of the generic 80px, and releasing at that floor minimizes the zone rather than persisting the sliver — it folds to its collapsed header, vertical rail or horizontal strip depending on the parent axis. The sliver size is never written, so restoring returns the height it had before.
Contributor
૮ >ﻌ< ა ci reviewran on feaa325 ℹ️ InfoDesktop E2E visual evidence · View test artifacts · View job3 visual diffs. inline evidence is publishing... |
The terminal fix was only one instance. An audit of the other pane toggles found ⌘G and ⌘J diverging the same way, proven with a probe: with review stacked behind files in the right column, or either pane inside a minimized zone, the store reads open while nothing is on screen, so the press re-asserts a value it already held and the key does nothing. isPaneVisible / togglePaneVisible replace the tool-panel-only pair and now back every toggle. Close still routes through closeTreePane, so each pane keeps its own semantics: a tool panel collapses to its rail, files and review close through their store, anything else is dismissed. files and review were bound with a closer and no opener, so the boolean went stale as soon as anything but the toggle revealed them. bindPaneVisibility moves into the tree store beside bindToolPaneCollapse, documents the two as a pair, and both panes now pass both halves. Keeping the binding in the store also means the tests drive the real function — the earlier copy in the test file passed with the fix reverted, which is how the missing opener survived the first pass. setTreePaneHidden keeps its quiet path: a reactive unhide (a cwd arriving) must not front or un-minimize over what the user is looking at. Only user intent goes through the reveal path.
main reworked the same surface while this was open, so three hunks needed deciding rather than accepting. Logs became summon-only (#75862): the contribution only exists while $logsOpen is on, docked as its OWN zone beside the terminal instead of a tab in its strip. That supersedes the static logs pane and the bindToolPaneCollapse call here — main already registers logs' closer/opener directly, so both were dropped in favour of its version. main also added a ⌘K "Toggle terminal" row reading $terminalTakeover, and gave logs back a 7.5rem minHeight under a comment claiming the terminal's sizing rule. Both are the bugs this branch fixes, so they move onto the shared behaviour: the palette row reads isPaneVisible/togglePaneVisible like every other pane toggle, and logs loses the floor so the comment is true — the sash folds its zone to the rail instead of stranding a sliver.
OutThisLife
enabled auto-merge
August 1, 2026 06:26
1 task
1 task
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…minal-persist Toggle any pane wherever you put it, and keep the header hidden
13 tasks
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.
Dragging the terminal to the bottom stacks logs into its zone, and every tool-panel toggle broke in that stack — ⌃`, the statusbar button, ⌘J's terminal fallback. A lone terminal never reproduced it, which is why it read as randomly broken: it worked again only after closing the terminal from its own tab, because that broke the stack up.
Auditing the rest of the toggles found the same divergence on ⌘G and ⌘J, so this fixes the class rather than the one key.
The toggles asked a boolean, not the tree
!$terminalTakeover.get()flips a value with no idea what's on screen. Once anything else moved the pane — stacked behind a sibling tab, minimized from the zone menu, closed with ⌘W — the store said "open" while nothing was visible, and the press spent itself re-asserting a value it already held.A probe confirmed it was never terminal-specific. With review stacked behind files in the right column, or either pane inside a minimized zone, ⌘G and ⌘J were dead in exactly the same way.
isPaneVisible/togglePaneVisiblenow back every toggle. Close still routes throughcloseTreePane, so each pane keeps its own semantics: a tool panel collapses to its rail, files and review close through their store, anything else is dismissed.setTreePaneHiddenkeeps its quiet path — a reactive unhide (a cwd arriving) must not front or un-minimize over what the user is looking at. Only user intent takes the reveal path.files and review had a closer and no opener
So their booleans went stale the moment anything but the toggle revealed them.
bindPaneVisibilitymoves into the tree store besidebindToolPaneCollapse, documents the two as a pair, and both panes now pass both halves.Boot revealed instead of leaving the tree alone
bindPaneCollapseransetPaneCollapsed(id, !open), andfalsethere fronts the pane. Logs binds last, so it stole the active tab from the persisted tree. ⌃` then asked to collapse a terminal that was no longer active — the shared-zone branch declines that by design — so the first press did nothing. Boot now only ever collapses; the persisted tree already records which tab was active."Hide header" had two independent clobbers
normalize()deletedheaderHiddenwhenever a zone dropped to one pane — a lone zone is headerless by default, so the flag looked redundant. It isn't: it's the user's standing preference for that zone, and dropping it brought the bar back the moment a pane rejoined. Re-adoption then pinnedheaderHidden: falseunconditionally, which is right for a pane arriving somewhere new and wrong for a zone whose bar was deliberately hidden. Adoption now carries the destination zone's own setting, read before the insert sinceinsertAtGrouppins the flag itself on a center drop.Min-height
The terminal and logs carried a
7.5remfloor, so dragging the seam down jammed with a sliver of unusable terminal showing. Tool-panel zones now floor at theh-7header strip, and releasing there minimizes the zone — it folds to its collapsed header, vertical rail or horizontal strip depending on the parent axis. The sliver size is never written, so restoring returns the previous height.Verification
Eleven regression tests across the two toggle classes, all driven through the real bindings. Reverting the fixes turns them red — including the ⌃`-is-a-dead-key case and the missing opener.
That last one is worth calling out: the tests originally kept a local copy of each binding, and passed with the fix reverted. Both bindings moved into the store so the tests exercise production code, which is what caught the missing
files/reviewopener at all.1164 tests pass across
pane-shell,app/chat,app/shell,storeandapp/contrib; eslint clean on the changed files.