### Initialize and Start Mutter Session Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Demonstrates the initialization of Mutter-specific compositor, input, and capture backends, followed by starting a Waydriver session. Requires the MutterCompositor to be started first to expose its state. ```rust let mut compositor = MutterCompositor::new(); compositor.start(None).await?; // state() is Option>; always Some immediately after a // successful start(). Expect documents the invariant locally. let state = compositor.state().expect("state available after start"); let input = MutterInput::new(state.clone()); let capture = MutterCapture::new(state); let session = Session::start(Box::new(compositor), Box::new(input), Box::new(capture), cfg).await?; ``` -------------------------------- ### Run Gnome Calculator Example Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md This example demonstrates the API surface for a full session lifecycle, AT-SPI button clicks, keyboard input, unit conversion, and result verification. It is runnable with `cargo run -p waydriver-examples --example gnome_calculator`. ```rust cargo run -p waydriver-examples --example gnome_calculator ``` -------------------------------- ### GTK Fixture Action Event Examples Source: https://github.com/bohdantkachenko/waydriver/blob/main/crates/waydriver-fixture-gtk/README.md These examples demonstrate the various action events emitted by interactive widgets. Each event follows the format 'fixture-event: [key=value ...]' and is printed to stdout. Tests can consume these lines to confirm actions, such as clicks or toggles, have occurred. String fields may contain debug-formatted values with escaped quotes, while integer fields are bare. Avoid parsing fields directly; use string containment checks for robustness. ```shell fixture-event: clicked primary-button ``` ```shell fixture-event: toggled mode-toggle active=true ``` ```shell fixture-event: checked agree-check active=true ``` ```shell fixture-event: text-changed text-entry text="hello" ``` ```shell fixture-event: activated text-entry text="hello" ``` ```shell fixture-event: selected flavor-dropdown index=1 ``` ```shell fixture-event: selected size-combo active_id="l" ``` ```shell fixture-event: row-selected item-list index=2 ``` ```shell fixture-event: text-changed notes-area text="..." ``` ```shell fixture-event: dialog-opened sample-dialog ``` ```shell fixture-event: dialog-closed sample-dialog ``` ```shell fixture-event: text-changed adw-entry-row text="hi" ``` ```shell fixture-event: selected adw-combo-row index=1 ``` ```shell fixture-event: toggled adw-switch-row active=true ``` ```shell fixture-event: activated adw-action-row ``` ```shell fixture-event: dialog-opened adw-sample-dialog ``` ```shell fixture-event: dialog-closed adw-sample-dialog ``` ```shell fixture-event: drag-started drag-source payload="dnd-payload-token" ``` ```shell fixture-event: drag-entered drop-target ``` ```shell fixture-event: drag-left drop-target ``` ```shell fixture-event: drag-ended drag-source delete_data=false ``` ```shell fixture-event: dropped drop-target payload="dnd-payload-token" ``` ```shell fixture-event: clicked open-hidden-group-dialog ``` ```shell fixture-event: dialog-opened hidden-group-dialog ``` ```shell fixture-event: lazy-shown hidden-group-target-group ``` ```shell fixture-event: dialog-closed hidden-group-dialog ``` ```shell fixture-event: activated hidden-group-control-row ``` ```shell fixture-event: activated lazy-button ``` ```shell fixture-event: clicked open-non-initial-page-dialog ``` ```shell fixture-event: dialog-opened non-initial-page-dialog ``` ```shell fixture-event: dialog-closed non-initial-page-dialog ``` ```shell fixture-event: toggled lazy-switch active=true ``` -------------------------------- ### Start Waydriver Session and Interact with UI Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md This snippet demonstrates how to initialize a Waydriver session with the Mutter backend, take a screenshot, locate and interact with UI elements using XPath selectors, perform keyboard actions, and wait for specific text. ```rust use std::sync::Arc; use waydriver::{Session, SessionConfig, CompositorRuntime}; use waydriver_compositor_mutter::MutterCompositor; use waydriver_input_mutter::MutterInput; use waydriver_capture_mutter::MutterCapture; let mut compositor = MutterCompositor::new(); compositor.start(None).await?; // `state()` is `Option`; immediately after a successful `start()` it is // always `Some` — `expect` documents that invariant locally. let state = compositor.state().expect("state available after start"); let input = MutterInput::new(state.clone()); let capture = MutterCapture::new(state); let session = Arc::new(Session::start( Box::new(compositor), Box::new(input), Box::new(capture), SessionConfig { command: "your-gtk-app".into(), args: vec![], cwd: None, app_name: "your-gtk-app".into(), // Record the entire session to a WebM file. Set to `None` to skip. video_output: Some("/tmp/session.webm".into()), video_bitrate: None, // defaults to waydriver::capture::DEFAULT_VIDEO_BITRATE (2 Mbps) video_fps: None, // defaults to waydriver::capture::DEFAULT_VIDEO_FPS (15) }, ).await?); // Take a screenshot (returns PNG bytes). let png = session.take_screenshot().await?; // Target widgets with XPath selectors over the AT-SPI tree. Actions // auto-wait for the element to be visible + enabled before firing. session.locate("//Button[@name='primary-button']").click().await?; session.locate("//Text[@name='search']").set_text("hello").await?; // Keyboard input with modifier chords. session.press_chord("Ctrl+Shift+S").await?; // Explicit waits when auto-wait isn't enough — e.g. an item appearing // after some async work. session.locate("//Label[@name='status']") .wait_for_text(|t| t == "ready") .await?; // Inspect the tree while debugging selectors. let xml = session.dump_tree().await?; println!("{xml}"); Arc::try_unwrap(session).unwrap().kill().await?; ``` -------------------------------- ### Install Arch Linux Dependencies Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md Installs necessary packages for WayDriver on Arch Linux, including Mutter, PipeWire, GStreamer, and related libraries. ```bash sudo pacman -S pkg-config glib2 gstreamer gst-plugins-base gst-plugins-good gst-plugin-pipewire mutter pipewire wireplumber at-spi2-core dbus ``` -------------------------------- ### Configure MCP Client for Docker Runtime Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md Configure your MCP client to use the Waydriver Docker image as the MCP server. This example mounts the current directory as read-only workspace and a temporary directory for reports. ```json { "mcpServers": { "waydriver-mcp": { "command": "sh", "args": ["-c", "docker run --rm -i --network none -v \"$PWD:/workspace:ro\" -v /tmp/waydriver:/tmp/waydriver ghcr.io/bohdantkachenko/waydriver-mcp:latest"] } } } ``` -------------------------------- ### Install Build Dependencies on Fedora Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md Shell command to install build dependencies for waydriver on Fedora systems. Includes pkg-config, GLib development files, and GStreamer development files. ```sh sudo dnf install pkg-config glib2-devel gstreamer1-devel \ gstreamer1-plugins-base-devel mutter pipewire wireplumber \ gstreamer1-plugins-base gstreamer1-plugins-good \ gstreamer1-plugins-pipewire at-spi2-core dbus ``` -------------------------------- ### Install Build Dependencies on Debian/Ubuntu Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md Shell command to install build dependencies for waydriver on Debian/Ubuntu systems. Includes pkg-config, GLib development files, and GStreamer development files. ```sh sudo apt install pkg-config libglib2.0-dev libgstreamer1.0-dev \ libgstreamer-plugins-base1.0-dev mutter pipewire wireplumber \ gstreamer1.0-plugins-base gstreamer1.0-plugins-good \ gstreamer1.0-pipewire at-spi2-core dbus ``` -------------------------------- ### Display Session Start Time and Reload Page Source: https://github.com/bohdantkachenko/waydriver/blob/main/crates/waydriver-mcp/src/viewer.html Sets the text content for the 'started-at' element with the formatted session start time and initiates periodic page reloads every 2 seconds. ```javascript document.getElementById('started-at').textContent = new Date(STARTED_AT_MS).toLocaleString(); reload(); setInterval(reload, 2000); ``` -------------------------------- ### Build Docker Images for Waydriver Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Commands to build different Docker images for Waydriver, including the runtime image, builder image, and an image for examples. ```sh docker build -t waydriver-mcp . # runtime image docker build --target builder-base -t waydriver-mcp-builder . # builder image docker build --target runtime-e2e -t waydriver-mcp-e2e . # runtime + waydriver-fixture-gtk ``` -------------------------------- ### Install Node.js Dependencies with Named Volume Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md Installs Node.js dependencies into a named volume for reuse. This command is run when the package.json or package-lock.json changes. ```sh docker volume create myapp-nodemods docker run --rm -v "$PWD/package.json:/app/package.json:ro" -v "$PWD/package-lock.json:/app/package-lock.json:ro" -v "myapp-nodemods:/app/node_modules" -w /app ghcr.io/bohdantkachenko/waydriver-mcp-builder:latest sh -c "dnf install -y nodejs npm && npm ci --omit=dev" ``` -------------------------------- ### Install Node.js Dependencies with Builder Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Install Node.js dependencies for an application using the MCP builder image. A named volume `myapp-nodemods` is used to persist dependencies. This command should be re-run when the lockfile changes. ```sh docker volume create myapp-nodemods docker run --rm \ -v "$PWD/package.json:/app/package.json:ro" \ -v "$PWD/package-lock.json:/app/package-lock.json:ro" \ -v "myapp-nodemods:/app/node_modules" \ -w /app \ ghcr.io/bohdantkachenko/waydriver-mcp-builder:latest \ sh -c "dnf install -y nodejs npm && npm ci --omit=dev" ``` -------------------------------- ### Extend MCP Runtime Image with Node.js Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Extend the base MCP runtime image to include Node.js. This is necessary for running Node.js applications within the MCP environment. Dependencies are cleaned up after installation. ```dockerfile FROM ghcr.io/bohdantkachenko/waydriver-mcp:latest RUN dnf install -y nodejs && dnf clean all ``` -------------------------------- ### Enumerate Text and Regions in a Dialog Source: https://github.com/bohdantkachenko/waydriver/blob/main/docs/visual-locator.md Use `list_text` to get all OCR'd lines and their bounding boxes within a dialog. Use `list_labelled_regions` to pair each line with its enclosing visual region for further interaction or analysis. ```rust let dialog = session.locate("//Dialog[@name='Preferences']"); // Every OCR'd line inside the dialog, line text + union bbox. let hits = dialog.list_text().await?; for h in &hits { println!("{:?} at {:?}", h.text, h.bounds); } // Each line paired with its enclosing visual region. One flood-fill // per label; the screenshot is taken once and reused. for (label, region) in dialog.list_labelled_regions().await? { println!("{} ({:?}) inside {:?} shape", label.text, label.bounds, region.shape()); } ``` -------------------------------- ### Run Docker Build via Nix Convenience Apps Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Convenience commands using Nix to build the Waydriver Docker images. These abstract the underlying Docker build process. ```sh nix run .#docker-build # runtime nix run .#docker-build-e2e # runtime + waydriver-fixture-gtk ``` -------------------------------- ### Run NixOS App Binary with MCP Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Configure the MCP server to run a NixOS application by volume-mounting the Nix store. This allows Nix-built binaries to function correctly within the container by providing access to their dependencies in `/nix/store`. ```json "args": ["run", "--rm", "-i", "-v", "/nix/store:/nix/store:ro", "-v", "/home/user/myapp:/workspace:ro", "ghcr.io/bohdantkachenko/waydriver-mcp:latest"] ``` -------------------------------- ### Run waydriver-fixture-gtk Manually Source: https://github.com/bohdantkachenko/waydriver/blob/main/crates/waydriver-fixture-gtk/README.md Execute the fixture application from the command line. Specify the section to load using the `--section` flag. ```sh cargo run -p waydriver-fixture-gtk # default: gtk4 ``` ```sh cargo run -p waydriver-fixture-gtk -- --section=adw # just libadwaita ``` ```sh cargo run -p waydriver-fixture-gtk -- --section=dnd # just drag-and-drop ``` ```sh cargo run -p waydriver-fixture-gtk -- --section=lazy-a11y # adw lazy-realization repros ``` -------------------------------- ### Run Rust App Binary with MCP Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Configure the MCP server to run a Rust application by volume-mounting its built binary. The binary is expected to be in `/home/user/myapp/build` and will be accessible within the container at `/workspace`. ```json { "waydriver-mcp": { "command": "docker", "args": ["run", "--rm", "-i", "-v", "/home/user/myapp/build:/workspace:ro", "ghcr.io/bohdantkachenko/waydriver-mcp:latest"] } } ``` -------------------------------- ### Build C/C++ App with Builder Image Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Build a C/C++ application using the MCP builder image. This command uses `meson` for build system configuration and compilation. The builder image includes common development tools like `gcc`, `g++`, and `ninja-build`. ```sh docker run --rm -v "$PWD:/src:ro" -v "$PWD/build:/out" \ ghcr.io/bohdantkachenko/waydriver-mcp-builder:latest \ sh -c "cp -r /src /tmp/build && cd /tmp/build && meson setup _build && meson compile -C _build && cp _build/myapp /out/" ``` -------------------------------- ### Configure MCP Client for Docker with Nix Store Mount Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md This configuration is for NixOS users, mounting the Nix store to ensure Nix-built binaries work correctly within the Docker container. It includes the same workspace and report directory mounts. ```json { "mcpServers": { "waydriver-mcp": { "command": "sh", "args": ["-c", "docker run --rm -i --network none -v /nix/store:/nix/store:ro -v \"$PWD:/workspace:ro\" -v /tmp/waydriver:/tmp/waydriver ghcr.io/bohdantkachenko/waydriver-mcp:latest"] } } } ``` -------------------------------- ### Get Region at Specific Coordinates Source: https://github.com/bohdantkachenko/waydriver/blob/main/docs/visual-locator.md Use `session.region_at` to obtain a `RegionLocator` for the shape containing a given pixel. This method bypasses OCR and AT-SPI lookups, directly performing a flood-fill from the specified coordinates. ```rust // I already know there's a clickable thing near here. let region = session.region_at(512, 365).await?; match region.shape() { Shape::Pill | Shape::Rectangle => region.click().await?, _ => return Err(anyhow!("expected a button-shaped widget at the cursor")), } ``` -------------------------------- ### Build and Run Waydriver MCP Binary Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Commands to build the Waydriver MCP binary using Nix and run it via a Nix wrapper that injects necessary runtime dependencies. ```sh nix build # builds ./result/bin/waydriver (unwrapped) nix run .#mcp # runs the wrapper with runtime deps injected (see flake.nix apps) ``` -------------------------------- ### Build C/C++ App with MCP Builder Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md Build a C/C++ application using the waydriver-mcp-builder Docker image. This command compiles the application using Meson build system and copies the resulting binary to the output directory. ```sh docker run --rm -v "$PWD:/src:ro" -v "$PWD/build:/out" ghcr.io/bohdantkachenko/waydriver-mcp-builder:latest sh -c "cp -r /src /tmp/build && cd /tmp/build && meson setup _build && meson compile -C _build && cp _build/myapp /out/" ``` -------------------------------- ### Configure waydriver-fixture-gtk as an E2E Test Fixture Source: https://github.com/bohdantkachenko/waydriver/blob/main/crates/waydriver-fixture-gtk/README.md Set up the session configuration to use waydriver-fixture-gtk as the command-line application for end-to-end testing. You can specify the command, arguments, and application name. ```rust let cfg = SessionConfig { command: "waydriver-fixture-gtk".into(), // or absolute path args: vec!["--section=gtk4".into()], // optional, default "gtk4" app_name: "waydriver-fixture-gtk".into(), .. }; ``` -------------------------------- ### Build Rust App with MCP Builder Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md Build a Rust application using the waydriver-mcp-builder Docker image. Mounts the current directory as source and a build directory for output. The compiled binary is placed in the output directory. ```sh docker run --rm -v "$PWD:/src:ro" -v "$PWD/build:/out" ghcr.io/bohdantkachenko/waydriver-mcp-builder:latest sh -c "cp -r /src /tmp/build && cd /tmp/build && cargo build --release && cp target/release/myapp /out/" ``` -------------------------------- ### Build Rust App with Builder Image Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Build a Rust application using the MCP builder image to ensure ABI compatibility. Mounts the source code and outputs the built binary to a local build directory. The `cargo build --release` command is used. ```sh docker run --rm -v "$PWD:/src:ro" -v "$PWD/build:/out" \ ghcr.io/bohdantkachenko/waydriver-mcp-builder:latest \ sh -c "cp -r /src /tmp/build && cd /tmp/build && cargo build --release && cp target/release/myapp /out/" ``` -------------------------------- ### Run Application with Nix Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md Command to run an application using Nix for local development without Docker. This command wraps the binary with the required runtime environment variables. ```sh nix run .#mcp ``` -------------------------------- ### Prewarming Visual Locator Engine Source: https://github.com/bohdantkachenko/waydriver/blob/main/docs/visual-locator.md Configure the Session to prewarm the visual locator engine during startup. This helps avoid delays on the first `find_by_text` call by loading the OCR models in the background. ```rust Set [`SessionConfig::prewarm_visual = true`](https://docs.rs/waydriver/latest/waydriver/struct.SessionConfig.html#structfield.prewarm_visual) ``` -------------------------------- ### Mount Nix Store for NixOS Users Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md JSON snippet for Docker arguments. Mounts the Nix store directory into the MCP container, allowing Nix-built binaries to function correctly. ```json "args": ["run", "--rm", "-i", "-v", "/nix/store:/nix/store:ro", "-v", "/path/to/myapp:/workspace:ro", "ghcr.io/bohdantkachenko/waydriver-mcp:latest"] ``` -------------------------------- ### Pull Prebuilt Docker Images Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md Pull the latest Waydriver MCP runtime and builder images from GitHub Container Registry. These images contain all necessary system dependencies. ```sh docker pull ghcr.io/bohdantkachenko/waydriver-mcp:latest docker pull ghcr.io/bohdantkachenko/waydriver-mcp-builder:latest ``` -------------------------------- ### OCR Pipeline Overview Source: https://github.com/bohdantkachenko/waydriver/blob/main/docs/visual-locator.md This diagram illustrates the steps involved in the OCR pipeline, from taking a screenshot to filtering recognized text and returning bounding boxes. It highlights the use of PipeWire for screenshots, image loading, OCR engine processing, and text filtering. ```text ┌──────────────────────────────────────────────┐ │ Session::take_screenshot() │ │ PipeWire keepalive stream → PNG bytes │ └────────────────────┬─────────────────────────┘ │ v ┌──────────────────────────────────────────────┐ │ image::load_from_memory(...) │ │ PNG → DynamicImage │ └────────────────────┬─────────────────────────┘ │ optional .within(rect) │ crop to parent region + 32px context pad │ (Locator::find_by_text) v ┌──────────────────────────────────────────────┐ │ ocrs::OcrEngine │ │ prepare_input → detect_words → │ │ find_text_lines → recognize_text │ │ (pure-Rust, ONNX via rten) │ └────────────────────┬─────────────────────────┘ │ v ┌──────────────────────────────────────────────┐ │ Filter words by `text` (Substring/Exact) │ │ Translate bboxes back to screen coords │ │ Return Vec │ └──────────────────────────────────────────────┘ ``` -------------------------------- ### Build Waydriver from Source with Docker Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md Build the Waydriver MCP Docker image from source code using the `docker build` command. This creates a local image tagged as `waydriver-mcp`. ```sh docker build -t waydriver-mcp . ``` -------------------------------- ### Find and Click Icon Image Source: https://github.com/bohdantkachenko/waydriver/blob/main/docs/visual-locator.md Reads a reference PNG icon and finds its location on the screen to perform a click action. Ensure the reference PNG is correctly placed in the 'references' directory. ```rust let icon = std::fs::read("references/save_icon.png")?; session .find_image(&icon)? .with_threshold(0.9) .click() .await?; ``` -------------------------------- ### Build and Test Workspace Crates Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Commands to build, test, and lint all crates within the workspace using Cargo. Use these for general development and testing. ```sh cargo build --workspace cargo test --workspace cargo test -p waydriver # single crate cargo test -p waydriver keysym # single test module within a crate cargo clippy --workspace cargo fmt --all ``` -------------------------------- ### Mount Source and Dependencies for Node.js Apps Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md JSON snippet for Docker arguments. Mounts the application source code and Node.js modules from a named volume into the MCP container. Allows free editing of source code. ```json "args": ["run", "--rm", "-i", "-v", "/path/to/myapp/src:/app/src:ro", "-v", "myapp-nodemods:/app/node_modules:ro", "myapp-mcp:latest"] ``` -------------------------------- ### Configure MCP Server for Waydriver Source: https://github.com/bohdantkachenko/waydriver/blob/main/README.md JSON configuration for the waydriver-mcp server. Specifies the Docker command and arguments to run the MCP container, mounting the application build directory as a workspace. ```json { "mcpServers": { "waydriver-mcp": { "command": "docker", "args": ["run", "--rm", "-i", "-v", "/path/to/myapp/build:/workspace:ro", "ghcr.io/bohdantkachenko/waydriver-mcp:latest"] } } } ``` -------------------------------- ### Visual Region Detection Pipeline Flowchart Source: https://github.com/bohdantkachenko/waydriver/blob/main/docs/visual-locator.md This flowchart illustrates the steps involved in the region detection pipeline, from input parameters to the flood-fill process and stopping conditions. ```mermaid graph TD subgraph Inputs parent_bounds[parent_bounds (AT-SPI Rect, screen coords)] inner_bbox[inner_bbox (OCR text bbox, screen coords)] full_png[full_png (Session::take_screenshot)] tuning[tuning (SessionConfig::visual_region_tuning)] end subgraph Preprocessing crop_translate[Crop full_png to parent_bounds
Translate inner_bbox into crop coords] end subgraph Seed Picking pick_seed[pick_seed_outside(inner_bbox, image)
Try right / left / below / above the
inner bbox, +4 px offset. Sanity-check
uniformity vs a neighbouring pixel so we
don't seed on glyph antialiasing fringe.] end subgraph Flood Fill flood_fill[flood_fill(image, seed, tolerance)
BFS, Vec<bool> visited grid.
Add 4-neighbour pixels where
‖rgb(neighbour) - rgb(seed)‖₂ ≤ tolerance
Track bbox + centroid as we go.] end subgraph Region Calculation region_calc[region_0 = { bbox, centroid }
Translate back to screen coords.
Push into result list.] end subgraph Stopping Conditions stop_check[Stop?
• region == previous region (no growth)
• region covers entire crop
• iteration count ≥ tuning.max_regions
• pixel_just_outside(region) has nowhere
to go (region touches all image edges)] end subgraph Next Seed next_seed[seed = pixel_just_outside(region.bbox)
Loop back to flood_fill.] end Inputs --> crop_translate crop_translate --> pick_seed pick_seed --> flood_fill flood_fill --> region_calc region_calc --> stop_check stop_check -- otherwise --> next_seed stop_check -- Stop? --> end_process((End)) next_seed --> flood_fill ``` -------------------------------- ### Build Fixture Binary Source: https://github.com/bohdantkachenko/waydriver/blob/main/crates/waydriver-fixture-gtk/README.md Ensures the GTK fixture binary is rebuilt if it has been edited since the last build. This is necessary to avoid running tests against a stale binary. ```sh cargo build -p waydriver-fixture-gtk ``` -------------------------------- ### Mount Node.js App Source and Dependencies Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Configure the MCP agent to mount the Node.js application source code and its dependencies from a named volume. This allows for live code changes without restarting the MCP session. ```json "args": ["run", "--rm", "-i", "-v", "/home/user/myapp/src:/app/src:ro", "-v", "myapp-nodemods:/app/node_modules:ro", "myapp-mcp:latest"] ``` -------------------------------- ### Render Event Parameters as Definition List Source: https://github.com/bohdantkachenko/waydriver/blob/main/crates/waydriver-mcp/src/viewer.html Renders event parameters into a definition list (`
`) for clear display. Filters out null, undefined, or empty string values. ```javascript function renderParams(params) { const entries = Object.entries(params || {}).filter(([_, v]) => v !== null && v !== undefined && v !== ''); if (!entries.length) return null; const dl = el('dl', { class: 'grid grid-cols-[auto_1fr] gap-x-3 gap-y-1 text-sm mt-1' }); for (const [k, v] of entries) { dl.appendChild(el('dt', { class: 'text-slate-500', text: k })); const dd = el('dd', { class: 'mono text-slate-800 break-all' }); dd.textContent = typeof v === 'string' ? v : JSON.stringify(v); dl.appendChild(dd); } return dl; } ``` -------------------------------- ### VisualLocator Debug Output Source: https://github.com/bohdantkachenko/waydriver/blob/main/docs/visual-locator.md Shows the debug representation of a VisualLocator, indicating its kind, text, match mode, region, and timeout. ```text VisualLocator { kind: "text-label", text: "Add account", match_mode: Substring, region: Some(Rect { ... }), timeout: None } ``` -------------------------------- ### Extend MCP Builder Image with DNF Source: https://github.com/bohdantkachenko/waydriver/blob/main/AGENTS.md Extend the default MCP builder image to include additional development dependencies, such as `libadwaita-devel`, using `dnf`. This is useful for C/C++ applications requiring specific libraries. ```dockerfile FROM ghcr.io/bohdantkachenko/waydriver-mcp-builder:latest RUN dnf install -y libadwaita-devel ``` -------------------------------- ### Clicking a Button by Text Source: https://github.com/bohdantkachenko/waydriver/blob/main/docs/visual-locator.md Locates a dialog, finds text within it, and clicks the centroid of the surrounding visual shape. This is efficient for elements not directly accessible via AT-SPI but rendered with text. ```rust let dialog = session.locate("//Dialog[@name='Preferences']"); let text = dialog.find_by_text("lazy-button").await?; dialog.last_region(&text).await?.click().await?; ``` -------------------------------- ### Load and Handle events.js Script Source: https://github.com/bohdantkachenko/waydriver/blob/main/crates/waydriver-mcp/src/viewer.html Dynamically loads 'events.js', removes the script on successful load, and displays an error message if loading fails. This script is generated alongside index.html. ```javascript ad() { const s = document.createElement('script'); s.src = 'events.js?v=' + Date.now(); s.onload = () => s.remove(); s.onerror = () => { s.remove(); document.getElementById('notice').innerHTML = '
Failed to load events.js
waydriver-mcp writes this file alongside index.html on every tool call. If the session directory was moved or only index.html was copied, reopen the full directory; otherwise the server may no longer be running.
'; }; document.body.appendChild(s); } ``` -------------------------------- ### Render a Single Waydriver Event Source: https://github.com/bohdantkachenko/waydriver/blob/main/crates/waydriver-mcp/src/viewer.html Constructs the HTML for a single Waydriver event, including action pills, status, parameters, message, and screenshot. Handles different event types and statuses. ```javascript function renderEvent(ev) { const pillClass = PILL_CLASS[ev.action] || 'bg-slate-100 text-slate-700'; const statusClass = ev.status === 'ok' ? 'bg-emerald-100 text-emerald-700' : 'bg-rose-100 text-rose-700'; const card = el('li', { class: 'bg-white rounded-lg border border-slate-200 shadow-sm p-4 flex gap-4' }); const left = el('div', { class: 'w-20 shrink-0 text-right' }); left.appendChild(el('div', { class: 'text-xs text-slate-400', text: '#' + ev.seq })); left.appendChild(el('div', { class: 'mono text-xs text-slate-600 mt-0.5', text: fmtTime(ev.ts_ms) })); card.appendChild(left); const body = el('div', { class: 'flex-1 min-w-0' }); const head = el('div', { class: 'flex items-center gap-2 flex-wrap' }); head.appendChild(el('span', { class: 'pill ' + pillClass, text: ev.action })); head.appendChild(el('span', { class: 'pill ' + statusClass, text: ev.status })); body.appendChild(head); const params = renderParams(ev.params); if (params) body.appendChild(params); const message = renderMessage(ev.message); if (message) body.appendChild(message); if (ev.screenshot) { const a = el('a', { href: ev.screenshot, target: '_blank', rel: 'noopener' }); a.appendChild(el('img', { src: ev.screenshot, loading: 'lazy', alt: 'screenshot', class: 'thumb' })); body.appendChild(a); } card.appendChild(body); return card; } ```