Skip to content

iOS: add terminal tab overview - #6370

Closed
austinywang wants to merge 43 commits into
mainfrom
issue-6347-ios-tab-overview
Closed

austinywang wants to merge 43 commits into
mainfrom
issue-6347-ios-tab-overview

Conversation

@austinywang

@austinywang austinywang commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Adds an iOS Safari-style All Tabs overview with a scrollable grid of terminal preview cards, close buttons, selection, tab count, Done, and + new-terminal actions.
  • Caches bounded full render-grid text previews for overview cards and adds mobile terminal close support through the shared mobile RPC path.
  • Adds a DEBUG simulator harness for deterministic tab-overview screenshots.

Screenshot

iOS terminal tab overview

Local path: cmux-assets/issue-6347-ios-tab-overview/ios-simulator/2026-06-17Tfinal/tab-overview-grid.png

Validation

  • swift test --package-path Packages/iOS/CmuxMobileShell --filter MobileShellCompositePreviewTests (17 tests passed)
  • CMUX_SKIP_ZIG_BUILD=1 ./ios/scripts/reload.sh --tag issue-6347-ios-tab-overview
  • jq empty ios/cmux/Resources/Localizable.xcstrings Resources/Localizable.xcstrings
  • git diff --check
  • Bare-English SwiftUI string scan over touched Swift files

Localization Audit

  • Changed surfaces: All Tabs toolbar/title, tab count, Done, New Terminal, close-terminal accessibility label, selected-state accessibility label, no-preview fallback, DEBUG Copy Debug Logs menu label, and the Mac-side terminal-close protected error.
  • Updated ios/cmux/Resources/Localizable.xcstrings for English and Japanese mobile UI strings.
  • Updated Resources/Localizable.xcstrings for the close-protected host message across existing locales.

Implements #6347.


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


Summary by cubic

Adds an iOS Safari‑style All Tabs overview with grid previews, quick selection, + New Terminal, Done, and per‑tab close. Keeps close controls accurate from the Mac, updates the nav‑title cap for the new overview button, and ships a DEBUG‑only preview shell for screenshots. Implements #6347.

  • New Features

    • Full‑screen cover with preview cards from live render‑grid and mobile.terminal.replay, selection, tab count, Done, and + New Terminal.
    • Per‑tab close via mobile.terminal.close; gated by terminal.close.v1 and per‑terminal can_close from the workspace list (hidden for last tab, pinned/confirm‑required/remote‑tmux, or when the Mac hides tab close).
    • Toolbar entry with localized strings and accessibility; DEBUG CMUX_UITEST_TERMINAL_OVERVIEW_PREVIEW mounts a connected preview shell and opens the overview for simulator screenshots (DEBUG‑only sources).
  • Bug Fixes

    • Keep can_close current: observe pin changes, close‑policy (UserDefaults), and shell‑activity via async streams; iOS refreshes before opening the overview.
    • Route terminal close through the mobile‑host seam; Mac rejects protected/last‑tab closes, clears per‑surface viewport state, and returns the refreshed workspace list; iOS ignores stale responses (latest wins) and reconciles from that response.
    • Overview previews: cache only full frames, ignore deltas, prune on tab changes, refresh stale/missing every 10s, and cap preview rows/scalars/bytes; keep overview RPC off the main actor and mark the mobile shell logger nonisolated.
    • Reserve nav‑title width for the picker + overview button (+ chat toggle) so titles don’t clip; use catalog plural for the tab‑count label.
    • Localize All Tabs UI and the Mac‑side close‑protected error; localize “Copy Debug Logs” in the DEBUG menu.

Written for commit 5f7e36d. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Terminal closing: Users can now close individual terminals. The system prevents closing the last terminal in a workspace to ensure continuity.
    • Terminal overview: New "All Tabs" view displays preview thumbnails of all terminals in a workspace for quick navigation and efficient multi-terminal management.

@vercel

vercel Bot commented Jun 18, 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 20, 2026 1:25pm
cmux-staging Building Building Preview, Comment Jun 20, 2026 1:25pm

@coderabbitai

coderabbitai Bot commented Jun 18, 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

Adds a Safari-style "All Tabs" terminal overview to the iOS app: a new SwiftUI full-screen cover presenting tab cards with text previews and a close affordance. The Mac host gains a mobile.terminal.close / terminal.close RPC handler that enforces single-terminal protection, and the iOS composite stores per-terminal preview snapshots fetched via mobile.terminal.replay. Capability advertisement, auth exemptions, localization, and UI test harness plumbing complete the stack.

Changes

Terminal Tab Overview Feature

Layer / File(s) Summary
Mac-side terminal close RPC and capability advertisement
Sources/TerminalController.swift, Sources/Mobile/MobileHostService+Capabilities.swift, Sources/Mobile/MobileHostService.swift, Packages/iOS/CmuxMobileRPC/.../MobileCoreRPCClient.swift
v2MobileTerminalClose validates workspace/surface, enforces ≥2-terminal guard, closes via closeSurfaceRecordingHistory, and returns the updated workspace list. terminal.close.v1 is advertised in capabilities, close methods are exempted from ticket-scope auth, and stack-auth fallback is extended to cover close RPCs.
Mac control socket protocol and bridging
Packages/macOS/CmuxControlSocket/.../ControlMobileHostContext.swift, ControlCommandCoordinator+MobileHost.swift, Sources/TerminalController+ControlMobileHostContext.swift, Packages/macOS/CmuxControlSocket/Tests/...
ControlMobileHostContext gains controlMobileTerminalClose, routing is wired in the coordinator for both method aliases, TerminalController bridges JSON params to the v2 handler, and tests verify alias routing and parameter forwarding.
MobileShellComposite state and capability wiring
Packages/iOS/CmuxMobileShell/.../MobileShellComposite.swift
Adds terminalOverviewPreviewLinesByID cache dictionary, supportsTerminalCloseActions feature gate, terminal.close.v1 in preview-host capabilities, workspace-change cache pruning hook, and internal access-level adjustments.
Terminal overview caching, refresh, close, and preview extraction
Packages/iOS/CmuxMobileShell/.../MobileShellComposite+TerminalOverview.swift, MobileShellComposite+TerminalOutputDelivery.swift
Implements async refreshTerminalOverviewPreviews (RPC-backed, client-guarded), closeTerminal dispatching to remote or preview paths, line truncation to 160 chars, full-frame snapshot capture in deliverTerminalRenderGrid, live-terminal cache pruning, and a DEBUG harness store factory.
SwiftUI terminal overview UI components
Packages/iOS/CmuxMobileShellUI/.../TerminalTabOverviewItem.swift, TerminalTabOverviewCard.swift, TerminalTabOverviewView.swift
TerminalTabOverviewItem data model; TerminalTabOverviewCard with preview lines, selection indicator, accessibility, and optional close button; TerminalTabOverviewView with adaptive LazyVGrid, bottom bar (new terminal, tab count, done), and singular/plural tab-count localization.
WorkspaceDetailView and Container wiring
Packages/iOS/CmuxMobileShellUI/.../WorkspaceDetailView.swift, WorkspaceDetailContainer.swift
Adds closeTerminal callback and isTabOverviewPresented state; inserts "All Tabs" toolbar button and fullScreenCover across all three UI modes (chat, browser, terminal); computes terminalOverviewItems and terminalOverviewRefreshKey; WorkspaceDetailContainer conditionally supplies closeTerminalClosure; localizes "Copy Debug Logs" label.
UI test config, harness entry point, and localization
Packages/iOS/CmuxMobileSupport/.../UITestConfig.swift, ios/cmuxPackage/.../CMUXMobileRootScene.swift, ios/cmux/Resources/Localizable.xcstrings, Resources/Localizable.xcstrings
UITestConfig.terminalOverviewPreviewEnabled reads CMUX_UITEST_TERMINAL_OVERVIEW_PREVIEW; CMUXMobileRootScene branches on it to mount the harness store; localization adds overview UI strings and close-blocked error messages across 17+ locales.
Preview mode and end-to-end tests
Packages/iOS/CmuxMobileShell/Tests/.../MobileShellCompositePreviewTests.swift, cmuxTests/TerminalAndGhosttyTests.swift
Five preview-mode tests cover close neighbor selection, last-terminal protection, preview line extraction, cache pruning, and delta-frame bypass. One end-to-end test verifies terminal.close returns the refreshed workspace list with the closed terminal absent.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(70, 130, 180, 0.5)
    note over WorkspaceDetailView,MobileShellComposite: All Tabs Overview Refresh
    WorkspaceDetailView->>MobileShellComposite: .task(id: terminalOverviewRefreshKey)
    MobileShellComposite->>MobileShellComposite: refreshTerminalOverviewPreviews(in: workspaceID)
    loop per terminal
      MobileShellComposite->>MacHost: mobile.terminal.replay
      MacHost-->>MobileShellComposite: render-grid rows
      MobileShellComposite->>MobileShellComposite: cache preview lines (if client still current)
    end
    MobileShellComposite-->>WorkspaceDetailView: terminalOverviewItems updated
  end
  rect rgba(180, 100, 60, 0.5)
    note over WorkspaceDetailView,MacHost: Close Terminal (remote)
    WorkspaceDetailView->>WorkspaceDetailContainer: onClose(terminalID)
    WorkspaceDetailContainer->>MobileShellComposite: closeTerminal(id:in:)
    MobileShellComposite->>MacHost: mobile.terminal.close
    alt ≥2 terminals remain
      MacHost-->>MobileShellComposite: updated workspaces list
      MobileShellComposite->>MobileShellComposite: clear preview cache, applyRemoteWorkspaceList
    else last terminal
      MacHost-->>MobileShellComposite: error (protected)
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

  • manaflow-ai/cmux#6022: Both PRs extend requestNeedsStackAuthFallback in MobileCoreRPCClient.swift with additional terminal/workspace RPC method cases for authorization fallback handling.

Poem

🐇 Hop hop, now tabs are laid out in a grid,
Each terminal preview shown just like Safari did.
A tap to select, an X to close with care,
The last one standing — bunny guards it there!
Replay frames fetch the preview lines with flair,
And localized in languages beyond compare. 🌿


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 Blocking Runtime ❌ Error PR introduces blocking/timing primitives in production code: Task.sleep in MobileCoreRPCClient and MobileHostService; multiple NSLock instances in MobileHostService; DispatchSemaphore with .wait()... Replace Task.sleep timeouts with cancellable async sequences or real signals; convert NSLock usage to async actors where possible; remove DispatchSemaphore.wait() blocking calls in favor of MainActor message passing.
Cmux Algorithmic Complexity ❌ Error Three violations of algorithmic complexity rules: (1) pruneTerminalOverviewPreviewCacheForLiveTerminals() rescans all workspaces with flatMap+filter+contains on every workspaces didSet (hot path);... Cache the live terminal IDs set as a property; use @State for terminalOverviewItems; memoize terminalOverviewRefreshKey or use explicit bounds (e.g., max 50 terminals per workspace with documented scale).
Cmux No Test Or Debug Seam In Production Source ❌ Error Public method terminalOverviewPreviewHarnessStore() in production source Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TerminalOverview.swift is a #if DEBUG test harne... Move terminalOverviewPreviewHarnessStore to a test-support module or test target, making MobileShellComposite code accessible via @testable import if needed. See #6452 for reference.
Docstring Coverage ⚠️ Warning Docstring coverage is 17.46% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (19 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly and concisely summarizes the main feature: adding a terminal tab overview to iOS, which is the primary objective of the changeset.
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 No Swift 6 actor isolation issues found. MobileShellComposite and stores are @MainActor; loggers marked nonisolated; async background work properly delegated to nonisolated static helpers; UI types...
Cmux Expensive Synchronous Load ✅ Passed PR adds iOS terminal tab overview with async/await patterns properly applied. All expensive operations (RPC calls, preview generation) are async; closeTerminal and refreshTerminalOverviewPreviews p...
Cmux Cache Substitution Correctness ✅ Passed Cache is transient (in-memory, non-persisted), not in a history/undo/snapshot path. Cold cache returns nil with ?? [] fallback; event-driven refresh via terminalOverviewRefreshKey ensures cache can...
Cmux No Hacky Sleeps ✅ Passed PR contains only Swift and localization files; the check applies exclusively to TypeScript, JavaScript, shell, and non-Swift build/runtime scripts.
Cmux Swift Concurrency ✅ Passed Fire-and-forget Tasks in button action closures are acceptable at SwiftUI boundaries where synchronous callbacks are required; no DispatchQueue, Combine, or completion-handler patterns found.
Cmux Swift @Concurrent ✅ Passed Two new public async methods on @MainActor class correctly delegate network-heavy work to nonisolated static helpers (explicit actor hops), matching allowed pattern for UI-bound async functions.
Cmux Swift File And Package Boundaries ✅ Passed All new files are under 400 lines with clear single responsibilities; additions to existing files are under 250 lines; no mixed responsibilities detected; feature logic properly confined to SwiftPM...
Cmux Swiftpm Lockfiles ✅ Passed PR includes two new SwiftPM packages (CmuxMobileShellUI and ios/cmuxPackage) with both Package.swift and Package.resolved files committed, .gitignore files don't ignore Package.resolved, and root X...
Cmux Swift Logging ✅ Passed All logging in the PR complies with swift-logging.md: NSLog is DEBUG-only (allowed), new Logger declarations are properly nonisolated in @MainActor classes, and Logger calls use proper privacy anno...
Cmux User-Facing Error Privacy ✅ Passed Error message "This terminal can't be closed right now." is generic and doesn't expose vendor names, internal details, environment variables, credentials, or other sensitive information prohibited...
Cmux Full Internationalization ✅ Passed PR implements full internationalization: all user-facing Swift text uses L10n.string() or String(localized:), new xcstrings keys have complete translations for all supported locales (en/ja for iOS...
Cmux Swiftui State Layout ✅ Passed SwiftUI changes follow all rules: new views use value snapshots and closures (no store refs in LazyVGrid rows), single new @State for UI presentation with writes in event handlers only, no Observab...
Cmux Architecture Rethink ✅ Passed PR maintains clear single ownership: MobileShellComposite owns the terminal-overview preview cache with coherent updates from render-grid delivery, explicit refresh, and terminal-close handlers. No...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR adds iOS SwiftUI Views (TerminalTabOverviewView, TerminalTabOverviewCard) presented via fullScreenCover modal, not standalone windows. No NSWindow, NSPanel, NSWindowController, or SwiftUI Window...
Cmux Source Artifacts ✅ Passed All 24 changed files are legitimate source artifacts: 17 hand-written Swift source files, 5 Swift test files, and 2 localization catalogs (.xcstrings). No screenshots, binaries, generated files, De...
Description check ✅ Passed PR description covers what changed (All Tabs overview, terminal close support, DEBUG harness), why (implements #6347), testing approach, and includes screenshots and validation steps.
✨ 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-6347-ios-tab-overview

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 and usage tips.

@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/TerminalTabOverviewView.swift`:
- Around line 89-91: The String.localizedStringWithFormat call in the tab count
section uses the plural key mobile.terminal.overview.tabCount.many, which
diverges from the repository's ICU-style plural convention. Replace the .many
plural key with .other to align with the standard plural handling pattern used
throughout the repo (using .one and .other keys for ICU-style localization).
This ensures consistent plural handling across all supported locales.
🪄 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: e97fb8f2-714e-4ef7-9584-fad064cdb912

📥 Commits

Reviewing files that changed from the base of the PR and between 90f77dd and 263e082.

⛔ Files ignored due to path filters (1)
  • cmux-assets/issue-6347-ios-tab-overview/ios-simulator/2026-06-17Tfinal/tab-overview-grid.png is excluded by !**/*.png
📒 Files selected for processing (17)
  • Packages/iOS/CmuxMobileRPC/Sources/CmuxMobileRPC/MobileCoreRPCClient.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TerminalOutputDelivery.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TerminalOverview.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellCompositePreviewTests.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalTabOverviewCard.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalTabOverviewItem.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalTabOverviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailContainer.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift
  • Packages/iOS/CmuxMobileSupport/Sources/CmuxMobileSupport/UITestConfig.swift
  • Resources/Localizable.xcstrings
  • Sources/Mobile/MobileHostService+Capabilities.swift
  • Sources/Mobile/MobileHostService.swift
  • Sources/TerminalController.swift
  • ios/cmux/Resources/Localizable.xcstrings
  • ios/cmuxPackage/Sources/cmuxFeature/CMUXMobileRootScene.swift
👮 Files not reviewed due to content moderation or server errors (1)
  • Sources/TerminalController.swift

@greptile-apps

greptile-apps Bot commented Jun 18, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds an iOS Safari-style "All Tabs" terminal overview feature: a full-screen grid of preview cards with selection, per-tab close, a tab count, Done, and New Terminal actions. It also wires up mobile.terminal.close as a new RPC command on both the Mac host and iOS client, with capability gating, protected-state checks, viewport cleanup, and a refreshed workspace-list response.

  • Adds TerminalTabOverviewView / TerminalTabOverviewCard / TerminalTabOverviewItem in CmuxMobileShellUI, driven by MobileShellComposite+TerminalOverview.swift which caches bounded plain-text render-grid previews, prunes stale entries on workspace changes, and staleness-refreshes every 10 s via mobile.terminal.replay.
  • Adds v2MobileTerminalClose on the Mac (TerminalController.swift) with last-tab protection, canClosePanelWithoutPrompt gating, viewport-report cleanup, and workspace-list response; propagates can_close per terminal through MobileSyncWorkspaceListResponse and MobileWorkspacePreview+RemoteMapping; adds a closePolicyChangeSignals async stream in MobileWorkspaceListObserver to re-emit when UserDefaults close-warning prefs change, plus pinnedPanelIds and per-workspace shell-activity stream observations to keep can_close current.
  • Adds a DEBUG-only MobileShellComposite+TerminalOverviewPreviewHarness.swift (in the dedicated Debug/ folder), a CMUXMobilePreviewShellView wrapper, and UITestConfig.terminalOverviewPreviewEnabled for deterministic simulator screenshots; ships full en/ja localization for all new iOS strings and updates the Mac Localizable.xcstrings for the mobile.terminal.closeBlocked.message key.

Confidence Score: 5/5

Safe to merge — the terminal close path is correctly protected against the last-tab case on both sides, capability gating is end-to-end, and the can_close staleness signals are all wired and cleaned up.

The Mac-side close handler properly short-circuits before calling the side-effectful mobileCloseSurfaceRecordingHistoryIfAllowed when only one terminal remains. The iOS generation counter correctly discards stale responses from concurrent close requests. The debug harness is correctly isolated to the Debug/ folder and guarded by #if DEBUG. Localization coverage matches the iOS catalog's two-locale surface. No logic gaps or data-race risks were found across the full diff.

No files require special attention.

Important Files Changed

Filename Overview
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TerminalOverview.swift New 230-line extension handling overview preview caching, staleness refresh, remote close RPC, and preview-mode fallback. Generation-counter pattern for stale-response handling is correct; nonisolated static RPC helpers keep network work off the main actor.
Sources/TerminalController.swift Adds v2MobileTerminalClose with last-tab guard, canClosePanelWithoutPrompt delegation, viewport-report cleanup, and refreshed workspace list response. Side-effectful guard pattern in mobileCloseSurfaceRecordingHistoryIfAllowed is intentional and correctly short-circuits on last-terminal.
Sources/Workspace.swift Adds panelShellActivityStateChanges() async stream, canClosePanelWithoutPrompt, and requestNonInteractiveCloseTabRecordingHistoryIfAllowed. Fan-out notification and weak-self cleanup in onTermination are correct.
Sources/Mobile/MobileWorkspaceListObserver.swift Adds three new observation sources: UserDefaults close-policy signals, pinnedPanelIds Combine publisher, and per-workspace shell-activity async stream. All cancel in deinit; summary-hash folds in can_close so stale mobile controls self-correct.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView.swift Adds overview toolbar button, full-screen cover, and tab-overview projection. The fullScreenCover modifier is correctly duplicated across each platform-conditional toolbar branch; terminalOverviewRefreshKey restarts the fetch task on workspace/connection changes.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalTabOverviewView.swift New view with LazyVGrid, adaptive columns, bottom toolbar with tab count/Done/New. All strings routed through L10n with catalog-backed keys.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TerminalTabOverviewCard.swift New card view with close button, selection indicator, and monospaced text preview. Accessibility labels and identifiers are present. Preview line rendering is bounded.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/Debug/MobileShellComposite+TerminalOverviewPreviewHarness.swift DEBUG-only harness in the dedicated Debug/ folder; entirely wrapped in #if DEBUG and used only from CMUXMobileRootScene's debug launch path. Correctly isolated from production sources.
ios/cmux/Resources/Localizable.xcstrings Adds all new overview string keys with both en and ja translations. The iOS catalog only supports these two locales, so coverage is complete.
Resources/Localizable.xcstrings Adds mobile.terminal.closeBlocked.message across all 20 Mac locales (fixed from earlier review thread).

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant iOS as iOS (MobileShellComposite)
    participant Mac as Mac (TerminalController)
    participant WS as Workspace

    note over iOS: User opens All Tabs overview
    iOS->>iOS: refreshTerminalOverviewPreviews()
    iOS->>Mac: mobile.terminal.replay (per terminal)
    Mac-->>iOS: renderGrid (full frame)
    iOS->>iOS: cache terminalOverviewPreviewLinesByID

    note over iOS: User taps close on a card
    iOS->>Mac: mobile.terminal.close
    Mac->>WS: canClosePanelWithoutPrompt()
    alt close allowed
        WS-->>Mac: true
        Mac->>WS: mobileCloseSurfaceRecordingHistoryIfAllowed()
        WS-->>Mac: panel closed
        Mac->>Mac: clearMobileViewportReports()
        Mac-->>iOS: MobileSyncWorkspaceListResponse
        iOS->>iOS: applyRemoteWorkspaceList()
    else close protected
        WS-->>Mac: false
        Mac-->>iOS: err protected
        iOS->>iOS: refreshWorkspaces()
    end
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"}}}%%
sequenceDiagram
    participant iOS as iOS (MobileShellComposite)
    participant Mac as Mac (TerminalController)
    participant WS as Workspace

    note over iOS: User opens All Tabs overview
    iOS->>iOS: refreshTerminalOverviewPreviews()
    iOS->>Mac: mobile.terminal.replay (per terminal)
    Mac-->>iOS: renderGrid (full frame)
    iOS->>iOS: cache terminalOverviewPreviewLinesByID

    note over iOS: User taps close on a card
    iOS->>Mac: mobile.terminal.close
    Mac->>WS: canClosePanelWithoutPrompt()
    alt close allowed
        WS-->>Mac: true
        Mac->>WS: mobileCloseSurfaceRecordingHistoryIfAllowed()
        WS-->>Mac: panel closed
        Mac->>Mac: clearMobileViewportReports()
        Mac-->>iOS: MobileSyncWorkspaceListResponse
        iOS->>iOS: applyRemoteWorkspaceList()
    else close protected
        WS-->>Mac: false
        Mac-->>iOS: err protected
        iOS->>iOS: refreshWorkspaces()
    end
Loading

Reviews (29): Last reviewed commit: "fix: use catalog plural for mobile tab c..." | Re-trigger Greptile

Comment thread Resources/Localizable.xcstrings
@austinywang

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 20, 2026 •

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@austinywang

Copy link
Copy Markdown
Contributor Author

Greptile P2 follow-up: I left the explicit workspace_id guard in v2MobileTerminalClose. The shared mobileWorkspaceIDValidationError helper rejects malformed non-null IDs; this guard handles missing/null workspace_id so close returns invalid_params instead of falling through to a not_found terminal response.

@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

This branch was successfully deployed

1 active deployment
Preview – cmux — 5f7e36d7 Deployed Jun 20, 2026 by vercel[bot]
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