feat(deck): tab-bar-style tiles with repo icons, attention sorting, and tile-style setting - #576
Merged
Conversation
…ndings - deck owns un-gated fetchRepoIconMeta probing (TabBar probe is setting-gated and conditionally mounted; leader window may lack TabBar) - panesForTab synthesized-pane fallback for layout-less tabs (addTab never seeds a layout), mirroring TabBar.tsx:203-221 - IconImageCache drawn-empty probe (<1% alpha) for dimensionless SVGs that load but draw blank; explicit-dims drawImage rule in the renderer - verified jsdom NoOpResourceLoader constraints encoded in test guidance - Rust-server terminal-meta coverage documented as accepted tab-bar parity
…h-eyes review
- Task 4 step 4: state the required terminalMeta/repoIcons reducer registration
in the controller/e2e/VirtualDeckPanel fixture stores (preloadedState alone is
silently ignored without matching reducers) and correct the misdiagnosed
failure mode; run VirtualDeckPanel suite too. Task 3/8 now reference it.
- Task 8: make the no-periodic-repaint test able to go RED (register a
changing-snapshot terminal-text reader); drop the false claim that
deck-controller.test.ts has PREVIEW_REFRESH_TICKS tests (only the e2e suite
covers previews); add a late-terminalMeta probe test.
- Task 8 step 3.7: call probeRepoIcons BEFORE the model-JSON bail-out in
onStoreChange - terminalMeta enrichment doesn't change the model JSON, so a
post-bail-out probe never fires in the TabBar-less leader scenario.
- Task 10/11: use the real markTabAttention({ tabId }) object payload (a bare
string silently defeats the RED gate) and add an armed-gate sanity assertion.
…ting, controller-suite API, grep scope Fresh-eyes review iteration 2 blocking fixes: - Task 3: layout-less tests override tab.mode to 'claude' (fixture tabs are mode 'shell'; synthesized pane inherits tab.mode, so greenIcon and repo-cwd resolution were unreachable as written); corrected the wrong fixture-fact comment and the drift-guard note - Task 6: deferredLoader counts loader invocations; dedup/no-retry assertions use calls() instead of the vacuous Map-keyed pending.size, pinning the load-bearing no-retry-after-failure property - Task 8: test snippets rewritten against deck-controller.test.ts's real API (tabCount, 2-arg setup + 3rd-arg controller options, no defaultSettings); repoIconsOnTabs seeded pre-start via updateSettingsLocal through a new StoreOpts option; setup-extension instructions rewritten with verified facts - Task 4: per-suite fixture API claim corrected (makeState vs makeStore vs makeDeckStore) - Task 9: dead-reference grep excludes SettingsView.core.test.tsx's unrelated previewLines local so the no-matches gate is achievable - Task 10: snippets use tabCount (active tab defaults to t1); closeTab described accurately as the tabsSlice async thunk
…e2e setup 4th param + deferredLoader port Fresh-eyes iteration 3 blocking fixes: - Task 8 step 3.8 (new): register terminalMeta/repoIcons reducers in deck-manager.test.ts makeStore - probeRepoIcons unconditionally reads both slices and that suite starts real controllers, so without them every manager test dies in start(); Step 4 Expected updated to match. - Task 11: Interfaces now mandate the two missing harness extensions - extend the e2e suite's 3-param setup() with a 4th extra-controller- options parameter (spread last into the controller constructor) and port deferredLoader from icon-image-cache.test.ts; Step 1 heading and the repo-icon scenario annotated so harness failures aren't misdiagnosed as integration bugs.
…rom tab-bar state flags
… bar's own conditions
…adiness 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <[email protected]>
…ar fallback and drawn-empty probe
…us dot, active ring
…meta probe, drops the preview repaint
…rget a press Task 4 made selectDeckModel sorted by status priority, so a mid-press re-sort (e.g. a tab gaining attention) could move tabs between keys and the release would act on whatever the slot showed at keyUp, not what the user saw when they pressed. keyDown now snapshots the key's displayed target (pager / tab / none); keyUp acts on that snapshot. A tab closed mid-press is a no-op; the action-layer keyUp branch is unchanged (action keys are fixed indices, unaffected by sorting). 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <[email protected]>
…ns, press snapshot Task 11: seven new e2e scenarios through the real store + real DeckController + FakeDeckDevice covering status-priority sorting (stable within groups), the three background treatments + active ring, blue/green dots, repo-icon unready->ready repaint via an injected IconImageCache with a deferred loader, pager paging over the sorted order, the press-down target snapshot under a mid-press re-sort, and short/long-press on the sorted layout. Harness: setup() gains a 4th extra-controller-options param spread last into the constructor; makeDeckStore gains activeTab, paneStatus, terminalMeta, and repoIcons seeding; deferredLoader ported from icon-image-cache.test.ts. All 9 pre-existing scenarios pass unmodified (already sorted-order-aware). 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <[email protected]>
… plan - Task 8: mergeLocalSettings does not exist as an action; use updateSettingsLocal (verified synchronous re-resolution; sanity assertion added against the extractLegacyLocalSettingsSeed silent no-op trap) - Task 4: reducer state is immer-frozen; adopt the structuredClone withTileStyle idiom instead of direct mutation - Task 1: name the three streamDeck whitelists explicitly (silent-drop trap); record verified cross-window crossTabSync propagation - Task 2: record verified a11y-pattern evidence; note TabsView private SegmentedControl duplicate is out of scope
…eaking strict toEqual assertions Fresh Eyes review found the 'all existing e2e scenarios PASS unchanged' gate unachievable: Task 6 adds style:'icons' to tab KeySpecs, which breaks three strict toEqual tab-spec expectations in test/e2e/stream-deck-flow.test.tsx that no task updated. Step 5 now instructs both fixture edits (defaultSettings tileStyle + the three toEqual expectations) and corrects the false 'fails to compile' prediction (tests are outside tsconfig include; signal is runtime assertion behavior).
…, terminal-previews opt-in
…assertion Add `tileStyle: 'terminal-previews'` to the 'survives the legacy seed normalizer' test fixture and assert it survives extraction/normalization. This positive-path guard prevents silent-strip failures if `tileStyle` is removed from the `pickKeys` whitelist in extractLegacyLocalSettingsSeed or the seed normalizer Zod block. Generated with Amplifier Co-Authored-By: Amplifier <[email protected]>
…ion for classic tiles
…to status-icons style
…eviews tile style
…polling gate, strip waiting union 🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier) Co-Authored-By: Amplifier <[email protected]>
This was referenced Jul 30, 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.
Part 1 — Deck tile redesign
Stream Deck tiles now mirror the tab bar instead of showing terminal screenshots: tab title on top, centered repo icon(s) resolved by the same code the tab bar uses (cap-at-3, colored letter-avatar fallback, blank-SVG detection), status backgrounds matching tab-bar semantics (green border + light green fill for bar-on-top tabs; light green fill for green-filled tabs; no fill otherwise), white ring still marks the active tab. Keys sort by attention priority (bar-on-top → green-filled → green-icon → blue-icon → rest, stable by tab order within groups) with a press-snapshot guard so mid-press reorders can't misfire a press. The old preview/capture machinery was removed from the default path.
Part 2 — Tile-style setting + waiting-count union
New Settings → Stream Deck "tile style" option: "Status icons" (new design, default) vs "Terminal previews" (classic look restored from git history: live previews + status rings + tab-bar order). Switching applies live with no reload; capture polling only runs in classic mode; persists client-side. Stream Deck+ touch strip "waiting" count now counts the union of needs-attention and waiting-for-approval tabs (each tab once), in both styles; approval-waiting tabs get an amber attention treatment.
Quality notes