things-api 0.19.2 → 0.19.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/deputy/prebuilt/Things API Helper.app/Contents/CodeResources +0 -0
- package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/MacOS/things-reader +0 -0
- package/deputy/prebuilt/Things API Helper.app/Contents/MacOS/things-deputy +0 -0
- package/dist/contracts.d.ts +1 -1
- package/dist/contracts.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/ui-state.d.ts +1 -1
- package/dist/ui-state.js +33 -8
- package/dist/ui-state.js.map +1 -1
- package/dist/write/vectors/ui-state.d.ts +94 -6
- package/dist/write/vectors/ui-state.js +283 -68
- package/dist/write/vectors/ui-state.js.map +1 -1
- package/dist/write/vectors/ui.d.ts +16 -0
- package/dist/write/vectors/ui.js +139 -16
- package/dist/write/vectors/ui.js.map +1 -1
- package/package.json +1 -1
- package/skills/things-cli/SKILL.md +1 -1
|
@@ -47,6 +47,65 @@ export const AX_DIALOG_SHELL_SNIPPET = ` set shellRef to missing value
|
|
|
47
47
|
set sheetDepth to sheetDepth + 1
|
|
48
48
|
end repeat
|
|
49
49
|
end if`;
|
|
50
|
+
/** Probes whose absence makes the census unusable for a keystroke decision. */
|
|
51
|
+
const CRITICAL_PROBES = ["running", "frontmost", "dialog"];
|
|
52
|
+
/** Every probe name the census can report, for parsing its record back. */
|
|
53
|
+
const KNOWN_PROBES = new Set([
|
|
54
|
+
"running",
|
|
55
|
+
"frontmost",
|
|
56
|
+
"dialog",
|
|
57
|
+
"frontapp",
|
|
58
|
+
"focus",
|
|
59
|
+
]);
|
|
60
|
+
/**
|
|
61
|
+
* Per-APPLE-EVENT budget for every read in the census (`with timeout of N
|
|
62
|
+
* seconds`). Without one, osascript's default is two MINUTES: a System Events
|
|
63
|
+
* call that does not come back is then bounded only by the caller's own process
|
|
64
|
+
* deadline, which is how issue #629's field incident spent ~15s per inspection
|
|
65
|
+
* and ~56s per drive discovering nothing. With one, a read that will not answer
|
|
66
|
+
* raises AppleScript error -1712 and the census carries on to the next probe —
|
|
67
|
+
* or stops, if the probe was one the caller decides on.
|
|
68
|
+
*/
|
|
69
|
+
const PROBE_TIMEOUT_S = 2;
|
|
70
|
+
/**
|
|
71
|
+
* Wall-clock budget for the WHOLE census, checked between probes. `with
|
|
72
|
+
* timeout` bounds one Apple event, not a run of them, so a surface that is
|
|
73
|
+
* merely slow (rather than wedged) could still add up. Past this, the remaining
|
|
74
|
+
* probes are skipped and reported as stalled rather than waited on.
|
|
75
|
+
*/
|
|
76
|
+
const CENSUS_BUDGET_S = 8;
|
|
77
|
+
/**
|
|
78
|
+
* The transport deadline for one census hop — the backstop under the in-script
|
|
79
|
+
* budgets, not the mechanism. Deliberately far below the 15s step timeout that
|
|
80
|
+
* bounded the old single-shot script: nothing here may take this long, and if
|
|
81
|
+
* it does the caller must hear about it while the drive can still be aborted
|
|
82
|
+
* cleanly rather than after four of them have gone by.
|
|
83
|
+
*/
|
|
84
|
+
export const CENSUS_TIMEOUT_MS = 12_000;
|
|
85
|
+
/** Did a probe the caller has to DECIDE on fail to answer? */
|
|
86
|
+
export function censusUnverifiable(state) {
|
|
87
|
+
if (state === null)
|
|
88
|
+
return true;
|
|
89
|
+
return CRITICAL_PROBES.some((p) => state.stalledProbes.includes(p) || state.failedProbes.includes(p));
|
|
90
|
+
}
|
|
91
|
+
/** Name the probes that did not answer, for a diagnostic someone has to act on. */
|
|
92
|
+
export function describeUnprovenProbes(state) {
|
|
93
|
+
const label = {
|
|
94
|
+
running: "whether Things is running",
|
|
95
|
+
frontmost: "whether Things owns the screen",
|
|
96
|
+
dialog: "which dialog is open",
|
|
97
|
+
frontapp: "which application owns the screen",
|
|
98
|
+
focus: "which element has keyboard focus",
|
|
99
|
+
};
|
|
100
|
+
const parts = [];
|
|
101
|
+
if (state.stalledProbes.length > 0) {
|
|
102
|
+
parts.push(`did not answer in time: ${state.stalledProbes.map((p) => label[p]).join(", ")}`);
|
|
103
|
+
}
|
|
104
|
+
if (state.failedProbes.length > 0) {
|
|
105
|
+
parts.push(`could not be read: ${state.failedProbes.map((p) => label[p]).join(", ")}`);
|
|
106
|
+
}
|
|
107
|
+
return parts.join("; ");
|
|
108
|
+
}
|
|
50
109
|
/** A recognizable token in the script so a test runner can key off the ui-state command. */
|
|
51
110
|
export const UI_STATE_MARKER = "-- ui-state census (read-only)";
|
|
52
111
|
/** The label every ui-state dispatch carries (one stable command shape). */
|
|
@@ -54,14 +113,39 @@ export const UI_STATE_LABEL = "read the window and focus state";
|
|
|
54
113
|
/** The Things application's process name — the frontmost value that means "us". */
|
|
55
114
|
export const THINGS_PROCESS = "Things3";
|
|
56
115
|
/**
|
|
57
|
-
* The census script
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
116
|
+
* The census script — ADDRESSED probes, each on its own Apple-event budget
|
|
117
|
+
* (issue #629).
|
|
118
|
+
*
|
|
119
|
+
* WHAT CHANGED, AND WHY IT HAD TO. The 0.19.2 census was one unbounded script
|
|
120
|
+
* that opened with two UNADDRESSED queries: `first application process whose
|
|
121
|
+
* frontmost is true` (the entire process table enumerated) and `value of
|
|
122
|
+
* attribute "AXFocusedUIElement"` on whatever that returned (a system-wide
|
|
123
|
+
* focused-element resolution). Everything else the ui vector runs — every step
|
|
124
|
+
* the field incident's log shows succeeding, inside the very sheet the census
|
|
125
|
+
* could not describe — is addressed: `tell process "Things3" to …`. So the one
|
|
126
|
+
* script that stalled was the one script that left the addressed style, and it
|
|
127
|
+
* stalled on the critical path of BOTH the per-step guard and the cleanup that
|
|
128
|
+
* was supposed to recover from it. Rebuilt here so that:
|
|
129
|
+
*
|
|
130
|
+
* - the decision-critical facts are ADDRESSED and are proven FIRST;
|
|
131
|
+
* - every read carries `with timeout of ${PROBE_TIMEOUT_S} seconds`, so a
|
|
132
|
+
* surface that will not answer costs seconds, not the caller's whole
|
|
133
|
+
* deadline;
|
|
134
|
+
* - a critical probe that does not answer STOPS the census then and there —
|
|
135
|
+
* the remaining probes cannot change what the caller must now do (abort and
|
|
136
|
+
* clean up), so waiting for them is pure latency;
|
|
137
|
+
* - the two unaddressed queries survive only as DECORATION, last, skipped
|
|
138
|
+
* entirely when the addressed probes already answered the question they
|
|
139
|
+
* were there to answer.
|
|
140
|
+
*
|
|
141
|
+
* Every probe still degrades one field rather than failing the census, and what
|
|
142
|
+
* could not be proven is NAMED (`stalled=` / `failed=`) instead of silently
|
|
143
|
+
* reading as a clean "nothing is open".
|
|
61
144
|
*/
|
|
62
145
|
export function axUiStateScript() {
|
|
63
146
|
return `${UI_STATE_MARKER}
|
|
64
147
|
set frontName to ""
|
|
148
|
+
set frontIsThings to false
|
|
65
149
|
set focusRole to ""
|
|
66
150
|
set focusSub to ""
|
|
67
151
|
set canInspect to true
|
|
@@ -70,70 +154,159 @@ set sheetForm to "none"
|
|
|
70
154
|
set sheetKind to "none"
|
|
71
155
|
set sheetDepth to 0
|
|
72
156
|
set census to ""
|
|
73
|
-
|
|
157
|
+
set stalled to ""
|
|
158
|
+
set failed to ""
|
|
159
|
+
set halted to false
|
|
160
|
+
set t0 to (current date)
|
|
161
|
+
|
|
162
|
+
-- P1 running: a name-keyed lookup, no Accessibility round-trip.
|
|
163
|
+
try
|
|
164
|
+
with timeout of ${PROBE_TIMEOUT_S} seconds
|
|
165
|
+
tell application "System Events" to set thingsRunning to (exists application process "${THINGS_PROCESS}")
|
|
166
|
+
end timeout
|
|
167
|
+
on error errMsg number errNum
|
|
168
|
+
if errNum is -1712 then
|
|
169
|
+
set stalled to stalled & "running "
|
|
170
|
+
else
|
|
171
|
+
set failed to failed & "running "
|
|
172
|
+
end if
|
|
173
|
+
set halted to true
|
|
174
|
+
end try
|
|
175
|
+
|
|
176
|
+
-- P2 frontmost, ADDRESSED: the single fact the per-step input guard decides on.
|
|
177
|
+
if (not halted) and thingsRunning then
|
|
74
178
|
try
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
on error
|
|
87
|
-
set canInspect to false
|
|
179
|
+
with timeout of ${PROBE_TIMEOUT_S} seconds
|
|
180
|
+
tell application "System Events" to tell process "${THINGS_PROCESS}" to set frontIsThings to (frontmost as boolean)
|
|
181
|
+
end timeout
|
|
182
|
+
if frontIsThings then set frontName to "${THINGS_PROCESS}"
|
|
183
|
+
on error errMsg number errNum
|
|
184
|
+
if errNum is -1712 then
|
|
185
|
+
set stalled to stalled & "frontmost "
|
|
186
|
+
else
|
|
187
|
+
set failed to failed & "frontmost "
|
|
188
|
+
end if
|
|
189
|
+
set halted to true
|
|
88
190
|
end try
|
|
191
|
+
end if
|
|
192
|
+
|
|
193
|
+
-- P3 dialog: shell, form, stack depth and control census — all addressed
|
|
194
|
+
-- inside the Things process, which is the shape every working drive step uses.
|
|
195
|
+
if (not halted) and thingsRunning then
|
|
89
196
|
try
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
end tell
|
|
93
|
-
if thingsRunning then
|
|
94
|
-
tell application "System Events" to tell process "${THINGS_PROCESS}"
|
|
197
|
+
with timeout of ${PROBE_TIMEOUT_S} seconds
|
|
198
|
+
tell application "System Events" to tell process "${THINGS_PROCESS}"
|
|
95
199
|
${AX_DIALOG_SHELL_SNIPPET}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
200
|
+
if shellRef is not missing value then
|
|
201
|
+
set nCb to -1
|
|
202
|
+
set nPu to -1
|
|
203
|
+
set nBt to -1
|
|
204
|
+
set nGp to -1
|
|
205
|
+
set nTf to -1
|
|
206
|
+
try
|
|
207
|
+
set nCb to (count of checkboxes of shellRef)
|
|
208
|
+
end try
|
|
209
|
+
try
|
|
210
|
+
set nPu to (count of pop up buttons of shellRef)
|
|
211
|
+
end try
|
|
212
|
+
try
|
|
213
|
+
set nBt to (count of buttons of shellRef)
|
|
214
|
+
end try
|
|
215
|
+
try
|
|
216
|
+
set nGp to (count of groups of shellRef)
|
|
217
|
+
end try
|
|
218
|
+
try
|
|
219
|
+
set nTf to (count of text fields of shellRef)
|
|
220
|
+
end try
|
|
221
|
+
set census to "cb:" & nCb & " pu:" & nPu & " bt:" & nBt & " gp:" & nGp & " tf:" & nTf
|
|
222
|
+
set winId to ""
|
|
223
|
+
try
|
|
224
|
+
set winId to (value of attribute "AXIdentifier" of shellRef) as text
|
|
225
|
+
end try
|
|
226
|
+
if winId starts with "MovePopUpDialog-" then
|
|
227
|
+
set sheetKind to "move-picker"
|
|
228
|
+
else if nCb is 2 and nPu is 1 and nBt is 2 and nGp is 1 and nTf is 0 then
|
|
229
|
+
set groupOk to false
|
|
230
|
+
try
|
|
231
|
+
set g to group 1 of shellRef
|
|
232
|
+
if ((count of text fields of g) + (count of pop up buttons of g)) > 0 then set groupOk to true
|
|
233
|
+
end try
|
|
234
|
+
if groupOk then set sheetKind to "repeat"
|
|
235
|
+
end if
|
|
236
|
+
if sheetKind is "none" then set sheetKind to "other"
|
|
237
|
+
end if
|
|
238
|
+
end tell
|
|
239
|
+
end timeout
|
|
240
|
+
on error errMsg number errNum
|
|
241
|
+
if errNum is -1712 then
|
|
242
|
+
set stalled to stalled & "dialog "
|
|
243
|
+
else
|
|
244
|
+
set failed to failed & "dialog "
|
|
245
|
+
end if
|
|
246
|
+
set halted to true
|
|
247
|
+
end try
|
|
248
|
+
end if
|
|
249
|
+
|
|
250
|
+
-- P4 frontapp: the ONLY enumeration left, and it runs only when the addressed
|
|
251
|
+
-- probe has already said the screen is not ours — its whole job is naming the
|
|
252
|
+
-- application in the refusal sentence.
|
|
253
|
+
if (not halted) and (not frontIsThings) then
|
|
254
|
+
if ((current date) - t0) > ${CENSUS_BUDGET_S} then
|
|
255
|
+
set stalled to stalled & "frontapp "
|
|
256
|
+
else
|
|
257
|
+
try
|
|
258
|
+
with timeout of ${PROBE_TIMEOUT_S} seconds
|
|
259
|
+
tell application "System Events" to set frontName to (name of first application process whose frontmost is true) as text
|
|
260
|
+
end timeout
|
|
261
|
+
on error errMsg number errNum
|
|
262
|
+
if errNum is -1712 then
|
|
263
|
+
set stalled to stalled & "frontapp "
|
|
264
|
+
else
|
|
265
|
+
set failed to failed & "frontapp "
|
|
266
|
+
end if
|
|
267
|
+
end try
|
|
268
|
+
end if
|
|
269
|
+
end if
|
|
270
|
+
|
|
271
|
+
-- P5 focus: decoration, and the most expensive read in the census. Addressed at
|
|
272
|
+
-- the process that owns the screen rather than resolved system-wide, run last,
|
|
273
|
+
-- and skipped outright once the budget is spent. An ERROR here (as opposed to a
|
|
274
|
+
-- timeout) is the secure-system-modal signature: macOS exposes no tree for one.
|
|
275
|
+
if not halted then
|
|
276
|
+
if ((current date) - t0) > ${CENSUS_BUDGET_S} then
|
|
277
|
+
set stalled to stalled & "focus "
|
|
278
|
+
else
|
|
279
|
+
set focusTarget to frontName
|
|
280
|
+
if focusTarget is "" then
|
|
281
|
+
set stalled to stalled & "focus "
|
|
282
|
+
else
|
|
119
283
|
try
|
|
120
|
-
|
|
284
|
+
with timeout of ${PROBE_TIMEOUT_S} seconds
|
|
285
|
+
tell application "System Events" to tell process focusTarget
|
|
286
|
+
set fe to value of attribute "AXFocusedUIElement"
|
|
287
|
+
-- No focused element is a perfectly ordinary state (an app
|
|
288
|
+
-- with no key window); it is not an unreadable screen.
|
|
289
|
+
if fe is not missing value then
|
|
290
|
+
set focusRole to (role of fe) as text
|
|
291
|
+
try
|
|
292
|
+
set focusSub to (subrole of fe) as text
|
|
293
|
+
end try
|
|
294
|
+
end if
|
|
295
|
+
end tell
|
|
296
|
+
end timeout
|
|
297
|
+
on error errMsg number errNum
|
|
298
|
+
if errNum is -1712 then
|
|
299
|
+
set stalled to stalled & "focus "
|
|
300
|
+
else
|
|
301
|
+
set canInspect to false
|
|
302
|
+
set failed to failed & "focus "
|
|
303
|
+
end if
|
|
121
304
|
end try
|
|
122
|
-
if winId starts with "MovePopUpDialog-" then
|
|
123
|
-
set sheetKind to "move-picker"
|
|
124
|
-
else if nCb is 2 and nPu is 1 and nBt is 2 and nGp is 1 and nTf is 0 then
|
|
125
|
-
set groupOk to false
|
|
126
|
-
try
|
|
127
|
-
set g to group 1 of shellRef
|
|
128
|
-
if ((count of text fields of g) + (count of pop up buttons of g)) > 0 then set groupOk to true
|
|
129
|
-
end try
|
|
130
|
-
if groupOk then set sheetKind to "repeat"
|
|
131
|
-
end if
|
|
132
|
-
if sheetKind is "none" then set sheetKind to "other"
|
|
133
305
|
end if
|
|
134
|
-
end
|
|
306
|
+
end if
|
|
135
307
|
end if
|
|
136
|
-
|
|
308
|
+
|
|
309
|
+
return "front=" & frontName & linefeed & "isfront=" & frontIsThings & linefeed & "running=" & thingsRunning & linefeed & "form=" & sheetForm & linefeed & "depth=" & sheetDepth & linefeed & "kind=" & sheetKind & linefeed & "census=" & census & linefeed & "role=" & focusRole & linefeed & "subrole=" & focusSub & linefeed & "inspectable=" & canInspect & linefeed & "stalled=" & stalled & linefeed & "failed=" & failed`;
|
|
137
310
|
}
|
|
138
311
|
/**
|
|
139
312
|
* Parse the census record into a {@link UiState}. Returns null when the output
|
|
@@ -150,6 +323,7 @@ export function parseUiState(stdout) {
|
|
|
150
323
|
}
|
|
151
324
|
if (!fields.has("kind") || !fields.has("inspectable"))
|
|
152
325
|
return null;
|
|
326
|
+
const probes = (key) => (fields.get(key) ?? "").split(/\s+/).filter((p) => KNOWN_PROBES.has(p));
|
|
153
327
|
const kindRaw = fields.get("kind") ?? "none";
|
|
154
328
|
const sheetKind = kindRaw === "repeat" || kindRaw === "move-picker" || kindRaw === "other" ? kindRaw : "none";
|
|
155
329
|
const formRaw = fields.get("form") ?? "none";
|
|
@@ -157,12 +331,17 @@ export function parseUiState(stdout) {
|
|
|
157
331
|
const frontRaw = fields.get("front") ?? "";
|
|
158
332
|
const frontmostApp = frontRaw === "" ? null : frontRaw;
|
|
159
333
|
const role = fields.get("role") ?? "";
|
|
160
|
-
|
|
334
|
+
// AppleScript coerces an absent attribute to the literal words "missing
|
|
335
|
+
// value"; that is "no subrole", not a subrole named that.
|
|
336
|
+
const subroleRaw = fields.get("subrole") ?? "";
|
|
337
|
+
const subrole = subroleRaw === "missing value" ? "" : subroleRaw;
|
|
161
338
|
const census = fields.get("census") ?? "";
|
|
162
339
|
const depth = Number(fields.get("depth") ?? "0");
|
|
163
340
|
return {
|
|
164
341
|
thingsRunning: fields.get("running") === "true",
|
|
165
|
-
|
|
342
|
+
// Decided by the ADDRESSED probe, not by comparing a name the enumeration
|
|
343
|
+
// may never have been asked for (issue #629).
|
|
344
|
+
thingsFrontmost: fields.get("isfront") === "true",
|
|
166
345
|
frontmostApp,
|
|
167
346
|
sheetOpen: sheetKind !== "none",
|
|
168
347
|
sheetKind,
|
|
@@ -171,14 +350,19 @@ export function parseUiState(stdout) {
|
|
|
171
350
|
sheetControls: census === "" ? null : census,
|
|
172
351
|
focusOwner: frontmostApp === null ? null : { app: frontmostApp, role, subrole: subrole || null },
|
|
173
352
|
inspectable: fields.get("inspectable") === "true",
|
|
353
|
+
stalledProbes: probes("stalled"),
|
|
354
|
+
failedProbes: probes("failed"),
|
|
174
355
|
};
|
|
175
356
|
}
|
|
176
357
|
/**
|
|
177
358
|
* Read the census through the injected runner. Returns null on a transport
|
|
178
359
|
* failure — an UNKNOWN state, which every caller treats fail-closed (the guard
|
|
179
360
|
* refuses; the cleanup path does not send a blind Escape).
|
|
361
|
+
*
|
|
362
|
+
* `timeoutMs` defaults to {@link CENSUS_TIMEOUT_MS}: a census is not a drive
|
|
363
|
+
* step and must not borrow a drive step's patience (issue #629).
|
|
180
364
|
*/
|
|
181
|
-
export async function readUiState(run, timeoutMs) {
|
|
365
|
+
export async function readUiState(run, timeoutMs = CENSUS_TIMEOUT_MS) {
|
|
182
366
|
const res = await run({ primitive: "resolve", label: UI_STATE_LABEL, script: axUiStateScript() }, timeoutMs);
|
|
183
367
|
if (!res.ok)
|
|
184
368
|
return null;
|
|
@@ -194,6 +378,12 @@ export async function readUiState(run, timeoutMs) {
|
|
|
194
378
|
export function describeFocusOwner(state) {
|
|
195
379
|
if (state === null)
|
|
196
380
|
return "the window state could not be read";
|
|
381
|
+
// #629: an inspection that did not come back says nothing about who owns the
|
|
382
|
+
// screen — and saying "an unidentified application is frontmost" would read
|
|
383
|
+
// as a measurement. Name the probe that stalled instead.
|
|
384
|
+
if (censusUnverifiable(state)) {
|
|
385
|
+
return `the window state inspection did not complete (${describeUnprovenProbes(state)})`;
|
|
386
|
+
}
|
|
197
387
|
if (!state.inspectable) {
|
|
198
388
|
return ("a system dialog owns the screen — macOS does not expose it to other apps, so it cannot be " +
|
|
199
389
|
`identified from here${state.frontmostApp === null ? "" : ` (frontmost application: ${state.frontmostApp})`}`);
|
|
@@ -204,11 +394,36 @@ export function describeFocusOwner(state) {
|
|
|
204
394
|
? `${app} is frontmost`
|
|
205
395
|
: `${app} is frontmost and keyboard focus is on a ${role}`;
|
|
206
396
|
}
|
|
207
|
-
/**
|
|
397
|
+
/**
|
|
398
|
+
* A one-line human summary of the census, for a diagnostic line or a warning.
|
|
399
|
+
*
|
|
400
|
+
* Reports WHAT EACH PROBE PROVED. A stalled probe leaves its clause reading
|
|
401
|
+
* "could not be determined" and is named at the end — never omitted, and never
|
|
402
|
+
* rendered as its default (issue #629: a census that could not see the open
|
|
403
|
+
* Repeat sheet used to report a clean screen).
|
|
404
|
+
*/
|
|
208
405
|
export function describeUiState(state) {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
406
|
+
const unproven = (p) => state.stalledProbes.includes(p) || state.failedProbes.includes(p);
|
|
407
|
+
const trailer = () => {
|
|
408
|
+
const unprovenText = describeUnprovenProbes(state);
|
|
409
|
+
return unprovenText === "" ? "" : ` — ${unprovenText}`;
|
|
410
|
+
};
|
|
411
|
+
if (unproven("running")) {
|
|
412
|
+
return `nothing about the screen could be established${trailer()}`;
|
|
413
|
+
}
|
|
414
|
+
if (!state.thingsRunning && !unproven("frontmost")) {
|
|
415
|
+
return `Things is not running${trailer()}`;
|
|
416
|
+
}
|
|
417
|
+
const front = unproven("frontmost")
|
|
418
|
+
? "whether Things owns the screen could not be determined"
|
|
419
|
+
: state.thingsFrontmost
|
|
420
|
+
? "Things is frontmost"
|
|
421
|
+
: unproven("frontapp")
|
|
422
|
+
? "another application is frontmost (it could not be named)"
|
|
423
|
+
: `${state.frontmostApp ?? "an unidentified application"} is frontmost`;
|
|
424
|
+
if (unproven("dialog")) {
|
|
425
|
+
return `${front}; whether a dialog is open in Things could not be determined${trailer()}`;
|
|
426
|
+
}
|
|
212
427
|
const sheet = state.sheetKind === "none"
|
|
213
428
|
? "no dialog is open in Things"
|
|
214
429
|
: state.sheetKind === "repeat"
|
|
@@ -219,7 +434,7 @@ export function describeUiState(state) {
|
|
|
219
434
|
// A stack means the thing in front is sitting ON another dialog, and each one
|
|
220
435
|
// has to be dismissed in turn (MODALX1 §6).
|
|
221
436
|
const stacked = state.sheetDepth > 1 ? `, on top of ${state.sheetDepth - 1} more` : "";
|
|
222
|
-
return `${front}; ${sheet}${stacked}`;
|
|
437
|
+
return `${front}; ${sheet}${stacked}${trailer()}`;
|
|
223
438
|
}
|
|
224
439
|
/**
|
|
225
440
|
* The warning an OPEN Things dialog earns, wherever it is reported.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui-state.js","sourceRoot":"","sources":["../../../src/write/vectors/ui-state.ts"],"names":[],"mappings":"AAqDA,yEAAyE;AACzE,MAAM,eAAe,GAAG,CAAC,CAAC;AAE1B;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;YAqB3B,eAAe;;;;;;;;;SASlB,CAAC;
|
|
1
|
+
{"version":3,"file":"ui-state.js","sourceRoot":"","sources":["../../../src/write/vectors/ui-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -558,6 +558,15 @@ export declare function axAbortScript(): string;
|
|
|
558
558
|
* the census to decide that.
|
|
559
559
|
*/
|
|
560
560
|
export declare function axCancelDialogScript(): string;
|
|
561
|
+
/**
|
|
562
|
+
* The Cancel button's on-screen FRAME, resolved through the same addressed
|
|
563
|
+
* dialog-shell path the AXPress dismissal uses (issue #629). Feeds the pointer
|
|
564
|
+
* fallback: if `AXPress` on the button reports success and the dialog is still
|
|
565
|
+
* standing, a real click at the button's own AX-resolved centre is the next
|
|
566
|
+
* thing to try before discarding the window wholesale. The frame comes from the
|
|
567
|
+
* tree, never from a remembered coordinate, so a moved dialog fails closed.
|
|
568
|
+
*/
|
|
569
|
+
export declare function axCancelFrameScript(): string;
|
|
561
570
|
/**
|
|
562
571
|
* The PROVEN app-level clearance / relocation maneuver (SESSGATE, #480, live-host
|
|
563
572
|
* recovery): close the front Things window — which takes an attached modal sheet
|
|
@@ -606,6 +615,13 @@ export interface ClearResult {
|
|
|
606
615
|
sheetKind?: UiSheetKind;
|
|
607
616
|
/** Who owned the screen when the cleanup started, when it was not Things. */
|
|
608
617
|
focusOwner?: string;
|
|
618
|
+
/**
|
|
619
|
+
* True when the cleanup ran WITHOUT a working window-state inspection (issue
|
|
620
|
+
* #629) — the dismissal and its proof came from addressed reads alone, so the
|
|
621
|
+
* outcome is real but the identity of what was dismissed was taken from what
|
|
622
|
+
* this drive had already observed rather than re-confirmed.
|
|
623
|
+
*/
|
|
624
|
+
unverified?: boolean;
|
|
609
625
|
}
|
|
610
626
|
/**
|
|
611
627
|
* resolve-frame: read the element's on-screen frame (top-left origin, points)
|