Skip to content

feat(sidebar): show inner tabs in workspace hover - #24785

Closed
teamleaderleo wants to merge 43 commits into
feat-cmux-nextfrom
codex/sidebar-workspace-hover-20261024
Closed

teamleaderleo wants to merge 43 commits into
feat-cmux-nextfrom
codex/sidebar-workspace-hover-20261024

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Workspace hover cards now open a compact, Rex-style inner-tab popover for every non-empty workspace. The header names the workspace; each tab row shows its icon, title, abbreviated cwd, existing status indicator and status word. Rows select the workspace and tab on mouse release, close the card, and support Up/Down plus Return from the card's keyboard monitor. The card stays interactive while the pointer crosses into it.

Leo asked for this directly on 2026-10-24:

"also when it comes to hovering over the sidebar workspaces, we should just do what rex does and it shows the inner tabs... if they exist. apparently we dont really like the existing situation it kinda sucks i agree the depiction is bad... tho wouldnt first prompt/input needing/whatever MAYBE be nice...? idk tho. we can tuck that behind toggle, but default just only show the inner tabs on hover and be able to go to and focus them when hovering ovre workspaces. let's go get some codex doing stuff"

The existing prompt, needs-input and workspace-facts card remains intact behind the new sidebar.hoverCards.richDetails setting, which is off by default. This matches the private Rex density while keeping cmux glass, colors and typography; the private reference image is not included here. The change does not touch Lawrence's rail placement or Chief sidebar code.

Scope: the change is one interaction plus its settings/export/test surfaces. The raw diff exceeds 800 lines because 262 lines are the two localized setting strings and 91 lines are fleet-generated exports; splitting the compact body from keyboard/click routing would leave a partial interaction.

Risk: the shared hover-card coordinator now permits mouse events for this one interactive body and consumes its arrow/Return keys. Events outside the card still dismiss and pass through, and the rich card continues through its existing path. Empty workspaces have no tab popover and therefore do not show a hover card in the default mode.

Stale-press repair — 2026-10-29

At 1ad21a369b, each reusable hover-card row captures its TabID on mouse-down, clears the press on configure, and only activates on release when the captured ID still matches the current row. aPressedRowCannotSelectAReusedRowAfterItsTabChanges presses the first tab, reconfigures the row as the replacement tab, releases, and proves no replacement tab is selected. Swift syntax and the prepush gate pass; no duplicate native job was dispatched.

Current integration — 2026-10-29

Current head 46fc445c34 merges feat-cmux-next at aff72f12bd into the stale-press repair at 1ad21a369b. The only conflict in this merge was schemas/defaults/cmux-next.json; regenerating the snapshot preserves every current-base default and adds the default-off sidebar.hoverCards.richDetails setting with fresh source fingerprints. Prepush gate, Swift syntax for the 20 changed files, defaults freshness and diff checks pass. No duplicate native job was dispatched.

Dependency: #26942 remains the only external dependency. Its drawn workspace-fill/pinned-pill anchors, inward snapping, no-gap geometry and both sidebar-owner notes are retained alongside the current base's anchor behavior. The per-tab hover content and stale-press fix are unchanged by this merge.

Prior native evidence is tied to its original head: at d1ee8995ea, the app compile passed, 38 tests passed across eight focused suites, and GUI retry 95a9bed132d925513c2f1773 passed all five keyboard/card tests. These receipts do not establish native validation of the new merge head.

Testing

  • python3 scripts/cmux-next/prepush-gate.py passed.
  • Both new settings strings cover all 21 locales used by the Settings web page; the native catalog strings and keys are preserved.
  • Fleet app compile at 71ce4d6c3b passed (job edb49ba8a54e6c042b549101); later changes only complete settings translations and strengthen the interaction capture tour.
  • Added WorkspaceTabHoverCardTests for tab line projection, single-tab behavior, arrow navigation, Return focus, release-click and pointer transfer; SidebarTabMappingTests covers per-tab cwd and status mapping. Six focused native suites ran at 85c2c9a2a8: mapping, dwell, scroll and pinned-row suites passed. The new keyboard fixture failed before establishing its synthetic window/hover target; repaired at 924d3e77ae and all 5 tests passed on the fleet (job 48d5375b7ce0bee70fd438ae, exit 0). Its test now requires the visible native window, a registered hover source, a shown target and an event associated with that same window before testing key consumption. The row escape tests now preserve S2’s flush anchor geometry.
  • Remote webviews full check passed on Linux (job 5096b7a0036307e3dbe2a4ec): formatting, lint, typecheck, browser-lane and protocol checks.
  • Rebased onto base e275db3f69, retaining Lawrence’s geometry and pinned-row hover lookup. The card reuses the current per-tab folder/state projection. Fleet export job 7d423c7c3850d3db326334ac passed all 9 settings/MDM export tests; the exact generated schema, MDM docs, settings reference and default snapshot are committed at 71ce4d6c3b. defaults_guard.py check-fresh passes. Repeating regeneration at 85c2c9a2a8 passed all 9 tests with exit 0 and no changed export; the empty patch upload failed separately with cache HTTP 400. Current base derives the source stamp instead of committing it, so the retired stamp is not restored.

Changelog

Added: Workspace hover cards show selectable inner tabs with per-tab status and cwd.

Proof

Real hover, after (cmux-ci capture at 4df66d7983, fleet build, capture mini at 2x, tour workspace-hover-tabs-card): a workspace with three terminal tabs, the pointer on its sidebar row, and the inner-tab card shown over the sidebar. Synthetic data only: the tabs are plain shells in /tmp, so each title repeats its path (the shell's own title). Cropped to the card with its row for context.

Light Dark
light after dark after

Same hover before the contrast fix (at e2a0a93d99, same tour). The paths drew in the tertiary text token (#808080 in this dark theme) and read as washed-out grey on the glass.

Light Dark
light before dark before

Interaction proof (earlier head 85c2c9a2a8, unchanged interaction code): hover, enter the card, click a different tab; the card closes after selection. GIF, video.

Base (46e3205f42, no inner-tab card): light, dark.

Dark text contrast fix

Each inner-tab row's path now uses the theme's secondary text token, the same token the rich card uses for its facts. Titles stay primary. WorkspaceTabHoverCardContrastTests pins both the tokens and the rendered ink in a dark theme against the rich card's title:

  • Red at 473667b61c on the fleet (gui-session-v1): path token #808080 instead of #A1A1A1, and path ink 0.289 against a floor of 0.323. The titles already matched the rich card's title (ink 0.717).
  • Green at 4df66d7983, together with the nine hover suites (10 of 10 passed, fleet step a67f5e08).

Checklist

  • Behavior changes have added or updated tests.
  • UI and settings localization audited with scripts/localize-changes.
  • Independent Codex gpt-6.1-sol xhigh source review: SHIP at 46fc445c34. Native receipts and captures above retain their original heads; no new native run or capture is claimed for this merge.

Visual review

Viewed after image: yes
Visual verdict: Ship, because the after stills show the real inner-tab card over the hovered sidebar row in light and dark with bright titles and paths that now read clearly in secondary grey on the dark glass, no repeated per-row controls and a card that fits beside the sidebar, so it sits fine next to ChatGPT or Claude.

Agent session: agent session

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review ffa9106: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr24785 -f ref=codex/sidebar-workspace-hover-20261024 -f platform=macos -f backend_mode=local

Passes: CI passes on ffa9106824.

CI passes on ffa9106824 (run 41196451005 attempt 1).

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

web and size checks: green

Default changes

This pull request changes 7 defaults at 27da5cfaa693 (what everyone gets without configuring anything):

  • setting.sidebar.hoverCards.richDetails: (none) -> false (a new setting, off by default: passes on its own)
  • tunable-source.CmuxNextApp/InputVerification/DebugMouse.swift:hoverCard: (none) -> "7175b7af653eecf98cab75e2650a10cd6b7449ab26c3c67bb1e3bc7688633a30"
  • tunable-source.CmuxNextApp/InputVerification/DebugMouse.swift:send: "109678464546150433b22506d4a396faaeefc8780735a38a07897e61c9bace43" -> "3b90069867380238edfa0db55dd00eb317e7688c6019d7ca37340f1f6c11adf0"
  • tunable-source.CmuxNextSettings/HoverCardSettings.swift:parse: "8ae7a617a3dfde7b020caefd66084f105ffc223c924c277c07c09478f0cb884c" -> "d5b844daddfb29df9ecc152c5b6b5c40963914be524afa9a71ed2e463d3962f7"
  • tunable-source.CmuxNextSettings/Schema/SettingsSchema+HoverCards.generated.swift:descriptors: "0bb6ea3cfc77de63adb3bb064514d9a38d1ed4a9961f2c4aca2af15dfc9ec68f" -> "89317b9d3ba6caa77a7b26da82ea500613598386280a9d9c81ffb89652431957"
  • tunable-source.CmuxNextSettings/Schema/SettingsSchema+HoverCards.generated.swift:richDetailsDefault: (none) -> "2e86392ed24f0930ba69b9a7a2b49f639dac49bb6f0c61fceb0e83d0902a90ef"
  • tunable-source.CmuxNextSettings/Schema/SettingsSchema+HoverCards.generated.swift:richDetailsPath: (none) -> "c02a818af69ddc007208fcfc4f8402212e08f61807843601812b8df8ab821bb7"

Needs a review. It passes with an independent review receipt on this commit: a comment or review whose first line is Review (<reviewer>): SHIP at 27da5cfaa693e4ac1f20facdecd687ad1f2f918a, from a member, not a self-review (the newest verdict naming the head decides; a later BLOCK beats an earlier SHIP), or with an approving review on this commit from @lawrencecchen or @austinywang (the call owners in .github/defaults-call-owners.json, never the author). A receipt posted as a review re-runs this check; after a plain comment, re-run it. The needs a call label alone does not pass, and a new push needs a new receipt.

Regenerate the snapshot with python3 scripts/ci/defaults_guard.py snapshot.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Bead cx-7992e created for this PR by the cmux coordinator.

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 24, 2026
@blacksmith-sh

blacksmith-sh Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Found 4 test failures on Blacksmith runners:

Failures

Test View Logs
main.DeveloperIdAppTests.test_download_prints_the_active_profile_only/
test_download_prints_the_active_profile_only
View Logs
stubs: /System/Library/Frameworks/Security.framework/Versions/A/Security has no stub/
Security has no stub
View Logs
stubs: CoreFoundation.tbd: install-name /System/Library/Frameworks/
CoreFoundation.framework/Versions/A/CoreFoundation, missing 1: ['_CFRetain']/
CoreFoundation, missing 1: ['_CFRetain']
View Logs
stubs: CoreFoundation.tbd: install-name /System/Library/Frameworks/
CoreFoundation.framework/Versions/A/CoreFoundation, missing 1: ['_log2']/
CoreFoundation, missing 1: ['_log2']
View Logs

Fix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

@teamleaderleo
teamleaderleo force-pushed the codex/sidebar-workspace-hover-20261024 branch from 408d7fd to d8a092d Compare October 24, 2026 05:22
@teamleaderleo
teamleaderleo force-pushed the codex/sidebar-workspace-hover-20261024 branch from d8a092d to 14e92eb Compare October 24, 2026 05:25
@teamleaderleo
teamleaderleo force-pushed the codex/sidebar-workspace-hover-20261024 branch from 14e92eb to 1ae5728 Compare October 24, 2026 05:34
@teamleaderleo
teamleaderleo force-pushed the codex/sidebar-workspace-hover-20261024 branch from 1ae5728 to f733a49 Compare October 24, 2026 05:40
@teamleaderleo
teamleaderleo force-pushed the codex/sidebar-workspace-hover-20261024 branch from f733a49 to 6a8aaed Compare October 24, 2026 05:48
@cursor

cursor Bot commented Oct 24, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo teamleaderleo added the hold cmux-next batch queue: keep this PR out of the batch (docs/ci/cmux-next-batch.md) label Oct 24, 2026
@teamleaderleo
teamleaderleo force-pushed the codex/sidebar-workspace-hover-20261024 branch from 6a8aaed to cb8f8bd Compare October 24, 2026 06:00
@teamleaderleo
teamleaderleo force-pushed the codex/sidebar-workspace-hover-20261024 branch from 920ac09 to 64efd77 Compare October 28, 2026 21:49
Sidebar-Look: no visual change; regression coverage for Leo’s workspace preview gap.
Agent-Session: https://cmux.com/deeplink/agent?id=aid-f0e2e06c2fc61fa2b914
Sidebar-Look: Leo: "the gap between the hover preview and ... the workspace sidebar element thingy". Touch the row before the drag-out thumb; snap inward so fractional edges leave no seam.
Agent-Session: https://cmux.com/deeplink/agent?id=aid-f0e2e06c2fc61fa2b914
# Conflicts:
#	plans/cmux-next/sidebar-owner.md
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol high, next-review): SHIP at 9137768

No blocking findings.

teamleaderleo and others added 4 commits October 30, 2026 09:45
…ount the inner-tab gallery cards

SidebarHoverCardEscapeTests.theCardFollowsTheHoverToTheNextRow failed by
9 pt on display workers: with no scroll view the list sizes itself to its
rows (124 pt) at the window's bottom, so the third row's top sat 68 pt
above the window's bottom and its 77 pt inner-tab card was clamped up to
the window edge (card 100-177, row top 168). The fixture now puts the
rows at the window's top, which is the room its comment meant to give.

HoverCardSharedRowsTests expected six workspace gallery cards; this PR
adds the five inner-tab cards, so the gallery has eleven.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8ac862c5f65d08f98445
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Independent review (gpt-6.1-sol high) at 22bd712: BLOCK.

  1. Packages/macOS/CmuxNext/Sources/CmuxNextDesign/HoverCards/HoverCardCoordinator.swift:388-394: every left-click inside the interactive card is passed to the non-activating panel, including the title and blank areas. Those views do not handle the click, so it is swallowed and the card neither dismisses nor forwards it. Only tab-row controls should bypass the normal dismissal path.

  2. Packages/macOS/CmuxNext/Sources/CmuxNextSidebar/Views/WorkspaceHoverCard.swift:223-227, WorkspaceTabHoverCard.swift:91-96: deactivation clears only onSelect; keyboard selection state remains when the same tab IDs are shown again. After pressing Down, leaving, and re-entering the workspace, the old row remains highlighted and Return selects it without new navigation.

  3. Packages/macOS/CmuxNext/Sources/CmuxNextSidebar/Views/WorkspaceTabHoverCard.swift:283-286: .busy(progress:) and loading states are rendered with the generic “Working” word, discarding the existing status word/progress (for example, 50% done from Strings.activity). This contradicts the contract to show each tab’s existing status word.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, next-review): SHIP at f9554b1

No blocking findings.

@cmux-bot cmux-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cmux-bot approves f9554b1: an independent review passed this exact head (next-review receipt by teamleaderleo). A push needs a new review; a later BLOCK at this head dismisses this approval.

…-hover-fix

# Conflicts:
#	plans/cmux-next/sidebar-owner.md
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol high, next-review): SHIP at 30eaf59

No blocking findings.

teamleaderleo and others added 2 commits October 30, 2026 20:39
The settings schema export (scripts/cmux-next/regenerate-settings-exports.sh
on the fleet at 6551871, applied with pr-autofix-apply.sh --changed) adds
the surfaces block of sidebar.hoverCards.richDetails and base's
sidebar.textSize, with the MDM docs that follow the schema;
web/data/next-docs/settings-reference.generated.json comes from
bun web/scripts/export-next-docs.ts. The defaults snapshot stays the base
autofix's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8ac862c5f65d08f98445
@cursor

cursor Bot commented Oct 31, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

…-hover-fix

# Conflicts:
#	schemas/settings/settings-schema.json
#	web/data/next-docs/settings-reference.generated.json
@cursor

cursor Bot commented Oct 31, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

teamleaderleo and others added 10 commits October 30, 2026 22:16
scripts/cmux-next/regenerate-settings-exports.sh on the fleet at d24023e
(applied with pr-autofix-apply.sh --changed) lists
sidebar.hoverCards.richDetails in the Sidebar group, as the generator
writes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8ac862c5f65d08f98445
…ture tour

WorkspaceTabHoverCardContrastTests fails before the fix: the card's paths
draw in the tertiary text token, washed out next to the rich card.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8ac862c5f65d08f98445
The paths used the tertiary token (#808080 in a dark theme), which read as
washed-out grey on the dark glass next to the rich card, whose facts use
secondary text. WorkspaceTabHoverCardContrastTests was red before this on
the fleet (path ink 0.29 vs the 0.32 floor; token #808080 vs #A1A1A1).

The capture tour takes window stills only (no whole-display shots).

Sidebar-Look: review of #24785: "the dark inner-tab hover card's titles and paths are washed-out grey on the glass"
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8ac862c5f65d08f98445
…-hover-fix

# Conflicts:
#	Packages/macOS/CmuxNext/Sources/CmuxNextSettings/Schema/SettingsSchema+AgentPolicy.swift
#	plans/cmux-next/sidebar-owner.md
Fleet step 14ec68f9 regenerated them at 66a8297; the snapshot matches its patch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8ac862c5f65d08f98445
…ooser

Fleet step de3960c6 (regenerate-settings-exports.sh at 27da5cf) wrote them;
base had not regenerated them yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-8ac862c5f65d08f98445
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6.1-sol xhigh, next-review): SHIP at ffa9106

SHIP at ffa9106

Visual verdict: after light/dark cards fit beside the sidebar with readable text and no off-screen layout.

  1. [P1][follow-up] After the 10-second resource pin expires while the pointer remains on the workspace row, the machine changes from .pinned to .shown, but the coordinator never replaces the rich body with the default compact tab body. Resource callbacks only refit the existing panel, so the rich card and sampling persist until the pointer leaves or retargets. WorkspaceHoverCard.swift:42-45,148-180

Follow-ups:

  • [P1][follow-up] Replace the pinned rich body when the pin lifetime ends, and close resource sampling when returning to the compact hover card.

@cmux-bot cmux-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cmux-bot approves ffa9106: an independent review passed this exact head (next-review receipt by teamleaderleo). A push needs a new review; a later BLOCK at this head dismisses this approval.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Closing: this change landed on feat-cmux-next as #28897 (carry of #28139, which carries this PR's commits with their authorship), merged 2026-10-31 12:55Z. Merging base into this branch would only conflict with its own landed copy. Still open from this PR's review: the dark-mode inner-tab hover card draws titles and paths in washed-out grey on the glass, and the after captures never showed the card itself. Those go to a follow-up on the landed code.

This branch was previously deployed

3 inactive deployments
artifacts — ffa91068 Deployed Oct 31, 2026 by teamleaderleo via add the Windows daemon to the tree #89487
sentry-dsyms — ffa91068 Deployed Oct 31, 2026 by teamleaderleo via upload cmux-tui dSYMs to Sentry #89487
ci-routing-agent — ffa91068 Deployed Oct 31, 2026 by teamleaderleo via namespace autofix #9620
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant