From beda5149d9c99e0178058d7caa96a04c2244d347 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Fri, 7 Aug 2026 23:05:23 -0500 Subject: [PATCH] test: pin read_window_below into the toolset + post-hook contracts, appease eslint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The desktop_ui and post-hook ownership contract tests enumerate their tool sets exactly — add read_window_below to both (plus the executor-path parametrize case). Lint: sorted type import, explicit GetWindowsModule type instead of an import() annotation, curly + blank-line style. --- apps/desktop/electron/main.ts | 1 + apps/desktop/electron/window-below.test.ts | 8 +++++++- apps/desktop/electron/window-below.ts | 20 +++++++++++++++++-- tests/run_agent/test_run_agent.py | 5 +++++ .../tui_gateway/test_gui_surface_toolsets.py | 1 + 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/apps/desktop/electron/main.ts b/apps/desktop/electron/main.ts index 7aa17d8f9ad9d..2d2943dbfc8c6 100644 --- a/apps/desktop/electron/main.ts +++ b/apps/desktop/electron/main.ts @@ -10354,6 +10354,7 @@ ipcMain.handle('hermes:window:readBelow', async event => { const titlesAvailable = IS_MAC ? systemPreferences.getMediaAccessStatus?.('screen') === 'granted' : true + const [x, y] = win.getPosition() const [width, height] = win.getSize() diff --git a/apps/desktop/electron/window-below.test.ts b/apps/desktop/electron/window-below.test.ts index 3f0ce33e3f7d9..e07d1a6522a63 100644 --- a/apps/desktop/electron/window-below.test.ts +++ b/apps/desktop/electron/window-below.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest' -import { pickWindowBelow, type EnumeratedWindow } from './window-below' +import { type EnumeratedWindow, pickWindowBelow } from './window-below' const win = ( pid: number, @@ -24,6 +24,7 @@ describe('pickWindowBelow', () => { it('picks the first overlapping window behind ours in z-order', () => { const chrome = win(1, 120, 120) const spotify = win(2, 130, 130) + const { below, frontmost } = pickWindowBelow( [win(SELF_PID, 100, 100), chrome, spotify], SELF_PID, @@ -37,6 +38,7 @@ describe('pickWindowBelow', () => { it('skips windows behind ours that do not overlap', () => { const elsewhere = win(1, 5000, 5000) const covered = win(2, 200, 200) + const { below } = pickWindowBelow( [win(SELF_PID, 100, 100), elsewhere, covered], SELF_PID, @@ -49,6 +51,7 @@ describe('pickWindowBelow', () => { it('skips our own other windows (same pid) while walking down', () => { const secondHermesWindow = win(SELF_PID, 150, 150) const target = win(7, 160, 160) + const { below } = pickWindowBelow( [win(SELF_PID, 100, 100), secondHermesWindow, target], SELF_PID, @@ -60,6 +63,7 @@ describe('pickWindowBelow', () => { it('reports frontmost even when nothing overlaps', () => { const elsewhere = win(1, 5000, 5000) + const { below, frontmost } = pickWindowBelow( [win(SELF_PID, 100, 100), elsewhere], SELF_PID, @@ -73,6 +77,7 @@ describe('pickWindowBelow', () => { it('windows in front of ours are never "below", even overlapping', () => { const inFront = win(3, 110, 110) const behind = win(4, 120, 120) + const { below, frontmost } = pickWindowBelow( [inFront, win(SELF_PID, 100, 100), behind], SELF_PID, @@ -100,6 +105,7 @@ describe('pickWindowBelow', () => { it('edge-adjacent bounds do not count as overlap', () => { const adjacent = win(1, 900, 100) // starts exactly at our right edge + const { below } = pickWindowBelow( [win(SELF_PID, 100, 100), adjacent], SELF_PID, diff --git a/apps/desktop/electron/window-below.ts b/apps/desktop/electron/window-below.ts index 648895d86532f..4026b75e32f1f 100644 --- a/apps/desktop/electron/window-below.ts +++ b/apps/desktop/electron/window-below.ts @@ -61,12 +61,25 @@ export function pickWindowBelow( return { below, frontmost } } -type GetWindowsModule = typeof import('get-windows') +type GetWindowsModule = { + openWindows: (options?: { + accessibilityPermission?: boolean + screenRecordingPermission?: boolean + }) => Promise< + Array<{ + bounds?: { height?: number; width?: number; x?: number; y?: number } + id?: number + owner?: { name?: string; processId?: number } + title?: string + }> + > +} let getWindowsModule: Promise | null = null const loadGetWindows = (): Promise => { getWindowsModule ??= import('get-windows') + return getWindowsModule } @@ -84,6 +97,7 @@ export async function readWindowBelow( titlesAvailable: boolean ): Promise { let raw + try { const { openWindows } = await loadGetWindows() raw = await openWindows( @@ -95,7 +109,9 @@ export async function readWindowBelow( return null } - if (!Array.isArray(raw)) return null + if (!Array.isArray(raw)) { + return null + } // get-windows documents openWindows() as front-to-back, and macOS/Windows // honor that (CGWindowList / EnumWindows order). Its lib/linux.js, however, diff --git a/tests/run_agent/test_run_agent.py b/tests/run_agent/test_run_agent.py index 5ef8e1c1c8017..222ba26ca6e58 100644 --- a/tests/run_agent/test_run_agent.py +++ b/tests/run_agent/test_run_agent.py @@ -2284,6 +2284,7 @@ class TestAgentRuntimePostHookOwnershipSync: ("clarify", {"question": "Continue?"}), ("read_terminal", {}), ("read_preview", {}), + ("read_window_below", {}), ("delegate_task", {"goal": "Check the child path"}), ) @@ -2327,6 +2328,10 @@ class TestAgentRuntimePostHookOwnershipSync: "tools.read_preview_tool.read_preview_tool", lambda **kwargs: '{"ok":true}', ) + monkeypatch.setattr( + "tools.read_window_tool.read_window_below_tool", + lambda **kwargs: '{"ok":true}', + ) monkeypatch.setattr(agent, "_get_session_db_for_recall", lambda: None) monkeypatch.setattr( agent, diff --git a/tests/tui_gateway/test_gui_surface_toolsets.py b/tests/tui_gateway/test_gui_surface_toolsets.py index 14e76011183ae..13263bbab5642 100644 --- a/tests/tui_gateway/test_gui_surface_toolsets.py +++ b/tests/tui_gateway/test_gui_surface_toolsets.py @@ -23,6 +23,7 @@ GUI_TOOLS = { "open_preview", "read_preview", "read_terminal", + "read_window_below", "react_to_message", }