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
@@ -0,0 +1,403 @@
1
+ /**
2
+ * The FIXED-recurrence DEFAULT-anchor law + the weekly-weekday derivation the
3
+ * promote verbs use (issue #476; evidence: docs/lab/anch2-next-field.md +
4
+ * anch1-repeat-anchor.md, golden-v2 / Things 3.22.12).
5
+ *
6
+ * DEFAULT LAW (ANCH1, still valid as the DEFAULT). Left untouched, the Repeat
7
+ * dialog's "Next:" field defaults the first occurrence to the next calendar match
8
+ * ON OR AFTER TODAY (interval-independent), and a weekday-less weekly rule
9
+ * defaults to SUNDAY. ANCH2 then showed the "Next:" field is EDITABLE and honored
10
+ * (docs/lab/anch2-next-field.md) — so the promote verbs DRIVE it with the item's
11
+ * scheduled date rather than refuse a wrong-phase series. This module no longer
12
+ * carries a phase-refusal (the ANCH1 `H-REPEAT-ANCHOR` premise — "no drivable
13
+ * first-occurrence control" — was false).
14
+ *
15
+ * What it still provides:
16
+ * 1. {@link deriveWeeklyWeekdays} — when a weekly rule omits `weekdays` but a
17
+ * concrete anchor date is known, derive the recurring weekday FROM that date
18
+ * so the series fires on the intended weekday (not the app's Sunday default).
19
+ * Driving "Next:" fixes the FIRST occurrence; this fixes the recurring day.
20
+ * 2. {@link fixedSpawnPlan} — the DEFAULT spawn shape (used by the simulator
21
+ * when no explicit first occurrence is requested): first occurrence = next
22
+ * match ≥ today, an instance spawns only when today is itself an occurrence.
23
+ *
24
+ * Daily/weekly follow the probed default law; monthly/yearly keep the caller's
25
+ * today+interval model for the default (their default-anchor law is unprobed).
26
+ */
27
+ import { addDaysIso } from "../model/dates.js";
28
+ import { WD_TO_WEEKDAY, WEEKDAY_TO_WD } from "./repeat-rule.js";
29
+ /** True iff `v` is a concrete `YYYY-MM-DD` date (not a list keyword / undefined). */
30
+ export function isIsoDate(v) {
31
+ return typeof v === "string" && /^\d{4}-\d{2}-\d{2}$/.test(v);
32
+ }
33
+ /** Weekday of an ISO date, 0 = Sunday … 6 = Saturday (evaluated at UTC noon, tz-invariant). */
34
+ export function weekdayOfIso(iso) {
35
+ const [y, m, d] = iso.split("-").map(Number);
36
+ return new Date(Date.UTC(y, m - 1, d, 12)).getUTCDay();
37
+ }
38
+ /** Whole days from `a` to `b` (b − a); negative when b precedes a. */
39
+ export function daysBetweenIso(a, b) {
40
+ const [ay, am, ad] = a.split("-").map(Number);
41
+ const [by, bm, bd] = b.split("-").map(Number);
42
+ return Math.round((Date.UTC(by, bm - 1, bd) - Date.UTC(ay, am - 1, ad)) / 86_400_000);
43
+ }
44
+ /** The smallest date on or after `todayIso` whose weekday is `wd` (0 = Sunday). */
45
+ function nextWeekdayOnOrAfter(todayIso, wd) {
46
+ const delta = (((wd - weekdayOfIso(todayIso)) % 7) + 7) % 7;
47
+ return addDaysIso(todayIso, delta);
48
+ }
49
+ /** The Sunday that starts the week containing `iso` (the app's weeks start Sunday). */
50
+ function weekAnchorSunday(iso) {
51
+ return addDaysIso(iso, -weekdayOfIso(iso));
52
+ }
53
+ /** A true modulo (result always in [0, n)). */
54
+ function mod(x, n) {
55
+ return ((x % n) + n) % n;
56
+ }
57
+ /** The rule's effective weekday numbers (explicit set, else the app's Sunday default). */
58
+ function effectiveWds(rule) {
59
+ return rule.weekdays !== undefined && rule.weekdays.length > 0
60
+ ? rule.weekdays.map((w) => WEEKDAY_TO_WD[w])
61
+ : [0];
62
+ }
63
+ /**
64
+ * Whether `d` is on the active-week grid of a weekly rule anchored at `firstOcc`
65
+ * (weeks fire every `interval` weeks from the anchor's Sunday-week). Weekday match
66
+ * is checked separately.
67
+ */
68
+ function weeklyActiveWeek(firstOcc, d, interval) {
69
+ const weeks = daysBetweenIso(weekAnchorSunday(firstOcc), weekAnchorSunday(d)) / 7;
70
+ return mod(weeks, interval) === 0;
71
+ }
72
+ /**
73
+ * When a WEEKLY rule omits its weekday set but a concrete anchor date is known,
74
+ * the weekday to drive explicitly (so the series fires on the anchor date's
75
+ * weekday, not the app's Sunday default). Returns `undefined` when nothing should
76
+ * change (non-weekly, weekdays already given, or no concrete anchor date).
77
+ */
78
+ export function deriveWeeklyWeekdays(rule, anchorIso) {
79
+ if (rule.afterCompletion === true)
80
+ return undefined;
81
+ if (rule.frequency !== "weekly")
82
+ return undefined;
83
+ if (rule.weekdays !== undefined)
84
+ return undefined;
85
+ if (!isIsoDate(anchorIso))
86
+ return undefined;
87
+ return [WD_TO_WEEKDAY[weekdayOfIso(anchorIso)]];
88
+ }
89
+ /** The 1-based day-of-month of an ISO date. */
90
+ function dayOfMonthIso(iso) {
91
+ return Number(iso.split("-")[2]);
92
+ }
93
+ /** The 1-based month of an ISO date. */
94
+ function monthOfIso(iso) {
95
+ return Number(iso.split("-")[1]);
96
+ }
97
+ /**
98
+ * When a MONTHLY rule omits its day anchor but a concrete first-occurrence date
99
+ * is known, the day-of-month anchor to drive EXPLICITLY (so the series recurs on
100
+ * that day, not the Repeat dialog's untouched default). Returns `undefined` when
101
+ * nothing should change (non-monthly, an explicit anchor already given, or no
102
+ * concrete date). Mirrors {@link deriveWeeklyWeekdays} for the monthly unit —
103
+ * the same day-of-month the read-path decoder / composeOffsets derives from the
104
+ * occurrence date, so the derived anchor is byte-consistent with the rule blob.
105
+ */
106
+ export function deriveMonthlyAnchor(rule, anchorIso) {
107
+ if (rule.afterCompletion === true)
108
+ return undefined;
109
+ if (rule.frequency !== "monthly")
110
+ return undefined;
111
+ if (rule.monthly !== undefined)
112
+ return undefined;
113
+ if (!isIsoDate(anchorIso))
114
+ return undefined;
115
+ return { day: dayOfMonthIso(anchorIso) };
116
+ }
117
+ /**
118
+ * When a YEARLY rule omits its month+day anchor but a concrete first-occurrence
119
+ * date is known, the {month, day} anchor to drive EXPLICITLY (so the series recurs
120
+ * on that month/day, not the dialog's untouched January-1 default — the ANCH2-c /
121
+ * issue #493 anchor-drop). Returns `undefined` when nothing should change
122
+ * (non-yearly, an explicit anchor already given, or no concrete date).
123
+ */
124
+ export function deriveYearlyAnchor(rule, anchorIso) {
125
+ if (rule.afterCompletion === true)
126
+ return undefined;
127
+ if (rule.frequency !== "yearly")
128
+ return undefined;
129
+ if (rule.yearly !== undefined)
130
+ return undefined;
131
+ if (!isIsoDate(anchorIso))
132
+ return undefined;
133
+ return { month: monthOfIso(anchorIso), day: dayOfMonthIso(anchorIso) };
134
+ }
135
+ /**
136
+ * The date to drive into the Repeat dialog's "Next:" field for a rule whose
137
+ * `next` is the scheduled START (`--when`). A DEADLINED rule anchors on the
138
+ * DEADLINE — the dialog's "Next:" is the next deadline and the instance START =
139
+ * deadline − startDaysEarlier — so it is driven with `next + startDaysEarlier` and
140
+ * the app back-shifts the start to `next` (YANCH1 #493, golden-v3 probe: Next
141
+ * driven to a date with start-N lands the instance start N days earlier). A
142
+ * non-deadlined rule (or one with no concrete `next`) drives `next` verbatim.
143
+ * Returns `undefined` when `next` is absent/non-concrete.
144
+ */
145
+ export function deadlineDriveNext(p) {
146
+ if (!isIsoDate(p.next))
147
+ return undefined;
148
+ const shift = p.deadline === true || (p.startDaysEarlier ?? 0) > 0 ? (p.startDaysEarlier ?? 0) : 0;
149
+ return addDaysIso(p.next, shift);
150
+ }
151
+ /**
152
+ * The calendar-anchor fields to drive EXPLICITLY for a fixed weekly/monthly/yearly
153
+ * rule when the caller supplied a concrete first-occurrence date but NO explicit
154
+ * anchor — each derived from that date by the SAME refIso law composeOffsets uses
155
+ * (weekly → weekday, monthly → day-of-month, yearly → month+day). Driving the
156
+ * anchor pop-ups makes the series RECUR on the intended calendar placement;
157
+ * leaving the anchor to the "Next:" first-occurrence field alone fixes only the
158
+ * FIRST occurrence and leaves the dialog's untouched default as the recurring rule
159
+ * (weekly → Sunday, monthly → 1st, yearly → January 1 — ANCH2 cell c / issue
160
+ * #493). Returns only the fields that need driving; an explicit anchor, an
161
+ * after-completion rule, daily, or no concrete date yields an empty patch. This
162
+ * completes the derive-and-drive family the weekly weekday-derivation began
163
+ * post-ANCH1 (decisions.md).
164
+ */
165
+ export function deriveFixedAnchor(rule, anchorIso) {
166
+ const weekdays = deriveWeeklyWeekdays(rule, anchorIso);
167
+ const monthly = deriveMonthlyAnchor(rule, anchorIso);
168
+ const yearly = deriveYearlyAnchor(rule, anchorIso);
169
+ return {
170
+ ...(weekdays !== undefined && { weekdays }),
171
+ ...(monthly !== undefined && { monthly }),
172
+ ...(yearly !== undefined && { yearly }),
173
+ };
174
+ }
175
+ // ------------------------------------------------ off-rule first occurrence (DACON1)
176
+ //
177
+ // A concrete `--when` together with an EXPLICIT calendar anchor
178
+ // (weekdays/monthly/yearly) can DISAGREE — the first occurrence lands off the
179
+ // rule's grid. This is NOT an error by default: the Repeat dialog's "Next:" field
180
+ // accepts an off-schedule first occurrence, so the series appears on `--when` the
181
+ // first time and follows the anchor thereafter (e.g. `--weekdays wednesday --when
182
+ // <a thursday>` = Thursday first, Wednesdays after). In DEADLINE mode `--when` is
183
+ // the START and each occurrence is DUE `startDaysEarlier` days later; the anchor
184
+ // names the DUE date, so the off-rule test compares the anchor against
185
+ // `deadlineDriveNext` (= when + N, the deadline). `deriveFixedAnchor` covers the
186
+ // NO-explicit-anchor case (anchor derived from `--when`, never off-rule).
187
+ //
188
+ // EMPIRICAL boundary (docs/lab/dacon1-deadline-contradiction.md, golden-v3 /
189
+ // Things 3.22.14). The app HONORS an off-rule first for WEEKLY and YEARLY (cells
190
+ // DC1/DC5, DC3/DC4: the typed `--when` lands verbatim as the first instance start,
191
+ // the anchor drives the recurring grid). It does NOT for MONTHLY: the month row's
192
+ // "Next:" field SNAPS to the anchor day (cell DC2: Next 08-10 with a day-20 anchor
193
+ // committed 08-20, then the CLI's read-back rejected it, -2700). So an off-rule
194
+ // first is EXPRESSIBLE for weekly/yearly (allowed + disclosed) and INEXPRESSIBLE
195
+ // for monthly (fail-closed at validation rather than mid-drive).
196
+ /** Days in the calendar month containing `iso`. */
197
+ function daysInMonthOf(iso) {
198
+ const [y, m] = iso.split("-").map(Number);
199
+ return new Date(Date.UTC(y, m, 0)).getUTCDate(); // day 0 of month m+1 = last day of m
200
+ }
201
+ /** True iff `iso` is the last calendar day of its month. */
202
+ function isLastDayOfMonth(iso) {
203
+ return dayOfMonthIso(iso) === daysInMonthOf(iso);
204
+ }
205
+ /** Which occurrence (1-based) of its own weekday `iso` is within its month. */
206
+ function weekdayOrdinalInMonth(iso) {
207
+ return Math.floor((dayOfMonthIso(iso) - 1) / 7) + 1;
208
+ }
209
+ /** True iff `iso` is the LAST occurrence of its weekday in its month. */
210
+ function isLastWeekdayInMonth(iso) {
211
+ return dayOfMonthIso(iso) + 7 > daysInMonthOf(iso);
212
+ }
213
+ /** Whether date `iso` lands on the monthly/yearly day-or-nth-weekday `anchor`. */
214
+ function dateSatisfiesDayAnchor(iso, anchor) {
215
+ if ("day" in anchor) {
216
+ return anchor.day === "last" ? isLastDayOfMonth(iso) : dayOfMonthIso(iso) === anchor.day;
217
+ }
218
+ if (WEEKDAY_TO_WD[anchor.weekday] !== weekdayOfIso(iso))
219
+ return false;
220
+ return anchor.ordinal === "last"
221
+ ? isLastWeekdayInMonth(iso)
222
+ : weekdayOrdinalInMonth(iso) === anchor.ordinal;
223
+ }
224
+ /** "1st" | "2nd" | … | "5th" | "last" for an nth-weekday ordinal. */
225
+ function ordinalWord(ordinal) {
226
+ if (ordinal === "last")
227
+ return "last";
228
+ return `${ordinal}${["th", "st", "nd", "rd", "th"][ordinal] ?? "th"}`;
229
+ }
230
+ /** Human phrase for a monthly/yearly day-or-nth-weekday anchor (surface copy). */
231
+ function describeDayAnchor(anchor) {
232
+ if ("day" in anchor)
233
+ return anchor.day === "last" ? "the last day of the month" : `day ${anchor.day}`;
234
+ return `the ${ordinalWord(anchor.ordinal)} ${anchor.weekday}`;
235
+ }
236
+ /** The effective deadline back-shift (days) for the given params, mirroring {@link deadlineDriveNext}. */
237
+ function anchorShiftDays(p) {
238
+ return p.deadline === true || (p.startDaysEarlier ?? 0) > 0 ? (p.startDaysEarlier ?? 0) : 0;
239
+ }
240
+ /** Whether `driveIso` lands on the explicit anchor of these params (deadline-shift date already applied). */
241
+ function driveDateOnAnchor(p, driveIso) {
242
+ if (p.frequency === "weekly" && p.weekdays !== undefined && p.weekdays.length > 0) {
243
+ return p.weekdays.includes(WD_TO_WEEKDAY[weekdayOfIso(driveIso)]);
244
+ }
245
+ if (p.frequency === "monthly" && p.monthly !== undefined) {
246
+ return dateSatisfiesDayAnchor(driveIso, p.monthly);
247
+ }
248
+ if (p.frequency === "yearly" && p.yearly !== undefined) {
249
+ return monthOfIso(driveIso) === p.yearly.month && dateSatisfiesDayAnchor(driveIso, p.yearly);
250
+ }
251
+ return true; // no explicit anchor for this frequency ⇒ never off-rule (derived from --when)
252
+ }
253
+ /** The recurring-pattern phrase for the explicit anchor (the "thereafter" half of the disclosure). */
254
+ function describeRulePattern(p) {
255
+ if (p.frequency === "weekly" && p.weekdays !== undefined) {
256
+ return `every ${p.weekdays.join(", ")}`;
257
+ }
258
+ if (p.frequency === "monthly" && p.monthly !== undefined) {
259
+ return `monthly on ${describeDayAnchor(p.monthly)}`;
260
+ }
261
+ if (p.frequency === "yearly" && p.yearly !== undefined) {
262
+ return `yearly in month ${p.yearly.month} on ${describeDayAnchor(p.yearly)}`;
263
+ }
264
+ return "the rule";
265
+ }
266
+ export function assessOffRuleFirst(p, preservedDeadlineOffset) {
267
+ if (p.afterCompletion === true)
268
+ return null;
269
+ if (!isIsoDate(p.next))
270
+ return null;
271
+ const driveIso = deadlineDriveNext(p);
272
+ if (driveIso === undefined)
273
+ return null;
274
+ if (driveDateOnAnchor(p, driveIso))
275
+ return null; // on-rule — the common case
276
+ const shift = anchorShiftDays(p);
277
+ // RSPA1-D: a reschedule that PRESERVES the template's existing deadline (the
278
+ // request carries no --deadline / --start-days-earlier) drives "Next:" verbatim
279
+ // (shift 0), but the app reads that driven date as the DUE date of the still-
280
+ // deadlined rule and back-shifts the START by the preserved offset. So the first
281
+ // occurrence APPEARS `preserved` days BEFORE --when and is DUE on --when — the
282
+ // inverse of the explicit-deadline case (where --when is the start and the due is
283
+ // `shift` days later). `assessOffRuleFirst` is otherwise deadline-shift-aware only
284
+ // via the params' own flags; the caller threads the pre-state template's offset so
285
+ // the disclosure states the true appear/due dates the app actually lands.
286
+ const preservedShift = shift === 0 && preservedDeadlineOffset != null ? Math.abs(preservedDeadlineOffset) : 0;
287
+ const pattern = describeRulePattern(p);
288
+ // MONTHLY off-rule first is INEXPRESSIBLE — the month row's "Next:" field snaps
289
+ // to the anchor day (dacon1-deadline-contradiction.md cell DC2). Fail closed at
290
+ // validation with the two nearest expressible alternatives. (When the deadline is
291
+ // preserved, --when IS the due date the anchor names, so the shift-0 hint — "set
292
+ // --when to a date on <anchor>" — is the correct guidance, exactly as here.)
293
+ if (p.frequency === "monthly") {
294
+ const onRuleHint = shift > 0
295
+ ? `set --when so that --when + ${shift} lands on ${describeDayAnchor(p.monthly)}`
296
+ : `set --when to a date on ${describeDayAnchor(p.monthly)}`;
297
+ return {
298
+ kind: "dishonored",
299
+ refusal: `a monthly rule cannot start off its anchor: the Repeat dialog snaps the first ` +
300
+ `occurrence to ${describeDayAnchor(p.monthly)}, so a first occurrence on ` +
301
+ `${p.next} would not hold. Either ${onRuleHint}, or omit the monthly anchor to take it ` +
302
+ `from --when.`,
303
+ };
304
+ }
305
+ // WEEKLY / YEARLY off-rule first is HONORED — allow + disclose both halves. The
306
+ // appear/due assignment depends on which deadline mode applies: an explicit
307
+ // deadline makes --when the START (due `shift` days later); a preserved deadline
308
+ // makes --when the DUE date (start `preservedShift` days earlier).
309
+ let appearsIso;
310
+ let dueIso;
311
+ let earlierDays;
312
+ if (shift > 0) {
313
+ appearsIso = p.next;
314
+ dueIso = addDaysIso(p.next, shift);
315
+ earlierDays = shift;
316
+ }
317
+ else if (preservedShift > 0) {
318
+ dueIso = p.next;
319
+ appearsIso = addDaysIso(p.next, -preservedShift);
320
+ earlierDays = preservedShift;
321
+ }
322
+ else {
323
+ appearsIso = p.next;
324
+ dueIso = null;
325
+ earlierDays = 0;
326
+ }
327
+ const dueClause = dueIso !== null ? `, due ${dueIso}` : "";
328
+ const ongoing = earlierDays > 0
329
+ ? `thereafter: ${pattern}, appearing ${earlierDays} day${earlierDays === 1 ? "" : "s"} earlier`
330
+ : `thereafter: ${pattern}`;
331
+ return {
332
+ kind: "honored",
333
+ disclosure: {
334
+ appearsIso,
335
+ dueIso,
336
+ message: `off-rule first occurrence — appears ${appearsIso}${dueClause}; ${ongoing}`,
337
+ },
338
+ };
339
+ }
340
+ /**
341
+ * The app's first occurrence of a FIXED daily/weekly rule = the next calendar
342
+ * match on or after today. `null` for after-completion (no calendar) or an
343
+ * unguarded frequency (monthly/yearly). Weekly uses `weekdays` (caller should
344
+ * pass the DERIVED set); with no weekdays it falls back to the app's Sunday default.
345
+ */
346
+ export function fixedFirstOccurrence(rule, todayIso) {
347
+ if (rule.afterCompletion === true)
348
+ return null;
349
+ if (rule.frequency === "daily")
350
+ return todayIso; // every day is an occurrence
351
+ if (rule.frequency === "weekly") {
352
+ let best = null;
353
+ for (const wd of effectiveWds(rule)) {
354
+ const cand = nextWeekdayOnOrAfter(todayIso, wd);
355
+ if (best === null || daysBetweenIso(cand, best) > 0)
356
+ best = cand;
357
+ }
358
+ return best;
359
+ }
360
+ return null; // monthly/yearly: default anchor law unprobed — not guarded
361
+ }
362
+ /**
363
+ * The smallest occurrence STRICTLY AFTER today (the template's cursor,
364
+ * rt1_nextInstanceStartDate). Daily/weekly only. Returns `null` for other
365
+ * frequencies / after-completion.
366
+ */
367
+ export function nextFixedOccurrenceAfter(rule, todayIso) {
368
+ if (rule.afterCompletion === true)
369
+ return null;
370
+ if (rule.frequency === "daily")
371
+ return addDaysIso(todayIso, Math.max(1, rule.interval));
372
+ if (rule.frequency === "weekly") {
373
+ const first = fixedFirstOccurrence(rule, todayIso);
374
+ if (first === null)
375
+ return null;
376
+ const wds = effectiveWds(rule);
377
+ const interval = Math.max(1, rule.interval);
378
+ let d = addDaysIso(todayIso, 1);
379
+ for (let i = 0; i < (interval + 2) * 7; i++) {
380
+ if (wds.includes(weekdayOfIso(d)) && weeklyActiveWeek(first, d, interval))
381
+ return d;
382
+ d = addDaysIso(d, 1);
383
+ }
384
+ return first; // unreachable in practice
385
+ }
386
+ return null;
387
+ }
388
+ export function fixedSpawnPlan(rule, todayIso) {
389
+ const first = fixedFirstOccurrence(rule, todayIso);
390
+ if (first === null) {
391
+ // Not a guarded frequency — degenerate plan (caller handles monthly/yearly).
392
+ return { refIso: todayIso, instanceStartIso: todayIso, cursorIso: todayIso, instanceCount: 1 };
393
+ }
394
+ const isToday = first === todayIso;
395
+ const cursor = isToday ? (nextFixedOccurrenceAfter(rule, todayIso) ?? first) : first;
396
+ return {
397
+ refIso: first,
398
+ instanceStartIso: isToday ? todayIso : null,
399
+ cursorIso: cursor,
400
+ instanceCount: isToday ? 1 : 0,
401
+ };
402
+ }
403
+ //# sourceMappingURL=repeat-anchor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repeat-anchor.js","sourceRoot":"","sources":["../../src/write/repeat-anchor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { RepeatRuleParams } from "./operations.ts";
2
+ import type { FieldAssertion } from "./verify/delta.ts";
3
+ /** The full requested-rule vocabulary minus the target uuid. */
4
+ export type RuleFields = Omit<RepeatRuleParams, "uuid">;
5
+ export interface RuleAssertOptions {
6
+ /**
7
+ * Include the ANCH2 first-occurrence cursor assertion (`repeating.nextOccurrence`
8
+ * = rt1_nextInstanceStartDate) when `next` is requested. TRUE for
9
+ * reschedule-repeat — the cursor is driven into the EXISTING template in place
10
+ * with an on-rule `--when`, so a wrong-anchor drive is caught. FALSE for
11
+ * make-repeating / add-repeating: the cursor is the first RULE-ALIGNED occurrence
12
+ * ≥ today (ANCH1 spawn law), which coincides with the requested `--when` only
13
+ * when that date is on-rule AND future — an overdue seed or an off-rule `--when`
14
+ * makes the cursor legitimately differ. Those verbs instead verify (a) the rule
15
+ * BLOB anchor at full fidelity — the calendar anchor is asserted whether it was
16
+ * given explicitly or DERIVED from `--when` (YANCH1 #493: this is what catches a
17
+ * dropped January-1 / Sunday / 1st-of-month anchor), and (b) the driven FIRST
18
+ * occurrence (rt1_instanceCreationStartDate, verbatim even off-rule) through the
19
+ * dedicated post-drive check in promote-clone.ts — not the cursor.
20
+ */
21
+ includeCursor: boolean;
22
+ }
23
+ /**
24
+ * Build the full-fidelity expected-rule assertion set for a validated rule-params
25
+ * bag. The base three (type/unit/interval) are always emitted; every other field
26
+ * contributes only when requested (requested-fields-only law).
27
+ */
28
+ export declare function expectedRuleAssertions(params: RuleFields, opts: RuleAssertOptions): FieldAssertion[];
@@ -0,0 +1,169 @@
1
+ /**
2
+ * FULL-FIDELITY expected-rule assertions for the rule-writing verbs
3
+ * (reschedule-repeat, make-repeating, add-repeating; to-do AND project).
4
+ *
5
+ * The idempotency precheck (pipeline.ts step 5a½) and the post-drive verify both
6
+ * ride the SAME {@link FieldAssertion} set an op's `expectedDelta` produces. When
7
+ * that set asserted only unit+interval (the RSIM5-era shallow subset), a
8
+ * reschedule that changed ONLY the monthly anchor / deadline offset / ends bound
9
+ * read back "already satisfied" and was skipped with a false idempotent-no-op —
10
+ * issue #491. This builder closes that class by construction: it maps the COMPLETE
11
+ * requested vocabulary onto assertions over the DECODED rule (decodeRecurrenceRule
12
+ * shapes) + the template's deadline column, never a raw blob/string compare.
13
+ *
14
+ * Two laws:
15
+ * 1. REQUESTED-FIELDS-ONLY. Only fields the caller actually set contribute an
16
+ * assertion; the three base fields (type/unit/interval) are always asserted
17
+ * (frequency+interval are required; the rule TYPE is meaningful even when
18
+ * `afterCompletion` is defaulted). A bare `{frequency, interval}` reschedule
19
+ * therefore never fails on an untouched anchor/ends/deadline — those keep
20
+ * their existing don't-care semantics.
21
+ * 2. EXHAUSTIVE MAP. {@link RULE_ASSERT_MAP} is a `Record` over every key of the
22
+ * rule vocabulary; each key is either an assert-producer or an explicit skip
23
+ * carrying a written reason. Adding a field to {@link RepeatRuleParams} breaks
24
+ * compilation here until it is consciously handled — a multi-consumer
25
+ * vocabulary must never be hand-enumerated per consumer (decisions.md).
26
+ */
27
+ import { anchorKeyOfOffsets, decodeOffsetEntry } from "../model/recurrence.js";
28
+ import { composeRepeatRuleSpec } from "./recurrence-rule-blob.js";
29
+ /** A never-used anchor reference: every anchor path that reaches the key builder
30
+ * carries an EXPLICIT anchor (weekdays/monthly/yearly present), so composeOffsets
31
+ * never falls back to deriving one from this date. */
32
+ const ANCHOR_DUMMY_REF = "2000-01-01";
33
+ /**
34
+ * The canonical, order-insensitive anchor key the DECODED rule would carry for
35
+ * these requested params — computed by composing the numeric offsets exactly as a
36
+ * write would and round-tripping them through the SAME per-offset decode the read
37
+ * path uses, so the expected key is byte-consistent with the observed one.
38
+ */
39
+ function expectedAnchorKey(p) {
40
+ const spec = composeRepeatRuleSpec({ uuid: "", ...p }, ANCHOR_DUMMY_REF, 0);
41
+ return anchorKeyOfOffsets((spec.of ?? []).map((o) => decodeOffsetEntry(o)));
42
+ }
43
+ /**
44
+ * The Ends bound, per the RRX1 laws: ends-after sets the `rc` occurrence-count
45
+ * total and OMITS the end date; ends-on-date sets `ed` and no count; never = both
46
+ * null. Every arm asserts BOTH columns so a reschedule from one bound kind to
47
+ * another is fully discriminated (e.g. after→on-date must clear the count).
48
+ */
49
+ function endsAsserts(ends) {
50
+ switch (ends.kind) {
51
+ case "never":
52
+ return [
53
+ { field: "repeating.rule.endDate", equals: null },
54
+ { field: "repeating.rule.occurrenceCount", equals: null },
55
+ ];
56
+ case "on-date":
57
+ return [
58
+ { field: "repeating.rule.endDate", equals: ends.date },
59
+ { field: "repeating.rule.occurrenceCount", equals: null },
60
+ ];
61
+ case "after":
62
+ return [
63
+ { field: "repeating.rule.occurrenceCount", equals: ends.count },
64
+ { field: "repeating.rule.endDate", equals: null },
65
+ ];
66
+ default: {
67
+ const exhaustive = ends;
68
+ throw new Error(`unknown ends bound ${JSON.stringify(exhaustive)}`);
69
+ }
70
+ }
71
+ }
72
+ /**
73
+ * EXHAUSTIVE over every key of the rule vocabulary. The mapped-type key set (`-?`
74
+ * makes each required) is what makes a newly added {@link RepeatRuleParams} field
75
+ * a COMPILE error until it earns an entry here.
76
+ */
77
+ const RULE_ASSERT_MAP = {
78
+ frequency: {
79
+ kind: "assert",
80
+ always: true,
81
+ build: (p) => [{ field: "repeating.rule.unit", equals: p.frequency }],
82
+ },
83
+ interval: {
84
+ kind: "assert",
85
+ always: true,
86
+ build: (p) => [{ field: "repeating.rule.interval", equals: p.interval }],
87
+ },
88
+ afterCompletion: {
89
+ kind: "assert",
90
+ // The rule TYPE is always meaningful (an absent flag ⇒ a fixed schedule); a
91
+ // fixed→after-completion conversion leaves unit+interval unchanged, so without
92
+ // this the precheck could not tell the target had not yet been reached.
93
+ always: true,
94
+ build: (p) => [
95
+ {
96
+ field: "repeating.rule.type",
97
+ equals: p.afterCompletion === true ? "after-completion" : "fixed",
98
+ },
99
+ ],
100
+ },
101
+ weekdays: {
102
+ kind: "assert",
103
+ build: (p) => [{ field: "repeating.rule.anchorKey", equals: expectedAnchorKey(p) }],
104
+ },
105
+ monthly: {
106
+ kind: "assert",
107
+ build: (p) => [{ field: "repeating.rule.anchorKey", equals: expectedAnchorKey(p) }],
108
+ },
109
+ yearly: {
110
+ kind: "assert",
111
+ build: (p) => [{ field: "repeating.rule.anchorKey", equals: expectedAnchorKey(p) }],
112
+ },
113
+ ends: {
114
+ kind: "assert",
115
+ build: (p) => (p.ends === undefined ? [] : endsAsserts(p.ends)),
116
+ },
117
+ deadline: {
118
+ kind: "assert",
119
+ // A start-offset request also asserts a deadline: startDaysEarlier implies one
120
+ // (assertRepeatRule refuses startDaysEarlier with deadline:false).
121
+ when: (p) => p.deadline !== undefined || (p.startDaysEarlier ?? 0) > 0,
122
+ build: (p) => [
123
+ {
124
+ field: "repeating.deadlined",
125
+ equals: p.deadline === true || (p.startDaysEarlier ?? 0) > 0,
126
+ },
127
+ ],
128
+ },
129
+ startDaysEarlier: {
130
+ kind: "assert",
131
+ // ts = −startDaysEarlier on the decoded rule (a deadline-relative start offset).
132
+ build: (p) => [{ field: "repeating.rule.startOffsetDays", equals: -(p.startDaysEarlier ?? 0) }],
133
+ },
134
+ next: {
135
+ kind: "assert",
136
+ // The ANCH2 first-occurrence CURSOR (rt1_nextInstanceStartDate → nextOccurrence)
137
+ // — the first RULE-ALIGNED occurrence, which equals the requested `--when` only
138
+ // when that date is itself on-rule AND future. Gated by
139
+ // RuleAssertOptions.includeCursor (reschedule only) — see expectedRuleAssertions.
140
+ build: (p) => p.next === undefined ? [] : [{ field: "repeating.nextOccurrence", equals: p.next }],
141
+ },
142
+ reminder: {
143
+ kind: "skip",
144
+ reason: "not stored in the recurrence-rule blob (rt1_recurrenceRule) — 'Add reminders' sets a " +
145
+ "time-of-day on the SPAWNED INSTANCES, not on the rule (RRX1/ANCH2). It has no decoded-rule " +
146
+ "field to compare against, so it is verified through the instance reminder-byte path, not here.",
147
+ },
148
+ };
149
+ /**
150
+ * Build the full-fidelity expected-rule assertion set for a validated rule-params
151
+ * bag. The base three (type/unit/interval) are always emitted; every other field
152
+ * contributes only when requested (requested-fields-only law).
153
+ */
154
+ export function expectedRuleAssertions(params, opts) {
155
+ const out = [];
156
+ for (const key of Object.keys(RULE_ASSERT_MAP)) {
157
+ // The cursor is a reschedule-only expectation (see RuleAssertOptions).
158
+ if (key === "next" && !opts.includeCursor)
159
+ continue;
160
+ const spec = RULE_ASSERT_MAP[key];
161
+ if (spec.kind === "skip")
162
+ continue;
163
+ const present = spec.when !== undefined ? spec.when(params) : params[key] !== undefined;
164
+ if (present || spec.always === true)
165
+ out.push(...spec.build(params));
166
+ }
167
+ return out;
168
+ }
169
+ //# sourceMappingURL=repeat-asserts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repeat-asserts.js","sourceRoot":"","sources":["../../src/write/repeat-asserts.ts"],"names":[],"mappings":"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"}