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.
@@ -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. Every read is wrapped: a surface that will not answer
58
- * degrades that ONE field rather than failing the whole census, because the
59
- * cases this exists for — a foreign modal, an AX-blind session — are exactly
60
- * the cases where half the tree is unreadable.
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
- tell application "System Events"
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
- set fp to first application process whose frontmost is true
76
- set frontName to (name of fp) as text
77
- try
78
- set fe to value of attribute "AXFocusedUIElement" of fp
79
- set focusRole to (role of fe) as text
80
- try
81
- set focusSub to (subrole of fe) as text
82
- end try
83
- on error
84
- set canInspect to false
85
- end try
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
- if (exists application process "${THINGS_PROCESS}") then set thingsRunning to true
91
- end try
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
- if shellRef is not missing value then
97
- set nCb to -1
98
- set nPu to -1
99
- set nBt to -1
100
- set nGp to -1
101
- set nTf to -1
102
- try
103
- set nCb to (count of checkboxes of shellRef)
104
- end try
105
- try
106
- set nPu to (count of pop up buttons of shellRef)
107
- end try
108
- try
109
- set nBt to (count of buttons of shellRef)
110
- end try
111
- try
112
- set nGp to (count of groups of shellRef)
113
- end try
114
- try
115
- set nTf to (count of text fields of shellRef)
116
- end try
117
- set census to "cb:" & nCb & " pu:" & nPu & " bt:" & nBt & " gp:" & nGp & " tf:" & nTf
118
- set winId to ""
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
- set winId to (value of attribute "AXIdentifier" of shellRef) as text
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 tell
306
+ end if
135
307
  end if
136
- return "front=" & frontName & linefeed & "running=" & thingsRunning & linefeed & "form=" & sheetForm & linefeed & "depth=" & sheetDepth & linefeed & "kind=" & sheetKind & linefeed & "census=" & census & linefeed & "role=" & focusRole & linefeed & "subrole=" & focusSub & linefeed & "inspectable=" & canInspect`;
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
- const subrole = fields.get("subrole") ?? "";
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
- thingsFrontmost: frontmostApp === THINGS_PROCESS,
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
- /** A one-line human summary of the census, for a diagnostic line or a warning. */
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 front = state.thingsFrontmost
210
- ? "Things is frontmost"
211
- : `${state.frontmostApp ?? "an unidentified application"} is frontmost`;
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":"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"}
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)