Skip to content
Open
Show file tree
Hide file tree
Changes from 105 commits
Commits
Show all changes
275 commits
Select commit Hold shift + click to select a range
c052f67
fix: route mobile push and read state through HTTP
lawrencecchen Mar 18, 2026
7b5f2b7
ios: track mobile workspace analytics
lawrencecchen Mar 18, 2026
0cc1cbf
docs: record convex mobile cache-first architecture
lawrencecchen Mar 18, 2026
7280c82
ios: copy local config into dogfood builds
lawrencecchen Mar 18, 2026
3997738
Fix iOS terminal discovery auth state
lawrencecchen Mar 21, 2026
033252b
test: add cmuxd binary stdio compatibility harness
lawrencecchen Mar 21, 2026
9debe35
test: freeze cmuxd direct tls compatibility
lawrencecchen Mar 21, 2026
b6e5dbc
feat: scaffold zig cmuxd-remote binary
lawrencecchen Mar 21, 2026
a246726
feat: add zig terminal session core with ghostty-vt
lawrencecchen Mar 21, 2026
5f5cdd7
feat: add zig stdio terminal session handlers
lawrencecchen Mar 21, 2026
cd848c0
feat: port zig proxy streams and cli relay
lawrencecchen Mar 21, 2026
6afe13b
feat: port zig direct tls daemon auth
lawrencecchen Mar 21, 2026
4a4eefb
build: switch dev remote daemon fallback to zig
lawrencecchen Mar 21, 2026
70656f7
build: switch remote daemon asset pipeline to zig
lawrencecchen Mar 21, 2026
4e7b732
build: isolate zig remote daemon asset builds
lawrencecchen Mar 21, 2026
6b905db
docs: document zig remote daemon rewrite
lawrencecchen Mar 21, 2026
06f8d81
test: add bonsplit compatibility regressions
lawrencecchen Mar 21, 2026
e1d5e70
fix: restore bonsplit compatibility shims
lawrencecchen Mar 21, 2026
ca1252c
build: sync xcode project metadata
lawrencecchen Mar 21, 2026
0428c93
build: update bonsplit submodule
lawrencecchen Mar 21, 2026
d35e9cd
build: pin ghosttykit checksum for current ghostty
lawrencecchen Mar 21, 2026
53c2e9f
fix: restore go cli relay oracle behavior
lawrencecchen Mar 21, 2026
a70a36d
fix: rebuild ghostty helper for current upstream
lawrencecchen Mar 21, 2026
4541919
fix: correct ubuntu zig archive path
lawrencecchen Mar 21, 2026
1332e3c
refactor: extract zig session service core
lawrencecchen Mar 23, 2026
0a62d6f
feat: add local unix socket mode for cmuxd
lawrencecchen Mar 23, 2026
59703af
feat: add cmuxd session cli commands
lawrencecchen Mar 23, 2026
e1830f6
test: add session attach compat coverage
lawrencecchen Mar 23, 2026
93f29a3
feat: add cmuxd session attach cli
lawrencecchen Mar 23, 2026
f8f6bbb
chore: add session cli smoke script
lawrencecchen Mar 23, 2026
d0d3bdd
Merge remote-tracking branch 'origin/main' into task-move-ios-app-int…
lawrencecchen Mar 25, 2026
520b4ed
feat: back desktop terminals with local cmuxd sessions
lawrencecchen Mar 25, 2026
953557b
test: add cmuxd remote transport regressions
lawrencecchen Mar 25, 2026
aeb40a3
fix: drain pty output during daemon writes
lawrencecchen Mar 25, 2026
b908e5f
fix: drop duplicate bonsplit tab drop shim
lawrencecchen Mar 25, 2026
66324d5
build: use clt sdk for local zig daemon builds
lawrencecchen Mar 25, 2026
d0afa9a
feat: add WebSocket transport for iOS-to-Mac terminal connections
lawrencecchen Mar 30, 2026
496fbe2
fix: build errors for macOS and iOS
lawrencecchen Mar 30, 2026
5d07362
fix: iOS WS debug config, auto-login persistence, toolbar layout
lawrencecchen Mar 30, 2026
f2b055b
fix: resolve build errors and RPC decode failure
lawrencecchen Mar 30, 2026
797da21
fix: terminal.open command, processOutput rendering, PTY exhaustion
lawrencecchen Mar 30, 2026
4217092
fix: rendering and WebSocket connection stability
lawrencecchen Mar 30, 2026
0e38b3a
fix: inline Monokai Classic colors, add processOutput logging
lawrencecchen Mar 30, 2026
9688324
investigate: GhosttyKit iOS doesn't load config files
lawrencecchen Mar 31, 2026
5695aa9
feat: propagate machineStatus through iOS data model
lawrencecchen Mar 31, 2026
b7497e8
fix: invalidate URLSession on WebSocket transport disconnect
lawrencecchen Mar 31, 2026
150fa3d
fix: protect TerminalSSHTransport mutable state with NSLock
lawrencecchen Mar 31, 2026
7c6a4b0
Harden iOS RPC client with ID validation, timeout, and better errors
lawrencecchen Mar 31, 2026
0948181
fix: GhosttyKit config loading now works with CI-built xcframework
lawrencecchen Mar 31, 2026
00d2d5a
fix: GhosttySurfaceView lifecycle + GhosttyRuntime robustness
lawrencecchen Mar 31, 2026
7b2c504
Merge pull request #2380 from manaflow-ai/worktree-agent-ae07067c
lawrencecchen Mar 31, 2026
ad3c334
Merge pull request #2381 from manaflow-ai/fix-websocket-session-leak
lawrencecchen Mar 31, 2026
8284691
Merge pull request #2382 from manaflow-ai/fix-ios-ssh-transport-threa…
lawrencecchen Mar 31, 2026
8e3afd5
Merge pull request #2384 from manaflow-ai/fix-ios-rpc-client-hardening
lawrencecchen Mar 31, 2026
cadf01c
feat: offline badge, stale workspace filtering, connection-priority s…
lawrencecchen Mar 31, 2026
cbaa5e1
Update ghostty submodule to include iOS build improvements
lawrencecchen Mar 31, 2026
06e3ed6
trigger CI: rebuild GhosttyKit with iOS improvements
lawrencecchen Mar 31, 2026
71d876d
chore: trigger CI
lawrencecchen Mar 31, 2026
d1121e1
ci: add workflow_dispatch trigger to build-ghosttykit
lawrencecchen Mar 31, 2026
6ce2c7d
fix: update ghostty submodule with missing text.zig
lawrencecchen Mar 31, 2026
43d5830
build: update GhosttyKit to ff171a15 with iOS improvements
lawrencecchen Mar 31, 2026
b2cacff
fix: apply config to surface, set UIView bg from config
lawrencecchen Mar 31, 2026
274af05
fix: update ghostty to drain renderer mailbox in embedded draw
lawrencecchen Mar 31, 2026
5826954
fix: ghostty embedded renderer applies config directly
lawrencecchen Mar 31, 2026
8ebe743
revert: remove ghostty_surface_update_config, rely on initial config
lawrencecchen Mar 31, 2026
22e1d61
debug: ghostty bg_color logging
lawrencecchen Mar 31, 2026
f848c99
debug: unconditional bg_color log
lawrencecchen Mar 31, 2026
aa0e98b
fix: ghostty renderer falls back to config bg, revert transparent layer
lawrencecchen Mar 31, 2026
71727ed
experiment: red bg test
lawrencecchen Mar 31, 2026
8e25526
fix: ghostty iOS drawFrame skip early returns for bg_color
lawrencecchen Mar 31, 2026
7a20839
fix: Monokai colors for snapshot fallback, restore config loading
lawrencecchen Mar 31, 2026
17b1333
fix: update ghostty with iOS Metal rendering fixes (IOSurface, layer,…
lawrencecchen Mar 31, 2026
3b9b766
milestone: iOS terminal renders text + Monokai background via Metal
lawrencecchen Mar 31, 2026
a16709e
fix: ANSI colors, keyboard return key, CADisplayLink vsync
lawrencecchen Apr 1, 2026
2e5da2f
Clean up iOS terminal sidebar labels
lawrencecchen Apr 2, 2026
2557476
fix(ios): auto-detect Mac IP for physical device builds
lawrencecchen Apr 2, 2026
e1de296
fix(ios): add missing -c flag to codex button command
lawrencecchen Apr 3, 2026
164f281
feat: port MobilePresence publisher for desktop-to-mobile sync
lawrencecchen Apr 3, 2026
dc7f441
fix(ios): dynamic terminal bg color + COLORTERM=truecolor for SSH ses…
lawrencecchen Apr 3, 2026
08b6e39
feat: wire desktop auth + MobilePresence heartbeat publisher
lawrencecchen Apr 4, 2026
5973bbe
Merge origin/main into task-move-ios-app-into-cmux-repo
lawrencecchen Apr 7, 2026
b777bc9
Merge origin/main + Ghostty manual IO + iOS fixes
lawrencecchen Apr 7, 2026
63b9200
iOS: enable Metal renderer colors via synchronous rendering
lawrencecchen Apr 8, 2026
fd23931
iOS: remote daemon client, server discovery, and sidebar improvements
lawrencecchen Apr 8, 2026
60670b1
Add terminal rendering test script for iOS
lawrencecchen Apr 8, 2026
1e93e44
iOS: default to Menlo font for terminal rendering
lawrencecchen Apr 8, 2026
f6a1d61
iOS: use small initial frame to avoid surface size mismatch
lawrencecchen Apr 8, 2026
7c9f86f
iOS: widen input proxy frame to full view width
lawrencecchen Apr 8, 2026
d983b57
iOS: fetch scrollback on connect to populate terminal history
lawrencecchen Apr 8, 2026
47dd639
Merge remote-tracking branch 'origin/main' into task-move-ios-app-int…
lawrencecchen Apr 8, 2026
a524077
iOS: fix terminal resize and rendering after initial frame
lawrencecchen Apr 8, 2026
10fed42
iOS: fix staircase rendering and remove plain-text scrollback
lawrencecchen Apr 8, 2026
801f47c
iOS: add terminal scrolling via pan gesture
lawrencecchen Apr 8, 2026
fb428f6
iOS: fix scroll direction and last line clipped by accessory bar
lawrencecchen Apr 8, 2026
110d3c6
iOS: fix type-check error in TerminalSidebarRootView
lawrencecchen Apr 8, 2026
36e1cff
iOS: move arrow nub into accessory toolbar
lawrencecchen Apr 8, 2026
057f5bb
iOS: smaller nub circle without extra background/padding
lawrencecchen Apr 8, 2026
2f0a112
Remove outer border from arrow nub
lawrencecchen Apr 8, 2026
598a41c
iOS: fix surface dispose deadlock, workspace rename sync, sidebar cle…
lawrencecchen Apr 8, 2026
42a3e00
Add MobileDaemonBridge and tagged iOS builds
lawrencecchen Apr 8, 2026
46fb971
iOS: retain bridge in surface leak workaround to prevent dangling poi…
lawrencecchen Apr 8, 2026
aed0e7b
Resolve cmuxApp.swift merge conflicts, add project files
lawrencecchen Apr 8, 2026
0f6b2a7
iOS: fix surface teardown deadlock (libxev EVFILT_MACHPORT bug)
lawrencecchen Apr 8, 2026
d22c813
iOS: fix double-subtracted accessory bar height when keyboard visible
lawrencecchen Apr 8, 2026
db3db01
iOS: rename Beta→Nightly, align bundle IDs with macOS, fix testflight…
lawrencecchen Apr 8, 2026
9a4fc2f
iOS: reduce spacing between navigation title and servers section
lawrencecchen Apr 8, 2026
9fbf6c3
iOS: hide implementation details from auth error messages
lawrencecchen Apr 8, 2026
047f74b
iOS: account for safe area bottom inset in terminal height
lawrencecchen Apr 8, 2026
f5d1bfc
iOS: handle all auth error types with user-friendly messages
lawrencecchen Apr 8, 2026
6ad55e0
iOS: disable window padding to eliminate gap above accessory bar
lawrencecchen Apr 8, 2026
dd0bcd2
iOS: fix crash on Apple Sign In with invalid credentials
lawrencecchen Apr 8, 2026
d3d99f9
iOS: use main bundle ID (com.cmuxterm.app) for TestFlight/Nightly
lawrencecchen Apr 8, 2026
64ab3a9
Update Stack Auth credentials to new production/dev projects
lawrencecchen Apr 8, 2026
213964d
iOS: add INVALID_APPLE_CREDENTIALS to user-facing error messages, imp…
lawrencecchen Apr 9, 2026
ad30e50
iOS: restore nightly bundle ID, testflight script uploads to both apps
lawrencecchen Apr 9, 2026
18fe4fa
iOS: parallel TestFlight uploads for Release and Nightly
lawrencecchen Apr 9, 2026
1ac3801
iOS: remove Convex, unify WebSocket sync, add server scanner
lawrencecchen Apr 9, 2026
d20fe1b
TailscaleKit discovery + port migration to 52100
lawrencecchen Apr 9, 2026
5464a5f
iOS: shared terminal sessions, manual server entry, pin sorting
lawrencecchen Apr 9, 2026
533ae1e
Daemon-owned PTY: Manual I/O mode + session sync
lawrencecchen Apr 10, 2026
32b9a25
reload.sh: build cmuxd-remote with ReleaseFast, parallelize zig builds
lawrencecchen Apr 10, 2026
efcba9d
Fix terminal latency and attachment leak in daemon bridge
lawrencecchen Apr 10, 2026
e4607bc
Pass per-surface env vars to daemon shell via env command
lawrencecchen Apr 10, 2026
b0084e1
iOS: stable attachment ID to prevent daemon attachment leaks
lawrencecchen Apr 10, 2026
6ea8932
Pre-create daemon sessions on workspace restore
lawrencecchen Apr 10, 2026
56327c0
Pass shell integration env vars to pre-created daemon sessions
lawrencecchen Apr 10, 2026
0190346
Simplify daemon session ID to use only surface ID
lawrencecchen Apr 10, 2026
bfbd93d
iOS: add ⌘ modifier button to terminal keyboard toolbar (Mac only)
lawrencecchen Apr 10, 2026
bd52403
iOS: resync surface geometry after pinch-zoom font change
lawrencecchen Apr 10, 2026
86a66ca
Fix iOS app freeze, daemon drift, and discovery split-brain
lawrencecchen Apr 12, 2026
0de127e
Fix prompt re-rendering and remove unnecessary discovery polling
lawrencecchen Apr 12, 2026
749c7b8
Sync pinned workspace state and add pin swipe action on iOS
lawrencecchen Apr 12, 2026
ca28f15
Add multi-pane sync and pane switcher dropdown on iOS
lawrencecchen Apr 12, 2026
d138a63
Fix Ctrl+D pane close, live pane picker, daemon offline cleanup
lawrencecchen Apr 12, 2026
8e73df0
Tap-title pane dropdown and multi-pane session_ids in daemon
lawrencecchen Apr 12, 2026
646de9b
Sync per-pane titles and directories to iOS
lawrencecchen Apr 12, 2026
2e3cc4b
Fix tab rename sync and surface lifecycle on pane switch
lawrencecchen Apr 12, 2026
a4dc14a
Auto-sync panel title/directory changes to iOS
lawrencecchen Apr 12, 2026
9bf0466
Extract OSC title/directory from PTY output in daemon
lawrencecchen Apr 12, 2026
d918362
Graceful offline handling: keep workspaces, backoff, auto-recover
lawrencecchen Apr 12, 2026
8f30127
Reuse existing daemon on macOS app restart
lawrencecchen Apr 12, 2026
fb39b20
Fix quit dialog not showing when daemon was reused
lawrencecchen Apr 12, 2026
7dd37e0
Fix line wrapping by deferring resize after surface layout
lawrencecchen Apr 12, 2026
c8790b3
Persist daemon session IDs across quit+reopen
lawrencecchen Apr 12, 2026
1451fd3
Fix resize on launch: queue pending resize until bridge connects
lawrencecchen Apr 12, 2026
490ec92
Fix session restore: use saved IDs throughout the restore flow
lawrencecchen Apr 12, 2026
4c12077
Fix snapshot: save actual daemon session ID, not recomputed one
lawrencecchen Apr 12, 2026
4d57a27
Fix pre-create to use saved session IDs
lawrencecchen Apr 12, 2026
aee65d4
Fix blank pane: isRunning now does live socket check for reused daemons
lawrencecchen Apr 12, 2026
3f71afc
Kill child shells on daemon exit to prevent PTY leaks
lawrencecchen Apr 12, 2026
4e8ed2f
Add workspace.ensure_surfaces socket command for headless testing
lawrencecchen Apr 13, 2026
39774a6
docs: Phase 0 push protocol spec for daemon refactor
lawrencecchen Apr 13, 2026
9444728
Phase 4.1: Incremental OSC state machine in TerminalSession
lawrencecchen Apr 13, 2026
3a8b267
daemon/remote: kqueue-based PTY pump thread
lawrencecchen Apr 13, 2026
47a8235
daemon/remote: terminal.subscribe + terminal.output push events
lawrencecchen Apr 13, 2026
c383797
Phase 4.2 Zig: include notifications in terminal.output frames
lawrencecchen Apr 13, 2026
295b4b2
daemon/remote: CLI attach switches from terminal.read polling to subs…
lawrencecchen Apr 13, 2026
94d5456
Phase 1c: per-connection outbound queue for Unix socket
lawrencecchen Apr 13, 2026
ef80b04
ios: terminal transport switches to terminal.subscribe push
lawrencecchen Apr 13, 2026
a7697ca
hello: advertise terminal.subscribe/workspace.subscribe/notifications…
lawrencecchen Apr 13, 2026
f430286
Phase 2.3: per-session has_unread_output flag
lawrencecchen Apr 13, 2026
18a70b4
Add DaemonConnection: single persistent socket for macOS
lawrencecchen Apr 13, 2026
373e253
iOS Phase 3.1: TerminalDaemonConnection + workspace event handler
lawrencecchen Apr 13, 2026
0b7bb52
iOS Phase 3.2: TerminalSidebarStore migrates to TerminalDaemonConnection
lawrencecchen Apr 13, 2026
9619698
iOS Phase 3.3: pool terminal sessions through TerminalDaemonConnection
lawrencecchen Apr 13, 2026
87d5a10
iOS Phase 4.2: NotificationManager schedules local push from terminal…
lawrencecchen Apr 13, 2026
91f335d
Collapse bridges onto single DaemonConnection socket
lawrencecchen Apr 13, 2026
597c7f3
Phase 2.1: macOS subscribes to workspace.changed
lawrencecchen Apr 13, 2026
a1a63f4
Phase 2.2: feature-flagged migration of pinned/customTitle/customColor
lawrencecchen Apr 13, 2026
f10ccf3
Phase 2.1-extended: flag-gated daemon-authority for workspace existence
lawrencecchen Apr 13, 2026
7682476
Phase 2.1-ext caveat: skip workspace.sync when daemon owns existence
lawrencecchen Apr 13, 2026
0b87a3f
Phase 4.3 web: APNs bridge at /api/notifications/push
lawrencecchen Apr 13, 2026
199426c
iOS Phase 4.3: APNs remote push provisioning
lawrencecchen Apr 13, 2026
e8c7313
Phase 4.3 Zig: daemon.configure_notifications + remote APNs push
lawrencecchen Apr 13, 2026
400236a
iOS tests: add sessionID to TerminalRemoteDaemonSessionClient mocks
lawrencecchen Apr 13, 2026
fc89fc1
iOS tests: match 4-arg session transport factory + sharedSessionID re…
lawrencecchen Apr 13, 2026
f7d37bc
Phase 1 integration tests: test harness + first test
lawrencecchen Apr 13, 2026
23ff44a
Phase 1 integration tests: backpressure, EOF, reconnect, stress, leaks
lawrencecchen Apr 14, 2026
82c94d0
Fix unresolved merge conflict in GhosttyConfigTests.swift
lawrencecchen Apr 14, 2026
e47031c
Tests: non-blocking fd for integration test client
lawrencecchen Apr 14, 2026
c8b634d
Tests: harden timing-sensitive integration tests
lawrencecchen Apr 14, 2026
a5d425a
daemon: deliver eof-only push event when PTY closes after last byte
lawrencecchen Apr 14, 2026
0950c44
daemon: exit pump loop on kevent error instead of blind-sleep retry
lawrencecchen Apr 14, 2026
81b7e55
Tests: replace subscribe-race pre-sleep with terminal.read RPC barrier
lawrencecchen Apr 14, 2026
df537d2
Tests: relax backpressure test to avoid kernel-buffer dependence
lawrencecchen Apr 14, 2026
f4c610a
daemon: close two UAF races under disconnect-during-flood
lawrencecchen Apr 14, 2026
396ebcd
Tests: clarify test 8 post-disconnect sleep comment
lawrencecchen Apr 14, 2026
8f089f4
daemon: replace pump processing_mutex with per-Entry in_flight counter
lawrencecchen Apr 14, 2026
71c9743
Tests: preserve non-matching frames across awaitResponse
lawrencecchen Apr 14, 2026
c503f81
Fix blank terminal: read terminal.output fields from top of frame
lawrencecchen Apr 14, 2026
e6c7798
Tests: replace disconnect-settle sleep with subscriberCount poll
lawrencecchen Apr 14, 2026
97ad01a
Tests: make integration deadlines scalable for loaded hosts
lawrencecchen Apr 14, 2026
94134ee
daemon: advertise workspace.sync capability
lawrencecchen Apr 14, 2026
4017899
Fix iOS discovery: ws-port must fall inside 52100-52199
lawrencecchen Apr 14, 2026
4a4ca73
daemon: emit session.size_changed push on effective-size change
lawrencecchen Apr 14, 2026
9202fe5
iOS+macOS: pin Ghostty surface to daemon's effective grid + letterbox…
lawrencecchen Apr 14, 2026
45b8b34
Instrument daemon effective-size path with NSLog / dlog trace
lawrencecchen Apr 14, 2026
e81e53b
macOS: draw subtle border around pinned terminal area when letterboxed
lawrencecchen Apr 15, 2026
77ff67d
iOS empty-state: surface a 'Start on <server>' button when servers ex…
lawrencecchen Apr 15, 2026
d6949c7
macOS letterbox: left-align + shrink surfaceView frame to fix ghosting
lawrencecchen Apr 15, 2026
ee0e39a
macOS letterbox: add debug logs + fix pin feedback loop on natural-si…
lawrencecchen Apr 15, 2026
0bb48e1
macOS letterbox: don't pin on daemon-echo; only when effective < natural
lawrencecchen Apr 15, 2026
8ff6260
macOS letterbox: use lastReportedToDaemon to detect true sibling-shrink
lawrencecchen Apr 15, 2026
0dc7d56
iOS: invalidate pool entries when daemon endpoint changes
lawrencecchen Apr 15, 2026
dfc88dd
Single-source-of-truth view sizing across daemon + iOS + macOS
lawrencecchen Apr 15, 2026
51fb525
daemon: add workspace.open_pane RPC
lawrencecchen Apr 15, 2026
4a21acb
Steps 2/5: wire clients to daemon-minted session_ids
lawrencecchen Apr 15, 2026
0189bb5
Step 7: mark computeSessionID as legacy; point new call sites at open…
lawrencecchen Apr 15, 2026
a160c5b
DaemonConnection.openPane: retry not_found with backoff
lawrencecchen Apr 15, 2026
804510c
Mark computeSessionID/preCreateSession as @deprecated
lawrencecchen Apr 15, 2026
54ecf65
Remove computeSessionID: daemon is the sole session id minter
lawrencecchen Apr 15, 2026
b39a8c0
Adopt daemon pane session id for daemon-materialized workspaces
lawrencecchen Apr 16, 2026
1094102
Invalidate cached cell metrics on font change + config reload
lawrencecchen Apr 16, 2026
c47591f
Defer workspace.sync while openPane is in flight
lawrencecchen Apr 16, 2026
54007d7
Unblock workspace.sync when openPane exhausts retries
lawrencecchen Apr 16, 2026
98765d3
Drop vestigial socketPath parameter from DaemonTerminalBridge
lawrencecchen Apr 16, 2026
89c4c87
Defer workspace.sync when a panel has no bridge yet; log sync path
lawrencecchen Apr 16, 2026
ba459db
Fix ghost-attachment leak and centralize daemon-size reporting
lawrencecchen Apr 16, 2026
1bcafeb
Stop letterbox pin from monotonically shrinking
lawrencecchen Apr 16, 2026
eea2fcf
Create workspace on daemon before surface fires openPane
lawrencecchen Apr 16, 2026
e4c81be
Detach workspace.open_pane's bootstrap attachment
lawrencecchen Apr 16, 2026
77c0246
Revert "Detach workspace.open_pane's bootstrap attachment"
lawrencecchen Apr 16, 2026
0ad537f
Spawn cmuxd-remote via nohup so it survives mac app quit
lawrencecchen Apr 16, 2026
d0d05a7
Detach cmuxd-remote via sh '& disown' so it survives mac app quit
lawrencecchen Apr 16, 2026
ef85bc5
Revert "Detach cmuxd-remote via sh '& disown' so it survives mac app …
lawrencecchen Apr 16, 2026
8a6f9f4
Revert "Spawn cmuxd-remote via nohup so it survives mac app quit"
lawrencecchen Apr 16, 2026
30c2c87
Add debug.app.quit_keep_daemon socket action
lawrencecchen Apr 16, 2026
e525cfd
Spawn daemon with perl POSIX::setsid + /tmp stop tracing
lawrencecchen Apr 16, 2026
fa33d48
Drop "Keep Daemon" feature; daemon lifecycle is tied to mac app
lawrencecchen Apr 16, 2026
58d5da5
Respect "Warn Before Quit" for tagged DEV builds too
lawrencecchen Apr 16, 2026
5635f4d
Pull-to-refresh on iOS workspace list + daemon push on connect
lawrencecchen Apr 16, 2026
6f6f65f
Document cross-stack reload checklist (mac + iOS + daemon)
lawrencecchen Apr 16, 2026
19f49b0
Remove TailscaleKit entirely
lawrencecchen Apr 16, 2026
36f5003
ios: swap print() for os.Logger and migrate AuthManager to @Observable
lawrencecchen Apr 16, 2026
9b58e3e
ios: migrate NotificationRouteStore, ServerScanner, NotificationManag…
lawrencecchen Apr 16, 2026
8582615
ios: migrate LiveAnchormuxConfigStore to @Observable, drop stale Tail…
lawrencecchen Apr 16, 2026
41af789
ios: migrate TerminalSessionController to @Observable
lawrencecchen Apr 16, 2026
f80a062
ios: swap three NSLog sites for os.Logger
lawrencecchen Apr 16, 2026
ffc8a32
ios: migrate more NSLog sites to os.Logger
lawrencecchen Apr 16, 2026
7a1430a
ios: finish NSLog → os.Logger sweep
lawrencecchen Apr 16, 2026
0feb004
ios tests: conform Stub session clients to workspaceList()
lawrencecchen Apr 16, 2026
e370ca4
ios: make TerminalSSHTransport lock usage async-safe
lawrencecchen Apr 16, 2026
2d13c04
ios: migrate TerminalSidebarStore to @Observable
lawrencecchen Apr 16, 2026
984aae5
ios: split TerminalModels into concern-based files
lawrencecchen Apr 16, 2026
cab80d1
ios: drop three hacky sleeps for event-driven signals
lawrencecchen Apr 16, 2026
cbafa76
ios: cancel inbox-empty-snapshot fallback on team switch
lawrencecchen Apr 16, 2026
135bceb
ios: cancel stale 'copied' reset on rapid re-tap in scanner log
lawrencecchen Apr 16, 2026
d861301
ios: retire unreachable responseMismatch enum case
lawrencecchen Apr 16, 2026
8bfe8ce
ios: scanner probe skips push events while awaiting hello response
lawrencecchen Apr 16, 2026
9f8e981
ios: pre-reserve RPC slot before writeLine, pair test reads to writes
lawrencecchen Apr 16, 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
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .github/workflows/build-ghosttykit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches:
- main
pull_request:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,22 @@ jobs:
with:
go-version-file: daemon/remote/go.mod

- name: Install zig
run: |
set -euo pipefail
ZIG_REQUIRED="0.15.2"
if command -v zig >/dev/null 2>&1 && zig version 2>/dev/null | grep -q "^${ZIG_REQUIRED}"; then
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Use an exact version check for zig version; the current prefix grep can accept unintended versions.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci.yml, line 56:

<comment>Use an exact version check for `zig version`; the current prefix grep can accept unintended versions.</comment>

<file context>
@@ -49,6 +49,22 @@ jobs:
+        run: |
+          set -euo pipefail
+          ZIG_REQUIRED="0.15.2"
+          if command -v zig >/dev/null 2>&1 && zig version 2>/dev/null | grep -q "^${ZIG_REQUIRED}"; then
+            echo "zig ${ZIG_REQUIRED} already installed"
+          else
</file context>
Suggested change
if command -v zig >/dev/null 2>&1 && zig version 2>/dev/null | grep -q "^${ZIG_REQUIRED}"; then
if command -v zig >/dev/null 2>&1 && [ "$(zig version 2>/dev/null)" = "${ZIG_REQUIRED}" ]; then
Fix with Cubic

echo "zig ${ZIG_REQUIRED} already installed"
else
echo "Installing zig ${ZIG_REQUIRED} from tarball"
curl -fSL "https://ziglang.org/download/${ZIG_REQUIRED}/zig-x86_64-linux-${ZIG_REQUIRED}.tar.xz" -o /tmp/zig.tar.xz
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Mar 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Add integrity verification (checksum/signature) for the Zig tarball before extracting and installing it.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/ci.yml, line 60:

<comment>Add integrity verification (checksum/signature) for the Zig tarball before extracting and installing it.</comment>

<file context>
@@ -49,6 +49,22 @@ jobs:
+            echo "zig ${ZIG_REQUIRED} already installed"
+          else
+            echo "Installing zig ${ZIG_REQUIRED} from tarball"
+            curl -fSL "https://ziglang.org/download/${ZIG_REQUIRED}/zig-x86_64-linux-${ZIG_REQUIRED}.tar.xz" -o /tmp/zig.tar.xz
+            tar xf /tmp/zig.tar.xz -C /tmp
+            sudo mv /tmp/zig-x86_64-linux-${ZIG_REQUIRED}/zig /usr/local/bin/zig
</file context>
Fix with Cubic

tar xf /tmp/zig.tar.xz -C /tmp
sudo mv /tmp/zig-x86_64-linux-${ZIG_REQUIRED}/zig /usr/local/bin/zig
sudo rm -rf /usr/local/lib/zig
sudo mv /tmp/zig-x86_64-linux-${ZIG_REQUIRED}/lib /usr/local/lib/zig
zig version
fi

- name: Run remote daemon tests
working-directory: daemon/remote
run: go test ./...
Expand Down
418 changes: 95 additions & 323 deletions .github/workflows/test-e2e.yml

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@
[submodule "vendor/bonsplit"]
path = vendor/bonsplit
url = https://github.com/manaflow-ai/bonsplit.git
[submodule "vendor/tls.zig"]
path = vendor/tls.zig
url = https://github.com/ianic/tls.zig
branch = zig-0.15.x
8 changes: 7 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,12 @@ This makes it visible in the GitHub PR UI (Commits tab, check statuses) that the
- Only explicit focus-intent commands may mutate in-app focus/selection (`window.focus`, `workspace.select/next/previous/last`, `surface.focus`, `pane.focus/last`, browser focus commands, and v1 focus equivalents).
- All non-focus commands should preserve current user focus context while still applying data/model changes.

## Testing policy
## Timing policy

- Do not use sleep-based timing in application/runtime code when an event-, state-, or callback-driven mechanism is available.
- Deterministic sleeps are acceptable in tests when they are the smallest practical verification tool.

## E2E mac UI tests

**Never run tests locally.** All tests (E2E, UI, python socket tests) run via GitHub Actions or on the VM.

Expand Down Expand Up @@ -237,3 +242,4 @@ Notes:
- README download button points to `releases/latest/download/cmux-macos.dmg`.
- Versioning: bump the minor version for updates unless explicitly asked otherwise.
- Changelog: update `CHANGELOG.md`; docs changelog is rendered from it.

439 changes: 167 additions & 272 deletions GhosttyTabs.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions LICENSE_SCOPE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# License Scope

Default repository license:
- `LICENSE` (GNU AGPL v3) applies to this repository except where a more
specific license file governs a subtree.

Directory-specific override:
- `ios/**` is governed by `ios/LICENSE` and is proprietary / all-rights-reserved.
- The AGPL license at `LICENSE` does not grant rights for files under `ios/**`.
25 changes: 25 additions & 0 deletions Packages/CMUXAuthCore/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// swift-tools-version: 6.0
import PackageDescription

let package = Package(
name: "CMUXAuthCore",
platforms: [
.iOS(.v18),
.macOS(.v15),
],
products: [
.library(
name: "CMUXAuthCore",
targets: ["CMUXAuthCore"]
),
],
targets: [
.target(
name: "CMUXAuthCore"
),
.testTarget(
name: "CMUXAuthCoreTests",
dependencies: ["CMUXAuthCore"]
),
]
)
39 changes: 39 additions & 0 deletions Packages/CMUXAuthCore/Sources/CMUXAuthCore/CMUXAuthConfig.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Foundation

public enum CMUXAuthEnvironment: Sendable {
case development
case production
}

public struct CMUXAuthConfig: Equatable, Sendable {
public let projectId: String
public let publishableClientKey: String

public init(projectId: String, publishableClientKey: String) {
self.projectId = projectId
self.publishableClientKey = publishableClientKey
}

public static func resolve(
environment: CMUXAuthEnvironment,
overrides: [String: String] = [:],
developmentProjectId: String,
productionProjectId: String,
developmentPublishableClientKey: String,
productionPublishableClientKey: String
) -> Self {
let projectId: String
let publishableClientKey: String

switch environment {
case .development:
projectId = overrides["STACK_PROJECT_ID_DEV"] ?? developmentProjectId
publishableClientKey = overrides["STACK_PUBLISHABLE_CLIENT_KEY_DEV"] ?? developmentPublishableClientKey
case .production:
projectId = overrides["STACK_PROJECT_ID_PROD"] ?? productionProjectId
publishableClientKey = overrides["STACK_PUBLISHABLE_CLIENT_KEY_PROD"] ?? productionPublishableClientKey
}

return Self(projectId: projectId, publishableClientKey: publishableClientKey)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Foundation

public final class CMUXAuthIdentityStore: @unchecked Sendable {
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Avoid @unchecked Sendable here while sharing JSONEncoder/JSONDecoder instances; it disables concurrency checking and can lead to races if the store is used across tasks. Either remove the unchecked conformance or isolate/instantiate encoders per call.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Packages/CMUXAuthCore/Sources/CMUXAuthCore/CMUXAuthIdentityStore.swift, line 3:

<comment>Avoid `@unchecked Sendable` here while sharing `JSONEncoder`/`JSONDecoder` instances; it disables concurrency checking and can lead to races if the store is used across tasks. Either remove the unchecked conformance or isolate/instantiate encoders per call.</comment>

<file context>
@@ -0,0 +1,29 @@
+import Foundation
+
+public final class CMUXAuthIdentityStore: @unchecked Sendable {
+    private let keyValueStore: CMUXAuthKeyValueStore
+    private let key: String
</file context>
Fix with Cubic

private let keyValueStore: CMUXAuthKeyValueStore
private let key: String
private let decoder = JSONDecoder()
private let encoder = JSONEncoder()

public init(keyValueStore: CMUXAuthKeyValueStore, key: String) {
self.keyValueStore = keyValueStore
self.key = key
}

public func save(_ user: CMUXAuthUser) throws {
let data = try encoder.encode(user)
keyValueStore.set(data, forKey: key)
}

public func load() throws -> CMUXAuthUser? {
guard let data = keyValueStore.data(forKey: key) else {
return nil
}
return try decoder.decode(CMUXAuthUser.self, from: data)
}

public func clear() {
keyValueStore.removeObject(forKey: key)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Foundation

public protocol CMUXAuthKeyValueStore: AnyObject {
func bool(forKey defaultName: String) -> Bool
func data(forKey defaultName: String) -> Data?
func set(_ value: Any?, forKey defaultName: String)
func removeObject(forKey defaultName: String)
}

extension UserDefaults: CMUXAuthKeyValueStore {}

public final class CMUXAuthSessionCache: @unchecked Sendable {
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Mar 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: @unchecked Sendable is unsafe here because the injected key-value store is not constrained to a sendable/thread-safe type.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Packages/CMUXAuthCore/Sources/CMUXAuthCore/CMUXAuthSessionCache.swift, line 12:

<comment>`@unchecked Sendable` is unsafe here because the injected key-value store is not constrained to a sendable/thread-safe type.</comment>

<file context>
@@ -0,0 +1,32 @@
+
+extension UserDefaults: CMUXAuthKeyValueStore {}
+
+public final class CMUXAuthSessionCache: @unchecked Sendable {
+    private let keyValueStore: CMUXAuthKeyValueStore
+    private let key: String
</file context>
Suggested change
public final class CMUXAuthSessionCache: @unchecked Sendable {
public final class CMUXAuthSessionCache {
Fix with Cubic

private let keyValueStore: CMUXAuthKeyValueStore
private let key: String

public init(keyValueStore: CMUXAuthKeyValueStore, key: String) {
self.keyValueStore = keyValueStore
self.key = key
}

public var hasTokens: Bool {
keyValueStore.bool(forKey: key)
}

public func setHasTokens(_ value: Bool) {
keyValueStore.set(value, forKey: key)
}

public func clear() {
keyValueStore.removeObject(forKey: key)
}
}
102 changes: 102 additions & 0 deletions Packages/CMUXAuthCore/Sources/CMUXAuthCore/CMUXAuthState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import Foundation

public struct CMUXAuthAutoLoginCredentials: Equatable, Sendable {
public let email: String
public let password: String

public init(email: String, password: String) {
self.email = email
self.password = password
}
}

public enum CMUXAuthLaunchConfig {
public static func autoLoginCredentials(
from environment: [String: String],
clearAuth: Bool,
mockDataEnabled: Bool
) -> CMUXAuthAutoLoginCredentials? {
if clearAuth || mockDataEnabled {
return nil
}
guard let email = environment["CMUX_UITEST_STACK_EMAIL"], !email.isEmpty else {
return nil
}
guard let password = environment["CMUX_UITEST_STACK_PASSWORD"], !password.isEmpty else {
return nil
}
return CMUXAuthAutoLoginCredentials(email: email, password: password)
}

public static func fixtureUser(
from environment: [String: String],
clearAuth: Bool,
mockDataEnabled: Bool
) -> CMUXAuthUser? {
if clearAuth || mockDataEnabled {
return nil
}
guard environment["CMUX_UITEST_AUTH_FIXTURE"] == "1" else {
return nil
}
return CMUXAuthUser(
id: environment["CMUX_UITEST_AUTH_USER_ID"] ?? "uitest_user",
primaryEmail: environment["CMUX_UITEST_AUTH_EMAIL"] ?? "uitest@cmux.local",
displayName: environment["CMUX_UITEST_AUTH_NAME"] ?? "UI Test"
)
}
}

public enum CMUXAuthMagicLinkCode {
public static func compose(code: String, nonce: String) -> String {
code + nonce
}
}

public struct CMUXAuthState: Equatable, Sendable {
public let isAuthenticated: Bool
public let currentUser: CMUXAuthUser?
public let isRestoringSession: Bool

public init(isAuthenticated: Bool, currentUser: CMUXAuthUser?, isRestoringSession: Bool) {
self.isAuthenticated = isAuthenticated
self.currentUser = currentUser
self.isRestoringSession = isRestoringSession
}

public static func primed(
clearAuthRequested: Bool,
mockDataEnabled: Bool,
fixtureUser: CMUXAuthUser?,
autoLoginCredentials: CMUXAuthAutoLoginCredentials?,
cachedUser: CMUXAuthUser?,
hasTokens: Bool,
mockUser: CMUXAuthUser
) -> Self {
if clearAuthRequested {
return .cleared()
}

if mockDataEnabled {
return Self(isAuthenticated: true, currentUser: mockUser, isRestoringSession: false)
}

if let fixtureUser {
return Self(isAuthenticated: true, currentUser: fixtureUser, isRestoringSession: false)
}

if autoLoginCredentials != nil {
return Self(isAuthenticated: true, currentUser: cachedUser, isRestoringSession: false)
}

return Self(
isAuthenticated: hasTokens,
currentUser: cachedUser,
isRestoringSession: false
)
}

public static func cleared() -> Self {
Self(isAuthenticated: false, currentUser: nil, isRestoringSession: false)
}
}
13 changes: 13 additions & 0 deletions Packages/CMUXAuthCore/Sources/CMUXAuthCore/CMUXAuthUser.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Foundation

public struct CMUXAuthUser: Codable, Equatable, Sendable {
public let id: String
public let primaryEmail: String?
public let displayName: String?

public init(id: String, primaryEmail: String?, displayName: String?) {
self.id = id
self.primaryEmail = primaryEmail
self.displayName = displayName
}
}
Loading
Loading