things-api 0.5.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 (184) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -0
  3. package/bin/things.js +9 -0
  4. package/dist/audit/log.d.ts +10 -0
  5. package/dist/audit/log.js +31 -0
  6. package/dist/audit/log.js.map +1 -0
  7. package/dist/audit/schema.d.ts +37 -0
  8. package/dist/audit/schema.js +9 -0
  9. package/dist/audit/schema.js.map +1 -0
  10. package/dist/cli/commands/doctor.d.ts +9 -0
  11. package/dist/cli/commands/doctor.js +60 -0
  12. package/dist/cli/commands/doctor.js.map +1 -0
  13. package/dist/cli/commands/mcp.d.ts +7 -0
  14. package/dist/cli/commands/mcp.js +26 -0
  15. package/dist/cli/commands/mcp.js.map +1 -0
  16. package/dist/cli/commands/project.d.ts +5 -0
  17. package/dist/cli/commands/project.js +50 -0
  18. package/dist/cli/commands/project.js.map +1 -0
  19. package/dist/cli/commands/reads.d.ts +21 -0
  20. package/dist/cli/commands/reads.js +295 -0
  21. package/dist/cli/commands/reads.js.map +1 -0
  22. package/dist/cli/commands/snapshot.d.ts +7 -0
  23. package/dist/cli/commands/snapshot.js +22 -0
  24. package/dist/cli/commands/snapshot.js.map +1 -0
  25. package/dist/cli/commands/todo.d.ts +6 -0
  26. package/dist/cli/commands/todo.js +43 -0
  27. package/dist/cli/commands/todo.js.map +1 -0
  28. package/dist/cli/commands/writes.d.ts +9 -0
  29. package/dist/cli/commands/writes.js +994 -0
  30. package/dist/cli/commands/writes.js.map +1 -0
  31. package/dist/cli/exit-codes.d.ts +26 -0
  32. package/dist/cli/exit-codes.js +26 -0
  33. package/dist/cli/exit-codes.js.map +1 -0
  34. package/dist/cli/main.d.ts +4 -0
  35. package/dist/cli/main.js +73 -0
  36. package/dist/cli/main.js.map +1 -0
  37. package/dist/cli/output.d.ts +42 -0
  38. package/dist/cli/output.js +16 -0
  39. package/dist/cli/output.js.map +1 -0
  40. package/dist/cli/style.d.ts +6 -0
  41. package/dist/cli/style.js +25 -0
  42. package/dist/cli/style.js.map +1 -0
  43. package/dist/client.d.ts +184 -0
  44. package/dist/client.js +187 -0
  45. package/dist/client.js.map +1 -0
  46. package/dist/config.d.ts +31 -0
  47. package/dist/config.js +76 -0
  48. package/dist/config.js.map +1 -0
  49. package/dist/contracts.d.ts +79 -0
  50. package/dist/contracts.js +46 -0
  51. package/dist/contracts.js.map +1 -0
  52. package/dist/db/baselines/db-v26.d.ts +8 -0
  53. package/dist/db/baselines/db-v26.js +16 -0
  54. package/dist/db/baselines/db-v26.js.map +1 -0
  55. package/dist/db/baselines/index.d.ts +3 -0
  56. package/dist/db/baselines/index.js +4 -0
  57. package/dist/db/baselines/index.js.map +1 -0
  58. package/dist/db/connection.d.ts +22 -0
  59. package/dist/db/connection.js +40 -0
  60. package/dist/db/connection.js.map +1 -0
  61. package/dist/db/fingerprint.d.ts +42 -0
  62. package/dist/db/fingerprint.js +82 -0
  63. package/dist/db/fingerprint.js.map +1 -0
  64. package/dist/db/locate.d.ts +13 -0
  65. package/dist/db/locate.js +44 -0
  66. package/dist/db/locate.js.map +1 -0
  67. package/dist/db/schema.d.ts +37 -0
  68. package/dist/db/schema.js +81 -0
  69. package/dist/db/schema.js.map +1 -0
  70. package/dist/diagnose.d.ts +67 -0
  71. package/dist/diagnose.js +143 -0
  72. package/dist/diagnose.js.map +1 -0
  73. package/dist/index.d.ts +46 -0
  74. package/dist/index.js +23 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/mcp/server.d.ts +8 -0
  77. package/dist/mcp/server.js +1002 -0
  78. package/dist/mcp/server.js.map +1 -0
  79. package/dist/model/dates.d.ts +38 -0
  80. package/dist/model/dates.js +104 -0
  81. package/dist/model/dates.js.map +1 -0
  82. package/dist/model/entities.d.ts +117 -0
  83. package/dist/model/entities.js +21 -0
  84. package/dist/model/entities.js.map +1 -0
  85. package/dist/model/mappers.d.ts +55 -0
  86. package/dist/model/mappers.js +105 -0
  87. package/dist/model/mappers.js.map +1 -0
  88. package/dist/model/occurrences.d.ts +46 -0
  89. package/dist/model/occurrences.js +164 -0
  90. package/dist/model/occurrences.js.map +1 -0
  91. package/dist/model/recurrence.d.ts +52 -0
  92. package/dist/model/recurrence.js +164 -0
  93. package/dist/model/recurrence.js.map +1 -0
  94. package/dist/paths.d.ts +6 -0
  95. package/dist/paths.js +30 -0
  96. package/dist/paths.js.map +1 -0
  97. package/dist/read/detail.d.ts +8 -0
  98. package/dist/read/detail.js +34 -0
  99. package/dist/read/detail.js.map +1 -0
  100. package/dist/read/project-view.d.ts +34 -0
  101. package/dist/read/project-view.js +87 -0
  102. package/dist/read/project-view.js.map +1 -0
  103. package/dist/read/queries.d.ts +39 -0
  104. package/dist/read/queries.js +134 -0
  105. package/dist/read/queries.js.map +1 -0
  106. package/dist/read/snapshot.d.ts +25 -0
  107. package/dist/read/snapshot.js +39 -0
  108. package/dist/read/snapshot.js.map +1 -0
  109. package/dist/read/tags.d.ts +17 -0
  110. package/dist/read/tags.js +64 -0
  111. package/dist/read/tags.js.map +1 -0
  112. package/dist/read/views.d.ts +152 -0
  113. package/dist/read/views.js +322 -0
  114. package/dist/read/views.js.map +1 -0
  115. package/dist/surface-copy.d.ts +15 -0
  116. package/dist/surface-copy.js +16 -0
  117. package/dist/surface-copy.js.map +1 -0
  118. package/dist/write/automation-probe.d.ts +12 -0
  119. package/dist/write/automation-probe.js +59 -0
  120. package/dist/write/automation-probe.js.map +1 -0
  121. package/dist/write/batch.d.ts +51 -0
  122. package/dist/write/batch.js +97 -0
  123. package/dist/write/batch.js.map +1 -0
  124. package/dist/write/capabilities.d.ts +16 -0
  125. package/dist/write/capabilities.js +16 -0
  126. package/dist/write/capabilities.js.map +1 -0
  127. package/dist/write/commands.d.ts +32 -0
  128. package/dist/write/commands.js +1274 -0
  129. package/dist/write/commands.js.map +1 -0
  130. package/dist/write/environment.d.ts +29 -0
  131. package/dist/write/environment.js +105 -0
  132. package/dist/write/environment.js.map +1 -0
  133. package/dist/write/experimental.d.ts +7 -0
  134. package/dist/write/experimental.js +39 -0
  135. package/dist/write/experimental.js.map +1 -0
  136. package/dist/write/failure-hints.d.ts +32 -0
  137. package/dist/write/failure-hints.js +71 -0
  138. package/dist/write/failure-hints.js.map +1 -0
  139. package/dist/write/guards.d.ts +21 -0
  140. package/dist/write/guards.js +312 -0
  141. package/dist/write/guards.js.map +1 -0
  142. package/dist/write/lock.d.ts +10 -0
  143. package/dist/write/lock.js +70 -0
  144. package/dist/write/lock.js.map +1 -0
  145. package/dist/write/operations.d.ts +262 -0
  146. package/dist/write/operations.js +34 -0
  147. package/dist/write/operations.js.map +1 -0
  148. package/dist/write/pipeline.d.ts +90 -0
  149. package/dist/write/pipeline.js +375 -0
  150. package/dist/write/pipeline.js.map +1 -0
  151. package/dist/write/planner.d.ts +40 -0
  152. package/dist/write/planner.js +57 -0
  153. package/dist/write/planner.js.map +1 -0
  154. package/dist/write/pre-state.d.ts +125 -0
  155. package/dist/write/pre-state.js +299 -0
  156. package/dist/write/pre-state.js.map +1 -0
  157. package/dist/write/reopen.d.ts +29 -0
  158. package/dist/write/reopen.js +63 -0
  159. package/dist/write/reopen.js.map +1 -0
  160. package/dist/write/reorder.d.ts +19 -0
  161. package/dist/write/reorder.js +285 -0
  162. package/dist/write/reorder.js.map +1 -0
  163. package/dist/write/undo.d.ts +53 -0
  164. package/dist/write/undo.js +703 -0
  165. package/dist/write/undo.js.map +1 -0
  166. package/dist/write/vectors/applescript.d.ts +5 -0
  167. package/dist/write/vectors/applescript.js +216 -0
  168. package/dist/write/vectors/applescript.js.map +1 -0
  169. package/dist/write/vectors/registry.d.ts +2 -0
  170. package/dist/write/vectors/registry.js +11 -0
  171. package/dist/write/vectors/registry.js.map +1 -0
  172. package/dist/write/vectors/types.d.ts +48 -0
  173. package/dist/write/vectors/types.js +2 -0
  174. package/dist/write/vectors/types.js.map +1 -0
  175. package/dist/write/vectors/url-scheme.d.ts +3 -0
  176. package/dist/write/vectors/url-scheme.js +176 -0
  177. package/dist/write/vectors/url-scheme.js.map +1 -0
  178. package/dist/write/verify/delta.d.ts +126 -0
  179. package/dist/write/verify/delta.js +281 -0
  180. package/dist/write/verify/delta.js.map +1 -0
  181. package/dist/write/verify/poller.d.ts +24 -0
  182. package/dist/write/verify/poller.js +28 -0
  183. package/dist/write/verify/poller.js.map +1 -0
  184. package/package.json +52 -0
@@ -0,0 +1,299 @@
1
+ import { encodePackedDate, localToday } from "../model/dates.js";
2
+ import { TASK_STATUS_FROM_DB } from "../model/entities.js";
3
+ import { byUuid } from "../read/detail.js";
4
+ export function emptyPreState() {
5
+ return {
6
+ target: null,
7
+ destProject: null,
8
+ destProjectStatus: null,
9
+ destArea: null,
10
+ destHeading: null,
11
+ missingTags: [],
12
+ parentTag: null,
13
+ entityTarget: null,
14
+ childTags: [],
15
+ openChildren: [],
16
+ canceledChildren: [],
17
+ completedChildren: [],
18
+ checklistCount: 0,
19
+ trashedCount: 0,
20
+ existingEntityUuids: [],
21
+ sameTitleUuids: [],
22
+ reorder: null,
23
+ };
24
+ }
25
+ function resolveByTitleOrUuid(db, table, ref) {
26
+ const byId = db.prepare(`SELECT uuid, title FROM ${table} WHERE uuid = ?`).get(ref);
27
+ if (byId !== undefined)
28
+ return { resolved: byId, matches: 1 };
29
+ const rows = db
30
+ .prepare(`SELECT uuid, title FROM ${table} WHERE title = ? COLLATE NOCASE`)
31
+ .all(ref);
32
+ const first = rows[0];
33
+ return {
34
+ resolved: rows.length === 1 && first !== undefined ? first : null,
35
+ matches: rows.length,
36
+ };
37
+ }
38
+ export function resolveArea(db, ref) {
39
+ return resolveByTitleOrUuid(db, "TMArea", ref.uuid ?? ref.title ?? "");
40
+ }
41
+ export function resolveProject(db, ref) {
42
+ const key = ref.uuid ?? ref.title ?? "";
43
+ const byId = db
44
+ .prepare("SELECT uuid, title FROM TMTask WHERE uuid = ? AND type = 1 AND trashed = 0")
45
+ .get(key);
46
+ if (byId !== undefined)
47
+ return { resolved: byId, matches: 1 };
48
+ const rows = db
49
+ .prepare("SELECT uuid, title FROM TMTask WHERE title = ? COLLATE NOCASE AND type = 1 AND trashed = 0")
50
+ .all(key);
51
+ const first = rows[0];
52
+ return {
53
+ resolved: rows.length === 1 && first !== undefined ? first : null,
54
+ matches: rows.length,
55
+ };
56
+ }
57
+ export function resolveHeading(db, projectUuid, headingTitle) {
58
+ const rows = db
59
+ .prepare("SELECT uuid, title FROM TMTask WHERE type = 2 AND trashed = 0 AND project = ? AND title = ? COLLATE NOCASE")
60
+ .all(projectUuid, headingTitle);
61
+ const first = rows[0];
62
+ return {
63
+ resolved: rows.length === 1 && first !== undefined ? first : null,
64
+ matches: rows.length,
65
+ };
66
+ }
67
+ export function projectStatus(db, uuid) {
68
+ const row = db.prepare("SELECT status FROM TMTask WHERE uuid = ? AND type = 1").get(uuid);
69
+ if (row === undefined)
70
+ return null;
71
+ return TASK_STATUS_FROM_DB[row.status] ?? null;
72
+ }
73
+ export function missingTagTitles(db, titles) {
74
+ return titles.filter((t) => db.prepare("SELECT 1 FROM TMTag WHERE title = ? COLLATE NOCASE").get(t) === undefined);
75
+ }
76
+ export function resolveTag(db, ref) {
77
+ return resolveByTitleOrUuid(db, "TMTag", ref);
78
+ }
79
+ export function loadTarget(db, uuid) {
80
+ return byUuid(db, uuid);
81
+ }
82
+ export function projectChildren(db, projectUuid) {
83
+ const rows = db
84
+ .prepare("SELECT uuid FROM TMTask WHERE type = 0 AND trashed = 0 AND (project = ? OR heading IN " +
85
+ "(SELECT uuid FROM TMTask WHERE type = 2 AND project = ?))")
86
+ .all(projectUuid, projectUuid);
87
+ const todos = [];
88
+ for (const r of rows) {
89
+ const t = byUuid(db, r.uuid);
90
+ if (t !== null && t.type === "to-do")
91
+ todos.push(t);
92
+ }
93
+ return todos;
94
+ }
95
+ /**
96
+ * Titles of every DESCENDANT tag under the given tag (excluding itself).
97
+ * Deleting the parent CASCADE-DELETES all of these (P16) — the guard lists
98
+ * them. UNION (not UNION ALL): a parent cycle must terminate, not hang.
99
+ */
100
+ export function childTagTitles(db, tagUuid) {
101
+ const rows = db
102
+ .prepare(`WITH RECURSIVE d(uuid) AS (
103
+ SELECT ? UNION SELECT t.uuid FROM TMTag t JOIN d ON t.parent = d.uuid
104
+ )
105
+ SELECT t.title FROM TMTag t JOIN d ON t.uuid = d.uuid WHERE t.uuid != ?`)
106
+ .all(tagUuid, tagUuid);
107
+ return rows.map((r) => r.title);
108
+ }
109
+ export function trashedCount(db) {
110
+ const row = db.prepare("SELECT COUNT(*) AS n FROM TMTask WHERE trashed = 1").get();
111
+ return row.n;
112
+ }
113
+ export function isRepeatingTemplate(task) {
114
+ return task !== null && task.type !== "heading" && task.repeating.isTemplate;
115
+ }
116
+ const NOT_TEMPLATE_ROW = "(rt1_recurrenceRule IS NULL AND repeater IS NULL)";
117
+ /**
118
+ * Scope membership + full wire list for `reorder`. Eligibility mirrors the
119
+ * lab evidence exactly:
120
+ * - today: Today members with raw startBucket=0, to-dos AND projects
121
+ * (O01/O03/O12), by todayIndex. Bucket-1 members are listed as
122
+ * rejected candidates — including one silently de-evenings it
123
+ * (O03), so the guard refuses.
124
+ * - evening: raw startBucket=1 AND startDate == today exactly (evening
125
+ * membership expires daily), by todayIndex. Bounce-only (O03).
126
+ * - project: un-headed open to-do children, by "index" (O04/O09/O11);
127
+ * headed children are rejected candidates (O06 rips them out).
128
+ * - area: direct open area to-dos (O05/O10) AND projects (O14), by
129
+ * "index" — but only SAME-TYPE requests; mixed wire lists are
130
+ * unprobed and the guard rejects them.
131
+ * - inbox: unscheduled to-dos with no container (start=0), by "index"
132
+ * (A6/P8a — the command ranks the sent list in order).
133
+ * - headings: the HEADING rows (type=2) of a project, by "index" (scf P1 —
134
+ * the private command accepts heading uuids; children follow).
135
+ * - someday: loose someday to-dos (start=2, no startDate, no container), by
136
+ * "index". The Someday list handler is anchor-stacked (P6h/P7e/
137
+ * P8b) — the compiler emits the validated two-call protocol.
138
+ * Someday PROJECTS moved inconsistently across probes (P7a vs
139
+ * P8c) and are rejected candidates until locked.
140
+ * - projects: TOP-LEVEL sidebar projects (type=1, no area, start=1,
141
+ * undated), by "index". Bounce-only: a when=someday ->
142
+ * when=anytime round-trip front-inserts (P8e).
143
+ */
144
+ export function computeReorderPre(db, params, containerUuid, now) {
145
+ const todayIso = localToday(now);
146
+ const packedToday = encodePackedDate(todayIso);
147
+ const key = params.scope === "today" || params.scope === "evening" ? "todayIndex" : "index";
148
+ const select = (where, binds, rankCol) => db
149
+ .prepare(`SELECT uuid, title, ${rankCol} AS rank, startBucket, type FROM TMTask
150
+ WHERE trashed = 0 AND status = 0 AND ${NOT_TEMPLATE_ROW} AND ${where}
151
+ ORDER BY ${rankCol} ASC`)
152
+ .all(...binds);
153
+ let members = [];
154
+ const rejectedCandidates = new Map();
155
+ switch (params.scope) {
156
+ case "today":
157
+ case "evening": {
158
+ const all = select("type IN (0, 1) AND startDate IS NOT NULL AND startDate <= ? AND start IN (1, 2)", [packedToday], "todayIndex");
159
+ if (params.scope === "today") {
160
+ members = all.filter((m) => m.startBucket === 0);
161
+ for (const m of all) {
162
+ if (m.startBucket === 1) {
163
+ rejectedCandidates.set(m.uuid, "is an evening-bucket item — a native Today reorder would silently de-evening " +
164
+ "it (O03); use scope 'evening' for it instead");
165
+ }
166
+ }
167
+ }
168
+ else {
169
+ // Evening membership expires daily: only exact-today bucket-1 rows.
170
+ members = all.filter((m) => m.startBucket === 1 && rowStartDate(db, m.uuid) === packedToday);
171
+ for (const m of all) {
172
+ if (!members.some((e) => e.uuid === m.uuid)) {
173
+ rejectedCandidates.set(m.uuid, m.startBucket === 1
174
+ ? "is a STALE evening item (startDate in the past) — it renders in Today " +
175
+ "proper; re-schedule it before reordering"
176
+ : "is in the Today section, not This Evening — use scope 'today'");
177
+ }
178
+ }
179
+ }
180
+ break;
181
+ }
182
+ case "project": {
183
+ members = select("type = 0 AND heading IS NULL AND project = ?", [containerUuid ?? ""], `"index"`);
184
+ const headed = db
185
+ .prepare(`SELECT t.uuid FROM TMTask t JOIN TMTask h ON t.heading = h.uuid
186
+ WHERE t.trashed = 0 AND t.type = 0 AND h.project = ?`)
187
+ .all(containerUuid ?? "");
188
+ for (const r of headed) {
189
+ rejectedCandidates.set(r.uuid, "is inside a heading — a project-scope reorder RIPS headed children out of " +
190
+ "their heading (O06); heading-scoped ordering is not automatable");
191
+ }
192
+ break;
193
+ }
194
+ case "area": {
195
+ members = select("type IN (0, 1) AND heading IS NULL AND area = ?", [containerUuid ?? ""], `"index"`);
196
+ break;
197
+ }
198
+ case "inbox": {
199
+ // Inbox = unscheduled to-dos with no container (start=0, A6). Ranks on
200
+ // "index"; the private command re-ranks the full wire list exactly.
201
+ members = select("type = 0 AND start = 0", [], `"index"`);
202
+ break;
203
+ }
204
+ case "headings": {
205
+ members = select("type = 2 AND project = ?", [containerUuid ?? ""], `"index"`);
206
+ break;
207
+ }
208
+ case "someday": {
209
+ members = select("type = 0 AND start = 2 AND startDate IS NULL AND project IS NULL AND area IS NULL " +
210
+ "AND heading IS NULL", [], `"index"`);
211
+ const projects = db
212
+ .prepare(`SELECT uuid FROM TMTask WHERE trashed = 0 AND status = 0 AND type = 1
213
+ AND start = 2 AND startDate IS NULL`)
214
+ .all();
215
+ for (const r of projects) {
216
+ rejectedCandidates.set(r.uuid, "is a someday PROJECT — the Someday handler moved projects inconsistently across " +
217
+ "probes (P7a/P8c); only loose someday to-dos reorder in this scope");
218
+ }
219
+ break;
220
+ }
221
+ case "projects": {
222
+ members = select("type = 1 AND area IS NULL AND start = 1 AND startDate IS NULL", [], `"index"`);
223
+ const others = db
224
+ .prepare(`SELECT uuid, area, start, startDate FROM TMTask
225
+ WHERE trashed = 0 AND status = 0 AND type = 1
226
+ AND NOT (area IS NULL AND start = 1 AND startDate IS NULL)`)
227
+ .all();
228
+ for (const r of others) {
229
+ rejectedCandidates.set(r.uuid, r.area !== null
230
+ ? "lives in an area — use scope 'area' (projects within an area reorder natively, O14)"
231
+ : "is not a plain Anytime project — the bounce round-trip (when=someday -> " +
232
+ "when=anytime) only preserves state for undated start=anytime projects (P8e)");
233
+ }
234
+ break;
235
+ }
236
+ }
237
+ const seen = new Set();
238
+ const duplicates = [];
239
+ for (const uuid of params.uuids) {
240
+ if (seen.has(uuid) && !duplicates.includes(uuid))
241
+ duplicates.push(uuid);
242
+ seen.add(uuid);
243
+ }
244
+ const memberSet = new Map(members.map((m) => [m.uuid, m]));
245
+ const rejected = [];
246
+ const projectMembers = [];
247
+ for (const uuid of params.uuids) {
248
+ const member = memberSet.get(uuid);
249
+ if (member === undefined) {
250
+ rejected.push({
251
+ uuid,
252
+ reason: rejectedCandidates.get(uuid) ?? "is not an open member of this scope",
253
+ });
254
+ continue;
255
+ }
256
+ if (member.type === 1)
257
+ projectMembers.push(uuid);
258
+ }
259
+ const requestedTypes = new Set(params.uuids.map((u) => memberSet.get(u)?.type).filter((t) => t !== undefined));
260
+ const mixedTypes = params.scope === "area" && requestedTypes.size > 1;
261
+ // Area scope pins ONLY the requested type's cohort: to-dos and projects
262
+ // rank on "index" independently in the sidebar, and a mixed wire list is
263
+ // unprobed (O05/O10 vs O14) — same-type extension keeps the send inside
264
+ // validated territory. Other scopes extend with every member (today's
265
+ // mixed to-do+project wire list IS validated, O12).
266
+ const uniformType = params.scope === "area" && requestedTypes.size === 1;
267
+ const requestedType = [...requestedTypes][0];
268
+ const requested = new Set(params.uuids);
269
+ const wireList = [
270
+ ...params.uuids,
271
+ ...members
272
+ .filter((m) => !requested.has(m.uuid))
273
+ .filter((m) => !uniformType || m.type === requestedType)
274
+ .map((m) => m.uuid),
275
+ ];
276
+ return {
277
+ key,
278
+ members: members.map((m) => ({
279
+ uuid: m.uuid,
280
+ title: m.title,
281
+ rank: m.rank,
282
+ startBucket: m.startBucket,
283
+ type: m.type,
284
+ })),
285
+ rejected,
286
+ duplicates,
287
+ projectMembers,
288
+ mixedTypes,
289
+ wireList,
290
+ };
291
+ }
292
+ function rowStartDate(db, uuid) {
293
+ const row = db.prepare("SELECT startDate FROM TMTask WHERE uuid = ?").get(uuid);
294
+ return row?.startDate ?? null;
295
+ }
296
+ export function projectOf(task) {
297
+ return task !== null && task.type === "project" ? task : null;
298
+ }
299
+ //# sourceMappingURL=pre-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pre-state.js","sourceRoot":"","sources":["../../src/write/pre-state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * project.reopen orchestrator. The bare op reopens ONLY the project row
3
+ * (P02/P05 — the app leaves cascade-resolved children resolved). With
4
+ * restoreChildren, children that were resolved BY THE CASCADE are reopened
5
+ * too, identified by the P03-validated timing window: same resolved status
6
+ * as the project and a stopDate within CASCADE_WINDOW_SECONDS of the
7
+ * project's. Each child reopen is a full verified mutation.
8
+ */
9
+ import { type MutationResult, type WriteDeps, type WriteOptions } from "./pipeline.ts";
10
+ /** P03: cascade writes stamp children within <2s of the project row. */
11
+ export declare const CASCADE_WINDOW_SECONDS = 2;
12
+ export interface ProjectReopenResult {
13
+ project: MutationResult;
14
+ /** Per-child verified reopen results (restoreChildren only). */
15
+ children: {
16
+ uuid: string;
17
+ title: string;
18
+ result: MutationResult;
19
+ }[];
20
+ }
21
+ export interface ProjectReopenOptions extends WriteOptions {
22
+ /**
23
+ * Also reopen children the completion/cancellation cascade resolved —
24
+ * detected via the stopDate window. Children resolved at other times
25
+ * (e.g. finished days earlier) are never touched (P04 semantics).
26
+ */
27
+ restoreChildren?: boolean;
28
+ }
29
+ export declare function runProjectReopen(deps: WriteDeps, uuid: string, options?: ProjectReopenOptions): Promise<ProjectReopenResult>;
@@ -0,0 +1,63 @@
1
+ /**
2
+ * project.reopen orchestrator. The bare op reopens ONLY the project row
3
+ * (P02/P05 — the app leaves cascade-resolved children resolved). With
4
+ * restoreChildren, children that were resolved BY THE CASCADE are reopened
5
+ * too, identified by the P03-validated timing window: same resolved status
6
+ * as the project and a stopDate within CASCADE_WINDOW_SECONDS of the
7
+ * project's. Each child reopen is a full verified mutation.
8
+ */
9
+ import { runMutation } from "./pipeline.js";
10
+ /** P03: cascade writes stamp children within <2s of the project row. */
11
+ export const CASCADE_WINDOW_SECONDS = 2;
12
+ function cascadeCandidates(deps, projectUuid) {
13
+ return deps.db
14
+ .prepare(`SELECT c.uuid, c.title FROM TMTask c
15
+ JOIN TMTask p ON p.uuid = ?
16
+ WHERE c.trashed = 0 AND c.type = 0 AND c.status = p.status AND c.status != 0
17
+ AND c.stopDate IS NOT NULL AND p.stopDate IS NOT NULL
18
+ AND abs(c.stopDate - p.stopDate) < ?
19
+ AND (c.project = p.uuid OR c.heading IN
20
+ (SELECT uuid FROM TMTask WHERE type = 2 AND project = p.uuid))`)
21
+ .all(projectUuid, CASCADE_WINDOW_SECONDS);
22
+ }
23
+ export async function runProjectReopen(deps, uuid, options = {}) {
24
+ const { restoreChildren, ...writeOptions } = options;
25
+ // Candidates must be computed BEFORE the reopen clears the project's
26
+ // stopDate (the window is relative to it).
27
+ const candidates = restoreChildren === true ? cascadeCandidates(deps, uuid) : [];
28
+ const project = await runMutation(deps, "project.reopen", { uuid }, writeOptions);
29
+ const children = [];
30
+ if (project.kind === "ok" || project.kind === "dry-run") {
31
+ for (const child of candidates) {
32
+ if (project.kind === "dry-run") {
33
+ children.push({
34
+ uuid: child.uuid,
35
+ title: child.title,
36
+ result: {
37
+ kind: "dry-run",
38
+ op: "todo.reopen",
39
+ plan: {
40
+ op: "todo.reopen",
41
+ vector: "applescript",
42
+ tier: 0,
43
+ invocation: `(cascade restore) reopen ${child.title}`,
44
+ expectedDelta: {
45
+ mode: "state",
46
+ uuid: child.uuid,
47
+ assert: [{ field: "status", equals: "open" }],
48
+ },
49
+ hazardsChecked: [],
50
+ },
51
+ },
52
+ });
53
+ continue;
54
+ }
55
+ const result = await runMutation(deps, "todo.reopen", { uuid: child.uuid }, writeOptions);
56
+ children.push({ uuid: child.uuid, title: child.title, result });
57
+ if (result.kind !== "ok")
58
+ break; // stop compounding on a failed leg
59
+ }
60
+ }
61
+ return { project, children };
62
+ }
63
+ //# sourceMappingURL=reopen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reopen.js","sourceRoot":"","sources":["../../src/write/reopen.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAA0D,MAAM,eAAe,CAAC;AAEpG,wEAAwE;AACxE,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAsBxC,SAAS,iBAAiB,CAAC,IAAe,EAAE,WAAmB;IAC7D,OAAO,IAAI,CAAC,EAAE;SACX,OAAO,CACN;;;;;;6EAMuE,CACxE;SACA,GAAG,CAAC,WAAW,EAAE,sBAAsB,CAAkC,CAAC;AAC/E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAe,EACf,IAAY,EACZ,UAAgC,EAAE;IAElC,MAAM,EAAE,eAAe,EAAE,GAAG,YAAY,EAAE,GAAG,OAAO,CAAC;IACrD,qEAAqE;IACrE,2CAA2C;IAC3C,MAAM,UAAU,GAAG,eAAe,KAAK,IAAI,CAAC,CAAC,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAEjF,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,gBAAgB,EAAE,EAAE,IAAI,EAAE,EAAE,YAAY,CAAC,CAAC;IAClF,MAAM,QAAQ,GAAoC,EAAE,CAAC;IACrD,IAAI,OAAO,CAAC,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QACxD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAC/B,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC/B,QAAQ,CAAC,IAAI,CAAC;oBACZ,IAAI,EAAE,KAAK,CAAC,IAAI;oBAChB,KAAK,EAAE,KAAK,CAAC,KAAK;oBAClB,MAAM,EAAE;wBACN,IAAI,EAAE,SAAS;wBACf,EAAE,EAAE,aAAa;wBACjB,IAAI,EAAE;4BACJ,EAAE,EAAE,aAAa;4BACjB,MAAM,EAAE,aAAa;4BACrB,IAAI,EAAE,CAAC;4BACP,UAAU,EAAE,4BAA4B,KAAK,CAAC,KAAK,EAAE;4BACrD,aAAa,EAAE;gCACb,IAAI,EAAE,OAAO;gCACb,IAAI,EAAE,KAAK,CAAC,IAAI;gCAChB,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;6BAC9C;4BACD,cAAc,EAAE,EAAE;yBACnB;qBACF;iBACF,CAAC,CAAC;gBACH,SAAS;YACX,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,YAAY,CAAC,CAAC;YAC1F,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAChE,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI;gBAAE,MAAM,CAAC,mCAAmC;QACtE,CAAC;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { ReorderParams } from "./operations.ts";
2
+ import { type MutationResult, type WriteDeps, type WriteOptions } from "./pipeline.ts";
3
+ /**
4
+ * Bounce cost is 2 verified mutations per item; beyond this the today scope
5
+ * should use the native strategy and the evening scope should be re-thought.
6
+ */
7
+ export declare const BOUNCE_MAX_ITEMS = 10;
8
+ export type ReorderResult = MutationResult | {
9
+ kind: "bounce-aborted";
10
+ op: "reorder";
11
+ detail: string;
12
+ /** Uuids already placed (they ARE at the top, in requested order). */
13
+ placed: string[];
14
+ /** Uuids not yet placed (still in their prior positions). */
15
+ remaining: string[];
16
+ /** The failing leg's result when a mutation failed (null = state check). */
17
+ cause: MutationResult | null;
18
+ };
19
+ export declare function runReorder(deps: WriteDeps, params: ReorderParams, options?: WriteOptions): Promise<ReorderResult>;