Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions libs/cua-driver/rust/crates/cua-driver/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,21 @@ fn main() {
None => pip_preview::PipConfig::from_args(),
};
maybe_init_pip();

// Agent-cursor overlay. The DAEMON is the process that actually
// performs clicks / AX presses, so the overlay NSWindow + render
// loop must run HERE — not only in the in-process `mcp` arm. In the
// daemon-proxy setup (`mcp` relaunches `open -n -g … serve` and
// proxies to it), the proxy never renders and, before this, neither
// did the daemon — so every cursor command was a silent no-op and
// the agent cursor never appeared. Init the channel before spawning
// the serve thread so `run_on_main_thread()` always finds it ready
// (mirrors the Mcp arm).
let cursor_cfg = cursor_overlay::CursorConfig::from_args();
if cursor_cfg.enabled {
platform_macos::cursor::overlay::init(cursor_cfg.clone());
}

let reg = Arc::new(build_macos_registry());
reg.init_self_weak();
let sp = socket.unwrap_or_else(serve::default_socket_path);
Expand Down Expand Up @@ -320,6 +335,15 @@ fn main() {
// stays up as long as the daemon does.
if pip_cfg.enabled {
platform_macos::pip::run_appkit_main_loop();
} else if cursor_cfg.enabled {
// Render the agent-cursor overlay: park the main thread in the
// AppKit run loop so the overlay NSWindow draws. `run_on_main_thread`
// self-guards on `has_graphic_access()` and returns immediately
// when the daemon has no Window Server session — fall through to
// join so the daemon still serves headless. The serve thread runs
// on its background thread regardless.
platform_macos::cursor::overlay::run_on_main_thread();
let _ = serve_handle.join();
Comment on lines 336 to +346

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't let the PiP branch bypass the cursor overlay.

When PiP and the cursor overlay are both enabled, this ordering never calls platform_macos::cursor::overlay::run_on_main_thread(). In the same file, the mcp path still does maybe_init_pip() and then runs the overlay on the main thread, so serve now regresses the combined mode to "overlay initialized but never rendered."

Suggested shape
-            if pip_cfg.enabled {
-                platform_macos::pip::run_appkit_main_loop();
-            } else if cursor_cfg.enabled {
+            if cursor_cfg.enabled {
                 // Render the agent-cursor overlay: park the main thread in the
                 // AppKit run loop so the overlay NSWindow draws. `run_on_main_thread`
                 // self-guards on `has_graphic_access()` and returns immediately
                 // when the daemon has no Window Server session — fall through to
                 // join so the daemon still serves headless. The serve thread runs
                 // on its background thread regardless.
                 platform_macos::cursor::overlay::run_on_main_thread();
                 let _ = serve_handle.join();
+            } else if pip_cfg.enabled {
+                platform_macos::pip::run_appkit_main_loop();
             } else {
                 let _ = serve_handle.join();
             }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if pip_cfg.enabled {
platform_macos::pip::run_appkit_main_loop();
} else if cursor_cfg.enabled {
// Render the agent-cursor overlay: park the main thread in the
// AppKit run loop so the overlay NSWindow draws. `run_on_main_thread`
// self-guards on `has_graphic_access()` and returns immediately
// when the daemon has no Window Server session — fall through to
// join so the daemon still serves headless. The serve thread runs
// on its background thread regardless.
platform_macos::cursor::overlay::run_on_main_thread();
let _ = serve_handle.join();
if cursor_cfg.enabled {
// Render the agent-cursor overlay: park the main thread in the
// AppKit run loop so the overlay NSWindow draws. `run_on_main_thread`
// self-guards on `has_graphic_access()` and returns immediately
// when the daemon has no Window Server session — fall through to
// join so the daemon still serves headless. The serve thread runs
// on its background thread regardless.
platform_macos::cursor::overlay::run_on_main_thread();
let _ = serve_handle.join();
} else if pip_cfg.enabled {
platform_macos::pip::run_appkit_main_loop();
} else {
let _ = serve_handle.join();
}
🤖 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 `@libs/cua-driver/rust/crates/cua-driver/src/main.rs` around lines 336 - 346,
The PiP branch currently returns early and skips initializing/rendering the
cursor overlay when both pip_cfg.enabled and cursor_cfg.enabled are true; update
the control flow so that when cursor_cfg.enabled is true you always call
platform_macos::cursor::overlay::run_on_main_thread() (even if pip_cfg.enabled
is also true), then run platform_macos::pip::run_appkit_main_loop() as needed
and finally join the serve_handle (serve_handle.join()) so the overlay actually
renders in combined PiP+overlay mode; check the existing maybe_init_pip() usage
to preserve any initialization ordering.

} else {
let _ = serve_handle.join();
}
Expand Down