Skip to content

Flatten mobile terminal switcher menu - #7087

Merged
austinywang merged 9 commits into
mainfrom
issue-7085-flatten-nav-switcher-menu
Jun 30, 2026
Merged

austinywang merged 9 commits into
mainfrom
issue-7085-flatten-nav-switcher-menu

Conversation

@austinywang

@austinywang austinywang commented Jun 30, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Make the mobile workspace title pill non-interactive so the rectangle-stack picker is the single nav-bar menu layer.
  • Inline workspace actions into the terminal picker menu as flat sections.
  • Extend the iOS UI test mock and dropdown test so workspace actions are available directly from MobileTerminalDropdown.

Closes #7085

Verification

  • Static diff hygiene: git diff --check
  • Localization audit: parsed Resources/Localizable.xcstrings and ios/cmux/Resources/Localizable.xcstrings; verified existing mobile menu/action keys have English and Japanese entries in ios/cmux/Resources/Localizable.xcstrings.
  • Not run per task instruction: local tests, local build/reload.
  • Pending: iOS Simulator visual verification artifact.

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Flattened the mobile nav by making the workspace title pill non-interactive and moving workspace actions into the terminal picker. This reduces menu layers on mobile and addresses #7085.

  • Refactors
    • Replaced the interactive title menu with a display-only WorkspaceToolbarTitleControl; removed WorkspaceTitleMenu; retained the "MobileWorkspaceTitleMenu" accessibility identifier, and UI tests now assert it is non-interactive.
    • Moved workspace actions (Rename, Read state, Close) into the terminal picker and unified its label/accessibility to mobile.terminal.picker.menuTitle ("Workspace and Terminals").
    • Updated WorkspaceDetailView, WorkspaceChatPane, and inline chat/browser views to use the new title control and inject workspace actions into the picker.
    • Expanded Agent Chat inline preview to include workspace actions and "New Terminal" in the picker; added action capabilities to the preview model; finished UI test migration and updated the mock via mobile.host.status.

Written for commit 0d5ad7d. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added WorkspaceToolbarTitleControl to unify the iOS workspace title control across browser, terminal, and inline chat, including chat-toggle and back-button behavior.
    • Reworked inline terminal picker/menu actions (rename, read-state, close) with a dedicated “New Terminal” section.
  • Bug Fixes
    • Standardized the terminal picker menu button label and accessibility title using shared localization (“Workspace and Terminals”).
  • Tests
    • Updated UI tests to assert menu items via stable accessibility identifiers; refreshed inline interaction flow and mock host status responses.
  • Documentation
    • Reworded the rename-workspace dialog description for clearer context.

@vercel

vercel Bot commented Jun 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 30, 2026 6:27am
cmux-staging Building Building Preview, Comment Jun 30, 2026 6:27am

@coderabbitai

coderabbitai Bot commented Jun 30, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

WorkspaceTitleMenu becomes WorkspaceToolbarTitleControl, workspace title actions move into the terminal picker menu, and the chat/detail/demo toolbar call sites switch to the new control. The iOS UI tests and mock host status response are updated to match the flat menu structure.

Changes

Workspace toolbar and picker flattening

Layer / File(s) Summary
Toolbar title control replacement
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceTitleMenu.swift, Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceToolbarTitleControl.swift
WorkspaceTitleMenu<Label, MenuContent> is replaced by WorkspaceToolbarTitleControl<Label> that renders only the fitted label and keeps the title sizing and accessibility behavior.
Chat pane and detail view wiring
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceChatPane.swift, Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+AgentChat.swift, Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift, Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceRenameDialog.swift
WorkspaceChatPane drops its generic title-menu content plumbing and uses the new toolbar title control; detail-view toolbar leading controls switch to the same control; titleMenuContent is appended into terminalPickerMenuContent; the rename dialog comment is rephrased.
Inline demo toolbar and picker
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/AgentChatDemoScreen.swift, ios/cmux/Resources/Localizable.xcstrings
The inline demo title area uses WorkspaceToolbarTitleControl, the terminal picker becomes a labeled menu with workspace actions and a new-terminal section, a preview workspace model is added, and a shared picker menu title string is localized.
UI tests and mock host status
ios/cmuxUITests/cmuxUITests.swift
UI tests assert the new workspace action buttons, update inline picker interaction and compact-height lookup, and add the mock mobile.host.status route and response payload.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • manaflow-ai/cmux#5687: Adds iOS UI-test helper patterns around menu-item assertions and mock-host coordination in the same test surface.
  • manaflow-ai/cmux#6362: Touches WorkspaceDetailView’s terminal picker menu content, overlapping with the same toolbar/menu wiring.
  • manaflow-ai/cmux#7056: Refactors the same workspace toolbar/title plumbing across WorkspaceChatPane, WorkspaceDetailView, and the demo screen.

Poem

🐇 I hopped through menus, one layer at a time,
Now the picker is flat and the title is fine.
No chevron tunnel, no submenu maze,
Just tidy toolbar actions in SwiftUI’s haze.
The rabbit does a wiggle and gives a small cheer —
One flat menu now, and the path is clear.

🚥 Pre-merge checks | ✅ 24 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (24 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: flattening the mobile terminal switcher menu.
Description check ✅ Passed Summary and verification are present and relevant, but the demo video and checklist template sections are missing.
Linked Issues check ✅ Passed The changes flatten the nested mobile menu, localize labels, preserve identifiers, and update tests as required by #7085.
Out of Scope Changes check ✅ Passed The diff stays focused on the mobile menu flattening work, with only a minor comment reflow outside the main behavior change.
Cmux Swift Actor Isolation ✅ Passed Touched code is SwiftUI UI code or Sendable value models; no new shared mutable reference or background-store isolation regression was introduced.
Cmux Swift Blocking Runtime ✅ Passed No production Swift adds blocking waits/sleeps/sync; the only new waits are XCTest waitForExistence in UI tests, which is allowed test-only scaffolding.
Cmux Browser Automation Off-Main ✅ Passed PR touches iOS/mobile UI and tests only; no changes in Sources/TerminalController.swift or ControlCommandExecutionPolicy.swift where this rule applies.
Cmux Expensive Synchronous Load ✅ Passed The diff only refactors toolbar/menu UI and preview data; no synchronous agent-history load or JSON/transcript parsing was added on main/UI paths.
Cmux Cache Substitution Correctness ✅ Passed Only UI/menu flattening and test/localization updates changed; no persistence/history/snapshot read was swapped for cache, and existing chat cache logic stayed intact.
Cmux No Hacky Sleeps ✅ Passed PR touches Swift UI/test and localization only; no changed TS/JS/shell/runtime files introduce sleeps, timers, or polling.
Cmux Algorithmic Complexity ✅ Passed Changed Swift UI code only flattens menus and adds a width helper; no nested scans, repeated sorts/filters, or per-target rescans were introduced.
Cmux Swift Concurrency ✅ Passed Diff only refactors SwiftUI title/menu UI and UI tests; no new DispatchQueue, Combine, completion-handler, or fire-and-forget Task patterns were added.
Cmux Swift @Concurrent ✅ Passed Changed files add only pure SwiftUI view wrappers; no new @concurrent/nonisolated async or heavy async call sites were introduced, and existing tasks remain UI-bound.
Cmux Swift File And Package Boundaries ✅ Passed Touched production Swift files are small UI/package glue; no new >400-line file, no >800-line expansion, and no mixed UI/network/persistence responsibility was introduced.
Cmux Swiftpm Lockfiles ✅ Passed PASS: The PR only changes Swift source, localization, and UI tests; no Package.swift, Package.resolved, .gitignore, workflow, or Xcode project files were touched.
Cmux Swift Logging ✅ Passed No production logging was added; the only found NSLog is in a #if DEBUG helper, which the rule explicitly allows.
Cmux User-Facing Error Privacy ✅ Passed The PR only refactors title/menu UI and test mocks; no production error, alert, or recovery copy was added or changed to expose internal details.
Cmux Full Internationalization ✅ Passed PASS: the new menu title uses the localized L10n wrapper, and mobile.terminal.picker.menuTitle has English and Japanese entries in the touched catalog.
Cmux Swiftui State Layout ✅ Passed PASS: touched SwiftUI files add only local @State/onGeometryChange sizing and Menu refactors; no new ObservableObject/@published, lazy-list store refs, or render-time state writes.
Cmux Architecture Rethink ✅ Passed PASS: The diff flattens the nav menu into one shared Menu path and adds test/mock plumbing; no sleeps, polling, duplicate owners, or split lifecycle wiring in prod code.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed Changed files are mobile SwiftUI views/menus only; no NSWindow/NSPanel/WindowGroup or cmuxAuxiliaryWindowIdentifiers changes.
Cmux Source Artifacts ✅ Passed Changed paths are Swift source, UI tests, and an xcstrings catalog—allowed by the rule, with no logs, screenshots, caches, or build artifacts.
Cmux No Test Or Debug Seam In Production Source ✅ Passed No new test-only/debug seam was added in production Sources; the PR only refactors real UI and leaves isolated debug-only UI/logging intact.
Cmux No Ambient Global State ✅ Passed Touched Swift files add only view structs/extension methods; no new file-scope mutable state or singleton API was introduced.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-7085-flatten-nav-switcher-menu

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jun 30, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR flattens the mobile nav by making the workspace title pill non-interactive (WorkspaceToolbarTitleControl via mobileGlassCompactNavigationTitle()) and moving workspace actions (Rename, Read State, Close) into the terminal picker menu as a flat section — reducing the mobile UI from two interactive toolbar layers to one.

  • WorkspaceTitleMenu deleted: display and action responsibilities are split between the new WorkspaceToolbarTitleControl (visual-only pill) and terminalPickerMenuContent (which now embeds titleMenuContent between the terminal list and the create-new section).
  • WorkspaceChatPane simplified: the TitleMenuContent generic parameter is dropped; the trailing cluster with workspace actions reaches chat mode through WorkspaceDetailView+AgentChat.swift's toolbarTrailingCluster, so no action surface is lost.
  • Tests and mock updated: UI tests switch from buttons["MobileWorkspaceTitleMenu"] to descendants(matching: .any) (verifying the element is no longer a button), migrate workspace-action assertions from the title tap to the surface picker, remove the polling-sleep tapCompactToolbarTitleMenu helper, and add mobile.host.status handling to the mock server so capability-gated action buttons appear.

Confidence Score: 5/5

Safe to merge: all three toolbar contexts (terminal, browser, chat) reach workspace actions through the terminal picker, localization is complete for the new button label, and the tests correctly validate the non-interactive title element and the flattened menu structure.

The workspace action surface is preserved across all toolbar modes via the terminal picker's embedded titleMenuContent. The non-interactive title control is consistently handled by mobileGlassCompactNavigationTitle() on iOS 26+ (glass button with hit testing and .isButton removed) and falls back to a plain view on earlier OS versions. Tests are updated to match the new accessibility element type and menu location, and the mock server now correctly seeds host capabilities so action items are visible in connected-app tests. No production regressions or logic gaps were identified.

No files require special attention.

Important Files Changed

Filename Overview
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceToolbarTitleControl.swift New non-interactive title control replacing WorkspaceTitleMenu; uses mobileGlassCompactNavigationTitle() which removes .isButton and disables hit testing on iOS 26+ (falls back to plain view on pre-iOS 26). Clean, single-responsibility file.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift Replaces WorkspaceTitleMenu with WorkspaceToolbarTitleControl in all three toolbar contexts (terminal, browser, chat); inlines titleMenuContent into terminalPickerMenuContent between the terminal list and create-new section.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceChatPane.swift Drops the titleMenuContent generic parameter and replaces Menu with WorkspaceToolbarTitleControl; trailing cluster (including workspace actions via the picker) is supplied by the parent WorkspaceDetailView+AgentChat.swift, so no functionality is lost.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/AgentChatDemoScreen.swift Updates debug preview to use WorkspaceToolbarTitleControl for the title pill and a Menu with WorkspaceTitleMenuContent + New Terminal for the surface picker; adds inlinePreviewWorkspace with full actionCapabilities so tests can assert all workspace action items.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+AgentChat.swift Removes the now-deleted titleMenuContent parameter from the WorkspaceChatPane call site; no other logic changes.
ios/cmuxUITests/cmuxUITests.swift Updates all title-menu references to use descendants(matching: .any) for the non-button element; migrates title-tap assertions to surface-picker tap; adds workspace action assertions inside the terminal picker; removes the polling-sleep tapCompactToolbarTitleMenu helper; adds mobileHostStatusResult() to mock server.
ios/cmux/Resources/Localizable.xcstrings Adds mobile.terminal.picker.menuTitle with English and Japanese translations; no existing keys are removed or changed.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceTitleMenu.swift File deleted; its responsibilities split into WorkspaceToolbarTitleControl (display) and terminalPickerMenuContent (actions).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    WDV[WorkspaceDetailView] -->|terminal mode| TC[WorkspaceToolbarTitleControl non-interactive title pill]
    WDV -->|browser mode| TC
    WDV -->|chat mode via WorkspaceDetailView+AgentChat| TC
    WDV -->|all modes trailing cluster| TPTB[terminalPickerToolbarButton MobileTerminalDropdown]
    TPTB --> TPMC[terminalPickerMenuContent]
    TPMC --> TS[Section Terminals ForEach workspace.terminals]
    TPMC --> TMC[titleMenuContent WorkspaceTitleMenuContent Rename / Read State / Close]
    TPMC --> NS[Section New Workspace / New Terminal / New Browser]
    TPMC --> DS[Section View as Text / Send Feedback]
    TC -.->|accessibilityIdentifier| AID[MobileWorkspaceTitleMenu not a button hit testing off .isButton removed on iOS 26+]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    WDV[WorkspaceDetailView] -->|terminal mode| TC[WorkspaceToolbarTitleControl non-interactive title pill]
    WDV -->|browser mode| TC
    WDV -->|chat mode via WorkspaceDetailView+AgentChat| TC
    WDV -->|all modes trailing cluster| TPTB[terminalPickerToolbarButton MobileTerminalDropdown]
    TPTB --> TPMC[terminalPickerMenuContent]
    TPMC --> TS[Section Terminals ForEach workspace.terminals]
    TPMC --> TMC[titleMenuContent WorkspaceTitleMenuContent Rename / Read State / Close]
    TPMC --> NS[Section New Workspace / New Terminal / New Browser]
    TPMC --> DS[Section View as Text / Send Feedback]
    TC -.->|accessibilityIdentifier| AID[MobileWorkspaceTitleMenu not a button hit testing off .isButton removed on iOS 26+]
Loading

Reviews (5): Last reviewed commit: "Assert mobile title control is nonintera..." | Re-trigger Greptile

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ios/cmuxUITests/cmuxUITests.swift`:
- Around line 298-300: Finish migrating the remaining title-pill UI tests by
replacing any `app.buttons["MobileWorkspaceTitleMenu"]` lookup and tap in the
old dropdown flows with the flattened terminal-picker path used by
`WorkspaceToolbarTitleControl`, so the tests no longer depend on the
non-hit-testable title control. Update the affected test helpers/cases around
the existing menu assertions to use the new picker interaction and keep the
rename/read-state/close menu checks aligned with the migrated path.

In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift`:
- Around line 442-443: The rectangle-stack picker in WorkspaceDetailView is
still exposed with the misleading “Terminals” label even though it now opens
both workspace and terminal actions. Update the picker’s accessibility/title
label to a combined workspace+terminal menu name, and route it through the
localized string API used elsewhere in the view so the new text has matching
string-catalog entries for all supported locales. Use the WorkspaceDetailView
picker/title menu symbols to locate and replace the current label source.

In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceTitleMenu.swift`:
- Around line 20-22: The iOS fallback in WorkspaceTitleMenu currently puts the
MobileWorkspaceTitleMenu accessibility identifier on fittedLabel, so it is no
longer exposed as a button. Update the fallback branch in WorkspaceTitleMenu to
keep the same accessibility container/traits as the supported OS path, or adjust
the element so app.buttons["MobileWorkspaceTitleMenu"] still resolves correctly
for callers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e11dfc67-db7c-4544-88ad-76714750272c

📥 Commits

Reviewing files that changed from the base of the PR and between aee4ba2 and f8d8820.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (6)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceChatPane.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+AgentChat.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceRenameDialog.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceTitleMenu.swift
  • ios/cmuxUITests/cmuxUITests.swift
💤 Files with no reviewable changes (1)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+AgentChat.swift

Comment thread ios/cmuxUITests/cmuxUITests.swift
Comment thread Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceTitleMenu.swift Outdated

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ios/cmuxUITests/cmuxUITests.swift (1)

3484-3485: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep the UI-test mobile.host.status payload aligned with production.

Sources/Mobile/MobileHostService.swift:296-310 documents the public mobile.host.status reply as only routes, terminal_fidelity, and capabilities. Adding mac_device_id / mac_display_name here means the test server accepts a shape the real handler never emits, so client code can accidentally start depending on impossible fields and still pass CI. Mirror publicStatusPayload(...) instead, and leave Mac identity on the authenticated attach/network-status path.

Also applies to: 3607-3618

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ios/cmuxUITests/cmuxUITests.swift` around lines 3484 - 3485, The
`mobile.host.status` UI-test response is exposing extra Mac identity fields that
the production `publicStatusPayload(...)` never returns. Update
`mobileHostStatusResult()` (and the related `mobile.host.status` test cases) so
the payload matches the production `MobileHostService` shape exactly, keeping
only `routes`, `terminal_fidelity`, and `capabilities`, and leave
`mac_device_id` / `mac_display_name` on the authenticated attach/network-status
path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@ios/cmuxUITests/cmuxUITests.swift`:
- Around line 3484-3485: The `mobile.host.status` UI-test response is exposing
extra Mac identity fields that the production `publicStatusPayload(...)` never
returns. Update `mobileHostStatusResult()` (and the related `mobile.host.status`
test cases) so the payload matches the production `MobileHostService` shape
exactly, keeping only `routes`, `terminal_fidelity`, and `capabilities`, and
leave `mac_device_id` / `mac_display_name` on the authenticated
attach/network-status path.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c1313316-f544-4614-ab70-1d5c1013555c

📥 Commits

Reviewing files that changed from the base of the PR and between f8d8820 and fa455da.

📒 Files selected for processing (5)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/AgentChatDemoScreen.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceTitleMenu.swift
  • ios/cmux/Resources/Localizable.xcstrings
  • ios/cmuxUITests/cmuxUITests.swift

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ios/cmuxUITests/cmuxUITests.swift`:
- Line 289: The UI test is querying MobileWorkspaceTitleMenu through
app.buttons, but WorkspaceToolbarTitleControl now assigns that identifier to a
non-interactive view, so the lookup will never succeed. Update the title-control
existence check in cmuxUITests to query the correct element type for
MobileWorkspaceTitleMenu, then keep the subsequent picker assertions unchanged
so the test reaches them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2df0b2af-5e34-44be-8389-4596d5a93c32

📥 Commits

Reviewing files that changed from the base of the PR and between fa455da and 8f489a6.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (3)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceChatPane.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift
  • ios/cmuxUITests/cmuxUITests.swift

@coderabbitai coderabbitai 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.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ios/cmuxUITests/cmuxUITests.swift`:
- Line 289: The UI test is querying MobileWorkspaceTitleMenu through
app.buttons, but WorkspaceToolbarTitleControl now assigns that identifier to a
non-interactive view, so the lookup will never succeed. Update the title-control
existence check in cmuxUITests to query the correct element type for
MobileWorkspaceTitleMenu, then keep the subsequent picker assertions unchanged
so the test reaches them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2df0b2af-5e34-44be-8389-4596d5a93c32

📥 Commits

Reviewing files that changed from the base of the PR and between fa455da and 8f489a6.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (3)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceChatPane.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift
  • ios/cmuxUITests/cmuxUITests.swift
🛑 Comments failed to post (1)
ios/cmuxUITests/cmuxUITests.swift (1)

289-289: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Stop querying MobileWorkspaceTitleMenu as a button.

WorkspaceToolbarTitleControl now exposes that identifier on a non-interactive view, so app.buttons["MobileWorkspaceTitleMenu"] will stay false even when the title control is present. This test will fail before it reaches the flattened picker assertions.

Proposed fix
-        XCTAssertTrue(app.buttons["MobileWorkspaceTitleMenu"].waitForExistence(timeout: 4))
+        XCTAssertTrue(app.descendants(matching: .any)["MobileWorkspaceTitleMenu"].waitForExistence(timeout: 4))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

        XCTAssertTrue(app.descendants(matching: .any)["MobileWorkspaceTitleMenu"].waitForExistence(timeout: 4))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ios/cmuxUITests/cmuxUITests.swift` at line 289, The UI test is querying
MobileWorkspaceTitleMenu through app.buttons, but WorkspaceToolbarTitleControl
now assigns that identifier to a non-interactive view, so the lookup will never
succeed. Update the title-control existence check in cmuxUITests to query the
correct element type for MobileWorkspaceTitleMenu, then keep the subsequent
picker assertions unchanged so the test reaches them.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ios/cmuxUITests/cmuxUITests.swift (1)

3519-3520: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep the UI-test mobile.host.status mock aligned with the production payload.

The new mock status route appears to hand-build a partial capability list and envelope, but production derives capabilities from MobileHostService.mobileHostCapabilities and returns the fuller v2MobileHostStatus shape. That creates a second source of truth, so capability-gating regressions can be masked in UI tests when the real host contract changes. Mirror the production payload shape/capability source here instead of hardcoding a subset. As per path instructions, reliability-single-source-of-truth.md says “tests/mocks should reflect that single source of truth.”

Also applies to: 3642-3653

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ios/cmuxUITests/cmuxUITests.swift` around lines 3519 - 3520, The UI-test mock
for mobile.host.status is diverging from the production contract by hardcoding a
partial payload instead of mirroring the real status shape and capability
source. Update mobileHostStatusResult and the related mock route handling to
build the response from the same source as production, namely
MobileHostService.mobileHostCapabilities and the v2MobileHostStatus envelope, so
the mock stays aligned when the production contract changes.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ios/cmuxUITests/cmuxUITests.swift`:
- Around line 289-290: The current assertions around MobileWorkspaceTitleMenu
only verify that the element exists, so they do not catch regressions where the
title pill becomes tappable again. Update the affected UI tests to keep the
existence check via titleControl/MobileWorkspaceTitleMenu, and add a negative
assertion that app.buttons["MobileWorkspaceTitleMenu"] does not exist (or an
equivalent non-interactive assertion) so the title menu is confirmed to be
non-interactive in each of the listed test blocks.

---

Outside diff comments:
In `@ios/cmuxUITests/cmuxUITests.swift`:
- Around line 3519-3520: The UI-test mock for mobile.host.status is diverging
from the production contract by hardcoding a partial payload instead of
mirroring the real status shape and capability source. Update
mobileHostStatusResult and the related mock route handling to build the response
from the same source as production, namely
MobileHostService.mobileHostCapabilities and the v2MobileHostStatus envelope, so
the mock stays aligned when the production contract changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 068da6ec-6d2b-4315-aa5c-273a2fdb91c8

📥 Commits

Reviewing files that changed from the base of the PR and between 8f489a6 and 202bacc.

📒 Files selected for processing (2)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceToolbarTitleControl.swift
  • ios/cmuxUITests/cmuxUITests.swift
💤 Files with no reviewable changes (1)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceToolbarTitleControl.swift

Comment thread ios/cmuxUITests/cmuxUITests.swift

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ios/cmuxUITests/cmuxUITests.swift (1)

3522-3523: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep the mobile.host.status mock aligned with the public-status contract.

This mock now advertises mac_display_name / mac_device_id on mobile.host.status, but Sources/Mobile/MobileHostService.swift:296-331 defines that route’s public payload as identity-free; those fields only belong on the verified identity-status path. Leaving them here lets UI tests pass against a payload production should never serve, which can hide incorrect host-identity reads. Restrict this mock to the public status fields (capabilities, terminal_fidelity, etc.), or add a separate mock for the authenticated identity-bearing route if a test actually needs Mac identity. As per path instructions, "flag more than one disagreeing source of truth for the same fact" and fail closed when the reliable signal is missing.

Also applies to: 3645-3656

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@ios/cmuxUITests/cmuxUITests.swift` around lines 3522 - 3523, The
`mobile.host.status` mock in `cmuxUITests` is returning Mac identity fields that
do not belong in the public-status contract. Update `mobileHostStatusResult()`
and the `case "mobile.host.status"` handling so this mock only serves the public
fields defined by `MobileHostService`’s public status route (such as
capabilities and terminal fidelity), and move any `mac_display_name` /
`mac_device_id` coverage to a separate authenticated identity-status mock if
needed.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@ios/cmuxUITests/cmuxUITests.swift`:
- Around line 3522-3523: The `mobile.host.status` mock in `cmuxUITests` is
returning Mac identity fields that do not belong in the public-status contract.
Update `mobileHostStatusResult()` and the `case "mobile.host.status"` handling
so this mock only serves the public fields defined by `MobileHostService`’s
public status route (such as capabilities and terminal fidelity), and move any
`mac_display_name` / `mac_device_id` coverage to a separate authenticated
identity-status mock if needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4379136d-ef65-4c5e-a1f3-8a42463207b3

📥 Commits

Reviewing files that changed from the base of the PR and between 202bacc and 0d5ad7d.

📒 Files selected for processing (1)
  • ios/cmuxUITests/cmuxUITests.swift

@austinywang
austinywang merged commit c259e38 into main Jun 30, 2026
37 checks passed
austinywang added a commit that referenced this pull request Jun 30, 2026
* Revert "Flatten mobile terminal switcher menu (#7087)"

This reverts commit c259e38.

* Keep mobile terminal picker stable

* Reuse title menu in mobile chat chrome

* Gate mobile title menu on actions

* Preserve terminal picker fallback selection

* Address mobile picker review feedback

* Satisfy mobile picker policy review

This branch was successfully deployed

1 active deployment
Preview – cmux — 0d5ad7df Deployed Jun 30, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

iOS/iPad: nav-bar workspace/terminal switcher nests a submenu ('menu in a menu') — flatten to one layer

1 participant