mirror of
https://github.com/lahfir/agent-desktop.git
synced 2026-07-31 11:19:16 +00:00
Settle the Playwright-grade reliability contract in agent-desktop-core before the Windows/Linux adapters are built, so they inherit it instead of redesigning it. Every command now observes, waits, verifies, and reports honestly instead of firing blindly. Highlights: capability-supertrait split of PlatformAdapter with not_supported() defaults; canonical role/state vocabulary with live `is --property visible`; display enumeration (`list-displays`) and honest `--screen` with scale factor; truthful Automation permission; `native_id` identity spine; window-id-first resolution; serializable `LocatorQuery` with live `find`; default-on auto-wait before every ref action; three-way `hit_test` occlusion gate; `scroll_into_view` in core; core accessible-name precedence; typed `ActionStep` delivery tier; `ProcessState` and `APP_UNRESPONSIVE`; `LaunchOptions`; baseline-diff desktop signals (`wait --event`); typed clipboard (`Text`/`Image`/`FileUrls`); mouse modifier chords and `mouse-wheel`. Hardened through a 35-reviewer pass with independent validation and a green live e2e gate (109/0), plus a head-vs-main performance comparison harness. BREAKING CHANGE: default-on auto-wait changes the timing of every previously-untouched ref-action call (bounded 5000 ms default; `--timeout-ms 0` restores single-shot). `ENVELOPE_VERSION` is now `2.1` (adds the `APP_UNRESPONSIVE` code and process state in error details). FFI ABI major is `3` (append-only struct evolution; `wait --event` is intentionally not exposed over FFI). The legacy string clipboard API is removed in favor of typed content. `key-down`/`key-up` fail closed until daemon-owned held input exists. `close-app` verifies termination and the osascript fallback path is removed. `--text` matching is subtree containment: `find --text X --first` returns the outermost matching container.
146 lines
5.6 KiB
Rust
146 lines
5.6 KiB
Rust
//! Verifies the committed C header is also a valid C++17 interface.
|
|
|
|
use std::path::PathBuf;
|
|
use std::process::Command;
|
|
|
|
fn system_cxx() -> Option<&'static str> {
|
|
["c++", "clang++", "g++"].into_iter().find(|compiler| {
|
|
Command::new(compiler)
|
|
.arg("--version")
|
|
.output()
|
|
.is_ok_and(|output| output.status.success())
|
|
})
|
|
}
|
|
|
|
fn header_include_dir() -> PathBuf {
|
|
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("include")
|
|
}
|
|
|
|
#[test]
|
|
fn committed_header_compiles_as_cpp17_with_portable_abi_types() {
|
|
let Some(cxx) = system_cxx() else {
|
|
eprintln!("skipping: system C++ compiler not found");
|
|
return;
|
|
};
|
|
|
|
let stem = format!("agent_desktop_header_cpp17_{}", std::process::id());
|
|
let tmp = std::env::temp_dir().join(format!("{stem}.cpp"));
|
|
let obj = std::env::temp_dir().join(format!("{stem}.o"));
|
|
let src = r#"
|
|
#include <cstdint>
|
|
#include <limits>
|
|
#include <type_traits>
|
|
#include "agent_desktop.h"
|
|
|
|
static void log_callback(std::int32_t level, const char *message) {
|
|
(void)level;
|
|
(void)message;
|
|
}
|
|
|
|
static_assert(std::is_enum_v<AdModifier>);
|
|
static_assert(std::is_same_v<std::underlying_type_t<AdModifier>, std::int32_t>);
|
|
static_assert(AD_MODIFIER_META == 0);
|
|
static_assert(AD_MODIFIER_CTRL == 1);
|
|
static_assert(AD_MODIFIER_ALT == 2);
|
|
static_assert(AD_MODIFIER_SHIFT == 3);
|
|
static_assert(AD_MODIFIER_CMD == AD_MODIFIER_META);
|
|
|
|
static_assert(std::is_enum_v<AdSnapshotSurface>);
|
|
static_assert(std::is_same_v<std::underlying_type_t<AdSnapshotSurface>, std::int32_t>);
|
|
static_assert(AD_SNAPSHOT_SURFACE_WINDOW == 0);
|
|
static_assert(AD_SNAPSHOT_SURFACE_FOCUSED == 1);
|
|
static_assert(AD_SNAPSHOT_SURFACE_MENU == 2);
|
|
static_assert(AD_SNAPSHOT_SURFACE_MENUBAR == 3);
|
|
static_assert(AD_SNAPSHOT_SURFACE_SHEET == 4);
|
|
static_assert(AD_SNAPSHOT_SURFACE_POPOVER == 5);
|
|
static_assert(AD_SNAPSHOT_SURFACE_ALERT == 6);
|
|
static_assert(AD_SNAPSHOT_SURFACE_DESKTOP == 7);
|
|
static_assert(AD_SNAPSHOT_SURFACE_TASKBAR == 8);
|
|
static_assert(AD_SNAPSHOT_SURFACE_SYSTEM_TRAY == 9);
|
|
static_assert(AD_SNAPSHOT_SURFACE_QUICK_SETTINGS == 10);
|
|
static_assert(AD_SNAPSHOT_SURFACE_NOTIFICATION_CENTER == 11);
|
|
static_assert(AD_SNAPSHOT_SURFACE_TOOLBAR == 12);
|
|
static_assert(AD_SNAPSHOT_SURFACE_DOCK == 13);
|
|
static_assert(AD_SNAPSHOT_SURFACE_SPOTLIGHT == 14);
|
|
static_assert(AD_SNAPSHOT_SURFACE_MENU_BAR_EXTRAS == 15);
|
|
static_assert(AD_SNAPSHOT_SURFACE_SYSTEM_TRAY_OVERFLOW == 16);
|
|
static_assert(AD_SNAPSHOT_SURFACE_START_MENU == 17);
|
|
static_assert(AD_SNAPSHOT_SURFACE_ACTION_CENTER == 18);
|
|
|
|
static_assert(AD_DELIVERY_DISPOSITION_UNKNOWN == 0);
|
|
static_assert(AD_DELIVERY_DISPOSITION_NOT_DELIVERED == 1);
|
|
static_assert(AD_DELIVERY_DISPOSITION_DELIVERY_UNCERTAIN == 2);
|
|
static_assert(AD_DELIVERY_DISPOSITION_DELIVERED_UNVERIFIED == 3);
|
|
static_assert(AD_DELIVERY_DISPOSITION_DELIVERED_VERIFIED == 4);
|
|
static_assert(AD_FIND_SELECTION_KIND_STRICT == 0);
|
|
static_assert(AD_FIND_SELECTION_KIND_FIRST == 1);
|
|
static_assert(AD_FIND_SELECTION_KIND_LAST == 2);
|
|
static_assert(AD_FIND_SELECTION_KIND_NTH == 3);
|
|
static_assert(AD_IDENTIFIER_KIND_AX_IDENTIFIER == 0);
|
|
static_assert(AD_IDENTIFIER_KIND_AX_DOM_IDENTIFIER == 1);
|
|
static_assert(AD_IDENTIFIER_KIND_AUTOMATION_ID == 2);
|
|
static_assert(AD_IDENTIFIER_KIND_RUNTIME_ID == 3);
|
|
static_assert(AD_IDENTIFIER_KIND_ATSPI_OBJECT_PATH == 4);
|
|
static_assert(AD_POLICY_KIND_HEADLESS == 0);
|
|
static_assert(AD_POLICY_KIND_FOCUS_FALLBACK == 1);
|
|
static_assert(AD_POLICY_KIND_HEADED == 2);
|
|
static_assert(AD_RETRY_DISPOSITION_UNKNOWN == 0);
|
|
static_assert(AD_RETRY_DISPOSITION_SAFE == 1);
|
|
static_assert(AD_RETRY_DISPOSITION_UNSAFE == 2);
|
|
static_assert(AD_STEP_MECHANISM_SEMANTIC_API == 1);
|
|
static_assert(AD_STEP_MECHANISM_PHYSICAL_SYNTHETIC == 2);
|
|
|
|
using AppPid = decltype(AdAppInfo{}.pid);
|
|
using WindowPid = decltype(AdWindowInfo{}.pid);
|
|
using RefPid = decltype(AdRefProcess{}.pid);
|
|
using ScreenshotPid = decltype(AdScreenshotTarget{}.pid);
|
|
static_assert(std::is_same_v<AppPid, std::uint32_t>);
|
|
static_assert(std::is_same_v<WindowPid, std::uint32_t>);
|
|
static_assert(std::is_same_v<RefPid, std::uint32_t>);
|
|
static_assert(std::is_same_v<ScreenshotPid, std::uint32_t>);
|
|
static_assert(std::numeric_limits<AppPid>::max() == UINT32_MAX);
|
|
|
|
using ListSurfacesFn = AdResult (*)(const AdAdapter *, std::uint32_t, AdSurfaceList **);
|
|
using ListExactSurfacesFn = AdResult (*)(const AdAdapter *, std::uint32_t, AdExactSurfaceList **);
|
|
using ListDisplaysFn = AdResult (*)(const AdAdapter *, AdDisplayList **);
|
|
static_assert(std::is_same_v<decltype(&ad_list_surfaces), ListSurfacesFn>);
|
|
static_assert(std::is_same_v<decltype(&ad_list_surfaces_exact), ListExactSurfacesFn>);
|
|
static_assert(std::is_same_v<decltype(&ad_list_displays), ListDisplaysFn>);
|
|
static_assert(sizeof(AdDisplayInfo) == AD_DISPLAY_INFO_SIZE);
|
|
static_assert(offsetof(AdDisplayInfo, id) == 8);
|
|
static_assert(offsetof(AdDisplayInfo, scale) == 56);
|
|
|
|
int main() {
|
|
const auto callback_result = ad_set_log_callback(log_callback);
|
|
const auto clear_callback_result = ad_set_log_callback(nullptr);
|
|
(void)callback_result;
|
|
(void)clear_callback_result;
|
|
return 0;
|
|
}
|
|
"#;
|
|
std::fs::write(&tmp, src).expect("write C++17 test translation unit");
|
|
|
|
let output = Command::new(cxx)
|
|
.arg("-std=c++17")
|
|
.arg("-pedantic-errors")
|
|
.arg("-Wall")
|
|
.arg("-Wextra")
|
|
.arg("-Werror")
|
|
.arg("-I")
|
|
.arg(header_include_dir())
|
|
.arg("-c")
|
|
.arg(&tmp)
|
|
.arg("-o")
|
|
.arg(&obj)
|
|
.output()
|
|
.expect("C++ compiler invocation failed");
|
|
|
|
let _ = std::fs::remove_file(&tmp);
|
|
let _ = std::fs::remove_file(&obj);
|
|
|
|
assert!(
|
|
output.status.success(),
|
|
"C++17 compile of agent_desktop.h failed:\n{}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
}
|