things-api 0.19.4 → 0.20.1
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/audit/schema.d.ts +28 -10
- package/dist/audit/schema.js +21 -0
- package/dist/audit/schema.js.map +1 -1
- package/dist/cli/commands/doctor.js +3 -1
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/op-result.js +15 -9
- package/dist/cli/commands/op-result.js.map +1 -1
- package/dist/cli/commands/repeat-flags.d.ts +19 -1
- package/dist/cli/commands/repeat-flags.js +71 -0
- package/dist/cli/commands/repeat-flags.js.map +1 -1
- package/dist/cli/commands/rescue.d.ts +12 -0
- package/dist/cli/commands/rescue.js +83 -0
- package/dist/cli/commands/rescue.js.map +1 -0
- package/dist/cli/commands/writes.js +35 -25
- package/dist/cli/commands/writes.js.map +1 -1
- package/dist/cli/help.js +25 -25
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +12 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/resolve-invocation.d.ts +9 -1
- package/dist/cli/resolve-invocation.js +71 -0
- package/dist/cli/resolve-invocation.js.map +1 -1
- package/dist/cli/unknown-command.d.ts +26 -0
- package/dist/cli/unknown-command.js +135 -0
- package/dist/cli/unknown-command.js.map +1 -0
- package/dist/contracts.d.ts +4 -3
- package/dist/contracts.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +55 -10
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/entities.d.ts +11 -0
- package/dist/model/entities.js.map +1 -1
- package/dist/model/mappers.js +26 -9
- package/dist/model/mappers.js.map +1 -1
- package/dist/model/today-placement.d.ts +65 -0
- package/dist/model/today-placement.js +59 -0
- package/dist/model/today-placement.js.map +1 -0
- package/dist/op-result.d.ts +15 -2
- package/dist/op-result.js +72 -20
- package/dist/op-result.js.map +1 -1
- package/dist/process-instance.d.ts +41 -0
- package/dist/process-instance.js +82 -0
- package/dist/process-instance.js.map +1 -0
- package/dist/rescue.d.ts +247 -0
- package/dist/rescue.js +811 -0
- package/dist/rescue.js.map +1 -0
- package/dist/session-grant.js +4 -15
- package/dist/session-grant.js.map +1 -1
- package/dist/ui-state.d.ts +8 -4
- package/dist/ui-state.js +8 -4
- package/dist/ui-state.js.map +1 -1
- package/dist/write/commands.d.ts +9 -0
- package/dist/write/commands.js +138 -51
- package/dist/write/commands.js.map +1 -1
- package/dist/write/disclosures.d.ts +24 -0
- package/dist/write/disclosures.js +24 -0
- package/dist/write/disclosures.js.map +1 -1
- package/dist/write/experimental.d.ts +16 -0
- package/dist/write/experimental.js +19 -0
- package/dist/write/experimental.js.map +1 -1
- package/dist/write/failure-hints.js +3 -2
- package/dist/write/failure-hints.js.map +1 -1
- package/dist/write/guards.d.ts +1 -1
- package/dist/write/guards.js +130 -8
- package/dist/write/guards.js.map +1 -1
- package/dist/write/lock.d.ts +85 -1
- package/dist/write/lock.js +121 -6
- package/dist/write/lock.js.map +1 -1
- package/dist/write/move.js +33 -6
- package/dist/write/move.js.map +1 -1
- package/dist/write/operations.d.ts +52 -6
- package/dist/write/operations.js +22 -0
- package/dist/write/operations.js.map +1 -1
- package/dist/write/opid.d.ts +69 -8
- package/dist/write/opid.js +111 -17
- package/dist/write/opid.js.map +1 -1
- package/dist/write/param-schema.js +14 -2
- package/dist/write/param-schema.js.map +1 -1
- package/dist/write/pipeline.d.ts +43 -2
- package/dist/write/pipeline.js +206 -43
- package/dist/write/pipeline.js.map +1 -1
- package/dist/write/planner.d.ts +7 -0
- package/dist/write/planner.js +12 -0
- package/dist/write/planner.js.map +1 -1
- package/dist/write/pre-state.d.ts +9 -9
- package/dist/write/pre-state.js +44 -38
- package/dist/write/pre-state.js.map +1 -1
- package/dist/write/preserve-modified.d.ts +17 -8
- package/dist/write/preserve-modified.js.map +1 -1
- package/dist/write/promote-clone.js +60 -17
- package/dist/write/promote-clone.js.map +1 -1
- package/dist/write/reorder.js +28 -7
- package/dist/write/reorder.js.map +1 -1
- package/dist/write/repeat-rule.d.ts +25 -1
- package/dist/write/repeat-rule.js +69 -0
- package/dist/write/repeat-rule.js.map +1 -1
- package/dist/write/resolution-timestamps.js +103 -80
- package/dist/write/resolution-timestamps.js.map +1 -1
- package/dist/write/reversibility.js +2 -2
- package/dist/write/reversibility.js.map +1 -1
- package/dist/write/template-mutation.js +14 -2
- package/dist/write/template-mutation.js.map +1 -1
- package/dist/write/undo.js +45 -5
- package/dist/write/undo.js.map +1 -1
- package/dist/write/vectors/simulator.js +48 -2
- package/dist/write/vectors/simulator.js.map +1 -1
- package/dist/write/vectors/types.d.ts +10 -0
- package/dist/write/vectors/ui-drag.d.ts +102 -0
- package/dist/write/vectors/ui-drag.js +425 -11
- package/dist/write/vectors/ui-drag.js.map +1 -1
- package/dist/write/vectors/ui-state.d.ts +22 -6
- package/dist/write/vectors/ui-state.js +1 -1
- package/dist/write/vectors/ui-state.js.map +1 -1
- package/dist/write/vectors/ui.d.ts +29 -1
- package/dist/write/vectors/ui.js +57 -5
- package/dist/write/vectors/ui.js.map +1 -1
- package/dist/write/vectors/url-scheme.js +26 -0
- package/dist/write/vectors/url-scheme.js.map +1 -1
- package/package.json +1 -1
- package/schema/envelope.schema.json +1 -2
- package/skills/things-cli/SKILL.md +4 -2
- package/skills/things-cli/references/repeating.md +1 -1
- package/dist/cli/commands/ui-state.d.ts +0 -11
- package/dist/cli/commands/ui-state.js +0 -27
- package/dist/cli/commands/ui-state.js.map +0 -1
package/dist/rescue.d.ts
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `things rescue` — the headless emergency surface for un-sticking Things
|
|
3
|
+
* (issue #640).
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS. Things can reach a state where the app is up, answering, and
|
|
6
|
+
* unusable to automation, with no scripted way back. Three measured behaviours
|
|
7
|
+
* converge on it:
|
|
8
|
+
*
|
|
9
|
+
* - a standing modal sheet EMPTIES the app's top-level AppleScript collections
|
|
10
|
+
* (oddities §25 / MODALX1), so `delete` reports `-1728 Can't get to do id` on
|
|
11
|
+
* a row the database holds open — issue #620's "ghost clone", which has no
|
|
12
|
+
* second cause;
|
|
13
|
+
* - a standing sheet GATES Things Cloud sync entirely (oddities §24), so writes
|
|
14
|
+
* land locally and silently never leave the Mac;
|
|
15
|
+
* - a Repeat dialog opened while Things is BACKGROUNDED becomes a detached
|
|
16
|
+
* window that nothing dismisses (oddities §26 / DRVLAT1 §5) — not its own
|
|
17
|
+
* Cancel, not Escape, not ⌘W, not a real HID click at its Cancel frame.
|
|
18
|
+
*
|
|
19
|
+
* The shipped driver never creates the third state (every dialog recipe
|
|
20
|
+
* activates Things first, which is exactly why that step is permanent), but a
|
|
21
|
+
* killed client, a harness tool-timeout or a person walking away mid-dialog can
|
|
22
|
+
* all leave the first two. {@link rescueStatus} reports them; the other two
|
|
23
|
+
* verbs act on them. This is the single home for both halves — the read-only
|
|
24
|
+
* census that was once the top-level `ui-state` command lives here now.
|
|
25
|
+
*
|
|
26
|
+
* THE THREE VERBS, separated by what they can cost you:
|
|
27
|
+
*
|
|
28
|
+
* - {@link rescueStatus} free, ungated, read-only — the census + the lock
|
|
29
|
+
* table + a "we must not touch that" verdict;
|
|
30
|
+
* - {@link rescueDismiss} gated two ways — presses ONE dialog's own Cancel;
|
|
31
|
+
* - {@link rescueRelaunch} gated two ways — ends the process and starts it
|
|
32
|
+
* again, the only cure measured for oddities §26.
|
|
33
|
+
*
|
|
34
|
+
* PERMISSIONS DOCTRINE. Nothing here raises a macOS consent dialog. The screen
|
|
35
|
+
* is read behind the prompt-free capability verdict, exactly as `doctor
|
|
36
|
+
* --ui-state` reads it, and a machine that has not granted the access is TOLD so
|
|
37
|
+
* rather than
|
|
38
|
+
* prompted. {@link rescueRelaunch} is the deliberate exception to needing that
|
|
39
|
+
* grant at all — see its own note.
|
|
40
|
+
*/
|
|
41
|
+
import { type AuditWriter } from "./audit/log.ts";
|
|
42
|
+
import { type UiCapability } from "./capability.ts";
|
|
43
|
+
import { type UiState } from "./write/vectors/ui-state.ts";
|
|
44
|
+
import { type UiRunner } from "./write/vectors/ui.ts";
|
|
45
|
+
/** What a relaunch could establish about the database it left behind. */
|
|
46
|
+
export interface RescueSchemaVerdict {
|
|
47
|
+
/** Did the database open and read as a shape this build understands? */
|
|
48
|
+
ok: boolean;
|
|
49
|
+
/** One sentence, for the report. */
|
|
50
|
+
detail: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Every side-effecting thing this module does, injectable. Production defaults
|
|
54
|
+
* are the real ones; the unit suite substitutes all of them, which is what makes
|
|
55
|
+
* the gating, the refusals and the kill ladder testable without an app.
|
|
56
|
+
*/
|
|
57
|
+
export interface RescueDeps {
|
|
58
|
+
/** The prompt-free GUI capability verdict. */
|
|
59
|
+
uiCapability?: () => UiCapability;
|
|
60
|
+
/** The osascript / reveal dispatch seam — the same transport the drive uses. */
|
|
61
|
+
run?: UiRunner;
|
|
62
|
+
/** Process environment, for config, the lock path and the change-history directory. */
|
|
63
|
+
env?: NodeJS.ProcessEnv;
|
|
64
|
+
/** Where a rescue ACTION records what it did. */
|
|
65
|
+
audit?: AuditWriter;
|
|
66
|
+
now?: () => number;
|
|
67
|
+
pidAlive?: (pid: number) => boolean;
|
|
68
|
+
/** Which pids Things is running as, newest first; empty when it is not running. */
|
|
69
|
+
thingsPids?: () => Promise<number[]>;
|
|
70
|
+
/** Signal one pid. Never throws for a pid that has already gone. */
|
|
71
|
+
signal?: (pid: number, sig: NodeJS.Signals) => void;
|
|
72
|
+
/** Start Things in the BACKGROUND — we do not steal the screen to fix the screen. */
|
|
73
|
+
launch?: () => Promise<{
|
|
74
|
+
ok: boolean;
|
|
75
|
+
detail: string;
|
|
76
|
+
}>;
|
|
77
|
+
/** Read the database's own verdict, for the post-relaunch check. */
|
|
78
|
+
schemaStatus?: () => RescueSchemaVerdict;
|
|
79
|
+
sleep?: (ms: number) => Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* A modal that is NOT ours. `inspectable: false` is the signature of a secure
|
|
83
|
+
* system modal — a macOS privacy/consent dialog, which belongs to no
|
|
84
|
+
* application's Accessibility tree and which no rescue verb may ever press a
|
|
85
|
+
* button on. It is reported so the operator knows to look at the screen, and so
|
|
86
|
+
* they know the refusal that follows is deliberate rather than a failure.
|
|
87
|
+
*/
|
|
88
|
+
export interface RescueForeignModal {
|
|
89
|
+
/** The application that owns the screen, or null when even that could not be read. */
|
|
90
|
+
owner: string | null;
|
|
91
|
+
detail: string;
|
|
92
|
+
}
|
|
93
|
+
/** The mutation lock, as `rescue status` reports it. Read-only, always. */
|
|
94
|
+
export interface RescueLockView {
|
|
95
|
+
path: string;
|
|
96
|
+
held: boolean;
|
|
97
|
+
pid: number | null;
|
|
98
|
+
/** ISO instant the holder took it. */
|
|
99
|
+
since: string | null;
|
|
100
|
+
/** Human age ("4m 12s"), or null when it could not be computed. */
|
|
101
|
+
heldFor: string | null;
|
|
102
|
+
/** Does a process with that pid still exist? */
|
|
103
|
+
alive: boolean;
|
|
104
|
+
/** Alive AND older than any change takes — old enough to say so. */
|
|
105
|
+
suspect: boolean;
|
|
106
|
+
detail: string;
|
|
107
|
+
}
|
|
108
|
+
export interface RescueStatusReport {
|
|
109
|
+
/** Could the screen be read at all on this machine? */
|
|
110
|
+
screenReadable: boolean;
|
|
111
|
+
/** One sentence: the census summary, or the reason there is none. */
|
|
112
|
+
detail: string;
|
|
113
|
+
/** The census; null when it could not be read. */
|
|
114
|
+
state: UiState | null;
|
|
115
|
+
lock: RescueLockView;
|
|
116
|
+
/** Set when something we must not touch owns the screen. */
|
|
117
|
+
foreignModal: RescueForeignModal | null;
|
|
118
|
+
/** Consequences worth stating — the open-dialog sync gate. */
|
|
119
|
+
warnings: string[];
|
|
120
|
+
/** What to do next, including which rescue verb applies. */
|
|
121
|
+
remediation: string[];
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Read everything a stuck machine can be asked about, without touching any of
|
|
125
|
+
* it. Never throws and never refuses: the cases this exists for are exactly the
|
|
126
|
+
* ones where something is already wrong, so every failure is a REPORTED state.
|
|
127
|
+
*/
|
|
128
|
+
export declare function rescueStatus(deps?: RescueDeps): Promise<RescueStatusReport>;
|
|
129
|
+
export type RescueDismissOutcome =
|
|
130
|
+
/** Nothing was stranded — no dialog was open. */
|
|
131
|
+
"no-dialog"
|
|
132
|
+
/** Cancel was pressed and the dialog is confirmed gone. */
|
|
133
|
+
| "dismissed"
|
|
134
|
+
/** Cancel was pressed and the dialog is demonstrably still there (oddities §26). */
|
|
135
|
+
| "still-open"
|
|
136
|
+
/** Cancel was pressed and the screen could not be re-read to confirm either way. */
|
|
137
|
+
| "unverified"
|
|
138
|
+
/** Nothing was pressed. */
|
|
139
|
+
| "refused";
|
|
140
|
+
export interface RescueDismissResult {
|
|
141
|
+
outcome: RescueDismissOutcome;
|
|
142
|
+
/** Which press worked, when one did. */
|
|
143
|
+
how: "cancel-button" | "cancel-click" | null;
|
|
144
|
+
before: UiState | null;
|
|
145
|
+
after: UiState | null;
|
|
146
|
+
/** Dialogs still stacked after this one; null when it could not be re-read. */
|
|
147
|
+
levelsRemaining: number | null;
|
|
148
|
+
detail: string;
|
|
149
|
+
remediation: string[];
|
|
150
|
+
notes: string[];
|
|
151
|
+
warnings: string[];
|
|
152
|
+
}
|
|
153
|
+
/** The two keys `rescue dismiss` needs, spelled the way each surface spells them. */
|
|
154
|
+
export interface RescueDismissAck {
|
|
155
|
+
/** `--dangerously-dismiss-dialog`. */
|
|
156
|
+
dangerouslyDismissDialog?: boolean;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Close the dialog IN FRONT by pressing its own Cancel button — FGRD2's proven
|
|
160
|
+
* Cancel, generalized off the drive's abort path and onto a dialog no drive
|
|
161
|
+
* opened.
|
|
162
|
+
*
|
|
163
|
+
* EXACTLY ONE LIFO LEVEL PER INVOCATION. Sheets nest as `AXSheet` children of
|
|
164
|
+
* the sheet below and dismiss strictly last-in-first-out (MODALX1 §6). A loop
|
|
165
|
+
* that cleared a whole stack in one command would be a loop pressing an unknown
|
|
166
|
+
* number of buttons on an unknown number of dialogs; instead this closes the top
|
|
167
|
+
* one, re-reads, and reports how many remain so the caller decides.
|
|
168
|
+
*
|
|
169
|
+
* PROVEN, never assumed. The press reporting success is NOT closure: the
|
|
170
|
+
* detached editor of oddities §26 accepts an AXPress on its Cancel and stays
|
|
171
|
+
* exactly where it is. Closure is decided by a fresh census showing the stack one
|
|
172
|
+
* level shorter, and an unconfirmable press is reported as unconfirmed.
|
|
173
|
+
*
|
|
174
|
+
* WHAT IT CAN COST YOU: the dialog's own pending edits, and nothing else. The
|
|
175
|
+
* database is untouched, and a URL command parked behind a consent sheet is
|
|
176
|
+
* discarded with it (URLEN1).
|
|
177
|
+
*/
|
|
178
|
+
export declare function rescueDismiss(ack?: RescueDismissAck, deps?: RescueDeps): Promise<RescueDismissResult>;
|
|
179
|
+
export type RescueRelaunchOutcome = "relaunched" | "refused" | "failed";
|
|
180
|
+
export interface RescueRelaunchResult {
|
|
181
|
+
outcome: RescueRelaunchOutcome;
|
|
182
|
+
/** Which rung actually ended the process. */
|
|
183
|
+
endedBy: "quit" | "sigterm" | "sigkill" | "not-running" | null;
|
|
184
|
+
before: UiState | null;
|
|
185
|
+
after: UiState | null;
|
|
186
|
+
/** The step-by-step account of the ladder, always present. */
|
|
187
|
+
ladder: string[];
|
|
188
|
+
detail: string;
|
|
189
|
+
remediation: string[];
|
|
190
|
+
notes: string[];
|
|
191
|
+
warnings: string[];
|
|
192
|
+
}
|
|
193
|
+
/** The keys `rescue relaunch` needs. The second one is profile-dependent. */
|
|
194
|
+
export interface RescueRelaunchAck {
|
|
195
|
+
/** `--yes`. */
|
|
196
|
+
yes?: boolean;
|
|
197
|
+
/** `--dangerously-force-quit`; required only under the `workstation` profile. */
|
|
198
|
+
dangerouslyForceQuit?: boolean;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* End Things and start it again — the nuclear rung, and the ONLY cure this
|
|
202
|
+
* project has measured for the detached editor of oddities §26. DRVLAT1 §5 tried
|
|
203
|
+
* every other route against the same live dialog (its own Cancel backgrounded,
|
|
204
|
+
* foregrounded and after `AXRaise`; Escape; ⌘W then re-activate; a real HID click
|
|
205
|
+
* at the AX-resolved Cancel frame) and every one was inert.
|
|
206
|
+
*
|
|
207
|
+
* THE LADDER, each rung bounded:
|
|
208
|
+
*
|
|
209
|
+
* 1. ask Things to quit through its own scripting interface. Bounded, because
|
|
210
|
+
* a standing sheet swallows ⌘Q and the `quit` verb can block behind one.
|
|
211
|
+
* 2. SIGTERM, and wait for the process to go.
|
|
212
|
+
* 3. SIGKILL — the lab's canonical reset for a modal that will not clear.
|
|
213
|
+
* 4. start it again in the BACKGROUND: we do not steal the screen to fix the
|
|
214
|
+
* screen.
|
|
215
|
+
* 5. prove it: the process is answering, the database still reads as the shape
|
|
216
|
+
* this version expects, and no dialog is open.
|
|
217
|
+
*
|
|
218
|
+
* WHAT IS LOST: the Things database is write-ahead-logged, so everything already
|
|
219
|
+
* committed survives a kill unconditionally. The ceiling is what was never
|
|
220
|
+
* committed — the edits sitting in the dialog being destroyed.
|
|
221
|
+
*
|
|
222
|
+
* WHAT COMES BACK: sync. While a dialog stands, Things stops sending changes to
|
|
223
|
+
* Things Cloud (oddities §24); killing the dialog with the process releases that,
|
|
224
|
+
* and everything written on this Mac in the meantime goes out.
|
|
225
|
+
*
|
|
226
|
+
* DELIBERATELY NOT GATED ON THE GUI CAPABILITY. Every other verb that touches the
|
|
227
|
+
* app needs the GUI grant, because it synthesizes input into someone's window.
|
|
228
|
+
* This one signals a process the user already owns, which needs no grant at all —
|
|
229
|
+
* and the machines that need it most are exactly the ones where the Accessibility
|
|
230
|
+
* path is what broke. The quit rung and the census still run through the granted
|
|
231
|
+
* seam when it is available, and are skipped without complaint when it is not.
|
|
232
|
+
*/
|
|
233
|
+
export declare function rescueRelaunch(ack?: RescueRelaunchAck, deps?: RescueDeps): Promise<RescueRelaunchResult>;
|
|
234
|
+
/**
|
|
235
|
+
* The human render of `things rescue status`.
|
|
236
|
+
*
|
|
237
|
+
* A ROW WHOSE PROBE DID NOT ANSWER SAYS SO (issue #629). Printing a field's
|
|
238
|
+
* unset default ("none", "unknown") beside rows that WERE measured is exactly
|
|
239
|
+
* what made a stalled inspection read as a clean screen in the field, so an
|
|
240
|
+
* unproven probe renders as "not established" rather than as its default, and
|
|
241
|
+
* the probes are named again in full on the `unproven:` row.
|
|
242
|
+
*/
|
|
243
|
+
export declare function rescueStatusLines(report: RescueStatusReport): string[];
|
|
244
|
+
/** The human render of `things rescue dismiss`. */
|
|
245
|
+
export declare function rescueDismissLines(result: RescueDismissResult): string[];
|
|
246
|
+
/** The human render of `things rescue relaunch`. */
|
|
247
|
+
export declare function rescueRelaunchLines(result: RescueRelaunchResult): string[];
|