Repository navigation
Previews: show a header Preview button and side panel only while a window has something to preview - #590
Merged
Conversation
…indow has something to preview The mirror reports per-window preview counts (offered, open) on a new previews message, the hub keeps them with the window's live state, and the session views draw a header Preview button (count badge) that opens the gateway's session page in a side panel, with New tab as the secondary hand-off. The sidebar marks windows with something to preview. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…n-nothing; docs describe the built behaviour Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rincipal; document MUSTER_MIRROR_E2E_PREVIEWS_FILE Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…bject route (its answer never tells a window from a ghost) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…-only # Conflicts: # web/static/app.css
…ond row, so the title keeps its width Below sm the button is a 20px pill at the end of the status line (laid out at the line's own height, a 44px tap target above the title's hit area); from sm up it stays beside the Rendered | Terminal switch. One slot per place, each polled only at its width. e2e asserts the title, header and conversation do not move when the button appears at 390px, and the desktop placement. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…and full-screen focus defer properly - The sidebar's preview mark now has the Preview button's own gate: without a live viewer plugin (revoked, no viewer, MUSTER_PLUGIN_ORIGINS unset) its counts are zeroed, read once per list and not at all with the seam off. - Escape closes the panel only when no other dialog or popover is open and no handler took it. - Full screen (below sm), everything behind the panel is inert while it is open, restored on close. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Owner
Author
|
Round 0 (requirements & deletion), recorded late from the round's report: verdict proceed to the checklist, no open premises, one deletion candidate. |
Owner
Author
|
Round 1 (nine-axis checklist) at |
ZacxDev
marked this pull request as ready for review
November 11, 2026 07:18
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.
What
The previews control on a mirrored window's session views is now shown only while that window has something to preview, and it lives in the header, not in a row above the chat.
muster-mirror -previewsends a newpreviewshost to muster message on its existing mirror connection, a whole map of tmux window id to{offered, open}(counts only, no port or process). It is sent after the window list and again whenever it changes, and an empty map clears it. It follows the existingwork/colorsper-window-message convention: an older muster's read loop drops the unknown type, and an older host never sends one, so its windows show no button.previewhost.Host.Summary().offeredcounts listener reports with no open preview on that port (the same set the gateway's session page lists as offers), andopencounts open previews. It returns nil while no gateway tunnel serves the offer stream or while previews are off.HostView.Previews, copied toSessionView.Previews). It is never kept for an offline host and never stored. A change nudges the owner's views (agent.changed), the same as work counts.smit is a 44x44 icon with the badge on its corner.smup the panel sits over the right of the page; on phones it takes the whole screen. Close or Escape unloads it.viewerPlugins()stays the first gate (no slot, no poll, no frame-src without a live viewer plugin). The counts only narrow it: the button is drawn only whileoffered + open > 0.frame-srcfollows the viewer plugins alone, so a button that appears after load can still frame its panel.GET /ui/mirror/preview-buttonevery 10 s while the tab is visible. The session views hold no event stream, and this keeps it that way. A zero-count poll does not read the plugin store, and a revoked token removes the button at the next poll. The sidebar refreshes on its existing triggers.Tests
internal/mirror/previews_test.go: normalise, pinned wire bytes, hub arrival/nudge/clear/offline.internal/mirrorhost/previews_test.go: send after the windows, re-send only on change, none without-preview, worst case fits one frame.internal/previewhost/summary_test.go: offers minus open ports, nil without a tunnel or while off.internal/api/plugin_chip_test.go: button only while counts > 0 on both views, the poll route's gates, the sidebar mark, the existing CSP/sandbox/gate tests adapted.cmd/muster-mirror: the shipped build cannot take counts from the e2e file.okcheck inNormalizePreviews, is equivalent, because iteration is over listed windows and a zero entry is dropped anyway. A no-op control mutant survived, as it should.previews.spec.tsdrives the real chain through the button and panel, and adds a hidden-when-nothing case: a quiet@2window on the real host's report gets no button and no sidebar mark, with@1as the control.plugin-chip.spec.tsplays the counts viaMUSTER_MIRROR_E2E_PREVIEWS_FILEand covers the button appearing and disappearing live on an open page.cls.spec.tsmeasures the views with the button.e2e was not run locally; CI is the authority.
🤖 Generated with Claude Code