Skip to content

feat(doctor): proper Windows diagnostics + interactive-session detection - #1543

Merged
f-trycua merged 5 commits into
mainfrom
feat/cua-driver-rs-doctor-windows-session
May 17, 2026
Merged

feat(doctor): proper Windows diagnostics + interactive-session detection#1543
f-trycua merged 5 commits into
mainfrom
feat/cua-driver-rs-doctor-windows-session

Conversation

@f-trycua

@f-trycua f-trycua commented May 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

cua-driver doctor on Windows + Linux was previously falling through to the legacy cleanup codepath (Nothing to clean — install is up to date.), which is useless when the actual symptom is window-driving tools silently returning empty arrays. This PR turns doctor into a real diagnostic surface.

  • Probe-runner refactor — new crates/cua-driver/src/doctor.rs with Probe / Report types, plain-text output by default, --json for scripting. Each probe is one tagged line ([ok] / [warn] / [err]). Exit code is 0 on [ok] / [warn], non-zero only on [err].
  • Cross-platform probes on every target: binary version + arch, install dir (symlink-resolved), ~/.cua-driver-rs home (cached release-dir count), telemetry state.
  • Windows interactive-session detection — the critical fix. ProcessIdToSessionId(GetCurrentProcessId()); Session 0 emits a [warn] explicitly naming the affected tools (list_windows, click, type_text, screenshot, get_window_state) and the remediation (RDP / console / scheduled task in the user's session). Sessions ≥1 confirm OpenWindowStationW(WinSta0) + GetForegroundWindow() for a positive [ok].
  • Windows COM / EnumWindows probesCoCreateInstance(CUIAutomation) availability + top-level visible window count. Zero-window count gets a "consistent with Session 0 warning above" detail when both fire, so users read the two findings as one.
  • Linux probesDISPLAY / WAYLAND_DISPLAY matrix, X11 connection reachability, AT-SPI bus availability via AT_SPI_BUS env + gdbus introspect org.a11y.Bus fallback.
  • macOS unchanged in spirit — legacy LaunchAgent + update-script cleanup preserved as structured probes; pointer to cua-driver diagnose for the full TCC / cdhash dump.
  • Docs — installation.mdx gains a Windows: interactive-session requirements section explaining the Windows session model, symptoms, diagnosis via cua-driver doctor, and five practical fixes. CLI reference + PARITY.md updated to reflect the new shape.

The Session 0 root cause was confirmed experimentally during recent Windows VM testing — SSH-launched processes land in Session 0 by default, and EnumWindows / GetForegroundWindow / PrintWindow are all WindowStation+Desktop-scoped, so they silently return empty results. Users see "no windows found" and assume the tools are broken; they aren't. This probe surfaces the misconfig directly.

Test plan

  • cargo build --release -p cua-driver on macOS — clean (one pre-existing dead-code warning unrelated to this PR)
  • cargo check --release --target x86_64-pc-windows-msvc -p platform-windows — clean (only pre-existing warnings)
  • cargo test --release -p cua-driver --bin cua-driver — 48 passed, 0 failed (5 new doctor tests + existing telemetry / version-check suites)
  • cua-driver doctor on macOS (this host) — see sample output below; exit 0
  • cua-driver doctor --json on macOS — well-formed JSON, ok: true, all probe fields present
  • cua-driver doctor from RDP on Windows — should report [ok] interactive session: session N has an attached interactive desktop (needs Windows VM)
  • cua-driver doctor from SSH on Windows — should report the Session 0 warning with the full remediation detail line (needs Windows VM)
  • cua-driver doctor on a Linux X11 desktop — should report [ok] display server: X11 (DISPLAY=...) + connection / AT-SPI status (needs Linux host)
  • cua-driver doctor on a Wayland-only Linux session — should warn about XWayland (needs Linux host)

Sample output

macOS (this host, exit 0):

[ok  ] binary: cua-driver 0.2.1 (aarch64-macos)
[ok  ] install dir: /…/target/release/cua-driver
         path: /…/target/release/cua-driver
[ok  ] home dir: /Users/you/.cua-driver-rs (0 release dirs cached)
[ok  ] telemetry: enabled (install-id present)
[ok  ] legacy LaunchAgent: not present
[ok  ] legacy update script: not present
[ok  ] TCC + cdhash report: for a full bundle / signature / TCC dump, run `cua-driver diagnose`

Windows over SSH (Session 0, expected output — mocked from probe shape; needs VM verification):

[ok  ] binary: cua-driver 0.2.1 (x86_64-windows)
[ok  ] install dir: C:\Users\you\AppData\Local\Programs\trycua\cua-driver-rs\bin\cua-driver.exe
[ok  ] home dir: C:\Users\you\.cua-driver-rs (3 release dirs cached)
[ok  ] telemetry: enabled (install-id present)
[warn] interactive session: running in Session 0 (services); window-driving tools (list_windows, click, type_text, screenshot, get_window_state) will return empty results — these APIs need an attached interactive desktop.
         re-run cua-driver from an interactive logon (RDP, console, or a scheduled task in the user's session) for the GUI tools to function.
[ok  ] UI Automation: CoCreateInstance(CUIAutomation) succeeded
[ok  ] EnumWindows visible: 0 windows
         consistent with the Session 0 warning above — EnumWindows is scoped to the calling session's desktop.

Windows via RDP / console (Session N>0, expected — mocked):

[ok  ] interactive session: session 2 has an attached interactive desktop (WinSta0 + foreground window)
[ok  ] UI Automation: CoCreateInstance(CUIAutomation) succeeded
[ok  ] EnumWindows visible: 47 windows

Linux on X11 (expected — mocked):

[ok  ] display server: X11 (DISPLAY=:0)
[ok  ] X11 connection: connected, 12 visible top-level windows
[ok  ] AT-SPI: bus address present (AT_SPI_BUS=unix:abstract=/tmp/dbus-…)

Commits

  1. 92ef9371feat(doctor): cross-platform diagnostic probes + structured output
  2. 258c029bfeat(doctor): Windows interactive-session detection (Session 0 warning)
  3. a4fae457docs: Windows interactive-session requirements + doctor probes

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added cua-driver doctor to verify installation and environment across Windows, Linux, and macOS.
    • --json option for machine-readable output (skips update banner); exit code is non‑zero only when an error probe occurs.
    • Platform probes: Windows session/desktop checks, Linux display/AT‑SPI checks, macOS legacy cleanup diagnostics.
  • Documentation

    • Installation guide now shows example doctor output, Windows interactive‑session requirements, remediation options, and advises re-running doctor after fixes.
  • Docs

    • CLI/reference version updated to v0.2.0.

Review Change Stack

f-trycua and others added 3 commits May 17, 2026 18:45
`cua-driver doctor` was a thin legacy-cleanup script that printed
"Nothing to clean — install is up to date." on every fresh install
and emitted nothing meaningful on Windows / Linux. Replace it with a
probe-runner that emits structured, grep-friendly output and runs
platform-appropriate checks.

- New `crates/cua-driver/src/doctor.rs` with `Probe` / `Report` types,
  `--json` flag for scripting, and per-platform probe modules behind
  `#[cfg(target_os = ...)]`.
- Cross-platform probes: binary version + arch, install dir (with
  symlink resolution), package home dir (release-dir count), telemetry
  state.
- Windows probes: UI Automation COM availability (CoCreateInstance
  CUIAutomation), top-level visible-window count via EnumWindows. The
  interactive-session probe is added in the next commit.
- Linux probes: DISPLAY / WAYLAND_DISPLAY detection, X11 connection
  reachability, AT-SPI bus availability hint.
- macOS keeps the legacy-cleanup behavior, but reported as structured
  probes so existing users on stale installs still get the cleanup;
  pointer to `cua-driver diagnose` for the full TCC / cdhash dump.

Exit code is `0` on `[ok]` / `[warn]`, non-zero only when at least
one `[err]` probe failed (e.g. binary cannot resolve its own
install dir). Warnings do not fail the run because misconfigured
environments are sometimes the expected state (CI rendering the
report).

New `platform-windows::diagnostics` module exposes the COM probe;
cross-platform stubs keep the cua-driver crate buildable on every
target without duplicating the diagnostic surface.

5 new unit tests cover text + JSON rendering, status-tag mapping,
and the cross-platform probe smoke path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Window-driving tools (list_windows, click, type_text, screenshot,
get_window_state) silently return empty results when cua-driver runs
in Session 0 on Windows. The root cause is that EnumWindows,
GetForegroundWindow, and friends are scoped to the calling process's
WindowStation + Desktop, and SSH-launched processes land in Session 0
with no attached interactive desktop. Users see "no windows found",
assume the tools are broken, and waste hours debugging a non-bug.

Surface the misconfiguration directly:

- `platform-windows::diagnostics::current_session_id()` —
  ProcessIdToSessionId(GetCurrentProcessId()) wrapper.
- `platform-windows::diagnostics::interactive_desktop_check()` —
  OpenWindowStationW(WinSta0) + GetForegroundWindow handle probe.
- `doctor` reports `[warn] interactive session: running in Session 0
  (services); window-driving tools will return empty results — these
  APIs need an attached interactive desktop. Re-run from an
  interactive logon (RDP, console, or a scheduled task in the user's
  session).` whenever the calling process is in Session 0.
- Non-Session-0 runs get a positive `[ok]` line confirming
  WinSta0 + a foreground window are reachable, so the diagnostic is
  symmetric.
- EnumWindows count probe now appends a "consistent with Session 0
  warning above" detail line when both fire, so the user reads the
  two probes as one finding instead of two separate bugs.

Adds Win32_System_RemoteDesktop + Win32_System_StationsAndDesktops
features to the platform-windows windows-rs dep so the new probes
compile. Cross-platform stubs in diagnostics.rs keep the cua-driver
crate compilable on macOS and Linux without conditional dependency
chains.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Documents the new diagnostic surface and the Session 0 gotcha that
prompted it:

- `docs/content/docs/cua-driver/guide/getting-started/installation.mdx`
  gets a new `Windows: interactive-session requirements` section
  explaining the Windows session model in one paragraph, the
  symptoms (window-driving tools return empty arrays), how to
  diagnose with `cua-driver doctor`, and five practical fixes
  (RDP, console, Windows Terminal under the logged-in user,
  scheduled task in the user's session, session-launcher utility).
- The same file gets a "for a structured environment + install
  report on any platform" callout pointing at `cua-driver doctor`
  with sample output.
- `docs/content/docs/cua-driver/reference/cli-reference.mdx`
  replaces the one-line "clean up stale install bits" description
  with the full probe-runner shape, exit-code semantics, and
  `--json` flag.
- `libs/cua-driver-rs/PARITY.md` gains a `CLI subcommand: doctor`
  row covering every probe per platform and the intentional
  divergence from Swift (Swift only does macOS legacy cleanup;
  Rust runs on Windows + Linux where the analogous misconfigs are
  the dominant "tools broken" failure mode).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment May 17, 2026 5:24pm

Request Review

@coderabbitai

coderabbitai Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Implements cua-driver doctor: adds probe/report types, cross-platform and OS-specific probes (Windows session/COM/window checks, Linux display/X11/AT‑SPI, macOS legacy cleanup), CLI --json output with exit-code rules, and user documentation/parity notes.

Changes

cua-driver doctor implementation and CLI integration

Layer / File(s) Summary
Doctor data types, rendering, and tests
libs/cua-driver-rs/crates/cua-driver/src/doctor.rs
Defines Status, Probe, Report, text (to_text) and JSON (to_json) renderers, has_errors() semantics, and unit tests validating formatting and ok/error behavior.
Cross-platform probes and helpers
libs/cua-driver-rs/crates/cua-driver/src/doctor.rs
Implements probes for binary version/target, canonicalized install path, home cache inspection, telemetry opt-out/id detection, and home-dir helper.
Windows platform probes and diagnostics module
libs/cua-driver-rs/crates/cua-driver/src/doctor.rs, crates/platform-windows/src/diagnostics.rs, crates/platform-windows/Cargo.toml, crates/platform-windows/src/lib.rs
Adds Windows probes (interactive-session/session‑0 warning, interactive-desktop check, UI Automation COM probe, visible-window enumeration) and a diagnostics module exposing current_session_id(), interactive_desktop_check(), ui_automation_available(), is_non_interactive_error() with cross-target stubs and tests; updates Windows windows crate features and exports the diagnostics module.
Linux platform probes and dependency
libs/cua-driver-rs/crates/cua-driver/src/doctor.rs, crates/cua-driver/Cargo.toml
Adds DISPLAY/Wayland, X11 window enumeration, and AT‑SPI reachability probes using a bounded gdbus introspect; adds wait-timeout dependency to bound child wait.
macOS platform probes
libs/cua-driver-rs/crates/cua-driver/src/doctor.rs
Adds opportunistic checks for legacy LaunchAgent and updater script removal and emits informational pointer to cua-driver diagnose for TCC/cdhash reporting.
CLI wiring, help, and entrypoint dispatch
libs/cua-driver-rs/crates/cua-driver/src/cli.rs, libs/cua-driver-rs/crates/cua-driver/src/main.rs
Introduces Command::Doctor { json: bool }, parses --json, documents doctor options in help, implements run_doctor_cmd(json) to render text or pretty JSON and exit non-zero when errors exist, and updates main dispatch to skip the update banner when --json is used.
User docs and parity audit
docs/content/docs/cua-driver/guide/getting-started/installation.mdx, docs/content/docs/cua-driver/reference/cli-reference.mdx, docs/content/docs/cua-driver/reference/mcp-tools.mdx, libs/cua-driver-rs/PARITY.md
Adds installation guide doctor workflow and Windows Session 0 guidance, bumps CLI/reference versions to 0.2.0, and documents Rust doctor probe categories, output tags, --json behavior, and exit-code semantics in PARITY.md.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • trycua/cua#1490: Overlaps on cua-driver doctor CLI behavior and cleanup/registration changes.
  • trycua/cua#1536: Related to suppressing the update banner for doctor --json in main dispatch.

Poem

🐰 A doctor hops in, probes in paw,
Checking sessions, windows, and more—
Text or JSON it will show,
One small exit when errors grow,
Re-run after fixes, hop back for encore.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: implementation of Windows diagnostics and interactive-session detection for the doctor command, which is the primary focus of this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cua-driver-rs-doctor-windows-session

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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 and usage tips.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 5

🤖 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 `@docs/content/docs/cua-driver/guide/getting-started/installation.mdx`:
- Line 239: Update the sentence describing the `doctor` command so it no longer
claims `doctor` performs full TCC/cdhash diagnostics on macOS; instead state
that `doctor` runs general version + install-layout + telemetry checks and
platform probes, and for detailed TCC and cdhash diagnostics on macOS users
should be directed to `cua-driver diagnose`; specifically edit the line
mentioning “TCC + cdhash on macOS” to remove those as `doctor` probes and add a
short clause pointing users to `cua-driver diagnose` for that detailed report.

In `@libs/cua-driver-rs/crates/cua-driver/src/doctor.rs`:
- Around line 360-364: The warning message in the branch that handles an empty
result from list_windows overstates connectivity; update the Probe::warn call
inside the match arm that currently reads `v if v.is_empty()` (where `v` comes
from `list_windows`) so the title/text reflect that no windows were returned
rather than asserting an X11 connection—e.g., change the message to say "no
top-level windows returned (possible disconnected or inaccessible X11 display)"
or similar, keeping the change localized to the `report.push(Probe::warn(...))`
for that `v if v.is_empty()` arm.
- Around line 193-195: The release_count currently counts all directory entries
(including files); change the closure used on std::fs::read_dir(&releases) so it
filters entries to only directories (use entry.path().is_dir() or
entry.metadata()?.is_dir()) before counting; update the closure passed to
.map(|entries| ...) around the release_count variable to filter_map only entries
that are Ok and are directories so the "release dir(s) cached" metric reflects
directories only.
- Around line 380-391: The gdbus probe (the bus_ok check that builds a
Command::new("gdbus") and calls .output()) must be changed to run the subprocess
with a bounded timeout; replace the one-shot .output() call with spawning the
child (Command::spawn), then poll child.try_wait() in a loop or use a
wait-with-timeout helper (e.g., wait_timeout crate) with a configurable Duration
(e.g., 2–5s); if the timeout elapses kill the child (child.kill()), wait for it
to exit, and set bus_ok = false on timeout or non-success exit, ensuring errors
from spawn/kill/wait are handled and mapped to false as before.

In `@libs/cua-driver-rs/crates/platform-windows/src/diagnostics.rs`:
- Around line 146-150: The test ui_automation_available_succeeds_in_test_runner
assumes an interactive session and unconditionally asserts
ui_automation_available().is_ok(); change it to allow known non-interactive
(Session 0) failures instead of failing the test — call
ui_automation_available(), and if it returns Err, detect and accept the specific
non-interactive error (match on the error/HRESULT or the crate's error variant
returned by ui_automation_available) and convert that case into a test
skip/pass; otherwise require Ok. Implement a small helper (e.g.,
is_non_interactive_error) to centralize the error check and use it in the test
so CI Session 0 environments won't falsely fail.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e99a65d9-bd54-433a-97cb-30cbf66dec17

📥 Commits

Reviewing files that changed from the base of the PR and between b4536a9 and a4fae45.

⛔ Files ignored due to path filters (1)
  • libs/cua-driver-rs/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • docs/content/docs/cua-driver/guide/getting-started/installation.mdx
  • docs/content/docs/cua-driver/reference/cli-reference.mdx
  • libs/cua-driver-rs/PARITY.md
  • libs/cua-driver-rs/crates/cua-driver/src/cli.rs
  • libs/cua-driver-rs/crates/cua-driver/src/doctor.rs
  • libs/cua-driver-rs/crates/cua-driver/src/main.rs
  • libs/cua-driver-rs/crates/platform-windows/Cargo.toml
  • libs/cua-driver-rs/crates/platform-windows/src/diagnostics.rs
  • libs/cua-driver-rs/crates/platform-windows/src/lib.rs

Comment thread docs/content/docs/cua-driver/guide/getting-started/installation.mdx Outdated
Comment thread libs/cua-driver-rs/crates/cua-driver/src/doctor.rs
Comment thread libs/cua-driver-rs/crates/cua-driver/src/doctor.rs
Comment thread libs/cua-driver-rs/crates/cua-driver/src/doctor.rs Outdated
Comment thread libs/cua-driver-rs/crates/platform-windows/src/diagnostics.rs Outdated
f-trycua added 2 commits May 17, 2026 19:19
…ng + UIA test (CodeRabbit)

- gdbus probe wraps Command::spawn + wait_timeout(3s) so a hung D-Bus daemon
  can no longer freeze the whole doctor command.
- release_count filters dir-only entries (was counting files too).
- X11 probe message rewritten to hedge — empty list_windows could be no X
  server OR connected display with zero windows; the old text overstated.
- Windows UIA test tolerates the CO_E_NOTINITIALIZED / Session 0
  non-interactive failure as a valid outcome.
@f-trycua

Copy link
Copy Markdown
Collaborator Author

Pushed CR fixups + docs regen: 804a52d3 (doctor probes — bounded gdbus, dir-only release_count, X11 wording, UIA test tolerance), and the autogen-doc refresh that follows. @coderabbitai please re-review. Note: Check External Links (lychee) failure is the pre-existing redirect noise on unrelated files.

@coderabbitai

coderabbitai Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

@f-trycua: Thanks for pushing those fixups and the autogen-doc refresh! I'll kick off a fresh review of the PR now, taking into account the changes in 804a52d3 (bounded gdbus, dir-only release_count, X11 wording, and UIA test tolerance). I'll ignore the pre-existing Lychee redirect noise on unrelated files.

✅ Actions performed

Full review triggered.

@f-trycua
f-trycua merged commit ed8d5bd into main May 17, 2026
6 of 8 checks passed
@f-trycua
f-trycua deleted the feat/cua-driver-rs-doctor-windows-session branch May 17, 2026 17:25
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.

1 participant