Skip to content

Fix iOS terminal sizing priority across background resume - #18641

Merged
austinywang merged 6 commits into
mainfrom
task-18624-ios-resize-priority
Oct 16, 2026
Merged

austinywang merged 6 commits into
mainfrom
task-18624-ios-resize-priority

Conversation

@austinywang

@austinywang austinywang commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Backgrounding the iOS terminal no longer clears the phone's confirmed viewport lease by default, so the host keeps the last rendered grid through resume instead of briefly letting the Mac choose a different size. A persisted Settings toggle, Hand Off Terminal Sizing When Inactive, opts into the earlier phone/computer handoff behavior when users want the Mac to own sizing while the phone is inactive.

The change keeps CMUXMobileShellStore's reported viewport and generation as the source of truth, threads the persisted preference through WorkspaceDetailView into the terminal coordinator, and applies the preference before inactive lifecycle cleanup. Enabling the toggle while already inactive releases the lease immediately; disabling it leaves the current lease intact until the next foreground mount.

Fixes #18624

Testing

  • Added MobileDisplaySettingsTests coverage for the default-without-write behavior and cross-instance persistence.
  • Added TerminalSurfaceMountOwnershipTests coverage for default background/resume lease preservation, explicit opt-in handoff release, and foreground recovery when the output stream has been torn down.
  • Addressed the Cursor Bugbot finding: foreground reconciliation now uses the persisted handoff preference when stopping stale mounted tasks, so transient stream recovery cannot release the phone lease unless handoff is enabled.
  • Regression-first commits: 4c7ea19b466 records the original behavioral expectation, 4e3dafcb78 records the foreground-recovery regression, and the following fix commits implement each behavior.
  • Focused local command: swift test --package-path Packages/iOS/CmuxMobileShellUI --filter 'MobileDisplaySettingsTests|TerminalSurfaceMountOwnershipTests'. The pre-fix and fixed attempts in this checkout could not start because swift is unavailable (/bin/bash: swift: command not found), so zero local tests executed.
  • Portable verification: git diff HEAD~2..HEAD --check passed and the changed XCStrings resource parses with python3 -m json.tool. The Swift syntax verifier reported swiftc is unavailable; native compilation and app launch were not checked locally.
  • The iOS connectivity soak was not run: this lifecycle change needs a tagged app/device build, while the request explicitly prohibits reproducing on the user's machine. No user-device reproduction or app install was performed.
  • CI run 38662110144 built the iOS simulator product. Its first package-test attempt exposed one unrelated flaky IrohMacSwitchRecoveryTests.macSwitchDuringRecoveryKeepsTheSwitchedMac failure; the failed jobs were rerun and the iPhone, iPad, package, and aggregate iOS checks passed.

Changelog

Fixed: iOS terminal sizing keeps its confirmed viewport across background and resume, with an opt-in Mac handoff setting.

Proof

CI-only for this pass. Native app launch and screenshots were intentionally skipped under the no-user-machine-reproduction constraint.

Issue lifecycle

Impact map

  • Source of truth and owner: CMUXMobileShellStore's reported viewport and generation; GhosttySurfaceRepresentable.Coordinator owns the viewport lease and inactive lifecycle transition; MobileDisplaySettings persists the opt-in handoff choice.
  • Direct callers and sibling entrypoints inspected: WorkspaceDetailView.terminalArtifactSurface, the representable coordinator factory/update path, didChangeWindowAttachment, detach, viewport report/clear methods, and existing terminal mount ownership tests.
  • Cross-surface effects: the Settings toggle is localized in all 9 supported iOS locales; desktop sizing policy remains host-owned, and SSH/local terminal surfaces continue through the same coordinator lifecycle.
  • Tests and evidence: persistence tests cover relaunch-style settings instances; lifecycle tests cover default lease retention, generation stability, and explicit handoff release.
  • Residual risk: a native iOS build and suspended-app visual check remain for CI/device verification because the local SwiftPM package target cannot run on macOS 12 with its macOS 14 dependencies, and user-machine reproduction was explicitly excluded.

Mergeability

  • Base SHA: fba804b
  • Head SHA: d308b17
  • Conflict-only gate: PASS; no conflicted paths (gate ref gate/task-18624-ios-resize-priority-1791493114)

HIG

The Apple Human Interface Guidelines Settings page was consulted for the persisted toggle placement and explanatory footer: https://developer.apple.com/design/human-interface-guidelines/settings

Merge-main commit by scripts/merge-main.sh.
Merged by scripts/merge-main.sh: origin/main at ae560e6.

Merge-main-previous-head: b9e28cf
Merge-main-base: ae560e6
@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 9 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 542c435a-aee8-45be-ac24-182fe763b3f2
📥 Commits

Reviewing files that changed from the base of the PR and between fba804b and d308b17.

📒 Files selected for processing: 8
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/GhosttySurfaceRepresentable+CoordinatorFactory.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/GhosttySurfaceRepresentable.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileDisplaySettings.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileSettingsView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/Resources/Localizable.xcstrings
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceDetailView+TerminalArtifacts.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/MobileDisplaySettingsTests.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/TerminalSurfaceMountOwnershipTests.swift
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 6a9daba. Configure here.

@austinywang

Copy link
Copy Markdown
Contributor Author

Addressed the Cursor Bugbot high-severity finding in d308b17b44c91d750ca1b3214a6b1c21fd48111f. Foreground recovery now passes the persisted handoffTerminalSizingWhenInactive preference into stopMountedTasks, so losing the output consumer during reconciliation does not release the phone viewport lease by default. Added foreground recovery preserves the viewport lease by default to TerminalSurfaceMountOwnershipTests to cover the stream-loss resume path and generation stability.

@austinywang

Copy link
Copy Markdown
Contributor Author

Closeout verification update:\n\n- The PR head matches the verified local and remote branch head.\n- The PR is open, non-draft, mergeable, and clean.\n- Required checks are green or intentionally skipped.\n- No unresolved review threads remain.\n\nThis PR is ready for review. No merge was performed.

@austinywang
austinywang merged commit 0f1a175 into main Oct 16, 2026
75 of 77 checks passed
@austinywang
austinywang deleted the task-18624-ios-resize-priority branch October 16, 2026 00:39
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for d308b17b44: every check was green at merge (16 verified; 16 skipped by policy). Full suite runs on main after merge.

teamleaderleo pushed a commit to teamleaderleo/cmux that referenced this pull request Oct 16, 2026
…cx-q1lnl)

15 main commits since the last sync (ec21dd9). Full rename detection
(merge.renameLimit=30000). Priority: main's signing commits.

Signing (one version per script):
- scripts/ci/signing-keychain.sh, scripts/import-apple-developer-id-intermediates.sh,
  scripts/ci/finalize-release.py, scripts/ci/publish-release-assets.py,
  tests/test_github_release_publication.py: identical on both sides after
  feat's ports (5f8d2ce, b0c33eb, fad7929, a2380e7); the
  .p12 + `-f pkcs12` import and the SHA-1 fingerprint check stay.
- tests/test_signing_keychain_real_import.sh: main's version (manaflow-ai#21151: the
  G2 intermediate from the .p12 must be met in the keychain; openssl error
  text). signing-keychain-macos.yml: identical.
- scripts/ci/notarize-nightly-dmg.sh, resume-nightly-notarization.sh,
  scripts/ci/smoke-dmg.sh: main's CMUX_DEFER_LAUNCH_SMOKES (manaflow-ai#21024) on feat's
  script.
- .github/workflows/nightly.yml (manaflow-ai#21024, manaflow-ai#21049, manaflow-ai#21140): the signing job is
  split three ways: secret-free prepare-nightly-variant (helper, cmux-tui
  client, regressions, thinning, sidecar handshake; takes feat's
  build-nightly-app output), build-sign-notarize-nightly (runs no bundle
  code; smokes deferred), secret-free verify-signed-nightly (signed app,
  CLI, sidecar, SSH daemon contract, feat's 15 s crash-checking launch smoke,
  smoke-dmg.sh on the final DMG). Recovery keeps feat's find/recover jobs;
  recover defers smokes to a new secret-free verify-recovered-nightly-next.
  publish-nightly needs both verify jobs and publishes only tested digests.
  Literal Blacksmith labels on secret-holding jobs (incl. sign-release-notes).
  Promote guard (manaflow-ai#21049) merged without conflict. Feat's .publish-tooling
  recheck (manaflow-ai#21144 port), publish-by-id (manaflow-ai#21140, feat already had it),
  nightly-next notary pause/hold, signed-unnotarized zip, 20m wait,
  publish-nightly-identity-legacy and legacy-identity-target are kept.
  Not ported: main's CMUX_NOTARY_SUBMIT_ONLY async notarization (feat keeps
  its in-job wait + recovery); publish-nightly-identity-legacy defers its
  launch smokes and has no secret-free smoke of the re-signed NIGHTLY DMG
  yet (it re-signs the build verify-signed-nightly smoked).
- .github/workflows/release.yml: feat's job (90 min, universal app only) with
  main's literal blacksmith-12vcpu-macos-26 signing label (manaflow-ai#21024); feat's
  single-appcast resume and MDM asset list (manaflow-ai#21140 resume).
- tests/test_nightly_universal_build.sh: feat's in-job wait contract and
  pin-cmux-tui.sh resolver, main's prepare-nightly-variant job name.
  tests/test_nightly_next_recovery.py, test_nightly_cmux_tui_resolve.py,
  test_nightly_next_computer_use_helper.py,
  test_nightly_signed_unnotarized_artifact.py: updated for the new jobs.

Other conflict choices:
- 128 modify/delete in the legacy app, CLI, iOS/macOS legacy packages,
  cmuxTests, legacy resources and legacy docs: kept deleted.
- cmux.xcodeproj/project.pbxproj: feat-cmux-next's side.
- .github/test-determinism-allowlist.txt: feat's side (main's entries name
  deleted tests).
- cmux-tui (manaflow-ai#20570, Cloud terminal cwd): mux.rs feat's split file;
  publish_resource_event (mux/journal.rs) now publishes pending terminal
  directories; terminal_directory.rs notifies with publish_journal_event and
  keeps feat's emit_terminal_tabs_changed; cmux-tui-platform platform.rs:
  case-insensitive kitty-shell-cwd scheme and the Windows drive slash strip
  ported into feat's existing parser. Main's new unit tests dropped.
- cmux-browser-host JS, plans/cmux-next/browser-repl, tests/browser-parity:
  feat's side. manaflow-ai#18380 (browser repl hardening) NOT ported: feat has its own
  earlier port (cx-2y2, cx-p9mu, cx-wj2w); main's later version targets the
  WebKit/Swift host and conflicts in ~100 hunks; it needs a port lane gated
  by the browser-parity harness. Main's new unit tests, scenarios 40/41 and
  async-owner.js dropped.
- CmuxNextDesign Localizable.xcstrings: feat's side (rename detection mapped
  main's legacy Resources/Localizable.xcstrings keys there).

Not ported (legacy-only code paths): manaflow-ai#20346, manaflow-ai#21128, manaflow-ai#20354, manaflow-ai#18641, manaflow-ai#21135.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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: remember resize priority and phone/computer handoff

1 participant