Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T03:53:00Z
norm: '1'
sig: 9cb6c3e49e9e89a4
body_hash: 3841b3ec6afb2924
raw_hash: df11d5a8cf5c0636
vouched: 2026-10-20T13:08:22Z
body_hash: 3341f836eb7b413b
raw_hash: c1f9af46cfeac4e0
vouched: 2026-11-12T19:43:59Z
lines: 1-286
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-11-02T16:12:36Z
norm: '1'
sig: 9cb6c3e49e9e89a4
body_hash: 9d9ffaccaeee4733
raw_hash: e23bc0e0a622ec5d
body_hash: d24fe84faca71ef1
raw_hash: 285317310b611c97
vouched: 2026-11-12T19:43:59Z
lines: 1-308
supersedes: 01M5BKJWVVGTA2MXXFH8WD7ADT
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-10-20T12:41:15Z
norm: '1'
sig: 9cb6c3e49e9e89a4
body_hash: 8a9ea0714973a82a
raw_hash: 74a0e29a25be2c3a
body_hash: 834a3cc77b499908
raw_hash: 0a8adc11be29a95e
vouched: 2026-11-12T19:43:59Z
lines: 1-133
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-11-02T18:28:23Z
norm: '1'
sig: 9cb6c3e49e9e89a4
body_hash: 1a1907423feee250
raw_hash: 9b656a63ea16121d
body_hash: 834a3cc77b499908
raw_hash: 0a8adc11be29a95e
vouched: 2026-11-12T19:43:59Z
lines: 1-169
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T04:25:55Z
norm: '1'
sig: 9cb6c3e49e9e89a4
body_hash: d7ab3a923729569f
raw_hash: 490623e9c71688bc
vouched: 2026-10-24T23:36:33Z
body_hash: d98f3ea8385575ae
raw_hash: 0204b97245343640
vouched: 2026-11-12T19:43:59Z
lines: 1-831
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T03:22:18Z
norm: '1'
sig: 0fd09e8458d728cc
body_hash: 3b0abb299ffcfe0b
raw_hash: 62455994b90c7cfa
vouched: 2026-10-20T12:05:54Z
body_hash: 78bc32d6c8786781
raw_hash: b9160a43193908ae
vouched: 2026-11-12T19:43:59Z
lines: 1-131
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T03:03:37Z
norm: '1'
sig: 0fd09e8458d728cc
body_hash: 18d014746c1f0441
raw_hash: d33974560c2d7845
vouched: 2026-10-20T11:31:44Z
body_hash: 76d7ebe225d14687
raw_hash: 271356e3bc645c7b
vouched: 2026-11-12T19:43:59Z
lines: 1-646
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T04:47:35Z
norm: '1'
sig: 0fd09e8458d728cc
body_hash: 18d014746c1f0441
raw_hash: d33974560c2d7845
vouched: 2026-10-20T11:31:44Z
body_hash: 76d7ebe225d14687
raw_hash: 271356e3bc645c7b
vouched: 2026-11-12T19:43:59Z
lines: 1-646
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T05:09:14Z
norm: '1'
sig: 0fd09e8458d728cc
body_hash: 18d014746c1f0441
raw_hash: d33974560c2d7845
vouched: 2026-10-20T11:31:44Z
body_hash: 76d7ebe225d14687
raw_hash: 271356e3bc645c7b
vouched: 2026-11-12T19:43:59Z
lines: 1-646
supersedes: 01M5BPTDK4VCACPY2GS3CRBSTF
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-10-20T13:07:54Z
norm: '1'
sig: 27abcba5e975f16e
body_hash: 32e37c9908746f04
raw_hash: a3a043dc83705494
body_hash: 156e41d5cd6594ec
raw_hash: 76d0ecf4f3fe0413
vouched: 2026-11-12T19:43:59Z
lines: 1-164
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-11-03T01:17:06Z
norm: '1'
sig: 27abcba5e975f16e
body_hash: b6118ea4420e4b5c
raw_hash: 6a1f1910291f43cd
body_hash: 156e41d5cd6594ec
raw_hash: 76d0ecf4f3fe0413
vouched: 2026-11-12T19:43:59Z
lines: 1-171
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-10-20T13:07:55Z
norm: '1'
sig: 27abcba5e975f16e
body_hash: e326dd2d74b29cdb
raw_hash: 912c5d321737d476
body_hash: c618a4c2409e17b6
raw_hash: f26d1ad337533364
vouched: 2026-11-12T19:43:59Z
lines: 1-846
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-11-02T18:28:23Z
norm: '1'
sig: 1574ff353918c008
body_hash: 0eeeb80ab28ee018
raw_hash: 311343ab0a3723b4
body_hash: 937d6a95b016e8c7
raw_hash: 5bbca8fb1b1434d4
vouched: 2026-11-12T19:43:59Z
lines: 1-526
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T03:09:47Z
norm: '1'
sig: 27abcba5e975f16e
body_hash: 22b623691bf046c2
raw_hash: c51598ff808c374f
vouched: 2026-11-02T16:12:35Z
body_hash: 9e26e542c95e910f
raw_hash: b496f2c41bd71769
vouched: 2026-11-12T19:43:59Z
lines: 1-373
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T03:09:47Z
norm: '1'
sig: 27abcba5e975f16e
body_hash: 22b623691bf046c2
raw_hash: c51598ff808c374f
vouched: 2026-11-02T16:12:35Z
body_hash: 9e26e542c95e910f
raw_hash: b496f2c41bd71769
vouched: 2026-11-12T19:43:59Z
lines: 1-373
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T03:00:42Z
norm: '1'
sig: 27abcba5e975f16e
body_hash: 99f766697f5cf49a
raw_hash: 2e2cf668fd7553e6
vouched: 2026-11-03T02:45:55Z
body_hash: 80bd99e2dbc88f58
raw_hash: 3d0594b030addc3a
vouched: 2026-11-12T19:43:59Z
lines: 1-360
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T05:17:02Z
norm: '1'
sig: 27abcba5e975f16e
body_hash: 99f766697f5cf49a
raw_hash: 2e2cf668fd7553e6
vouched: 2026-11-03T02:45:55Z
body_hash: 80bd99e2dbc88f58
raw_hash: 3d0594b030addc3a
vouched: 2026-11-12T19:43:59Z
lines: 1-360
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-11-03T01:40:11Z
norm: '1'
sig: 27abcba5e975f16e
body_hash: 99f766697f5cf49a
raw_hash: 2e2cf668fd7553e6
vouched: 2026-11-03T02:45:55Z
body_hash: 80bd99e2dbc88f58
raw_hash: 3d0594b030addc3a
vouched: 2026-11-12T19:44:00Z
lines: 1-560
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-11-03T01:42:00Z
norm: '1'
sig: 27abcba5e975f16e
body_hash: 99f766697f5cf49a
raw_hash: 2e2cf668fd7553e6
vouched: 2026-11-03T02:45:55Z
body_hash: 80bd99e2dbc88f58
raw_hash: 3d0594b030addc3a
vouched: 2026-11-12T19:44:00Z
lines: 1-560
supersedes: 01M6ERHPXM4ZVJSQWDFV4GWZBF
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-11-02T18:28:23Z
norm: '1'
sig: 27abcba5e975f16e
body_hash: 4a1a6138d04e81d2
raw_hash: 9e7decda7e8dffa8
body_hash: 8adb37cdd2e8385a
raw_hash: 03c72e9fbe8856b7
vouched: 2026-11-12T19:44:00Z
lines: 1-152
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-10-20T17:21:33Z
norm: '1'
sig: 1574ff353918c008
body_hash: 6243d6c3b242a4db
raw_hash: 5bd16c78dfed21ca
vouched: 2026-10-20T17:37:48Z
body_hash: e241e3e0cd80128c
raw_hash: b52824f29bc8ce91
vouched: 2026-11-12T19:44:00Z
lines: 1-182
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-10-20T17:37:38Z
norm: '1'
sig: 1574ff353918c008
body_hash: 6243d6c3b242a4db
raw_hash: 5bd16c78dfed21ca
body_hash: e241e3e0cd80128c
raw_hash: b52824f29bc8ce91
vouched: 2026-11-12T19:44:00Z
lines: 1-191
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-10-20T05:17:02Z
norm: '1'
sig: b318dcdf7403555b
body_hash: 036cca83f9058e03
raw_hash: 7e61420b94593d3e
body_hash: 04b32048b59b385f
raw_hash: e618ddbc1c9a2085
vouched: 2026-11-12T19:44:00Z
lines: 1-339
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ anchor: '@file'
created: 2026-11-02T16:12:36Z
norm: '1'
sig: 021fb596db81e6d0
body_hash: b0d0a93ad9fd4411
raw_hash: aba6b363e3981de3
body_hash: 53e61ffa87279904
raw_hash: 80d654e5bdd9cffa
vouched: 2026-11-12T19:44:00Z
lines: 1-30
supersedes: 01M5R48RRWQMVESK6RVKFWF174
---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ anchor: '@file'
created: 2026-11-02T16:12:36Z
norm: '1'
sig: 78473a106add9cfc
body_hash: 20a6956cc14ca9d2
raw_hash: 0fb3a60c49e77ca1
vouched: 2026-11-03T02:45:55Z
body_hash: dee2458bb266d140
raw_hash: 38e6dd2a0a1ad4b4
vouched: 2026-11-12T19:44:00Z
lines: 1-980
supersedes: 01M5D682W73BEYBRAPTSK672XW
---
Expand Down
2 changes: 1 addition & 1 deletion dist/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ export function desktopTools({ place, app }) {
{
name: "desktop_windows",
op: "windows",
description: `List one app's windows by pid, with the target that window tools take. Read-only. Each row's availability gives state (available, limited or unavailable), a reason (minimized, app_hidden, other_space, off_screen, session_locked, display_asleep, accessibility_unavailable…) and a hint naming the tool that recovers it; check it before acting, since nothing recovers automatically. Rows also carry space_ids, and display_index off the main display. Untitled windows off screen and on no Space, such as menu bar strips, are only counted in hidden_windows; all true lists them.`,
description: `List one app's windows by pid, with the target that window tools take. Read-only. Each row's availability gives state (available, limited or unavailable), a reason (minimized, app_hidden, other_space, off_screen, session_locked, display_asleep, accessibility_unavailable, attached_sheet…) and a hint naming the tool that recovers it; a sheet or alert is listed as a window of its own but is inspected, clicked and answered through the window it is attached to (sheet_of_window_id); check it before acting, since nothing recovers automatically. Rows also carry space_ids, and display_index off the main display. Untitled windows off screen and on no Space, such as menu bar strips, are only counted in hidden_windows; all true lists them.`,
parameters: {
type: "object",
required: ["pid"],
Expand Down
6 changes: 6 additions & 0 deletions native2/Sources/DesktopCore/Availability.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ public func windowAvailability(_ window: JSON, sessionLocked: Bool, appHidden: B
return .object([("state", "unavailable"), ("reason", "open_save_panel_service"),
("hint", "This window belongs to the service that draws another app's Open or Save panel, and to its sheets such as Go to Folder. Use the app that opened the panel: its desktop_windows lists the panel with the same title and bounds, which desktop_inspect and desktop_click reach in the background. To go to a folder or file, pass the app's target to desktop_dialog, then desktop_dialog_answer with path.")])
}
// A sheet's own window shows only pixels and takes no input; its parent's snapshot holds the sheet's elements and
// image, whether or not the window server calls the sheet on screen (#245).
if window["observation_reason"]?.string == "attached_sheet", let parent = window["sheet_of_window_id"]?.int {
return .object([("state", "unavailable"), ("reason", "attached_sheet"), ("parent_window_id", JSON(parent)),
("hint", JSON("This window is a sheet attached to window \(parent) of the same app. Inspect window \(parent) instead: its snapshot shows the sheet and lists it as an AXSheet with its text and buttons, which desktop_click presses in the background. desktop_dialog with window \(parent)'s target reads it, and desktop_dialog_answer answers it."))])
}
if window["is_minimized"]?.bool == true {
return .object([("state", "unavailable"), ("reason", "minimized"),
("hint", JSON("The window is minimized. Restore it with desktop_restore, using its target from desktop_windows, \(reinspect)"))])
Expand Down
6 changes: 6 additions & 0 deletions native2/Sources/DesktopHost/Dialogs.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ private func dialogWindows(_ pid: pid_t) async -> [DialogWindow] {

/// Reads the target's dialog; a native refusal reads as the bridge reported it, an unmatched dialog as the client did.
private func readDialog(_ target: DialogTarget) async throws -> DialogRead {
// A sheet's own window holds no Accessibility tree; the sheet is read through the window it's attached to (#245).
if let id = target.window?.id, let listing = try? await Mac.windows(pid: target.pid),
let parent = listing["windows"]?.array?.first(where: { $0["window_id"]?.int == id })?["sheet_of_window_id"]?.int
{
throw BridgeError(message: "Window \(id) is a sheet attached to window \(parent), and Accessibility reaches the sheet only through window \(parent). Pass window \(parent)'s target from desktop_windows, or the app's target from desktop_apps")
}
let windows = await dialogWindows(target.pid)
let read: DialogRead
do {
Expand Down
22 changes: 20 additions & 2 deletions native2/Sources/DesktopHost/Inspect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ extension Tools {
}
let save = try saveRequest(arguments)

// A sheet's own window has no Accessibility tree and takes no input; its parent's snapshot holds both (#245).
if request.scope == nil, let parent = try await run({ Mac.sheetParent(pid: pid, windowID: windowID) }) {
return ToolResult(text: JSON.object([
"inspection_error": .object([("code", "ATTACHED_SHEET"), ("message", JSON(
"Window \(windowID) is a sheet attached to window \(parent). Accessibility reaches the sheet only through window \(parent), "
+ "and input reaches it only through a snapshot of window \(parent). Inspect window \(parent) instead: its snapshot "
+ "shows the sheet and lists it as an AXSheet with its text and buttons."))]),
"requested_target": .object([("pid", JSON(pid)), ("window_id", JSON(windowID)), ("mode", JSON(mode))]),
"parent_window_id": JSON(parent),
]).text, isError: true)
}
var retried = false
let observed: Observation
do {
Expand Down Expand Up @@ -116,7 +127,14 @@ extension Tools {
}

static func observation(pid: pid_t, windowID: Int) async throws -> (JSON, (data: String, mimeType: String)) {
let observed = try await observation(pid: pid, windowID: windowID, InspectRequest(), started: .now)
let observed: Observation
do {
observed = try await observation(pid: pid, windowID: windowID, InspectRequest(), started: .now)
} catch let error as ToolError where error.message.range(of: "incomplete|sparse", options: [.regularExpression, .caseInsensitive]) != nil {
// Input that opens a sheet or alert often leaves the tree mid-change for a moment (#244), as inspect retries.
try await Task.sleep(for: .milliseconds(500))
observed = try await observation(pid: pid, windowID: windowID, InspectRequest(), started: .now)
}
return (observed.data, observed.image)
}

Expand Down Expand Up @@ -235,7 +253,7 @@ extension Tools {
// loads rows as they're read grows and moves what's below, so a screenshot taken during the walk can show
// content where it no longer is, and a point read off it misses (#159).
let elements = try await run { try budget.map { try Mac.elements(pid: pid, windowID: windowID, budget: $0) } ?? ElementTree() }
let image = try await Mac.captureWindow(windowID, bounds: window.bounds)
let image = try await Mac.captureWindow(windowID, bounds: window.bounds, pid: pid)
let captureDone = ContinuousClock.now
guard Mac.generation(pid) == generation, let after = Mac.window(windowID), after.pid == pid, after.bounds == window.bounds else {
throw ToolError("invalidRequest: Snapshot is stale: Exact observation window changed during the observation. Inspect it again.")
Expand Down
Loading
Loading