Skip to content

Native Swift frontend for cmux TUI - #9785

Closed
lawrencecchen wants to merge 221 commits into
mainfrom
feat-cmux-tui-swift-frontend
Closed

lawrencecchen wants to merge 221 commits into
mainfrom
feat-cmux-tui-swift-frontend

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Source-first successor to closed stacked PR 9459 after PR 9634 landed. Restores native renderer event queue and canonical VT color transitions, guards pressure input, and validates required invitation errors.


Note

High Risk
Large cross-language surface (Rust C ABI, Iroh transport, terminal host protocol, AppKit/Ghostty) with new CI paths; mistakes could affect remote sessions, PTY lifecycle, or test gating—not a small UI-only change.

Overview
Introduces NativeMuxDemo, a standalone macOS SwiftUI client that talks to the cmux remote daemon over Iroh and renders terminals locally with GhosttyKit (Metal/libghostty) instead of parsing PTY bytes in Rust ghostty-vt.

The Swift app wires workspaces, spaces, niri-style viewport columns, splits/stacks, terminal and browser panes, optimistic focus, session event streams, and per-pane native terminal surfaces via a new C ABI from cmux-terminal-client (native-renderer feature).

Protocol and workspace: Adds cmux-terminal-host-protocol and routes cmux-tui-core / cmux-terminal-client through it for shared host framing and CMNR reset payloads. CI full mode now runs workspace-wide isolated Rust tests (replacing core-only isolation), doctests, builds cmux-terminal-client with native-renderer, runs Swift tests, and a native-frontend job gates hosted verification.

Tooling: Demo launchers (run-demo.sh, remote lifecycle scripts), Ghostty side-by-side client launcher, and EN/JA localization ship with the app bundle under cmux-tui/target/native-mux-demo/.

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


Summary by cubic

Adds a native macOS SwiftUI frontend that renders terminals locally with GhosttyKit, extracts terminal‑host framing into cmux-terminal-host-protocol v4, and restores an ordered, backpressured native render queue with a safe C ABI for Swift. CI now runs workspace‑wide isolated Rust (incl. doctests) and Swift tests, gates a hosted native-frontend job, and the remote demo readiness flow is phase‑aware with separate transfer and startup budgets.

  • New Features

    • App NativeMuxDemo: local GhosttyKit terminals; ordered/backpressured render queue with canonical color transitions; input‑epoch guards; coalesced resizes; one active terminal per visible pane; per‑handle serialized Swift FFI; runs frontend requests off the actor executor; recovers event gaps; EN/JA; optional side‑by‑side Ghostty launcher; Swift tests; local/remote lifecycle scripts; closes streams before teardown; phase‑aware remote readiness budgets.
    • Protocol/client: new cmux-terminal-host-protocol v4 (extracted from core); cmux-remote-protocol::RESOURCE_PROTOCOL; cmux-remote exposes public mux_codec and gates daemon internals behind a daemon-services feature (default); cmux-terminal-client ships a native frontend C ABI and Swift modulemap, preserves ordered resource envelopes, restores bounded Kitty replay/snapshots, retains leased render bytes/events across resync and backpressure accounting, bounds and drains resource batches, reuses shared transport enrollment, serializes per‑handle FFI, and closes streams before shutdown.
    • Core/CLI/Spec/CI: durable terminal‑close tombstones with agent‑projection cleanup; require Kitty graphics release before terminal retirement; pane split --viewport-width requires --right and validates 0.1–1.0 with localized errors; spec clarifies bounded clear‑history VT replay; CI uses a new workspace‑wide isolated test runner and runs doctests, Swift tests, and a hosted native-frontend gate.
  • Migration

    • cmux-remote: defaults now include daemon-services. For client‑only builds, disable default features and enable iroh-transport.
    • Replace host framing with cmux-terminal-host-protocol; read the control protocol via cmux-remote-protocol::RESOURCE_PROTOCOL.
    • cmux-terminal-client features: default text-renderer; enable native-renderer to skip ghostty-vt. Swift app: include GhosttyKit.xcframework in Package.swift; use apps/macos/NativeMuxDemo/run-demo.sh or run-remote-demo.sh.

Written for commit 8318e49. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added a native macOS frontend demo with terminal and browser panes, workspaces, spaces, tabs, resizable layouts, remote connections, and English/Japanese localization.
    • Added native terminal rendering, input, resizing, clipboard, mouse, IME, and lifecycle support.
    • Added optional viewport width control for rightward pane splits.
    • Added robust terminal-host framing, launch-failure, and exit-status handling.
  • Documentation

    • Added setup, launch, remote execution, and lifecycle verification guidance.
  • Bug Fixes

    • Improved pane-split validation and terminal rendering resynchronization.
  • Tests

    • Added coverage for local and remote lifecycle behavior, protocol handling, layout decoding, and remote command execution.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds a shared terminal-host protocol crate, native frontend and terminal C APIs, a macOS SwiftUI NativeMuxDemo, local and remote launch workflows, lifecycle verification, and viewport-width resource support.

Changes

Native frontend and terminal protocol

Layer / File(s) Summary
Shared protocol and client transport
cmux-tui/crates/cmux-terminal-host-protocol/..., cmux-tui/crates/cmux-terminal-client/..., cmux-tui/crates/cmux-remote/...
The terminal-host protocol moves into a workspace crate. The terminal client adds frontend requests, C APIs, terminal attachments, native render events, feature gating, and shared transport setup.
Resource and viewport support
cmux-tui/crates/cmux-tui-core/..., cmux-tui/spec/..., cmux-tui/bindings/*/.cmux-resource-api.json
pane.split accepts a bounded viewport_width only for rightward splits. Protocol inventory paths, surface exports, documentation, and binding checksums are updated.

NativeMuxDemo application

Layer / File(s) Summary
NativeMuxDemo application
cmux-tui/apps/macos/NativeMuxDemo/...
The macOS app adds SwiftUI workspace, pane, terminal, browser, and layout views; resource snapshots; Ghostty integration; connection state; localization; packaging; and tests.

Demo workflows

Layer / File(s) Summary
Local demo workflow
cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh, launch-ghostty-client.sh, verify-demo-lifecycle.sh
The local workflow builds and signs the app, seeds daemon resources, enrolls clients, launches terminal clients, and verifies cleanup.
Remote demo workflow
cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh, remote-command.sh, remote-daemon-owner.sh, remote-lifecycle-ready.sh, verify-remote-demo-lifecycle.sh
The remote workflow transfers binaries, manages SSH status framing, owns daemon lifetime, polls readiness, and verifies normal and owner-loss cleanup.

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

Sequence Diagram(s)

sequenceDiagram
  participant runRemoteDemo as run-remote-demo.sh
  participant remoteOwner as remote-daemon-owner.sh
  participant daemon as cmux daemon
  participant nativeDemo as NativeMuxDemo
  participant frontendClient as cmux-terminal-client

  runRemoteDemo->>remoteOwner: Launch daemon with ownership channel
  remoteOwner->>daemon: Start and monitor daemon
  runRemoteDemo->>daemon: Create workspace and invitation
  runRemoteDemo->>nativeDemo: Launch with invitation and autoconnect
  nativeDemo->>frontendClient: Connect and request resources
  frontendClient->>daemon: Send lane-aware JSON requests
  daemon-->>frontendClient: Return snapshots and render events
  frontendClient-->>nativeDemo: Deliver terminal updates
  nativeDemo->>remoteOwner: Disconnect on app shutdown
  remoteOwner->>daemon: Shut down daemon and terminal hosts
Loading

Important

Pre-merge checks failed

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

❌ Failed checks (10 errors, 2 warnings)

Check name Status Explanation Resolution
Cmux Swift Actor Isolation ❌ Error New cross-actor value models and helpers, including ResourceSnapshot, LayoutNode, JSONValue, TerminalGeometry, and FrontendService helpers, lack explicit nonisolated annotations while actor and det... Mark Codable/Sendable models and pure helpers as nonisolated. Keep FrontendModel and NativeTerminalModel explicitly @MainActor, and retain documented isolation for shared FFI lifetime wrappers.
Cmux Swift Blocking Runtime ❌ Error Production Swift enqueues synchronous FFI calls; the client uses runtime.block_on, timeout waits, and blocking disconnect joins in connection, request, terminal, and shutdown paths. Expose callback- or event-driven async FFI APIs and await those signals. Do not occupy detached tasks or serial GCD queues with block_on, timeout waits, or join-based shutdown.
Cmux No Hacky Sleeps ❌ Error Added run-demo.sh and run-remote-demo.sh use fixed sleeps while polling daemon readiness, invitation claims, client counts, process discovery, and teardown. Replace fixed sleep polling with owner-provided readiness events, blocking process or pipe waits, or a tested cancellation-aware timeout abstraction.
Cmux Algorithmic Complexity ❌ Error WorkspaceSidebar.swift:26 sorts all workspaces on every body pass, and line 49 calls selectedWorkspace per row; FrontendModel scans workspaces up to three times, producing O(W²) rendering. Cache sorted workspaces and selected IDs in the snapshot/view model, then pass selection state to rows. Also precompute filtered stack IDs before rendering.
Cmux Swift Concurrency ❌ Error FrontendModel.mutate and NativeTerminalModel.shutdown launch unowned Task work for real mutations and cleanup; neither task is stored or cancelled, unlike the required AppKit termination bridge. Make mutation and shutdown entry points async and await them from callers, or store and cancel their tasks and await completion during model shutdown.
Cmux Swift Package Boundaries ❌ Error NativeMuxDemo's executable target contains 379-line C-ABI transport, 501-line mutation model, and Foundation-only JSON/layout/resource domain types; Package.swift has no reusable core target. Extract JSONValue, layout/resource models, and the C-ABI service into a small NativeMuxDemoCore target exposing a FrontendClient protocol; keep SwiftUI, AppKit, Ghostty, and app lifecycle in the executable.
Cmux User-Facing Error Privacy ❌ Error NativeMuxDemo displays raw C/daemon errors via error.localizedDescription, including Iroh/Noise details, and its visible renderer errors name Ghostty. Map connection and request failures to generic localized cmux messages. Keep raw transport and renderer details in internal diagnostics, not alerts or inline error text.
Cmux Swiftui State Layout ❌ Error New code uses GeometryReader to size column and split children, and WorkspaceSidebar passes FrontendModel into LazyVStack rows; both violate swiftui-state-layout.md. Use onGeometryChange or localized background measurement for layout sizes. Pass immutable workspace snapshots and action closures into sidebar rows instead of capturing FrontendModel.
Cmux Architecture Rethink ❌ Error NativeMuxDemoApp uses Task.yield before placement, then DemoWindowPlacement re-resolves NSApplication.keyWindow; this creates a timing-dependent window ownership race. Make the app delegate pass its explicit window and value layout snapshot to placement, then apply it synchronously; remove Task.yield and global key-window lookup.
Cmux No Ambient Global State ❌ Error Localization.swift:3 and DemoWindowPlacement.swift:41 add static-only namespaces; FrontendService.swift:62 and NativeTerminalModel.swift:15 add internal file-scope functions. Move localization and placement into constructable injected types; make copyFrontendCString and terminalGeometry private/fileprivate helpers or methods on owning types.
Docstring Coverage ⚠️ Warning Docstring coverage is 51.80% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description gives a detailed summary and rationale, but it omits the required Testing, Demo Video, Review Trigger, and Checklist sections. Add the required Testing, Demo Video, Review Trigger, and Checklist sections, including test results and a UI demo link.
✅ Passed checks (13 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Browser Automation Off-Main ✅ Passed The PR changes only NativeMuxDemo WebKit embedding; it adds no browser.* socket commands or policy/router files, and BrowserView.swift only calls WKWebView.load without waits or callbacks.
Cmux Expensive Synchronous Load ✅ Passed No agent-history loader or broad scan was added. The only file read loads the invitation, and resource JSON decoding runs in the non-main FrontendService actor.
Cmux Cache Substitution Correctness ✅ Passed No TypeScript/JavaScript changes; Swift paths are additions. FrontendModel performs session.snapshot reads on connect, mutation, and resource-update events, while cold state remains nil.
Cmux Swift @Concurrent ✅ Passed Changed async work is actor-isolated or UI coordination; the network connect uses Task.detached, and UI models cross FrontendService/TerminalHandle actors explicitly. No incorrect @concurrent usage...
Cmux Swiftpm Lockfiles ✅ Passed NativeMuxDemo/Package.swift adds only local system-library targets and linker settings; the PR changes no external SwiftPM pins, Package.resolved, .gitignore, or Xcode package references.
Cmux Swift Logging ✅ Passed Changed production Swift adds no print, debugPrint, dump, NSLog, Logger, or diagnostic stdout/file logging; the only stderr/FileHandle use is in the allowed test harness.
Cmux Full Internationalization ✅ Passed All static Swift UI copy uses the L10n NSLocalizedString helper; app catalogs have 54 matching translated en/ja keys, and both InfoPlist.strings files cover the touched entries.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed NativeMuxDemo adds only one user-facing NSWindow for its main workspace UI; it adds no auxiliary window or Cmd+W workaround, and the repository lint passes.
Cmux Source Artifacts ✅ Passed The cumulative diff contains only intentional source, tests, scripts, docs, configs, localization, protocol code, Cargo.lock, and tracked API metadata; no prohibited artifact paths or binary/log fi...
Cmux No Test Or Debug Seam In Production Source ✅ Passed Production Swift adds no DEBUG/test guards or test-named seams; tests use @testable import and directly observe internal state such as NativeMuxDemoAppDelegate.window.
Title check ✅ Passed The title clearly identifies the primary change: adding a native Swift frontend for cmux TUI.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-cmux-tui-swift-frontend

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 41

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmux-tui/apps/macos/NativeMuxDemo/Package.swift`:
- Around line 17-23: The xcframework paths are inconsistent and the Rust linker
path hardcodes the debug profile. In Package.swift, replace the relative
unsafeFlags paths with paths derived from a documented, verified build root and
select the Rust artifact without hardcoding debug. In
Sources/GhosttyKit/module.modulemap at line 2, verify and adjust the six-segment
xcframework path so it resolves to the same GhosttyKit.xcframework used by
Package.swift.

In `@cmux-tui/apps/macos/NativeMuxDemo/README.md`:
- Around line 1-86: The README currently provides only English operational
documentation. Add a Japanese locale-specific document matching the English
README’s launch, lifecycle, remote-demo, cleanup, commands, and safety
constraints, then update the package entry point to link both locale documents.
Follow the repository’s existing locale-specific Markdown naming and linking
conventions, and update every supported locale entry required by those
conventions.

In `@cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh`:
- Around line 364-383: Update the retry loops in run-demo.sh lines 364-383 and
run-remote-demo.sh lines 431-432 and 447-452: append || true to each enroll
pending/status command substitution so transient admin-socket or SSH failures
consume the retry budget instead of aborting under set -e. In both enroll status
loops, validate the captured value with a numeric regex before evaluating the
CONNECTED arithmetic comparison; no direct change is required at run-demo.sh
lines 364-383 beyond its pending substitution guard.

In `@cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh`:
- Around line 256-273: Update the cleanup function’s final status handling so
its exit trap explicitly terminates with exit_status after performing all
cleanup and log reporting. Replace the current return-based completion in
cleanup with an explicit exit, preserving the existing exit_status values set by
daemon-alive and remote-removal failures.

In `@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/BrowserView.swift`:
- Around line 48-49: Update the URL construction in BrowserView so the remote
browser.url is loaded only when its scheme is http or https; reject all other
schemes, including file and javascript, before creating NativeWebView.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/DemoWindowPlacement.swift`:
- Around line 11-28: The window-placement flow in applyIfConfigured() must
select the target window before choosing its screen, derive visibleFrame from
window.screen rather than NSScreen.screens.first, and pass that frame to
fit(visibleFrame:). Update fit(visibleFrame:) so ghosttyPositionX includes
visibleFrame.minX plus nativeWidth and gap, and preserve this behavior with a
non-zero-origin test.

In `@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/FrontendModel.swift`:
- Around line 226-242: Update selectWorkspace and selectScreen to track the
prior selection and explicitly restore it when their focus mutation fails, using
the mutation’s failure reporting through errorMessage or the existing mutation
completion path. Ensure workspace and screen selections are rolled back together
as needed, while preserving the optimistic selection on successful mutations.
- Around line 447-458: In the post-mutation success path of mutate, replace the
direct refreshNow() call with scheduleRefresh(). Preserve the existing mutation
request and error handling so refreshes are coalesced and serialized by
scheduleRefresh.
- Around line 465-483: Update the application termination flow around
FrontendModel.shutdown and the app delegate’s termination callbacks so closing
the last window uses applicationShouldTerminate with .terminateLater, then
signals termination only after the shutdown task has awaited all controller
shutdowns and ownedService.shutdown(). Preserve the existing shutdown guard and
cleanup behavior while ensuring windowWillClose cannot allow process termination
before teardown completes.
- Around line 85-131: Store the connection Task created in the connect flow as a
lifecycle property, and cancel it from shutdown() alongside updatesTask and
refreshTask. Ensure the task clears or remains safely handled after completion,
and preserve cancellation/error handling so it cannot install callbacks or
update transportDiagnostics/isConnecting after shutdown.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/FrontendService.swift`:
- Around line 100-160: Move the blocking FFI calls in request, attachTerminal,
and TerminalHandle send/resize methods off the actor’s cooperative thread pool
using the existing connect Task.detached pattern or a dedicated executor.
Preserve their current parameters, timeout, error decoding, and return behavior
while ensuring each network operation has an explicit executor boundary.
- Line 129: Update the response-payload conversion in the session
snapshot/mutation handling to construct Data directly from the result pointer,
removing the intermediate String(cString:) and utf8 conversion. Preserve the
existing null-terminated C-string semantics and resulting JSON payload behavior.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/GhosttyRemoteSurfaceView.swift`:
- Around line 507-522: Update the mouseButton mapping so button numbers 3
through 8 map sequentially to GHOSTTY_MOUSE_FOUR through GHOSTTY_MOUSE_NINE,
while preserving the existing mappings for 0–2, 9–10, and the default unknown
case.
- Around line 184-186: Guard the optional surface handle before calling
libghostty APIs in the .ready handler, viewDidMoveToWindow(),
becomeFirstResponder(), and resignFirstResponder(). Only invoke refresh, focus,
or other surface operations when surface is non-nil; otherwise leave the
runtime/surface state unchanged and avoid passing nil handles.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/GhosttyRuntime.swift`:
- Around line 21-23: Add a concise comment beside the NO_COLOR getenv/unsetenv
block explaining why it must be removed before ghostty_init and acknowledging
that this modifies the process environment, or replace the global environment
mutation with a libghostty-specific configuration that disables NO_COLOR without
affecting user preferences or child processes.
- Around line 46-61: Cancel the already-created ticker on every initializer
failure path before returning nil. In the fallback branch around
loadFallbackConfiguration() and fallback ghostty_app_new, call ticker.cancel()
before each failure return, while preserving the existing configuration cleanup
and successful NativeGhosttyRuntimeLifetime assignment.

In `@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/LayoutViews.swift`:
- Around line 38-114: Replace the top-level GeometryReader in the viewport
layout around the ForEach columns with localized geometry measurement, using
onGeometryChange or a contained background measurement to obtain the container
size without owning the entire layout; preserve naturalWidth, renderedWidth, and
height calculations. Apply the same localized measurement pattern to the split
container at LayoutViews.swift lines 182-198, with no other layout behavior
changes.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/NativeMuxDemoApp.swift`:
- Around line 43-47: Replace the deferred Task in the window creation flow with
lifecycle-based placement tied to the created NSWindow, using a dedicated window
lifecycle callback or by passing that NSWindow directly into
DemoWindowPlacement.applyIfConfigured(). Ensure placement cannot run after the
window is closed and does not resolve a stale keyWindow or windows.first.
- Around line 26-36: Assign the standalone NSWindow in NativeMuxDemoApp to a
stable cmux.* identifier and add the identical identifier to
cmuxAuxiliaryWindowIdentifiers so cmuxWindowShouldOwnCloseShortcut(_:)
recognizes it as auxiliary. Do not add a custom Cmd+W handler.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/NativeTerminalModel.swift`:
- Around line 59-81: Store the attachment lifecycle Task created by attach() in
a dedicated property, retaining its existing attachTerminal and consumeUpdates
flow. Update shutdownAndWait() to cancel that stored task alongside updateTask
and inputTask, and clear the reference when the task completes or shutdown
finishes.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Resources/en.lproj/Localizable.strings`:
- Line 30: Define explicit .one and .other pluralization entries for
spaces.count and columns.count in the English catalog, and add matching entries
in the Japanese catalog; update every count lookup call site to select the
appropriate key based on the count. Apply these changes in
en.lproj/Localizable.strings at lines 30-30 and 35-35, and
ja.lproj/Localizable.strings at lines 30-30 and 35-35.
- Line 26: Remove Iroh, libghostty, and Ghostty implementation names from
user-visible localization strings. Update the ready status at
cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Resources/en.lproj/Localizable.strings:26-26
and the error copy at :43-44 to use product-level terms; apply matching ready
and error translations at
cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Resources/ja.lproj/Localizable.strings:26-26
and :43-44, while retaining provider details only in sanitized diagnostics.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/ResourceSnapshot.swift`:
- Around line 104-122: Update FrontendModel snapshot ingestion to build and
retain precomputed indexes named screensByWorkspaceID, tabsByPaneID, panesByID,
terminalsByID, and browsersByID, sorting grouped screen and tab arrays by index
once. Refactor screens(in:), tabs(in:), pane(_:), terminal(for:), and
browser(for:) in ResourceSnapshot to read from these indexes instead of
filtering, sorting, or scanning the full collections on each call.

In `@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/SpacesBar.swift`:
- Around line 68-70: Update the Label localization in SpacesBar.swift (lines
68-70) to select columns.count.one when columns.count is one and
columns.count.other otherwise, preserving the count argument. Apply the same
explicit plural-key selection in WorkspaceSidebar.swift (lines 62-66), using
spaces.count.one for one space and spaces.count.other for all other counts.

In `@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/TerminalView.swift`:
- Around line 41-47: Update TerminalView’s rendering of terminal.errorMessage
and the NativeTerminalModel.attach() error flow so user-facing text uses
localized product-safe messages rather than raw error.localizedDescription.
Preserve sanitized diagnostic details only in internal logs, and ensure no
vendor, transport, or upstream error details reach the displayed Text.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/WorkspaceSidebar.swift`:
- Around line 26-28: Remove the per-render sorted call from the ForEach in
WorkspaceSidebar and iterate snapshot.workspaces directly. Ensure workspaces are
ordered by index when the snapshot is decoded or refreshed, preserving the same
ordering without repeated sorting in body updates.
- Around line 62-66: Update the workspace sidebar count text in the relevant
view to select the explicit spaces.count.one localization key when the screen
count is 1 and spaces.count.other otherwise, preserving the current count
interpolation. Add both keys with appropriate singular and plural translations
to every supported locale catalog.
- Around line 26-27: The workspace rows currently capture FrontendModel inside
workspaceButton(_:) under the LazyVStack. Replace that row implementation with a
value-only view that receives the selected workspace, screen count, and
select/close action closures as parameters, and update the LazyVStack call site
to pass immutable snapshot values and those closures instead of the model
reference.

In `@cmux-tui/apps/macos/NativeMuxDemo/test-remote-command.sh`:
- Around line 40-55: Remove the dead fallback branch after the `RUN_REMOTE_DEMO`
source path, including the `eval`, temporary environment variables, and
`remote_under_test` wrapper. Keep only the sourced `remote-command.sh` helper
path, and remove the now-unused `RUN_REMOTE_DEMO` variable declaration.

In `@cmux-tui/apps/macos/NativeMuxDemo/verify-remote-demo-lifecycle.sh`:
- Around line 10-24: Move the argument validation block before the
TEST_ROOT="$(mktemp -d ...)" initialization so invalid invocations exit before
creating temporary resources. Keep the existing validation behavior and usage
message unchanged, and leave the remaining lifecycle setup intact.

In `@cmux-tui/crates/cmux-remote/Cargo.toml`:
- Around line 14-15: Guard every use of the optional crates cmux_pty,
cmux_tui_core, and ghostty_vt with the daemon-services feature, keeping their
existing behavior when that feature is enabled. Add a CI check that builds
cmux-remote with --no-default-features so unguarded references are detected.

In `@cmux-tui/crates/cmux-terminal-client/Cargo.toml`:
- Around line 13-29: Gate the text-renderer implementation consistently on the
text-renderer feature: update lib.rs imports, key_input_from_chord, ClientState
fields and constructors, and the frontend module so they are only compiled when
enabled. Ensure native-renderer builds without ghostty_vt or text-renderer-only
symbols, while no-default-features builds also resolve cleanly.

In `@cmux-tui/crates/cmux-terminal-client/src/frontend.rs`:
- Around line 780-785: Update cmux_frontend_terminal_has_exited to return the
authoritative ClientState.exited boolean instead of comparing the diagnostic
status string, while preserving the existing null-pointer fallback of false.
- Around line 268-286: Update the request flow around the pending insertion and
control stream lookup so an unavailable mux-control cannot leave the new id in
control_state.pending. Resolve the stream before inserting the pending sender,
or explicitly remove the id when the lookup returns an error; preserve the
existing cleanup for send failures.
- Around line 369-375: Update the nonce-generation error branch in the
surrounding frontend connection setup to perform the same transport cleanup as
the control-stream failure path: shut down the multiplexer, connection,
provider, and Tokio runtime, and unregister the daemon stream before returning
null. Preserve copying the error into error_buffer via copy_utf8.

In `@cmux-tui/crates/cmux-terminal-client/src/lib.rs`:
- Around line 513-525: Update the MessageKind::Exit branch in apply so it always
returns FrameEffect::Stop after marking the terminal exited, regardless of the
result from continue_after_native_event. Do not propagate Restart or other
queue-overflow effects for this terminal event; reserve resynchronization for
non-terminal frames.
- Around line 424-429: Update the Reset event construction in
continue_after_native_event to include the complete Kitty rendering state from
snapshot, including kitty_image_aliases and kitty_state alongside
snapshot.replay. Ensure native renderers reconstruct the same image aliases and
replay state used by snapshot.apply_vt_replay_parts().

In `@cmux-tui/crates/cmux-terminal-host-protocol/Cargo.toml`:
- Around line 13-19: Move serde_json from [dependencies] to [dev-dependencies]
in the crate manifest, keeping it available for the #[cfg(test)] usage while
removing it from runtime dependencies.

In `@cmux-tui/crates/cmux-terminal-host-protocol/src/lib.rs`:
- Around line 703-724: Refactor FrameDecoder’s header state and decode flow to
retain the Header parsed during initial validation, eliminating the second
parse_header call and the drain-based payload memmove. Keep header bytes
separate from payload storage, while preserving early rejection of oversized
lengths and ensuring buffered_len() remains HEADER_LEN when rejection occurs, as
covered by oversized_length_is_rejected_before_payload_is_buffered.
- Around line 206-212: Update encode_terminal_exit’s
TerminalExitOutcome::Unknown branch to ensure the encoded reason is non-empty
before appending it, using the existing default reason established by
TerminalExit::unknown. Preserve UTF-8 truncation and ensure the resulting
payload always exceeds EXIT_PAYLOAD_HEADER_LEN so decode_terminal_exit accepts
it.
- Around line 15-28: Move the terminal-host handshake types CapabilityRights,
CapabilityToken, ClientHello, ClientRole, HostHello, HostIncarnation, and
TerminalId from cmux_tui_core::terminal_host into the
cmux-terminal-host-protocol crate alongside the existing protocol constants and
payload definitions. Update their visibility and all imports/re-exports so
cmux-remote and other callers use the protocol crate as the single source for
the complete handshake.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 91939b2b-7c54-4698-9fea-8026da75b859

📥 Commits

Reviewing files that changed from the base of the PR and between 21675cc and 643b9af.

⛔ Files ignored due to path filters (1)
  • cmux-tui/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (66)
  • cmux-tui/Cargo.toml
  • cmux-tui/apps/macos/NativeMuxDemo/Package.swift
  • cmux-tui/apps/macos/NativeMuxDemo/README.md
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/CCmuxTerminal/cmux_terminal_client.h
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/CCmuxTerminal/module.modulemap
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/GhosttyKit/module.modulemap
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/BrowserView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/DemoWindowPlacement.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/FrontendModel.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/FrontendService.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/GhosttyRemoteSurfaceView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/GhosttyRuntime.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/JSONValue.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/LayoutNode.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/LayoutViews.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Localization.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/NativeMuxDemoApp.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/NativeTerminalModel.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/PaneView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/ResourceSnapshot.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Resources/en.lproj/Localizable.strings
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Resources/ja.lproj/Localizable.strings
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/RootView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/SpacesBar.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/TerminalView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/WorkspaceSidebar.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Support/Info.plist
  • cmux-tui/apps/macos/NativeMuxDemo/Support/en.lproj/InfoPlist.strings
  • cmux-tui/apps/macos/NativeMuxDemo/Support/ja.lproj/InfoPlist.strings
  • cmux-tui/apps/macos/NativeMuxDemo/Tests/NativeMuxDemoTests/NativeMuxDemoTests.swift
  • cmux-tui/apps/macos/NativeMuxDemo/launch-ghostty-client.sh
  • cmux-tui/apps/macos/NativeMuxDemo/remote-command.sh
  • cmux-tui/apps/macos/NativeMuxDemo/remote-daemon-owner.sh
  • cmux-tui/apps/macos/NativeMuxDemo/remote-lifecycle-ready.sh
  • cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh
  • cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh
  • cmux-tui/apps/macos/NativeMuxDemo/test-remote-command.sh
  • cmux-tui/apps/macos/NativeMuxDemo/test-remote-lifecycle-ready.sh
  • cmux-tui/apps/macos/NativeMuxDemo/verify-demo-lifecycle.sh
  • cmux-tui/apps/macos/NativeMuxDemo/verify-remote-demo-lifecycle.sh
  • cmux-tui/bindings/cpp/.cmux-resource-api.json
  • cmux-tui/bindings/go/.cmux-resource-api.json
  • cmux-tui/bindings/java/.cmux-resource-api.json
  • cmux-tui/bindings/python/.cmux-resource-api.json
  • cmux-tui/bindings/rust/.cmux-resource-api.json
  • cmux-tui/bindings/typescript/.cmux-resource-api.json
  • cmux-tui/bindings/zig/.cmux-resource-api.json
  • cmux-tui/crates/cmux-remote/Cargo.toml
  • cmux-tui/crates/cmux-remote/src/lib.rs
  • cmux-tui/crates/cmux-remote/src/mux_codec.rs
  • cmux-tui/crates/cmux-remote/src/service.rs
  • cmux-tui/crates/cmux-terminal-client/Cargo.toml
  • cmux-tui/crates/cmux-terminal-client/include/cmux_terminal_client.h
  • cmux-tui/crates/cmux-terminal-client/src/frontend.rs
  • cmux-tui/crates/cmux-terminal-client/src/lib.rs
  • cmux-tui/crates/cmux-terminal-host-protocol/Cargo.toml
  • cmux-tui/crates/cmux-terminal-host-protocol/src/lib.rs
  • cmux-tui/crates/cmux-tui-core/Cargo.toml
  • cmux-tui/crates/cmux-tui-core/src/lib.rs
  • cmux-tui/crates/cmux-tui-core/src/resource_router.rs
  • cmux-tui/crates/cmux-tui-core/src/surface.rs
  • cmux-tui/crates/cmux-tui-core/src/terminal_host_protocol.rs
  • cmux-tui/scripts/check-spec-inventory.py
  • cmux-tui/scripts/test_check_spec_inventory.py
  • cmux-tui/spec/resource-operations-v2.json
  • cmux-tui/spec/terminal-host.md

Comment thread cmux-tui/apps/macos/NativeMuxDemo/Package.swift
Comment thread cmux-tui/apps/macos/NativeMuxDemo/README.md
Comment thread cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh
Comment thread cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh
Comment thread cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/BrowserView.swift Outdated
Comment thread cmux-tui/crates/cmux-terminal-client/src/lib.rs Outdated
Comment thread cmux-tui/crates/cmux-terminal-host-protocol/Cargo.toml
Comment thread cmux-tui/crates/cmux-terminal-host-protocol/src/lib.rs
Comment thread cmux-tui/crates/cmux-terminal-host-protocol/src/lib.rs
Comment thread cmux-tui/crates/cmux-terminal-host-protocol/src/lib.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review continued from previous batch...

Comment thread cmux-tui/crates/cmux-terminal-client/Cargo.toml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 16

♻️ Duplicate comments (5)
cmux-tui/apps/macos/NativeMuxDemo/test-remote-command.sh (1)

40-55: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the dead eval fallback branch.

This PR adds remote-command.sh in the same directory, so line 29 always succeeds and lines 40-55 never run. The branch also re-parses launcher text through eval, which static analysis flags. Delete the branch and keep only the sourced helper path. RUN_REMOTE_DEMO at line 6 then becomes unused.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/apps/macos/NativeMuxDemo/test-remote-command.sh` around lines 40 -
55, Remove the unreachable fallback branch beginning at the else clause,
including its sed/eval extraction, test environment setup, and remote_under_test
wrapper. Keep the sourced remote-command.sh path as the sole setup in the test
script, and remove the now-unused RUN_REMOTE_DEMO variable.

Source: Linters/SAST tools

cmux-tui/apps/macos/NativeMuxDemo/verify-remote-demo-lifecycle.sh (1)

10-24: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

The usage-error path leaks the temporary directory.

Line 10 creates TEST_ROOT. Lines 21-24 can exit 2 before line 45 installs the EXIT trap. The directory then stays in TMPDIR. Validate the arguments before you create TEST_ROOT.

🧹 Proposed fix
 RUNS="${2:-3}"
+if [[ $# -gt 2 || ! "$RUNS" =~ ^[1-9][0-9]*$ ]]; then
+  echo "Usage: verify-remote-demo-lifecycle.sh [ssh-host] [runs]" >&2
+  exit 2
+fi
 TEST_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/cmux-native-remote-lifecycle.XXXXXX")"
@@
 READY_POLL_SECONDS=0.1
-
-if [[ $# -gt 2 || ! "$RUNS" =~ ^[1-9][0-9]*$ ]]; then
-  echo "Usage: verify-remote-demo-lifecycle.sh [ssh-host] [runs]" >&2
-  exit 2
-fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/apps/macos/NativeMuxDemo/verify-remote-demo-lifecycle.sh` around
lines 10 - 24, Move the argument validation in verify-remote-demo-lifecycle.sh
before the TEST_ROOT assignment and any temporary-directory setup. Preserve the
existing usage message and exit status, while ensuring invalid arguments cannot
create an uncleaned temporary directory.
cmux-tui/apps/macos/NativeMuxDemo/README.md (1)

1-86: 📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Add matching Japanese operational documentation.

This README documents launch, lifecycle, and remote cleanup only in English. The app ships en.lproj and ja.lproj catalogs. Add a Japanese document with the same commands and safety constraints, and link both documents from the package entry point.

As per coding guidelines, "User-facing text must use localized APIs and matching catalogs; web, metadata, API, markdown, changelog, and user-facing data must use locale-specific sources and update every supported locale."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/apps/macos/NativeMuxDemo/README.md` around lines 1 - 86, Add a
Japanese README alongside the existing NativeMuxDemo documentation that mirrors
all launch, lifecycle, remote-demo, cleanup, command, and safety details in
README.md, using the same commands without alteration. Update the package entry
point to link both the English and Japanese documents, and ensure the Japanese
document is included through the app’s existing ja.lproj/catalog structure where
applicable.

Source: Coding guidelines

cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh (1)

256-273: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

return in the EXIT trap does not change the script exit status.

cleanup runs only as the EXIT trap. The shell exit status stays the status that triggered the trap. return does not override it. Lines 260 and 262 set exit_status=1 when the remote daemon is still alive or when the remote state removal fails, but the script still exits 0. verify-remote-demo-lifecycle.sh line 193 checks wait "$LAUNCHER_PID", so it reports a clean run after a failed remote cleanup.

🐛 Proposed fix
   if [[ "$LOCAL_ROOT" == "$TEMP_PARENT"/cmux-native-remote-client.* ]]; then
     rm -rf -- "$LOCAL_ROOT"
   fi
-  return "$exit_status"
+  exit "$exit_status"
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh` around lines 256 - 273,
Update the EXIT-trap cleanup function around cleanup so failures recorded in
exit_status override the final process status, rather than relying on return.
Preserve the existing daemon-alive and remote-removal checks, but explicitly
terminate or propagate exit_status from the trap when it is nonzero so
verify-remote-demo lifecycle checks observe the cleanup failure.
cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh (1)

364-383: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Retry loops abort on the first transient failure. Each poll loop assigns the result of a command substitution while set -e is active. One failed admin-socket call or one failed SSH round trip ends the script, so the remaining retry budget is never used. Two sites then feed a possibly empty value into an arithmetic comparison.

  • cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh#L364-L383: append || true to the enroll pending substitution at line 374, and apply the same guard plus a [[ "$CONNECTED_CLIENTS" =~ ^[0-9]+$ ]] check to the enroll status substitution at lines 527-529.
  • cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh#L431-L432: append || true to the enroll pending substitution so the loop continues on a transient SSH failure.
  • cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh#L447-L452: append || true to the enroll status substitution and guard (( CONNECTED >= 1 )) with [[ "$CONNECTED" =~ ^[0-9]+$ ]].
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh` around lines 364 - 383, Update
the retry loops to tolerate transient command failures under set -e. In
cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh lines 364-383, guard the enroll
pending substitution and enroll status substitution with || true, and only
perform arithmetic after validating CONNECTED_CLIENTS with [[
"$CONNECTED_CLIENTS" =~ ^[0-9]+$ ]]. In
cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh lines 431-432, guard enroll
pending with || true; at lines 447-452, guard enroll status similarly and
validate CONNECTED with [[ "$CONNECTED" =~ ^[0-9]+$ ]] before comparing it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmux-tui/apps/macos/NativeMuxDemo/README.md`:
- Around line 23-27: Remove the branch-specific
worktrees/feat-cmux-tui-swift-frontend/ prefix from every documented command in
the NativeMuxDemo README, including the run-demo.sh references and the commands
at the other noted locations. Use repository-relative paths beginning with
cmux-tui/apps/macos/NativeMuxDemo/ so the commands work from a normal checkout.

In `@cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh`:
- Around line 466-478: Reduce or remove the per-iteration remote polling in the
idle wait loop around remote_command. Prefer relying on the existing local kill
-0 checks for APP_PID and SSH_DAEMON_PID; if remote enroll connections state
must remain, poll it at a substantially longer interval rather than every 250
ms, while preserving the existing exit and daemon-failure behavior.

In `@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/BrowserView.swift`:
- Around line 33-35: Update the lock icon in the BrowserView URL display to
derive its system image from browser.url’s scheme: use the secure lock only for
HTTPS and an appropriate non-secure icon for HTTP or other schemes, preserving
the existing styling.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/DemoWindowPlacement.swift`:
- Around line 61-62: Update the layout persistence flow around JSONEncoder and
data.write in DemoWindowPlacement to log encoding and file-write failures with
Logger, while preserving the current early-return behavior and atomic write
option.

In `@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/FrontendModel.swift`:
- Around line 318-345: Update setViewportWidth to convert columns into a
fractional viewport width using Double(columns) divided by screenWidth, while
preserving the existing clamping and mutation flow as appropriate for the
0.1–1.0 pane.viewport_width.set contract.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/FrontendService.swift`:
- Around line 277-313: Bound the event accumulation in drainRenderEvents by
introducing a maximum batch size and stopping once result reaches that limit,
returning the collected events so the caller can drain remaining queued events
on a later invocation. Preserve the existing event-copying and unknown-event
handling behavior.

In `@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Localization.swift`:
- Around line 3-12: Replace the static-only L10n namespace with a constructable
localization dependency that provides text and format operations as instance
methods. Inject this dependency into the view or controller owners that render
user-facing strings, and update their calls to use the injected instance instead
of L10n’s static APIs; avoid introducing global or singleton state.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/NativeTerminalModel.swift`:
- Around line 136-148: Update NativeTerminalModel.resize to use a stored,
cancellable model-owned resize Task instead of creating an untracked Task per
geometry change. Coalesce updates so the operation submits the newest pending
geometry after any in-flight handle.resize completes, while preserving rejection
handling for the latest request. Cancel and clear this operation during
shutdownAndWait().
- Around line 15-20: Move the top-level terminalGeometry function onto the
TerminalGeometry type as an initializer or static member, preserving its
existing width/height calculations and clamping behavior. Update every caller to
use the new TerminalGeometry-owned API and remove the internal free function.

In `@cmux-tui/apps/macos/NativeMuxDemo/test-remote-lifecycle-ready.sh`:
- Around line 30-41: Increase the startup-attempt argument in the
cmux_wait_for_remote_demo_ready call for the first lifecycle case so it
comfortably exceeds the delay between the startup message and “Ready.” Keep the
long-transfer budget and all other arguments unchanged, preserving the test’s
verification that the transfer does not consume the startup budget.

In `@cmux-tui/apps/macos/NativeMuxDemo/verify-demo-lifecycle.sh`:
- Around line 95-99: Update the APP_PID discovery loop around new_pids to avoid
head -1 terminating the pipe early under pipefail; read only the first PID while
allowing new_pids to finish successfully, preserving the existing retry and
break behavior.

In `@cmux-tui/crates/cmux-terminal-client/include/cmux_terminal_client.h`:
- Around line 84-88: Remove constness from the consuming render-event accessor
by changing cmux_frontend_terminal_copy_next_render_event to accept a mutable
terminal pointer in both the C header and the Rust extern-C definition in
frontend.rs. Update any related declarations or call sites as needed while
preserving the existing queue-consumption behavior.

In `@cmux-tui/crates/cmux-terminal-client/src/frontend.rs`:
- Around line 845-855: Update cmux_frontend_client_disconnect around the
cmux-frontend-disconnect cleanup thread so it retains the thread’s JoinHandle
and waits for it to finish before returning, while preserving the separate
thread needed to drop the Runtime safely. Ensure completion is observed only
after control.close, multiplexer.shutdown, connection.close, and provider.close
have all completed.
- Around line 357-368: Update the open_control_stream handshake invoked by
connect_transport to accept and enforce the timeout already supplied to
frontend_connect, including the loop waiting for all three Opened lanes. Ensure
the timeout propagates through the runtime.block_on call and returns the
existing connection error/cleanup path instead of blocking indefinitely.
- Around line 690-698: Update the encode flow around encode_key so the mutex
guard is released before matching the result and handling errors. Bind the
encode_key(chord, repeat) result first, then lock terminal.state only in the Err
branch to set status, notify updates, and return false; preserve the existing
success and enqueue behavior.

In `@cmux-tui/crates/cmux-terminal-client/src/lib.rs`:
- Around line 296-329: Update push_native_render_event so the eligible adjacent
Bytes events are coalesced before enforcing the event-count limit, while still
enforcing the byte budget for both coalesced and newly queued events. Preserve
queue clearing and false-return behavior when either limit is exceeded. Add unit
tests covering coalescing, byte and count limits, and prepare_handshake
resetting both native_render_events and native_render_event_bytes.

---

Duplicate comments:
In `@cmux-tui/apps/macos/NativeMuxDemo/README.md`:
- Around line 1-86: Add a Japanese README alongside the existing NativeMuxDemo
documentation that mirrors all launch, lifecycle, remote-demo, cleanup, command,
and safety details in README.md, using the same commands without alteration.
Update the package entry point to link both the English and Japanese documents,
and ensure the Japanese document is included through the app’s existing
ja.lproj/catalog structure where applicable.

In `@cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh`:
- Around line 364-383: Update the retry loops to tolerate transient command
failures under set -e. In cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh lines
364-383, guard the enroll pending substitution and enroll status substitution
with || true, and only perform arithmetic after validating CONNECTED_CLIENTS
with [[ "$CONNECTED_CLIENTS" =~ ^[0-9]+$ ]]. In
cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh lines 431-432, guard enroll
pending with || true; at lines 447-452, guard enroll status similarly and
validate CONNECTED with [[ "$CONNECTED" =~ ^[0-9]+$ ]] before comparing it.

In `@cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh`:
- Around line 256-273: Update the EXIT-trap cleanup function around cleanup so
failures recorded in exit_status override the final process status, rather than
relying on return. Preserve the existing daemon-alive and remote-removal checks,
but explicitly terminate or propagate exit_status from the trap when it is
nonzero so verify-remote-demo lifecycle checks observe the cleanup failure.

In `@cmux-tui/apps/macos/NativeMuxDemo/test-remote-command.sh`:
- Around line 40-55: Remove the unreachable fallback branch beginning at the
else clause, including its sed/eval extraction, test environment setup, and
remote_under_test wrapper. Keep the sourced remote-command.sh path as the sole
setup in the test script, and remove the now-unused RUN_REMOTE_DEMO variable.

In `@cmux-tui/apps/macos/NativeMuxDemo/verify-remote-demo-lifecycle.sh`:
- Around line 10-24: Move the argument validation in
verify-remote-demo-lifecycle.sh before the TEST_ROOT assignment and any
temporary-directory setup. Preserve the existing usage message and exit status,
while ensuring invalid arguments cannot create an uncleaned temporary directory.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d664edff-be3c-45bc-92fc-20058a680059

📥 Commits

Reviewing files that changed from the base of the PR and between 21675cc and 643b9af.

⛔ Files ignored due to path filters (1)
  • cmux-tui/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (66)
  • cmux-tui/Cargo.toml
  • cmux-tui/apps/macos/NativeMuxDemo/Package.swift
  • cmux-tui/apps/macos/NativeMuxDemo/README.md
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/CCmuxTerminal/cmux_terminal_client.h
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/CCmuxTerminal/module.modulemap
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/GhosttyKit/module.modulemap
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/BrowserView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/DemoWindowPlacement.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/FrontendModel.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/FrontendService.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/GhosttyRemoteSurfaceView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/GhosttyRuntime.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/JSONValue.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/LayoutNode.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/LayoutViews.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Localization.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/NativeMuxDemoApp.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/NativeTerminalModel.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/PaneView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/ResourceSnapshot.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Resources/en.lproj/Localizable.strings
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Resources/ja.lproj/Localizable.strings
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/RootView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/SpacesBar.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/TerminalView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/WorkspaceSidebar.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Support/Info.plist
  • cmux-tui/apps/macos/NativeMuxDemo/Support/en.lproj/InfoPlist.strings
  • cmux-tui/apps/macos/NativeMuxDemo/Support/ja.lproj/InfoPlist.strings
  • cmux-tui/apps/macos/NativeMuxDemo/Tests/NativeMuxDemoTests/NativeMuxDemoTests.swift
  • cmux-tui/apps/macos/NativeMuxDemo/launch-ghostty-client.sh
  • cmux-tui/apps/macos/NativeMuxDemo/remote-command.sh
  • cmux-tui/apps/macos/NativeMuxDemo/remote-daemon-owner.sh
  • cmux-tui/apps/macos/NativeMuxDemo/remote-lifecycle-ready.sh
  • cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh
  • cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh
  • cmux-tui/apps/macos/NativeMuxDemo/test-remote-command.sh
  • cmux-tui/apps/macos/NativeMuxDemo/test-remote-lifecycle-ready.sh
  • cmux-tui/apps/macos/NativeMuxDemo/verify-demo-lifecycle.sh
  • cmux-tui/apps/macos/NativeMuxDemo/verify-remote-demo-lifecycle.sh
  • cmux-tui/bindings/cpp/.cmux-resource-api.json
  • cmux-tui/bindings/go/.cmux-resource-api.json
  • cmux-tui/bindings/java/.cmux-resource-api.json
  • cmux-tui/bindings/python/.cmux-resource-api.json
  • cmux-tui/bindings/rust/.cmux-resource-api.json
  • cmux-tui/bindings/typescript/.cmux-resource-api.json
  • cmux-tui/bindings/zig/.cmux-resource-api.json
  • cmux-tui/crates/cmux-remote/Cargo.toml
  • cmux-tui/crates/cmux-remote/src/lib.rs
  • cmux-tui/crates/cmux-remote/src/mux_codec.rs
  • cmux-tui/crates/cmux-remote/src/service.rs
  • cmux-tui/crates/cmux-terminal-client/Cargo.toml
  • cmux-tui/crates/cmux-terminal-client/include/cmux_terminal_client.h
  • cmux-tui/crates/cmux-terminal-client/src/frontend.rs
  • cmux-tui/crates/cmux-terminal-client/src/lib.rs
  • cmux-tui/crates/cmux-terminal-host-protocol/Cargo.toml
  • cmux-tui/crates/cmux-terminal-host-protocol/src/lib.rs
  • cmux-tui/crates/cmux-tui-core/Cargo.toml
  • cmux-tui/crates/cmux-tui-core/src/lib.rs
  • cmux-tui/crates/cmux-tui-core/src/resource_router.rs
  • cmux-tui/crates/cmux-tui-core/src/surface.rs
  • cmux-tui/crates/cmux-tui-core/src/terminal_host_protocol.rs
  • cmux-tui/scripts/check-spec-inventory.py
  • cmux-tui/scripts/test_check_spec_inventory.py
  • cmux-tui/spec/resource-operations-v2.json
  • cmux-tui/spec/terminal-host.md

Comment thread cmux-tui/apps/macos/NativeMuxDemo/README.md Outdated
Comment thread cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh
Comment thread cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/BrowserView.swift Outdated
Comment thread cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/DemoWindowPlacement.swift Outdated
Comment thread cmux-tui/crates/cmux-terminal-client/include/cmux_terminal_client.h
Comment thread cmux-tui/crates/cmux-terminal-client/src/frontend.rs Outdated
Comment thread cmux-tui/crates/cmux-terminal-client/src/frontend.rs Outdated
Comment thread cmux-tui/crates/cmux-terminal-client/src/frontend.rs Outdated
Comment thread cmux-tui/crates/cmux-terminal-client/src/lib.rs Outdated
Comment thread cmux-tui/crates/cmux-terminal-client/src/frontend.rs
Comment thread cmux-tui/crates/cmux-terminal-client/src/frontend.rs Outdated
@lawrencecchen
lawrencecchen force-pushed the feat-cmux-tui-swift-frontend branch from dedbbf8 to e40d1ac Compare August 7, 2026 08:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (2)
cmux-tui/crates/cmux-terminal-client/src/frontend.rs (1)

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

Close the control stream before tearing down the transport.

stream is already open on Line 363. This failure path shuts down the transport but does not call stream.close().await. Close the service stream first so the daemon receives a clean service closure before multiplexer shutdown.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/crates/cmux-terminal-client/src/frontend.rs` around lines 379 - 383,
Update the shutdown flow in the runtime.block_on cleanup block to call
stream.close().await before multiplexer.shutdown() and connection.close().
Preserve the existing provider.close() cleanup afterward so the control stream
is closed before transport teardown.
cmux-tui/crates/cmux-terminal-client/src/lib.rs (1)

452-457: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Preserve the complete Kitty state in the native Reset event.

The text renderer restores snapshot.replay, snapshot.kitty_image_aliases, and snapshot.kitty_state on Lines 429-434. The native Reset event forwards only snapshot.replay.

Extend the native Reset payload and its Swift consumer so they restore the aliases and Kitty replay state with the VT replay. Add an image-containing snapshot regression test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmux-tui/crates/cmux-terminal-client/src/lib.rs` around lines 452 - 457,
Update the native Reset flow around continue_after_native_event to carry
snapshot.replay, snapshot.kitty_image_aliases, and snapshot.kitty_state, and
update the corresponding Swift consumer to restore all three components like the
text renderer. Add a regression test using a snapshot containing an image that
verifies aliases and Kitty replay state survive Reset.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/BrowserView.swift`:
- Line 33: Update the security-icon selection in BrowserView to normalize the
URL scheme before checking whether it is HTTPS. Parse the scheme and compare its
lowercased value so mixed-case HTTPS URLs select lock.fill, while non-HTTPS URLs
continue selecting globe.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/NativeTerminalModel.swift`:
- Around line 144-154: Update the resizeTask closure around handle.resize so a
cancelled task returns immediately after the await, before updating errorMessage
or clearing state. When cleanup runs, clear resizeTask only if it still refers
to the active non-cancelled task, preventing an older task from clearing a newer
replacement.

In
`@cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/WorkspaceSidebar.swift`:
- Around line 62-66: Precompute and maintain a screenCountByWorkspaceID index in
ResourceSnapshot whenever screens are decoded or refreshed, rather than
filtering and sorting through screens for each workspace row. Update the
workspace sidebar row around snapshot.screens(in:) to read the workspace’s count
from this index while preserving the existing singular/plural formatting and
zero-count behavior.

---

Duplicate comments:
In `@cmux-tui/crates/cmux-terminal-client/src/frontend.rs`:
- Around line 379-383: Update the shutdown flow in the runtime.block_on cleanup
block to call stream.close().await before multiplexer.shutdown() and
connection.close(). Preserve the existing provider.close() cleanup afterward so
the control stream is closed before transport teardown.

In `@cmux-tui/crates/cmux-terminal-client/src/lib.rs`:
- Around line 452-457: Update the native Reset flow around
continue_after_native_event to carry snapshot.replay,
snapshot.kitty_image_aliases, and snapshot.kitty_state, and update the
corresponding Swift consumer to restore all three components like the text
renderer. Add a regression test using a snapshot containing an image that
verifies aliases and Kitty replay state survive Reset.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7a8c51f5-f60e-4e34-b885-f73ab038d66b

📥 Commits

Reviewing files that changed from the base of the PR and between 643b9af and dedbbf8.

📒 Files selected for processing (12)
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/BrowserView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/FrontendModel.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/GhosttyRemoteSurfaceView.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/NativeTerminalModel.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Resources/en.lproj/Localizable.strings
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/Resources/ja.lproj/Localizable.strings
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/SpacesBar.swift
  • cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/WorkspaceSidebar.swift
  • cmux-tui/apps/macos/NativeMuxDemo/run-demo.sh
  • cmux-tui/apps/macos/NativeMuxDemo/run-remote-demo.sh
  • cmux-tui/crates/cmux-terminal-client/src/frontend.rs
  • cmux-tui/crates/cmux-terminal-client/src/lib.rs

Comment thread cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/BrowserView.swift Outdated
Comment thread cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/NativeTerminalModel.swift Outdated
Comment thread cmux-tui/apps/macos/NativeMuxDemo/Sources/NativeMuxDemo/WorkspaceSidebar.swift Outdated
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Comment thread cmux-tui/crates/cmux-terminal-client/src/lib.rs
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

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

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

@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

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

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

@cursor

cursor Bot commented Aug 12, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

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

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

@lawrence703

Copy link
Copy Markdown
Collaborator

Closing this superseded NativeMuxDemo stack. Head 8318e4999209b5907080548d435a695e5168c997 is a 92-file/221-commit prototype with old Iroh/Swift package paths absent from current main.
The accepted migration direction is recorded in closed PR 10388: native CMTH is the shipped path and the PTY-in-PTY bridge is deletable. Current implementation work is split across daemon attach PR 10408, manual-IO PR 10742, cloud manual-IO PR 11062, and current-main rebuild PR 11402.
A new frontend PR is required if native Swift UI remains a product goal. No unique safe delta is retained in this old stack.

@lawrencecchen

Copy link
Copy Markdown
Contributor Author

Closing as superseded. This NativeMuxDemo stack targets obsolete Iroh and Swift package paths. The accepted migration direction is recorded in closed #10388; current implementation work is in #10408 and later native terminal-host work.

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.

2 participants