things-api 0.11.0 → 0.12.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.
- package/README.md +16 -5
- package/dist/audit/schema.d.ts +7 -0
- package/dist/audit/schema.js.map +1 -1
- package/dist/cli/commands/area.d.ts +18 -11
- package/dist/cli/commands/area.js +55 -67
- package/dist/cli/commands/area.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +1 -2
- package/dist/cli/commands/doctor.js +11 -1
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/install-skill.d.ts +19 -4
- package/dist/cli/commands/install-skill.js +101 -52
- package/dist/cli/commands/install-skill.js.map +1 -1
- package/dist/cli/commands/mcp.js +9 -0
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/project.d.ts +1 -0
- package/dist/cli/commands/project.js +20 -28
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/reads.js +100 -28
- package/dist/cli/commands/reads.js.map +1 -1
- package/dist/cli/commands/show.js +32 -8
- package/dist/cli/commands/show.js.map +1 -1
- package/dist/cli/commands/todo.js +1 -1
- package/dist/cli/commands/todo.js.map +1 -1
- package/dist/cli/commands/writes.js +769 -143
- package/dist/cli/commands/writes.js.map +1 -1
- package/dist/cli/did-you-mean.d.ts +14 -3
- package/dist/cli/did-you-mean.js +26 -3
- package/dist/cli/did-you-mean.js.map +1 -1
- package/dist/cli/glyphs.d.ts +16 -2
- package/dist/cli/glyphs.js +60 -12
- package/dist/cli/glyphs.js.map +1 -1
- package/dist/cli/help.js +67 -12
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +1 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/move-hint.d.ts +3 -2
- package/dist/cli/move-hint.js +2 -2
- package/dist/cli/move-hint.js.map +1 -1
- package/dist/cli/read-driver.d.ts +43 -5
- package/dist/cli/read-driver.js +81 -15
- package/dist/cli/read-driver.js.map +1 -1
- package/dist/cli/render.d.ts +19 -8
- package/dist/cli/render.js +59 -25
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/resolve-invocation.d.ts +2 -2
- package/dist/cli/resolve-invocation.js +3 -3
- package/dist/cli/resolve-invocation.js.map +1 -1
- package/dist/cli/skill-check.d.ts +12 -6
- package/dist/cli/skill-check.js +31 -14
- package/dist/cli/skill-check.js.map +1 -1
- package/dist/cli/skill.d.ts +8 -0
- package/dist/cli/skill.js +10 -0
- package/dist/cli/skill.js.map +1 -1
- package/dist/cli/verb-hint.js +1 -1
- package/dist/cli/verb-hint.js.map +1 -1
- package/dist/client.d.ts +140 -19
- package/dist/client.js +253 -38
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +66 -2
- package/dist/config.js +120 -12
- package/dist/config.js.map +1 -1
- package/dist/contracts.d.ts +176 -28
- package/dist/contracts.js +22 -1
- package/dist/contracts.js.map +1 -1
- package/dist/diagnose.d.ts +34 -2
- package/dist/diagnose.js +36 -1
- package/dist/diagnose.js.map +1 -1
- package/dist/index.d.ts +19 -8
- package/dist/index.js +19 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.js +733 -304
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/entities.d.ts +46 -3
- package/dist/model/entities.js.map +1 -1
- package/dist/model/mappers.d.ts +2 -0
- package/dist/model/mappers.js +41 -2
- package/dist/model/mappers.js.map +1 -1
- package/dist/model/recurrence.d.ts +8 -1
- package/dist/model/recurrence.js.map +1 -1
- package/dist/read/area-filter.d.ts +76 -0
- package/dist/read/area-filter.js +59 -0
- package/dist/read/area-filter.js.map +1 -0
- package/dist/read/area-view.d.ts +11 -11
- package/dist/read/area-view.js +50 -28
- package/dist/read/area-view.js.map +1 -1
- package/dist/read/detail.js +15 -8
- package/dist/read/detail.js.map +1 -1
- package/dist/read/predicates.d.ts +18 -0
- package/dist/read/predicates.js +19 -0
- package/dist/read/predicates.js.map +1 -1
- package/dist/read/project-view.d.ts +31 -15
- package/dist/read/project-view.js +72 -39
- package/dist/read/project-view.js.map +1 -1
- package/dist/read/pseudo-area.d.ts +29 -0
- package/dist/read/pseudo-area.js +27 -0
- package/dist/read/pseudo-area.js.map +1 -0
- package/dist/read/queries.d.ts +105 -18
- package/dist/read/queries.js +185 -30
- package/dist/read/queries.js.map +1 -1
- package/dist/read/scope.d.ts +126 -0
- package/dist/read/scope.js +162 -0
- package/dist/read/scope.js.map +1 -0
- package/dist/read/search-rank.d.ts +2 -5
- package/dist/read/shape.d.ts +162 -0
- package/dist/read/shape.js +686 -0
- package/dist/read/shape.js.map +1 -0
- package/dist/read/show-target.d.ts +9 -1
- package/dist/read/show-target.js +45 -4
- package/dist/read/show-target.js.map +1 -1
- package/dist/read/stage.d.ts +199 -0
- package/dist/read/stage.js +125 -0
- package/dist/read/stage.js.map +1 -0
- package/dist/read/truncation.d.ts +7 -5
- package/dist/read/truncation.js +33 -8
- package/dist/read/truncation.js.map +1 -1
- package/dist/read/views.d.ts +49 -9
- package/dist/read/views.js +193 -40
- package/dist/read/views.js.map +1 -1
- package/dist/surface-copy.d.ts +9 -0
- package/dist/surface-copy.js +9 -0
- package/dist/surface-copy.js.map +1 -1
- package/dist/write/batch.d.ts +49 -10
- package/dist/write/batch.js +423 -71
- package/dist/write/batch.js.map +1 -1
- package/dist/write/commands.js +266 -55
- package/dist/write/commands.js.map +1 -1
- package/dist/write/guards.d.ts +1 -1
- package/dist/write/guards.js +71 -10
- package/dist/write/guards.js.map +1 -1
- package/dist/write/heading.d.ts +10 -1
- package/dist/write/heading.js +35 -5
- package/dist/write/heading.js.map +1 -1
- package/dist/write/make-repeating-project.d.ts +2 -2
- package/dist/write/make-repeating-project.js +9 -9
- package/dist/write/make-repeating-project.js.map +1 -1
- package/dist/write/move.d.ts +130 -0
- package/dist/write/move.js +1533 -0
- package/dist/write/move.js.map +1 -0
- package/dist/write/operations.d.ts +105 -19
- package/dist/write/operations.js +56 -7
- package/dist/write/operations.js.map +1 -1
- package/dist/write/opid.d.ts +31 -0
- package/dist/write/opid.js +30 -0
- package/dist/write/opid.js.map +1 -0
- package/dist/write/pipeline.d.ts +70 -3
- package/dist/write/pipeline.js +198 -33
- package/dist/write/pipeline.js.map +1 -1
- package/dist/write/pre-state.d.ts +162 -8
- package/dist/write/pre-state.js +385 -20
- package/dist/write/pre-state.js.map +1 -1
- package/dist/write/reorder.d.ts +23 -3
- package/dist/write/reorder.js +1871 -85
- package/dist/write/reorder.js.map +1 -1
- package/dist/write/reversibility.js +19 -7
- package/dist/write/reversibility.js.map +1 -1
- package/dist/write/scope-guard.d.ts +31 -0
- package/dist/write/scope-guard.js +162 -0
- package/dist/write/scope-guard.js.map +1 -0
- package/dist/write/undo.js +120 -13
- package/dist/write/undo.js.map +1 -1
- package/dist/write/vectors/applescript.js +16 -7
- package/dist/write/vectors/applescript.js.map +1 -1
- package/dist/write/vectors/shortcuts.js +1 -1
- package/dist/write/vectors/shortcuts.js.map +1 -1
- package/dist/write/vectors/simulator.js +83 -27
- package/dist/write/vectors/simulator.js.map +1 -1
- package/dist/write/vectors/types.d.ts +11 -0
- package/dist/write/vectors/ui-certification.d.ts +3 -3
- package/dist/write/vectors/ui-certification.js +41 -5
- package/dist/write/vectors/ui-certification.js.map +1 -1
- package/dist/write/vectors/ui-drag.d.ts +21 -1
- package/dist/write/vectors/ui-drag.js +138 -27
- package/dist/write/vectors/ui-drag.js.map +1 -1
- package/dist/write/vectors/ui-recipes.d.ts +21 -1
- package/dist/write/vectors/ui-recipes.js +166 -7
- package/dist/write/vectors/ui-recipes.js.map +1 -1
- package/dist/write/vectors/ui.d.ts +25 -1
- package/dist/write/vectors/ui.js +142 -33
- package/dist/write/vectors/ui.js.map +1 -1
- package/dist/write/verify/delta.d.ts +17 -1
- package/dist/write/verify/delta.js +106 -29
- package/dist/write/verify/delta.js.map +1 -1
- package/package.json +7 -1
- package/schema/envelope.schema.json +383 -0
- package/skills/things-cli/SKILL.md +34 -17
- package/skills/things-cli/references/banner.md +35 -0
- package/skills/things-cli/references/contracts.md +30 -9
- package/skills/things-cli/references/errors.md +49 -0
- package/skills/things-cli/references/gui.md +1 -1
- package/skills/things-cli/references/model.md +15 -6
- package/skills/things-cli/references/ordering.md +71 -0
|
@@ -11,6 +11,24 @@ export class ProjectNotFoundError extends Error {
|
|
|
11
11
|
this.name = "ProjectNotFoundError";
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
+
/** Append `value` to the list at `key`, creating it on first use. */
|
|
15
|
+
function pushInto(map, key, value) {
|
|
16
|
+
const list = map.get(key) ?? [];
|
|
17
|
+
list.push(value);
|
|
18
|
+
map.set(key, list);
|
|
19
|
+
}
|
|
20
|
+
/** Group scheduled rows into per-day buckets (date ASC, within-day todayIndex ASC). */
|
|
21
|
+
function groupByDate(rows) {
|
|
22
|
+
const out = [];
|
|
23
|
+
for (const { date, todo } of rows.toSorted((a, b) => a.date.localeCompare(b.date) || a.ti - b.ti)) {
|
|
24
|
+
const last = out[out.length - 1];
|
|
25
|
+
if (last && last.date === date)
|
|
26
|
+
last.items.push(todo);
|
|
27
|
+
else
|
|
28
|
+
out.push({ date, items: [todo] });
|
|
29
|
+
}
|
|
30
|
+
return out;
|
|
31
|
+
}
|
|
14
32
|
export function projectView(db, uuid, now, filter = {}, zone) {
|
|
15
33
|
const overdue = filter.overdue === true;
|
|
16
34
|
const projectRow = fetchTaskByUuid(db, uuid);
|
|
@@ -43,7 +61,7 @@ export function projectView(db, uuid, now, filter = {}, zone) {
|
|
|
43
61
|
// the two uuid binds and lead the overdue bind, matching their left-to-right
|
|
44
62
|
// order in the SQL.
|
|
45
63
|
const tf = tagFilter(db, filter, { container: true });
|
|
46
|
-
const childRows = fetchTaskRows(db, `t.type = 0 AND (t.project = ? OR t.heading IN (
|
|
64
|
+
const childRows = fetchTaskRows(db, `t.type = 0 AND t.trashed = 0 AND (t.project = ? OR t.heading IN (
|
|
47
65
|
SELECT uuid FROM TMTask WHERE type = 2 AND project = ?
|
|
48
66
|
))${tf.sql}${overdueSql}
|
|
49
67
|
ORDER BY t."index" ASC`, [uuid, uuid, ...tf.binds, ...overdueBinds]);
|
|
@@ -54,24 +72,35 @@ export function projectView(db, uuid, now, filter = {}, zone) {
|
|
|
54
72
|
todo: mapTodo(r, refs, childTags.get(r.uuid) ?? [], packedToday),
|
|
55
73
|
}));
|
|
56
74
|
markLogged([project, ...todos.map((t) => t.todo)], boundary);
|
|
75
|
+
// Project-level (UNHEADED) buckets.
|
|
57
76
|
const active = [];
|
|
58
|
-
const byHeading = new Map();
|
|
59
77
|
const scheduledRows = [];
|
|
60
78
|
const repeating = [];
|
|
61
79
|
const someday = [];
|
|
62
80
|
const logged = [];
|
|
63
|
-
|
|
81
|
+
// Per-heading sub-buckets, keyed by heading uuid (§9 fidelity fix): a headed
|
|
82
|
+
// scheduled/someday/repeating child nests under its heading, NOT at the
|
|
83
|
+
// project level.
|
|
84
|
+
const headingItems = new Map();
|
|
85
|
+
const headingScheduled = new Map();
|
|
86
|
+
const headingSomeday = new Map();
|
|
87
|
+
const headingRepeating = new Map();
|
|
88
|
+
// Known (fetched, untrashed) headings — a child whose heading FK is not one
|
|
89
|
+
// of these falls back to the project-level (unheaded) buckets rather than
|
|
90
|
+
// vanishing (mirrors the render's historical loose fallback).
|
|
91
|
+
const headingSet = new Set(headings.map((h) => h.uuid));
|
|
92
|
+
const headingUuidOf = (row) => row.heading !== null && headingSet.has(row.heading) ? row.heading : null;
|
|
64
93
|
// Every untrashed, non-template OPEN child, regardless of which bucket it
|
|
65
94
|
// lands in below — surfaced (only when the project is itself resolved) as
|
|
66
95
|
// the PLOG1 stranded-open-child count.
|
|
67
96
|
let openChildren = 0;
|
|
68
97
|
for (const { row, todo } of todos) {
|
|
69
|
-
|
|
70
|
-
trashed.push(todo);
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
98
|
+
const h = headingUuidOf(row);
|
|
73
99
|
if (todo.repeating.isTemplate) {
|
|
74
|
-
|
|
100
|
+
if (h !== null)
|
|
101
|
+
pushInto(headingRepeating, h, todo);
|
|
102
|
+
else
|
|
103
|
+
repeating.push(todo);
|
|
75
104
|
continue;
|
|
76
105
|
}
|
|
77
106
|
if (row.status === 0)
|
|
@@ -84,61 +113,65 @@ export function projectView(db, uuid, now, filter = {}, zone) {
|
|
|
84
113
|
logged.push(todo);
|
|
85
114
|
continue;
|
|
86
115
|
}
|
|
87
|
-
if (
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
byHeading.set(row.heading, list);
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
116
|
+
if (h !== null)
|
|
117
|
+
pushInto(headingItems, h, todo);
|
|
118
|
+
else
|
|
93
119
|
active.push(todo);
|
|
94
|
-
}
|
|
95
120
|
continue;
|
|
96
121
|
}
|
|
97
122
|
if (row.start === 2 && row.startDate === null) {
|
|
98
|
-
|
|
123
|
+
if (h !== null)
|
|
124
|
+
pushInto(headingSomeday, h, todo);
|
|
125
|
+
else
|
|
126
|
+
someday.push(todo);
|
|
99
127
|
continue;
|
|
100
128
|
}
|
|
101
129
|
if (row.startDate !== null && row.startDate > packedToday) {
|
|
102
|
-
|
|
130
|
+
const sr = {
|
|
103
131
|
date: decodePackedDate(row.startDate) ?? "",
|
|
104
132
|
ti: row.todayIndex ?? 0,
|
|
105
133
|
todo,
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
list.push(todo);
|
|
112
|
-
byHeading.set(row.heading, list);
|
|
134
|
+
};
|
|
135
|
+
if (h !== null)
|
|
136
|
+
pushInto(headingScheduled, h, sr);
|
|
137
|
+
else
|
|
138
|
+
scheduledRows.push(sr);
|
|
113
139
|
continue;
|
|
114
140
|
}
|
|
115
|
-
|
|
141
|
+
if (h !== null)
|
|
142
|
+
pushInto(headingItems, h, todo);
|
|
143
|
+
else
|
|
144
|
+
active.push(todo);
|
|
116
145
|
}
|
|
117
146
|
logged.sort((a, b) => (b.stopped?.getTime() ?? 0) - (a.stopped?.getTime() ?? 0));
|
|
118
|
-
const scheduled = [];
|
|
119
147
|
// Within a day the UI sorts by todayIndex ASC (Upcoming drag order).
|
|
120
|
-
|
|
121
|
-
const last = scheduled[scheduled.length - 1];
|
|
122
|
-
if (last && last.date === date)
|
|
123
|
-
last.items.push(todo);
|
|
124
|
-
else
|
|
125
|
-
scheduled.push({ date, items: [todo] });
|
|
126
|
-
}
|
|
148
|
+
const scheduled = groupByDate(scheduledRows);
|
|
127
149
|
// Under any content scope (`--overdue` or a tag filter), a heading whose
|
|
128
150
|
// children were all filtered out collapses rather than rendering an empty
|
|
129
|
-
// section; a heading with
|
|
130
|
-
// every heading renders (its own empty state).
|
|
151
|
+
// section; a heading with any surviving child (in ANY sub-bucket) is kept.
|
|
152
|
+
// With no scope active every heading renders (its own empty state).
|
|
131
153
|
const contentScoped = overdue || tf.sql !== "";
|
|
132
154
|
const headingGroups = headings
|
|
133
|
-
.map((heading) => ({
|
|
134
|
-
|
|
155
|
+
.map((heading) => ({
|
|
156
|
+
heading,
|
|
157
|
+
items: headingItems.get(heading.uuid) ?? [],
|
|
158
|
+
scheduled: groupByDate(headingScheduled.get(heading.uuid) ?? []),
|
|
159
|
+
someday: headingSomeday.get(heading.uuid) ?? [],
|
|
160
|
+
repeating: headingRepeating.get(heading.uuid) ?? [],
|
|
161
|
+
}))
|
|
162
|
+
.filter((g) => !contentScoped ||
|
|
163
|
+
g.items.length > 0 ||
|
|
164
|
+
g.scheduled.length > 0 ||
|
|
165
|
+
g.someday.length > 0 ||
|
|
166
|
+
g.repeating.length > 0);
|
|
135
167
|
return {
|
|
136
168
|
project,
|
|
137
169
|
active,
|
|
138
170
|
headings: headingGroups,
|
|
139
|
-
|
|
171
|
+
scheduled,
|
|
172
|
+
someday,
|
|
173
|
+
repeating,
|
|
140
174
|
logged,
|
|
141
|
-
trashed,
|
|
142
175
|
openChildrenWhileResolved: project.status === "open" ? 0 : openChildren,
|
|
143
176
|
};
|
|
144
177
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-view.js","sourceRoot":"","sources":["../../src/read/project-view.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"project-view.js","sourceRoot":"","sources":["../../src/read/project-view.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `loose` pseudo-area: a reserved, case-insensitive ref that addresses the
|
|
3
|
+
* NULL area (area-less items) as if it were an area, on READ surfaces only. It
|
|
4
|
+
* mirrors the GUI sidebar's leading loose block — area-less projects, then loose
|
|
5
|
+
* direct to-dos — plus the "Later Projects" someday/scheduled block under
|
|
6
|
+
* `--show-later`. The reserved word ALWAYS wins over a real area that happens to
|
|
7
|
+
* be named "Loose" (that area is reachable only by uuid); when one shadows, the
|
|
8
|
+
* read surfaces a resolution disclosure. Every WRITE verb and the `open` command
|
|
9
|
+
* refuse the reserved word by name — the pseudo-area is a derived view, not a
|
|
10
|
+
* mutable container.
|
|
11
|
+
*/
|
|
12
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
13
|
+
/** The reserved ref (lowercase canonical form) that names the loose pseudo-area. */
|
|
14
|
+
export declare const LOOSE_REF = "loose";
|
|
15
|
+
/** True when a ref names the reserved `loose` pseudo-area (case-insensitive, trimmed). */
|
|
16
|
+
export declare function isLooseRef(ref: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The uuid of a real area whose title case-insensitively equals the reserved
|
|
19
|
+
* word, if any — for the resolution-shadow disclosure. Lowest sidebar index
|
|
20
|
+
* wins on the (pathological) chance of duplicates. Returns undefined when no
|
|
21
|
+
* real area shadows the reserved word.
|
|
22
|
+
*/
|
|
23
|
+
export declare function shadowingLooseArea(db: DatabaseSync): string | undefined;
|
|
24
|
+
/** The disclosure appended to a loose read when a real area shadows the reserved word. */
|
|
25
|
+
export declare function looseShadowNotice(uuid: string): string;
|
|
26
|
+
/** Refusal for opening the loose pseudo-area — it is a derived view, not an app screen. */
|
|
27
|
+
export declare const LOOSE_OPEN_REFUSAL = "the loose pseudo-area is a derived view \u2014 it cannot be opened; open a specific project or area by ref";
|
|
28
|
+
/** Refusal for `--to-area loose` — the reserved word is a read-only view, not a destination. */
|
|
29
|
+
export declare const LOOSE_TO_AREA_REFUSAL = "the loose pseudo-area is a derived view \u2014 it cannot be modified; to leave a to-do area-less use --loose (a project: --no-area), or target a real area named \"Loose\" by uuid";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** The reserved ref (lowercase canonical form) that names the loose pseudo-area. */
|
|
2
|
+
export const LOOSE_REF = "loose";
|
|
3
|
+
/** True when a ref names the reserved `loose` pseudo-area (case-insensitive, trimmed). */
|
|
4
|
+
export function isLooseRef(ref) {
|
|
5
|
+
return ref.trim().toLowerCase() === LOOSE_REF;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The uuid of a real area whose title case-insensitively equals the reserved
|
|
9
|
+
* word, if any — for the resolution-shadow disclosure. Lowest sidebar index
|
|
10
|
+
* wins on the (pathological) chance of duplicates. Returns undefined when no
|
|
11
|
+
* real area shadows the reserved word.
|
|
12
|
+
*/
|
|
13
|
+
export function shadowingLooseArea(db) {
|
|
14
|
+
const row = db
|
|
15
|
+
.prepare(`SELECT uuid FROM TMArea WHERE lower(title) = ? ORDER BY "index" ASC LIMIT 1`)
|
|
16
|
+
.get(LOOSE_REF);
|
|
17
|
+
return row?.uuid;
|
|
18
|
+
}
|
|
19
|
+
/** The disclosure appended to a loose read when a real area shadows the reserved word. */
|
|
20
|
+
export function looseShadowNotice(uuid) {
|
|
21
|
+
return `resolved to the loose pseudo-area; an area named "Loose" exists (uuid ${uuid}) — target it by uuid`;
|
|
22
|
+
}
|
|
23
|
+
/** Refusal for opening the loose pseudo-area — it is a derived view, not an app screen. */
|
|
24
|
+
export const LOOSE_OPEN_REFUSAL = "the loose pseudo-area is a derived view — it cannot be opened; open a specific project or area by ref";
|
|
25
|
+
/** Refusal for `--to-area loose` — the reserved word is a read-only view, not a destination. */
|
|
26
|
+
export const LOOSE_TO_AREA_REFUSAL = 'the loose pseudo-area is a derived view — it cannot be modified; to leave a to-do area-less use --loose (a project: --no-area), or target a real area named "Loose" by uuid';
|
|
27
|
+
//# sourceMappingURL=pseudo-area.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pseudo-area.js","sourceRoot":"","sources":["../../src/read/pseudo-area.ts"],"names":[],"mappings":"AAaA,oFAAoF;AACpF,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC;AAEjC,0FAA0F;AAC1F,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC;AAChD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,EAAgB;IACjD,MAAM,GAAG,GAAG,EAAE;SACX,OAAO,CAAC,6EAA6E,CAAC;SACtF,GAAG,CAAC,SAAS,CAAiC,CAAC;IAClD,OAAO,GAAG,EAAE,IAAI,CAAC;AACnB,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,yEAAyE,IAAI,uBAAuB,CAAC;AAC9G,CAAC;AAED,2FAA2F;AAC3F,MAAM,CAAC,MAAM,kBAAkB,GAC7B,uGAAuG,CAAC;AAE1G,gGAAgG;AAChG,MAAM,CAAC,MAAM,qBAAqB,GAChC,6KAA6K,CAAC"}
|
package/dist/read/queries.d.ts
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* schema manifest so removed columns fail loudly (drift), never silently.
|
|
4
4
|
*/
|
|
5
5
|
import type { DatabaseSync } from "node:sqlite";
|
|
6
|
-
import type
|
|
6
|
+
import { type Ref } from "../model/entities.ts";
|
|
7
7
|
import type { ChecklistRow, TaskRow } from "../model/mappers.ts";
|
|
8
|
+
import { type CandidateRef } from "./shape.ts";
|
|
8
9
|
/** Rows that repeat via a template are normal; template rows are invisible in list views. */
|
|
9
10
|
export declare const NOT_TEMPLATE = "(t.rt1_recurrenceRule IS NULL AND t.repeater IS NULL)";
|
|
10
11
|
/**
|
|
@@ -83,37 +84,44 @@ export declare function stripThingsUri(ref: string): string;
|
|
|
83
84
|
* that matches nothing reads identically wherever the miss is reported.
|
|
84
85
|
*/
|
|
85
86
|
export declare function noUuidMatch(entity: string, ref: string): string;
|
|
86
|
-
/** A disambiguation candidate for a reference-resolution failure. */
|
|
87
|
-
export interface RefCandidate {
|
|
88
|
-
uuid: string;
|
|
89
|
-
title: string;
|
|
90
|
-
/** Optional context that distinguishes same-named candidates (area for a project, parent path for a tag). */
|
|
91
|
-
context?: string;
|
|
92
|
-
}
|
|
93
87
|
/**
|
|
94
88
|
* A reference (uuid / partial-uuid / name) that did not resolve to exactly one
|
|
95
89
|
* entity. Extends RangeError so every existing `instanceof RangeError` handler
|
|
96
90
|
* keeps treating it as a usage-class failure — but the surfaces that know about
|
|
97
91
|
* it (CLI --json envelope, MCP tool result) additionally lift the structured
|
|
98
|
-
* `candidates` onto `error.
|
|
92
|
+
* `candidates` onto `error.detail.candidates` so an agent can self-correct
|
|
99
93
|
* without re-parsing the prose message. `code` mirrors the envelope error code.
|
|
100
94
|
*
|
|
101
95
|
* PUBLIC API — exported from src/index.ts. This is the one error the consumer
|
|
102
96
|
* surfaces catch to render structured disambiguation; its `code`
|
|
103
|
-
* ("not-found" | "ambiguous") and `candidates` ({@link
|
|
104
|
-
*
|
|
97
|
+
* ("not-found" | "ambiguous") and `candidates` ({@link CandidateRef}[], the ONE
|
|
98
|
+
* fixed candidate shape) are the documented machine shape
|
|
99
|
+
* (docs/design/architecture.md, Consumer boundary). The list is capped at
|
|
100
|
+
* {@link CANDIDATE_CAP}; on overflow the `message` states the total.
|
|
105
101
|
*/
|
|
106
102
|
export declare class ReferenceResolutionError extends RangeError {
|
|
107
103
|
readonly code: "not-found" | "ambiguous";
|
|
108
104
|
readonly ref: string;
|
|
109
|
-
readonly candidates:
|
|
105
|
+
readonly candidates: CandidateRef[];
|
|
110
106
|
constructor(message: string, opts: {
|
|
111
107
|
code: "not-found" | "ambiguous";
|
|
112
108
|
ref: string;
|
|
113
|
-
candidates?:
|
|
109
|
+
candidates?: CandidateRef[];
|
|
114
110
|
});
|
|
115
111
|
}
|
|
116
|
-
|
|
112
|
+
/**
|
|
113
|
+
* An optional membership clause (on alias `t`) restricting a resolver to
|
|
114
|
+
* in-scope rows — the container-scope no-oracle mechanism. When supplied, an
|
|
115
|
+
* out-of-scope row resolves to "not found" through the IDENTICAL code path a
|
|
116
|
+
* nonexistent one does, so the two are byte-indistinguishable. Built by
|
|
117
|
+
* `src/read/scope.ts`; queries.ts treats it as opaque SQL to avoid a runtime
|
|
118
|
+
* import cycle.
|
|
119
|
+
*/
|
|
120
|
+
export interface ScopeClause {
|
|
121
|
+
where: string;
|
|
122
|
+
binds: (string | number)[];
|
|
123
|
+
}
|
|
124
|
+
export declare function resolveTaskUuidPrefix(db: DatabaseSync, refRaw: string, entity?: string, scope?: ScopeClause): string;
|
|
117
125
|
/**
|
|
118
126
|
* Fold a name to its match key: NFC + case-fold + strip all whitespace and
|
|
119
127
|
* dashes/hyphens (ASCII hyphen, the U+2010–2015 dash block, U+2212 minus).
|
|
@@ -147,7 +155,21 @@ export interface NamedResolution {
|
|
|
147
155
|
*/
|
|
148
156
|
export declare function resolveNamedRef(db: DatabaseSync, table: string, extraWhere: string, extraBinds: (string | number)[], refRaw: string, options?: {
|
|
149
157
|
prefixTier?: boolean;
|
|
158
|
+
scopeWhere?: string;
|
|
159
|
+
scopeBinds?: (string | number)[];
|
|
160
|
+
/**
|
|
161
|
+
* An extra clause AND-ed into the NAME tiers ONLY (exact/case-insensitive/
|
|
162
|
+
* normalized title) — never the uuid-exact or uuid-prefix tiers. Lets a
|
|
163
|
+
* resolver narrow name resolution (e.g. project write targets to OPEN rows)
|
|
164
|
+
* while a UUID / partial-uuid — explicit intent — still reaches every row.
|
|
165
|
+
*/
|
|
166
|
+
nameExtraWhere?: string;
|
|
150
167
|
}): NamedResolution;
|
|
168
|
+
export declare function deadNameMatchHint(counts: {
|
|
169
|
+
trashed?: number;
|
|
170
|
+
logbook?: number;
|
|
171
|
+
completed?: number;
|
|
172
|
+
}): string;
|
|
151
173
|
/**
|
|
152
174
|
* Resolve a PROJECT write target from a uuid, partial-uuid, or unique name.
|
|
153
175
|
* Project write verbs (`things project update <ref>`, etc.) accept names
|
|
@@ -159,11 +181,30 @@ export declare function resolveNamedRef(db: DatabaseSync, table: string, extraWh
|
|
|
159
181
|
* targeted "that is a to-do, not a project" message rather than a misleading
|
|
160
182
|
* not-found. Otherwise the ref resolves as a project NAME through the SAME
|
|
161
183
|
* tiered {@link resolveNamedRef} matching the read side uses (shared core, not
|
|
162
|
-
* a fork)
|
|
163
|
-
*
|
|
164
|
-
*
|
|
184
|
+
* a fork).
|
|
185
|
+
*
|
|
186
|
+
* The NAME pool is LIVE + OPEN-scoped by default (`trashed = 0 AND status = 0`)
|
|
187
|
+
* — a trashed OR completed/canceled project never resolves-by-name or appears as
|
|
188
|
+
* an ambiguity candidate for an ordinary write verb. A completed project is
|
|
189
|
+
* excluded deliberately (broader than "logged", which needs the log-boundary
|
|
190
|
+
* clock this pure resolver lacks): placing an open child in it strands the child
|
|
191
|
+
* one sweep later (PLOG1). A name that matches ONLY non-open/trashed rows fails
|
|
192
|
+
* not-found with an honest hint (`things trash` / target-by-uuid) rather than a
|
|
193
|
+
* dead candidate. A UUID / partial-uuid resolves FIRST (via
|
|
194
|
+
* {@link resolveTaskUuidPrefix}, status-blind), so explicit-uuid intent still
|
|
195
|
+
* reaches a completed/logged project. `includeNonOpen` (the `project.reopen`
|
|
196
|
+
* verb — its whole point is a non-open target) widens the name pool to
|
|
197
|
+
* completed/canceled rows; `includeTrashed` (the trash-domain `project.restore`
|
|
198
|
+
* op) widens it to trashed rows so a restore-by-name can disambiguate them.
|
|
199
|
+
* Fail-closed with a candidate listing on an ambiguous name.
|
|
165
200
|
*/
|
|
166
|
-
export declare function resolveProjectWriteTarget(db: DatabaseSync, refRaw: string
|
|
201
|
+
export declare function resolveProjectWriteTarget(db: DatabaseSync, refRaw: string, scope?: {
|
|
202
|
+
task: ScopeClause;
|
|
203
|
+
named: {
|
|
204
|
+
where: string;
|
|
205
|
+
binds: (string | number)[];
|
|
206
|
+
};
|
|
207
|
+
}, includeTrashed?: boolean, includeNonOpen?: boolean): string;
|
|
167
208
|
export declare function resolveTagUuid(db: DatabaseSync, ref: string): string;
|
|
168
209
|
/**
|
|
169
210
|
* Write destinations stay strict (a trashed project is not a valid target);
|
|
@@ -173,10 +214,37 @@ export declare function resolveTagUuid(db: DatabaseSync, ref: string): string;
|
|
|
173
214
|
export declare function resolveProjectUuid(db: DatabaseSync, ref: string, options?: {
|
|
174
215
|
trashed?: boolean;
|
|
175
216
|
prefixTier?: boolean;
|
|
217
|
+
scopeWhere?: string;
|
|
218
|
+
scopeBinds?: (string | number)[];
|
|
176
219
|
}): string;
|
|
177
220
|
export declare function resolveAreaUuid(db: DatabaseSync, ref: string, options?: {
|
|
178
221
|
prefixTier?: boolean;
|
|
222
|
+
scopeWhere?: string;
|
|
223
|
+
scopeBinds?: (string | number)[];
|
|
179
224
|
}): string;
|
|
225
|
+
/**
|
|
226
|
+
* Resolve a HEADING SELECTOR (spec §2) inside one project through the SAME
|
|
227
|
+
* tiered core every other ref uses: exact title, or uuid (partial-uuid too).
|
|
228
|
+
* There is deliberately NO index/ordinal form — the "reindex hazard" makes an
|
|
229
|
+
* ordinal silently re-target a different heading after any reorder. An
|
|
230
|
+
* empty-string selector is a legal literal query (the app creates titleless
|
|
231
|
+
* headings); duplicates (or several titleless headings) are a resolution
|
|
232
|
+
* PRECONDITION, not an invariant, so ambiguity fails closed with uuid-bearing
|
|
233
|
+
* candidates (the H-DUPLICATE-TAG precedent). Shared by `todo add/move
|
|
234
|
+
* --heading` (via {@link resolveHeadingRef} → the H-AMBIGUOUS-HEADING guard)
|
|
235
|
+
* and by every project heading verb (via the thrower below).
|
|
236
|
+
*/
|
|
237
|
+
export declare function resolveHeadingRef(db: DatabaseSync, projectUuid: string, refRaw: string): NamedResolution;
|
|
238
|
+
/**
|
|
239
|
+
* Resolve a heading selector to its uuid+title within a project, throwing a
|
|
240
|
+
* {@link ReferenceResolutionError} (with uuid candidates on ambiguity) the
|
|
241
|
+
* consumer surfaces render as a usage error. The project-scoped heading verbs
|
|
242
|
+
* and the MCP heading tool resolve through this.
|
|
243
|
+
*/
|
|
244
|
+
export declare function resolveHeadingUuid(db: DatabaseSync, projectUuid: string, refRaw: string): {
|
|
245
|
+
uuid: string;
|
|
246
|
+
title: string;
|
|
247
|
+
};
|
|
180
248
|
/**
|
|
181
249
|
* A row's EFFECTIVE area: its own `area` link, else the area of its project,
|
|
182
250
|
* else the area of its heading's project. To-dos nested in a project (or under a
|
|
@@ -193,6 +261,25 @@ export declare function resolveAreaUuid(db: DatabaseSync, ref: string, options?:
|
|
|
193
261
|
export declare const EFFECTIVE_AREA = "COALESCE(\n t.area,\n (SELECT p.area FROM TMTask p WHERE p.uuid = t.project),\n (SELECT hp.area FROM TMTask h JOIN TMTask hp ON hp.uuid = h.project WHERE h.uuid = t.heading)\n)";
|
|
194
262
|
export declare function fetchTaskRows(db: DatabaseSync, where: string, params?: unknown[]): TaskRow[];
|
|
195
263
|
export declare function fetchTaskByUuid(db: DatabaseSync, uuid: string): TaskRow | null;
|
|
264
|
+
/**
|
|
265
|
+
* The uuid of a repeating template's LATEST spawned instance, or null when the
|
|
266
|
+
* template has none. The GUI-verified "Show Latest" law (SL1,
|
|
267
|
+
* docs/lab/sl1-show-latest.md, 2026-07-29): the pick is `max(creationDate)`
|
|
268
|
+
* among the template's instances — the most recently spawned occurrence — and
|
|
269
|
+
* NOTHING else. It is INDEPENDENT of `startDate`, `userModificationDate`,
|
|
270
|
+
* `stopDate`, and completion `status`: a completed newest-spawned instance is
|
|
271
|
+
* still the latest (the SL1 D1 case). No status filter; spans both to-do and
|
|
272
|
+
* project instances (`rt1_repeatingTemplate` points at the template regardless
|
|
273
|
+
* of type). `creationDate` is the occurrence midnight and unique per occurrence
|
|
274
|
+
* for a normal series, so ties are not expected.
|
|
275
|
+
*
|
|
276
|
+
* TRASHED instances are EXCLUDED (SL2, docs/lab/sl2-trash-dynamics.md, law L1):
|
|
277
|
+
* the GUI Show Latest never selects a trashed instance — it skips to the newest
|
|
278
|
+
* UNTRASHED one, and re-resolves live after an empty-trash. Only `trashed` is
|
|
279
|
+
* filtered; `status` is NOT (a COMPLETED newest-spawned instance is still the
|
|
280
|
+
* latest — SL1 D1). A template with no untrashed instances derives `null`.
|
|
281
|
+
*/
|
|
282
|
+
export declare function latestInstanceUuid(db: DatabaseSync, templateUuid: string): string | null;
|
|
196
283
|
export declare function fetchChecklistRows(db: DatabaseSync, taskUuid: string): ChecklistRow[];
|
|
197
284
|
/**
|
|
198
285
|
* Direct tags for a set of tasks, in one query. Returns uuid -> Ref[] in the
|