fix(cua-driver-rs)(macos): mcp runs headless instead of SIGABRT-ing without Window Server access (#1724) - #1781
Conversation
…nstead of SIGABRT-ing (#1724) When `cua-driver mcp` falls through to the in-process server (dev binary not inside CuaDriver.app, `--no-daemon-relaunch`, or a launchd parent), the cursor overlay brings up AppKit on the main thread. `+[NSApplication sharedApplication]` registers the process with the Window Server, and that registration **aborts the whole process** (SIGABRT in `_RegisterApplication`) when the process has no graphic-session access — e.g. `mcp` spawned as a stdio child from an SSH session, a LaunchDaemon, or a headless CI runner. The crash happens *before* the existing `mainScreen.is_null()` headless guard, so that guard never gets a chance to run. Reported in #1724. Probe `SessionGetInfo`'s `sessionHasGraphicAccess` bit — which answers "can this session talk to the Window Server?" without touching AppKit — and skip the overlay when it's unset, parking the main thread exactly as the overlay-disabled path already does. The MCP server keeps serving on its background thread, so `mcp` degrades to headless instead of dying. This is the macOS analogue of the Windows Session-0 short-circuit guard. Note: the *primary* repro from #1724 (a bundle-resolved `mcp` spawned by a client) is already handled on current releases by the daemon-proxy re-exec (#1525/#1530), which routes that case away from AppKit entirely. This change hardens the remaining in-process path. - `platform-macos/src/session.rs` — `has_graphic_access()` via SessionGetInfo - `platform-macos/src/cursor/overlay.rs` — gate AppKit init on it - `platform-macos/src/lib.rs` — expose the module Verified: builds + links the Security framework; the probe returns true in a GUI session (attrs 0x6030, graphic bit set) and the smoke test passes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdded macOS headless environment support by introducing a Security framework capability probe that detects Window Server access and conditionally gates AppKit initialization, preventing registration failures in CI, headless, and stdio scenarios while preserving background thread operation. ChangesHeadless macOS Support
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Problem
cua-driver mcpaborts with SIGABRT before the MCP handshake when launched as a stdio child in a context with no Window Server / graphic-session access. CrashReporter shows the abort inside AppKit process registration:Reported in #1724 (macOS 15.7.7, arm64; parent process python/codex).
Root cause
When
mcpfalls through to the in-process server (dev binary not insideCuaDriver.app,--no-daemon-relaunch, or a launchd parent), the cursor overlay brings up AppKit on the main thread.+[NSApplication sharedApplication]registers the process with the Window Server, and that registration aborts the whole process when the session has no graphic access — SSH, aLaunchDaemon, or a headless CI runner.The existing headless guard (
mainScreen.is_null()inrun_appkit) is too late — the abort happens earlier, insidesharedApplicationitself.Fix
Probe
SessionGetInfo'ssessionHasGraphicAccessbit — which answers "can this session talk to the Window Server?" without touching AppKit — and skip the overlay when it's unset, parking the main thread exactly as the overlay-disabled path already does. The MCP server keeps serving on its background thread, somcpdegrades to headless instead of dying.This is the macOS analogue of the Windows Session-0 short-circuit guard.
Changes
platform-macos/src/session.rs—has_graphic_access()viaSessionGetInfo(new)platform-macos/src/cursor/overlay.rs— gate AppKit init on it, with awarn!+ headless fallbackplatform-macos/src/lib.rs— expose the moduleVerification
cargo build -p cua-driver— builds and links theSecurityframework ✓status=0 attrs=0x6030 hasGraphic=true(thesessionHasGraphicAccessbit0x10is set) — so the overlay still runs normally for real users; only no-graphic-access contexts take the new headless path ✓false, which is exactly the distinction the guard relies on) ✓A full repro of the crash itself needs a no-graphic-access spawn context (SSH / LaunchDaemon), which can't be staged on a GUI dev box — happy to coordinate a live retest with the reporter.
Closes #1724
🤖 Generated with Claude Code
Summary by CodeRabbit
macOS Headless Environment Support