Skip to content

iOS: workspace surface inventory with per-kind fallback cards (workspace.surfaces.v1) - #8620

Closed
azooz2003-bit wants to merge 6 commits into
mainfrom
feat-ios-surface-inventory
Closed

azooz2003-bit wants to merge 6 commits into
mainfrom
feat-ios-surface-inventory

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jul 22, 2026 •

Copy link
Copy Markdown
Collaborator

Wave 0 of the iOS all-surfaces program: every Mac tab (all 11 SurfaceKinds, not just terminals) now syncs to the phone and appears in the surface picker with a per-kind icon; kinds without a native renderer yet show an informative fallback card with a working "Open on Mac" action.

Wire. New open-string MobileSurfaceKind constants in CMUXMobileCore (unknown kinds round-trip and route to the fallback card, so future kinds like simulator degrade gracefully). WorkspaceSyncRecord gains an optional surfaces array {surface_id, kind, title, file_path?}, stamped by a single mobileSurfaceDescriptors(in:) builder into BOTH sync-v2 rows and the legacy mobile.workspace.list payload (fidelity test asserts parity, including file_path). Descriptor fields are deliberately limited to what the workspace-list observer's summary hash already covers, so nothing on the wire can go silently stale; focus/URL/running-state fields are excluded on purpose and arrive with the waves that add their publishers. Capabilities: workspace.surfaces.v1, plus a new mobile.surface.focus RPC that reuses the control socket's surface.focus path (including window/workspace activation) with an explicit workspace-scoped ticket-authorization entry and a scoped-ticket denial test.

iOS. Surfaces flow through applyStateSyncProjection → legacy response DTO → MobileSurfacePreview (this projection previously dropped any non-terminal field). Selection is two-axis: selectedTerminalID and all its call sites are untouched; non-terminal Mac surfaces are explicit-tap only, so entering a workspace still lands on the terminal exactly as today, and the terminal stays permanently mounted under the card (opacity swap). The picker gains a "Mac Surfaces" section with per-kind SF Symbols; exactly one row carries the checkmark (checkedRowID, unit-tested). All new strings localized EN+JA.

In-flight coordination. This is deliberately minimal at contested seams: no picker rewrite, no browser selection behavior. #8188 (layout.v1) and #8289 (pane rack) carry layout/navigation payloads and can rebase their per-surface typing onto these shared kind constants whichever way the direction pick goes; #8298 stays authoritative for browser streaming and its "Mac Browsers" section folds into the kind-grouped list at rebase time. Browser tabs here are inventory-only cards until 8298 lands.

Verification. CMUXMobileCore 276 tests, CmuxMobileShellModel 166 tests, focused RPC/shell/state-sync suites, pbxproj wiring lint, package-group + Package.resolved policy checks, EN/JA localization audit for every new key, arm64 iOS simulator app build, and a Blacksmith cloud macOS build of tag iosrf. Note: main's macOS build is currently broken by an unrelated actor-initializer error from #8521; the tagged build applied the one-line fix from #8604 as an uncommitted overlay. This PR does not touch that file.

Next waves (specs staged): todo checklist renderer, panel-scoped file read context, filePreview/markdown viewers, agentSession chat binding, project snapshot, diff routing via #8221, generic frame-stream scaffold for the Simulator pane (#7857).

🤖 Generated with Claude Code


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


Summary by cubic

Syncs all Mac workspace surfaces to iOS and shows them in the picker with per‑kind icons. Unknown kinds render a fallback card with an “Open on Mac” action that focuses the surface on the Mac and shows a friendly error if the Mac can’t be reached.

  • New Features

    • Wire (CMUXMobileCore): added WorkspaceSyncRecord.surfaces {surface_id, kind, title, file_path?} and open‑string MobileSurfaceKind constants; included in sync‑v2 and legacy mobile.workspace.list; host advertises workspace.surfaces.v1 and surface.focus.v1; new mobile.surface.focus RPC implemented via TerminalController+MobileSurfaces and routed through surface.focus.
    • iOS (CmuxMobileRPC, CmuxMobileShellModel, CmuxMobileShellUI): new MobileSurfacePreview, a “Mac Surfaces” picker section with SF Symbols per kind, independent non‑terminal selection via selectedMacSurfaceID, and exactly one checked row; SurfaceFallbackCardView with EN/JA strings and an “Open on Mac” button.
  • Bug Fixes

    • Focus failure feedback: focusSurfaceOnMac reports success; the fallback card shows a localized error when unreachable; capability checks centralized and shared selectedMacSurface lookup lives on the workspace preview; checkmark resolution consistently picks a single row, including browser overlay and stale selections.
    • Tests assert canonical PanelType → wire‑kind strings and legacy vs sync surface inventory parity (including file_path); ticket authorization updated for mobile.surface.focus; unknown kind preservation and proper decoding when surfaces is absent covered.

Written for commit e505fb0. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added per-workspace “Mac surfaces” inventory (surface kind, title, and optional file path) to mobile workspace views and the workspace list.
    • Added Mac-surface selection to the terminal picker, plus an “Open on Mac” flow with new labels/icons and a fallback card when rendered on your Mac.
    • Added Mac surface focus support, letting mobile request focusing a selected surface on the owning Mac.
  • Bug Fixes
    • Improved state sync and decoding so missing surface inventories behave correctly and unknown surface kinds are preserved.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds Mac-rendered surface inventories to mobile workspace payloads and state sync, projects them into iOS models, supports explicit surface selection and fallback presentation, and adds capability-gated, workspace-authorized RPC focusing on the owning Mac.

Changes

Surface inventory and focus flow

Layer / File(s) Summary
Surface contracts and model projection
Packages/Shared/CMUXMobileCore/..., Packages/iOS/CmuxMobileRPC/..., Packages/iOS/CmuxMobileShellModel/...
Adds optional wire-level surface records, known and unknown surface-kind handling, RPC response DTOs, and iOS preview models with legacy decoding behavior.
Mac inventory generation and synchronization
Sources/TerminalController+MobileSurfaces.swift, Sources/TerminalController+MobileWorkspaceList.swift, Sources/Mobile/..., Sources/Workspace+SurfaceNavigation.swift, Sources/Panels/Panel.swift, cmuxTests/..., cmux.xcodeproj/project.pbxproj
Maps ordered panels to surface descriptors and emits matching inventories through workspace-list and state-sync payloads, with mapping and fidelity tests.
Surface focus RPC
Sources/TerminalController.swift, Sources/TerminalController+MobileSurfaces.swift, Sources/Mobile/..., Packages/iOS/CmuxMobileRPC/...
Routes mobile.surface.focus, validates identifiers and routing, applies workspace ticket authorization, advertises capabilities, and exposes the iOS client method.
Shell state and surface selection
Packages/iOS/CmuxMobileShell/...
Projects inventories into shell state, tracks Mac-surface selection independently from terminal selection, validates stale selections, and invokes focus through capability-aware routing.
Surface picker and fallback presentation
Packages/iOS/CmuxMobileShellUI/..., ios/cmux/Resources/Localizable.xcstrings
Adds Mac-surface picker rows, active-surface derivation, localized presentation, and a fallback card with an Open on Mac action.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Picker
  participant MobileShellComposite
  participant MobileCoreRPCClient
  participant TerminalController
  Picker->>MobileShellComposite: selectMacSurface(surfaceID)
  MobileShellComposite->>MobileCoreRPCClient: focusSurface(workspaceID, surfaceID)
  MobileCoreRPCClient->>TerminalController: mobile.surface.focus
  TerminalController-->>MobileCoreRPCClient: focus result
  MobileCoreRPCClient-->>MobileShellComposite: success or error
Loading

Possibly related PRs

  • manaflow-ai/cmux#8188: Extends the same iOS workspace-list decoding pipeline with additional workspace presentation data.
  • manaflow-ai/cmux#8207: Also extends MobileSyncWorkspaceListResponse.Workspace with an optional wire-backed field.
  • manaflow-ai/cmux#8284: Introduces the Mobile State Sync v2 record infrastructure extended by this change.

Suggested reviewers: lawrencecchen


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift @Concurrent ❌ Error MobileCoreRPCClient.focusSurface is async network work called from the UI path without @concurrent, so it can inherit the caller actor under Swift 6 rules. Annotate MobileCoreRPCClient.focusSurface with @concurrent (or hop via a detached/off-main helper) so the RPC request leaves MainActor; keep focusSurfaceOnMac UI-bound.
Cmux Swift Package Boundaries ❌ Error It adds reusable surface-kind mapping and descriptor building in app-target Sources/, and those helpers feed both sync-v2 and legacy payloads, so shared domain logic isn’t behind a package. Move the mapping and inventory builder into a small SwiftPM target (e.g. CmuxMobileSurfaceInventory) and expose a pure MobileSurfaceInventory/descriptor API; keep app files as glue only.
Cmux Architecture Rethink ❌ Error TerminalController+MobileSurfaces.swift duplicates the PanelType→kind switch already in Workspace.surfaceKind(for:), and tests only enforce parity, leaving two owners for the same wire mapping. Move the canonical PanelType→kind mapping into one shared helper/type, then have both Workspace and TerminalController call it instead of maintaining separate switches.
Docstring Coverage ⚠️ Warning Docstring coverage is 42.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (21 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PASS: New models are plain Sendable structs, UI/store code stays on @MainActor types, and the RPC client extension adds only a method to an immutable Sendable class.
Cmux Swift Blocking Runtime ✅ Passed Diff adds async/await and state updates only; no new semaphores, waits, sleeps, syncs, or locks were introduced.
Cmux Browser Automation Off-Main ✅ Passed This commit only changes surface-inventory UI/model files; no browser.* socket command, worker-routing, or policy-test changes appear in the diff.
Cmux Expensive Synchronous Load ✅ Passed No changed file adds or moves agent-history/transcript/JSONL loading onto a main-actor or interactive path; the new surface-focus path is async RPC/UI only.
Cmux Cache Substitution Correctness ✅ Passed State-sync/list snapshots read live panels and surfaces directly; the only cache is notification-preview memoization keyed by notification ID+timestamp, so staleness is checked.
Cmux No Hacky Sleeps ✅ Passed PASS — the PR only changes Swift, pbxproj, and localization files; no covered runtime scripts were added, so the no-hacky-sleeps rule doesn’t apply.
Cmux Algorithmic Complexity ✅ Passed PASS: the new surface lookups are single linear scans over one workspace’s data; no nested rescans or hot-path sorts/filters were introduced.
Cmux Swift Concurrency ✅ Passed No new legacy async patterns; added Tasks are UI/callback-bound and stored/cancelled, and no new Combine, DispatchQueue, or completion-handler APIs were introduced.
Cmux Swiftpm Lockfiles ✅ Passed No Package.swift, .gitignore, or Package.resolved files changed; the pbxproj diff only adds source/test file refs, not SwiftPM package references.
Cmux Swift Logging ✅ Passed No added or changed production Swift logging; diff scan found zero logging-related additions, and the existing WorkspaceDetailView NSLog was unchanged.
Cmux User-Facing Error Privacy ✅ Passed New UI/RPC errors are generic (“Couldn’t reach your Mac”, “Workspace not found”) and expose no vendor, credential, or raw upstream details.
Cmux Full Internationalization ✅ Passed New user-facing Swift copy uses L10n.string/defaultValue, and every new mobile.surface.* key in Localizable.xcstrings has en and ja translations.
Cmux Swiftui State Layout ✅ Passed No new forbidden SwiftUI state-layout patterns: rows use immutable snapshots/actions, no new ObservableObject/@Published/GeometryReader, and the geometry hook is preexisting.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS: The touched Swift files add views/models/RPC plumbing only; no NSWindow/NSPanel/NSWindowController/WindowGroup code or cmuxAuxiliaryWindowIdentifiers changes were introduced.
Cmux Source Artifacts ✅ Passed All changed paths are source/test/config/localization files; no logs, build outputs, caches, temp dirs, or other artifact paths appear in the PR diff.
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS — the touched production files add only real product APIs/helpers; no new #if DEBUG or test-only seams, and the widened workspaceRow feeds surface sync.
Cmux No Ambient Global State ✅ Passed New behavior is scoped to extensions/value types; I found no new file-scope API, mutable global, static-only namespace, or singleton.
Title check ✅ Passed The title clearly summarizes the primary change: adding iOS workspace surface inventory and per-kind fallback cards.
Description check ✅ Passed The description provides a detailed summary and verification details, but it omits the template's Demo Video, Review Trigger, and Checklist sections.
✨ 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 feat-ios-surface-inventory

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 Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds Mac workspace surface inventory and fallback rendering on iOS. The main changes are:

  • Syncs all workspace surface kinds through legacy and state-sync payloads.
  • Adds forward-compatible surface models and picker rows on iOS.
  • Shows localized fallback cards for surfaces without native renderers.
  • Adds workspace-authorized RPC routing to focus a surface on its Mac.
  • Reports focus failures when the owning Mac is unavailable.

Confidence Score: 5/5

The latest focus-failure changes look safe to merge.

  • Focus requests now return an explicit result for missing clients and RPC failures.
  • The fallback card turns failed requests into visible, localized feedback.
  • No additional qualifying production issue remains in the reviewed fix.

Important Files Changed

Filename Overview
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SurfaceFocus.swift Returns explicit success or failure for surface-focus requests across foreground and secondary Macs.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SurfaceFallbackCardView.swift Displays localized feedback when a surface-focus request cannot reach the owning Mac.

Reviews (4): Last reviewed commit: "Address review: focus-failure feedback, ..." | Re-trigger Greptile

Comment on lines +24 to +33
let target = workspaceMutationTarget(for: workspaceID)
guard let client = target.client else { return }
do {
try await client.focusSurface(
workspaceID: workspace.rpcWorkspaceID.rawValue,
surfaceID: surfaceID.rawValue
)
} catch {
if target.isForeground { markMacConnectionUnavailableIfNeeded(after: error) }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Secondary Focus Failures Stay Silent

When a secondary Mac still advertises this capability but has no live client, or its RPC fails, this action returns without changing connection state or reporting failure. The enabled “Open on Mac” button then appears to work but produces no visible result, leaving users unable to distinguish an unavailable Mac from a successful focus request.

@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 `@cmuxTests/MobileSurfaceKindMappingTests.swift`:
- Around line 12-18: Update mobileAndWorkspaceMappingsStayExhaustivelyInParity
to define the canonical expected PanelType-to-MobileSurfaceKind mapping for
every PanelType case, then assert each controller.mobileSurfaceKind result
against that expected value (and retain the workspace comparison if useful).
Compare typed enum values or canonical raw values directly so the test cannot
pass when both implementation mappings are identically incorrect.

In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView`+DerivedState.swift:
- Around line 11-18: The selected non-terminal Mac surface lookup is duplicated
and inconsistently filters terminal surfaces. Add a shared
MobileWorkspacePreview.selectedMacSurface(_:) helper containing the id and
!kind.isTerminal predicate, then use it in
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift:4306-4311
within selectMacSurface,
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift:92-98
within activeSurface, and
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+DerivedState.swift:11-18
within selectedToolbarSubtitle.

In `@Sources/TerminalController`+MobileSurfaces.swift:
- Around line 73-78: Replace the internal “TabManager not available” message
with the product-level “Workspace context is unavailable” message in both
error-return branches of the mobile surface routing flow: the guard using
controlSurfaceRoutingResolvesTabManager and the .tabManagerUnavailable case in
controlSurfaceFocus. Keep the existing error code and data unchanged.
🪄 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: 5cec1db3-4a31-475e-b588-401ad2091b03

📥 Commits

Reviewing files that changed from the base of the PR and between 4daa937 and 8b1b194.

📒 Files selected for processing (41)
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileStateSyncRecords.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileSurfaceKind.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/MobileStateSyncFrameCodingTests.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient+SurfaceFocus.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileSyncWorkspaceListResponse.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileWorkspacePreview+RemoteMapping.swift
  • Packages/iOS/CmuxMobileRPC/Tests/CmuxMobileRPCTests/MobileSurfaceInventoryTests.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+StateSync.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SurfaceFocus.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellCompositePreviewTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellStateSyncTests.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileSurfacePreview.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileWorkspacePreview.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileSurfacePreview+Presentation.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SurfaceFallbackCardView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalPickerMenu.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalPickerMenuActions.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalPickerMenuValue.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceActiveSurface.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+DerivedState.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+MenuState.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+Surfaces.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/TerminalPickerMenuValueTests.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceActiveSurfaceTests.swift
  • Sources/Mobile/MobileHostService+Capabilities.swift
  • Sources/Mobile/MobileHostService+TicketAuthorization.swift
  • Sources/Mobile/MobileStateSync.swift
  • Sources/Panels/Panel.swift
  • Sources/TerminalController+MobileSurfaces.swift
  • Sources/TerminalController+MobileWorkspaceList.swift
  • Sources/TerminalController.swift
  • Sources/Workspace+SurfaceNavigation.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/MobileHostConnectionLifecycleTests.swift
  • cmuxTests/MobileHostWorkspaceTicketAuthorizationTests.swift
  • cmuxTests/MobileSurfaceKindMappingTests.swift
  • cmuxTests/MobileWorkspaceListFidelityTests.swift
  • ios/cmux/Resources/Localizable.xcstrings

Comment thread cmuxTests/MobileSurfaceKindMappingTests.swift Outdated
Comment thread Sources/TerminalController+MobileSurfaces.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.

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
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SurfaceFallbackCardView.swift`:
- Around line 11-12: Scope the focus state in SurfaceFallbackCardView to the
current surface by resetting focusFailed and cancelling and clearing focusTask
whenever surface.id changes, or apply a stable .id(surface.id.rawValue) to
recreate the card per surface. Preserve the existing focus behavior while
preventing state from one surface leaking into another.
🪄 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: 260d0204-7492-45d7-a300-44ec8fce22d8

📥 Commits

Reviewing files that changed from the base of the PR and between 8b1b194 and 84b1a91.

📒 Files selected for processing (9)
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SurfaceFocus.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileWorkspacePreview.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SurfaceFallbackCardView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+DerivedState.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+Surfaces.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift
  • Sources/TerminalController+MobileSurfaces.swift
  • cmuxTests/MobileSurfaceKindMappingTests.swift
  • ios/cmux/Resources/Localizable.xcstrings

Comment on lines +11 to +12
@State private var focusFailed = false
@State private var focusTask: Task<Void, Never>?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the target file with line numbers
sed -n '1,220p' Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SurfaceFallbackCardView.swift | cat -n

printf '\n---\n'

# Find where this view is used
rg -n "SurfaceFallbackCardView|focusSurfaceOnMac|focusTask|focusFailed" Packages/iOS/CmuxMobileShellUI -S

Repository: manaflow-ai/cmux

Length of output: 3729


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+Surfaces.swift | cat -n

printf '\n---\n'

# Show any explicit identity used for the fallback card or its enclosing branch
rg -n "\.id\(|ForEach|SurfaceFallbackCardView|surfaceID|surface.id|workspaceID" Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+Surfaces.swift -n -S

Repository: manaflow-ai/cmux

Length of output: 3922


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "func focusSurfaceOnMac|focusSurfaceOnMac\(" Packages/iOS/CmuxMobileShellUI Packages -S

printf '\n---\n'

# Read the implementation if found
file=$(rg -l "func focusSurfaceOnMac|focusSurfaceOnMac\(" Packages -S | head -n 1 || true)
if [ -n "${file:-}" ]; then
  sed -n '1,260p' "$file" | cat -n
fi

Repository: manaflow-ai/cmux

Length of output: 4077


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,260p' Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SurfaceFocus.swift | cat -n

Repository: manaflow-ai/cmux

Length of output: 2163


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check whether the fallback card has an explicit identity or whether the parent branch is the only identity boundary.
rg -n "\.id\(|SurfaceFallbackCardView\(" Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI -S

Repository: manaflow-ai/cmux

Length of output: 830


Scope the task to the selected surface.

focusFailed and focusTask can be reused when SurfaceFallbackCardView stays mounted at the same structural position and surface.id changes, so a failed focus attempt for one Mac surface can leak into the next one. Cancel and clear that state when surface.id changes, or give the card a stable .id(surface.id.rawValue) so each surface gets its own task/state lifetime.

🤖 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/SurfaceFallbackCardView.swift`
around lines 11 - 12, Scope the focus state in SurfaceFallbackCardView to the
current surface by resetting focusFailed and cancelling and clearing focusTask
whenever surface.id changes, or apply a stable .id(surface.id.rawValue) to
recreate the card per surface. Preserve the existing focus behavior while
preventing state from one surface leaking into another.

@azooz2003-bit
azooz2003-bit force-pushed the feat-ios-surface-inventory branch from 84b1a91 to 98646cb Compare July 22, 2026 06:26

@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)
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift (1)

78-82: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Do not use a sleeping watchdog to release reconnect state.

This task clears isReconnectingStoredMac after 15 seconds even if reconnectActiveMacOutcome is still reading stores or dialing. A retry can therefore start while the previous reconnect remains active, leaving overlapping operations and duplicate state ownership. Tie the visible state to the reconnect operation’s explicit completion/cancellation instead of a second delayed task.

As per coding guidelines and path instructions, production Swift must not add ContinuousClock.sleep/delayed coordination as a lifecycle-race repair path; use an explicit owner and completion signal instead.

Also applies to: 1016-1023, 1813-1827

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`
around lines 78 - 82, Remove the sleeping/deadline-based release of
isReconnectingStoredMac, including storedMacReconnectRestoringDeadlineSeconds
and its related delayed-task logic. In reconnectActiveMacOutcome and the
surrounding stored-Mac reconnect flow, keep the reconnect state owned until the
operation explicitly completes or is cancelled, then clear it through that
completion path so retries cannot overlap an active reconnect.

Sources: Coding guidelines, 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 `@cmux.xcodeproj/project.pbxproj`:
- Line 1121: Replace the duplicated PBXBuildFile and PBXFileReference UUIDs used
by MobileSurfaceKindMappingTests.swift and
TerminalController+MobileSurfaces.swift with unique identifiers. Update each
file’s PBXFileReference, PBXBuildFile, group membership, and Sources build-phase
references consistently throughout the project object graph.

---

Outside diff comments:
In
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`:
- Around line 78-82: Remove the sleeping/deadline-based release of
isReconnectingStoredMac, including storedMacReconnectRestoringDeadlineSeconds
and its related delayed-task logic. In reconnectActiveMacOutcome and the
surrounding stored-Mac reconnect flow, keep the reconnect state owned until the
operation explicitly completes or is cancelled, then clear it through that
completion path so retries cannot overlap an active reconnect.
🪄 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: b7fd237e-9a07-4a1a-99ac-b09d68cbdb5b

📥 Commits

Reviewing files that changed from the base of the PR and between 84b1a91 and 98646cb.

📒 Files selected for processing (36)
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileStateSyncRecords.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileSurfaceKind.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/MobileStateSyncFrameCodingTests.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient+SurfaceFocus.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileSyncWorkspaceListResponse.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileWorkspacePreview+RemoteMapping.swift
  • Packages/iOS/CmuxMobileRPC/Tests/CmuxMobileRPCTests/MobileSurfaceInventoryTests.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+StateSync.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SurfaceFocus.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellCompositePreviewTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellStateSyncTests.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileSurfacePreview.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileWorkspacePreview.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileSurfacePreview+Presentation.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SurfaceFallbackCardView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalPickerMenu.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalPickerMenuActions.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalPickerMenuValue.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceActiveSurface.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+DerivedState.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+MenuState.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+Surfaces.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/TerminalPickerMenuValueTests.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceActiveSurfaceTests.swift
  • Sources/Mobile/MobileHostService+Capabilities.swift
  • Sources/Mobile/MobileHostService+TicketAuthorization.swift
  • Sources/Mobile/MobileStateSync.swift
  • Sources/Panels/Panel.swift
  • Sources/TerminalController+MobileSurfaces.swift
  • Sources/TerminalController+MobileWorkspaceList.swift
  • Sources/TerminalController.swift
  • Sources/Workspace+SurfaceNavigation.swift
  • cmux.xcodeproj/project.pbxproj

Comment thread cmux.xcodeproj/project.pbxproj
cmux reload-cloud and others added 4 commits July 22, 2026 15:42
…rt parity

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…cal kind assertions

Greptile P2: focusSurfaceOnMac now reports success and the fallback card
shows a localized caption when the Mac can't be reached instead of
silently doing nothing. CodeRabbit: the selected-Mac-surface predicate
lives once on MobileWorkspacePreview (one copy had dropped the
non-terminal clause), the kind-mapping test asserts canonical wire
strings rather than mere parity, and the surface-focus error message no
longer names TabManager.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@azooz2003-bit
azooz2003-bit force-pushed the feat-ios-surface-inventory branch from 98646cb to 5405e40 Compare July 22, 2026 22:42

@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 `@Sources/Workspace`+SurfaceNavigation.swift:
- Around line 13-18: Keep Workspace.surfaceKind(for:) as the sole canonical
PanelType-to-wire-kind mapping in
Sources/Workspace+SurfaceNavigation.swift:13-18. Update MobileSurfaceKind in
Sources/TerminalController+MobileSurfaces.swift:8-32 to delegate to that mapper
instead of defining a second switch, ensuring both legacy/state-sync and focus
inventories remain consistent.
🪄 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: 79b345c0-f19b-486c-add1-eabf1598c4de

📥 Commits

Reviewing files that changed from the base of the PR and between 98646cb and 5405e40.

📒 Files selected for processing (41)
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileStateSyncRecords.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileSurfaceKind.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/MobileStateSyncFrameCodingTests.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient+SurfaceFocus.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileSyncWorkspaceListResponse.swift
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileWorkspacePreview+RemoteMapping.swift
  • Packages/iOS/CmuxMobileRPC/Tests/CmuxMobileRPCTests/MobileSurfaceInventoryTests.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+StateSync.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SurfaceFocus.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellCompositePreviewTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellStateSyncTests.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileSurfacePreview.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileWorkspacePreview.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileSurfacePreview+Presentation.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/SurfaceFallbackCardView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalPickerMenu.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalPickerMenuActions.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalPickerMenuValue.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceActiveSurface.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+DerivedState.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+MenuState.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+Surfaces.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/TerminalPickerMenuValueTests.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceActiveSurfaceTests.swift
  • Sources/Mobile/MobileHostService+Capabilities.swift
  • Sources/Mobile/MobileHostService+TicketAuthorization.swift
  • Sources/Mobile/MobileStateSync.swift
  • Sources/Panels/Panel.swift
  • Sources/TerminalController+MobileSurfaces.swift
  • Sources/TerminalController+MobileWorkspaceList.swift
  • Sources/TerminalController.swift
  • Sources/Workspace+SurfaceNavigation.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/MobileHostConnectionLifecycleTests.swift
  • cmuxTests/MobileHostWorkspaceTicketAuthorizationTests.swift
  • cmuxTests/MobileSurfaceKindMappingTests.swift
  • cmuxTests/MobileWorkspaceListFidelityTests.swift
  • ios/cmux/Resources/Localizable.xcstrings

Comment on lines +13 to +18
Self.surfaceKind(for: panel.panelType)
}

/// Surface-kind mapping used by snapshots and mobile mapping parity tests.
static func surfaceKind(for panelType: PanelType) -> String {
switch panelType {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Keep the panel-to-mobile wire mapping in one place.

The same canonical PanelType → wire-kind table is now owned twice. Derive one mapper from the other (for example, create MobileSurfaceKind from Workspace.surfaceKind(for:)) so future panel kinds cannot make legacy/state-sync and focus inventories diverge.

  • Sources/Workspace+SurfaceNavigation.swift#L13-L18: retain or relocate the sole canonical mapping.
  • Sources/TerminalController+MobileSurfaces.swift#L8-L32: delegate to that canonical mapping instead of maintaining another switch.

As per coding guidelines, correctness-critical state must use “one reliable source of truth.”

📍 Affects 2 files
  • Sources/Workspace+SurfaceNavigation.swift#L13-L18 (this comment)
  • Sources/TerminalController+MobileSurfaces.swift#L8-L32
🤖 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 `@Sources/Workspace`+SurfaceNavigation.swift around lines 13 - 18, Keep
Workspace.surfaceKind(for:) as the sole canonical PanelType-to-wire-kind mapping
in Sources/Workspace+SurfaceNavigation.swift:13-18. Update MobileSurfaceKind in
Sources/TerminalController+MobileSurfaces.swift:8-32 to delegate to that mapper
instead of defining a second switch, ensuring both legacy/state-sync and focus
inventories remain consistent.

Sources: Coding guidelines, Path instructions

…ntory

# Conflicts:
#	Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellStateSyncTests.swift
#	Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalPickerMenu.swift
#	Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceActiveSurface.swift
#	Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+Surfaces.swift
#	Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift
#	Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceActiveSurfaceTests.swift
#	Sources/Mobile/MobileHostService+Capabilities.swift
#	cmux.xcodeproj/project.pbxproj
#	ios/cmux/Resources/Localizable.xcstrings
…-surface-inventory

# Conflicts:
#	cmux.xcodeproj/project.pbxproj
@lawrencecchen lawrencecchen added the stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening. label Sep 23, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in cmux backlog Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stale-revisit Closed after 30+ days without activity; preserved for possible revisit or reopening.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants