diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a1c44e27..1b7de756 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -109,7 +109,7 @@ jobs: uses: erlef/setup-beam@v1 with: otp-version: 26.2.1 - elixir-version: 1.15.7 + elixir-version: 1.16.3 - name: Cache Mix uses: actions/cache@v5 diff --git a/client/package.json b/client/package.json index eafebb94..dccd3d4b 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "my-project", - "version": "0.1.37", + "version": "0.1.38", "private": true, "scripts": { "dev": "vite --host 0.0.0.0 --port 3000", diff --git a/client/src-tauri/Cargo.lock b/client/src-tauri/Cargo.lock index ec70ccdf..51776231 100644 --- a/client/src-tauri/Cargo.lock +++ b/client/src-tauri/Cargo.lock @@ -11839,7 +11839,7 @@ dependencies = [ [[package]] name = "xero-cli" -version = "0.1.37" +version = "0.1.38" dependencies = [ "crossterm", "flate2", @@ -11860,7 +11860,7 @@ dependencies = [ [[package]] name = "xero-desktop" -version = "0.1.37" +version = "0.1.38" dependencies = [ "arc-swap", "arrow-array", diff --git a/client/src-tauri/Cargo.toml b/client/src-tauri/Cargo.toml index 792a41c4..536dede4 100644 --- a/client/src-tauri/Cargo.toml +++ b/client/src-tauri/Cargo.toml @@ -12,7 +12,7 @@ resolver = "2" [package] name = "xero-desktop" -version = "0.1.37" +version = "0.1.38" edition = "2021" default-run = "xero-desktop" description = "Xero desktop host" diff --git a/client/src-tauri/build.rs b/client/src-tauri/build.rs index 2ea64a7d..4021d2e3 100644 --- a/client/src-tauri/build.rs +++ b/client/src-tauri/build.rs @@ -82,9 +82,6 @@ fn compile_dictation_shim() { println!("cargo:rustc-link-lib=framework=Security"); if std::env::var_os("XERO_SKIP_DICTATION_SHIM").is_some() { - println!( - "cargo:warning=XERO_SKIP_DICTATION_SHIM is set; dictation status will report the native shim unavailable." - ); return; } @@ -200,9 +197,6 @@ fn compile_ios_helper() { println!("cargo:rerun-if-env-changed=XERO_SKIP_IOS_HELPER"); if std::env::var_os("XERO_SKIP_IOS_HELPER").is_some() { - println!( - "cargo:warning=XERO_SKIP_IOS_HELPER is set; iOS helper binary will not be compiled." - ); return; } diff --git a/client/src-tauri/crates/xero-cli/Cargo.toml b/client/src-tauri/crates/xero-cli/Cargo.toml index 00a60f57..290a8ad8 100644 --- a/client/src-tauri/crates/xero-cli/Cargo.toml +++ b/client/src-tauri/crates/xero-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xero-cli" -version = "0.1.37" +version = "0.1.38" edition = "2021" description = "Headless Xero CLI backed by xero-agent-core" diff --git a/client/src-tauri/crates/xero-desktop-sidecar/src/main.rs b/client/src-tauri/crates/xero-desktop-sidecar/src/main.rs index caaf0fd6..9a27e0e6 100644 --- a/client/src-tauri/crates/xero-desktop-sidecar/src/main.rs +++ b/client/src-tauri/crates/xero-desktop-sidecar/src/main.rs @@ -2,8 +2,8 @@ use std::{ collections::BTreeMap, fs, io::{self, BufRead, Cursor, Write}, - path::{Path, PathBuf}, - process::{self, Command}, + path::Path, + process, sync::{ atomic::{AtomicBool, AtomicI64, AtomicU64, Ordering}, Arc, Mutex, OnceLock, @@ -11,18 +11,24 @@ use std::{ time::{Duration, Instant}, }; +#[cfg(target_os = "macos")] +use std::path::PathBuf; +#[cfg(any(target_os = "macos", target_os = "windows"))] +use std::process::Command; + use base64::Engine as _; use image::{ImageFormat, RgbaImage}; use serde::Deserialize; use serde_json::json; use time::format_description::well_known::Rfc3339; +#[cfg(any(test, target_os = "macos", target_os = "windows"))] +use webrtc::media::Sample; use webrtc::{ api::{ media_engine::{MediaEngine, MIME_TYPE_H264}, APIBuilder, }, ice_transport::{ice_candidate::RTCIceCandidateInit, ice_server::RTCIceServer}, - media::Sample, peer_connection::{ configuration::RTCConfiguration, sdp::session_description::RTCSessionDescription, RTCPeerConnection, @@ -38,10 +44,11 @@ use webrtc::{ use xcap::{Monitor, Window}; #[cfg(target_os = "windows")] use xero_desktop_control_ipc::DesktopSidecarNotificationEntry; +#[cfg(any(target_os = "macos", target_os = "windows"))] +use xero_desktop_control_ipc::DesktopSidecarOcrTextBlock; use xero_desktop_control_ipc::{ - validate_sidecar_handshake, validate_sidecar_request, DesktopSidecarAccessibilityElement, + validate_sidecar_handshake, validate_sidecar_request, DesktopSidecarAccessibilitySnapshotPayload, DesktopSidecarAccessibilitySnapshotRequest, - DesktopSidecarAccessibilitySnapshotRow, DesktopSidecarAccessibilitySnapshotTarget, DesktopSidecarApp, DesktopSidecarAppInventoryEntry, DesktopSidecarAppInventoryPayload, DesktopSidecarAppListPayload, DesktopSidecarCapabilities, DesktopSidecarClipboardFilesPayload, DesktopSidecarClipboardHtmlPayload, DesktopSidecarClipboardImagePayload, @@ -51,14 +58,19 @@ use xero_desktop_control_ipc::{ DesktopSidecarDisplayListPayload, DesktopSidecarElementAtPointPayload, DesktopSidecarErrorBody, DesktopSidecarForegroundStatePayload, DesktopSidecarHandshake, DesktopSidecarLease, DesktopSidecarNotificationSnapshotPayload, DesktopSidecarOcrSnapshotPayload, - DesktopSidecarOcrSnapshotRequest, DesktopSidecarOcrTextBlock, DesktopSidecarOperation, - DesktopSidecarPermissionGrant, DesktopSidecarPermissionStatus, - DesktopSidecarPermissionsPayload, DesktopSidecarPointRequest, DesktopSidecarRequest, - DesktopSidecarResponse, DesktopSidecarScreenshotPayload, DesktopSidecarScreenshotRequest, - DesktopSidecarSessionDescription, DesktopSidecarStreamCapabilitiesPayload, - DesktopSidecarStreamMetrics, DesktopSidecarStreamPayload, DesktopSidecarStreamQuality, - DesktopSidecarStreamRequest, DesktopSidecarStreamStatus, DesktopSidecarStreamTransport, - DesktopSidecarWindow, DesktopSidecarWindowListPayload, + DesktopSidecarOcrSnapshotRequest, DesktopSidecarOperation, DesktopSidecarPermissionGrant, + DesktopSidecarPermissionStatus, DesktopSidecarPermissionsPayload, DesktopSidecarPointRequest, + DesktopSidecarRequest, DesktopSidecarResponse, DesktopSidecarScreenshotPayload, + DesktopSidecarScreenshotRequest, DesktopSidecarSessionDescription, + DesktopSidecarStreamCapabilitiesPayload, DesktopSidecarStreamMetrics, + DesktopSidecarStreamPayload, DesktopSidecarStreamQuality, DesktopSidecarStreamRequest, + DesktopSidecarStreamStatus, DesktopSidecarStreamTransport, DesktopSidecarWindow, + DesktopSidecarWindowListPayload, +}; +#[cfg(target_os = "macos")] +use xero_desktop_control_ipc::{ + DesktopSidecarAccessibilityElement, DesktopSidecarAccessibilitySnapshotRow, + DesktopSidecarAccessibilitySnapshotTarget, }; const WEBRTC_MAX_WIDTH: u32 = 1920; @@ -8440,6 +8452,7 @@ mod cross_platform_input { "volumeup" | "volume_up" | "audio_volume_up" => Ok(Key::VolumeUp), "volumedown" | "volume_down" | "audio_volume_down" => Ok(Key::VolumeDown), "volumemute" | "volume_mute" | "mute" | "audio_mute" => Ok(Key::VolumeMute), + #[cfg(all(unix, not(target_os = "macos")))] "micmute" | "mic_mute" => Ok(Key::MicMute), "mediaplaypause" | "media_play_pause" | "playpause" | "play_pause" => { Ok(Key::MediaPlayPause) @@ -8450,12 +8463,6 @@ mod cross_platform_input { "mediaprevious" | "media_previous" | "media_prev" | "media_prev_track" | "previous_track" | "prev_track" => Ok(Key::MediaPrevTrack), "mediastop" | "media_stop" => Ok(Key::MediaStop), - "mediafast" | "media_fast" | "media_fast_forward" | "fast_forward" => { - Ok(Key::MediaFast) - } - "mediarewind" | "media_rewind" | "rewind" => Ok(Key::MediaRewind), - "brightnessup" | "brightness_up" => Ok(Key::BrightnessUp), - "brightnessdown" | "brightness_down" => Ok(Key::BrightnessDown), "shift" => Ok(Key::Shift), "ctrl" | "control" => Ok(Key::Control), "alt" | "option" => Ok(Key::Alt), @@ -8494,6 +8501,36 @@ mod cross_platform_input { assert_eq!(key_for("v").expect("v"), Key::Unicode('v')); } + #[test] + fn key_mapper_rejects_macos_only_keys() { + for key in [ + "media_fast_forward", + "media_rewind", + "brightness_up", + "brightness_down", + ] { + assert_eq!( + key_for(key).expect_err("macOS-only key").code, + "desktop_key_unsupported" + ); + } + } + + #[cfg(target_os = "windows")] + #[test] + fn key_mapper_rejects_linux_only_keys_on_windows() { + assert_eq!( + key_for("mic_mute").expect_err("Linux-only key").code, + "desktop_key_unsupported" + ); + } + + #[cfg(all(unix, not(target_os = "macos")))] + #[test] + fn key_mapper_accepts_linux_mic_mute_key() { + assert_eq!(key_for("mic_mute").expect("mic mute"), Key::MicMute); + } + #[test] fn wheel_pixels_convert_to_bounded_scroll_units() { assert_eq!(scroll_units(80), 1); diff --git a/client/src-tauri/src/runtime/autonomous_tool_runtime/macos_automation.rs b/client/src-tauri/src/runtime/autonomous_tool_runtime/macos_automation.rs index abb21275..efc4502d 100644 --- a/client/src-tauri/src/runtime/autonomous_tool_runtime/macos_automation.rs +++ b/client/src-tauri/src/runtime/autonomous_tool_runtime/macos_automation.rs @@ -259,6 +259,7 @@ fn macos_action_label(action: AutonomousMacosAutomationAction) -> &'static str { } } +#[cfg(any(target_os = "macos", test))] fn resolve_monitor_index( monitor_ids: &[Option], primary_flags: &[bool], @@ -291,6 +292,7 @@ fn resolve_monitor_index( .or(Some(0)) } +#[cfg(any(target_os = "macos", test))] fn monitor_not_found_message(requested_monitor: u32, monitor_ids: &[Option]) -> String { let available = monitor_ids .iter() diff --git a/client/src-tauri/tauri.conf.json b/client/src-tauri/tauri.conf.json index 45bacca6..c0589b46 100644 --- a/client/src-tauri/tauri.conf.json +++ b/client/src-tauri/tauri.conf.json @@ -2,7 +2,7 @@ "$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "productName": "Xero", "mainBinaryName": "xero-desktop", - "version": "0.1.37", + "version": "0.1.38", "identifier": "com.hyperpush.xero", "build": { "beforeDevCommand": "pnpm dev", diff --git a/server/mix.exs b/server/mix.exs index 970357c4..2bb19429 100644 --- a/server/mix.exs +++ b/server/mix.exs @@ -5,7 +5,7 @@ defmodule Xero.MixProject do [ app: :xero, version: "0.1.0", - elixir: "~> 1.15", + elixir: "~> 1.16", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, aliases: aliases(),