Skip to content

Fix Hive viewer lifecycle, replay identity, and shared-package integration - #8027

Open
austinywang wants to merge 118 commits into
mainfrom
issue-8001-hive-viewer
Open

austinywang wants to merge 118 commits into
mainfrom
issue-8001-hive-viewer

Conversation

@austinywang

@austinywang austinywang commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Refs #8001. This PR is not approved for automatic merge or issue closure: it relocates shared mobile/iOS packages, and live Mac-to-Mac acceptance remains unverified.

Current status

This adds the gated Hive remote-Mac viewer foundation, Settings > Computers pairing, native mirror-workspace integration, and an auxiliary viewer. The previous description's claims that end-to-end acceptance was fully met and iOS code was untouched were inaccurate and are superseded here.

Production viewer admission remains deliberately unavailable (Sources/Hive/HiveComputersService.swift, viewerTransportAvailable == false). A numeric or named Tailscale route alone is not cryptographic peer identity; legacy bearer transport remains fail-closed. This PR must not be used to claim live two-Mac viewing is ready, or to close #8001, until that boundary is implemented and dogfooded.

Latest review/CI checkpoint — 48d27063f7

  • The final fix batch is pushed at 48d27063f75d601d347ef88729ee0eadb079ef3c, including the replay coordinator, synchronous disconnect admission revocation, app-host test serialization, and the Iroh lane-quota assertion correction. Current origin/main is 5939eaf985911cfbec5c8b4d61d563dd52b1ef1b; the branch includes it through merge commit 48d27063f7.
  • The previous full-head CI run 34203733933 at 6eb3532205 had a genuine lane-quota assertion failure (5 expected versus 7 implemented) plus widespread AppKit-state failures/timeouts in parallel app-host execution. The new head is awaiting its own required CI result; no assertion failure is being declared fixed until that run is green.
  • The tagged cloud build previously succeeded in offline mode with --no-dev-backend; the final-head tagged build is required after this push. Offline mode proves compilation/startup only because cmux-dev-backend-1 still fails DNS resolution; it cannot prove authenticated two-Mac viewer behavior.
  • All 49 review threads are represented in the audit inventory. The three newest Cursor findings were explicitly answered at this HEAD and resolved only after GitHub returned each reply. Cursor review body 5139234314 receives a top-level response below. CodeRabbit is paused and Greptile skipped the oversized diff; neither is represented as final-head approval.
  • Canonical UUID identity is shared by registry/pairing/presence indexes, scoped updates, pair/unpair, host verification, and app ownership keys. Opaque IDs retain exact case and whitespace. Two old opaque-ID fixtures were corrected rather than weakening the shared identity contract.
  • One injected route policy governs rows, best-instance choice, every pairing persistence path, and network runtime. Release excludes loopback-only hosts and prefers a compatible instance. Supported route kind is not authenticated admission.
  • Independent route-rebind tasks survive teardown of obsolete observers and are cancelled explicitly on detach/sign-out/window close. Ownership transfers before teardown to preserve scope; post-await selection cannot overwrite a changed scope. First-workspace readiness is event-driven with a cancellable injected deadline, not a polling loop.
  • The pre-fix identity/route tests produced 13 genuine behavioral assertion failures on a leased Mac. The fixed 63-test CmuxHive suite, 8-test CmuxHiveUI suite, and ten repeats of the focused replay/disconnect/coordinator regressions pass. Rebind/readiness tests validate the new seams; they do not claim a red native two-Mac route-churn reproduction.
  • App-host testables are explicitly parallelizable="NO": these suites share NSApplication, windows, and process-wide services, so serial execution within one test process protects GUI correctness at some intra-shard throughput cost. The six CI shards remain parallel across isolated runners.
  • MobileCoreRPCClient.retire() blocks new transport admission/dials but does not retroactively cancel an RPC already using an installed transport. Disconnect tests therefore assert synchronous Hive admission revocation and no new connection allocation, while allowing an already-installed request to finish during asynchronous teardown.

Changes

  • Compose the computer directory, pairing-code flow, account-scoped persistence, host sessions, terminal replay/input, and shared render-grid routing in CmuxHive.
  • Add native mirror-workspace reconciliation and a separate Canvas/AppKit viewer. Keep session lifecycle mutations out of view-body evaluation, evict stale sessions, and preserve focus and composed text.
  • Integrate current main and finish the relocation of Mac-consumed mobile packages under Packages/Shared, including the release-gate support sources missed by the earlier merge. Wire both app and unit-test consumers.
  • Preserve events arriving during initial snapshot refresh and coalesce workspace/render-grid topics into one host subscription.
  • Reuse a decoder owned by an off-main actor; require matching replay envelope workspace/surface IDs before applying a full frame; reject stale deltas and recover through bounded cancellable backoff.
  • Reject stale account-scope reads and pairing reloads before they can publish rows after sign-out.
  • Repair the Hive project-group closure and quote the extension filename; add native macOS plist validation alongside normalization/test-wiring guards.
  • Consolidate duplicate close-routing and settings-search declarations introduced by the main merge, preserving current-main window IDs and Computer Use search behavior. Reuse the Computers alias localization.
  • Make the Computers settings refresh task and native mirror attachment handle clock errors exhaustively so their non-throwing APIs compile.
  • Continue link pairing after a successful team-switch refresh, reject case-variant self-links, refresh the new scope after an older coalesced request, await refresh teardown before session reuse, drain input after replay recovery, and reject route-only transport construction without admission.
  • Initialize the sidebar workspace snapshot with an if expression, preserving filtering semantics while fixing the concrete app-host ViewBuilder compiler failure.
  • Repair final-head CI dependencies and Release compilation: extract the unchanged CLIError for shared CLI/test membership, wire the five real local-tmux helpers into cmuxTests, port all four obsolete cloud-rename tests to their current owners, guard DEBUG-only Hive probes, use lifecycle-safe mirror workspace creation, and fix the unmutated browser payload warning.
  • Add CmuxHive and CmuxHiveUI to the existing standalone-package CI lane.

Verification

  • Remote Swift Testing: 58 domain tests (including four parameterized replay-identity cases) and 8 AppKit/key-mapping tests passed. All 62 tracked Hive/HiveUI package files checksum-match pushed HEAD 258b0a6de31225122f7cd571f52bb7bbe34eda1e, and both suites were rerun from that source.
  • Real byte-transport/RPC tests cover workspace-event ordering, one shared subscription, replay and streamed frame reduction, FIFO input, reconnect, sign-out races, and disconnect during an actual cancellable backoff. AppKit tests cover Japanese text composition, disabled input, and preserving another control's first responder.
  • Regression-only commits precede their fixes. Replay-envelope and account-scope tests were run red on the remote Mac before their fixes, then green; the event-order regression also reproduced the failure remotely. Source fixes were batched for publication, so this is remote red/green evidence, not a claim that every intermediate commit got a separate GitHub run.
  • In the prior six-finding batch, the test-only commit precedes the six-review fix commit. New pairing, coalesced-scope, replay-input, and route-admission tests produced ten failing assertions before their fixes and pass after. The dropped-response teardown/reconnect test passes, including ten focused repeat runs, but also passed before the fix; it is coverage, not an independent reproduction of that exact late-write race. All 54 tracked Hive/HiveUI package files checksum-match pushed HEAD 9260576134.
  • Project syntax/normalization, app-test wiring (797 files), workspace package grouping, Package.resolved policy, and whitespace checks pass.
  • Localization audit: all 73 changed catalog keys have translated English and Japanese values; all feature string references have catalog entries. No new cmux-owned keyboard shortcuts.
  • Rename-aware length audit: all 80 new Swift files are below 500 lines (largest 495). The requested python3 scripts/swift_file_length_budget.py invocation fails because that script is absent from this checkout and main. No budget TSV was modified; tracked-file budget-row compliance cannot be certified by substituting line counting for the missing tool.

Explicit trade-offs and remaining acceptance work

  • Security takes precedence over enabling an unauthenticated viewer: the production transport gate stays closed. Live two-Mac pairing/view/input/reconnect and before/after visual acceptance are not established by scripted transport tests.
  • AWS had only about 104 MiB free and could not run Swift tests. Tests ran on a leased general-purpose fleet Mac (macOS 26.5.1; latest review batch on Xcode 26.3), never on Austin's Mac. This is not independent macOS 15 runtime evidence.
  • The normal cloud build could not provision its dev backend because cmux-dev-backend-1 did not resolve. The documented offline mode can validate native compilation/startup only, not backend-dependent flows. The tagged cloud build succeeded in 586 seconds. Two fleet launches verified the exact tag, workspace listing, and running terminal via the debug socket. Screenshot capture failed: the default provider lacks its bundle/authentication; the installed alternate driver does not support the requested screenshot tool. No credentials or privacy permissions were changed. Final HEAD CI status is recorded in the final audit comment.
  • After roughly 40 minutes waiting for the shared tagged-build lock, the collected fixes were pushed as one batch so hosted HEAD CI could run concurrently. The new CLA run then identified the resumed session’s generated, unlinked author identity. A second, metadata-only exact-lease push corrected only those 17 automation-authored commits to Austin’s existing linked identity. Every source tree, main parent, and test/fix ordering is preserved; no policy or consent was changed. This is an explicit exception to the requested single-push closeout.
  • Main advanced after that publication. Its web-only devbox identity update is integrated separately to keep the PR current; it does not change any native build or Hive test source. Required main synchronization is additional to the original fix batch.
  • The subsequent tagged cloud build exposed one remaining non-exhaustive clock catch in the native mirror controller. A separate compiler-only correction ends its optional first-workspace wait on any clock error. It preserves the existing bounded selection wait and focus behavior; replacing that wait with event-driven readiness is not claimed by this correction. This concrete failure required another corrective push and tagged cloud retry.
  • The final app-host CI run at 2f8091f080 exposed a ViewBuilder Void expression error. Its compiler fix and the six newly posted Cursor findings were collected in one additional push (9260576134), retaining separate test/fix commits. This further push responds to concrete new CI/review evidence; it is not a claim of one total push.
  • Final-head app-host compilation then exposed a missing hiveScope argument in the existing sidebar scale-test harness. The test-only correction a03fef5387 supplies its own TabManager scope, exactly like production, and leaves the file at 514 lines. It changes no assertions or runtime source. Another hosted CI run verifies this head; another tagged app build would not test anything new. This additional push is limited to the concrete compiler failure.
  • CI run 34191663075 at a03fef5387 passed package tests but exposed CLI helper test-membership errors, removed catalog test APIs, two new warning buckets, and five Release-only debug-log errors. These were batched in 278af106ec, merged with main 71eb616d6f, and published together at f6bb617c7b. That head subsequently passed package/build-and-lag verification but recorded a legacy Claude-hook process timeout in app-host shard 6; the next full-head CI run is checked independently. No timeout was raised or assertion removed to mask it. The test ports retain the four behavioral contracts at canonical catalog, provider receipt-policy, and rename-coordinator boundaries; they do not restore a second optimistic catalog state path. A remote executable probe confirmed that the old raw unquoted attach-command assertion fails while effective parsed arguments, the login-shell wrapper, and client-list runner/parser pass. Production quoting is unchanged. The shared legacy XCTest CLI integration harness is retained to avoid an unrelated harness-wide migration; the catalog tests use Swift Testing.
  • Three later Cursor findings required the additional c8d136cca6 fix batch and 258b0a6de3 main merge. They were published together, preserving test/fix ordering. This is an additional evidence-driven push, not a claim of one total push across the interrupted session.
  • The previous exact tagged app is quit. Its 689 MB local build and stale socket were moved to Trash after the tool rejected forced deletion; logs are preserved. Cleanup is recoverable and does not claim permanent disk reclamation.
  • Ambiguous terminal-input failures are not automatically replayed: a request may already have executed remotely, and duplicating a command is unsafe. The lifecycle changes to recovery instead.
  • Hive's standalone dependency graph is local-only and SwiftPM generated no package lockfile. The root Xcode lockfile remains tracked; no artificial lockfile or unrelated pin churn is introduced.
  • The broader repository-wide package-conventions diagnostic reports 56 violations whose fingerprints already exist on main (including relocated paths). No new allowances suppress those failures. Existing allowlist paths follow the package relocation; this PR does not broaden into unrelated iOS refactors.

Austin must review/dogfood and merge this PR; do not self-merge it or close the linked issue.

Automated summaries (advisory; maintained status above is authoritative)


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


Summary by cubic

Adds a gated macOS remote-Mac viewer for #8001: paired Macs appear under Settings > Computers and their workspaces render as native mirror workspaces with live input, replay identity validation, and reconnect handling. Production viewer admission stays disabled (viewerTransportAvailable == false), so live two-Mac use is not yet ready.

New Features

  • Settings > Computers lists owned hosts with presence, pairs via short-lived six-digit CmxPairingCode values, and offers per-computer window or sidebar presentation.
  • Remote workspaces attach as native mirror surfaces with identity-validated replay, resize repaint, focus recovery, dead-terminal pruning, and bounded retry.
  • Failed attaches show connection status instead of a blank sidebar, and never-realized host surfaces boot headless on replay.
  • Adds hive.open, hive.render_probe, and hive.sidebar_probe RPCs for headless verification.

Migration

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

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added a Computers section in Settings with list refresh, pairing via link, unpairing, copy pairing link, and opening the remote viewer.
    • Added merged computer rows with presence/status indicators and improved pairing eligibility/details.
    • Introduced a remote Mac viewer with workspace/terminal browsing, live terminal rendering, keyboard input (including paste), and automatic reconnect/reattaching.
    • Added English + Japanese localization and searchable Computers aliases.
  • Bug Fixes
    • Improved auxiliary viewer window close-shortcut ownership handling.

Note

High Risk
Large cross-platform package moves plus new auth/route/pairing and remote-terminal RPC paths; production viewer admission is intentionally gated off but the surface area touches tokens, Tailscale trust, and account-scoped pairing.

Overview
Introduces CmuxHive (and CI for CmuxHiveUI) as the macOS layer for Settings › Computers: merge team registry, local paired-computer SQLite, and presence; pair by registry row, 6-digit CmxPairingCode, or pasted attach link; and run remote Mac viewer sessions (workspace list, shared render-grid router, terminal replay/input, bounded reconnect). Control socket adds hive.open, hive.render_probe, and hive.sidebar_probe.

Shared mobile stack moves Mac-consumed packages from Packages/iOS to Packages/Shared (shell, RPC, shell model, paired Mac, terminal kit, etc.) with updated SwiftPM paths, iOS workflow gates, and test-determinism allowlist entries. CmxPairingCode and registry instance labels / isOwnedByCurrentUser support code-based rendezvous; MobileShellRouteAuthPolicy gains StackAuthChannelTrust so the Mac viewer may send Stack auth over verified Tailscale tunnel hosts while iOS stays loopback-only. Mac viewer Tailscale dials use a dedicated HiveTailscaleByteTransportFactory (transport-admission path; legacy bearer routes remain fail-closed per PR intent).

Smaller deltas: public render-grid width APIs, TerminalKeyboardDockPathSelection for iOS keyboard-dock routing, review-bot pointer to CmuxAuxiliaryWindows.swift, and a doc-only tweak to CLIError.

Reviewed by Cursor Bugbot for commit cdd9bb5. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel

vercel Bot commented Jul 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cmux Ready Ready Preview Sep 9, 2026 9:50pm UTC
cmux-staging Building Building Preview Sep 9, 2026 9:50pm UTC
cmux166 Ready Ready Preview Sep 9, 2026 9:50pm UTC
cmux41 Ready Ready Preview Sep 9, 2026 9:50pm UTC

@coderabbitai

coderabbitai Bot commented Jul 14, 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 macOS Hive support for discovering and pairing computers, viewing remote workspaces and terminals, rendering terminal input/output, exposing a Computers settings section, and wiring services, windows, packages, localization, and tests.

Changes

Hive computer discovery and pairing

Layer / File(s) Summary
Core Hive models and pairing
Packages/macOS/CmuxHive/Sources/CmuxHive/Hive*.swift
Defines account scoping, computer/instance/presence models, pairing outcomes, reconnect backoff, and pairing-link decoding with account and loopback validation.
Computer directory and composition
Packages/macOS/CmuxHive/Sources/CmuxHive/HiveComposition.swift, HiveComputerDirectory.swift, Packages/macOS/CmuxHive/Tests/CmuxHiveTests/*
Implements registry/store/presence merging, pairing and unpairing, refresh tracking, presence resubscription, and directory/link-decoder tests.

Remote viewer and terminal

Layer / File(s) Summary
Remote runtime and session state
Packages/macOS/CmuxHive/Sources/CmuxHive/HiveSyncRuntime.swift, HiveRemote*.swift, HiveTerminalGridModel.swift, Packages/macOS/CmuxHive/Tests/CmuxHiveTests/*
Provides network runtime configuration, reconnecting workspace and terminal sessions, render-grid reduction, input dispatch, and scripted transport tests.
Terminal UI and input
Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/*, Packages/macOS/CmuxHiveUI/Tests/*
Adds SwiftUI terminal rendering, cursor and span styling, keyboard capture and mapping, workspace navigation, lifecycle overlays, and key-mapping tests.

Settings and application integration

Layer / File(s) Summary
Computers settings
Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/*, Resources/Localizable.xcstrings
Adds settings snapshots, observation, host actions, navigation, pairing controls, per-device actions, and localized Computers/viewer strings.
Application services and window management
Sources/Hive/*, Sources/HostSettingsActions+Computers.swift, Sources/AppDelegate*.swift, Sources/SettingsNavigation*.swift, Sources/CmuxAuxiliaryWindows.swift, Sources/cmuxApp.swift
Configures Hive services, manages viewer windows, bridges settings actions, centralizes cloud-client setup, relocates close-shortcut ownership, and updates navigation/search.
Package manifests and build integration
Packages/macOS/CmuxHive/Package.swift, Packages/macOS/CmuxHiveUI/Package.swift, cmux.xcodeproj/project.pbxproj, .github/review-bot-rules/*, scripts/*, tests/*
Adds the Swift packages, wires Xcode products and sources, and updates auxiliary-window lint documentation and CI scenarios.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Settings as Computers Settings
  participant Directory as HiveComputerDirectory
  participant Registry as Device Registry
  participant Store as Paired Store
  participant Presence as Presence Client
  Settings->>Directory: refresh()
  Directory->>Registry: list devices
  Directory->>Store: load paired records
  Directory->>Presence: subscribe updates
  Directory-->>Settings: merged computer snapshots
Loading
sequenceDiagram
  participant Settings as Computers Settings
  participant Window as HiveViewerWindowController
  participant MacSession as HiveRemoteMacSession
  participant Terminal as HiveRemoteTerminalSession
  participant RemoteMac as Remote Mac
  Settings->>Window: show(deviceID:)
  Window->>MacSession: create viewer session
  MacSession->>RemoteMac: connect and request workspaces
  RemoteMac-->>MacSession: workspace list and updates
  MacSession->>Terminal: create terminal session
  Terminal->>RemoteMac: replay and subscribe render grid
  RemoteMac-->>Terminal: render_grid frames
  Terminal->>RemoteMac: terminal input
Loading

Possibly related issues

  • manaflow-ai/cmux#8000: The PR implements the umbrella issue’s macOS Hive registry, pairing, presence, remote-session, and viewer functionality.
  • manaflow-ai/cmux#8001: The PR directly implements the linked M1 scope for macOS device pairing and remote workspace/terminal control.

Possibly related PRs

  • manaflow-ai/cmux#3753: Both changes update the auxiliary-window close-shortcut lint and its source-file references.

Important

Pre-merge checks failed

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

❌ Failed checks (13 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error FAIL: production code adds HiveReconnectBackoff.delay() using Task.sleep and wires it into HiveComputersService, HiveRemoteMacSession, and HiveComputerDirectory retries. Move retry timing to an explicit cancelable signal/actor or existing reconnection primitive; avoid Task.sleep in production, or keep the delay injectable/test-only.
Cmux Cache Substitution Correctness ❌ Error HiveTerminalGridModel accepts queued delta render-grid frames with no stateSeq freshness check, so an older frame can overwrite a newer replay snapshot. Ignore non-full frames whose stateSeq is <= the current stateSeq; keep full replays accepted so host restarts still reset the snapshot.
Cmux Algorithmic Complexity ❌ Error FAIL: HiveComputerDirectory.mergedComputers rebuilds and sorts the full device list on every refresh/presence update (line 374) with no bound or cache; this is a hot path for ~1000 devices. Cache the merged/sorted snapshot or update only affected rows via keyed/indexed inserts; if the full sort is intentional, add a benchmark-backed size bound.
Cmux Swift Concurrency ❌ Error HiveRemoteTerminalSession.sendInput launches an untracked Task per keystroke, so input work can outlive detach and isn’t stored/cancelled. Move terminal input onto a session-owned cancellable worker, or make send APIs async and await client.sendRequest from the UI/AppKit boundary.
Cmux Swift @Concurrent ❌ Error HiveReconnectBackoff.delay(attempt:) is a plain async helper used from @MainActor reconnect loops, but it lacks @concurrent so the sleep can inherit UI isolation. Mark delay(attempt:) @concurrent (or hop it onto a detached/background task) so the backoff leaves the caller actor.
Cmux Swiftpm Lockfiles ❌ Error CmuxHive/CmuxHiveUI package refs were added in cmux.xcodeproj, but no root Xcode Package.resolved diff is present. Add the root cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved update alongside the package-reference change.
Cmux Swift Logging ❌ Error Sources/Hive/HiveComputersService.swift:48 adds a production NSLog(...), which violates the Swift logging rule for app/runtime code. Replace the NSLog with the app’s structured logger or remove the diagnostic; keep any such output out of production runtime code.
Cmux User-Facing Error Privacy ❌ Error User-facing error/recovery copy now mentions Tailscale, and the viewer shows raw MobileShellConnectionError.localizedDescription text from upstream RPC errors. Rewrite user-visible errors in product terms only, and map upstream errors to sanitized, generic messages before displaying them.
Cmux Full Internationalization ❌ Error New Swift UI text is localized, but every new xcstrings key is only translated for en/ja while the catalog already supports 20 locales. Add translations for every existing locale in Resources/Localizable.xcstrings for each new key (ar, bs, da, de, es, fr, it, km, ko, nb, pl, pt-BR, ru, th, tr, uk, zh-Hans, zh-Hant).
Cmux Swiftui State Layout ❌ Error HiveViewerRootView mutates @State terminalSessions from a body-called helper, which the rule forbids as render-time state mutation. Move terminal-session creation/caching out of body (e.g. lifecycle/onChange/task or owning controller) so rendering only reads immutable state.
Cmux Architecture Rethink ❌ Error HiveRemoteTerminalSession sends each keypress via an untracked Task, so input can reorder and outlive detach; the session should own a cancellable serial input worker. Route send(text/special/control) through one session-owned serial queue/actor canceled by detach, then verify ordering and teardown safety under rapid typing.
Cmux No Test Or Debug Seam In Production Source ❌ Error HiveComputerDirectory.swift adds a public mergedComputers() helper exposed for tests; the test target calls it directly, so shipping source grew a test-facing seam. Make mergedComputers internal and access it from CmuxHiveTests via @testable import; keep production rebuild() using the same internal helper.
Cmux No Ambient Global State ❌ Error Sources/Hive/HiveComputersService.swift:17 and HiveViewerWindowController.swift:14 add shared singletons; Sources/CmuxAuxiliaryWindows.swift:46 adds a top-level API func, all ambient global surface. Make them instance-owned and injected from the app seam (e.g. store services/controllers on AppDelegate or another composition root); keep only private/fileprivate file-scope helpers.
Docstring Coverage ⚠️ Warning Docstring coverage is 35.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (11 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy [#8001]: Computers listing/pairing, macOS viewer with workspaces and terminal input, reconnect logic, and package wiring are all present.
Out of Scope Changes check ✅ Passed The extra app, lint, and project wiring changes are supporting pieces for the viewer and Computers flow, not unrelated scope.
Cmux Swift Actor Isolation ✅ Passed Changed UI/session types are intentionally @MainActor; new value models stay nonisolated and I found no new unsafe Sendable refs or background store access.
Cmux Browser Automation Off-Main ✅ Passed The PR only adds Hive/computers viewer code; no browser socket automation files or browser.* command routing were changed.
Cmux Expensive Synchronous Load ✅ Passed The new macOS viewer/settings paths use async RPC and in-memory merges; no RestorableAgentSessionIndex.load() or history-file scan was added on @MainActor/UI paths.
Cmux No Hacky Sleeps ✅ Passed Diff only touches two Swift files and wraps existing HiveReconnectBackoff.delay calls in @Sendable closures; no non-Swift runtime sleeps/timers were introduced.
Cmux Swift File And Package Boundaries ✅ Passed PASS: The >400-line HiveComputerDirectory is a coherent CmuxHive domain type, while reusable logic lives in new CmuxHive/CmuxHiveUI packages and app-target files are small glue.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS: HiveViewerWindowController uses stable cmux.hiveViewerWindow, it’s listed in cmuxAuxiliaryWindowIdentifiers, and close routing uses cmuxWindowShouldOwnCloseShortcut; the CI lint covers...
Cmux Source Artifacts ✅ Passed Only two Swift source files changed; no logs, caches, temp dirs, build output, or other source-control artifacts were added.
Title check ✅ Passed The title clearly identifies the main changes: Hive viewer lifecycle, replay identity, and shared-package integration. It is concise and specific.
Description check ✅ Passed The description is comprehensive and covers the change summary, rationale, testing, verification results, limitations, and remaining acceptance work. It does not include the template's explicit Demo V…
✨ 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-8001-hive-viewer

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 14, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a macOS viewer for paired remote computers. The main changes are:

  • Live workspace and terminal-grid streaming over Tailscale.
  • Remote keyboard input and reconnect handling.
  • Computer pairing and presence controls in Settings.
  • Viewer-window management, localization, and behavior tests.

Confidence Score: 5/5

The latest updates do not add a separate blocking issue.

  • The recent backoff changes preserve the existing runtime behavior.
  • The sendable closure updates do not introduce a new failure path.
  • No additional issue qualifies for a separate follow-up comment.

Important Files Changed

Filename Overview
Packages/macOS/CmuxHive/Sources/CmuxHive/HiveReconnectBackoff.swift Changes reconnect backoff from a static namespace to a configurable value type.
Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift Adds terminal replay, render-grid subscriptions, input forwarding, and reconnect behavior.
Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalInputView.swift Adds AppKit keyboard capture and terminal key mapping.
Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift Builds the viewer layout and wires an explicitly sendable retry closure.

Reviews (10): Last reviewed commit: "Computers: bordered style for the row Op..." | Re-trigger Greptile

Comment thread Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift Outdated
Comment thread Packages/macOS/CmuxHive/Sources/CmuxHive/HiveReconnectBackoff.swift
@austinywang
austinywang force-pushed the issue-8001-hive-viewer branch from 3f4fcfd to ba4166f Compare July 14, 2026 01:25
@blacksmith-sh

This comment has been minimized.

@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: 15

🤖 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/macOS/CmuxHive/Sources/CmuxHive/HiveComputerDirectory.swift`:
- Around line 104-110: Update the listener and live-stream lifecycle handling
around removeListener(id:) and the referenced stream failure/cancellation paths
so loss of authoritative presence resets or expires presenceMap and rebuilds
computer rows with .unknown(...). Perform this invalidation before cancelling or
retrying presenceTask, including subscription failures and EOF, while preserving
normal live updates when the stream remains authoritative.
- Around line 277-280: Update the presence-update flow around the stream loop
and rebuild-related methods to avoid calling rebuild() with a full registry scan
and sort for every frame. Maintain device-ID-indexed row state, update only the
computers affected by each presence update, and publish a coalesced snapshot;
alternatively compute the immutable snapshot off the main actor before
publishing. Preserve existing presenceMap.apply(update) behavior and ensure the
affected-row updates remain consistent with paired records and instance
summaries.
- Around line 117-133: Bind each refresh and pairing flow in
HiveComputerDirectory to one authoritative account scope. Update refresh() to
record the scope owning computers and discard results when the scope changes,
rather than publishing stale data. Update pair(link:) and persistPairing to
reuse the validated scope instead of fetching a new one; registry-row pairing
must fail closed or refresh when its snapshot scope is no longer current.

In `@Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift`:
- Around line 150-152: Update the `.failed(message:)` assignment in
`HiveRemoteMacSession` to remove the raw
`lastError.map(String.init(describing:))` fallback. Preserve the localized
`MobileShellConnectionError` description, but use the existing generic localized
fallback (such as `Self.noRouteMessage`) for all other errors so upstream
details are not exposed.
- Around line 89-153: Update disconnect() to capture and cancel connectTask,
then await that task’s completion before cancelling eventTask and clearing
client/state. Preserve the existing teardown order after the awaited connection
task so any runConnect() completion, including event-loop startup, is cleaned up
before disconnect() returns.

In `@Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift`:
- Around line 149-154: The terminal.render_grid frame loop must avoid decoding
JSON on the MainActor and repeatedly allocating decoders. In
Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift#L149-L154,
dispatch payload decoding through await Task.detached {
Self.decodeFrame(payload) }.value before applying the frame; in `#L178-L185`, mark
decodeFrame nonisolated and add a private static sharedDecoder reused for
decoding instead of creating JSONDecoder inline.

In `@Packages/macOS/CmuxHive/Sources/CmuxHive/HiveTerminalGridModel.swift`:
- Around line 84-88: Update the row-clearing logic in the frame rendering loop
to call removeAll(keepingCapacity: true) on each existing rowSpans[row] array
instead of assigning an empty array, preserving capacity for subsequent span
appends.

In
`@Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveComputerDirectoryTests.swift`:
- Around line 227-235: Update the failure-path test around makeDirectory and
refresh to use one directory with a scripted registry that returns .ok first and
.transientFailure second. Refresh successfully to populate registry rows,
refresh again after the transient failure, and assert lastRefreshFailed is set
while the previously fetched rows remain available instead of expecting
computers to be empty.
- Around line 179-183: Update the persisted-record assertions in the directory
pairing tests, including the additional assertions around the unpairing case, to
load records with stackUserID “user-1” and teamID “team-1” instead of nil
values. Keep the existing emptiness expectations and ensure they query the same
account scope used by directory.pair and unpair operations.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift`:
- Around line 20-32: Update HiveTerminalGridView.body to remove the outer
GeometryReader and construct HiveTerminalGridMetrics inside the Canvas renderer
using Canvas’s provided CGSize parameter instead of proxy.size. Preserve the
existing grid columns, rows, drawing call, and background behavior.
- Around line 152-167: Cache the reference font metrics used by
HiveTerminalGridMetrics.init—referenceAdvance and referenceLineHeight, along
with the fixed referenceSize—at type or module scope so NSFont and
NSLayoutManager are created only once. Update the initializer’s widthLimited,
heightLimited, cellWidth, and lineHeight calculations to reuse those cached
values while preserving the existing sizing bounds and scaling behavior.
- Around line 1-3: Add the AppKit import to HiveTerminalGridView.swift so the
NSFont and NSLayoutManager references used by the view resolve correctly, while
leaving the existing CmuxHive, CMUXMobileCore, and SwiftUI imports unchanged.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift`:
- Around line 59-89: Refactor HiveViewerRootView so detail rendering only looks
up an existing terminal session and never mutates terminalSessions during body
evaluation. Split terminalSession(for:) into a read-only lookup and a creation
method, then trigger creation from selection changes using the appropriate
SwiftUI lifecycle callback while preserving the existing client guard and
session configuration.

In `@Sources/Hive/HiveComputersService.swift`:
- Around line 39-42: Replace the NSLog call in the HiveComputersService error
handler with the project’s existing os.Logger-based logging approach, preserving
the error details and message context. Add the OSLog import if required, and do
not introduce additional ad hoc logging.

In `@Sources/Hive/HiveViewerWindowController.swift`:
- Around line 51-55: Update presentWindow(deviceID:session:) so that when
viewersByDeviceID already contains an existing viewer, it disconnects the
redundant session before bringing the existing window forward and returning.
🪄 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: 7674508f-bd3b-4a21-b604-77f362fb83ef

📥 Commits

Reviewing files that changed from the base of the PR and between a023bef and ba4166f.

⛔ Files ignored due to path filters (1)
  • cmux.xcworkspace/contents.xcworkspacedata is excluded by !**/*.xcworkspace/contents.xcworkspacedata
📒 Files selected for processing (48)
  • Packages/macOS/CmuxHive/Package.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveAccountScope.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveComputer.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveComputerDirectory.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveComputerInstance.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveComputerPresence.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HivePairOutcome.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HivePairingLinkDecoder.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveReconnectBackoff.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteWorkspace.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveSyncRuntime.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveTerminalGridModel.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveComputerDirectoryTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HivePairingLinkDecoderTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveRemoteSessionTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveTerminalGridModelTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/ScriptedHostTransport.swift
  • Packages/macOS/CmuxHiveUI/Package.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveRemoteTerminalPane.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalColor.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalInputView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalKeyMapping.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerWorkspaceList.swift
  • Packages/macOS/CmuxHiveUI/Tests/CmuxHiveUITests/HiveTerminalKeyMappingTests.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Bindings/ComputersListModel.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Bindings/SettingObservationStarting.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Environment/ComputersSettingsSnapshot.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Environment/SettingsHostActions.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Navigation/SettingsSectionID.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Scene/SettingsWindowScene.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/ComputersSection.swift
  • Resources/Localizable.xcstrings
  • Sources/AppDelegate+CloudClients.swift
  • Sources/AppDelegate.swift
  • Sources/CmuxAuxiliaryWindows.swift
  • Sources/Hive/HiveComputersService.swift
  • Sources/Hive/HiveViewerWindowController.swift
  • Sources/HostSettingsActions+Computers.swift
  • Sources/Mobile/Pairing/MobilePairingWindowController.swift
  • Sources/SettingsNavigation.swift
  • Sources/SettingsNavigationTarget+SearchText.swift
  • Sources/SettingsSearchAliases.swift
  • Sources/cmuxApp.swift
  • cmux.xcodeproj/project.pbxproj
💤 Files with no reviewable changes (1)
  • Sources/cmuxApp.swift

Comment thread Packages/macOS/CmuxHive/Sources/CmuxHive/HiveComputerDirectory.swift Outdated
Comment thread Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift
Comment thread Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift Outdated
Comment thread Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift Outdated
Comment thread Sources/Hive/HiveComputersService.swift
Comment thread Sources/Hive/HiveViewerWindowController.swift Outdated
@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@austinywang
austinywang force-pushed the issue-8001-hive-viewer branch 2 times, most recently from ae25654 to 19440d2 Compare July 14, 2026 02:18
Comment thread Packages/macOS/CmuxHive/Sources/CmuxHive/HiveReconnectBackoff.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: 2

♻️ Duplicate comments (6)
Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift (2)

89-99: 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

disconnect() still doesn't synchronize with an in-flight runConnect() — unresolved from prior review.

disconnect() cancels connectTask without awaiting it. runConnect() (lines 124-149) only checks Task.isCancelled at the top of the route loop, not after fetchWorkspaces (line 138) resumes successfully. If disconnect() runs while runConnect() is suspended there, the resumed task can still set client, workspaces, phase = .connected, and start a brand-new eventTask after the session was told to disconnect — leaving a live socket/poll loop running on a session the app believes is idle.

🔒 Proposed fix
 public func disconnect() async {
     connectTask?.cancel()
+    await connectTask?.value
     connectTask = nil
     eventTask?.cancel()
     eventTask = nil
     if let client {
         await client.disconnect()
     }
     client = nil
     phase = .idle
 }
🤖 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/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift` around
lines 89 - 99, Update disconnect() and the runConnect() flow so disconnect
awaits completion of any in-flight connectTask before clearing the client and
setting phase to .idle. Ensure runConnect() rechecks cancellation after
fetchWorkspaces resumes and before publishing client/workspaces, transitioning
to .connected, or starting eventTask, preventing connection state from being
installed after disconnect.

150-152: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Failure message still leaks raw upstream error text — unresolved from prior review.

The lastError.map(String.init(describing:)) fallback prints whatever raw Error was thrown (socket/decoding/internal detail) into the user-visible .failed(message:) string, which flows straight into HiveViewerRootView's ContentUnavailableView description.

🛡️ Proposed fix
-        phase = .failed(message: (lastError as? MobileShellConnectionError)?.localizedDescription
-            ?? lastError.map(String.init(describing:))
-            ?? Self.noRouteMessage)
+        phase = .failed(message: (lastError as? MobileShellConnectionError)?.localizedDescription
+            ?? Self.noRouteMessage)
As per coding guidelines: "User-facing errors, alerts, ... must not expose ... raw upstream messages, identifiers, credentials, tokens, headers, private keys, session IDs, or unredacted payloads."
🤖 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/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift` around
lines 150 - 152, Update the failure-message construction in the session failure
path to remove the raw lastError String(describing:) fallback. Expose only
MobileShellConnectionError.localizedDescription when it is safe and otherwise
use Self.noRouteMessage, ensuring .failed(message:) never receives unredacted
upstream error details.

Source: Coding guidelines

Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift (1)

59-89: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Terminal session creation still mutates @State from a helper called during body evaluation — unresolved from prior review.

terminalSession(for:) is invoked from detail (part of body) and writes into terminalSessions (line 87) as a side effect of rendering, which SwiftUI can flag as undefined behavior ("Modifying state during view update").

♻️ Proposed refactor
     public var body: some View {
         NavigationSplitView {
             HiveViewerWorkspaceList(
                 workspaces: session.workspaces,
                 selection: $selection
             )
             .navigationSplitViewColumnWidth(min: 180, ideal: 230)
         } detail: {
             detail
         }
         .navigationTitle(session.displayName)
         .onAppear { session.connect() }
         .onChange(of: session.workspaces) { _, workspaces in
             reconcileSelection(workspaces: workspaces)
         }
+        .onChange(of: selection) { _, newSelection in
+            ensureTerminalSession(for: newSelection)
+        }
         .task {
             reconcileSelection(workspaces: session.workspaces)
+            ensureTerminalSession(for: selection)
         }
     }
     ...
-    private func terminalSession(for selection: HiveViewerSelection) -> HiveRemoteTerminalSession? {
-        if let existing = terminalSessions[selection] { return existing }
-        guard let client = session.client else { return nil }
-        let terminal = HiveRemoteTerminalSession(
-            client: client,
-            workspaceID: selection.workspaceID,
-            terminalID: selection.terminalID,
-            retryDelay: HiveReconnectBackoff().delay(attempt:)
-        )
-        terminalSessions[selection] = terminal
-        return terminal
-    }
+    private func terminalSession(for selection: HiveViewerSelection?) -> HiveRemoteTerminalSession? {
+        guard let selection else { return nil }
+        return terminalSessions[selection]
+    }
+
+    private func ensureTerminalSession(for selection: HiveViewerSelection?) {
+        guard let selection, terminalSessions[selection] == nil,
+              let client = session.client else { return }
+        terminalSessions[selection] = HiveRemoteTerminalSession(
+            client: client,
+            workspaceID: selection.workspaceID,
+            terminalID: selection.terminalID,
+            retryDelay: HiveReconnectBackoff().delay(attempt:)
+        )
+    }
As per coding guidelines: "Do not mutate state from `body` or helpers called by `body`... use lifecycle callbacks, model observers, reload completions, or event handlers instead."
🤖 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/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift` around
lines 59 - 89, Remove the terminalSessions mutation from terminalSession(for:)
when it is called during detail/body evaluation. Refactor session creation and
caching into a lifecycle callback, model observer, reload completion, or event
handler, then have terminalSession(for:) only read and return an existing
session; preserve the existing client, workspace, terminal, and retry
configuration.

Source: Coding guidelines

Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift (3)

1-4: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Import AppKit explicitly.

NSFont and NSLayoutManager are used in this file. Please explicitly import AppKit to ensure these references resolve correctly, rather than relying on transitive imports.

♻️ Proposed refactor
 public import CmuxHive
 import CMUXMobileCore
 public import SwiftUI
+public import AppKit
🤖 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/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift`
around lines 1 - 4, Update the imports in HiveTerminalGridView to explicitly
include AppKit, ensuring the NSFont and NSLayoutManager references resolve
directly while preserving the existing imports.

20-32: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Drop the outer GeometryReader; use Canvas's own size parameter.

Canvas's renderer closure already receives (inout GraphicsContext, CGSize) — the size parameter here is discarded (_) while proxy.size from a wrapping GeometryReader is used instead. The GeometryReader is redundant and adds an avoidable layout indirection. As per coding guidelines, avoid GeometryReader when localized background measurement or intrinsic alternatives exist.

♻️ Proposed refactor
     public var body: some View {
-        GeometryReader { proxy in
-            let metrics = HiveTerminalGridMetrics(
-                columns: grid.columns,
-                rows: grid.rows,
-                available: proxy.size
-            )
-            Canvas { context, _ in
-                draw(in: &context, metrics: metrics)
-            }
-        }
+        Canvas { context, size in
+            let metrics = HiveTerminalGridMetrics(
+                columns: grid.columns,
+                rows: grid.rows,
+                available: size
+            )
+            draw(in: &context, metrics: metrics)
+        }
         .background(HiveTerminalColor.parse(grid.terminalBackground) ?? HiveTerminalColor.fallbackBackground)
     }
🤖 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/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift`
around lines 20 - 32, Remove the outer GeometryReader from
HiveTerminalGridView.body and use the Canvas renderer’s CGSize parameter when
constructing HiveTerminalGridMetrics. Keep the existing grid columns, rows,
drawing call, and background behavior unchanged.

Source: Coding guidelines


152-167: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Hoist the reference font measurement out of the per-render init.

referenceFont, referenceAdvance, and referenceLineHeight only depend on the constant referenceSize, yet they're recomputed (including an NSFont allocation and an NSLayoutManager() instantiation) every time HiveTerminalGridMetrics is built — which happens on every streamed grid update, a rendering hot path. Cache these once and reuse them for the per-call scaling math.

♻️ Proposed refactor
     let cellWidth: CGFloat
     let lineHeight: CGFloat
     let fontSize: CGFloat
+
+    private static let referenceSize: CGFloat = 13
+    private static let referenceFont = NSFont.monospacedSystemFont(ofSize: referenceSize, weight: .regular)
+    private static let referenceAdvance = ("0" as NSString).size(withAttributes: [.font: referenceFont]).width
+    private static let referenceLineHeight = NSLayoutManager().defaultLineHeight(for: referenceFont)
 
     init(columns: Int, rows: Int, available: CGSize) {
         let columns = max(columns, 1)
         let rows = max(rows, 1)
-        // Measure the reference font once; monospaced advances scale linearly
-        // with point size, so one measurement fits any target size.
-        let referenceSize: CGFloat = 13
-        let referenceFont = NSFont.monospacedSystemFont(ofSize: referenceSize, weight: .regular)
-        let referenceAdvance = ("0" as NSString).size(withAttributes: [.font: referenceFont]).width
-        let referenceLineHeight = NSLayoutManager().defaultLineHeight(for: referenceFont)
-        let widthLimited = available.width / (CGFloat(columns) * referenceAdvance / referenceSize)
-        let heightLimited = available.height / (CGFloat(rows) * referenceLineHeight / referenceSize)
+        let sizeFactor = Self.referenceSize
+        let advance = Self.referenceAdvance
+        let refLineHeight = Self.referenceLineHeight
+        let widthLimited = available.width / (CGFloat(columns) * advance / sizeFactor)
+        let heightLimited = available.height / (CGFloat(rows) * refLineHeight / sizeFactor)
-        let size = max(min(widthLimited, heightLimited, 20), 4)
+        let size = max(min(widthLimited, heightLimited, 20), 4)
         fontSize = size
-        cellWidth = referenceAdvance * size / referenceSize
+        cellWidth = advance * size / sizeFactor
-        lineHeight = referenceLineHeight * size / referenceSize
+        lineHeight = refLineHeight * size / sizeFactor
     }
🤖 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/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift`
around lines 152 - 167, Move the constant reference font metrics used by
HiveTerminalGridMetrics.init(columns:rows:available:) into shared cached static
properties, including referenceAdvance and referenceLineHeight, so NSFont and
NSLayoutManager are created once. Update the initializer to reuse those cached
values for its per-call scaling calculations while preserving the existing
sizing and clamping behavior.
🤖 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/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalInputView.swift`:
- Around line 49-54: Remove the unconditional first-responder assignment from
updateNSView in HiveTerminalInputView; keep updating nsView.actions, but let the
existing mouseDown interaction or a dedicated focus model control terminal focus
instead of using isFocused during SwiftUI render updates.

In
`@Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/ComputersSection.swift`:
- Around line 308-314: Update the “Open” Button in the computer row to apply the
existing isPending state via .disabled(isPending), matching the Pair and Unpair
controls and preventing actions while unpairing is in progress.

---

Duplicate comments:
In `@Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift`:
- Around line 89-99: Update disconnect() and the runConnect() flow so disconnect
awaits completion of any in-flight connectTask before clearing the client and
setting phase to .idle. Ensure runConnect() rechecks cancellation after
fetchWorkspaces resumes and before publishing client/workspaces, transitioning
to .connected, or starting eventTask, preventing connection state from being
installed after disconnect.
- Around line 150-152: Update the failure-message construction in the session
failure path to remove the raw lastError String(describing:) fallback. Expose
only MobileShellConnectionError.localizedDescription when it is safe and
otherwise use Self.noRouteMessage, ensuring .failed(message:) never receives
unredacted upstream error details.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift`:
- Around line 1-4: Update the imports in HiveTerminalGridView to explicitly
include AppKit, ensuring the NSFont and NSLayoutManager references resolve
directly while preserving the existing imports.
- Around line 20-32: Remove the outer GeometryReader from
HiveTerminalGridView.body and use the Canvas renderer’s CGSize parameter when
constructing HiveTerminalGridMetrics. Keep the existing grid columns, rows,
drawing call, and background behavior unchanged.
- Around line 152-167: Move the constant reference font metrics used by
HiveTerminalGridMetrics.init(columns:rows:available:) into shared cached static
properties, including referenceAdvance and referenceLineHeight, so NSFont and
NSLayoutManager are created once. Update the initializer to reuse those cached
values for its per-call scaling calculations while preserving the existing
sizing and clamping behavior.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift`:
- Around line 59-89: Remove the terminalSessions mutation from
terminalSession(for:) when it is called during detail/body evaluation. Refactor
session creation and caching into a lifecycle callback, model observer, reload
completion, or event handler, then have terminalSession(for:) only read and
return an existing session; preserve the existing client, workspace, terminal,
and retry configuration.
🪄 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: 18b2f6a8-29de-4ec1-a35b-5a32f39e8e61

📥 Commits

Reviewing files that changed from the base of the PR and between ba4166f and ae25654.

⛔ Files ignored due to path filters (1)
  • cmux.xcworkspace/contents.xcworkspacedata is excluded by !**/*.xcworkspace/contents.xcworkspacedata
📒 Files selected for processing (35)
  • .github/review-bot-rules/swift-auxiliary-window-close-shortcuts.md
  • Packages/macOS/CmuxHive/Package.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveComposition.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveComputer.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveComputerDirectory.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveReconnectBackoff.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteWorkspace.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveSyncRuntime.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveTerminalGridModel.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveRemoteSessionTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveTerminalGridModelTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/ScriptedHostTransport.swift
  • Packages/macOS/CmuxHiveUI/Package.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveRemoteTerminalPane.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalColor.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalInputView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalKeyMapping.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerWorkspaceList.swift
  • Packages/macOS/CmuxHiveUI/Tests/CmuxHiveUITests/HiveTerminalKeyMappingTests.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Environment/SettingsHostActions.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/ComputersSection.swift
  • Resources/Localizable.xcstrings
  • Sources/CmuxAuxiliaryWindows.swift
  • Sources/Hive/HiveComputersService.swift
  • Sources/Hive/HiveViewerWindowController.swift
  • Sources/HostSettingsActions+Computers.swift
  • Sources/Mobile/Pairing/MobilePairingWindowController.swift
  • Sources/cmuxApp.swift
  • cmux.xcodeproj/project.pbxproj
  • scripts/lint_auxiliary_window_close_shortcuts.py
  • tests/test_ci_auxiliary_window_close_shortcuts.sh
💤 Files with no reviewable changes (1)
  • Sources/cmuxApp.swift

@austinywang
austinywang force-pushed the issue-8001-hive-viewer branch from 19440d2 to 4f0f897 Compare July 14, 2026 02:32

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Packages/macOS/CmuxHive/Package.swift (1)

1-59: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Include the Package.resolved lockfile in the PR diff.

The PR introduces new Swift packages (CmuxHive) and updates package references, but the root Xcode Package.resolved (at cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved) is missing from the PR stack. As per path instructions, whenever Swift package references change via Package.swift or xcodeproj, the corresponding lockfile must be committed to ensure no unexpected pin changes are hidden.

🤖 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/macOS/CmuxHive/Package.swift` around lines 1 - 59, Add the root
Xcode SwiftPM lockfile at
cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved to the
PR, regenerated after the dependency changes in the CmuxHive Package.swift
manifest. Ensure it records the resolved revisions for all referenced packages
without making unrelated dependency updates.

Source: Path instructions

♻️ Duplicate comments (1)
Sources/Hive/HiveViewerWindowController.swift (1)

51-55: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Disconnect the duplicate session to prevent resource leaks.

If show(deviceID:) is called rapidly in succession (e.g., from a double-click), multiple HiveRemoteMacSession instances will be created concurrently. When presentWindow processes the subsequent calls, it finds the existing window and returns early, which abandons the redundant session without calling its disconnect() method. This leaks the underlying network connections and tasks.

♻️ Proposed fix
     private func presentWindow(deviceID: String, session: HiveRemoteMacSession) {
         if let existing = viewersByDeviceID[deviceID] {
             existing.window.makeKeyAndOrderFront(nil)
+            Task { `@MainActor` in
+                await session.disconnect()
+            }
             return
         }
🤖 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/Hive/HiveViewerWindowController.swift` around lines 51 - 55, Update
presentWindow(deviceID:session:) so that when viewersByDeviceID[deviceID]
already contains a viewer, the incoming duplicate session is disconnected before
returning; preserve the existing window activation behavior.
🤖 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/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift`:
- Around line 171-175: Validate the decoded replay response’s workspace and
surface IDs against the active session before processing renderGrid in the
MobileTerminalReplayResponse path. Reject mismatched responses and only call
grid.apply(frame) when both identities match the current terminal session,
preserving input targeting through terminalID.

In `@Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteWorkspace.swift`:
- Around line 4-42: Mark the pure value-model types as nonisolated: add it to
HiveRemoteWorkspace and its nested Terminal in
Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteWorkspace.swift (lines 4-42),
HiveTerminalGridModel in
Packages/macOS/CmuxHive/Sources/CmuxHive/HiveTerminalGridModel.swift (line 16),
and HiveViewerSelection in
Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift (lines
109-119). Preserve their existing Sendable, Identifiable, and value-model
behavior.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveRemoteTerminalPane.swift`:
- Around line 17-24: Update the HiveTerminalInputView configuration in
HiveRemoteTerminalPane so input focus is enabled only when terminal.phase equals
.live, and remains disabled for attaching, reattaching, or any other unavailable
state. Use the typed lifecycle state directly and fail closed when a reliable
live signal is absent.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift`:
- Line 12: Update HiveViewerRootView’s workspaces reconciliation flow, including
reconcileSelection and the terminalSessions update path, to identify cached
sessions whose workspaceID/terminalID no longer exists in the live workspaces
and call each session’s detach() before removing its dictionary entry. Preserve
existing selection redirection and retain sessions that still correspond to live
terminals.

---

Outside diff comments:
In `@Packages/macOS/CmuxHive/Package.swift`:
- Around line 1-59: Add the root Xcode SwiftPM lockfile at
cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved to the
PR, regenerated after the dependency changes in the CmuxHive Package.swift
manifest. Ensure it records the resolved revisions for all referenced packages
without making unrelated dependency updates.

---

Duplicate comments:
In `@Sources/Hive/HiveViewerWindowController.swift`:
- Around line 51-55: Update presentWindow(deviceID:session:) so that when
viewersByDeviceID[deviceID] already contains a viewer, the incoming duplicate
session is disconnected before returning; preserve the existing window
activation behavior.
🪄 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: dd9e7ab1-06cf-4b35-a610-4c1e1f275879

📥 Commits

Reviewing files that changed from the base of the PR and between ae25654 and 19440d2.

⛔ Files ignored due to path filters (1)
  • cmux.xcworkspace/contents.xcworkspacedata is excluded by !**/*.xcworkspace/contents.xcworkspacedata
📒 Files selected for processing (31)
  • .github/review-bot-rules/swift-auxiliary-window-close-shortcuts.md
  • Packages/macOS/CmuxHive/Package.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteWorkspace.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveSyncRuntime.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveTerminalGridModel.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveRemoteSessionTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveTerminalGridModelTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/ScriptedHostTransport.swift
  • Packages/macOS/CmuxHiveUI/Package.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveRemoteTerminalPane.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalColor.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalInputView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalKeyMapping.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerWorkspaceList.swift
  • Packages/macOS/CmuxHiveUI/Tests/CmuxHiveUITests/HiveTerminalKeyMappingTests.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Environment/SettingsHostActions.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/ComputersSection.swift
  • Resources/Localizable.xcstrings
  • Sources/CmuxAuxiliaryWindows.swift
  • Sources/Hive/HiveComputersService.swift
  • Sources/Hive/HiveViewerWindowController.swift
  • Sources/HostSettingsActions+Computers.swift
  • Sources/Mobile/Pairing/MobilePairingWindowController.swift
  • Sources/cmuxApp.swift
  • cmux.xcodeproj/project.pbxproj
  • scripts/lint_auxiliary_window_close_shortcuts.py
  • tests/test_ci_auxiliary_window_close_shortcuts.sh
💤 Files with no reviewable changes (1)
  • Sources/cmuxApp.swift

Comment thread Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteWorkspace.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: 5

♻️ Duplicate comments (7)
Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift (3)

20-32: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Redundant GeometryReader wrapping Canvas.

Canvas's renderer closure already receives (inout GraphicsContext, CGSize); the parameter is discarded (_) while proxy.size from the outer GeometryReader is used instead, adding an avoidable layout indirection — unchanged from the prior round.

♻️ Proposed refactor
     public var body: some View {
-        GeometryReader { proxy in
-            let metrics = HiveTerminalGridMetrics(
-                columns: grid.columns,
-                rows: grid.rows,
-                available: proxy.size
-            )
-            Canvas { context, _ in
-                draw(in: &context, metrics: metrics)
-            }
-        }
+        Canvas { context, size in
+            let metrics = HiveTerminalGridMetrics(
+                columns: grid.columns,
+                rows: grid.rows,
+                available: size
+            )
+            draw(in: &context, metrics: metrics)
+        }
         .background(HiveTerminalColor.parse(grid.terminalBackground) ?? HiveTerminalColor.fallbackBackground)
     }
🤖 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/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift`
around lines 20 - 32, Remove the outer GeometryReader from
HiveTerminalGridView.body and use Canvas’s renderer CGSize parameter when
constructing HiveTerminalGridMetrics.available. Preserve the existing grid
columns, rows, draw call, and background behavior while eliminating the
discarded renderer size and redundant layout wrapper.

1-3: 🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

NSFont/NSLayoutManager used without an AppKit import.

This file only imports CmuxHive, CMUXMobileCore, and SwiftUI, yet NSFont.monospacedSystemFont (line 158) and NSLayoutManager() (line 160) are AppKit types. SwiftUI does not re-export AppKit types on macOS. A prior review round flagged this exact gap and marked it resolved in a later commit, but the current final file still lacks the import — please confirm this compiles, or add import AppKit.

#!/bin/bash
rg -n '^(public )?import AppKit' Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift
rg -n '_exported import AppKit' Packages/macOS/CmuxHiveUI Packages/Shared 2>/dev/null

Also applies to: 158-158, 160-160

🤖 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/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift`
around lines 1 - 3, Add an explicit AppKit import to HiveTerminalGridView
alongside its existing imports so the NSFont and NSLayoutManager references
compile on macOS; do not rely on SwiftUI re-exporting AppKit.

152-167: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Reference font measurement recomputed on every render.

referenceFont/referenceAdvance/referenceLineHeight only depend on the constant referenceSize but are recomputed — including an NSFont allocation and an NSLayoutManager() instantiation — on every HiveTerminalGridMetrics init, which happens on each streamed grid update (a rendering hot path). Cache these once at type scope.

As per coding guidelines: "Do not allocate NumberFormatter, DateFormatter... or similar formatters per call inside loops, row bodies, or concurrent maps; allocate once and reuse."

🤖 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/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift`
around lines 152 - 167, Cache the constant reference font metrics used by
HiveTerminalGridMetrics.init at type scope, including referenceAdvance and
referenceLineHeight (and the reference font if needed), so they are computed
once rather than per initialization. Update init to reuse those cached values
while preserving the existing size, cellWidth, and lineHeight calculations.

Source: Coding guidelines

Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift (2)

163-176: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Replay path applies frames without validating workspace/surface identity.

requestReplay() decodes MobileTerminalReplayResponse and calls grid.apply(frame) unconditionally. If the replay payload carries workspace/surface identity, a stale or misrouted response could paint the wrong terminal's grid while input still targets terminalID. Reject replays whose IDs don't match workspaceID/terminalID before applying. Unchanged from the prior round.

As per path instructions, correctness-critical workspace/surface identity must be validated against a single authoritative source rather than trusted implicitly.

🤖 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/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift`
around lines 163 - 176, Update requestReplay() to validate the decoded
MobileTerminalReplayResponse workspace and surface identifiers against the
authoritative workspaceID and terminalID before calling grid.apply(frame).
Reject or ignore mismatched replay responses, and only apply the frame when both
identities match.

Source: Path instructions


149-154: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

JSON frame decoding still runs on the @MainActor with a per-call JSONDecoder.

decodeFrame is a static member of this @MainActor class, so decoding terminal.render_grid payloads (line 151) happens on the main actor for every streamed frame — a latency-sensitive path — and allocates a new JSONDecoder() each call (line 184) instead of reusing one. Unchanged from the prior round.

As per coding guidelines: "flag changed CPU-heavy, file-I/O-heavy, parsing-heavy, or network-heavy async helpers called from UI isolation without an explicit actor hop."

🔧 Proposed fix
-    static func decodeFrame(_ payload: Data) -> MobileTerminalRenderGridFrame? {
+    private static let sharedDecoder = JSONDecoder()
+
+    nonisolated static func decodeFrame(_ payload: Data) -> MobileTerminalRenderGridFrame? {
         if let event = try? MobileTerminalRenderGridEvent.decode(payload), let frame = event.frame {
             return frame
         }
-        return try? JSONDecoder().decode(MobileTerminalRenderGridFrame.self, from: payload)
+        return try? sharedDecoder.decode(MobileTerminalRenderGridFrame.self, from: payload)
     }

and at the call site:

-                guard let payload = envelope.payloadJSON,
-                      let frame = Self.decodeFrame(payload),
+                guard let payload = envelope.payloadJSON,
+                      let frame = await Task.detached { Self.decodeFrame(payload) }.value,
                       frame.surfaceID == terminalID else { continue }

Also applies to: 178-185

🤖 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/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift`
around lines 149 - 154, Move terminal.render_grid frame decoding out of the
`@MainActor` by making decodeFrame nonisolated and explicitly hopping to a
background task or actor from the stream loop before decoding; keep UI updates
through grid.apply on the main actor. Reuse a shared JSONDecoder instead of
constructing one per decode call, updating decodeFrame and its call site while
preserving frame filtering behavior.

Source: Coding guidelines

Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveRemoteTerminalPane.swift (1)

17-24: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Input stays enabled during .attaching/.reattaching.

isFocused: true is hardcoded regardless of terminal.phase, so keystrokes can be captured/sent while the terminal isn't actually live. Drive isFocused from terminal.phase == .live and fail closed otherwise.

As per path instructions, correctness-critical input-route enable/disable must be driven by a single authoritative lifecycle source and fail closed when a reliable live signal is missing.

🔧 Proposed fix
             HiveTerminalInputView(
                 actions: HiveTerminalInputView.Actions(
                     sendText: { [weak terminal] in terminal?.send(text: $0) },
                     sendSpecial: { [weak terminal] in terminal?.send(specialKey: $0, modifiers: $1) },
                     sendControl: { [weak terminal] in terminal?.send(controlCharacter: $0) }
                 ),
-                isFocused: true
+                isFocused: terminal.phase == .live
             )
🤖 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/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveRemoteTerminalPane.swift`
around lines 17 - 24, Update the HiveTerminalInputView configuration in
HiveRemoteTerminalPane so isFocused is derived from the authoritative terminal
lifecycle state, enabling input only when terminal.phase == .live and returning
false for every other phase, including attaching and reattaching.

Source: Path instructions

Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift (1)

12-12: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Cached terminal sessions for vanished terminals are never detached.

terminalSessions only grows; reconcileSelection redirects selection away from a stale terminal/workspace but leaves that entry's HiveRemoteTerminalSession (and its background attach/reconnect loop) running indefinitely in the dictionary, unreachable from the UI. Prune entries whose (workspaceID, terminalID) no longer exists when workspaces updates, calling detach() before removal.

Also applies to: 78-107

🤖 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/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift` at
line 12, Update reconcileSelection and the workspaces-update reconciliation flow
to prune terminalSessions entries whose workspaceID/terminalID pair no longer
exists in workspaces. Call detach() on each stale HiveRemoteTerminalSession
before removing it from the dictionary, while preserving active sessions and
existing selection redirection behavior.
🤖 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/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift`:
- Around line 172-185: Update fetchWorkspaces in HiveRemoteMacSession so the
request result decoding and complete workspace/terminal mapping run through a
nonisolated or `@concurrent` helper/off-main service rather than on MainActor.
Await that helper, then return or assign the fully constructed
[HiveRemoteWorkspace] value on the existing actor-isolated path.

In
`@Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveTerminalGridModelTests.swift`:
- Line 65: Update the test around the rowSpans style assertion to safely
validate that the collection contains the required second element before
indexing it. Ensure the style assertion can fail normally rather than trapping
when the earlier grid.rows expectation does not guarantee rowSpans.count.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalInputView.swift`:
- Around line 68-76: Update the paste condition in HiveTerminalInputView so it
matches plain Command+V only, rejecting additional Shift, Option, or Control
modifiers while preserving the existing pasteboard lookup and actions?.sendText
behavior.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift`:
- Line 41: Refactor terminal-session handling around detail and
terminalSession(for:) so view rendering only performs lookup and never mutates
terminalSessions. Move session creation into a state-change-driven path
triggered by selection changes or an appropriate .task, while preserving reuse
of existing sessions and ensuring the selected session is available before
detail renders.
- Around line 45-57: Replace the raw Text(message) rendering in the .failed case
of HiveViewerRootView with a product-facing sanitized failure string, avoiding
direct display of MobileShellConnectionError.localizedDescription or
HiveRemoteMacSession descriptions. Keep the existing retry action and
unavailable-content layout unchanged.

---

Duplicate comments:
In `@Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift`:
- Around line 163-176: Update requestReplay() to validate the decoded
MobileTerminalReplayResponse workspace and surface identifiers against the
authoritative workspaceID and terminalID before calling grid.apply(frame).
Reject or ignore mismatched replay responses, and only apply the frame when both
identities match.
- Around line 149-154: Move terminal.render_grid frame decoding out of the
`@MainActor` by making decodeFrame nonisolated and explicitly hopping to a
background task or actor from the stream loop before decoding; keep UI updates
through grid.apply on the main actor. Reuse a shared JSONDecoder instead of
constructing one per decode call, updating decodeFrame and its call site while
preserving frame filtering behavior.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveRemoteTerminalPane.swift`:
- Around line 17-24: Update the HiveTerminalInputView configuration in
HiveRemoteTerminalPane so isFocused is derived from the authoritative terminal
lifecycle state, enabling input only when terminal.phase == .live and returning
false for every other phase, including attaching and reattaching.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift`:
- Around line 20-32: Remove the outer GeometryReader from
HiveTerminalGridView.body and use Canvas’s renderer CGSize parameter when
constructing HiveTerminalGridMetrics.available. Preserve the existing grid
columns, rows, draw call, and background behavior while eliminating the
discarded renderer size and redundant layout wrapper.
- Around line 1-3: Add an explicit AppKit import to HiveTerminalGridView
alongside its existing imports so the NSFont and NSLayoutManager references
compile on macOS; do not rely on SwiftUI re-exporting AppKit.
- Around line 152-167: Cache the constant reference font metrics used by
HiveTerminalGridMetrics.init at type scope, including referenceAdvance and
referenceLineHeight (and the reference font if needed), so they are computed
once rather than per initialization. Update init to reuse those cached values
while preserving the existing size, cellWidth, and lineHeight calculations.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift`:
- Line 12: Update reconcileSelection and the workspaces-update reconciliation
flow to prune terminalSessions entries whose workspaceID/terminalID pair no
longer exists in workspaces. Call detach() on each stale
HiveRemoteTerminalSession before removing it from the dictionary, while
preserving active sessions and existing selection redirection behavior.
🪄 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: 5ba81097-da58-4355-a6fd-7997287d347f

📥 Commits

Reviewing files that changed from the base of the PR and between 19440d2 and df779de.

⛔ Files ignored due to path filters (1)
  • cmux.xcworkspace/contents.xcworkspacedata is excluded by !**/*.xcworkspace/contents.xcworkspacedata
📒 Files selected for processing (33)
  • .github/review-bot-rules/swift-auxiliary-window-close-shortcuts.md
  • Packages/macOS/CmuxHive/Package.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveComposition.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteWorkspace.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveSyncRuntime.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveTerminalGridModel.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveRemoteSessionTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveTerminalGridModelTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/ScriptedHostTransport.swift
  • Packages/macOS/CmuxHiveUI/Package.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveRemoteTerminalPane.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalColor.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalInputView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalKeyMapping.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerWorkspaceList.swift
  • Packages/macOS/CmuxHiveUI/Tests/CmuxHiveUITests/HiveTerminalKeyMappingTests.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Environment/ComputersSettingsSnapshot.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Environment/SettingsHostActions.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/ComputersSection.swift
  • Resources/Localizable.xcstrings
  • Sources/CmuxAuxiliaryWindows.swift
  • Sources/Hive/HiveComputersService.swift
  • Sources/Hive/HiveViewerWindowController.swift
  • Sources/HostSettingsActions+Computers.swift
  • Sources/Mobile/Pairing/MobilePairingWindowController.swift
  • Sources/cmuxApp.swift
  • cmux.xcodeproj/project.pbxproj
  • scripts/lint_auxiliary_window_close_shortcuts.py
  • tests/test_ci_auxiliary_window_close_shortcuts.sh
💤 Files with no reviewable changes (1)
  • Sources/cmuxApp.swift

Comment thread Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift Outdated
Comment thread Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveTerminalGridModelTests.swift Outdated
@austinywang
austinywang force-pushed the issue-8001-hive-viewer branch from df779de to ac672db Compare July 14, 2026 19:15
austinywang and others added 8 commits July 14, 2026 12:21
…airing

Add the account-level device list and pairing half of hive M1 (the
remote-workspace viewer follows in the next slice).

- New Packages/macOS/CmuxHive: HiveComputerDirectory merges the team
  device registry (DeviceRegistryService), the local paired-computer
  store (MobilePairedMacStore in hive-paired-computers.sqlite3), and
  the presence worker stream (PresenceClient) into value-snapshot rows;
  HivePairingLinkDecoder applies the Mac-side loopback/account policy
  over the shared CmxAttachTicketInput grammar. 13 behavior tests.
- Settings > Computers section in CmuxSettingsUI: presence indicator,
  one-click pair from a registry row, pairing-link paste (the macOS
  counterpart of the phone's QR scan), unpair, refresh, and a shortcut
  to the existing pairing window.
- App wiring: HiveComputersService composition at the root (extracted
  configureCloudClients keeps AppDelegate.swift under budget),
  HostSettingsActions+Computers host bridge, settings navigation and
  search entries, EN+JA localization for all new strings.
- Links the existing iOS client packages (already macOS-capable) into
  the macOS app through CmuxHive; iOS targets unchanged.

Part of #8001

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

HiveComputersService.swift imports both modules directly, but only
CmuxHive was a declared product dependency, so the linker did not
reliably pull their static archives into the app dylib (undefined
symbols for DeviceRegistryService / PresenceClient /
MobilePairedMacStore on CI). Declare the products the app imports,
on both the cmux and cmuxTests targets.

Part of #8001

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

The app-side HiveComputersService named DeviceRegistryService /
PresenceClient / MobilePairedMacStore directly, which required declaring
CmuxMobileShell and CmuxMobilePairedMac as app-target package products.
That perturbed Xcode's package-product linkage graph: with the products
declared, CmuxAgentChat symbols moved out of the app binary's exports
and the cmuxTests bundle (which resolves them via bundle_loader) failed
to link on CI; without them, HiveComputersService.o itself had
undefined symbols.

Fix the class of problem instead of the instance: a new HiveComposition
factory inside CmuxHive names the concrete client-stack types, and the
app's composition root supplies configuration only (URLs, token
closures, device identity, loopback policy). The app target now imports
and links nothing below CmuxHive, so the pre-existing app/test linkage
graph is untouched (the product-dependency commit is reverted).

Also: HiveReconnectBackoff (instantiable bounded backoff shared by the
directory's presence resubscribe), and internal-import tightening that
clears public-import warnings.

Part of #8001

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adding CmuxHive (whose closure includes CmuxAgentChat via
CmuxMobileShell) to both the app and test targets makes Xcode build
CmuxAgentChat as part of a dynamic package framework instead of
statically into the app binary, so the app stops exporting its symbols
and the test bundle — which imports CmuxAgentChat but had no product
dependency of its own, resolving via bundle_loader — fails to link
(every undefined symbol on CI is a CmuxAgentChat one). Declare the
product on cmuxTests like the other shared packages so the test bundle
links it directly.

Part of #8001

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An unapplied method reference is not inferred @sendable, which trips
the Swift warning budget on the app build.

Part of #8001

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The only way to pair Mac-to-Mac was "Show Pairing Code…", which opens
the iPhone QR window — a Mac has no camera pointed at it. Add a Copy
Pairing Link button to the Pair This Mac row: it mints the same attach
payload the QR encodes (Tailscale-only v2 grammar; dev builds fall back
to an all-routes ticket so two tagged builds on one machine can pair
over loopback), puts it on the clipboard, and shows inline feedback.
Paste it into "Add by Pairing Link" on the other Mac.

Part of #8001

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Mac-to-Mac pairing is the copy-link flow; the QR window is an iPhone
concern and stays reachable from Settings > Mobile.

Part of #8001

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmux.xcodeproj/project.pbxproj (1)

8514-8523: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the root Xcode lockfile for these package refs. cmux.xcodeproj/project.pbxproj:8514-8523 adds CmuxHive and CmuxHiveUI, but cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved is not in the diff. Commit that lockfile alongside the project change so package resolution stays consistent.

🤖 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 `@cmux.xcodeproj/project.pbxproj` around lines 8514 - 8523, Commit the root
Swift Package Manager lockfile alongside the new CmuxHive and CmuxHiveUI product
dependencies. Update the workspace Package.resolved to record both local package
references and their resolved dependencies, keeping it consistent with the
XCSwiftPackageProductDependency entries in the project configuration.

Source: Path instructions

♻️ Duplicate comments (1)
Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift (1)

171-175: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Reject incomplete or mismatched replay responses.

requestReplay() succeeds when renderGrid is absent, after which the caller marks the session .live with an empty grid and stops retrying. Require a full frame before returning, and retain the previously requested workspace/surface identity checks before applying it.

🤖 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/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift`
around lines 171 - 175, Update requestReplay() to reject responses without
renderGrid by treating them as failures so callers do not mark an empty session
live. Before applying the frame, preserve and enforce the existing workspace and
surface identity checks, and only return successfully after receiving a complete
matching replay frame.
🤖 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/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift`:
- Around line 104-120: Replace the untracked Task in sendInput with a
session-owned, cancellable input worker that serializes requests in submission
order and is cancelled by detach(). Route all three terminal send APIs through
this worker, and update its failure handling so delivery errors are surfaced
through the session’s live-phase/error mechanism instead of being silently
discarded with try?.

In `@Packages/macOS/CmuxHive/Sources/CmuxHive/HiveTerminalGridModel.swift`:
- Around line 68-79: Update HiveTerminalGridModel.apply(_:) to track the latest
applied stateSeq and reject non-full frames whose frame.stateSeq is less than or
equal to the stored sequence. Continue accepting full frames regardless of
sequence so replay or host restarts can reset state, and update the stored
sequence whenever a frame is applied.

In `@Packages/macOS/CmuxHive/Tests/CmuxHiveTests/ScriptedHostTransport.swift`:
- Around line 78-84: Update ScriptedHostTransport’s killConnection() to set
isClosed = true before resuming current receiveWaiters, so connection
termination persists when no receiver is waiting. Preserve the existing waiter
cleanup and nil-resumption behavior; rely on connect() to clear isClosed during
reconnection.

In `@Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift`:
- Around line 64-83: Update the span rendering flow around style.invisible so
background painting, including custom and inverse backgrounds, occurs before
concealed spans skip glyph rendering. Preserve the existing return behavior for
invisible text after the background rectangle is drawn.

---

Outside diff comments:
In `@cmux.xcodeproj/project.pbxproj`:
- Around line 8514-8523: Commit the root Swift Package Manager lockfile
alongside the new CmuxHive and CmuxHiveUI product dependencies. Update the
workspace Package.resolved to record both local package references and their
resolved dependencies, keeping it consistent with the
XCSwiftPackageProductDependency entries in the project configuration.

---

Duplicate comments:
In `@Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift`:
- Around line 171-175: Update requestReplay() to reject responses without
renderGrid by treating them as failures so callers do not mark an empty session
live. Before applying the frame, preserve and enforce the existing workspace and
surface identity checks, and only return successfully after receiving a complete
matching replay frame.
🪄 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: 90123b3a-d9c8-4f70-b9d0-b8fb52291668

📥 Commits

Reviewing files that changed from the base of the PR and between df779de and ac672db.

⛔ Files ignored due to path filters (1)
  • cmux.xcworkspace/contents.xcworkspacedata is excluded by !**/*.xcworkspace/contents.xcworkspacedata
📒 Files selected for processing (31)
  • .github/review-bot-rules/swift-auxiliary-window-close-shortcuts.md
  • Packages/macOS/CmuxHive/Package.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteMacSession.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteTerminalSession.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveRemoteWorkspace.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveSyncRuntime.swift
  • Packages/macOS/CmuxHive/Sources/CmuxHive/HiveTerminalGridModel.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveRemoteSessionTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/HiveTerminalGridModelTests.swift
  • Packages/macOS/CmuxHive/Tests/CmuxHiveTests/ScriptedHostTransport.swift
  • Packages/macOS/CmuxHiveUI/Package.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveRemoteTerminalPane.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalColor.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalGridView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalInputView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveTerminalKeyMapping.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerRootView.swift
  • Packages/macOS/CmuxHiveUI/Sources/CmuxHiveUI/HiveViewerWorkspaceList.swift
  • Packages/macOS/CmuxHiveUI/Tests/CmuxHiveUITests/HiveTerminalKeyMappingTests.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Environment/SettingsHostActions.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/ComputersSection.swift
  • Resources/Localizable.xcstrings
  • Sources/CmuxAuxiliaryWindows.swift
  • Sources/Hive/HiveComputersService.swift
  • Sources/Hive/HiveViewerWindowController.swift
  • Sources/HostSettingsActions+Computers.swift
  • Sources/Mobile/Pairing/MobilePairingWindowController.swift
  • Sources/cmuxApp.swift
  • cmux.xcodeproj/project.pbxproj
  • scripts/lint_auxiliary_window_close_shortcuts.py
  • tests/test_ci_auxiliary_window_close_shortcuts.sh
💤 Files with no reviewable changes (1)
  • Sources/cmuxApp.swift

Comment thread Packages/macOS/CmuxHive/Sources/CmuxHive/HiveTerminalGridModel.swift Outdated
@austinywang

Copy link
Copy Markdown
Contributor Author

Cursor review 5139234314 is addressed at HEAD 48d27063f75d601d347ef88729ee0eadb079ef3c.

  • Replay attach/refresh ownership is unified by HiveTerminalReplayCoordinator: attach installs the listener first, waits for an in-flight replay, and requests a post-listener snapshot. The two replay findings no longer cancel subscriptions or flap reconnect.
  • Disconnect revokes client, renderGridRouter, phase, and admission synchronously before awaiting teardown; makeTerminalSession rejects teardown and requires a connected client/router. retire() blocks new dials but does not retroactively cancel already-installed RPCs, so the test asserts no new allocation while allowing an in-flight request to finish.
  • Evidence: the pre-fix race fixture produced 23 assertion failures; the fixed package run passed 63 CmuxHive tests and 8 CmuxHiveUI tests, with focused replay/disconnect/coordinator cases repeated 10 times.

The three inline findings from this review were each explicitly replied to and resolved after GitHub confirmed the replies. CodeRabbit is paused and Greptile skipped the oversized diff, so neither is treated as approval. Production viewer admission remains fail-closed (viewerTransportAvailable == false); live authenticated two-Mac listing/view/input/reconnect and visual screenshots remain unverified for Austin dogfood.

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

Stale Bugbot comment from a previous run.

Comment thread Sources/Hive/HiveViewerWindowController.swift

@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 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

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 dc47afa. Configure here.

Comment thread .github/test-determinism-allowlist.txt
@teamleaderleo teamleaderleo added area: cloud Cloud machines and workspaces, relay transport area: remote cmux ssh, remote daemon, tunnels, device pairing ready-to-land Reviewed and ready to land when CI is green labels Sep 30, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator

This is a broad Hive M1 feature with substantial package churn, so I’m leaving it open for team design and review.

This branch was successfully deployed

3 active (1 outdated) deployments
Preview – cmux166 — cdd9bb5c Deployed Sep 9, 2026 by vercel[bot]
Preview – cmux41 — cdd9bb5c Deployed Sep 9, 2026 by vercel[bot]
Preview – cmux — 136c70d2 Deployed Jul 15, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: cloud Cloud machines and workspaces, relay transport area: remote cmux ssh, remote daemon, tunnels, device pairing ready-to-land Reviewed and ready to land when CI is green

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hive M1: add multiple devices on macOS and view/control another Mac's workspaces (Tailscale)

2 participants