things-api 0.16.0 → 0.18.0

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.
Files changed (208) hide show
  1. package/README.md +1 -1
  2. package/deputy/VERSION +1 -0
  3. package/deputy/helpers-Info.plist +23 -0
  4. package/deputy/prebuilt/Things API Helper.app/Contents/CodeResources +0 -0
  5. package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/Info.plist +20 -0
  6. package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/MacOS/things-reader +0 -0
  7. package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/_CodeSignature/CodeResources +115 -0
  8. package/deputy/prebuilt/Things API Helper.app/Contents/Info.plist +23 -0
  9. package/deputy/prebuilt/Things API Helper.app/Contents/MacOS/things-deputy +0 -0
  10. package/deputy/prebuilt/Things API Helper.app/Contents/_CodeSignature/CodeResources +125 -0
  11. package/deputy/reader/Info.plist +20 -0
  12. package/deputy/reader/entitlements.plist +15 -0
  13. package/deputy/reader/main.swift +491 -0
  14. package/deputy/src/main.swift +133 -0
  15. package/deputy/src/osascript.swift +102 -0
  16. package/deputy/src/server.swift +350 -0
  17. package/deputy/src/sqlite.swift +121 -0
  18. package/dist/cli/commands/doctor.js +55 -2
  19. package/dist/cli/commands/doctor.js.map +1 -1
  20. package/dist/cli/commands/helpers.d.ts +17 -0
  21. package/dist/cli/commands/helpers.js +148 -0
  22. package/dist/cli/commands/helpers.js.map +1 -0
  23. package/dist/cli/commands/op-result.d.ts +15 -0
  24. package/dist/cli/commands/op-result.js +39 -0
  25. package/dist/cli/commands/op-result.js.map +1 -0
  26. package/dist/cli/commands/repeat-flags.d.ts +3 -3
  27. package/dist/cli/commands/repeat-flags.js +90 -33
  28. package/dist/cli/commands/repeat-flags.js.map +1 -1
  29. package/dist/cli/commands/writes.js +79 -6
  30. package/dist/cli/commands/writes.js.map +1 -1
  31. package/dist/cli/help.js +13 -2
  32. package/dist/cli/help.js.map +1 -1
  33. package/dist/cli/helpers-check.d.ts +10 -0
  34. package/dist/cli/helpers-check.js +59 -0
  35. package/dist/cli/helpers-check.js.map +1 -0
  36. package/dist/cli/interrupt.d.ts +42 -0
  37. package/dist/cli/interrupt.js +105 -0
  38. package/dist/cli/interrupt.js.map +1 -0
  39. package/dist/cli/main.js +27 -1
  40. package/dist/cli/main.js.map +1 -1
  41. package/dist/client.js +19 -2
  42. package/dist/client.js.map +1 -1
  43. package/dist/config.d.ts +70 -0
  44. package/dist/config.js +25 -1
  45. package/dist/config.js.map +1 -1
  46. package/dist/contracts.d.ts +9 -2
  47. package/dist/contracts.js +1 -1
  48. package/dist/contracts.js.map +1 -1
  49. package/dist/db/baselines/db-v26.js +8 -4
  50. package/dist/db/baselines/db-v26.js.map +1 -1
  51. package/dist/db/baselines/db-v27.d.ts +42 -0
  52. package/dist/db/baselines/db-v27.js +47 -0
  53. package/dist/db/baselines/db-v27.js.map +1 -0
  54. package/dist/db/baselines/index.js +2 -1
  55. package/dist/db/baselines/index.js.map +1 -1
  56. package/dist/db/locate.d.ts +4 -1
  57. package/dist/db/locate.js +3 -1
  58. package/dist/db/locate.js.map +1 -1
  59. package/dist/db/schema.d.ts +1 -1
  60. package/dist/db/schema.js +9 -0
  61. package/dist/db/schema.js.map +1 -1
  62. package/dist/deputy/bridge-worker.d.ts +1 -0
  63. package/dist/deputy/bridge-worker.js +79 -0
  64. package/dist/deputy/bridge-worker.js.map +1 -0
  65. package/dist/deputy/bridge.d.ts +14 -0
  66. package/dist/deputy/bridge.js +70 -0
  67. package/dist/deputy/bridge.js.map +1 -0
  68. package/dist/deputy/client.d.ts +19 -0
  69. package/dist/deputy/client.js +104 -0
  70. package/dist/deputy/client.js.map +1 -0
  71. package/dist/deputy/db-facade.d.ts +18 -0
  72. package/dist/deputy/db-facade.js +71 -0
  73. package/dist/deputy/db-facade.js.map +1 -0
  74. package/dist/deputy/files.d.ts +1 -0
  75. package/dist/deputy/files.js +16 -0
  76. package/dist/deputy/files.js.map +1 -0
  77. package/dist/deputy/install.d.ts +105 -0
  78. package/dist/deputy/install.js +467 -0
  79. package/dist/deputy/install.js.map +1 -0
  80. package/dist/deputy/notice.d.ts +6 -0
  81. package/dist/deputy/notice.js +28 -0
  82. package/dist/deputy/notice.js.map +1 -0
  83. package/dist/deputy/notices.d.ts +31 -0
  84. package/dist/deputy/notices.js +94 -0
  85. package/dist/deputy/notices.js.map +1 -0
  86. package/dist/deputy/osa.d.ts +21 -0
  87. package/dist/deputy/osa.js +72 -0
  88. package/dist/deputy/osa.js.map +1 -0
  89. package/dist/deputy/protocol.d.ts +86 -0
  90. package/dist/deputy/protocol.js +106 -0
  91. package/dist/deputy/protocol.js.map +1 -0
  92. package/dist/deputy/routing.d.ts +63 -0
  93. package/dist/deputy/routing.js +338 -0
  94. package/dist/deputy/routing.js.map +1 -0
  95. package/dist/deputy/shortcuts-exec.d.ts +10 -0
  96. package/dist/deputy/shortcuts-exec.js +50 -0
  97. package/dist/deputy/shortcuts-exec.js.map +1 -0
  98. package/dist/diagnose.d.ts +43 -1
  99. package/dist/diagnose.js +64 -2
  100. package/dist/diagnose.js.map +1 -1
  101. package/dist/index.d.ts +16 -2
  102. package/dist/index.js +17 -1
  103. package/dist/index.js.map +1 -1
  104. package/dist/mcp/server.js +25 -7
  105. package/dist/mcp/server.js.map +1 -1
  106. package/dist/model/mappers.d.ts +12 -3
  107. package/dist/model/mappers.js +6 -1
  108. package/dist/model/mappers.js.map +1 -1
  109. package/dist/model/occurrences.d.ts +14 -1
  110. package/dist/model/occurrences.js +20 -4
  111. package/dist/model/occurrences.js.map +1 -1
  112. package/dist/model/recurrence.d.ts +64 -9
  113. package/dist/model/recurrence.js +94 -19
  114. package/dist/model/recurrence.js.map +1 -1
  115. package/dist/model/template-projection.d.ts +26 -0
  116. package/dist/model/template-projection.js +113 -0
  117. package/dist/model/template-projection.js.map +1 -0
  118. package/dist/op-result.d.ts +46 -0
  119. package/dist/op-result.js +156 -0
  120. package/dist/op-result.js.map +1 -0
  121. package/dist/paths.d.ts +8 -0
  122. package/dist/paths.js +10 -0
  123. package/dist/paths.js.map +1 -1
  124. package/dist/read/detail.js +7 -1
  125. package/dist/read/detail.js.map +1 -1
  126. package/dist/read/queries.js +8 -1
  127. package/dist/read/queries.js.map +1 -1
  128. package/dist/read/views.d.ts +6 -4
  129. package/dist/read/views.js +60 -18
  130. package/dist/read/views.js.map +1 -1
  131. package/dist/sync-health.js +8 -3
  132. package/dist/sync-health.js.map +1 -1
  133. package/dist/trace/tracer.d.ts +87 -0
  134. package/dist/trace/tracer.js +167 -0
  135. package/dist/trace/tracer.js.map +1 -0
  136. package/dist/write/accessibility-probe.js +4 -2
  137. package/dist/write/accessibility-probe.js.map +1 -1
  138. package/dist/write/automation-probe.js +5 -1
  139. package/dist/write/automation-probe.js.map +1 -1
  140. package/dist/write/availability.js +7 -3
  141. package/dist/write/availability.js.map +1 -1
  142. package/dist/write/clear-reminder.js +24 -21
  143. package/dist/write/clear-reminder.js.map +1 -1
  144. package/dist/write/commands.js +95 -45
  145. package/dist/write/commands.js.map +1 -1
  146. package/dist/write/completion-context.d.ts +57 -0
  147. package/dist/write/completion-context.js +49 -0
  148. package/dist/write/completion-context.js.map +1 -0
  149. package/dist/write/experimental.d.ts +19 -0
  150. package/dist/write/experimental.js +50 -0
  151. package/dist/write/experimental.js.map +1 -1
  152. package/dist/write/failure-hints.d.ts +10 -1
  153. package/dist/write/failure-hints.js +8 -0
  154. package/dist/write/failure-hints.js.map +1 -1
  155. package/dist/write/guards.d.ts +1 -1
  156. package/dist/write/guards.js +10 -0
  157. package/dist/write/guards.js.map +1 -1
  158. package/dist/write/move.js +14 -6
  159. package/dist/write/move.js.map +1 -1
  160. package/dist/write/operations.d.ts +40 -7
  161. package/dist/write/pipeline.d.ts +41 -0
  162. package/dist/write/pipeline.js +289 -19
  163. package/dist/write/pipeline.js.map +1 -1
  164. package/dist/write/pre-state.d.ts +1 -1
  165. package/dist/write/pre-state.js +35 -17
  166. package/dist/write/pre-state.js.map +1 -1
  167. package/dist/write/promote-clone.js +434 -19
  168. package/dist/write/promote-clone.js.map +1 -1
  169. package/dist/write/reorder.js +76 -27
  170. package/dist/write/reorder.js.map +1 -1
  171. package/dist/write/repeat-anchor.d.ts +140 -0
  172. package/dist/write/repeat-anchor.js +403 -0
  173. package/dist/write/repeat-anchor.js.map +1 -0
  174. package/dist/write/repeat-asserts.d.ts +28 -0
  175. package/dist/write/repeat-asserts.js +169 -0
  176. package/dist/write/repeat-asserts.js.map +1 -0
  177. package/dist/write/repeat-rule.js +37 -12
  178. package/dist/write/repeat-rule.js.map +1 -1
  179. package/dist/write/vectors/applescript.js +7 -16
  180. package/dist/write/vectors/applescript.js.map +1 -1
  181. package/dist/write/vectors/session-reachability.d.ts +133 -0
  182. package/dist/write/vectors/session-reachability.js +151 -0
  183. package/dist/write/vectors/session-reachability.js.map +1 -0
  184. package/dist/write/vectors/shortcuts.js +5 -14
  185. package/dist/write/vectors/shortcuts.js.map +1 -1
  186. package/dist/write/vectors/simulator.d.ts +16 -1
  187. package/dist/write/vectors/simulator.js +122 -32
  188. package/dist/write/vectors/simulator.js.map +1 -1
  189. package/dist/write/vectors/types.d.ts +183 -10
  190. package/dist/write/vectors/ui-recipes.d.ts +8 -0
  191. package/dist/write/vectors/ui-recipes.js +246 -58
  192. package/dist/write/vectors/ui-recipes.js.map +1 -1
  193. package/dist/write/vectors/ui.d.ts +156 -14
  194. package/dist/write/vectors/ui.js +846 -84
  195. package/dist/write/vectors/ui.js.map +1 -1
  196. package/dist/write/verify/delta.d.ts +12 -14
  197. package/dist/write/verify/delta.js +35 -34
  198. package/dist/write/verify/delta.js.map +1 -1
  199. package/dist/write/verify/poller.d.ts +13 -0
  200. package/dist/write/verify/poller.js +38 -0
  201. package/dist/write/verify/poller.js.map +1 -1
  202. package/package.json +8 -1
  203. package/schema/envelope.schema.json +22 -0
  204. package/scripts/build-helpers.sh +104 -0
  205. package/scripts/deputy-cert-setup.sh +60 -0
  206. package/skills/things-cli/SKILL.md +11 -3
  207. package/skills/things-cli/references/errors.md +4 -0
  208. package/skills/things-cli/references/repeating.md +69 -0
@@ -4,6 +4,7 @@
4
4
  * the lab (url-scheme.matrix / applescript.matrix), never hardcoded logic.
5
5
  */
6
6
  import type { DisruptionTier } from "../../config.ts";
7
+ import type { HazardId } from "../guards.ts";
7
8
  import type { OperationKind } from "../operations.ts";
8
9
  export type VectorId = "url-scheme" | "applescript" | "shortcuts" | "ui";
9
10
  export interface CompiledInvocation {
@@ -46,6 +47,18 @@ export interface UiRecipe {
46
47
  /** The item the recipe acts on (revealed/selected via things:///show?id=). */
47
48
  targetUuid: string;
48
49
  steps: UiStep[];
50
+ /**
51
+ * DIALOG-class recipe: it opens a SHEET on the main Things window (the Repeat
52
+ * editor, the Convert confirm, the Move picker) and waits for it through the
53
+ * Accessibility tree. Such a recipe needs a Things window that is AX-reachable
54
+ * on the current Space — on a locked screen or in a full-screen app's Space
55
+ * the sheet opens on an unreachable window and the wait times out (SESSGATE,
56
+ * #480). The driver runs a session-reachability probe after the reveal and
57
+ * refuses (`blocked`) when the window is unreachable. Menu-only recipes (todo
58
+ * pause/resume — a pure menu-item press that works even under lock, AXVM1) do
59
+ * NOT set this and are never gated.
60
+ */
61
+ needsWindowReachability?: boolean;
49
62
  }
50
63
  export type UiPrimitive = "reveal" | "activate" | "resolve" | "press" | "set-value" | "select-popup" | "wait" | "key"
51
64
  /**
@@ -94,17 +107,84 @@ export type UiPrimitive = "reveal" | "activate" | "resolve" | "press" | "set-val
94
107
  */
95
108
  | "select-heading-row"
96
109
  /**
97
- * Set the Repeat dialog's date/time control (the reminder time, the "ends on
98
- * date" bound) an `AXDateTimeArea` whose value is an NSDate, NOT a text
99
- * field (UIC6). System Events cannot set it (`set value to <date>` errors
100
- * -10000), so the driver sets `AXValue` to an NSDate through the ObjC bridge
101
- * (JXA), the same bridge the mouse-synthesis primitive rides. `value` is the
102
- * spec: `time:HH:mm` (keep the control's date, set the time-of-day, for the
103
- * reminder) or `date:YYYY-MM-DD` (set the calendar date, for the end bound).
104
- * The control is located by role within the open dialog and fails closed if
105
- * it is absent.
110
+ * Assert the reveal actually landed an ELIGIBLE selection before a menu press
111
+ * (ADR1, issue #480). A `things:///show?id=<uuid>` reveal is assumed to select
112
+ * the to-do row, but on some surfaces (a future-scheduled to-do in Upcoming, an
113
+ * area view) it may navigate without leaving the row selected and an AXPress
114
+ * on the resulting DISABLED `Items Repeat…` "succeeds" as a silent no-op, so
115
+ * the dialog never opens and the drive dies at the dialog-wait timeout with no
116
+ * hint of the real cause. This step closes that gap fail-closed: it reads back
117
+ * `Things3 id of selected to dos` and requires EXACTLY the target uuid to be
118
+ * selected, then reads the addressed menu item's `AXEnabled`. It returns "OK"
119
+ * only when the target is the sole selection AND the menu item is enabled;
120
+ * otherwise it returns a diagnostic (`NOTSEL…`/`WRONGSEL…`/`DISABLED…`) the
121
+ * driver surfaces as an EARLY, named failure. `value` is the target uuid; `path`
122
+ * the menu item to enabled-check. Pure System Events, background-capable.
123
+ */
124
+ | "assert-eligible"
125
+ /**
126
+ * Set one of the Repeat dialog's date/time controls — each an `AXDateTimeArea`
127
+ * whose value is an NSDate, NOT a text field (UIC6). System Events cannot set
128
+ * it (`set value … to <date>` errors -10000), so the driver sets `AXValue` to
129
+ * an NSDate through the ObjC bridge (JXA), the same bridge the mouse-synthesis
130
+ * primitive rides. `value` is the spec: `time:HH:mm` (keep the control's date,
131
+ * set the time-of-day) or `date:YYYY-MM-DD` (set the calendar date).
132
+ *
133
+ * A fixed rule can expose up to THREE date areas at once — "Next:" (the first
134
+ * occurrence), the "Ends: on date" bound, and the reminder time (ANCH2 census,
135
+ * docs/lab/anch2-next-field.md) — so the target is chosen DETERMINISTICALLY by
136
+ * {@link UiStep.dtTarget}, never "the first AXDateTimeArea by role" (that
137
+ * ambiguity was the §8v collapse + the UIC6-g reminder mis-verdict). The
138
+ * reminder is the only time-bearing area; among the midnight date pickers the
139
+ * "Next" field is the top row and the "Ends" field the bottom row. Fails
140
+ * closed if the addressed control is absent.
141
+ */
142
+ | "set-datetime"
143
+ /**
144
+ * Converge a dialog CHECKBOX to a target state via a deterministic closed loop
145
+ * (RRD1): read the checkbox's `AXValue` (0/1), press ONLY when the observed
146
+ * state differs from the requested {@link UiStep.checkboxTarget}, then re-read to
147
+ * confirm it landed — never a blind toggle. This is what makes the Repeat
148
+ * dialog's "Add deadlines" / "Add reminders" checkboxes safe on a PRE-POPULATED
149
+ * reschedule dialog: the dialog opens with the item's CURRENT deadline/reminder
150
+ * state already reflected, so an unconditional press flips an already-correct box
151
+ * the wrong way (the live bug — a blind "Add deadlines" press UNCHECKED an
152
+ * already-deadlined rule, hiding the "start N days earlier" field it had already
153
+ * revealed). Only fields the caller actually requested emit a step; an
154
+ * unspecified `--deadline` / `--reminder` on reschedule emits NO step, so the
155
+ * pre-populated state is PRESERVED (requested-fields-only law, #492). Fails
156
+ * closed (an `error` the pipeline re-verifies) if the box will not converge
157
+ * within the bounded retries.
158
+ */
159
+ | "ensure-checkbox"
160
+ /**
161
+ * MEASURE which shape the open Repeat dialog is (RDLG2) and remember it for
162
+ * the rest of the drive. Emitted right before the first shape-dependent step;
163
+ * a dialog matching neither known shape aborts the drive fail-closed rather
164
+ * than press structural indexes it cannot vouch for.
165
+ */
166
+ | "probe-dialog-shape"
167
+ /**
168
+ * Choose the first occurrence from the Things 3.23 `Next:` pop-up — a bounded
169
+ * MENU of `Today` plus the rule's own upcoming occurrences (cascading through
170
+ * `More…` submenus), not a date field (RDLG2). The driver matches the request
171
+ * against each item's parsed date, descends the cascade, clicks the match, and
172
+ * reads the pop-up back. A date the rule never produces is UNREACHABLE in this
173
+ * dialog and fails closed — 3.23 replaced the free-form first-occurrence field
174
+ * the ≤3.22 `set-datetime next` drive wrote.
106
175
  */
107
- | "set-datetime";
176
+ | "select-next-occurrence"
177
+ /**
178
+ * Converge the weekly dialog's weekday ROWS onto an exact target set through a
179
+ * deterministic closed loop (RDLG2, the RRD1 fix): read the live row count,
180
+ * press the row-add button until there are at least as many rows as target
181
+ * weekdays, assign EVERY row from the target set (cycling, so a surplus row
182
+ * duplicates a target weekday instead of keeping a stale one — the app stores
183
+ * the weekdays as a set), then read every row back and confirm the set matches.
184
+ * Replaces the blind first-row-then-"+" drive, which left a pre-populated
185
+ * dialog's stale weekdays in the committed rule.
186
+ */
187
+ | "converge-weekdays";
108
188
  export interface UiStep {
109
189
  primitive: UiPrimitive;
110
190
  /** Human-readable step label — surfaced in the partial-state report. */
@@ -173,7 +253,58 @@ export interface UiStep {
173
253
  activateFallback?: boolean;
174
254
  /** drag-reorder only: the sidebar move the drag driver performs. */
175
255
  drag?: import("./ui-drag.ts").SidebarDragSpec;
256
+ /**
257
+ * set-datetime only: WHICH of the dialog's date areas to drive (ANCH2). The
258
+ * driver selects deterministically — `reminder` = the only time-bearing area;
259
+ * `next` = the top (smaller-y) midnight date picker; `ends` = the bottom
260
+ * (larger-y) midnight date picker. Required for every set-datetime step.
261
+ */
262
+ dtTarget?: "next" | "ends" | "reminder";
263
+ /**
264
+ * ensure-checkbox only: the desired checkbox state. The driver reads the
265
+ * control's `AXValue` and presses ONLY when it differs from this target, then
266
+ * confirms convergence (RRD1 closed loop). Required for every ensure-checkbox step.
267
+ */
268
+ checkboxTarget?: boolean;
269
+ /**
270
+ * Run this step ONLY under the named Repeat-dialog shape (RDLG2). The two
271
+ * shapes present the FIRST-OCCURRENCE control as different element CLASSES —
272
+ * an `AXDateTimeArea` (legacy) versus an `AXPopUpButton` (next-popup) — so the
273
+ * recipe emits BOTH drives and the driver executes the one matching the shape
274
+ * its `probe-dialog-shape` step measured. A step carrying this field with no
275
+ * shape probed fails closed.
276
+ */
277
+ onlyShape?: RepeatDialogShape;
278
+ /**
279
+ * Per-shape overrides merged into the step once the dialog shape is probed
280
+ * (RDLG2). The 3.23 `Next:` pop-up sits between Ends and every per-frequency
281
+ * control, shifting their group indices by +1 — so the SAME step carries both
282
+ * index sets and the driver picks by measured structure, never by app version.
283
+ * A step carrying this field whose probed shape has no entry fails closed.
284
+ */
285
+ shaped?: Partial<Record<RepeatDialogShape, {
286
+ pathCandidates?: string[];
287
+ value?: string;
288
+ }>>;
176
289
  }
290
+ /**
291
+ * The structural SHAPE of the Repeat dialog, MEASURED live (never sniffed from
292
+ * the app version — a version string says nothing about the tree the driver has
293
+ * to address, and a point release can move either way):
294
+ *
295
+ * - `next-popup` — Things 3.23+: the first occurrence is an `AXPopUpButton`
296
+ * listing Today + the rule's own upcoming occurrences; it sits between Ends and
297
+ * the per-frequency controls, so those are at +1.
298
+ * - `legacy` — Things ≤ 3.22: the first occurrence is a free-form
299
+ * `AXDateTimeArea` and the per-frequency controls follow Ends directly.
300
+ *
301
+ * Both shapes label that row `Next:` (measured on 3.22.14 and 3.23 alike), so the
302
+ * probe discriminates on the CONTROL CLASS occupying the row, not the label.
303
+ *
304
+ * Anything matching NEITHER shape is a third, unknown dialog — the drive
305
+ * refuses rather than press indexes it cannot vouch for.
306
+ */
307
+ export type RepeatDialogShape = "next-popup" | "legacy";
177
308
  export interface VectorSupport {
178
309
  support: "yes" | "partial" | "no";
179
310
  /**
@@ -200,11 +331,53 @@ export interface ExecuteResult {
200
331
  stderr: string;
201
332
  /** The transport was killed by its own deadline — the signature of an unanswered consent dialog. */
202
333
  timedOut?: boolean;
334
+ /**
335
+ * The vector REFUSED at runtime BEFORE touching the app — a precondition it
336
+ * can only check live (the ui vector's session-reachability gate: a locked
337
+ * screen / full-screen Space leaves no AX-reachable Things window for the
338
+ * dialog, SESSGATE #480). The pipeline maps this to a `blocked` outcome
339
+ * (exit 4), never a transport failure — nothing was mutated.
340
+ */
341
+ blocked?: {
342
+ hazard: HazardId;
343
+ detail: string;
344
+ remediation: string;
345
+ };
346
+ /**
347
+ * The ui vector's overall-drive WATCHDOG fired: the drive exceeded its budget
348
+ * so the CLI — not the caller — gave up first, cleared any open dialog, and
349
+ * returned (TRACE1, #487). Carried alongside a nonzero `exitCode` + `timedOut`
350
+ * so the pipeline routes it through the existing transport-failure re-verify
351
+ * (a mid-commit OK may still have landed), then shapes an HONEST timeout:
352
+ * confirmed-landed → ok with a disclosure; not-confirmed → verify-failed with
353
+ * `uncertain` set and the trace path, since a drive aborted mid-commit cannot
354
+ * promise the app is untouched. See {@link drive}.
355
+ */
356
+ watchdog?: {
357
+ budgetMs: number;
358
+ elapsedMs: number;
359
+ /** The step the drive was about to run (or running) when the budget blew. */
360
+ lastStep: string;
361
+ /** How the open dialog was cleaned up (SESSGATE clearDialog outcome). */
362
+ clear: "dismissed" | "cleared-blind" | "may-remain";
363
+ /** The local trace file reconstructing the timeline, when tracing is on. */
364
+ tracePath?: string | null;
365
+ };
203
366
  }
204
367
  export interface WriteVector {
205
368
  id: VectorId;
206
369
  matrix: VectorMatrix;
207
370
  execute(invocation: CompiledInvocation): Promise<ExecuteResult>;
371
+ /**
372
+ * ui vector ONLY: probe whether a Things window is AX-reachable on the current
373
+ * Space, so a promote ORCHESTRATOR can gate BEFORE it seeds a row (SESSGATE
374
+ * #480). It returns a not-reachable verdict scoped "session" (locked screen /
375
+ * full-screen — the certain-failure case the orchestrator refuses on, zero
376
+ * mutation) or "window" (only Things' window is off-Space — the orchestrator
377
+ * proceeds; the in-drive gate relocates it). Absent on the real transport
378
+ * vectors and the simulator, so a caller with no ui vector simply skips the gate.
379
+ */
380
+ probeReachability?: () => Promise<import("./session-reachability.ts").ReachabilityVerdict>;
208
381
  /**
209
382
  * The bench-harness SIMULATOR vector (src/write/vectors/simulator.ts). It
210
383
  * presents under a real {@link VectorId} but applies mutations via SQL from
@@ -38,6 +38,14 @@ export interface RepeatDialogRule {
38
38
  reminder?: string;
39
39
  deadline?: boolean;
40
40
  startDaysEarlier?: number;
41
+ /**
42
+ * The requested FIRST occurrence (ISO `YYYY-MM-DD`), driven into the dialog's
43
+ * "Next:" date field (ANCH2, issue #476). The default value of Next is the
44
+ * app's today-anchored first match; overwriting it makes the series start on
45
+ * the requested date verbatim (subsequent occurrences follow the rule). Omit
46
+ * to accept the app default. Not applicable to after-completion (no calendar).
47
+ */
48
+ next?: string;
41
49
  }
42
50
  export declare function pauseRepeatRecipe(targetUuid: string): UiRecipe;
43
51
  export declare function resumeRepeatRecipe(targetUuid: string): UiRecipe;