From 854a96e88046ceeb4565aa9b0448aec76f71401f Mon Sep 17 00:00:00 2001 From: Alessandro <155005371+3clyp50@users.noreply.github.com> Date: Sun, 10 May 2026 00:07:04 +0200 Subject: [PATCH] Treat bare desktop canvas as ready Allow the Linux Desktop state collector to report a healthy canvas when XFCE has no active application window, as long as the display, visible windows, and screenshots are available. Document the readiness rule in the linux-desktop skill and add regression coverage for the bare-desktop active_window=null case. --- plugins/_desktop/helpers/desktop_state.py | 1 - .../_desktop/skills/linux-desktop/SKILL.md | 2 + tests/test_office_desktop_state.py | 55 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/plugins/_desktop/helpers/desktop_state.py b/plugins/_desktop/helpers/desktop_state.py index bceb938f2..10225bbca 100644 --- a/plugins/_desktop/helpers/desktop_state.py +++ b/plugins/_desktop/helpers/desktop_state.py @@ -372,7 +372,6 @@ def collect_active_window(env: dict[str, str], capabilities: dict[str, str], err return None result = run([capabilities["xdotool"], "getactivewindow"], env=env, timeout=3) if result.returncode != 0: - errors.append(command_output(result) or "xdotool could not read the active window.") return None window_id = result.stdout.strip().splitlines()[0] if result.stdout.strip() else "" if not window_id: diff --git a/plugins/_desktop/skills/linux-desktop/SKILL.md b/plugins/_desktop/skills/linux-desktop/SKILL.md index 526c65d8a..6b4717cba 100644 --- a/plugins/_desktop/skills/linux-desktop/SKILL.md +++ b/plugins/_desktop/skills/linux-desktop/SKILL.md @@ -60,6 +60,8 @@ $DESKTOP key ctrl+s The script targets the persistent `agent-zero-desktop` X display, sets `DISPLAY`, `XAUTHORITY`, and `HOME` to the XFCE profile, then uses `xdotool` for input. Startup normally prepares this session. If `check` fails during explicit Desktop work, report that the Desktop runtime is not ready instead of installing packages ad hoc. +If `observe --json --screenshot` shows a reachable display, visible Desktop/window entries, and a fresh screenshot, the Desktop is usable even when `active_window` is `null`; a bare XFCE desktop can have no active application window. Treat missing screenshots, missing display, or unavailable `xdotool`/`xwd` as blockers and stop with the specific readiness message instead of repeating clicks or inventing a fallback. + For direct app launches without coordinates: ```bash diff --git a/tests/test_office_desktop_state.py b/tests/test_office_desktop_state.py index 482f54d51..b9139a227 100644 --- a/tests/test_office_desktop_state.py +++ b/tests/test_office_desktop_state.py @@ -92,6 +92,61 @@ def test_desktop_state_collects_x11_state_from_mocked_tools(tmp_path, monkeypatc assert [window["title"] for window in state["windows"]] == ["LibreOffice Calc", "Terminal"] +def test_desktop_state_allows_missing_active_window_when_display_is_reachable(tmp_path, monkeypatch): + session_dir = tmp_path / "sessions" + profile_dir = tmp_path / "profiles" / desktop_state.SESSION_ID + session_dir.mkdir(parents=True) + profile_dir.mkdir(parents=True) + (session_dir / f"{desktop_state.SESSION_ID}.json").write_text( + '{"display": 120, "profile_dir": "%s"}' % profile_dir, + encoding="utf-8", + ) + + monkeypatch.setattr(desktop_state, "SESSION_DIR", session_dir) + monkeypatch.setattr(desktop_state, "PROFILE_DIR", tmp_path / "profiles") + monkeypatch.setattr(desktop_state.shutil, "which", lambda name: f"/usr/bin/{name}") + + def fake_run(command, **kwargs): + del kwargs + name = Path(command[0]).name + if name == "xrandr": + return _completed(command, stdout="Screen 0: current 543 x 792, maximum 1920 x 1080\n") + if name == "xdotool" and command[1:3] == ["getmouselocation", "--shell"]: + return _completed(command, stdout="X=43\nY=244\nSCREEN=0\nWINDOW=18874412\n") + if name == "xdotool" and command[1] == "getactivewindow": + return _completed( + command, + returncode=1, + stderr="XGetWindowProperty[_NET_ACTIVE_WINDOW] failed (code=1)\n", + ) + if name == "xdotool" and command[1] == "search": + return _completed(command, stdout="18874412\n") + if name == "xdotool" and command[1] == "getwindowname": + return _completed(command, stdout="Desktop\n") + if name == "xwininfo": + return _completed( + command, + stdout=( + " Absolute upper-left X: 0\n" + " Absolute upper-left Y: 0\n" + " Width: 543\n" + " Height: 792\n" + ), + ) + if name == "xprop": + return _completed(command, stdout='WM_CLASS(STRING) = "xfdesktop", "Xfdesktop"\n') + raise AssertionError(f"unexpected command: {command}") + + monkeypatch.setattr(desktop_state.subprocess, "run", fake_run) + + state = desktop_state.collect_state() + + assert state["ok"] is True + assert state["active_window"] is None + assert state["errors"] == [] + assert [window["title"] for window in state["windows"]] == ["Desktop"] + + def test_desktop_state_screenshot_capture_uses_xwd_and_pillow_when_available(tmp_path, monkeypatch): monkeypatch.setattr(desktop_state, "SCREENSHOT_DIR", tmp_path) capabilities = {"xwd": "/usr/bin/xwd"}