Repository navigation
Improve Simulator discoverability on macOS and iOS - #9888
azooz2003-bit wants to merge 26 commits into
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds Simulator picker controls, serialized stream selection, deterministic DEBUG preview fixtures, UI tests, shared store ownership, and the built-in Simulator surface-tab action. ChangesSimulator discoverability
Vendor pointer update
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant WorkspaceDetailView
participant SimulatorPickerControl
participant MobileShellComposite
participant MobileSimulatorStreamSelectionCoordinator
WorkspaceDetailView->>SimulatorPickerControl: render simulator picker state
SimulatorPickerControl->>WorkspaceDetailView: select target panel
WorkspaceDetailView->>MobileShellComposite: request simulator transition
MobileShellComposite->>MobileSimulatorStreamSelectionCoordinator: enqueue selection
MobileSimulatorStreamSelectionCoordinator->>MobileShellComposite: stop previous and start target stream
Possibly related PRs
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (3 errors, 2 warnings)
✅ Passed checks (20 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift (1)
959-970: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy liftSerialize simulator stream transitions.
Each selection starts an independent, unowned task. During rapid A → B → C selection, the B task can resume and start B after the C task has stopped B. The local store then shows C as active while B also runs remotely.
Move this transition into a caller-owned coordinator or store operation that serializes the latest intent and cancels or supersedes older requests.
As per coding guidelines, do not create fire-and-forget
Task { ... }work with meaningful lifecycle unless it is stored, cancellable, or tied to a caller-owned operation.🤖 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 `@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift` around lines 959 - 970, Replace the unowned Task transition around stopMobileSimulatorStream and startMobileSimulatorStream with a caller-owned, stored coordinator or store operation that serializes selection intents. Ensure rapid selections cancel or supersede older transitions so only the latest panel’s stream is active, and expose lifecycle cancellation rather than creating fire-and-forget work.Source: Coding guidelines
🤖 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 7681-7684: Update the test lifecycle around setUpWithError and
tearDownWithError to restore XCUIDevice.shared.orientation to its prior/default
state and terminate the two application during teardown. Ensure cleanup runs
after every test, including failed tests, so shared device state and the fixture
process do not leak into later tests.
In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SimulatorPickerMenuValue.swift`:
- Around line 11-14: Update the initializer logic in SimulatorPickerMenuValue so
activePanelID is validated against the filtered self.rows rather than the
original rows parameter, ensuring it becomes nil whenever
supportsSimulatorStream is false and preserving valid IDs only for available
panels.
---
Outside diff comments:
In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift`:
- Around line 959-970: Replace the unowned Task transition around
stopMobileSimulatorStream and startMobileSimulatorStream with a caller-owned,
stored coordinator or store operation that serializes selection intents. Ensure
rapid selections cancel or supersede older transitions so only the latest
panel’s stream is active, and expose lifecycle cancellation rather than creating
fire-and-forget work.
🪄 Autofix
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 Plus
Run ID: 001c6a3c-0e17-4642-b11b-787ba3c1c596
📒 Files selected for processing (11)
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SimulatorPreview.swiftPackages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SimulatorDiscoverabilityPreviewView.swiftPackages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SimulatorPickerControl.swiftPackages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SimulatorPickerMenuValue.swiftPackages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+AgentChat.swiftPackages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swiftPackages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/SimulatorPickerMenuValueTests.swiftSources/CmuxConfig.swiftcmuxTests/CmuxConfigTests.swiftios/cmuxPackage/Sources/cmuxFeature/CMUXMobileRootScene.swiftios/cmuxUITests/cmuxUITests.swift
There was a problem hiding this comment.
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 `@vendor/bonsplit`:
- Line 1: Update the vendor/bonsplit submodule reference so it points to a
commit available on the configured submodule remote, either by pushing commit
8230030608931784878dc46b8b8581756e7a2d69 to the remote branch or changing the
superproject pointer to an already-pushed commit.
🪄 Autofix
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 Plus
Run ID: 4c1c33c9-825d-42da-9fe0-21770e061879
📒 Files selected for processing (13)
Packages/iOS/CmuxMobileShell/Package.swiftPackages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SimulatorStream.swiftPackages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swiftPackages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileSimulatorStreamSelectionCoordinator.swiftPackages/iOS/CmuxMobileShell/Sources/CmuxMobileShellDebugSupport/MobileShellComposite+SimulatorPreview.swiftPackages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileSimulatorStreamSelectionCoordinatorTests.swiftPackages/iOS/CmuxMobileShellUI/Package.swiftPackages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SimulatorDiscoverabilityPreviewView.swiftPackages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SimulatorPickerMenuValue.swiftPackages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+AgentChat.swiftPackages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swiftios/cmuxUITests/cmuxUITests.swiftvendor/bonsplit
There was a problem hiding this comment.
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)
7726-7727: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winWait for the UI state before both assertions.
After
panelB.tap(), Line 7727 can run beforeMobileSimulatorPickerreceives the new value. The assertion can fail intermittently. At Line 7735,existscan befalsebefore the workspace chrome finishes rendering, so the test can pass without proving that the picker is omitted. Wait for a value predicate after the tap and use a deadline-bounded absence check after the terminal picker is ready.Proposed test synchronization
panelB.tap() + let selectionExpectation = XCTNSPredicateExpectation( + predicate: NSPredicate(format: "value == %@", "iPhone B"), + object: twoPicker + ) + wait(for: [selectionExpectation], timeout: 4) XCTAssertEqual(twoPicker.value as? String, "iPhone B") ... - XCTAssertFalse(app.buttons["MobileSimulatorPicker"].exists) + XCTAssertFalse( + app.buttons["MobileSimulatorPicker"].waitForExistence(timeout: 2) + )As per coding guidelines, UI tests must await real completion signals or use deadline-bounded polls of real predicates before assertions.
Also applies to: 7734-7735
🤖 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 7726 - 7727, Update the UI test around panelB.tap() and the terminal picker assertion to synchronize with real UI state: wait for a value predicate confirming MobileSimulatorPicker has changed to “iPhone B” before asserting it, then wait until the workspace chrome is ready and perform a deadline-bounded poll confirming the picker’s exists predicate remains false. Ensure both assertions only run after their corresponding state transitions are complete.Source: Coding guidelines
🤖 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 7726-7727: Update the UI test around panelB.tap() and the terminal
picker assertion to synchronize with real UI state: wait for a value predicate
confirming MobileSimulatorPicker has changed to “iPhone B” before asserting it,
then wait until the workspace chrome is ready and perform a deadline-bounded
poll confirming the picker’s exists predicate remains false. Ensure both
assertions only run after their corresponding state transitions are complete.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: ef133c6f-b73f-48d4-97a5-ef539172bc8a
📒 Files selected for processing (3)
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/CMUXMobileAppView.swiftPackages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SimulatorDiscoverabilityPreviewView.swiftios/cmuxUITests/cmuxUITests.swift
…r-discoverability # Conflicts: # Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+TerminalArtifacts.swift # ios/cmux/cmuxApp.swift # ios/cmuxPackage/Sources/cmuxFeature/CMUXMobileRootScene.swift
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9eedc37. Configure here.
| } | ||
| pendingIntent = Intent(target: target) | ||
| startDrainIfNeeded() | ||
| } |
There was a problem hiding this comment.
Coordinator breaks multi-workspace streams
High Severity
MobileSimulatorStreamSelectionCoordinator tracks one global activeSelection, while the store and restartActiveMobileSimulatorStreams keep per-workspace actives. After a selection in another workspace—or a clear whose from does not match the coordinator—the drain can stop the wrong panel. cancel also leaves activeSelection stale across disconnect/reconnect, so later UI actions diverge from the store.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 9eedc37. Configure here.


Summary
Testing
./scripts/reload.sh --tag simvisIssues
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Note
Medium Risk
Changes span mobile stream lifecycle, cross-panel RPC ordering, and shared shell ownership; mistakes could cause stale streams or split Simulator state, but the area is heavily covered by new unit and UI tests.
Overview
iOS adds workspace chrome for Mac Simulator streaming: a one-tap Simulator toolbar control (hidden when unsupported or no panels), New Simulator Tab in the terminal picker when the Mac advertises create capability, and return navigation back to the prior terminal/browser surface.
Simulator selection and stream RPCs move into
MobileShellCompositewith a serializedMobileSimulatorStreamSelectionCoordinator, and the composite now owns a non-optionalMobileSimulatorStreamStoreso UI and RPC callbacks cannot drift onto different instances. Re-selecting a panel preserves locked / stalled / disconnected overlays instead of forcing a fresh “starting” state.End-to-end
mobile.simulator.createis added (capability id, Mac host handler, ticket/RPC client wiring, iOS client + composite refresh/create helpers).App shell structure:
MobileShellUISessionholds the store plus browser/simulator/terminal environment graph;GhosttyRuntimeOwnerinitializes Ghostty once at app composition with a retryable failure UI instead of per-surface init.macOS exposes create on the mobile RPC path, advertises the create capability with the simulator feature flag, renames user-facing strings from “pane” to tab, and speeds simulator device-picker label building. A config test asserts the default surface tab bar still omits a Simulator button when no explicit config exists.
Reviewed by Cursor Bugbot for commit 9eedc37. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Improves Simulator discoverability on iOS with a one‑tap control, adds in‑app Simulator tab creation and navigation, and keeps stream starts/stops ordered. Terminal rendering is now process‑lifetime with retry; iOS loads Ghostty config from an app‑owned path; macOS keeps the default tab bar without a Simulator button.
New Features
simulator.stream.create.v1is present.mobile.simulator.createRPC andMobileSimulatorStreamCapability.createIdentifier; exposed viaMobileHostService/MobileCoreRPCClient, withsupportsSimulatorStreamCreategating the UI and Terminal picker.MobileShellUISession; DEBUG addsSimulatorDiscoverabilityPreviewViewviaCmuxMobileShellDebugSupport. Terminal rendering moves to process‑lifetimeGhosttyRuntimeOwnerwith retry; iOS Ghostty config loads from an app‑owned file; strings/docs use “Simulator Tab”.Bug Fixes
MobileSimulatorStreamSelectionCoordinatorto prevent overlapping RPCs; reselecting preserves locked/stalled/disconnected overlays.MobileSimulatorStreamStoreeverywhere so selection stays accurate during navigation.Written for commit 9eedc37. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes
Tests