things-api 0.11.0 → 0.13.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 +16 -5
  2. package/dist/audit/schema.d.ts +7 -0
  3. package/dist/audit/schema.js.map +1 -1
  4. package/dist/cli/canonical-ref.d.ts +21 -0
  5. package/dist/cli/canonical-ref.js +23 -0
  6. package/dist/cli/canonical-ref.js.map +1 -0
  7. package/dist/cli/commands/area.d.ts +18 -11
  8. package/dist/cli/commands/area.js +81 -77
  9. package/dist/cli/commands/area.js.map +1 -1
  10. package/dist/cli/commands/doctor.d.ts +1 -2
  11. package/dist/cli/commands/doctor.js +11 -1
  12. package/dist/cli/commands/doctor.js.map +1 -1
  13. package/dist/cli/commands/install-skill.d.ts +19 -4
  14. package/dist/cli/commands/install-skill.js +130 -52
  15. package/dist/cli/commands/install-skill.js.map +1 -1
  16. package/dist/cli/commands/mcp.js +21 -1
  17. package/dist/cli/commands/mcp.js.map +1 -1
  18. package/dist/cli/commands/project.d.ts +1 -0
  19. package/dist/cli/commands/project.js +92 -48
  20. package/dist/cli/commands/project.js.map +1 -1
  21. package/dist/cli/commands/reads.d.ts +5 -1
  22. package/dist/cli/commands/reads.js +110 -31
  23. package/dist/cli/commands/reads.js.map +1 -1
  24. package/dist/cli/commands/setup.js +11 -4
  25. package/dist/cli/commands/setup.js.map +1 -1
  26. package/dist/cli/commands/show.js +75 -36
  27. package/dist/cli/commands/show.js.map +1 -1
  28. package/dist/cli/commands/todo.js +2 -2
  29. package/dist/cli/commands/todo.js.map +1 -1
  30. package/dist/cli/commands/writes.js +795 -144
  31. package/dist/cli/commands/writes.js.map +1 -1
  32. package/dist/cli/did-you-mean.d.ts +14 -3
  33. package/dist/cli/did-you-mean.js +44 -7
  34. package/dist/cli/did-you-mean.js.map +1 -1
  35. package/dist/cli/dry-run.d.ts +55 -0
  36. package/dist/cli/dry-run.js +92 -0
  37. package/dist/cli/dry-run.js.map +1 -0
  38. package/dist/cli/glyphs.d.ts +16 -2
  39. package/dist/cli/glyphs.js +60 -12
  40. package/dist/cli/glyphs.js.map +1 -1
  41. package/dist/cli/help.js +69 -13
  42. package/dist/cli/help.js.map +1 -1
  43. package/dist/cli/main.js +8 -1
  44. package/dist/cli/main.js.map +1 -1
  45. package/dist/cli/move-hint.d.ts +3 -2
  46. package/dist/cli/move-hint.js +2 -2
  47. package/dist/cli/move-hint.js.map +1 -1
  48. package/dist/cli/read-driver.d.ts +53 -5
  49. package/dist/cli/read-driver.js +82 -15
  50. package/dist/cli/read-driver.js.map +1 -1
  51. package/dist/cli/ref-render.d.ts +14 -0
  52. package/dist/cli/ref-render.js +9 -0
  53. package/dist/cli/ref-render.js.map +1 -0
  54. package/dist/cli/render.d.ts +40 -14
  55. package/dist/cli/render.js +128 -55
  56. package/dist/cli/render.js.map +1 -1
  57. package/dist/cli/resolve-invocation.d.ts +7 -5
  58. package/dist/cli/resolve-invocation.js +16 -7
  59. package/dist/cli/resolve-invocation.js.map +1 -1
  60. package/dist/cli/skill-check.d.ts +12 -6
  61. package/dist/cli/skill-check.js +31 -14
  62. package/dist/cli/skill-check.js.map +1 -1
  63. package/dist/cli/skill.d.ts +8 -0
  64. package/dist/cli/skill.js +10 -0
  65. package/dist/cli/skill.js.map +1 -1
  66. package/dist/cli/verb-hint.js +1 -1
  67. package/dist/cli/verb-hint.js.map +1 -1
  68. package/dist/client.d.ts +158 -26
  69. package/dist/client.js +254 -38
  70. package/dist/client.js.map +1 -1
  71. package/dist/config.d.ts +66 -2
  72. package/dist/config.js +120 -12
  73. package/dist/config.js.map +1 -1
  74. package/dist/contracts.d.ts +187 -28
  75. package/dist/contracts.js +22 -1
  76. package/dist/contracts.js.map +1 -1
  77. package/dist/db/baselines/db-v26.js +4 -1
  78. package/dist/db/baselines/db-v26.js.map +1 -1
  79. package/dist/diagnose.d.ts +34 -2
  80. package/dist/diagnose.js +36 -1
  81. package/dist/diagnose.js.map +1 -1
  82. package/dist/index.d.ts +21 -8
  83. package/dist/index.js +26 -3
  84. package/dist/index.js.map +1 -1
  85. package/dist/mcp/server.d.ts +9 -0
  86. package/dist/mcp/server.js +790 -322
  87. package/dist/mcp/server.js.map +1 -1
  88. package/dist/model/entities.d.ts +57 -4
  89. package/dist/model/entities.js.map +1 -1
  90. package/dist/model/mappers.d.ts +2 -0
  91. package/dist/model/mappers.js +44 -2
  92. package/dist/model/mappers.js.map +1 -1
  93. package/dist/model/recurrence.d.ts +8 -1
  94. package/dist/model/recurrence.js.map +1 -1
  95. package/dist/model/serialize.js +15 -3
  96. package/dist/model/serialize.js.map +1 -1
  97. package/dist/read/area-filter.d.ts +76 -0
  98. package/dist/read/area-filter.js +58 -0
  99. package/dist/read/area-filter.js.map +1 -0
  100. package/dist/read/area-view.d.ts +22 -11
  101. package/dist/read/area-view.js +54 -28
  102. package/dist/read/area-view.js.map +1 -1
  103. package/dist/read/detail.js +15 -8
  104. package/dist/read/detail.js.map +1 -1
  105. package/dist/read/predicates.d.ts +18 -0
  106. package/dist/read/predicates.js +19 -0
  107. package/dist/read/predicates.js.map +1 -1
  108. package/dist/read/project-view.d.ts +91 -15
  109. package/dist/read/project-view.js +135 -37
  110. package/dist/read/project-view.js.map +1 -1
  111. package/dist/read/pseudo-area.d.ts +29 -0
  112. package/dist/read/pseudo-area.js +27 -0
  113. package/dist/read/pseudo-area.js.map +1 -0
  114. package/dist/read/queries.d.ts +175 -19
  115. package/dist/read/queries.js +376 -32
  116. package/dist/read/queries.js.map +1 -1
  117. package/dist/read/scope.d.ts +126 -0
  118. package/dist/read/scope.js +161 -0
  119. package/dist/read/scope.js.map +1 -0
  120. package/dist/read/search-rank.d.ts +2 -5
  121. package/dist/read/shape.d.ts +181 -0
  122. package/dist/read/shape.js +737 -0
  123. package/dist/read/shape.js.map +1 -0
  124. package/dist/read/show-target.d.ts +9 -1
  125. package/dist/read/show-target.js +77 -17
  126. package/dist/read/show-target.js.map +1 -1
  127. package/dist/read/stage.d.ts +199 -0
  128. package/dist/read/stage.js +125 -0
  129. package/dist/read/stage.js.map +1 -0
  130. package/dist/read/truncation.d.ts +7 -12
  131. package/dist/read/truncation.js +56 -21
  132. package/dist/read/truncation.js.map +1 -1
  133. package/dist/read/views.d.ts +68 -16
  134. package/dist/read/views.js +206 -52
  135. package/dist/read/views.js.map +1 -1
  136. package/dist/surface-copy.d.ts +16 -0
  137. package/dist/surface-copy.js +16 -0
  138. package/dist/surface-copy.js.map +1 -1
  139. package/dist/write/batch.d.ts +49 -10
  140. package/dist/write/batch.js +423 -71
  141. package/dist/write/batch.js.map +1 -1
  142. package/dist/write/commands.js +268 -55
  143. package/dist/write/commands.js.map +1 -1
  144. package/dist/write/guards.d.ts +1 -1
  145. package/dist/write/guards.js +71 -10
  146. package/dist/write/guards.js.map +1 -1
  147. package/dist/write/heading.d.ts +10 -1
  148. package/dist/write/heading.js +35 -5
  149. package/dist/write/heading.js.map +1 -1
  150. package/dist/write/make-repeating-project.d.ts +2 -2
  151. package/dist/write/make-repeating-project.js +9 -9
  152. package/dist/write/make-repeating-project.js.map +1 -1
  153. package/dist/write/move.d.ts +134 -0
  154. package/dist/write/move.js +1874 -0
  155. package/dist/write/move.js.map +1 -0
  156. package/dist/write/operations.d.ts +105 -19
  157. package/dist/write/operations.js +56 -7
  158. package/dist/write/operations.js.map +1 -1
  159. package/dist/write/opid.d.ts +31 -0
  160. package/dist/write/opid.js +30 -0
  161. package/dist/write/opid.js.map +1 -0
  162. package/dist/write/pipeline.d.ts +70 -3
  163. package/dist/write/pipeline.js +198 -33
  164. package/dist/write/pipeline.js.map +1 -1
  165. package/dist/write/pre-state.d.ts +172 -8
  166. package/dist/write/pre-state.js +467 -25
  167. package/dist/write/pre-state.js.map +1 -1
  168. package/dist/write/reorder.d.ts +23 -3
  169. package/dist/write/reorder.js +2106 -86
  170. package/dist/write/reorder.js.map +1 -1
  171. package/dist/write/reversibility.js +19 -7
  172. package/dist/write/reversibility.js.map +1 -1
  173. package/dist/write/scope-guard.d.ts +31 -0
  174. package/dist/write/scope-guard.js +162 -0
  175. package/dist/write/scope-guard.js.map +1 -0
  176. package/dist/write/undo.js +120 -13
  177. package/dist/write/undo.js.map +1 -1
  178. package/dist/write/vectors/applescript.js +16 -7
  179. package/dist/write/vectors/applescript.js.map +1 -1
  180. package/dist/write/vectors/shortcuts.js +1 -1
  181. package/dist/write/vectors/shortcuts.js.map +1 -1
  182. package/dist/write/vectors/simulator.js +83 -27
  183. package/dist/write/vectors/simulator.js.map +1 -1
  184. package/dist/write/vectors/types.d.ts +11 -0
  185. package/dist/write/vectors/ui-certification.d.ts +3 -3
  186. package/dist/write/vectors/ui-certification.js +41 -5
  187. package/dist/write/vectors/ui-certification.js.map +1 -1
  188. package/dist/write/vectors/ui-drag.d.ts +21 -1
  189. package/dist/write/vectors/ui-drag.js +138 -27
  190. package/dist/write/vectors/ui-drag.js.map +1 -1
  191. package/dist/write/vectors/ui-recipes.d.ts +21 -1
  192. package/dist/write/vectors/ui-recipes.js +166 -7
  193. package/dist/write/vectors/ui-recipes.js.map +1 -1
  194. package/dist/write/vectors/ui.d.ts +25 -1
  195. package/dist/write/vectors/ui.js +142 -33
  196. package/dist/write/vectors/ui.js.map +1 -1
  197. package/dist/write/verify/delta.d.ts +17 -1
  198. package/dist/write/verify/delta.js +106 -29
  199. package/dist/write/verify/delta.js.map +1 -1
  200. package/package.json +7 -1
  201. package/schema/envelope.schema.json +397 -0
  202. package/skills/things-cli/SKILL.md +36 -17
  203. package/skills/things-cli/references/banner.md +35 -0
  204. package/skills/things-cli/references/contracts.md +32 -9
  205. package/skills/things-cli/references/errors.md +57 -0
  206. package/skills/things-cli/references/gui.md +1 -1
  207. package/skills/things-cli/references/model.md +18 -7
  208. package/skills/things-cli/references/ordering.md +88 -0
@@ -3,8 +3,9 @@
3
3
  * world BEFORE a mutation. One read pass, snapshot semantics per statement.
4
4
  */
5
5
  import type { DatabaseSync } from "node:sqlite";
6
- import type { AnyTask, Project, TaskStatus, TaskType, Todo } from "../model/entities.ts";
7
- import type { ContainerRef, ReorderParams } from "./operations.ts";
6
+ import { type IsoDate } from "../model/dates.ts";
7
+ import type { AnyTask, TaskStatus, TaskType, Todo } from "../model/entities.ts";
8
+ import type { ContainerRef, HeadingPlacement, ReorderParams } from "./operations.ts";
8
9
  export interface ResolvedContainer {
9
10
  uuid: string;
10
11
  title: string;
@@ -13,6 +14,14 @@ export interface ContainerResolution {
13
14
  resolved: ResolvedContainer | null;
14
15
  /** 0 = not found, 1 = ok, >1 = ambiguous title. */
15
16
  matches: number;
17
+ /**
18
+ * An honest not-found tail (`resolved === null && matches === 0`) when the NAME
19
+ * matched only non-open destination rows the resolver deliberately excludes —
20
+ * e.g. a completed/canceled project (which would strand an open child, PLOG1).
21
+ * Surfaced by H-UNKNOWN-DESTINATION so the caller learns the row exists and how
22
+ * to reach it (by uuid). Absent when the miss is a genuine no-match.
23
+ */
24
+ deadHint?: string;
16
25
  }
17
26
  export interface ReorderMember {
18
27
  uuid: string;
@@ -23,6 +32,16 @@ export interface ReorderMember {
23
32
  startBucket: number | null;
24
33
  /** 0 = to-do, 1 = project. */
25
34
  type: number;
35
+ /**
36
+ * Repeating TEMPLATE row (rt1_recurrenceRule or repeater set). Only the day-block
37
+ * scopes (`day`/`tomorrow`) admit templates as members (their projection is a
38
+ * first-class todayIndex member — TMPLSORT/PTMPL); every other scope's query keeps
39
+ * `NOT_TEMPLATE_ROW`, so this is always false there. The `day`/`tomorrow` dispatch
40
+ * reads it to split the per-class leg family (a TO-DO template rides a single-id
41
+ * `list "Upcoming"`/`list "Tomorrow"` native front-insert; a PROJECT template is
42
+ * byte-untouched under the suffix rule — never a when=/deadline leg, the §1 crash).
43
+ */
44
+ isTemplate: boolean;
26
45
  }
27
46
  export interface ReorderPre {
28
47
  /** Ordering key the scope ranks on. */
@@ -47,9 +66,25 @@ export interface ReorderPre {
47
66
  /** Full wire list: requested order first, remaining members after. */
48
67
  wireList: string[];
49
68
  }
69
+ /** area.delete: live member census of the area (non-trashed direct rows). */
70
+ export interface AreaMemberCounts {
71
+ /** Projects whose area FK is this area (trashed = 0). */
72
+ projects: number;
73
+ /** Direct to-dos in the area (trashed = 0, any status). */
74
+ todos: number;
75
+ }
50
76
  export interface PreState {
51
77
  /** Primary target for uuid-addressed operations. */
52
78
  target: AnyTask | null;
79
+ /**
80
+ * The response clock's local calendar date (guest/host clock), captured at
81
+ * pre-read. Feeds §9n reminder-liveness: the `when=` reminder auto-preserve
82
+ * (commands.ts `effectiveReminder`) gates a STALE reminder byte out against
83
+ * the target's CURRENT startDate under this date, rather than resurrecting a
84
+ * presentation-dead reminder. Defaults to the host today (emptyPreState); the
85
+ * date-bearing update preReads stamp the injected clock.
86
+ */
87
+ todayIso: IsoDate;
53
88
  destProject: ContainerResolution | null;
54
89
  /** Status of the resolved destination project (reopen hazard, T19). */
55
90
  destProjectStatus: TaskStatus | null;
@@ -70,6 +105,13 @@ export interface PreState {
70
105
  entityTarget: ContainerResolution | null;
71
106
  /** tag.delete: descendant tags that a delete would CASCADE onto (P16). */
72
107
  childTags: string[];
108
+ /**
109
+ * area.delete: live (non-trashed) member counts, direct to-dos and projects
110
+ * carrying the area's FK. A non-empty area's delete trashes its to-dos and
111
+ * takes its projects with it (A25/A25B), so the delete refuses unless the
112
+ * caller allows it. Null for non-area ops (and when the area did not resolve).
113
+ */
114
+ areaMembers: AreaMemberCounts | null;
73
115
  /** project.complete / project.cancel: children by pre-status. */
74
116
  openChildren: Todo[];
75
117
  canceledChildren: Todo[];
@@ -96,8 +138,25 @@ export interface PreState {
96
138
  * counts how many of these are dead post-op. Null for non-project ops.
97
139
  */
98
140
  repeatSubtreeUuids: string[] | null;
99
- /** heading.convert-to-project: the project-reveal + heading-row ordinal (HEADCERT1). */
141
+ /** project.promote-heading: the project-reveal + heading-row ordinal (HEADCERT1). */
100
142
  headingConvert: HeadingConvertTaxonomy | null;
143
+ /** project.move-heading: current heading order + computed target order. */
144
+ headingMove: HeadingMovePre | null;
145
+ /** project.move-heading-to-project: source reveal + heading + destination (HEADXPROJ). */
146
+ headingMoveToProject: HeadingMoveToProjectTaxonomy | null;
147
+ /** project.dissolve-heading: parent reveal + heading title + children (DISS1). */
148
+ headingDissolve: HeadingDissolveTaxonomy | null;
149
+ }
150
+ /** project.move-heading pre-computation (spec §2/§4). */
151
+ export interface HeadingMovePre {
152
+ /** Destination project resolution (the container the headings live in). */
153
+ project: ContainerResolution;
154
+ /** The project's non-trashed heading uuids in current display (index) order. */
155
+ current: string[];
156
+ /** Full target order after moving the block — feeds the native wire + delta. */
157
+ targetOrder: string[];
158
+ /** Reasons the move is illegal (empty = ok). */
159
+ problems: string[];
101
160
  }
102
161
  /**
103
162
  * Row-selection taxonomy for `project.make-repeating` (UIC4-f). A project is
@@ -133,6 +192,15 @@ export type ProjectRepeatTaxonomy = {
133
192
  detail: string;
134
193
  };
135
194
  export declare function emptyPreState(): PreState;
195
+ /**
196
+ * Read a project's current heading order and compute the FULL target order
197
+ * after moving `headings` (an ordered block) to the requested placement. The
198
+ * block lands contiguously in selection order; every other heading keeps its
199
+ * relative order. Children follow their heading on the wire (scf P1). Illegal
200
+ * requests (unknown/duplicated movee, an anchor that is a movee or absent)
201
+ * collect problems and leave the order unchanged.
202
+ */
203
+ export declare function computeHeadingMovePre(db: DatabaseSync, project: ContainerResolution, headings: string[], placement: HeadingPlacement): HeadingMovePre;
136
204
  /**
137
205
  * The uuids of a project's source subtree rows (non-trashed to-dos AND
138
206
  * headings, direct or heading-nested). `childrenReplaced` counts how many of
@@ -141,7 +209,7 @@ export declare function emptyPreState(): PreState;
141
209
  */
142
210
  export declare function projectSubtreeUuids(db: DatabaseSync, projectUuid: string): string[];
143
211
  /**
144
- * Taxonomy for `heading.convert-to-project`'s pure-AX drive (HEADCERT1). A
212
+ * Taxonomy for `project.promote-heading`'s pure-AX drive (HEADCERT1). A
145
213
  * heading is not selectable via `things:///show` (the reveal URL selects to-dos
146
214
  * only — the UIC1 blocker), but revealing the heading's PARENT PROJECT shows its
147
215
  * content table, in which the heading renders as a selectable ROW. The row
@@ -162,6 +230,74 @@ export type HeadingConvertTaxonomy = {
162
230
  detail: string;
163
231
  };
164
232
  export declare function classifyHeadingConvert(db: DatabaseSync, target: AnyTask | null): HeadingConvertTaxonomy;
233
+ /**
234
+ * Taxonomy for `project.move-heading-to-project`'s ellipsis-`Move…` drive
235
+ * (HEADXPROJ). Unlike the promote drive (positional), the heading row is
236
+ * TITLE-addressable: its `…` button is an AXUnknown whose AXDescription is
237
+ * `"More. <title>"`, so the recipe HID-clicks that button, then `Move…`, then
238
+ * TYPES the destination project title into the search picker and presses Return.
239
+ * Two collision surfaces therefore fail closed: (a) the SOURCE heading title is
240
+ * shared by another heading in the same project (the `"More. <title>"` node
241
+ * matches both — indistinguishable), and (b) the DESTINATION title is shared by
242
+ * another project (the picker is search-by-title — Return would pick the wrong
243
+ * row). A titleless heading is refused (its `"More. "` description matches every
244
+ * titleless heading). Verify oracle: the heading row's `project` FK becomes the
245
+ * destination (children follow via their intact heading FK — a single-row change).
246
+ */
247
+ export interface HeadingMoveToProjectPre {
248
+ /** Source project revealed via things:///show?id= to render the heading row. */
249
+ sourceProjectUuid: string;
250
+ /** The heading being moved (the verify oracle's target row). */
251
+ headingUuid: string;
252
+ /** The heading title — the `"More. <title>"` click target. */
253
+ headingTitle: string;
254
+ /** The destination project — the heading's `project` FK becomes this post-op. */
255
+ destProjectUuid: string;
256
+ /** The destination title typed into the Move… search picker. */
257
+ destProjectTitle: string;
258
+ }
259
+ export type HeadingMoveToProjectRefusal = "no-source" | "heading-not-found" | "heading-ambiguous" | "empty-heading-title" | "no-dest" | "dest-ambiguous" | "same-project";
260
+ export type HeadingMoveToProjectTaxonomy = {
261
+ kind: "ok";
262
+ pre: HeadingMoveToProjectPre;
263
+ } | {
264
+ kind: "refuse";
265
+ refusal: HeadingMoveToProjectRefusal;
266
+ detail: string;
267
+ candidates?: string[];
268
+ };
269
+ export declare function classifyHeadingMoveToProject(db: DatabaseSync, project: ContainerRef, headingSel: string, toProject: ContainerRef): HeadingMoveToProjectTaxonomy;
270
+ /**
271
+ * Taxonomy for `project.dissolve-heading`'s ellipsis-`Delete` drive (DISS1). Same
272
+ * title-addressed `"More. <title>"` reveal as the cross-project move, driving the
273
+ * popover's Delete instead of Move…. DISS1 (2026-07-28, Things 3.22.11): Delete
274
+ * HARD-DELETES the heading row (removed from TMTask) while its children become
275
+ * DIRECT project children (heading→NULL, project→the parent, index preserved,
276
+ * NOT trashed) — no confirm sheet. Contrast the Shortcuts delete cascade (P12),
277
+ * which TRASHES the children. Fails closed on a title shared by another heading in
278
+ * the project (the drive addresses by title) and on a titleless heading.
279
+ */
280
+ export interface HeadingDissolvePre {
281
+ /** Parent project revealed via things:///show?id= to render the heading row. */
282
+ projectReveal: string;
283
+ /** The heading being dissolved (the verify oracle's gone-target). */
284
+ headingUuid: string;
285
+ /** The heading title — the `"More. <title>"` click target. */
286
+ headingTitle: string;
287
+ /** Open children that become direct project children (for the result note). */
288
+ childUuids: string[];
289
+ }
290
+ export type HeadingDissolveRefusal = "not-a-heading" | "no-project" | "title-ambiguous" | "empty-title";
291
+ export type HeadingDissolveTaxonomy = {
292
+ kind: "ok";
293
+ pre: HeadingDissolvePre;
294
+ } | {
295
+ kind: "refuse";
296
+ refusal: HeadingDissolveRefusal;
297
+ detail: string;
298
+ candidates?: string[];
299
+ };
300
+ export declare function classifyHeadingDissolve(db: DatabaseSync, target: AnyTask | null): HeadingDissolveTaxonomy;
165
301
  /**
166
302
  * Classify a project for `project.make-repeating`'s pure-AX row-selection
167
303
  * recipe (UIC4-f), or refuse. Reads DB truth (area / start / template / status)
@@ -170,8 +306,19 @@ export declare function classifyHeadingConvert(db: DatabaseSync, target: AnyTask
170
306
  */
171
307
  export declare function classifyProjectRepeat(db: DatabaseSync, target: AnyTask | null): ProjectRepeatTaxonomy;
172
308
  export declare function resolveArea(db: DatabaseSync, ref: ContainerRef): ContainerResolution;
309
+ /**
310
+ * Resolve a project DESTINATION (`--to-project` / `--project` on add/move). NAME
311
+ * resolution is OPEN-only (`status = 0`) — a completed/canceled project is not a
312
+ * valid live destination by name: placing an open child there strands it (PLOG1,
313
+ * "a completed-in-place project strands children identically, one sweep later").
314
+ * A UUID / partial-uuid still reaches a completed project (explicit intent —
315
+ * `nameExtraWhere` narrows the NAME tiers only). When a name matches ONLY non-open
316
+ * projects, the resolution carries a `deadHint` so the destination not-found says
317
+ * the row exists and how to reach it (by uuid), instead of a bare "project not
318
+ * found".
319
+ */
173
320
  export declare function resolveProject(db: DatabaseSync, ref: ContainerRef): ContainerResolution;
174
- export declare function resolveHeading(db: DatabaseSync, projectUuid: string, headingTitle: string): ContainerResolution;
321
+ export declare function resolveHeading(db: DatabaseSync, projectUuid: string, headingSel: string): ContainerResolution;
175
322
  export declare function projectStatus(db: DatabaseSync, uuid: string): TaskStatus | null;
176
323
  export declare function resolveTag(db: DatabaseSync, ref: string): ContainerResolution;
177
324
  export declare function loadTarget(db: DatabaseSync, uuid: string): AnyTask | null;
@@ -194,6 +341,14 @@ export declare function projectChildren(db: DatabaseSync, projectUuid: string):
194
341
  * them. UNION (not UNION ALL): a parent cycle must terminate, not hang.
195
342
  */
196
343
  export declare function childTagTitles(db: DatabaseSync, tagUuid: string): string[];
344
+ /**
345
+ * Live member census for `area.delete` (A25/A25B). Counts the area's non-trashed
346
+ * DIRECT members: to-dos carrying the area FK (any status — a logged to-do is
347
+ * still trashed by the delete) and projects carrying the area FK. Deleting a
348
+ * non-empty area trashes the to-dos and takes the projects with it, so the guard
349
+ * uses these counts to refuse fail-closed unless the caller allows it.
350
+ */
351
+ export declare function areaMemberCounts(db: DatabaseSync, areaUuid: string): AreaMemberCounts;
197
352
  export declare function trashedCount(db: DatabaseSync): number;
198
353
  export declare function isRepeatingTemplate(task: AnyTask | null): boolean;
199
354
  /**
@@ -212,8 +367,6 @@ export declare function isRepeatingTemplate(task: AnyTask | null): boolean;
212
367
  * unprobed and the guard rejects them.
213
368
  * - inbox: unscheduled to-dos with no container (start=0), by "index"
214
369
  * (A6/P8a — the command ranks the sent list in order).
215
- * - headings: the HEADING rows (type=2) of a project, by "index" (scf P1 —
216
- * the private command accepts heading uuids; children follow).
217
370
  * - someday: loose someday to-dos AND area-less someday projects, by
218
371
  * "index"; same-type requests only. The Someday list handler is
219
372
  * anchor-stacked with OPPOSITE stack directions by row type:
@@ -224,4 +377,15 @@ export declare function isRepeatingTemplate(task: AnyTask | null): boolean;
224
377
  * when=anytime round-trip front-inserts (P8e).
225
378
  */
226
379
  export declare function computeReorderPre(db: DatabaseSync, params: ReorderParams, containerUuid: string | null, now: Date): ReorderPre;
227
- export declare function projectOf(task: AnyTask | null): Project | null;
380
+ /**
381
+ * A row's live Today/Evening flag — `"today"`, `"evening"`, or `null` — read
382
+ * from the SAME marker the `today`/`evening` reorder membership uses
383
+ * ({@link computeReorderPre}, O01/O03/§9n): an ARRIVED scheduled row
384
+ * (`start IN (1,2)` AND `startDate <= today`) carries the flag — `evening` at
385
+ * raw `startBucket=1` (a live evening flag expires daily, so a stale past-dated
386
+ * bucket-1 row reads `today` proper), `today` otherwise. Someday, anytime,
387
+ * inbox, and future-scheduled rows carry NO flag. Single-sourced here so any
388
+ * de-Today guard (e.g. the `projects` bounce's de-star refusal in reorder.ts)
389
+ * keys off the one marker and can never drift from the membership query.
390
+ */
391
+ export declare function todayEveningFlagOf(db: DatabaseSync, uuid: string, now: Date): "today" | "evening" | null;