Unify the preview rail onto one tab list - #72963
Merged
Merged
Conversation
The right rail held two things at once: a list of file tabs, and a privileged "live preview" slot with a hardcoded `preview` tab id backed by a separate session-keyed registry. The two were written under different session-id rules and reconciled against each other, so an `open_preview` from a session whose stored id hadn't landed yet was set and then immediately cleared — the pane flashed and vanished. Artifacts arrived as a third list with their own pane and renderers. Now everything the rail can show is a `PreviewTarget` in `$previewTabs`, and `openPreview` is the only way in. `$previewTarget` is a computed read of the active tab, the session registry and its reconciler are gone, and artifacts render in the real preview pane through the shared mode switcher and source view instead of a parallel one. Artifact tabs stay memory-only since the registry rebuilds from the transcript.
`$activeSessionId` only ever holds the primary chat's session, but surfaces that render once per transcript were reading it as if it meant "the session on screen." A preview produced inside a session tile was recorded under the main chat's key and surfaced in the main chat's composer, which is what prompted this. The tool row now records under its own `SessionView`, and the same fix applies to the other readers of that atom that render per surface: attachment pills and inline preview links resolve relative paths against their session's cwd, composer voice and auto-speak read and subscribe to their own transcript, and the thread's compaction label, prompt-wait gate and turn timer follow the session that mounted them. `ComposerScope` now carries a `$messages` atom rather than a read closure so both the imperative read and the subscription come from one place.
The preview pane shares a collapsible column with the file tree, and `revealTreePane` un-collapses a column through that column's bound store — which on the right is `$fileBrowserOpen`, the tree's own ⌘J toggle. So every preview open literally called `setFileBrowserOpen(true)` and the tree came with it. `revealPreview` now un-collapses the column directly and leaves the toggle alone. The tree pane's visibility binding gains `$fileBrowserOpen` to match, since its presence was tracking only the column's collapse — without that it would still render the moment anything opened the column.
Contributor
૮ >ﻌ< ა ci reviewran on cd25a9f ℹ️ InfoDesktop E2E visual evidence · View test artifacts · View job1 visual diff. inline evidence is publishing... |
This was referenced Aug 3, 2026
randlee
pushed a commit
to randlee/hermes-agent
that referenced
this pull request
Aug 11, 2026
…real-preview Unify the preview rail onto one tab list
33hodl
pushed a commit
to 33hodl/hermes-agent
that referenced
this pull request
Aug 12, 2026
…real-preview Unify the preview rail onto one tab list
This was referenced Aug 17, 2026
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.
The right rail had two preview systems living in one tab strip: a list of
file tabs, plus a privileged "live preview" slot with a hardcoded
previewtab id backed by a separate session-keyed registry. Artifacts had recently
arrived as a third list with their own pane and renderers. This collapses
all three into one list, then fixes two bugs that only became visible once
there was a single path to look at.
One list, one way in
Everything the rail can show is now a
PreviewTargetin$previewTabs,and
openPreviewis the only entry point.$previewTargetis a computedread of the active tab; the session registry and the effect that reconciled
it against the tabs are gone.
That reconciler is what made
open_previewunreliable. The two systemsresolved "which session is this for" under different rules, so a tool
opening a preview in a session whose stored id hadn't landed yet would set
the target and then immediately clear it — the pane flashed and vanished.
Artifacts render in the real preview pane through the shared mode switcher
and source view rather than a parallel pane, with a version stepper in the
header's trailing slot. Their tabs stay memory-only since the registry
rebuilds from the transcript on load; file and URL tabs persist like they
did before.
Composer and transcript state follows its own session
$activeSessionIdonly ever holds the primary chat's session, but surfacesthat render once per transcript were reading it as if it meant "the session
on screen." A preview produced inside a session tile got recorded under the
main chat's key and showed up in the main chat's composer.
The tool row now records under its own
SessionView, along with the otherper-surface readers of that atom: attachment pills and inline preview links
resolve relative paths against their session's cwd, composer voice and
auto-speak read and subscribe to their own transcript, and the thread's
compaction label, prompt-wait gate and turn timer follow the session that
mounted them.
Previews open without the file tree
The preview pane shares a collapsible column with the file tree, and
revealTreePaneun-collapses a column through that column's bound store —which on the right is
$fileBrowserOpen, the tree's own Cmd+J toggle. Everypreview open was calling
setFileBrowserOpen(true)and bringing the treewith it. The reveal now un-collapses the column directly and leaves the
toggle alone.
Test plan
open_previewfrom the main chat opens the rail and it stays openopen_previewfrom a session tab opens the rail (the event used to bedropped, since it was gated on the primary chat's session id)
tree in beside it
duplicating
transcript
Two related bugs are deliberately left out: native notifications and the
background-delegation notice read the same primary-only atom, so you get a
completion toast for the tile you're looking at. Fixing them means importing
$focusedRuntimeIdinto those leaf stores, which drags insession-statesand its module-level layout side effects — that hung unrelated suites. It
needs those side effects untangled first.