Skip to content

Add Copy Debug Information to iOS Settings - #13007

Merged
lawrencecchen merged 1 commit into
mainfrom
feat-ios-copy-debug-info
Sep 19, 2026
Merged

lawrencecchen merged 1 commit into
mainfrom
feat-ios-copy-debug-info

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add a one-tap Copy Debug Information action to iOS Settings > Diagnostics.
  • Include account, build, device, install, host, connection, and transport identifiers without credentials or terminal content.
  • Add a tested, stable report formatter and localized Settings label.

Testing

  • swift test from Packages/iOS/CmuxMobileSupport
  • python3 scripts/localization_catalog.py check
  • python3 scripts/check-package-resolved-policy.py
  • Packages/iOS/CmuxMobileShellUI package build was attempted but is blocked in this checkout because GhosttyKit.xcframework is absent.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Adds a one-tap Copy Debug Information action to iOS Settings > Diagnostics that copies a support snapshot to the clipboard.

  • The snapshot includes account, device, build, host, connection, and analytics identifiers, and excludes credentials and terminal content.
  • The button shows a temporary Copied confirmation after tapping.
  • Adds a tested MobileDebugInformation formatter in CmuxMobileSupport and localized labels.

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

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added a “Copy Debug Information” option in iOS Settings.
    • Users can copy diagnostic details—including app, device, connection, and support information—to the clipboard.
    • Copied reports indicate unavailable fields and exclude sensitive access and refresh tokens.
    • Added localized text for the new diagnostics action across supported languages.
  • Bug Fixes

    • Improved diagnostics data availability for support troubleshooting.

@github-actions

Copy link
Copy Markdown
Contributor

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

@coderabbitai

coderabbitai Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 81462342-0df0-4937-88dc-ba792b06879b

📥 Commits

Reviewing files that changed from the base of the PR and between 9f29ddf and cb5818b.

📒 Files selected for processing (6)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/AnalyticsEnvironment.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileSettingsView.swift
  • Packages/iOS/CmuxMobileSupport/Sources/CmuxMobileSupport/MobileDebugInformation.swift
  • Packages/iOS/CmuxMobileSupport/Tests/CmuxMobileSupportTests/MobileDebugInformationTests.swift
  • ios/cmux/Resources/Localizable.xcstrings
  • ios/cmuxPackage/Sources/cmuxFeature/CMUXMobileRootScene.swift

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

The iOS mobile settings diagnostics section now creates and copies a structured debug report. The report includes account, device, app, analytics, host, and connection details. The analytics client ID is propagated through the SwiftUI environment.

Changes

Mobile debug information

Layer / File(s) Summary
Analytics environment propagation
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/AnalyticsEnvironment.swift, ios/cmuxPackage/Sources/cmuxFeature/CMUXMobileRootScene.swift
Adds the analyticsClientID environment value and injects the analytics anonymous ID at the root scene.
Debug information report contract
Packages/iOS/CmuxMobileSupport/Sources/CmuxMobileSupport/MobileDebugInformation.swift, Packages/iOS/CmuxMobileSupport/Tests/CmuxMobileSupportTests/MobileDebugInformationTests.swift
Adds the public MobileDebugInformation type and tests field ordering, unavailable values, and secret exclusion.
Settings copy flow
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileSettingsView.swift, ios/cmux/Resources/Localizable.xcstrings
Adds the diagnostics copy button, report assembly, pasteboard copy, temporary copied state, and localized button text.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant MobileSettingsDiagnosticsSection
  participant MobileDebugInformation
  participant UIPasteboard
  MobileSettingsDiagnosticsSection->>MobileDebugInformation: Assemble diagnostic fields
  MobileDebugInformation-->>MobileSettingsDiagnosticsSection: Render report text
  MobileSettingsDiagnosticsSection->>UIPasteboard: Copy report to general pasteboard
Loading

Suggested reviewers: azooz2003-bit


Important

Pre-merge checks failed

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

❌ Failed checks (5 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error The PR adds try? await Task.sleep(for: .seconds(2)) in the shipped MobileSettingsDiagnosticsSection implementation at MobileSettingsView.swift:1128. The new task uses the sleep to hold the “Copi… Replace the production Task.sleep with an approved cancellation-aware timing mechanism or explicit UI state transition. Keep the “Copied” feedback independent of Task.sleep; for example, use a project timer/scheduler abstraction that ow…
Cmux Swift Concurrency ❌ Error The diff adds a discarded Task { @mainactor in ... } in copyDebugInformation() at MobileSettingsView.swift:1127. It sleeps for two seconds and then changes didCopyDebugInformation, so it owns … Store the copy-feedback task in view state, cancel any previous task before starting a new one, and cancel and clear it in the diagnostics view’s onDisappear. Keep the delayed reset in the stored task and check cancellation before mutatin…
Cmux User-Facing Error Privacy ❌ Error The new production Settings action copies a user-facing support report to UIPasteboard.general. The report includes Hexclave Auth ID and a dynamic Team ID from authManager, as shown in `Mobile… Remove hexclaveAuthID and teamID from the user-facing copied report, including their labels. Keep any required correlation data in sanitized internal telemetry or logs. Use only safe, minimal product-level diagnostics in the copied supp…
Cmux Full Internationalization ❌ Error The new Settings button text is localized correctly: it uses L10n.string(...), and mobile.settings.diagnostics.copyDebugInfo has translated entries for all nine locales already present in `ios/cmu… Route every report label and the unavailable-value text through the localized API. Add matching translated keys to ios/cmux/Resources/Localizable.xcstrings for en, ja, de, fr, ar, es, zh-Hant, zh-Hans, and ko. Update the…
Cmux Swiftui State Layout ❌ Error The diff introduces a store reference below the settings form boundary. MobileSettingsView renders MobileSettingsDiagnosticsSection inside Form, and the new section stores `let store: CMUXMobile… Do not pass CMUXMobileShellStore into MobileSettingsDiagnosticsSection. Resolve connectionState and transport in MobileSettingsView and pass those immutable value snapshots, or pass a value-producing/action closure. Keep the diagn…
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 5 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (19 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the primary change: adding a Copy Debug Information action to iOS Settings.
Description check ✅ Passed The description clearly explains the change, its purpose, included data, credential exclusions, tests performed, and the blocked package build. It omits the template's Demo Video, Review Trigger, and …
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 Cloud Persistent Session And Early Input ✅ Passed PASS. The pull request changes only iOS Settings diagnostics, a support report formatter, localization, and analytics environment injection. copyDebugInformation() reads existing connectionState a…
Cmux Swift Actor Isolation ✅ Passed PASS. The new MobileDebugInformation is an immutable String? value model with Sendable conformance in a Swift 6 package that has no default MainActor isolation setting. The new settings code acc…
Cmux Browser Automation Off-Main ✅ Passed PASS. The pull request changes only iOS settings, support report formatting, localization, and root analytics environment injection. It does not modify Sources/TerminalController.swift, `ControlComm…
Cmux Expensive Synchronous Load ✅ Passed PASS. The PR adds a SwiftUI button that formats already-resolved device, auth, app, host, and connection values, then copies the report. The changed files add no agent-history loader, transcript or tr…
Cmux Cache Substitution Correctness ✅ Passed PASS: The PR does not replace a fresh authoritative read with a cached value in a persistence, history, undo, or snapshot consumer. The new report is built on demand and copied only to UIPasteboard.ge…
Cmux No Hacky Sleeps ✅ Passed PASS. The PR changes only Swift source/tests and an xcstrings localization catalog. The only added delay is Task.sleep(for: .seconds(2)) in Swift, used to reset the visible “Copied” state. The rule …
Cmux Algorithmic Complexity ✅ Passed No complexity failure is introduced. The new report formatter in Packages/iOS/CmuxMobileSupport/Sources/CmuxMobileSupport/MobileDebugInformation.swift:68-85 processes an explicit 13-field tuple list…
Cmux Swift @Concurrent ✅ Passed PASS. The Swift diff adds only synchronous report construction and @MainActor-isolated copyDebugInformation(), which reads UI/auth state, writes the pasteboard, and updates UI state. Its only asyn…
Cmux Swift Package Boundaries ✅ Passed PASS. The independently testable report model and formatter are introduced in the existing CmuxMobileSupport SwiftPM target as public MobileDebugInformation, with dedicated package tests. The chan…
Cmux Swiftpm Lockfiles ✅ Passed PASS. The PR changes source, tests, localization, and root-scene code only. Packages/iOS/CmuxMobileShellUI/Package.swift, Packages/iOS/CmuxMobileSupport/Package.swift, all Package.resolved files…
Cmux Swift Logging ✅ Passed The diff adds no print, debugPrint, dump, NSLog, ad hoc file output, stdout/stderr output, or new Logger declaration. The existing mobileRootSceneLog declaration is identical in the base a…
Cmux Architecture Rethink ✅ Passed PASS. The diff adds one local Copy Debug Information action in the existing diagnostics section and one root environment snapshot for the analytics ID. The new Task.sleep only controls the requested…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS. The authoritative diff changes mobile SwiftUI views, an environment key, a support report, and root environment injection. It adds no NSWindow, NSPanel, NSWindowController, Window, or WindowGrou…
Cmux Source Artifacts ✅ Passed PASS. The diff changes only hand-written Swift source, a Swift test under the standard test target, a localization catalog, and one SwiftUI integration line. All six paths are in normal Sources, Tests…
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS. The production diff adds no test-build guard, test hook, or accessor for otherwise-private state. copyDebugInformation() is a private method called by the user-facing Diagnostics button and bu…
Full details: Docstring Coverage

Explanation

Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 8 functions across 5 files. (1 skipped: 1 unsupported.)

Full details: Cmux Swift Blocking Runtime

Explanation

The PR adds try? await Task.sleep(for: .seconds(2)) in the shipped MobileSettingsDiagnosticsSection implementation at MobileSettingsView.swift:1128. The new task uses the sleep to hold the “Copied” state for two seconds before resetting it. The repository rule explicitly lists Task.sleep in non-test Swift as a failure, including small delays and animation timing. The test-only and non-Task.sleep UI-delay exceptions do not apply.

Resolution

Replace the production Task.sleep with an approved cancellation-aware timing mechanism or explicit UI state transition. Keep the “Copied” feedback independent of Task.sleep; for example, use a project timer/scheduler abstraction that owns cancellation when the view disappears or the button is pressed again, or remove the delayed reset and use a purely state-driven SwiftUI presentation.

Full details: Cmux Swift Concurrency

Explanation

The diff adds a discarded Task { @mainactor in ... } in copyDebugInformation() at MobileSettingsView.swift:1127. It sleeps for two seconds and then changes didCopyDebugInformation, so it owns a real UI-feedback lifecycle. The task is not stored or cancelled when the button is tapped again or when the diagnostics view disappears. The existing log-export task in the same view is stored in @State and cancelled on disappearance, which confirms the available lifecycle pattern. This is not a required SwiftUI or OS callback boundary because copyDebugInformation() already runs on @MainActor. No new Dispatch, Combine, or completion-handler pattern was introduced.

Resolution

Store the copy-feedback task in view state, cancel any previous task before starting a new one, and cancel and clear it in the diagnostics view’s onDisappear. Keep the delayed reset in the stored task and check cancellation before mutating didCopyDebugInformation; alternatively, use a SwiftUI lifecycle-bound .task(id:) for the two-second reset.

Full details: Cmux User-Facing Error Privacy

Explanation

The new production Settings action copies a user-facing support report to UIPasteboard.general. The report includes Hexclave Auth ID and a dynamic Team ID from authManager, as shown in MobileDebugInformation.report and copyDebugInformation(). The rule forbids internal provider names and team IDs unless the user supplied the exact ID. The new tests confirm these fields are part of the report. This behavior is introduced by the pull request.

Resolution

Remove hexclaveAuthID and teamID from the user-facing copied report, including their labels. Keep any required correlation data in sanitized internal telemetry or logs. Use only safe, minimal product-level diagnostics in the copied support text.

Full details: Cmux Full Internationalization

Explanation

The new Settings button text is localized correctly: it uses L10n.string(...), and mobile.settings.diagnostics.copyDebugInfo has translated entries for all nine locales already present in ios/cmux/Resources/Localizable.xcstrings. However, the production MobileDebugInformation.report adds user-visible clipboard text (Device ID, Email, Hexclave Auth ID, and the other field labels, plus <unavailable>) as English literals. MobileSettingsDiagnosticsSection.copyDebugInformation() places this report on UIPasteboard.general, so the text is exposed to the user. The report does not use String(localized:defaultValue:) or an equivalent API, and it has no matching catalog entries.

Resolution

Route every report label and the unavailable-value text through the localized API. Add matching translated keys to ios/cmux/Resources/Localizable.xcstrings for en, ja, de, fr, ar, es, zh-Hant, zh-Hans, and ko. Update the report tests to verify the localized English fixture and preserve the required report format.

Full details: Cmux Swiftui State Layout

Explanation

The diff introduces a store reference below the settings form boundary. MobileSettingsView renders MobileSettingsDiagnosticsSection inside Form, and the new section stores let store: CMUXMobileShellStore?. CMUXMobileShellStore is an alias for the @Observable MobileShellComposite. The rule prohibits plain store properties in lazy/list-style row subtrees. The other prohibited patterns are not introduced: no new ObservableObject, @Published, GeometryReader, or render-time state write is present.

Resolution

Do not pass CMUXMobileShellStore into MobileSettingsDiagnosticsSection. Resolve connectionState and transport in MobileSettingsView and pass those immutable value snapshots, or pass a value-producing/action closure. Keep the diagnostics section dependent on snapshots and closures instead of a store reference.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

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.

@lawrencecchen
lawrencecchen enabled auto-merge (squash) September 19, 2026 04:26
@lawrencecchen

lawrencecchen commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor Author

Fleet instruction update for head cb5818ba829c5a2176fe914dda75bf245ad68a7c: this PR is classified ios. No macOS build tag is claimed. The current controller app recipe does not establish iOS/test readiness; that requires the appropriate validated recipe. Use cmux-ci for supported jobs, retain the returned ID and receipt, and wait on the same ID after any timeout. Do not use retired maclease allocation or post credentials. Exact-head tags will be posted only after the applicable build succeeds.

@lawrencecchen
lawrencecchen merged commit 4c67b4d into main Sep 19, 2026
40 of 43 checks passed
rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 19, 2026
4c67b4d feat(ios): add copy debug information action (manaflow-ai#13007)
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.

1 participant