Skip to content

cmux-next: Mac Screen tabs (see and control another Mac) and Share This Mac - #20426

Closed
azooz2003-bit wants to merge 60 commits into
feat-cmux-screen-kitfrom
feat-cmux-next-mac-screen
Closed

azooz2003-bit wants to merge 60 commits into
feat-cmux-screen-kitfrom
feat-cmux-next-mac-screen

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Draft. This adds Mac Screen tabs to cmux-next on macOS: see and control another Mac from a cmux tab. It also adds Share This Mac, so a Mac running cmux can be viewed by another. The screen code is CmuxScreenKit (feat-cmux-screen-kit), which this PR is stacked on.

What it adds

  • cmux://mac-screen (the home page):
    • Your paired Macs (Connect, Open in New Tab, Rename, Forget).
    • "Pair a Mac" (paste a cmux-vnc://pair link).
    • Share This Mac.
    • Pasting a pairing link into the address bar also pairs. It is never sent as a search.
  • cmux://mac-screen?mac=<id> (one Mac's screen):
    • The record holds only an id; the pairing secret is in the Keychain.
    • Tabs opened by automation, or restored after relaunch, wait for Connect.
    • The picture is WebRTC video with hardware H.264, fitted to the pane, rendered by the new macOS ScreenVideoView.
    • Input reuses the remote view pane's capture (RemoteInputSurface): physical keys, IME text, pointer, buttons and scroll. cmux's Command/Control shortcuts stay local; Control-Option-Escape releases the keyboard.
    • Toolbar: path, fps, RTT, codec, size, display, quality, Send Keys, Refresh and Disconnect.
    • Connecting, reconnecting, failed and ended cards; reconnects are automatic.
    • A hidden tab keeps its stream for 20 s, then ends it; showing the tab reconnects.
  • Share This Mac:
    • Off by default; a person turns it on.
    • Screen Recording and Accessibility rows with Open System Settings.
    • The link (masked), Copy, a QR code, and Reset Link with a confirmation.
    • The viewer's status with Disconnect.
    • While a device controls this Mac, a menu bar item offers Disconnect Viewer and Stop Sharing.
    • It runs ScreenStreamHost with ScreenCaptureKit and CGEvent in-process.
  • Library additions (additive; both iOS demo apps and cmux-vnc-host still build):
    • macOS ScreenVideoView.
    • ScreenStreamHost.onEvent and disconnectViewer().
    • An empty display list now fails instead of crashing.
    • Signaling uses an ephemeral URLSession with no URL cache, so the room secret header and TURN credentials no longer reach Cache.db.
  • Settings > Development (DEV builds only): a new section, shown only when the host is a DEV build (dev_only category in the settings export, dev_build from DevTools.isDebugBuild). It holds Mac Screen > Relay Only (macScreen.debug.relayOnly, off): Mac Screen sessions use the TURN relay only (ICE policy relay, viewer side), and connected tabs reconnect when it changes. Library: additive ScreenStreamViewer(pairing:relayOnly:) and ScreenSession.relayOnly, off by default. Exports regenerated on the fleet (scripts/measure/export-settings-artifacts.sh); settings page tests 125/125.
  • macScreen.open ("New Mac Screen Tab"): in the palette, the File menu and the + menu. CLI: tab new-mac-screen.
  • debug.mac_screen and scripts/cmux-next/mac-screen-live.py for live checks. Links move only through 0600 files.

Verification

  • Live runs from a tagged build:
    • Pairing and streaming from mini 2's Swift host, Rust host and a cmux-next Share This Mac host.
    • Connect to picture in 0.7–2.1 s, direct path, H264 HW, 1920×1080 letterboxed.
    • Input proven on the remote (click, type, Cmd-A/C/V, scroll, right-click, drag).
    • Lifecycle: confirm gate, Disconnect and Reconnect, host restart, Try Again.
    • Viewer CPU mostly 6–9% at 19–36 fps. No hangs in a 30 s Time Profiler trace.
  • Review: a correctness review found 14 items, and a live verification round found 6 bugs. All are fixed; see the review comment.
  • Final evidence: the final evidence round runs on the head build and goes to an independent verifier.

Known issues and decisions

  • WebRTC.framework and the Chromium Embedded Framework both define 8 RTC* Objective-C classes. Code binds within its own framework, so only lookups by class name are ambiguous, and the live runs work. The clean fix is a WebRTC build with a renamed prefix; that is a library dependency decision.
  • The trust call for Share This Mac is on Design and product calls (gallery: #15427), plus CI admin #13742.
  • App size: this PR adds about 70 lines of glue to CmuxNextApp. The VNC branches under it add about 480 more, which the stack needs to offset before targeting feat-cmux-next.
  • The palette shows a globe icon for Mac Screen tab rows, the same as the remote view tab.

Changelog

  • Added: Mac Screen tabs in cmux-next for seeing and controlling another Mac, and Share This Mac.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Oct 14, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@blacksmith-sh

This comment has been minimized.

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

CI fast guards failed on 7a4a19d2df (https://github.com/manaflow-ai/cmux/actions/runs/38747264838). It does not block the merge; a red guard merged into main breaks it for every open PR.
The log named no failed step; see the run.

Agents: python3 scripts/ci/guard_attribution.py fix applies the mechanical fixes locally. This comment is updated in place on each push.

@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Probably yours: Fast static checks failed: a static check failed, FAILED localization (1.12s).

CI failed on 7a4a19d2df (run 38747264838 attempt 1): 2 code, 8 unknown.
macOS jobs did not run: compile and app tests were skipped: Fast static checks failure.

Job Verdict Why
Fast static checks code a static check failed
guards / workflow-guard-tests / release-ios unknown no known signature; failed step: Validate iOS simulator build-once contract
guards / workflow-guard-tests / app-host-cache unknown no known signature; failed step: Validate iOS video recording failures
guards / workflow-guard-tests / preflight unknown no known signature; failed step: Validate macOS runner guards
guards / workflow-guard-tests / ci unknown no known signature; failed step: Propagate failed independent fast guard
guards / workflow-guard-tests / quality-determinism code a Python test failed
guards / workflow-guard-tests / release-tooling unknown no known signature; failed step: Validate retried Ghostty Zig package fetches
guards / workflow-guard-history unknown no known signature; failed step: Validate SwiftPM lockfile policy
web / react-apps-check unknown no known signature; failed step: Test webviews
tests unknown no known signature; failed step: Check platform workflow routing
Matched log lines
Fast static checks: FAILED localization (1.12s)
guards / workflow-guard-tests / quality-determinism: FAIL: test_scans_only_test_sources (__main__.CommandLine.test_scans_only_test_sources)

Not re-run automatically: Fast static checks, guards / workflow-guard-tests / release-ios, guards / workflow-guard-tests / app-host-cache, guards / workflow-guard-tests / preflight, guards / workflow-guard-tests / ci are not machine failures.

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

… (crash-class gate); workspace package groups
- Address bar: pairing links and cmux://mac-screen resolve to URLs, never a
  search (the room secret must not reach a search engine); pairing from the
  address bar needs a person.
- Hidden tabs end their session (and pending reconnects) after the grace
  period on a DemandTimer; showing them reconnects.
- Share This Mac: the menu bar indicator follows the viewer session, events
  arrive in order, a capture failure ends the viewer session, one permission
  prompt at a time, no blocking host lookup, an unreadable Keychain never
  resets the link.
- The store reads and writes off the main thread; Mac tabs wait for it.
- Other Mac Screen records navigate within the tab; a new-tab open by a
  person expires; weak session in observation; the card re-lays out.
- Page service and debug method live in CmuxNextMacScreen (App size).
- ScreenCaptureBackend: no display to capture fails instead of crashing.
- Tests: Keychain failure keeps the link; pairing links never search.
- Plain keys (f) always reach the other Mac: only Command/Control chords
  can stay in cmux as its shortcuts.
- Control-Option-Escape releases the keyboard on Mac Screen tabs.
- The restored home page fills its tab (hosting view sizing off).
- Quitting a sharing cmux ends the viewer session at once.
- Renaming a Mac renames its open tabs; Forget asks first; New Mac Screen
  Tab always opens a new tab in the pane it ran on.
- CmuxVNCWebRTC signaling uses an ephemeral session with no URL cache:
  the room secret header and TURN credentials never reach Cache.db.
@blacksmith-sh

This comment has been minimized.

@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Correctness review (subagent, at 4cdaf56) and resolution

The fixes are in 4408cc6 and 69c95b3, together with fixes from a live verification run on 4cdaf56.

# Finding Resolution
1 (high, security) A pairing link pasted in the address bar became a search, so its room secret went to the search engine. Fixed. BrowserURLResolver returns a URL for cmux-vnc://pair and cmux://mac-screen, so they never become a search or a remote suggestion. Tests cover it.
2 (high, gate) CmuxNextApp size cap. The page service and debug method moved to CmuxNextMacScreen; this PR adds about 70 lines of call-site glue to the App. The VNC branches this stack sits on add about 480 App lines, so the stack needs an offset or a cap decision before it targets feat-cmux-next.
3 (medium) Main-thread concurrency: Task.sleep, Host.current, sync file reads. Fixed. A DemandTimer replaces the sleep, there is no host lookup, and the store reads and writes off the main thread (Mac tabs wait for it).
4 (medium) A hidden tab could get stuck reconnecting, or reconnect while hidden. Fixed. The grace period ends the session and any pending reconnects; showing the tab reconnects.
5 (medium) The indicator hid while a viewer still had input; events arrived out of order. Fixed. The indicator follows the viewer session, events go through one ordered stream, and a capture failure ends the viewer session.
6 A stale new-tab mark from a person could confirm an automation-opened tab. Fixed. Marks expire after 5 s and are dropped when no tab opens.
7 Automation could save Macs through the address bar. Fixed. Pairing from the address bar requires a person.
8 Navigating to another Mac's record broke the tab. Fixed. Mac Screen records navigate within the tab, unconfirmed.
9 Session leak through observation. Fixed. The session is captured weakly.
10 The card did not re-lay out when its content changed. Fixed. Layout tracks model.card.
11 A Keychain read error reset this Mac's link. Fixed. Only a missing item makes a new link; a failed read shows "link unavailable". Tested.
12 ScreenCaptureBackend indexed an empty display list. Fixed. It throws instead.
13 Wrong pane for the action; confirmations never forgotten; two permission prompts at once; Return pressed Connect. Fixed.
14 (policy) Share This Mac needs a policy switch. Recommendation posted on #13742.

Found during live verification and fixed: the letter f never reached the remote (plain keys could match cmux bindings; now only Command and Control chords stay local); Control-Option-Escape did not release the keyboard; a restored home page drew blank; a stale "connected" status after the host app quit; Rename did not update open tabs; Forget had no confirmation. Separately, signaling now uses an ephemeral URLSession with no URL cache, so the room secret header and TURN credentials are no longer written to Cache.db.

- Control-Option-Escape releases the keyboard as a state: control stays off
  even when focus returns to the screen, until the next click on it.
- A Mac Screen tab never hides its content view (a tab restored hidden
  collapsed the chrome and drew blank); Connect starts the stream even when
  no reveal reached the tab.
- The failed card never shows the session's raw error (it can quote the
  signaling URL with the room id); debug state reports only 'failed'.
- Share This Mac: Disconnect also turns sharing off (the viewer would
  reconnect with the link); one Stop Sharing action in the menu bar.
- The keyboard hint shows only while the screen is live.
@blacksmith-sh

This comment has been minimized.

…loses the dropped stream

Library bug fix (CmuxVNCWebRTC, CmuxScreenKit; both iOS demos and
cmux-vnc-host build): ScreenStreamViewer.connect() left its room socket and
peer link running after its open timeout, so when the host next joined the
leftover viewer offered and opened a session nobody saw (a Share This Mac
host reported a viewer that was not there). ScreenSession, giving up after
its reconnect limit, also left the dropped stream's room socket
reconnecting. Both now close.
A tab restored as its pane's selected tab is shown before the pane has its
launch size; its browser chrome laid out at that size kept the stale frames
(page area 0 high at the bottom, toolbar under it) until a tab switch. The
pane now lays the content subtree out in its own layout pass whenever the
host frame or the content frame changes. Seen with restored remote view and
Mac Screen tabs.
…k handling

- macOS ScreenVideoView enqueues decoded frames from libwebrtc's decode
  thread into an AVSampleBufferDisplayLayer (hardware frames are already
  CVPixelBuffers; I420 frames are copied to pooled NV12). RTCMTLNSVideoView
  drew on the main thread (texture uploads, drawable waits): a 1.97 s and a
  323 ms main-thread hang under Animation Hitches.
- ScreenCaptureBackend restarts capture when its stream stops with an error
  and re-reads the displays when they change (a display mode change froze
  the picture while the session stayed connected).
- Copy Link marks the pasteboard item concealed (clipboard managers skip it).
- Quitting the viewer ends its sessions, so the host stops showing a viewer.
- Library (additive, off by default): ScreenStreamViewer(pairing:relayOnly:)
  and ScreenSession.relayOnly pass ICE transport policy 'relay' to the peer
  link (the flag the throughput tests already used). Nothing changes for a
  caller that does not set it; only the viewer side is restricted, so the
  host keeps its normal candidates.
- DEBUG builds only (compiled out of Release and NIGHTLY): a 'Relay Only
  (DEV)' toggle in a Mac Screen tab's quality menu (reconnects the session),
  CMUX_NEXT_MAC_SCREEN_RELAY_ONLY=1 to start sessions relay-only, and
  debug.mac_screen relay_only {enabled}. The toolbar's path reads Relay.
…elay Only

- SettingsSection.development and a Development category (hammer) holding
  the Mac Screen group; the page export marks it dev_only and the host
  lists send dev_build (DevTools.isDebugBuild), so the React page shows the
  category, its search results and its rows only in DEV builds. The schema
  and the key stay the same in every build (the CLI and React embed one
  export); only DEV builds apply it.
- macScreen.debug.relayOnly (bool, off; userOnly for agents): Mac Screen
  sessions use the TURN relay only. MacScreenPages follows the setting in
  DEBUG builds and reconnects running sessions when it changes.
- The Relay Only toolbar toggle, the env var and the debug RPC switch from
  the previous commit are gone: Settings is the one place.
- cmux app settings --section development; strings in 21 languages.
@blacksmith-sh

This comment has been minimized.

…ction

schemas/settings/settings-schema.json and docs/mdm (exported on the fleet by
scripts/measure/export-settings-artifacts.sh), webviews settings strings
(gen-strings), the page parity test reads dev_only through devOnly. Settings
page tests: 125 pass (bun, run on mini 2: Freestyle was unavailable).
… Screen fixes

- Every route to the Development category (deep link, app settings
  --section development, settings.open, the relay key's focus link) opens the
  default page outside DEV builds: the page's shownSection and
  SettingsWindowService.route both check dev_build. The mock host reports a
  DEV build. Tests: categories (shownSection), a render test with dev_build
  false and true, and the Swift route test.
- Reset Link re-masks the new link (it was shown with its QR code when Show
  was on before the reset).
- Forgetting a Mac ends its open tabs' sessions; they show not paired.
- A confirm or missing card never reports the keyboard as captured.
The callbacks run on the main thread; removing the callback and
releasing the backend it held from another thread could free it while a
callback was still running.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Independent verification: approved at 86fc8e4 (macscr26)

A fresh reviewer, separate from the implementer and from the agent that captured the evidence, approved the 12 acceptance criteria against build macscr26 (86fc8e4). The reviewer checked every artifact SHA against the build, measured the layouts and attributed each failing check.

Earlier rejections and their fixes. Each fix has a test that failed first.

  • macscr23: stopping a session while a screen capture was starting left the capture running → fixed in c69ace2. The display callback is now released on the main thread → 86fc8e4.
  • macscr24/25: a failed connection attempt was counted as two drops, so Relay Only's first switch could give up after about 6 s → f1c341e.
  • macscr25: Relay Only reconnected a hidden tab that had failed → 86fc8e4 (reconnectsOnRelayChange; the red run was at 5406a1d).
  • Earlier rounds: right-click sent with button number 0, a Keychain write failing silently, focus rings on the text fields, and the narrow-pane toolbar.

Evidence from macscr26. Viewer on a cmux Mac mini; Swift and Rust reference hosts plus a cmux-next host on a second mini.

  • Connect to picture: 0.6–1.9 s with hardware H.264; viewer CPU 3–8 %.
  • Streaming: 0 main-thread stalls in a 60 s streaming-only run.
  • Control: pointer, click, typing, ⌘A/C/V, scroll, drag and right-click all reach the remote Mac. The ⌃⌥⎋ release chord returns the keyboard to cmux, and ⌘T stays local.
  • Relay Only: behaves correctly in all six tab states: shown, hidden within grace, hidden after grace, shown failed, hidden failed, and waiting for Connect.
  • Stalls: the 270–300 ms stalls come from AppKit's sheet animation (NSMoveHelper). An Open Folder sheet shows the same stalls with no Mac Screen tab open.
  • Secrets: scans of the evidence, app data and unified logs found no pairing secret.

Not covered by runtime evidence

  • Keyboard control of a cmux-next host: no available test Mac has Screen Recording and Accessibility granted to cmux; viewing and click control were shown.
  • The display picker: the test Macs have one display each.
  • Relay Only's absence in NIGHTLY and Release builds: covered by #if DEBUG and the route tests.

Failing checks. The base feat-cmux-screen-kit is 633 commits behind main.

  • Not caused by this branch: the workflow guards, CI fast guards, react-apps-check, localization-defaults and the rollup status jobs. They fail on files this branch doesn't touch (agent-pane tests, .github, tests/, ios/).
  • Localization parity: it fails on the base too, but this branch adds 843 entries: its new catalogs' machine translations are marked needs_review. These still need resolving before merge.

The PR stays a draft until it's dogfooded and the trust decision on #13742 is made.

🤖 Generated with Claude Code

azooz2003-bit and others added 8 commits October 14, 2026 20:55
Routes name only the record (home, mac:<id>), a restored Mac tab waits
for Connect, a forgotten Mac's restored tab says it is not paired, the
title follows renames, focus goes to the input surface, and visibility
follows the view. Red until the page tab lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The home page, the toolbar and the cards resolve their colors in the theme
scope they sit in and again when it changes (Settings > Appearance), not
macOS's system styling. Red until the themed hosting lands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mac Screen was a browser app page (cmux://mac-screen in a browser tab, under
the address bar). It is now a native page tab (InternalPageID.macScreen) like
Diff and Settings: its own title (Mac Screen, or the Mac's name, live on
rename) and remote-display icon, no browser chrome or engine.

- Routes are "home" or "mac:<saved Mac id>", never the pairing secret; a
  relaunched or reopened tab shows that record behind the Connect card. A
  restored tab of a forgotten Mac says it is not paired.
- New Mac Screen Tab, the home page's Open in New Tab, debug.mac_screen open
  and pair, a cmux://mac-screen address and a pairing link a person types in
  an address bar all open the page tab (only a person's open connects at
  once). An old browser tab on a Mac Screen address is replaced by the page
  tab, waiting for Connect.
- The tab view reports when it is shown (in a window and not hidden):
  hidden pauses (20 s grace), shown resumes. Its focus target is the
  screen's input surface. Closing the tab ends the session.
- Every surface (home page, toolbar, cards, rename sheet) resolves Palette
  tokens in the tab's theme scope and again on every theme change, with
  Typography and Metrics, so Settings > Appearance shows at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The page is clear over a window backdrop (Palette.paneFill), the rename
sheet uses the popup surface, and the tab view draws no black of its own
(the screen keeps its black letterbox). Imports the strip tab id alias.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RemoteSystemShortcuts holds the seam with today's behavior (the tap takes
nothing, never installs); the tests say when it installs, which chords it
takes (the system list, never the release chord or ordinary typing, the
system list over cmux bindings) and what it sends.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Tuple arguments did not type-check; the chords are a small Sendable value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A setting, off by default (macScreen.systemShortcuts, Keyboard > Mac Screen,
userOnly for agents), with a toggle in the toolbar's Send Keys menu and on
the home page. While it is on, cmux has Accessibility, a connected Mac
Screen tab has the keyboard, its window is key and cmux is active, one
session keyboard event tap (RemoteSystemShortcutTap) takes the system
chords before macOS acts on them and sends them through the tab's input
surface: Cmd-Space, Cmd-Option-Space, Control-Space, Cmd-Tab, Cmd-`,
Control-arrows, Cmd-Shift-3/4/5, Control-Cmd-Q, Cmd-Q/W/H/M. The tap is
removed as soon as any condition stops (focus, the release chord, a tab
hidden or closed, the session ending, a window or the app losing focus,
the setting), and asks on every key too.

Precedence: the system list goes to the other Mac even where it is a cmux
binding (Cmd-W, Cmd-Q); other chords keep the capture view's rule, so
cmux's other shortcuts stay here. The release chord is never taken.
Modifiers and ordinary typing still go through the capture view, and a
key the tap took never reaches it, so nothing is sent twice.

Without Accessibility the home page and the menu offer Allow Accessibility
(the system prompt, else System Settings in the background), rechecked when
cmux becomes active. Secure Event Input hides keys from taps; then the
chords act on this Mac as without the setting. debug.mac_screen state
reports system_shortcuts, system_shortcuts_tap and accessibility. Strings
in 21 languages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…shortcuts

schemas/settings/settings-schema.json and docs/mdm exported on the fleet by
scripts/measure/export-settings-artifacts.sh (step 5fb9dd64c63899dcc2d1b5bd
at a82f69f); the settings page strings add the four schema keys of
macScreen.systemShortcuts in gen-strings' order and format.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
azooz2003-bit and others added 14 commits October 15, 2026 01:14
…ome tab (red)

A Mac opened in place from the home page kept the tab's route "home", so a
relaunch showed the home page instead of the Mac. The home page now asks its
host to open the Mac's own tab in place of the home tab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Connect and Pair and Connect on the home page, and Home on a screen, used to
swap what the tab shows in place, which kept the tab's store route: a home
tab that showed a Mac came back as the home page after a relaunch. Now the
host opens the record as a new Mac Screen tab right after it (selected,
confirmed by the person: no Connect card) and closes the old tab once the
new one exists (a store tab once the daemon made it), so the route names the
Mac. The in-place swap stays only as the fallback when no pane lists the tab.

debug.mac_screen state rows add route and store_tab (the store tab id, null
for an app-only tab that does not restore).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The compiler could not type-check the mapped closure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Showing an ended tab with Relay Only on went to the failed card in half a
second: the pane started a single attempt (session.connect) where a relay
often needs a few tries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Showing an ended or failed tab, Connect on the card, and the toolbar's
Connect and Try Again called session.connect(): one attempt, so a relay
that needs a few tries showed the failed card at once. They now go through
session.reconnect() (5 attempts with backoff), as the Relay Only switch
already did. A tab the person disconnected stays down until Connect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every pane connect now retries, so the session's reconnecting flag is
set on a first connect too and the card said Reconnecting. The seam
keeps today's behavior; the test fails on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After Connect on the confirm card the tab held the keyboard, so the
next keystrokes went to the remote Mac unasked. RemoteInputSurface
gains waitForClick() (the release chord's state); the pane does not
call it yet, so the test fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…te Mac

"to This Mac" in a session's menu read as the viewer; the item now
matches the setting's title in every locale.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every newly made screen starts with the keyboard here until a click on the
picture (only Connect on the card did that), and when a screen of a Mac
starts connecting, the other connecting or connected screens of that Mac
end, so a hidden tab in its grace no longer takes the host's one viewer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Every newly made screen starts with the keyboard here (released) until a
  click on the picture, whichever way it opened (home Connect, Pair and
  Connect, Open in New Tab, a pasted link, New Mac Screen Tab), not only
  Connect on the card. A reconnect in the same pane keeps the state.
- Hosts take one viewer and the newest wins: when a screen starts
  connecting (showing the tab, Connect, Try Again, a person's new tab), the
  other connecting or connected screens of the same Mac end now, hidden (as
  if their grace ran out) or shown (an older split shows Disconnected rather
  than the two taking the host from each other). Showing an ended tab or
  pressing Reconnect connects it again and ends the others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A click on a card's button over the picture sometimes reached the capture
view under it, which forwarded it to the other Mac and took the keyboard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The input gate only checked that the screen was open, so the capture view
stayed in control mode under every card (connecting, waiting, failed,
Disconnected): a click on a card's button that reached it went to the other
Mac and took the keyboard. Now control mode and the pointer follow
"open and no card", synced whenever the card can change; under a card the
capture view is not hit-tested (RemoteInputSurface.acceptsPointer), so a
click there neither goes to the host nor takes the keyboard. A screen that
had the keyboard before a drop keeps first responder (nothing is sent, keys
stay in cmux) and uses it again once the picture is back; a released one
still needs a click.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Superseded by #22788, which carries this Mac Screen work plus the device hub (no pairing links), merged with current feat-cmux-next and targeting feat-cmux-next directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant