things-api 0.9.0 → 0.10.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 (214) hide show
  1. package/README.md +30 -11
  2. package/dist/audit/log.js +56 -2
  3. package/dist/audit/log.js.map +1 -1
  4. package/dist/audit/schema.d.ts +26 -8
  5. package/dist/audit/schema.js +42 -1
  6. package/dist/audit/schema.js.map +1 -1
  7. package/dist/cli/commands/area.d.ts +26 -3
  8. package/dist/cli/commands/area.js +125 -70
  9. package/dist/cli/commands/area.js.map +1 -1
  10. package/dist/cli/commands/doctor.d.ts +1 -1
  11. package/dist/cli/commands/doctor.js +44 -5
  12. package/dist/cli/commands/doctor.js.map +1 -1
  13. package/dist/cli/commands/mcp.js +23 -4
  14. package/dist/cli/commands/mcp.js.map +1 -1
  15. package/dist/cli/commands/project.d.ts +18 -1
  16. package/dist/cli/commands/project.js +69 -31
  17. package/dist/cli/commands/project.js.map +1 -1
  18. package/dist/cli/commands/reads.js +423 -157
  19. package/dist/cli/commands/reads.js.map +1 -1
  20. package/dist/cli/commands/repeat-flags.d.ts +20 -0
  21. package/dist/cli/commands/repeat-flags.js +76 -0
  22. package/dist/cli/commands/repeat-flags.js.map +1 -0
  23. package/dist/cli/commands/setup.js +2 -3
  24. package/dist/cli/commands/setup.js.map +1 -1
  25. package/dist/cli/commands/show.js +47 -24
  26. package/dist/cli/commands/show.js.map +1 -1
  27. package/dist/cli/commands/todo.d.ts +1 -1
  28. package/dist/cli/commands/todo.js +7 -6
  29. package/dist/cli/commands/todo.js.map +1 -1
  30. package/dist/cli/commands/writes.js +378 -148
  31. package/dist/cli/commands/writes.js.map +1 -1
  32. package/dist/cli/did-you-mean.d.ts +1 -1
  33. package/dist/cli/excess-args.d.ts +15 -0
  34. package/dist/cli/excess-args.js +51 -0
  35. package/dist/cli/excess-args.js.map +1 -0
  36. package/dist/cli/glyphs.d.ts +39 -2
  37. package/dist/cli/glyphs.js +91 -21
  38. package/dist/cli/glyphs.js.map +1 -1
  39. package/dist/cli/help.d.ts +54 -0
  40. package/dist/cli/help.js +355 -0
  41. package/dist/cli/help.js.map +1 -0
  42. package/dist/cli/main.js +32 -25
  43. package/dist/cli/main.js.map +1 -1
  44. package/dist/cli/period.d.ts +7 -0
  45. package/dist/cli/period.js +12 -0
  46. package/dist/cli/period.js.map +1 -1
  47. package/dist/cli/read-driver.d.ts +26 -19
  48. package/dist/cli/read-driver.js +67 -33
  49. package/dist/cli/read-driver.js.map +1 -1
  50. package/dist/cli/render.d.ts +92 -28
  51. package/dist/cli/render.js +318 -97
  52. package/dist/cli/render.js.map +1 -1
  53. package/dist/cli/resolve-invocation.d.ts +42 -4
  54. package/dist/cli/resolve-invocation.js +97 -14
  55. package/dist/cli/resolve-invocation.js.map +1 -1
  56. package/dist/cli/tag-filters.d.ts +59 -0
  57. package/dist/cli/tag-filters.js +57 -0
  58. package/dist/cli/tag-filters.js.map +1 -0
  59. package/dist/cli/verb-hint.d.ts +25 -0
  60. package/dist/cli/verb-hint.js +138 -0
  61. package/dist/cli/verb-hint.js.map +1 -0
  62. package/dist/cli/width.d.ts +135 -0
  63. package/dist/cli/width.js +313 -0
  64. package/dist/cli/width.js.map +1 -0
  65. package/dist/client.d.ts +137 -24
  66. package/dist/client.js +105 -16
  67. package/dist/client.js.map +1 -1
  68. package/dist/config.d.ts +11 -0
  69. package/dist/config.js +3 -0
  70. package/dist/config.js.map +1 -1
  71. package/dist/contracts.d.ts +87 -17
  72. package/dist/contracts.js +44 -1
  73. package/dist/contracts.js.map +1 -1
  74. package/dist/db/fingerprint.d.ts +12 -0
  75. package/dist/db/fingerprint.js +15 -1
  76. package/dist/db/fingerprint.js.map +1 -1
  77. package/dist/db/locate.js +1 -1
  78. package/dist/db/locate.js.map +1 -1
  79. package/dist/diagnose.d.ts +63 -0
  80. package/dist/diagnose.js +38 -1
  81. package/dist/diagnose.js.map +1 -1
  82. package/dist/index.d.ts +30 -4
  83. package/dist/index.js +35 -2
  84. package/dist/index.js.map +1 -1
  85. package/dist/mcp/server.d.ts +9 -1
  86. package/dist/mcp/server.js +691 -133
  87. package/dist/mcp/server.js.map +1 -1
  88. package/dist/model/entities.d.ts +31 -7
  89. package/dist/model/entities.js.map +1 -1
  90. package/dist/model/mappers.d.ts +7 -0
  91. package/dist/model/mappers.js +7 -2
  92. package/dist/model/mappers.js.map +1 -1
  93. package/dist/model/serialize.d.ts +28 -0
  94. package/dist/model/serialize.js +80 -0
  95. package/dist/model/serialize.js.map +1 -0
  96. package/dist/model/when-sugar.d.ts +47 -0
  97. package/dist/model/when-sugar.js +45 -0
  98. package/dist/model/when-sugar.js.map +1 -0
  99. package/dist/read/area-view.d.ts +8 -1
  100. package/dist/read/area-view.js +49 -13
  101. package/dist/read/area-view.js.map +1 -1
  102. package/dist/read/filter-contract.d.ts +117 -0
  103. package/dist/read/filter-contract.js +78 -0
  104. package/dist/read/filter-contract.js.map +1 -0
  105. package/dist/read/predicates.d.ts +30 -0
  106. package/dist/read/predicates.js +30 -0
  107. package/dist/read/predicates.js.map +1 -1
  108. package/dist/read/project-view.d.ts +12 -1
  109. package/dist/read/project-view.js +39 -8
  110. package/dist/read/project-view.js.map +1 -1
  111. package/dist/read/queries.d.ts +149 -6
  112. package/dist/read/queries.js +250 -31
  113. package/dist/read/queries.js.map +1 -1
  114. package/dist/read/sections.d.ts +51 -0
  115. package/dist/read/sections.js +37 -0
  116. package/dist/read/sections.js.map +1 -0
  117. package/dist/read/sidebar-order.js +2 -1
  118. package/dist/read/sidebar-order.js.map +1 -1
  119. package/dist/read/tags.d.ts +27 -3
  120. package/dist/read/tags.js +83 -12
  121. package/dist/read/tags.js.map +1 -1
  122. package/dist/read/truncation.d.ts +71 -0
  123. package/dist/read/{pagination.js → truncation.js} +103 -94
  124. package/dist/read/truncation.js.map +1 -0
  125. package/dist/read/views.d.ts +140 -16
  126. package/dist/read/views.js +264 -67
  127. package/dist/read/views.js.map +1 -1
  128. package/dist/surface-copy.d.ts +19 -0
  129. package/dist/surface-copy.js +32 -0
  130. package/dist/surface-copy.js.map +1 -1
  131. package/dist/sync-health.d.ts +78 -0
  132. package/dist/sync-health.js +312 -0
  133. package/dist/sync-health.js.map +1 -0
  134. package/dist/write/accessibility-probe.d.ts +12 -0
  135. package/dist/write/accessibility-probe.js +63 -0
  136. package/dist/write/accessibility-probe.js.map +1 -0
  137. package/dist/write/automation-probe.d.ts +7 -0
  138. package/dist/write/automation-probe.js +8 -1
  139. package/dist/write/automation-probe.js.map +1 -1
  140. package/dist/write/batch.js +4 -2
  141. package/dist/write/batch.js.map +1 -1
  142. package/dist/write/capabilities.d.ts +8 -0
  143. package/dist/write/capabilities.js +13 -6
  144. package/dist/write/capabilities.js.map +1 -1
  145. package/dist/write/commands.d.ts +2 -0
  146. package/dist/write/commands.js +562 -48
  147. package/dist/write/commands.js.map +1 -1
  148. package/dist/write/edit-checklist.js +3 -2
  149. package/dist/write/edit-checklist.js.map +1 -1
  150. package/dist/write/guards.d.ts +2 -7
  151. package/dist/write/guards.js +64 -6
  152. package/dist/write/guards.js.map +1 -1
  153. package/dist/write/heading.js +2 -0
  154. package/dist/write/heading.js.map +1 -1
  155. package/dist/write/lock.d.ts +40 -2
  156. package/dist/write/lock.js +91 -14
  157. package/dist/write/lock.js.map +1 -1
  158. package/dist/write/make-repeating-project.d.ts +4 -0
  159. package/dist/write/make-repeating-project.js +253 -0
  160. package/dist/write/make-repeating-project.js.map +1 -0
  161. package/dist/write/operations.d.ts +145 -1
  162. package/dist/write/operations.js +48 -0
  163. package/dist/write/operations.js.map +1 -1
  164. package/dist/write/pipeline.d.ts +19 -0
  165. package/dist/write/pipeline.js +109 -26
  166. package/dist/write/pipeline.js.map +1 -1
  167. package/dist/write/pre-state.d.ts +68 -3
  168. package/dist/write/pre-state.js +102 -3
  169. package/dist/write/pre-state.js.map +1 -1
  170. package/dist/write/reopen.js +3 -2
  171. package/dist/write/reopen.js.map +1 -1
  172. package/dist/write/reorder.js +27 -17
  173. package/dist/write/reorder.js.map +1 -1
  174. package/dist/write/repeat-rule.d.ts +22 -0
  175. package/dist/write/repeat-rule.js +258 -0
  176. package/dist/write/repeat-rule.js.map +1 -0
  177. package/dist/write/reversibility.js +49 -0
  178. package/dist/write/reversibility.js.map +1 -1
  179. package/dist/write/tag-refs.d.ts +47 -0
  180. package/dist/write/tag-refs.js +126 -0
  181. package/dist/write/tag-refs.js.map +1 -0
  182. package/dist/write/undo.d.ts +74 -5
  183. package/dist/write/undo.js +493 -80
  184. package/dist/write/undo.js.map +1 -1
  185. package/dist/write/vectors/registry.d.ts +17 -1
  186. package/dist/write/vectors/registry.js +18 -2
  187. package/dist/write/vectors/registry.js.map +1 -1
  188. package/dist/write/vectors/types.d.ts +119 -3
  189. package/dist/write/vectors/ui-certification.d.ts +48 -0
  190. package/dist/write/vectors/ui-certification.js +46 -0
  191. package/dist/write/vectors/ui-certification.js.map +1 -0
  192. package/dist/write/vectors/ui-drag.d.ts +188 -0
  193. package/dist/write/vectors/ui-drag.js +1095 -0
  194. package/dist/write/vectors/ui-drag.js.map +1 -0
  195. package/dist/write/vectors/ui-recipes.d.ts +70 -0
  196. package/dist/write/vectors/ui-recipes.js +558 -0
  197. package/dist/write/vectors/ui-recipes.js.map +1 -0
  198. package/dist/write/vectors/ui.d.ts +137 -0
  199. package/dist/write/vectors/ui.js +656 -0
  200. package/dist/write/vectors/ui.js.map +1 -0
  201. package/dist/write/verify/delta.d.ts +31 -3
  202. package/dist/write/verify/delta.js +22 -6
  203. package/dist/write/verify/delta.js.map +1 -1
  204. package/dist/write/verify/poller.js +1 -0
  205. package/dist/write/verify/poller.js.map +1 -1
  206. package/package.json +1 -1
  207. package/dist/cli/exit-codes.d.ts +0 -26
  208. package/dist/cli/exit-codes.js +0 -26
  209. package/dist/cli/exit-codes.js.map +0 -1
  210. package/dist/cli/output.d.ts +0 -42
  211. package/dist/cli/output.js +0 -16
  212. package/dist/cli/output.js.map +0 -1
  213. package/dist/read/pagination.d.ts +0 -104
  214. package/dist/read/pagination.js.map +0 -1
@@ -1,5 +1,12 @@
1
+ import { localToday } from "../model/dates.js";
2
+ import { isActiveProjectRow } from "./area-view.js";
1
3
  import { AREA_PREVIEW_LIMIT, DEFAULT_LIST_LIMIT, PROJECT_PREVIEW_LIMIT } from "../surface-copy.js";
4
+ import { partitionSomedaySection, splitSectionBlocks } from "./sections.js";
5
+ // The per-block cap shape and the structural section splitters live in
6
+ // ./sections.ts (imported for capping here). Re-exported so existing importers
7
+ // — and the truncation unit test — keep one import site.
2
8
  export { AREA_PREVIEW_LIMIT, DEFAULT_LIST_LIMIT, PROJECT_PREVIEW_LIMIT };
9
+ export { partitionSomedaySection, splitSectionBlocks };
3
10
  const whole = (total, limit) => ({
4
11
  shown: total,
5
12
  total,
@@ -7,50 +14,50 @@ const whole = (total, limit) => ({
7
14
  truncated: false,
8
15
  });
9
16
  /** Flat list: slice to the limit; total is the full filtered length. */
10
- export function paginateList(items, limit) {
17
+ export function truncateList(items, limit) {
11
18
  const total = items.length;
12
19
  if (limit === null || total <= limit)
13
- return { data: items, pagination: whole(total, limit) };
20
+ return { data: items, truncation: whole(total, limit) };
14
21
  return {
15
22
  data: items.slice(0, limit),
16
- pagination: { shown: limit, total, limit, truncated: true },
23
+ truncation: { shown: limit, total, limit, truncated: true },
17
24
  };
18
25
  }
19
26
  /**
20
27
  * Today split: the cut runs across Today then This Evening in render order,
21
28
  * so a limit smaller than the Today block trims Evening to nothing. The badge
22
- * (a whole-view count summary) is preserved unchanged.
29
+ * (a whole-view count summary) is preserved unchanged. The truncation carries
30
+ * a per-section (`today`/`evening`) shown/total breakdown so a renderer can
31
+ * keep This Evening honest under the single global cap without a pre-cap copy.
23
32
  */
24
- export function paginateToday(view, limit) {
25
- const total = view.today.length + view.evening.length;
26
- if (limit === null || total <= limit)
27
- return { data: view, pagination: whole(total, limit) };
33
+ export function truncateToday(view, limit) {
34
+ const todayTotal = view.today.length;
35
+ const eveningTotal = view.evening.length;
36
+ const total = todayTotal + eveningTotal;
37
+ const sections = (shownToday, shownEvening) => [
38
+ { key: "today", shown: shownToday, total: todayTotal },
39
+ { key: "evening", shown: shownEvening, total: eveningTotal },
40
+ ];
41
+ if (limit === null || total <= limit) {
42
+ return {
43
+ data: view,
44
+ truncation: { ...whole(total, limit), sections: sections(todayTotal, eveningTotal) },
45
+ };
46
+ }
28
47
  const today = view.today.slice(0, limit);
29
48
  const evening = view.evening.slice(0, Math.max(0, limit - today.length));
30
49
  const shown = today.length + evening.length;
31
50
  return {
32
51
  data: { today, evening, badge: view.badge },
33
- pagination: { shown, total, limit, truncated: true },
52
+ truncation: {
53
+ shown,
54
+ total,
55
+ limit,
56
+ truncated: true,
57
+ sections: sections(today.length, evening.length),
58
+ },
34
59
  };
35
60
  }
36
- export function splitSectionBlocks(section) {
37
- const direct = [];
38
- const projects = [];
39
- let cur = null;
40
- for (const item of section.items) {
41
- if (item.type === "project") {
42
- cur = { project: item, items: [] };
43
- projects.push(cur);
44
- }
45
- else if (cur === null) {
46
- direct.push(item);
47
- }
48
- else {
49
- cur.items.push(item);
50
- }
51
- }
52
- return { direct, projects };
53
- }
54
61
  const takeUpTo = (items, limit) => limit === null ? items : items.slice(0, limit);
55
62
  /**
56
63
  * Anytime: the block skeleton is ALWAYS complete — every area header and
@@ -67,57 +74,42 @@ export function previewSections(sections, limits) {
67
74
  for (const section of sections) {
68
75
  const { direct, projects } = splitSectionBlocks(section);
69
76
  const shownDirect = takeUpTo(direct, limits.area);
70
- if (direct.length > 0) {
71
- if (direct.length > shownDirect.length)
72
- truncated = true;
73
- blocks.push({
74
- kind: section.area === null ? "loose" : "area",
75
- uuid: section.area?.uuid ?? null,
76
- title: section.area?.title ?? null,
77
- shown: shownDirect.length,
78
- total: direct.length,
79
- limit: limits.area,
80
- });
81
- }
77
+ if (direct.length > shownDirect.length)
78
+ truncated = true;
79
+ // Project item-lists nest inside their area/loose block.
80
+ const children = [];
82
81
  const items = [...shownDirect];
83
- for (const { project, items: children } of projects) {
84
- const shownChildren = takeUpTo(children, limits.project);
85
- if (children.length > 0) {
86
- if (children.length > shownChildren.length)
82
+ for (const { project, items: kids } of projects) {
83
+ const shownChildren = takeUpTo(kids, limits.project);
84
+ if (kids.length > 0) {
85
+ if (kids.length > shownChildren.length)
87
86
  truncated = true;
88
- blocks.push({
87
+ children.push({
89
88
  kind: "project",
90
- uuid: project.uuid,
89
+ ref: project.uuid,
91
90
  title: project.title,
92
91
  shown: shownChildren.length,
93
- total: children.length,
92
+ total: kids.length,
94
93
  limit: limits.project,
95
94
  });
96
95
  }
97
96
  items.push(project, ...shownChildren);
98
97
  }
98
+ if (direct.length > 0 || children.length > 0) {
99
+ blocks.push({
100
+ kind: section.area === null ? "loose" : "area",
101
+ ref: section.area?.uuid ?? null,
102
+ title: section.area?.title ?? null,
103
+ shown: shownDirect.length,
104
+ total: direct.length,
105
+ limit: limits.area,
106
+ ...(children.length > 0 && { children }),
107
+ });
108
+ }
99
109
  outSections.push({ area: section.area, items });
100
110
  }
101
111
  return { data: outSections, grouped: { truncated, blocks } };
102
112
  }
103
- export function partitionSomedaySection(section) {
104
- const own = [];
105
- const byProject = new Map();
106
- for (const item of section.items) {
107
- const container = item.type === "to-do" ? (item.project ?? item.headingProject ?? null) : null;
108
- if (container === null) {
109
- own.push(item);
110
- continue;
111
- }
112
- let group = byProject.get(container.uuid);
113
- if (group === undefined) {
114
- group = { project: container, items: [] };
115
- byProject.set(container.uuid, group);
116
- }
117
- group.items.push(item);
118
- }
119
- return { own, children: [...byProject.values()] };
120
- }
121
113
  /**
122
114
  * Someday preview: every group survives; `limits.area` (null = no cap)
123
115
  * applies independently to each section's own block (project rows + direct
@@ -132,29 +124,18 @@ export function previewSomedaySections(sections, limits) {
132
124
  for (const section of sections) {
133
125
  const { own, children } = partitionSomedaySection(section);
134
126
  const shownOwn = takeUpTo(own, limits.area);
135
- if (own.length > 0) {
136
- if (own.length > shownOwn.length)
137
- truncated = true;
138
- const totalProjects = own.filter((i) => i.type === "project").length;
139
- blocks.push({
140
- kind: section.area === null ? "loose" : "area",
141
- uuid: section.area?.uuid ?? null,
142
- title: section.area?.title ?? null,
143
- shown: shownOwn.length,
144
- total: own.length,
145
- limit: limits.area,
146
- totalProjects,
147
- totalTodos: own.length - totalProjects,
148
- });
149
- }
127
+ if (own.length > shownOwn.length)
128
+ truncated = true;
129
+ // The active-project child groups nest inside this section's own block.
130
+ const childBlocks = [];
150
131
  const items = [...shownOwn];
151
132
  for (const group of children) {
152
133
  const shown = takeUpTo(group.items, limits.project);
153
134
  if (group.items.length > shown.length)
154
135
  truncated = true;
155
- blocks.push({
136
+ childBlocks.push({
156
137
  kind: "project",
157
- uuid: group.project.uuid,
138
+ ref: group.project.uuid,
158
139
  title: group.project.title,
159
140
  shown: shown.length,
160
141
  total: group.items.length,
@@ -162,6 +143,20 @@ export function previewSomedaySections(sections, limits) {
162
143
  });
163
144
  items.push(...shown);
164
145
  }
146
+ if (own.length > 0 || childBlocks.length > 0) {
147
+ const totalProjects = own.filter((i) => i.type === "project").length;
148
+ blocks.push({
149
+ kind: section.area === null ? "loose" : "area",
150
+ ref: section.area?.uuid ?? null,
151
+ title: section.area?.title ?? null,
152
+ shown: shownOwn.length,
153
+ total: own.length,
154
+ limit: limits.area,
155
+ totalProjects,
156
+ totalTodos: own.length - totalProjects,
157
+ ...(childBlocks.length > 0 && { children: childBlocks }),
158
+ });
159
+ }
165
160
  outSections.push({ area: section.area, items });
166
161
  }
167
162
  return { data: outSections, grouped: { truncated, blocks } };
@@ -169,24 +164,38 @@ export function previewSomedaySections(sections, limits) {
169
164
  /**
170
165
  * Sectioned cap for the `area show` detail view: its sections are containers,
171
166
  * so there is no strict total limit — instead `limits.project` bounds the
172
- * project-ROWS section and `limits.area` the direct-to-dos section (null =
173
- * uncapped). The toggled later/logged lists and the trashed bucket pass
174
- * through untouched. Counts ride the same grouped-block shape the sidebar
175
- * catalogues emit (kind "projects" = the project-rows section).
167
+ * ACTIVE project-ROWS section and `limits.area` the direct-to-dos section
168
+ * (null = uncapped). The cap is render-aware: only the area's ACTIVE project
169
+ * rows are capped, while its future-scheduled and someday project rows always
170
+ * survive (the card renders them under its uncapped Upcoming/Someday sections),
171
+ * so the human view derives entirely from this bounded shape. The toggled
172
+ * later/logged lists and the trashed bucket pass through untouched. Counts ride
173
+ * the same grouped-block shape the sidebar catalogues emit (kind "projects" =
174
+ * the active project-rows section). `now` classifies the schedule split.
176
175
  */
177
- export function capAreaSections(view, limits) {
176
+ export function capAreaSections(view, limits, now) {
177
+ const todayIso = localToday(now);
178
178
  const blocks = [];
179
179
  let truncated = false;
180
- const projects = limits.project === null ? view.projects : view.projects.slice(0, limits.project);
181
- if (view.projects.length > 0) {
182
- if (projects.length < view.projects.length)
180
+ // Cap the ACTIVE project rows in place; scheduled/someday rows always survive.
181
+ const activeTotal = view.projects.filter((p) => isActiveProjectRow(p, todayIso)).length;
182
+ const shownActive = limits.project === null ? activeTotal : Math.min(activeTotal, limits.project);
183
+ let activeSeen = 0;
184
+ const projects = view.projects.filter((p) => {
185
+ if (!isActiveProjectRow(p, todayIso))
186
+ return true;
187
+ activeSeen += 1;
188
+ return limits.project === null || activeSeen <= limits.project;
189
+ });
190
+ if (activeTotal > 0) {
191
+ if (shownActive < activeTotal)
183
192
  truncated = true;
184
193
  blocks.push({
185
194
  kind: "projects",
186
- uuid: view.area.uuid,
195
+ ref: view.area.uuid,
187
196
  title: view.area.title,
188
- shown: projects.length,
189
- total: view.projects.length,
197
+ shown: shownActive,
198
+ total: activeTotal,
190
199
  limit: limits.project,
191
200
  });
192
201
  }
@@ -196,7 +205,7 @@ export function capAreaSections(view, limits) {
196
205
  truncated = true;
197
206
  blocks.push({
198
207
  kind: "area",
199
- uuid: view.area.uuid,
208
+ ref: view.area.uuid,
200
209
  title: view.area.title,
201
210
  shown: active.length,
202
211
  total: view.active.length,
@@ -205,4 +214,4 @@ export function capAreaSections(view, limits) {
205
214
  }
206
215
  return { data: { ...view, projects, active }, grouped: { truncated, blocks } };
207
216
  }
208
- //# sourceMappingURL=pagination.js.map
217
+ //# sourceMappingURL=truncation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncation.js","sourceRoot":"","sources":["../../src/read/truncation.ts"],"names":[],"mappings":"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"}
@@ -20,7 +20,18 @@
20
20
  * overdue bucket=1 items roll back into Today proper (live-
21
21
  * verified against the UI, 2026-07-02).
22
22
  * Sidebar badge split: red = items with deadline <= today,
23
- * gray = the rest (exact 270/122 reconciliation on live data).
23
+ * gray = the rest (exact 270/122 reconciliation on live data). The
24
+ * badge counts OPEN members only — a checked-but-unswept row is in
25
+ * the list but out of the count (the GUI badge is remaining work).
26
+ * CHECKED-BUT-UNSWEPT (GUI-parity ruling 2026-07-14, Mike — "this
27
+ * is the behavior of the Things GUI and I like it"): membership is
28
+ * OPEN_OR_UNSWEPT, not OPEN — a completed/canceled row the log-move
29
+ * sweep has NOT yet passed (completion ≠ logged; see
30
+ * log-boundary.ts) stays in Today IN PLACE, keeping the exact
31
+ * comparator slot (startBucket / referenceDate / todayIndex) it held
32
+ * open. It leaves when the sweep boundary advances past its stopDate
33
+ * (boundary-relative, no new state). Mixed-context resolved styling
34
+ * (dim / dim+strike) applies automatically in formatItem.
24
35
  * - anytime: ALL active items — unscheduled PLUS Today members (the UI
25
36
  * renders Today members with a star; live-verified via screenshot
26
37
  * 2026-07-02: starred = in Today, unstarred = unscheduled).
@@ -29,7 +40,29 @@
29
40
  * project that is not itself anytime-visible (someday/future/
30
41
  * logged/trashed) are excluded — the project row represents
31
42
  * them. Result is grouped in sidebar order (SidebarSection[]).
32
- * - upcoming: start=2 AND startDate > today, PLUS each fixed repeating
43
+ * CHECKED-BUT-UNSWEPT (GUI-parity ruling 2026-07-14, Mike): like
44
+ * Today, membership is OPEN_OR_UNSWEPT — a closed row the sweep has
45
+ * not passed keeps its index slot until the boundary moves past its
46
+ * stopDate. A closed-but-unswept PROJECT row shows in place and its
47
+ * children stay cascade-excluded (PROJECT_ANYTIME_ACTIVE still tests
48
+ * p.status = 0): the checked project row represents its children,
49
+ * the same precedent as a logged/someday container.
50
+ * - upcoming: TWO cohorts merged, grouped/sorted by COALESCE(startDate,
51
+ * deadline) (UPC1, GUI-verified, docs/lab/upcoming-research.md):
52
+ * (1) SCHEDULED — start=2 AND startDate > today, grouped under its
53
+ * when-date (a deadline it also carries rides along as a flag);
54
+ * (2) DEADLINE-FORECAST — startDate IS NULL AND start IN (1, 2)
55
+ * AND deadline > today AND (deadlineSuppressionDate IS NULL OR
56
+ * deadlineSuppressionDate < deadline), grouped under its DEADLINE
57
+ * date (both to-dos and projects). INBOX (start=0) is EXCLUDED — a
58
+ * future deadline does not forecast an Inbox item into Upcoming,
59
+ * though a DUE one still pulls it into Today. The suppression guard
60
+ * drops a dismissed-nag deadline (supp == deadline) and lets a
61
+ * re-armed one (supp < deadline) reappear — the todayView clause
62
+ * one step earlier (deadline > today). A when+deadline row appears
63
+ * ONCE under its when-date, never double-emitted (the forecast
64
+ * cohort requires startDate IS NULL). Forecast rows keep
65
+ * startDate=null (no faked when-date). PLUS each fixed repeating
33
66
  * template's next occurrence synthesized from
34
67
  * rt1_nextInstanceStartDate (UI parity; opt out via
35
68
  * repeats:false). Occurrence deadline = start − rule.ts
@@ -53,18 +86,76 @@ export type ListItem = Todo | Project;
53
86
  /** Optional list-view filters. */
54
87
  export interface ViewFilter {
55
88
  /**
56
- * Tag (uuid or unique title): direct OR inherited membership (UI
57
- * semantics), INCLUDING items tagged with a hierarchy descendant of the
58
- * given tag (documented app behavior the UI's tag filter matches
59
- * child-tagged items; not lab-oracled).
89
+ * Convenience shorthand for a single-element {@link tags} a lone
90
+ * inheritance-inclusive tag ref. Production surfaces (CLI `--tag`, MCP
91
+ * `tag`) always pass the array form; this exists for internal/test callers.
60
92
  */
61
93
  tag?: string;
62
94
  /**
63
- * Match the given tag ONLY no hierarchy descendants. Useful when a
95
+ * Tag refs (uuid or unique title). In FLAT views (today/inbox/anytime/
96
+ * someday/upcoming/search/logbook) this is direct OR inherited membership (UI
97
+ * semantics), INCLUDING items tagged with a hierarchy descendant of each
98
+ * given tag (documented app behavior — the UI's tag filter matches
99
+ * child-tagged items; not lab-oracled). In CONTAINER views (`project show`,
100
+ * `area show`, the `projects` list) the same ref instead matches rows carrying
101
+ * the tag DIRECTLY (still with descendant expansion) — the view's own
102
+ * container-inheritance hop is suppressed, since every child inherits the
103
+ * container's tags and an inheritance-inclusive filter there is vacuous. The
104
+ * host view selects the behavior via {@link tagFilter}'s `container` option.
105
+ * Multiple refs AND together — an item must match EVERY ref (each
106
+ * independently expanded to its descendant set, OR-matched within,
107
+ * AND-combined across).
108
+ */
109
+ tags?: string[];
110
+ /**
111
+ * Match each given tag ref ONLY — no hierarchy descendants. Useful when a
64
112
  * parent tag has its own direct assignments distinct from its children's.
65
113
  */
66
114
  exactTag?: boolean;
115
+ /**
116
+ * Only items with NO tag (the GUI's "No Tag"). In FLAT views this negates the
117
+ * WHOLE direct+inherited membership relation — an item is untagged iff no
118
+ * possible `tag` value could ever match it. In CONTAINER views it instead
119
+ * means "no DIRECT tag" (the container's own inherited tags are suppressed,
120
+ * matching the container `tag` semantics). Mutually exclusive with
121
+ * `tag`/`exactTag` (the surfaces reject the combination).
122
+ */
123
+ untagged?: boolean;
124
+ /**
125
+ * Only OPEN items whose deadline is strictly BEFORE today (due-today is NOT
126
+ * overdue — it mirrors the app's Today badge, where an equal-to-today
127
+ * deadline is "due" and only an earlier one is "overdue"). A content scope
128
+ * like `tag`: it narrows, never lifts a default, and composes as AND with
129
+ * `tag`/`untagged`. The boundary rides the view's injected clock (see
130
+ * {@link OVERDUE}). Honored by the current-work views (today, inbox, anytime,
131
+ * someday, search); the forward-looking `upcoming` and the closed-item
132
+ * `logbook` deliberately do not accept it (see docs/design/cli-grammar.md).
133
+ */
134
+ overdue?: boolean;
67
135
  }
136
+ /**
137
+ * Compose the tag scope for a filter into an AND-chained SQL fragment plus its
138
+ * binds. Every clause AND-combines: the `untagged` negation and each `--tag`
139
+ * ref (each ref independently resolved and descendant-expanded per `exactTag`).
140
+ * The mutually-exclusive combination (`untagged` with a tag-presence flag) is
141
+ * refused at the CLI/MCP surfaces; here it would simply AND to an empty result.
142
+ * Splices in before {@link overdueFilter} so the tag binds precede the overdue
143
+ * bind.
144
+ *
145
+ * `options.container` selects the CONTAINER semantics (`project show` /
146
+ * `area show` / the `projects` list): the view's own inheritance hop is dropped,
147
+ * so `--tag` matches a DIRECT assignment (still descendant-expanded) and
148
+ * `--untagged` means "no direct tag". Every child inherits its container's tags,
149
+ * so an inheritance-inclusive filter there is vacuous — direct-on-the-row is the
150
+ * useful, GUI-faithful behavior. FLAT views omit the option and keep the
151
+ * inheritance-inclusive relation.
152
+ */
153
+ export declare function tagFilter(db: DatabaseSync, filter: ViewFilter | undefined, options?: {
154
+ container?: boolean;
155
+ }): {
156
+ sql: string;
157
+ binds: string[];
158
+ };
68
159
  export interface TodayView {
69
160
  today: ListItem[];
70
161
  evening: ListItem[];
@@ -74,8 +165,28 @@ export interface TodayView {
74
165
  other: number;
75
166
  };
76
167
  }
77
- export declare function todayView(db: DatabaseSync, now?: Date, filter?: ViewFilter): TodayView;
78
- export declare function inboxView(db: DatabaseSync, filter?: ViewFilter): ListItem[];
168
+ export interface TodayFilter extends ViewFilter {
169
+ /**
170
+ * Restrict to the This-Evening section: the Today section is filtered out
171
+ * (returned empty) and the badge counts only the evening members. A section
172
+ * visibility toggle, not a volume change — the row limit still applies.
173
+ */
174
+ eveningOnly?: boolean;
175
+ }
176
+ export declare function todayView(db: DatabaseSync, now?: Date, filter?: TodayFilter): TodayView;
177
+ export interface InboxFilter extends ViewFilter {
178
+ /**
179
+ * Only captures created at/after this instant. Keyed on the item's CREATION
180
+ * timestamp (the raw Cocoa/Unix-epoch creationDate, compared like
181
+ * `changes`/`logbook` do their epoch columns — NOT the packed startDate
182
+ * encoding). A demoted item keeps its original creation date, so this is
183
+ * arrival-into-Things, not arrival-into-the-Inbox.
184
+ */
185
+ since?: Date;
186
+ /** Only captures created at/before this instant (creation timestamp). */
187
+ until?: Date;
188
+ }
189
+ export declare function inboxView(db: DatabaseSync, now?: Date, filter?: InboxFilter): ListItem[];
79
190
  /**
80
191
  * One sidebar-ordered block of a grouped view (anytime/someday): the area
81
192
  * (null = the top-level, area-less block, which the UI renders first) and its
@@ -87,7 +198,19 @@ export interface SidebarSection {
87
198
  items: ListItem[];
88
199
  }
89
200
  export declare function anytimeView(db: DatabaseSync, now?: Date, filter?: ViewFilter): SidebarSection[];
90
- /** The UI's star marker in Anytime: the item is also a Today member. */
201
+ /**
202
+ * The UI's star marker in Anytime: the item is also a Today member. Mirrors
203
+ * {@link todayView}'s two membership arms so an unscheduled item pulled into
204
+ * Today by a due deadline stars exactly like a scheduled one:
205
+ * - SCHEDULED — a When-date that has arrived (startDate <= today); or
206
+ * - DEADLINE-DRIVEN — no When-date, but a due/overdue deadline (deadline <=
207
+ * today) pulls it into Today (the todayView arm that lets a bare deadline
208
+ * surface an item). Only reached for anytime-visible rows (start=1,
209
+ * startDate NULL), so it never over-stars someday/inbox rows.
210
+ * KNOWN LIMITATION: todayView's deadline arm also drops a DISMISSED-nag
211
+ * deadline (deadlineSuppressionDate >= deadline); that column is not surfaced
212
+ * on the entity, so a suppressed unscheduled overdue row is over-starred here.
213
+ */
91
214
  export declare function isTodayMember(item: ListItem, now?: Date): boolean;
92
215
  export interface UpcomingFilter extends ViewFilter {
93
216
  /** Include repeating templates' next occurrences (UI parity; default true). */
@@ -140,15 +263,16 @@ export interface LogbookFilter extends ViewFilter {
140
263
  /** Only entries logged at/before this instant. */
141
264
  until?: Date;
142
265
  }
143
- export declare function logbookView(db: DatabaseSync, options?: LogbookFilter): ListItem[];
144
- export declare function trashView(db: DatabaseSync, options?: {
266
+ export declare function logbookView(db: DatabaseSync, now?: Date, options?: LogbookFilter): ListItem[];
267
+ export declare function trashView(db: DatabaseSync, now?: Date, options?: {
145
268
  limit?: number | null;
146
269
  }): ListItem[];
147
270
  export declare function projectsView(db: DatabaseSync, options?: {
148
271
  areaUuid?: string;
149
272
  later?: boolean;
273
+ overdue?: boolean;
150
274
  now?: Date;
151
- }): Project[];
275
+ } & ViewFilter): Project[];
152
276
  export interface SearchOptions extends ViewFilter {
153
277
  /** Row cap; `null` returns every match (surfaces slice for display). */
154
278
  limit?: number | null;
@@ -176,7 +300,7 @@ export type ChangedItem = ListItem & {
176
300
  * carry no modification dates, and checklist-item edits do not bump the
177
301
  * parent task — those changes are invisible here.
178
302
  */
179
- export declare function changesView(db: DatabaseSync, options: {
303
+ export declare function changesView(db: DatabaseSync, now: Date | undefined, options: {
180
304
  since: Date;
181
305
  limit?: number | null;
182
306
  }): ChangedItem[];
@@ -197,7 +321,7 @@ export interface LiteSearchResult {
197
321
  export declare function liteTitleSearch(db: DatabaseSync, query: string, options?: {
198
322
  type?: "to-do" | "project" | "area";
199
323
  limit?: number;
200
- }): LiteSearchResult;
324
+ }, now?: Date): LiteSearchResult;
201
325
  /** A search result annotated with WHY it surfaced (additive; `matchedVia` present only for heading-credited projects). */
202
326
  export type SearchResultItem = ListItem & {
203
327
  matchedVia?: {
@@ -205,4 +329,4 @@ export type SearchResultItem = ListItem & {
205
329
  title: string;
206
330
  };
207
331
  };
208
- export declare function searchView(db: DatabaseSync, query: string, options?: SearchOptions): SearchResultItem[];
332
+ export declare function searchView(db: DatabaseSync, query: string, options?: SearchOptions, now?: Date): SearchResultItem[];