Skip to content

Add a desktop target to xcrs over WebDriver - #122

Merged
setoelkahfi merged 4 commits into
developmentfrom
feature/xcrs-desktop-target
Nov 4, 2026
Merged

setoelkahfi merged 4 commits into
developmentfrom
feature/xcrs-desktop-target

Conversation

@setoelkahfi

Copy link
Copy Markdown
Collaborator

Adds a desktop target to xcrs, so an agent can drive a Tauri app on Linux through tauri-driver (WebKitWebDriver) with the same MCP tools it uses on mobile.

  • device_select and device_capabilities take webdriver_url. SelectedTarget::Desktop is a new variant, and resolve_target rejects webdriver_url combined with any Apple or Android field. resolve_selected_target keeps its signature.
  • crates/xcrs/src/webdriver.rs is a W3C WebDriver client over the existing reqwest dependency, with no client library. It speaks the same protocol as the e2e/binary/smoke.mjs script in sigit-app.
  • Mapping: app_install_launch and app_launch start a session (which launches the binary), app_terminate ends it, ui_describe returns the page source, ui_element_list returns visible interactive elements (capped at 200), ui_tap clicks the one displayed element matching an id, name, test id, ARIA label, title or text, input_text types into the focused element, screen_capture returns a PNG.
  • Every other tool returns an error saying it has no desktop meaning. The 21-tool list is unchanged.
  • A running app cannot be attached to, because tauri-driver launches the app when the session is created.

Tests: cargo test -p xcrs (95 lib tests, including a stub WebDriver server for session, source, screenshot, click, ambiguous and missing matches, typing, the element cap and error mapping), cargo clippy -p xcrs --all-targets and cargo fmt --check are clean on macOS. I have not run it against a real tauri-driver yet.

SelectedTarget::Desktop, selected with device_select webdriver_url, drives an
app through tauri-driver or any WebDriver endpoint using reqwest and plain
JSON. app_install_launch and app_launch start a session, ui_describe returns
the page source, ui_element_list and ui_tap work on labelled elements,
input_text types into the focused element, and screen_capture returns a PNG.
The other tools return an error saying they have no desktop meaning, and the
21-tool list is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: siGit Code v1.7.6 <noreply@sigit.si>
@setoelkahfi setoelkahfi self-assigned this Nov 4, 2026

@sigit-code-review sigit-code-review 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.

Adds a Desktop variant to SelectedTarget selected by a new webdriver_url field on device_select/device_capabilities, plus a hand-rolled W3C WebDriver client (webdriver.rs) that maps seven of the 21 tools onto a tauri-driver session: launch tools create the session (which starts the app), terminate deletes it, describe/elements/tap/text/screenshot run against it. resolve_target is the new general resolver; resolve_selected_target keeps its old signature. The macro dispatches desktop targets before the per-platform matches, and every other tool returns a no-desktop-meaning error. Tests cover the resolver, a stub WebDriver server, and error mapping.

Main things to look at: the input_text body shape (see finding — tauri-driver currently drops the W3C text field, so typing may fail against a real driver), the app_install_launch desktop branch that only fires when the stored target is desktop and silently ignores an explicitly passed Apple field, and the session map keyed by base URL with no validation that the session still exists server-side.


Automated review by siGit Code Review · commit 0315b46 · see the review dashboard

Comment thread crates/xcrs/src/webdriver.rs Resolved
Comment thread crates/xcrs/src/mcp.rs Resolved
Comment thread crates/xcrs/src/mcp.rs Resolved
Comment thread crates/xcrs/src/webdriver.rs Resolved
Comment thread crates/xcrs/src/webdriver.rs Resolved
Comment thread crates/xcrs/src/webdriver.rs Resolved
Comment thread crates/xcrs/src/webdriver.rs Resolved
Comment thread crates/xcrs/src/mcp.rs Resolved
Comment thread crates/xcrs/src/webdriver.rs Resolved
Comment thread crates/xcrs/src/mcp.rs Resolved
setoelkahfi and others added 2 commits November 4, 2026 10:18
…letes, show raw error bodies

Element Send Keys now carries both text and the legacy value array, a failed
session delete keeps the id so app_terminate can retry, a non-JSON error
body is included in the message, and the capability probe times out after
two seconds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: siGit Code v1.7.6 <noreply@sigit.si>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: siGit Code v1.7.6 <noreply@sigit.si>

@sigit-code-review sigit-code-review 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.

The diff tightens the WebDriver client: error responses now keep non-object bodies, /status probes are capped at 2s, end_session deletes before forgetting the session so app_terminate can retry, and type_text sends both the W3C text and legacy value arrays. The added tests cover those paths. One edge remains: a JSON object returned by a proxy rather than by WebDriver is still trusted and its body discarded, so the error loses the clue.

The earlier send-keys, delete-retry, raw-body, and 60s-status-probe findings are addressed; the start_session failure-swallowing concern is unchanged and still open.


Automated review by siGit Code Review · commit 3a2b851 · changes since 0315b46 · see the review dashboard

Comment thread crates/xcrs/src/webdriver.rs Resolved
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: siGit Code v1.7.6 <noreply@sigit.si>

@sigit-code-review sigit-code-review 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.

Re-review of the delta since 3a2b851: the error-shape fix in webdriver.rs now trusts a body as WebDriver JSON only when value.error is a string, so a valid-JSON-but-wrong-shape reply like {"message":"no healthy upstream"} falls through to the raw-body branch and its text is kept — exactly as agreed in the earlier thread, and a test covers it. The non-object case still lands in the body branch because value defaults to Null. All previously raised threads (send-keys shape, session delete ordering, driver_ready probe timeout, argument naming, formatting) remain addressed or closed as before; nothing new to flag.


Automated review by siGit Code Review · commit 571acdb · changes since 3a2b851 · see the review dashboard

@setoelkahfi
setoelkahfi merged commit 9cd23db into development Nov 4, 2026
41 checks passed
@setoelkahfi
setoelkahfi deleted the feature/xcrs-desktop-target branch November 4, 2026 10:18
@setoelkahfi setoelkahfi mentioned this pull request Nov 4, 2026
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.

3 participants