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,375 @@
1
+ /**
2
+ * The mutation pipeline: fingerprint gate → lock → pre-read → guards →
3
+ * vector planning → ensure-running → execute → verified read-after-write →
4
+ * audit. Every mutation attempt is audited, including blocked decisions.
5
+ */
6
+ import { execFile, execFileSync } from "node:child_process";
7
+ import { localToday } from "../model/dates.js";
8
+ import { COMMANDS } from "./commands.js";
9
+ import { describeEnvironmentChanges, diffEnvironment, } from "./environment.js";
10
+ import { sdefDeclaresPrivateReorder } from "./experimental.js";
11
+ import { classifyTransportFailure, classifyVerifyFailure, } from "./failure-hints.js";
12
+ import { evaluateGuards } from "./guards.js";
13
+ import { acquireMutationLock, MutationLockError } from "./lock.js";
14
+ import { planVector } from "./planner.js";
15
+ import { createDbReader, evaluateDelta, getField, } from "./verify/delta.js";
16
+ import { pollUntilVerified } from "./verify/poller.js";
17
+ export function readAuthToken(db) {
18
+ try {
19
+ const row = db.prepare("SELECT uriSchemeAuthenticationToken AS t FROM TMSettings").get();
20
+ return row?.t ?? null;
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ function defaultIsAppRunning() {
27
+ try {
28
+ execFileSync("pgrep", ["-x", "Things3"], { stdio: "ignore" });
29
+ return true;
30
+ }
31
+ catch {
32
+ return false;
33
+ }
34
+ }
35
+ /** Background-launch Things and wait for the process (tier 1, by policy). */
36
+ async function defaultEnsureRunning(alreadyRunning) {
37
+ if (alreadyRunning)
38
+ return true;
39
+ await new Promise((resolve) => {
40
+ execFile("open", ["-g", "-a", "Things3"], () => resolve());
41
+ });
42
+ const deadline = Date.now() + 20_000;
43
+ while (Date.now() < deadline) {
44
+ if (defaultIsAppRunning()) {
45
+ await new Promise((r) => setTimeout(r, 2000)); // post-launch settle
46
+ return true;
47
+ }
48
+ await new Promise((r) => setTimeout(r, 250));
49
+ }
50
+ return false;
51
+ }
52
+ /** Capture pre-values of asserted fields + movement tripwires for the spec. */
53
+ function capturePre(spec, deps, pre) {
54
+ const reader = createDbReader(deps.db);
55
+ const modDates = {};
56
+ const fields = {};
57
+ const captureFor = (uuid, assertions) => {
58
+ modDates[uuid] = reader.modDateOf(uuid);
59
+ const entity = reader.taskByUuid(uuid);
60
+ const captured = {};
61
+ for (const a of assertions) {
62
+ captured[a.field] = entity === null ? undefined : (getField(entity, a.field) ?? null);
63
+ }
64
+ fields[uuid] = captured;
65
+ };
66
+ if (spec.mode === "update" || spec.mode === "state") {
67
+ captureFor(spec.uuid, spec.assert);
68
+ if (spec.mode === "state" && spec.cascade !== undefined) {
69
+ for (const c of spec.cascade)
70
+ captureFor(c.uuid, c.assert);
71
+ }
72
+ }
73
+ if (spec.mode === "ordering") {
74
+ const preRanks = {};
75
+ for (const uuid of spec.sequence)
76
+ preRanks[uuid] = reader.rankOf(uuid, spec.key);
77
+ fields["__ordering__"] = preRanks;
78
+ }
79
+ if (spec.mode === "entity-updated") {
80
+ const current = reader.entityFields(spec.entity, spec.uuid);
81
+ const captured = {};
82
+ for (const a of spec.assert)
83
+ captured[a.field] = current?.[a.field] ?? null;
84
+ fields[spec.uuid] = captured;
85
+ }
86
+ if (spec.mode === "trash-emptied") {
87
+ return { modDates, fields, trashedCount: pre.trashedCount };
88
+ }
89
+ return { modDates, fields };
90
+ }
91
+ export async function runMutation(deps, op, params, options = {}) {
92
+ const startedAt = deps.now?.() ?? new Date();
93
+ const spec = COMMANDS[op];
94
+ const config = deps.config;
95
+ const actor = options.actor ?? config.actor;
96
+ const maxDisruption = options.maxDisruption ?? config.maxDisruption;
97
+ const audit = (partial) => {
98
+ const fp = deps.fingerprint();
99
+ const record = {
100
+ v: 1,
101
+ ts: startedAt.toISOString(),
102
+ actor,
103
+ host: config.host,
104
+ op,
105
+ uuid: null,
106
+ vector: null,
107
+ disruption: null,
108
+ invocation: null,
109
+ requested: params,
110
+ pre: null,
111
+ observed: null,
112
+ verify: null,
113
+ durationMs: (deps.now?.() ?? new Date()).getTime() - startedAt.getTime(),
114
+ env: {
115
+ pkg: deps.pkgVersion ?? "0.0.1",
116
+ dbVersion: fp.observation.databaseVersion,
117
+ fingerprint: fingerprintLabel(fp, config),
118
+ },
119
+ ...partial,
120
+ };
121
+ deps.audit.append(record);
122
+ };
123
+ // 1. Drift gate: writes hard-block on fingerprint mismatch.
124
+ const fp = deps.fingerprint();
125
+ const fpLabel = fingerprintLabel(fp, config);
126
+ if (fpLabel === "drift" || fpLabel === "unknown") {
127
+ const detail = fp.kind === "unknown-version"
128
+ ? `unknown database version ${fp.observation.databaseVersion ?? "?"} (newer Things?)`
129
+ : "schema fingerprint deviates from the shipped baseline";
130
+ audit({ result: "blocked:drift" });
131
+ return {
132
+ kind: "blocked",
133
+ op,
134
+ reason: "drift",
135
+ likelyCause: "schema-drift",
136
+ detail,
137
+ remediation: "update things-api to a release with a matching baseline, or (at your own risk) " +
138
+ "`things config set accepted-fingerprint <observed hash>` after reviewing `things doctor`",
139
+ };
140
+ }
141
+ // 2. Serialize mutations (create-probe verification must never race).
142
+ let lock;
143
+ try {
144
+ lock = await acquireMutationLock(deps.lockPath);
145
+ }
146
+ catch (err) {
147
+ if (err instanceof MutationLockError) {
148
+ audit({ result: "blocked:lock" });
149
+ return {
150
+ kind: "blocked",
151
+ op,
152
+ reason: "lock",
153
+ detail: err.message,
154
+ remediation: "wait for the concurrent mutation to finish and retry",
155
+ };
156
+ }
157
+ throw err;
158
+ }
159
+ try {
160
+ // 3. Pre-read + guards.
161
+ const pre = spec.preRead(deps.db, params, deps.now?.() ?? new Date());
162
+ const acks = {
163
+ ...(options.acknowledgeChecklistReset !== undefined && {
164
+ acknowledgeChecklistReset: options.acknowledgeChecklistReset,
165
+ }),
166
+ ...(options.acknowledgeProjectReopen !== undefined && {
167
+ acknowledgeProjectReopen: options.acknowledgeProjectReopen,
168
+ }),
169
+ ...(options.dangerouslyPermanent !== undefined && {
170
+ dangerouslyPermanent: options.dangerouslyPermanent,
171
+ }),
172
+ ...(options.acknowledgeTagSubtree !== undefined && {
173
+ acknowledgeTagSubtree: options.acknowledgeTagSubtree,
174
+ }),
175
+ };
176
+ const block = evaluateGuards(spec.hazards, {
177
+ op,
178
+ params: params,
179
+ pre,
180
+ acks,
181
+ });
182
+ if (block !== null) {
183
+ audit({ result: `blocked:${block.hazard}` });
184
+ return {
185
+ kind: "blocked",
186
+ op,
187
+ reason: "hazard",
188
+ hazard: block.hazard,
189
+ detail: block.detail,
190
+ remediation: block.remediation,
191
+ };
192
+ }
193
+ // 4. Vector planning under the disruption policy.
194
+ const appRunning = (deps.isAppRunning ?? defaultIsAppRunning)();
195
+ const plan = planVector(op, deps.vectors, {
196
+ maxDisruption,
197
+ appRunning,
198
+ allowExperimental: config.allowExperimental,
199
+ ...(options.vector !== undefined && { forcedVector: options.vector }),
200
+ });
201
+ if (plan.kind === "unsupported") {
202
+ audit({ result: "unsupported" });
203
+ return { kind: "unsupported", op, considered: plan.considered };
204
+ }
205
+ if (plan.kind === "tier-blocked") {
206
+ audit({ result: "blocked:disruption-tier" });
207
+ return {
208
+ kind: "blocked",
209
+ op,
210
+ reason: "disruption-tier",
211
+ detail: `operation needs disruption tier ${plan.requiredTier} ` +
212
+ `(app ${appRunning ? "running" : "closed — launch required"}), ` +
213
+ `policy allows ${plan.maxDisruption}`,
214
+ remediation: "pass --allow-disruptive / raise maxDisruption, or launch Things first",
215
+ };
216
+ }
217
+ const { vector, effectiveTier } = plan.candidate;
218
+ // 4b. Experimental canary: the private sdef command can vanish in any
219
+ // Things update — re-check the declaration before every dispatch.
220
+ if (plan.candidate.support.experimental === true) {
221
+ const declared = (deps.sdefProbe ?? sdefDeclaresPrivateReorder)();
222
+ if (!declared) {
223
+ audit({ result: "blocked:environment" });
224
+ return {
225
+ kind: "blocked",
226
+ op,
227
+ reason: "environment",
228
+ detail: "the installed Things no longer declares the private reorder command in its " +
229
+ "sdef — the experimental surface has likely been removed by an app update",
230
+ remediation: "check `things doctor`, file/track the change, and fall back to the bounce " +
231
+ "strategy where available",
232
+ };
233
+ }
234
+ }
235
+ // 5. Compile + expected delta.
236
+ const nowEpoch = Math.floor((deps.now?.() ?? new Date()).getTime() / 1000);
237
+ const token = readAuthToken(deps.db);
238
+ const invocation = spec.compile(params, vector.id, pre, { token });
239
+ const delta = spec.expectedDelta(pre, params, {
240
+ nowEpoch,
241
+ todayIso: localToday(deps.now?.() ?? new Date()),
242
+ });
243
+ if (options.dryRun === true) {
244
+ return {
245
+ kind: "dry-run",
246
+ op,
247
+ plan: {
248
+ op,
249
+ vector: vector.id,
250
+ tier: effectiveTier,
251
+ invocation: invocation.redactedPayload,
252
+ expectedDelta: delta,
253
+ hazardsChecked: spec.hazards,
254
+ },
255
+ };
256
+ }
257
+ // 6. Ensure the app is running in the BACKGROUND before dispatch —
258
+ // plain opens and AppleEvents to a closed Things steal focus (A40/A41).
259
+ const running = await (deps.ensureRunning ?? defaultEnsureRunning)(appRunning);
260
+ if (!running) {
261
+ audit({ result: "blocked:environment" });
262
+ return {
263
+ kind: "blocked",
264
+ op,
265
+ reason: "environment",
266
+ detail: "Things did not become available after a background launch attempt",
267
+ remediation: "launch Things manually and retry",
268
+ };
269
+ }
270
+ // 7. Execute + verify. The environment tuple diff feeds failure
271
+ // attribution (a changed tuple is the classic consent re-prompt trigger)
272
+ // and, on success, a warning + refreshed recording.
273
+ const envChanges = deps.environment !== undefined
274
+ ? diffEnvironment(deps.environment.load(), deps.environment.capture())
275
+ : [];
276
+ const withHint = (base, hint) => hint === null ? base : { ...base, likelyCause: hint.likelyCause, hint: hint.hint };
277
+ const preCapture = capturePre(delta, deps, pre);
278
+ const executeResult = await vector.execute(invocation);
279
+ if (executeResult.exitCode !== 0 || executeResult.timedOut === true) {
280
+ audit({
281
+ result: "verify-failed:silent-noop",
282
+ vector: vector.id,
283
+ disruption: effectiveTier,
284
+ invocation: invocation.redactedPayload,
285
+ pre: flattenPreFields(preCapture.fields),
286
+ });
287
+ return withHint({
288
+ kind: "verify-failed",
289
+ op,
290
+ reason: "silent-noop",
291
+ expected: delta,
292
+ observed: null,
293
+ detail: `transport failed (exit ${executeResult.exitCode ?? "?"}${executeResult.timedOut === true ? ", timed out" : ""}): ${executeResult.stderr.trim()}`,
294
+ }, classifyTransportFailure({
295
+ vector: vector.id,
296
+ stderr: executeResult.stderr,
297
+ timedOut: executeResult.timedOut === true,
298
+ environmentChanges: envChanges,
299
+ }));
300
+ }
301
+ const reader = createDbReader(deps.db);
302
+ const timeoutMs = options.verifyTimeoutMs ?? (appRunning ? 6000 : 10_000);
303
+ const outcome = await pollUntilVerified(() => evaluateDelta(delta, reader, preCapture), timeoutMs, deps.poller ?? {});
304
+ const auditCommon = {
305
+ vector: vector.id,
306
+ disruption: effectiveTier,
307
+ invocation: invocation.redactedPayload,
308
+ pre: flattenPreFields(preCapture.fields),
309
+ observed: outcome.observed,
310
+ verify: { attempts: outcome.attempts, elapsedMs: outcome.elapsedMs },
311
+ };
312
+ if (outcome.kind === "ok") {
313
+ const uuid = outcome.discoveredUuid ??
314
+ (delta.mode === "update" || delta.mode === "state" ? delta.uuid : null);
315
+ audit({ ...auditCommon, result: "ok", uuid });
316
+ if (deps.environment !== undefined) {
317
+ deps.environment.record(deps.environment.capture());
318
+ }
319
+ return {
320
+ kind: "ok",
321
+ op,
322
+ uuid,
323
+ observed: outcome.observed,
324
+ vector: vector.id,
325
+ tier: effectiveTier,
326
+ ...(envChanges.length > 0 && {
327
+ warnings: [
328
+ `environment changed since the last verified write: ` +
329
+ `${describeEnvironmentChanges(envChanges)} — the first use of another ` +
330
+ `capability may show a macOS consent prompt`,
331
+ ],
332
+ }),
333
+ };
334
+ }
335
+ audit({ ...auditCommon, result: `verify-failed:${outcome.kind}` });
336
+ return withHint({
337
+ kind: "verify-failed",
338
+ op,
339
+ reason: outcome.kind,
340
+ expected: delta,
341
+ observed: outcome.observed,
342
+ detail: outcome.kind === "silent-noop"
343
+ ? "no observable change in the database (the app accepted the command but did nothing)"
344
+ : outcome.kind === "timeout"
345
+ ? "something moved but the expected state never appeared within the timeout"
346
+ : "the database reached a state contradicting the expected delta",
347
+ }, classifyVerifyFailure({
348
+ reason: outcome.kind,
349
+ vector: vector.id,
350
+ authTokenPresent: token !== null,
351
+ environmentChanges: envChanges,
352
+ }));
353
+ }
354
+ finally {
355
+ lock.release();
356
+ }
357
+ }
358
+ export function fingerprintLabel(fp, config) {
359
+ if (fp.kind === "ok")
360
+ return "ok";
361
+ if (fp.kind === "unknown-version")
362
+ return "unknown";
363
+ return config.acceptedFingerprint === fp.observation.fingerprint ? "user-accepted" : "drift";
364
+ }
365
+ function flattenPreFields(fields) {
366
+ const uuids = Object.keys(fields);
367
+ if (uuids.length === 0)
368
+ return null;
369
+ if (uuids.length === 1) {
370
+ const only = uuids[0];
371
+ return only === undefined ? null : (fields[only] ?? null);
372
+ }
373
+ return fields;
374
+ }
375
+ //# sourceMappingURL=pipeline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/write/pipeline.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Vector selection under the disruption policy. Effective tier accounts for
3
+ * the ensure-running step: when Things is closed, the pipeline background-
4
+ * launches it first (tier 1) — required because both a plain `open` and an
5
+ * AppleEvent to a closed Things steal focus (U01, A40/A41).
6
+ */
7
+ import type { DisruptionTier } from "../config.ts";
8
+ import type { OperationKind } from "./operations.ts";
9
+ import type { VectorId, VectorSupport, WriteVector } from "./vectors/types.ts";
10
+ export interface PlanCandidate {
11
+ vector: WriteVector;
12
+ support: VectorSupport;
13
+ /** Tier this call will actually incur, given current app state. */
14
+ effectiveTier: DisruptionTier;
15
+ }
16
+ export type Plan = {
17
+ kind: "selected";
18
+ candidate: PlanCandidate;
19
+ } | {
20
+ kind: "unsupported";
21
+ considered: {
22
+ vector: VectorId;
23
+ why: string;
24
+ }[];
25
+ } | {
26
+ kind: "tier-blocked";
27
+ requiredTier: DisruptionTier;
28
+ maxDisruption: DisruptionTier;
29
+ considered: {
30
+ vector: VectorId;
31
+ tier: DisruptionTier;
32
+ }[];
33
+ };
34
+ export declare function planVector(op: OperationKind, vectors: WriteVector[], options: {
35
+ maxDisruption: DisruptionTier;
36
+ appRunning: boolean;
37
+ forcedVector?: VectorId;
38
+ /** Config gate for `experimental: true` matrix entries (default off). */
39
+ allowExperimental?: boolean;
40
+ }): Plan;
@@ -0,0 +1,57 @@
1
+ export function planVector(op, vectors, options) {
2
+ const considered = [];
3
+ const viable = [];
4
+ for (const vector of vectors) {
5
+ if (options.forcedVector !== undefined && vector.id !== options.forcedVector)
6
+ continue;
7
+ const support = vector.matrix[op];
8
+ if (support === undefined) {
9
+ considered.push({ vector: vector.id, why: "no matrix entry for this operation" });
10
+ continue;
11
+ }
12
+ if (support.support === "no") {
13
+ considered.push({
14
+ vector: vector.id,
15
+ why: support.notes ?? "operation not supported by this vector",
16
+ });
17
+ continue;
18
+ }
19
+ if (support.validation !== "validated") {
20
+ considered.push({
21
+ vector: vector.id,
22
+ why: `capability is ${support.validation} — not lab-validated`,
23
+ });
24
+ continue;
25
+ }
26
+ if (support.experimental === true && options.allowExperimental !== true) {
27
+ considered.push({
28
+ vector: vector.id,
29
+ why: "rides an undocumented app surface — enable it with " +
30
+ "`things config set allow-experimental true`",
31
+ });
32
+ continue;
33
+ }
34
+ const launchTier = options.appRunning ? 0 : 1;
35
+ const effectiveTier = Math.max(support.disruption, launchTier);
36
+ viable.push({ vector, support, effectiveTier });
37
+ }
38
+ if (viable.length === 0)
39
+ return { kind: "unsupported", considered };
40
+ const allowed = viable.filter((c) => c.effectiveTier <= options.maxDisruption);
41
+ if (allowed.length === 0) {
42
+ const requiredTier = Math.min(...viable.map((c) => c.effectiveTier));
43
+ return {
44
+ kind: "tier-blocked",
45
+ requiredTier,
46
+ maxDisruption: options.maxDisruption,
47
+ considered: viable.map((c) => ({ vector: c.vector.id, tier: c.effectiveTier })),
48
+ };
49
+ }
50
+ // Lowest tier wins; registry order breaks ties.
51
+ allowed.sort((a, b) => a.effectiveTier - b.effectiveTier);
52
+ const winner = allowed[0];
53
+ if (winner === undefined)
54
+ return { kind: "unsupported", considered };
55
+ return { kind: "selected", candidate: winner };
56
+ }
57
+ //# sourceMappingURL=planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../../src/write/planner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Pre-read: everything guards and delta-builders need to know about the
3
+ * world BEFORE a mutation. One read pass, snapshot semantics per statement.
4
+ */
5
+ import type { DatabaseSync } from "node:sqlite";
6
+ import type { AnyTask, Project, TaskStatus, Todo } from "../model/entities.ts";
7
+ import type { ContainerRef, ReorderParams } from "./operations.ts";
8
+ export interface ResolvedContainer {
9
+ uuid: string;
10
+ title: string;
11
+ }
12
+ export interface ContainerResolution {
13
+ resolved: ResolvedContainer | null;
14
+ /** 0 = not found, 1 = ok, >1 = ambiguous title. */
15
+ matches: number;
16
+ }
17
+ export interface ReorderMember {
18
+ uuid: string;
19
+ title: string;
20
+ /** Current rank on the scope's ordering key (todayIndex or "index"). */
21
+ rank: number;
22
+ /** Raw startBucket (0 = today, 1 = evening); today/evening scopes only. */
23
+ startBucket: number | null;
24
+ /** 0 = to-do, 1 = project. */
25
+ type: number;
26
+ }
27
+ export interface ReorderPre {
28
+ /** Ordering key the scope ranks on. */
29
+ key: "index" | "todayIndex";
30
+ /** Eligible members in current order (wire-list extension source). */
31
+ members: ReorderMember[];
32
+ /** Requested uuids that are not eligible members, with the reason. */
33
+ rejected: {
34
+ uuid: string;
35
+ reason: string;
36
+ }[];
37
+ /** Requested uuids appearing more than once. */
38
+ duplicates: string[];
39
+ /** Requested project-type members (bounce cannot move projects). */
40
+ projectMembers: string[];
41
+ /**
42
+ * Area scope only: the request mixes to-do and project members. Same-type
43
+ * area reorders are validated (O05/O10 to-dos, O14 projects); a mixed wire
44
+ * list is unprobed, so the guard rejects it.
45
+ */
46
+ mixedTypes: boolean;
47
+ /** Full wire list: requested order first, remaining members after. */
48
+ wireList: string[];
49
+ }
50
+ export interface PreState {
51
+ /** Primary target for uuid-addressed operations. */
52
+ target: AnyTask | null;
53
+ destProject: ContainerResolution | null;
54
+ /** Status of the resolved destination project (reopen hazard, T19). */
55
+ destProjectStatus: TaskStatus | null;
56
+ destArea: ContainerResolution | null;
57
+ /** Heading resolution inside the destination (or target's) project. */
58
+ destHeading: ContainerResolution | null;
59
+ /** Requested tag titles absent from TMTag (case-insensitive). */
60
+ missingTags: string[];
61
+ /** tag.add parent resolution. */
62
+ parentTag: ContainerResolution | null;
63
+ /** area.delete / tag.delete target resolution (TMArea/TMTag). */
64
+ entityTarget: ContainerResolution | null;
65
+ /** tag.delete: descendant tags that a delete would CASCADE onto (P16). */
66
+ childTags: string[];
67
+ /** project.complete / project.cancel: children by pre-status. */
68
+ openChildren: Todo[];
69
+ canceledChildren: Todo[];
70
+ completedChildren: Todo[];
71
+ checklistCount: number;
72
+ trashedCount: number;
73
+ /** Pre-existing uuids for entity-created probes. */
74
+ existingEntityUuids: string[];
75
+ /** Pre-existing same-title/type rows (todo.add-logged create-probe exclusion). */
76
+ sameTitleUuids: string[];
77
+ /** Scope membership + wire list for the reorder operation. */
78
+ reorder: ReorderPre | null;
79
+ }
80
+ export declare function emptyPreState(): PreState;
81
+ export declare function resolveArea(db: DatabaseSync, ref: ContainerRef): ContainerResolution;
82
+ export declare function resolveProject(db: DatabaseSync, ref: ContainerRef): ContainerResolution;
83
+ export declare function resolveHeading(db: DatabaseSync, projectUuid: string, headingTitle: string): ContainerResolution;
84
+ export declare function projectStatus(db: DatabaseSync, uuid: string): TaskStatus | null;
85
+ export declare function missingTagTitles(db: DatabaseSync, titles: string[]): string[];
86
+ export declare function resolveTag(db: DatabaseSync, ref: string): ContainerResolution;
87
+ export declare function loadTarget(db: DatabaseSync, uuid: string): AnyTask | null;
88
+ export declare function projectChildren(db: DatabaseSync, projectUuid: string): Todo[];
89
+ /**
90
+ * Titles of every DESCENDANT tag under the given tag (excluding itself).
91
+ * Deleting the parent CASCADE-DELETES all of these (P16) — the guard lists
92
+ * them. UNION (not UNION ALL): a parent cycle must terminate, not hang.
93
+ */
94
+ export declare function childTagTitles(db: DatabaseSync, tagUuid: string): string[];
95
+ export declare function trashedCount(db: DatabaseSync): number;
96
+ export declare function isRepeatingTemplate(task: AnyTask | null): boolean;
97
+ /**
98
+ * Scope membership + full wire list for `reorder`. Eligibility mirrors the
99
+ * lab evidence exactly:
100
+ * - today: Today members with raw startBucket=0, to-dos AND projects
101
+ * (O01/O03/O12), by todayIndex. Bucket-1 members are listed as
102
+ * rejected candidates — including one silently de-evenings it
103
+ * (O03), so the guard refuses.
104
+ * - evening: raw startBucket=1 AND startDate == today exactly (evening
105
+ * membership expires daily), by todayIndex. Bounce-only (O03).
106
+ * - project: un-headed open to-do children, by "index" (O04/O09/O11);
107
+ * headed children are rejected candidates (O06 rips them out).
108
+ * - area: direct open area to-dos (O05/O10) AND projects (O14), by
109
+ * "index" — but only SAME-TYPE requests; mixed wire lists are
110
+ * unprobed and the guard rejects them.
111
+ * - inbox: unscheduled to-dos with no container (start=0), by "index"
112
+ * (A6/P8a — the command ranks the sent list in order).
113
+ * - headings: the HEADING rows (type=2) of a project, by "index" (scf P1 —
114
+ * the private command accepts heading uuids; children follow).
115
+ * - someday: loose someday to-dos (start=2, no startDate, no container), by
116
+ * "index". The Someday list handler is anchor-stacked (P6h/P7e/
117
+ * P8b) — the compiler emits the validated two-call protocol.
118
+ * Someday PROJECTS moved inconsistently across probes (P7a vs
119
+ * P8c) and are rejected candidates until locked.
120
+ * - projects: TOP-LEVEL sidebar projects (type=1, no area, start=1,
121
+ * undated), by "index". Bounce-only: a when=someday ->
122
+ * when=anytime round-trip front-inserts (P8e).
123
+ */
124
+ export declare function computeReorderPre(db: DatabaseSync, params: ReorderParams, containerUuid: string | null, now: Date): ReorderPre;
125
+ export declare function projectOf(task: AnyTask | null): Project | null;