Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
238 commits
Select commit Hold shift + click to select a range
b1e1854
CmuxVNC: shared RFB client engine and loopback demo server
azooz2003-bit Oct 13, 2026
4078522
CmuxVNC: fix test fixtures, flush the demo server's failure reason, t…
azooz2003-bit Oct 13, 2026
92ec614
remote view: regression test for the pane dropping its input sink
azooz2003-bit Oct 13, 2026
f6f6f18
cmux-next: VNC compatibility hosts in the remote view pane
azooz2003-bit Oct 13, 2026
bdc67c5
Add CmuxVNC to the workspace's shared package group
azooz2003-bit Oct 13, 2026
830f22b
VNC demo: separate damage rectangles, cached paint layer, optimized i…
azooz2003-bit Oct 13, 2026
fd40310
CmuxVNC: env-gated live server test; explicit literal types for Xcode…
azooz2003-bit Oct 13, 2026
0a25148
VNC: harden against hostile servers and close races found in review
azooz2003-bit Oct 13, 2026
ab5ee72
VNC live check: credentials through a 0600 file in development builds…
azooz2003-bit Oct 13, 2026
b329cee
cmux VNC iOS: one-time seed-hosts.json import (passwords to the Keych…
azooz2003-bit Oct 13, 2026
b8ce65e
cmux VNC iOS: one input model instead of trackpad and touch modes
azooz2003-bit Oct 13, 2026
0829aa8
Multi-display hosts: one page per display
azooz2003-bit Oct 13, 2026
a5d4d3a
cmux VNC iOS: fitted mode (default) and orientation lock
azooz2003-bit Oct 13, 2026
b47693e
CmuxVNCWebRTC: RFB over a WebRTC data channel, host bridge, cmux-vnc-…
azooz2003-bit Oct 13, 2026
a0ff212
cmux VNC iOS: WebRTC pairing (link, paste, QR scan), WebRTC sessions,…
azooz2003-bit Oct 13, 2026
0717dfe
cmux-vnc-signal: mint TURN in the Worker (rooms only check the secret…
azooz2003-bit Oct 13, 2026
c71b24f
cmux VNC iOS: -openSaved <name> opens a saved computer with its store…
azooz2003-bit Oct 13, 2026
0dd2a84
CmuxVNC: input-to-update latency probe (CMUX_VNC_LIVE_PROBE) and per-…
azooz2003-bit Oct 13, 2026
350a7ef
WebRTC VNC: measure everything; prefer TCP/TLS TURN relays
azooz2003-bit Oct 13, 2026
54c2d9c
cmux-vnc-signal: never let a dead socket crash a join (error 1101 aft…
azooz2003-bit Oct 13, 2026
8c63326
Screen stream over WebRTC: the screen as a hardware H.264 video track…
azooz2003-bit Oct 13, 2026
c20a14c
cmux VNC iOS: screen stream mode (WebRTC video + input channel); host…
azooz2003-bit Oct 13, 2026
76882d2
V2 (in progress): ScreenCaptureKit + CGEvent backend, WebRTC cleanup,…
azooz2003-bit Oct 13, 2026
053c920
Glass-to-glass latency under consecutive input; ordered input queue; …
azooz2003-bit Oct 13, 2026
a0397d6
cmux VNC: stream survives room drops, reconnects on its own, quality …
azooz2003-bit Oct 14, 2026
ec4534c
cmux-screen: cross-platform Rust screen stream host over WebRTC
azooz2003-bit Oct 14, 2026
ddaae6f
cmux-screen host: fit 5K/6K and large Retina captures to 4K for H.264…
azooz2003-bit Oct 14, 2026
3da15cf
cmux-screen host: fixes from the correctness review
azooz2003-bit Oct 14, 2026
c003abc
cmux VNC iOS: a second app, cmux VNC Rust, for trying the Rust host
azooz2003-bit Oct 14, 2026
61268c2
CmuxScreenKit: the cmux VNC screen code as a library, UI features opt-in
azooz2003-bit Oct 14, 2026
8302478
cmux-next: Mac Screen tabs (WIP)
azooz2003-bit Oct 14, 2026
87904d3
Mac Screen: tests, live check script, strings in 21 languages, host c…
azooz2003-bit Oct 14, 2026
70261a6
Mac Screen: RemoteInputSurface wraps the remote view capture view (ov…
azooz2003-bit Oct 14, 2026
dde6980
Mac Screen: public Observation imports, nonisolated strings, required…
azooz2003-bit Oct 14, 2026
11bf96f
Share This Mac: menu bar indicator while a device controls this Mac
azooz2003-bit Oct 14, 2026
4cdaf56
Mac Screen toolbar: stats keep their width; shorter keyboard release …
azooz2003-bit Oct 14, 2026
8d6948c
Mac Screen: openInBackground for System Settings; nonisolated deinits…
azooz2003-bit Oct 14, 2026
4408cc6
Mac Screen: review fixes
azooz2003-bit Oct 14, 2026
69c95b3
Mac Screen: fixes from live verification
azooz2003-bit Oct 14, 2026
75264de
Mac Screen debug: public Foundation import, main-actor openTab
azooz2003-bit Oct 14, 2026
4dfea47
MacScreenStore: nonisolated file record (decoded off the main actor)
azooz2003-bit Oct 14, 2026
fc22893
Mac Screen: fixes from verification round 2
azooz2003-bit Oct 14, 2026
560fc55
Screen stream viewer: a failed connect tears itself down; giving up c…
azooz2003-bit Oct 14, 2026
7b17afa
Pane: lay out content at its new size when the host frame changes
azooz2003-bit Oct 14, 2026
c924609
Mac Screen: render off the main thread; capture recovers; quieter lin…
azooz2003-bit Oct 14, 2026
412bb15
Mac Screen: DEV-only relay switch for checking the TURN path
azooz2003-bit Oct 14, 2026
f6037da
Settings: a Development section (DEV builds only) with Mac Screen > R…
azooz2003-bit Oct 14, 2026
b09a768
Settings: regenerated exports and page strings for the Development se…
azooz2003-bit Oct 14, 2026
21a4f9e
Settings > Development: absent outside DEV builds on every route; Mac…
azooz2003-bit Oct 14, 2026
fd74c3f
Mac Screen: input follows the gate; keyboard state is never stale
azooz2003-bit Oct 14, 2026
f941e02
Mac Screen: regression test, no input behind the Connect card and a t…
azooz2003-bit Oct 14, 2026
c16f25c
Mac Screen: test that a refused Keychain write saves no Mac
azooz2003-bit Oct 14, 2026
af04b94
Mac Screen: tell the person when the Keychain refuses a pairing
azooz2003-bit Oct 14, 2026
95d4607
Mac Screen: test that a synthetic right-click stays a right-click
azooz2003-bit Oct 14, 2026
20172be
Remote view: a right-click is a right-click whatever its button number
azooz2003-bit Oct 14, 2026
cf7f8ac
Mac Screen: clearer bad-link message, and editing the link clears the…
azooz2003-bit Oct 14, 2026
d6e9cd9
Mac Screen: no focus rings on its text fields, plain menu bar icon
azooz2003-bit Oct 14, 2026
17d8ab8
Mac Screen: in a narrow pane the toolbar keeps its controls and the M…
azooz2003-bit Oct 14, 2026
183c466
Mac Screen: switching Relay Only reconnects with retries
azooz2003-bit Oct 14, 2026
dbbebf4
Mac Screen: rename in a sheet without a focus ring
azooz2003-bit Oct 14, 2026
75035a7
Mac Screen: a narrow toolbar shows whole stats or none, and keeps the…
azooz2003-bit Oct 14, 2026
0a9581d
Mac Screen: the theme's field for pairing and rename, with no focus ring
azooz2003-bit Oct 14, 2026
d659303
Settings: format the Development-section changes (oxfmt, print width …
azooz2003-bit Oct 14, 2026
c69ace2
Screen capture: a stop during start leaves no capture running
azooz2003-bit Oct 14, 2026
f1c341e
Screen stream viewer: a failed connect counts as one drop, not two
azooz2003-bit Oct 15, 2026
5406a1d
Mac Screen: test which tabs reconnect when Relay Only changes
azooz2003-bit Oct 15, 2026
2addc42
Mac Screen: a hidden ended or failed tab stays down when Relay Only c…
azooz2003-bit Oct 15, 2026
86fc8e4
Screen capture: release the display callback on the main thread
azooz2003-bit Oct 15, 2026
cf48e1c
Mac Screen: tests for Mac Screen as its own page tab kind
azooz2003-bit Oct 15, 2026
26f9771
Mac Screen: test that its surfaces follow the tab's theme scope
azooz2003-bit Oct 15, 2026
2f9aea4
Mac Screen: its own page tab kind, drawn in the theme
azooz2003-bit Oct 15, 2026
ba8089d
Mac Screen: the home page takes the pane's fill like other page tabs
azooz2003-bit Oct 15, 2026
044b784
Mac Screen: test the system shortcut tap's rules (red)
azooz2003-bit Oct 15, 2026
0bdb145
Mac Screen: system shortcut tap tests take chord values (red)
azooz2003-bit Oct 15, 2026
a82f69f
Mac Screen: Send System Shortcuts to the Remote Mac
azooz2003-bit Oct 15, 2026
70c7f60
Settings: regenerated exports and page strings for Mac Screen system …
azooz2003-bit Oct 15, 2026
8c7ac46
Mac Screen: test that opening a Mac from the home page replaces the h…
azooz2003-bit Oct 15, 2026
6de7dd8
Mac Screen: opening a Mac from the home page replaces the home tab
azooz2003-bit Oct 15, 2026
5e8f247
Mac Screen: spell out the new tab's created callback
azooz2003-bit Oct 15, 2026
af3f293
Mac Screen: test that the pane's connects use the reconnect policy (red)
azooz2003-bit Oct 15, 2026
f9f4e9f
Mac Screen: every connect the pane starts uses the reconnect policy
azooz2003-bit Oct 15, 2026
c2c6fe5
Mac Screen: test that a first connect's card says Connecting
azooz2003-bit Oct 15, 2026
d54cb5c
Mac Screen: a first connect's card says Connecting, not Reconnecting
azooz2003-bit Oct 15, 2026
15a8d49
Mac Screen: test that Connect leaves the keyboard here until a click
azooz2003-bit Oct 15, 2026
457ea06
Mac Screen: Connect leaves the keyboard here until a click on the screen
azooz2003-bit Oct 15, 2026
39b8b8c
Mac Screen: the Send Keys menu says Send System Shortcuts to the Remo…
azooz2003-bit Oct 15, 2026
077543d
Mac Screen: test the keyboard on open and one viewer per Mac (red)
azooz2003-bit Oct 15, 2026
e517fba
Mac Screen: a new screen waits for a click; one viewer per Mac
azooz2003-bit Oct 15, 2026
f20632f
Mac Screen: test that a card's screen takes no input (red)
azooz2003-bit Oct 15, 2026
7a4a19d
Mac Screen: the screen takes input only while live with no card
azooz2003-bit Oct 15, 2026
623a719
Device hub: protocol v1 for device keys, permissions, tickets and sig…
azooz2003-bit Oct 19, 2026
ed851bd
Device hub: Worker, User DO and Session DO with tests
azooz2003-bit Oct 19, 2026
3214db6
Device hub: dev environment, deploy steps and protocol clarifications
azooz2003-bit Oct 19, 2026
9ddc99c
Device hub: CmuxNextDevices, the app side of the device hub protocol
azooz2003-bit Oct 19, 2026
d7e98d8
Settings: deviceHub.url in the Development section
azooz2003-bit Oct 19, 2026
4f67053
Screen stream: tests for device hub signaling and view-only hosts (red)
azooz2003-bit Oct 19, 2026
64ebc0b
Screen stream: pluggable signaling, device hub tickets, view-only hosts
azooz2003-bit Oct 19, 2026
92777ca
Device hub: copy the URL components before adding the ticket (exclusi…
azooz2003-bit Oct 19, 2026
09ea17c
Device hub: the User DO socket's handshake is a URL and headers
azooz2003-bit Oct 19, 2026
0e19a3f
Device hub protocol: fpSig's role is the sender's; the relay blob format
azooz2003-bit Oct 19, 2026
f3f440c
Settings: regenerated exports for deviceHub.url
azooz2003-bit Oct 19, 2026
35d9c79
Device hub: read the TURN key by 1Password item id
azooz2003-bit Oct 19, 2026
121e3c2
Settings: a Devices category (DEV builds) with its devices card
azooz2003-bit Oct 19, 2026
2bd2f6a
Settings: regenerated exports for the Devices category
azooz2003-bit Oct 19, 2026
c000f96
Settings page: the Devices card
azooz2003-bit Oct 19, 2026
86cac2e
Mac Screen: tests for device hub tabs, cards, View Only and Settings …
azooz2003-bit Oct 19, 2026
0372726
Mac Screen: the user's devices through the device hub
azooz2003-bit Oct 19, 2026
08fdf30
Settings page: Devices card fits the page's checks
azooz2003-bit Oct 19, 2026
64b55f6
Mac Screen: device hub strings in every locale; public imports; pushe…
azooz2003-bit Oct 19, 2026
42d189b
Settings > Devices: absent values are null in the state; internal imp…
azooz2003-bit Oct 19, 2026
c949aff
Merge remote-tracking branch 'origin/feat-cmux-next-device-auth-setti…
azooz2003-bit Oct 19, 2026
902d38f
Device hub: test kept names, offline session ends and per-device audi…
azooz2003-bit Oct 19, 2026
4d06fdf
Device hub: keep renamed names, end offline devices' sessions, filter…
azooz2003-bit Oct 19, 2026
27b3755
Device hub: test Stack sign-in from several projects with namespaced …
azooz2003-bit Oct 19, 2026
10e670a
Device hub: accept several Stack projects with namespaced user ids
azooz2003-bit Oct 19, 2026
f305af8
Device hub: test that History asks for this device's entries only
azooz2003-bit Oct 19, 2026
b21294d
Device hub: History shows this device's sessions only
azooz2003-bit Oct 20, 2026
5eb58e4
Device hub: History filters by this device's id even before the list …
azooz2003-bit Oct 20, 2026
540f7c0
Device hub: test host-only permissions, authoritative end reasons, si…
azooz2003-bit Oct 20, 2026
1b0e98e
Device hub: host-only permissions, authoritative end reasons, sign-ou…
azooz2003-bit Oct 20, 2026
bfbe688
Mac Screen hub: tests for H1 fixes (red)
azooz2003-bit Oct 20, 2026
6df7c6e
Mac Screen hub: H1 fixes — TURN-safe usernames, authoritative end rea…
azooz2003-bit Oct 20, 2026
c9456fb
Device hub: the relay username test reads the TURN-safe label
azooz2003-bit Oct 20, 2026
fffeb4d
Merge remote-tracking branch 'origin/feat-cmux-next-device-auth' into…
azooz2003-bit Oct 20, 2026
17c198d
Device hub: test the device sign-out call and the expired reason (red)
azooz2003-bit Oct 20, 2026
c377ea4
Device hub: sign-out calls the hub's device sign-out first; the expir…
azooz2003-bit Oct 20, 2026
fa8805a
Mac Screen hub: tests for H2 fixes (red)
azooz2003-bit Oct 20, 2026
a95771d
Mac Screen hub: H2 fixes
azooz2003-bit Oct 20, 2026
bfa1170
Mac Screen hub: H2 strings in all 21 locales
azooz2003-bit Oct 20, 2026
3687451
Mac Screen hub: hubCard returns explicitly after its early case
azooz2003-bit Oct 20, 2026
5befda1
Mac Screen hub: a cancelled request's /end is awaitable (test waits o…
azooz2003-bit Oct 20, 2026
bd6c929
Mac Screen hub: tests for H3 fixes (red)
azooz2003-bit Oct 20, 2026
c59ce44
Mac Screen hub: H3 fixes
azooz2003-bit Oct 20, 2026
9685939
Device hub: test review findings (red)
azooz2003-bit Oct 20, 2026
f3d5826
Device hub: tests for the reviewer's fixes (red)
azooz2003-bit Oct 20, 2026
ae7cddb
Settings > Devices: test History's device added and removed entries (…
azooz2003-bit Oct 20, 2026
254fc55
Device hub: reviewer fixes — History layout, device entries, relay se…
azooz2003-bit Oct 20, 2026
6657d2e
Device hub: review fixes for signaling close, replay, owners, audit, …
azooz2003-bit Oct 20, 2026
23cebce
Device hub: tests for the path frame, approve_failed and audit device…
azooz2003-bit Oct 20, 2026
43a94d2
Device hub: path frame, approve_failed, deviceId in History; no close…
azooz2003-bit Oct 20, 2026
dad4cd9
Merge branch 'feat-cmux-next-device-auth' of https://github.com/manaf…
azooz2003-bit Oct 20, 2026
681e016
Device hub: test offline right after sign-out and device events in ev…
azooz2003-bit Oct 20, 2026
63a8006
Mac Screen hub: tests for H5 fixes (red)
azooz2003-bit Oct 20, 2026
244320d
Device hub: offline at once after sign-out; device events in every Hi…
azooz2003-bit Oct 20, 2026
c6da6e8
Mac Screen hub: H5 fixes
azooz2003-bit Oct 20, 2026
672218e
ScreenSession: the reconnect deadline is nonisolated
azooz2003-bit Oct 20, 2026
1091cc1
Device hub: a relay this Mac just saved keeps its secret until a list…
azooz2003-bit Oct 20, 2026
6fb540b
Merge branch 'feat-cmux-next-device-auth' of https://github.com/manaf…
azooz2003-bit Oct 20, 2026
4f6cd66
Mac Screen hub: tests for H6 changes (red)
azooz2003-bit Oct 20, 2026
c33ee4e
Device hub: test that removing a device keeps History rows and names …
azooz2003-bit Oct 20, 2026
a216ce8
Device hub: audit entries carry device names that survive removal
azooz2003-bit Oct 20, 2026
7c98ac8
Mac Screen hub: H6 changes
azooz2003-bit Oct 20, 2026
38d7d0c
Device hub: tests for History across a removal and the entries' own d…
azooz2003-bit Oct 20, 2026
99fd664
Settings > Devices: History names devices by the names audit entries …
azooz2003-bit Oct 20, 2026
e9df5d0
Merge branch 'feat-cmux-next-device-auth' of https://github.com/manaf…
azooz2003-bit Oct 20, 2026
d86a17a
License the device hub under the Business Source License
azooz2003-bit Oct 20, 2026
df8764f
Mac Screen: tests for removing link mode (red)
azooz2003-bit Oct 20, 2026
3c106c9
Mac Screen: remove link mode
azooz2003-bit Oct 20, 2026
5fb840c
Mac Screen: test fixes for removing link mode (counter isolation, no …
azooz2003-bit Oct 20, 2026
fa9ef13
Mac Screen: the test device id is nonisolated (test arguments)
azooz2003-bit Oct 20, 2026
04635d8
Merge origin/feat-cmux-next into the Mac Screen integration branch
azooz2003-bit Oct 20, 2026
b649b93
Mac Screen integration: regenerate the settings exports after the merge
azooz2003-bit Oct 20, 2026
8eab0ff
Merge origin/feat-cmux-next (af89d8c2716) into the Mac Screen integra…
azooz2003-bit Oct 20, 2026
8bfa55c
Mac Screen integration: regenerate the settings exports at 8eab0ff484e
azooz2003-bit Oct 20, 2026
6cc6b9b
Device hub: test the built-in hub address per build kind (red)
azooz2003-bit Oct 20, 2026
c1850d1
Device hub: built-in hub addresses; deploy the production hub
azooz2003-bit Oct 20, 2026
ece4553
Mac Screen integration: regenerate the settings exports at c1850d152f3
azooz2003-bit Oct 20, 2026
fd54579
Device hub: test that relay secrets never touch the Keychain on the m…
azooz2003-bit Oct 20, 2026
6104abb
Device hub: test that access is re-read after a reconnect and removal…
azooz2003-bit Oct 20, 2026
e493b29
Mac Screen: test that the Devices state reads no secret store, and As…
azooz2003-bit Oct 20, 2026
d397a71
Device hub worker: test Ask for Access above View Only and permission…
azooz2003-bit Oct 20, 2026
f6b7011
New Tab: test that pairing-link text is never searched, asked or load…
azooz2003-bit Oct 20, 2026
59082b9
Device hub worker: Ask for Access above View Only prompts the host; r…
azooz2003-bit Oct 20, 2026
adf12d2
Device hub: relay secrets off the main actor; re-read every host's ac…
azooz2003-bit Oct 20, 2026
1a04630
Pairing links: refused on every input surface with one shared check
azooz2003-bit Oct 20, 2026
28ada32
Remote VNC: translate the sign-in and private-network strings into ev…
azooz2003-bit Oct 20, 2026
c62c213
Mac Screen: clear the crash-safety ratchet in the VNC and Mac Screen …
azooz2003-bit Oct 20, 2026
7d7a88b
Mac Screen: dialog key hints, themed spinners, DemandTimer deadlines,…
azooz2003-bit Oct 20, 2026
88ce487
Webviews: format this feature's Settings › Devices and New Tab files …
azooz2003-bit Oct 20, 2026
372113a
Pairing links: make the refusal text nonisolated (newTab.submit plans…
azooz2003-bit Oct 20, 2026
3562ddd
Merge origin/feat-cmux-next (3265798366d) into feat-cmux-next-mac-scr…
azooz2003-bit Oct 21, 2026
402dadd
Merge origin/feat-cmux-next (73fccd9403f) into feat-cmux-next-mac-scr…
azooz2003-bit Oct 21, 2026
bb5e51c
Device hub: tests for the review's findings (red)
azooz2003-bit Oct 21, 2026
e2eee45
Device hub: no ticket for a session that ended mid-approval; identity…
azooz2003-bit Oct 21, 2026
e94b5e8
Device hub: test a session ending while approve() waits on the Sessio…
azooz2003-bit Oct 21, 2026
9c2e145
Device hub: lowering a permission keeps pending requests (they wait f…
azooz2003-bit Oct 21, 2026
ad390cd
Merge origin/feat-cmux-next (b69093a2ed9) into feat-cmux-next-mac-scr…
azooz2003-bit Oct 21, 2026
c823a19
Mac Screen: RemoteVNCSource's @unchecked Sendable is a reviewed crash…
azooz2003-bit Oct 21, 2026
6a19f1b
Merge origin/feat-cmux-next (ab0fbd92aa8) into feat-cmux-next-mac-scr…
azooz2003-bit Oct 21, 2026
0b49c5b
cmux-next: Mac Screen and remote_view session code leaves CmuxNextApp…
azooz2003-bit Oct 21, 2026
83024e4
Merge origin/feat-cmux-next (0805b95678f) into feat-cmux-next-mac-scr…
azooz2003-bit Oct 21, 2026
c97c2e4
Merge feat-cmux-next into feat-cmux-next-mac-screen-integration
teamleaderleo Oct 21, 2026
17435fb
Mac Screen devices card: type its test helper and keep the confirm gr…
teamleaderleo Oct 21, 2026
d81c180
cmux-next: RemoteViewDebugRdHost publicly imports Foundation
teamleaderleo Oct 21, 2026
dfd90dd
Merge origin/feat-cmux-next (3b01de6500b7) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 21, 2026
4732f77
cmux-next: the CI target graph names the Mac Screen, device hub and r…
azooz2003-bit Oct 21, 2026
1e800b1
Mac Screen: the hosting view is not generic, so the Release optimizer…
azooz2003-bit Oct 21, 2026
71bc67b
Mac Screen: the connected dot on the home page is the lit glyph color
azooz2003-bit Oct 21, 2026
588e85e
New Tab: a pairing link is refused by the base's omnibox action too
azooz2003-bit Oct 21, 2026
4b1ef14
Settings exports: restamp after the base merge
azooz2003-bit Oct 21, 2026
d3b87f7
Merge origin/feat-cmux-next (032878897935) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 21, 2026
fbf2a20
Mac Screen: list the cmux-screen Cargo workspace; leave the CI target…
azooz2003-bit Oct 21, 2026
810e621
Merge origin/feat-cmux-next (9e2cf3bdc1f9) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 21, 2026
4656e02
Merge origin/feat-cmux-next (7692cfb5b738) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 21, 2026
05ca5ae
Merge origin/feat-cmux-next (25daac52afaa) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 22, 2026
c74f5ef
Merge origin/feat-cmux-next (c6b3b1721b72) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 22, 2026
37bfc03
Merge origin/feat-cmux-next (0f9944689ef4) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 22, 2026
0bc40d9
Merge origin/feat-cmux-next (5363032df884) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 22, 2026
a20ba4c
Merge origin/feat-cmux-next (164b139c3993) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 22, 2026
a8c49a6
Merge origin/feat-cmux-next (9201c88f31c8) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 22, 2026
08c55a2
Mac Screen: say why its popup surface stays solid (check-overlay-glass)
azooz2003-bit Oct 22, 2026
db69648
Mac Screen: the menu bar item's rows run registered actions
azooz2003-bit Oct 22, 2026
c02ad38
Merge origin/feat-cmux-next (28b1c3eb5e3f) into feat-cmux-next-mac-sc…
azooz2003-bit Oct 22, 2026
5049a29
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 22, 2026
7b099bb
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
ffc998b
Mac Screen: AppKit home page, toolbar, cards and approval prompt (no …
azooz2003-bit Oct 23, 2026
7d7802e
Mac Screen AppKit port: compile fixes (button font name, menu item is…
azooz2003-bit Oct 23, 2026
d5663ea
Mac Screen AppKit port: menu rows run through an action target (no NS…
azooz2003-bit Oct 23, 2026
da64bea
Mac Screen AppKit port: review fixes
azooz2003-bit Oct 23, 2026
a553ead
Mac Screen AppKit port: home column follows the page width; toolbar m…
azooz2003-bit Oct 23, 2026
200fe1b
Mac Screen AppKit port: the home page lays itself out on every resize…
azooz2003-bit Oct 23, 2026
01a89d6
Mac Screen AppKit port: wrapping labels settle their height before th…
azooz2003-bit Oct 23, 2026
5799670
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
e5056c4
Mac Screen AppKit port: visual parity and live type size
azooz2003-bit Oct 23, 2026
14f0833
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
0491de9
Mac Screen approval prompt: rebuild on a type scale change too
azooz2003-bit Oct 23, 2026
28ba4aa
Mac Screen: probed selectors, menu row baseline, CmuxVNC workflow off…
azooz2003-bit Oct 23, 2026
5657e60
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
afb80c2
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
5684818
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
3a80b42
Device hub socket: mark the keepalive sleep as a reviewed poll-allow
azooz2003-bit Oct 23, 2026
ada5350
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
97f9237
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
16a107e
Remote view tabs: mark the DEBUG weak tab registry as a reviewed sing…
azooz2003-bit Oct 23, 2026
c3c9521
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
0918f68
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
37c71c0
Devices tests: reviewed generic-class-allow on the Locked test box
azooz2003-bit Oct 23, 2026
79ad552
Merge origin/feat-cmux-next into feat-cmux-next-mac-screen-integration
azooz2003-bit Oct 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .github/rust-workspaces.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
# on its own paths; FILE must name the root.
# skip = "why" nothing checks it, for the reason given.

[[workspace]]
root = "cmux-screen"
skip = "standalone screen host on LiveKit's prebuilt libwebrtc; not linked into the app, which streams with CmuxScreenKit"

[[workspace]]
root = "cmux-tui"
covered_by = ".github/workflows/cmux-tui-spec.yml"
Expand Down
44 changes: 44 additions & 0 deletions .github/workflows/cmux-vnc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: CmuxVNC

# The shared RFB (VNC) client engine (Packages/Shared/CmuxVNC): protocol,
# authentication and decoder unit tests, plus end-to-end runs against the
# package's loopback demo server. The cmux-next app and the iOS demo
# (experiments/cmux-vnc-ios) both link it.

on:
pull_request:
paths:
- Packages/Shared/CmuxVNC/**
- scripts/select-ci-xcode.sh
- scripts/ci/xcode-pins.txt
- .xcode-version
- .github/workflows/cmux-vnc.yml
push:
branches: [main]
paths:
- Packages/Shared/CmuxVNC/**
- scripts/select-ci-xcode.sh
- scripts/ci/xcode-pins.txt
- .xcode-version
- .github/workflows/cmux-vnc.yml
workflow_dispatch:

permissions:
contents: read

concurrency:
group: cmux-vnc-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
swift-test:
runs-on: ${{ github.repository_owner != 'manaflow-ai' && 'macos-26' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && 'blacksmith-6vcpu-macos-15' || github.event_name == 'pull_request' && (vars.MACOS_RUNNER_PR || 'blacksmith-6vcpu-macos-15') || vars.CI_PAID_MACOS_OVERFLOW == '1' && vars.MACOS_RUNNER_15 || 'blacksmith-6vcpu-macos-15') }}
timeout-minutes: 20
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Select pinned Xcode
run: ./scripts/select-ci-xcode.sh
- name: Test the RFB engine
run: swift test --package-path Packages/Shared/CmuxVNC
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ using their commit email, link your PR from theirs and thank them. Let a human
close it; never close an outside PR without a human-written explanation.

The server directories listed in [LICENSE](LICENSE) (`web/`, `workers/ci-artifacts/`,
`workers/iroh-v2/`, `workers/presence/`, `services/iroh-relay-minter/`,
`workers/iroh-v2/`, `workers/presence/`, `workers/device-hub/`, `services/iroh-relay-minter/`,
`cmux-tui/relays/cloudflare-do/`, `backend/`) use the Business Source License, which needs
every outside author's CLA grant. Do not merge a PR that changes those
directories while CLA Assistant is red, and do not copy an outside
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,5 +170,5 @@ Agents working in this repository also follow [CLAUDE.md](CLAUDE.md) (also `AGEN

By contributing to this repository, you agree that:

1. Your contributions are licensed under the license of the directory you contribute to: the Business Source License 1.1 (`BUSL-1.1`) for the server directories listed in [LICENSE](LICENSE) (`web/`, `workers/ci-artifacts/`, `workers/iroh-v2/`, `workers/presence/`, `services/iroh-relay-minter/`, `cmux-tui/relays/cloudflare-do/`), and the project's GNU General Public License v3.0 or later (`GPL-3.0-or-later`) everywhere else unless a file states otherwise.
1. Your contributions are licensed under the license of the directory you contribute to: the Business Source License 1.1 (`BUSL-1.1`) for the server directories listed in [LICENSE](LICENSE) (`web/`, `workers/ci-artifacts/`, `workers/iroh-v2/`, `workers/presence/`, `workers/device-hub/`, `services/iroh-relay-minter/`, `cmux-tui/relays/cloudflare-do/`), and the project's GNU General Public License v3.0 or later (`GPL-3.0-or-later`) everywhere else unless a file states otherwise.
2. You grant Manaflow, Inc. a perpetual, worldwide, non-exclusive, royalty-free, irrevocable license to use, reproduce, modify, sublicense, and distribute your contributions under any license, including a commercial license offered to third parties.
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ production use, including self-hosting:
workers/ci-artifacts/
workers/iroh-v2/
workers/presence/
workers/device-hub/
services/iroh-relay-minter/
cmux-tui/relays/cloudflare-do/
backend/
Expand Down
43 changes: 43 additions & 0 deletions Packages/Shared/CmuxScreenKit/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// swift-tools-version: 6.2

import PackageDescription

// CmuxScreenKit: see and control a computer's screen from an app.
//
// - CmuxScreenKit (iOS, macOS): `ScreenSession`, one live session to a Mac
// (a cmux screen stream over WebRTC, RFB over WebRTC, or a direct VNC
// server), with reconnects, quality, input and live stats.
// - CmuxScreenKitUI (iOS): the opt-in screen UI: `ScreenView` (fitted mode,
// paging between displays, the single touch input model, keyboard) and
// `ScreenSessionView` (full-screen chrome whose parts are picked with
// `ScreenFeatures`), plus `MacShortcutsBar`, `ScreenOrientation` and
// `PairingScanner`.
let swiftSettings: [SwiftSetting] = [
.swiftLanguageMode(.v6),
]

let package = Package(
name: "CmuxScreenKit",
platforms: [.macOS(.v14), .iOS(.v17)],
products: [
.library(name: "CmuxScreenKit", targets: ["CmuxScreenKit"]),
.library(name: "CmuxScreenKitUI", targets: ["CmuxScreenKitUI"]),
],
dependencies: [
.package(path: "../CmuxVNC"),
.package(path: "../CmuxVNCWebRTC"),
],
targets: [
.target(
name: "CmuxScreenKit",
dependencies: [
.product(name: "CmuxVNC", package: "CmuxVNC"),
.product(name: "CmuxVNCDemoServer", package: "CmuxVNC"),
.product(name: "CmuxVNCWebRTC", package: "CmuxVNCWebRTC"),
],
swiftSettings: swiftSettings
),
.target(name: "CmuxScreenKitUI", dependencies: ["CmuxScreenKit"], swiftSettings: swiftSettings),
.testTarget(name: "CmuxScreenKitTests", dependencies: ["CmuxScreenKit"], swiftSettings: swiftSettings),
]
)
172 changes: 172 additions & 0 deletions Packages/Shared/CmuxScreenKit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# CmuxScreenKit

See and control a Mac's screen from an iOS app. This is the library behind
the cmux VNC demo apps (`experiments/cmux-vnc-ios`), which use it as their
only screen code.

| Product | Platforms | What it holds |
| --- | --- | --- |
| `CmuxScreenKit` | iOS 17, macOS 14 | `ScreenSession` (connect, reconnect, input, quality, stats), `ScreenPreferences`, `OrientationLock`, `ScreenPerfLog`; re-exports `CmuxVNC` and `CmuxVNCWebRTC` (`VNCPairing`, `VNCEndpoint`, `VNCKeysym`, `ScreenQuality`, …) |
| `CmuxScreenKitUI` | iOS 17 | `ScreenSessionView` (full-screen, features opt-in), `ScreenView` / `ScreenViewController` (the screen alone), `MacShortcutsBar`, `ScreenOrientation`, `PairingScanner` |

## Add it

SwiftPM, local path (Xcode: Add Package → Add Local…):

```swift
.package(path: "<repo>/Packages/Shared/CmuxScreenKit")
// target dependencies:
.product(name: "CmuxScreenKit", package: "CmuxScreenKit"),
.product(name: "CmuxScreenKitUI", package: "CmuxScreenKit"),
```

XcodeGen: see `experiments/cmux-vnc-ios/project.yml`.

## Connect to a Mac

A Mac runs a screen host and shows a pairing link (`cmux-vnc://pair?…`):
the Swift host (`cmux-vnc-host --capture`, Packages/Shared/CmuxVNCWebRTC) or
the Rust host (`cmux-screen/`). Both serve the same protocol over WebRTC,
through the cmux-vnc-signal Worker, with Cloudflare TURN when there is no
direct path.

```swift
import CmuxScreenKit
import CmuxScreenKitUI

let pairing = VNCPairing(link: URL(string: link)!)! // nil for anything that is not a pairing link
let session = ScreenSession(title: pairing.name, pairing: pairing)
session.connect()
```

Other targets: `ScreenSession(title:endpoint:credentials:)` for a VNC server
reached directly, `ScreenSession()` for the built-in demo desktop.

## Show it: everything

```swift
@State private var session: ScreenSession?

.fullScreenCover(item: $session) { session in
ScreenSessionView(session: session, features: .all) { self.session = nil }
}
```

`ScreenSessionView` closes the session when it goes away.

## Pick features

`ScreenFeatures` is an option set. `.all` is the demo app; `.minimal` is the
screen with a close button, state cards and display paging.

| Feature | What the user gets |
| --- | --- |
| `.shortcutsBar` | One-tap Mac shortcuts under the toolbar: Spotlight, Mission Control, App Windows, Switch App, Copy, Paste, Undo, Select All, New Tab, Close Window, Quit App, Screenshot, Force Quit, Lock Screen. Change the row with `shortcuts:` (`MacShortcutsBar.Shortcut`). |
| `.qualityMenu` | Quality in the options menu: Auto, Smooth Motion, Fixed Low (720p), Medium (1080p), High (full). |
| `.orientationLock` | Auto-Rotate / Portrait / Landscape, remembered. **Needs the app delegate hook below.** |
| `.fitToggle` | A Fit to Display toggle. Fitted mode itself (`preferences.fitToDisplay`, on by default) pins the view to one display: zoom out stops at its fit and panning stays inside it. |
| `.displayPaging` | Swipe at fit, or tap the page dots, to move between the Mac's displays. |
| `.stats` | The live line: path (Direct/Relay), fps, KB/s, round trip, codec, plus its toggle. |
| `.keyboard` | The keyboard button: the software keyboard with an Esc, Tab, arrows, Home/End, ⌃ ⌥ ⌘ (sticky) and F-key bar. Hardware keyboards work without it. |
| `.sendKeysMenu` | Send ⌃⌥⌦, ⌘⇥, ⌘Space and Esc from the options menu. |
| `.refresh` | Refresh Screen. |
| `.hideToolbar` | Hide the toolbar; a chevron brings it back. |
| `.resumeOnForeground` | Reconnect at once when the app returns after the stream dropped. |

```swift
ScreenSessionView(session: session, features: [.displayPaging, .keyboard, .shortcutsBar, .resumeOnForeground]) { … }
```

Always on: the touch input model (tap clicks where you touch, press-and-hold
then drag drags, two-finger tap right-clicks, two fingers scroll, pinch
zooms, one finger pans a zoomed view) and the connecting, reconnecting,
sign-in and error cards.

Orientation lock needs one line in the app delegate:

```swift
func application(_ application: UIApplication,
supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
MainActor.assumeIsolated { ScreenOrientation.shared.allowed }
}
```

## Bring your own chrome

`ScreenView(session:fitToDisplay:displayPaging:keyboardVisible:)` is the
screen alone (SwiftUI). `ScreenViewController(session:)` is the same thing
for UIKit. Drive everything else from `ScreenSession`:

- state: `phase` (`.connecting`, `.connected`, `.failed(message:needsSignIn:)`, `.ended`), `isReconnecting`, `stats`, `streamPath`, `frameSize`;
- input: `tap(_:modifiers:)`, `type(_:modifiers:)`, `key(_:down:)`, `click(_:)`, `movePointer(to:)`, `press(_:down:)`, `scroll(dx:dy:)`;
- `relayOnly`: connect only through the relay server (for testing that path).
- control: `selectDisplay(_:)`, `preferences.quality` + `applyQuality()`, `refresh()`, `resumeIfNeeded()`, `connect()`, `reconnect()` (connect again with retries), `close()`.

`MacShortcutsBar(session:shortcuts:)` and `PairingScanner { link in … }`
(VisionKit, QR; check `PairingScanner.isSupported`) also work on their own.

## Behaviour

- **Reconnects.** A dropped stream reconnects on its own: up to
`reconnectLimit` tries (default 5; 0 turns it off), after 0, 1, 2, 4 and
8 s. A drop in the room (signaling) connection never ends a running stream.
- **Keep preferences per Mac.** `ScreenPreferences` is `Codable`. Store
`session.preferences` when the session closes; `session.hostID` is free
for your own key.
- **Timing log.** `session.perf = ScreenPerfLog()` turns on the
input-to-frame log (Documents/perf.log). It is off by default.
- **Threads.** `ScreenSession` and every view are main-actor.

## Signaling: pairing rooms or the device hub

`ScreenStreamViewer` and `ScreenStreamHost` (CmuxVNCWebRTC) reach each other
through a `ScreenSignaling`: `send(_:)`, `messages()` (`ScreenSignal`:
`hello`, `peerJoined`, `peerLeft`, `offer`, `answer`, `candidate`, `bye`),
`iceServers()` and `close()`. Two implementations:

- `RoomSignaling(pairing:role:)`: a pairing link's room on the
cmux-vnc-signal Worker. `ScreenStreamViewer(pairing:)` and
`ScreenStreamHost(pairing:…).run()` use it exactly as before: the room is
reopened when it drops and a connected stream outlives it.
- `TicketSignaling(ticket:signalURL:signer:iceServers:expectedPeerKey:)`: one
device hub session (docs/device-hub/PROTOCOL.md). It opens
`signalURL?ticket=<jws>` with the device headers from a
`ScreenTicketSigner` (the app's Secure Enclave key), signs this side's DTLS
fingerprint into every offer and answer (`fpSig` over
`"<sid>|<role>|<fingerprint>"`, the `a=fingerprint:` values joined with
`,`), and verifies the peer's against the ticket's `peerKey`. A missing or
wrong `fpSig` aborts the session (`ScreenSignalingError`, `bye`, socket
closed). `iceServers` is the session's list: the ticket's cmux relay and
the user's relays. The ticket admits once, so the session ends with the
socket (`endsSessionOnClose`).

```swift
let signaling = try TicketSignaling(ticket: push.ticket, signalURL: push.signalURL, signer: signer,
iceServers: relays, expectedPeerKey: push.peer.signingKey)
// Viewer:
let viewer = ScreenStreamViewer(signaling: signaling)
try await viewer.connect()
// Host (a `view` session ignores all input but the display choice and refresh):
let host = ScreenStreamHost(name: "Studio", viewOnly: push.scope == "view", backend: { ScreenCaptureBackend(log: log) })
try await host.serve(signaling)
```

`ScreenStreamHost.disconnectViewer()` sends `bye` on a device hub session.
`ICEServerConfig` (urls, username, credential) is public for building the
list.

`ScreenSession(title:preferences:signaling:)` is a stream session whose
signaling the app supplies: each `connect()` asks the closure for the
connection to use (a ticket's `TicketSignaling`, which admits once) and
fails when it returns nil, so set `reconnectLimit = 0` and start a new
session for a new ticket. Input, quality and stats work as for a pairing.

`ICERelayCheck(servers:timeout:).run()` checks a TURN relay: a relay-only
peer connection gathers candidates, and `.relayed` means the relay gave
this device a `typ relay` address.

## Tests

`swift test` in this folder runs the tests that need no device. The UI target
builds for iOS only, through the demo apps
(`xcodebuild -project experiments/cmux-vnc-ios/CmuxVNCiOS.xcodeproj -scheme CmuxVNCiOS`).
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// One import for consumers: the engine types (`VNCPairing`, `VNCEndpoint`,
// `VNCCredentials`, `VNCKeysym`, `ScreenQuality`, …) come with CmuxScreenKit.
@_exported import CmuxVNC
@_exported import CmuxVNCWebRTC
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import CmuxVNC
import Foundation
import QuartzCore

/// Opt-in per-update and per-input timings, one JSON line each, appended to
/// a file (default Documents/perf.log; pull it with `devicectl device copy from`).
/// Set `ScreenSession.perf` to turn it on:
/// - frame: server latency (request → first byte), receive+decode, pixels,
/// bytes since the last frame, wait on the main queue, image copy, draw;
/// - input: what was sent, and the time until the next frame shows (input → frame).
@MainActor
public final class ScreenPerfLog {
private let handle: FileHandle?
private let start = CACurrentMediaTime()
private var lastBytes = 0
private var pendingInput: (name: String, at: CFTimeInterval)?

public init(file: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("perf.log")) {
let url = file
if !FileManager.default.fileExists(atPath: url.path) { FileManager.default.createFile(atPath: url.path, contents: nil) }
handle = try? FileHandle(forWritingTo: url)
_ = try? handle?.seekToEnd()
write(["event": "session", "at": Date().ISO8601Format()])
}

public func input(_ name: String) {
if pendingInput == nil { pendingInput = (name, CACurrentMediaTime()) }
write(["event": "input", "t": ms(CACurrentMediaTime() - start), "name": name])
}

public func frame(_ frame: VNCFrame, stats: VNCSessionStats, copyMs: Double, drawMs: Double) {
let now = CACurrentMediaTime()
let queued = Double(DispatchTime.now().uptimeNanoseconds &- frame.publishedAt) / 1e6 - copyMs - drawMs
var line: [String: Any] = [
"event": "frame", "t": ms(now - start), "seq": frame.sequence,
"server_ms": stats.lastUpdateLatencyMs ?? -1, "recv_decode_ms": stats.lastDecodeMs ?? -1,
"pixels": stats.lastUpdatePixels, "bytes": stats.bytesReceived - lastBytes,
"main_wait_ms": max(0, queued), "copy_ms": copyMs, "draw_ms": drawMs,
]
lastBytes = stats.bytesReceived
if let input = pendingInput {
line["input"] = input.name
line["input_to_frame_ms"] = ms(now - input.at)
pendingInput = nil
}
write(line)
}

/// Stream mode: a rendered video frame (WebRTC) — closes an input's
/// input → frame timing. Frames repeat while idle (refresh), so a
/// measurement is the first frame after the input, an upper bound.
public func streamFrame() {
guard let input = pendingInput else { return }
pendingInput = nil
write(["event": "frame", "t": ms(CACurrentMediaTime() - start), "input": input.name,
"input_to_frame_ms": ms(CACurrentMediaTime() - input.at), "stream": true])
}

private func ms(_ seconds: CFTimeInterval) -> Double { (seconds * 1000).rounded() }

private func write(_ line: [String: Any]) {
guard let data = try? JSONSerialization.data(withJSONObject: line, options: [.sortedKeys]) else { return }
handle?.write(data + Data("\n".utf8))
}
}
Loading
Loading