things-api 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +77 -0
- package/bin/things.js +9 -0
- package/dist/audit/log.d.ts +10 -0
- package/dist/audit/log.js +31 -0
- package/dist/audit/log.js.map +1 -0
- package/dist/audit/schema.d.ts +37 -0
- package/dist/audit/schema.js +9 -0
- package/dist/audit/schema.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +9 -0
- package/dist/cli/commands/doctor.js +60 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +7 -0
- package/dist/cli/commands/mcp.js +26 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/project.d.ts +5 -0
- package/dist/cli/commands/project.js +50 -0
- package/dist/cli/commands/project.js.map +1 -0
- package/dist/cli/commands/reads.d.ts +21 -0
- package/dist/cli/commands/reads.js +295 -0
- package/dist/cli/commands/reads.js.map +1 -0
- package/dist/cli/commands/snapshot.d.ts +7 -0
- package/dist/cli/commands/snapshot.js +22 -0
- package/dist/cli/commands/snapshot.js.map +1 -0
- package/dist/cli/commands/todo.d.ts +6 -0
- package/dist/cli/commands/todo.js +43 -0
- package/dist/cli/commands/todo.js.map +1 -0
- package/dist/cli/commands/writes.d.ts +9 -0
- package/dist/cli/commands/writes.js +994 -0
- package/dist/cli/commands/writes.js.map +1 -0
- package/dist/cli/exit-codes.d.ts +26 -0
- package/dist/cli/exit-codes.js +26 -0
- package/dist/cli/exit-codes.js.map +1 -0
- package/dist/cli/main.d.ts +4 -0
- package/dist/cli/main.js +73 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.d.ts +42 -0
- package/dist/cli/output.js +16 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/style.d.ts +6 -0
- package/dist/cli/style.js +25 -0
- package/dist/cli/style.js.map +1 -0
- package/dist/client.d.ts +184 -0
- package/dist/client.js +187 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.js +76 -0
- package/dist/config.js.map +1 -0
- package/dist/contracts.d.ts +79 -0
- package/dist/contracts.js +46 -0
- package/dist/contracts.js.map +1 -0
- package/dist/db/baselines/db-v26.d.ts +8 -0
- package/dist/db/baselines/db-v26.js +16 -0
- package/dist/db/baselines/db-v26.js.map +1 -0
- package/dist/db/baselines/index.d.ts +3 -0
- package/dist/db/baselines/index.js +4 -0
- package/dist/db/baselines/index.js.map +1 -0
- package/dist/db/connection.d.ts +22 -0
- package/dist/db/connection.js +40 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/fingerprint.d.ts +42 -0
- package/dist/db/fingerprint.js +82 -0
- package/dist/db/fingerprint.js.map +1 -0
- package/dist/db/locate.d.ts +13 -0
- package/dist/db/locate.js +44 -0
- package/dist/db/locate.js.map +1 -0
- package/dist/db/schema.d.ts +37 -0
- package/dist/db/schema.js +81 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/diagnose.d.ts +67 -0
- package/dist/diagnose.js +143 -0
- package/dist/diagnose.js.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +8 -0
- package/dist/mcp/server.js +1002 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/model/dates.d.ts +38 -0
- package/dist/model/dates.js +104 -0
- package/dist/model/dates.js.map +1 -0
- package/dist/model/entities.d.ts +117 -0
- package/dist/model/entities.js +21 -0
- package/dist/model/entities.js.map +1 -0
- package/dist/model/mappers.d.ts +55 -0
- package/dist/model/mappers.js +105 -0
- package/dist/model/mappers.js.map +1 -0
- package/dist/model/occurrences.d.ts +46 -0
- package/dist/model/occurrences.js +164 -0
- package/dist/model/occurrences.js.map +1 -0
- package/dist/model/recurrence.d.ts +52 -0
- package/dist/model/recurrence.js +164 -0
- package/dist/model/recurrence.js.map +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.js +30 -0
- package/dist/paths.js.map +1 -0
- package/dist/read/detail.d.ts +8 -0
- package/dist/read/detail.js +34 -0
- package/dist/read/detail.js.map +1 -0
- package/dist/read/project-view.d.ts +34 -0
- package/dist/read/project-view.js +87 -0
- package/dist/read/project-view.js.map +1 -0
- package/dist/read/queries.d.ts +39 -0
- package/dist/read/queries.js +134 -0
- package/dist/read/queries.js.map +1 -0
- package/dist/read/snapshot.d.ts +25 -0
- package/dist/read/snapshot.js +39 -0
- package/dist/read/snapshot.js.map +1 -0
- package/dist/read/tags.d.ts +17 -0
- package/dist/read/tags.js +64 -0
- package/dist/read/tags.js.map +1 -0
- package/dist/read/views.d.ts +152 -0
- package/dist/read/views.js +322 -0
- package/dist/read/views.js.map +1 -0
- package/dist/surface-copy.d.ts +15 -0
- package/dist/surface-copy.js +16 -0
- package/dist/surface-copy.js.map +1 -0
- package/dist/write/automation-probe.d.ts +12 -0
- package/dist/write/automation-probe.js +59 -0
- package/dist/write/automation-probe.js.map +1 -0
- package/dist/write/batch.d.ts +51 -0
- package/dist/write/batch.js +97 -0
- package/dist/write/batch.js.map +1 -0
- package/dist/write/capabilities.d.ts +16 -0
- package/dist/write/capabilities.js +16 -0
- package/dist/write/capabilities.js.map +1 -0
- package/dist/write/commands.d.ts +32 -0
- package/dist/write/commands.js +1274 -0
- package/dist/write/commands.js.map +1 -0
- package/dist/write/environment.d.ts +29 -0
- package/dist/write/environment.js +105 -0
- package/dist/write/environment.js.map +1 -0
- package/dist/write/experimental.d.ts +7 -0
- package/dist/write/experimental.js +39 -0
- package/dist/write/experimental.js.map +1 -0
- package/dist/write/failure-hints.d.ts +32 -0
- package/dist/write/failure-hints.js +71 -0
- package/dist/write/failure-hints.js.map +1 -0
- package/dist/write/guards.d.ts +21 -0
- package/dist/write/guards.js +312 -0
- package/dist/write/guards.js.map +1 -0
- package/dist/write/lock.d.ts +10 -0
- package/dist/write/lock.js +70 -0
- package/dist/write/lock.js.map +1 -0
- package/dist/write/operations.d.ts +262 -0
- package/dist/write/operations.js +34 -0
- package/dist/write/operations.js.map +1 -0
- package/dist/write/pipeline.d.ts +90 -0
- package/dist/write/pipeline.js +375 -0
- package/dist/write/pipeline.js.map +1 -0
- package/dist/write/planner.d.ts +40 -0
- package/dist/write/planner.js +57 -0
- package/dist/write/planner.js.map +1 -0
- package/dist/write/pre-state.d.ts +125 -0
- package/dist/write/pre-state.js +299 -0
- package/dist/write/pre-state.js.map +1 -0
- package/dist/write/reopen.d.ts +29 -0
- package/dist/write/reopen.js +63 -0
- package/dist/write/reopen.js.map +1 -0
- package/dist/write/reorder.d.ts +19 -0
- package/dist/write/reorder.js +285 -0
- package/dist/write/reorder.js.map +1 -0
- package/dist/write/undo.d.ts +53 -0
- package/dist/write/undo.js +703 -0
- package/dist/write/undo.js.map +1 -0
- package/dist/write/vectors/applescript.d.ts +5 -0
- package/dist/write/vectors/applescript.js +216 -0
- package/dist/write/vectors/applescript.js.map +1 -0
- package/dist/write/vectors/registry.d.ts +2 -0
- package/dist/write/vectors/registry.js +11 -0
- package/dist/write/vectors/registry.js.map +1 -0
- package/dist/write/vectors/types.d.ts +48 -0
- package/dist/write/vectors/types.js +2 -0
- package/dist/write/vectors/types.js.map +1 -0
- package/dist/write/vectors/url-scheme.d.ts +3 -0
- package/dist/write/vectors/url-scheme.js +176 -0
- package/dist/write/vectors/url-scheme.js.map +1 -0
- package/dist/write/verify/delta.d.ts +126 -0
- package/dist/write/verify/delta.js +281 -0
- package/dist/write/verify/delta.js.map +1 -0
- package/dist/write/verify/poller.d.ts +24 -0
- package/dist/write/verify/poller.js +28 -0
- package/dist/write/verify/poller.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { addDaysIso, encodePackedDate, localToday } from "../model/dates.js";
|
|
2
|
+
import { mapProject, mapTodo } from "../model/mappers.js";
|
|
3
|
+
import { projectOccurrences } from "../model/occurrences.js";
|
|
4
|
+
import { decodeRecurrenceRule } from "../model/recurrence.js";
|
|
5
|
+
import { fetchTagsForTasks, fetchTaskRows, makeRefResolver, NOT_TEMPLATE, resolveAreaUuid, resolveProjectUuid, resolveTagUuid, tagScopeBinds, tagScopeSql, tagWithDescendants, } from "./queries.js";
|
|
6
|
+
function tagFilter(db, filter) {
|
|
7
|
+
if (filter?.tag === undefined)
|
|
8
|
+
return { sql: "", binds: [] };
|
|
9
|
+
const target = resolveTagUuid(db, filter.tag);
|
|
10
|
+
const uuids = filter.exactTag === true ? [target] : tagWithDescendants(db, target);
|
|
11
|
+
return { sql: ` AND ${tagScopeSql(uuids.length)}`, binds: tagScopeBinds(uuids) };
|
|
12
|
+
}
|
|
13
|
+
const LIVE = `t.type IN (0, 1) AND t.trashed = 0 AND ${NOT_TEMPLATE}`;
|
|
14
|
+
const OPEN = `${LIVE} AND t.status = 0`;
|
|
15
|
+
function materialize(db, rows) {
|
|
16
|
+
const refs = makeRefResolver(db);
|
|
17
|
+
const tags = fetchTagsForTasks(db, rows.map((r) => r.uuid));
|
|
18
|
+
return rows.map((row) => row.type === 1
|
|
19
|
+
? mapProject(row, refs, tags.get(row.uuid) ?? [])
|
|
20
|
+
: mapTodo(row, refs, tags.get(row.uuid) ?? []));
|
|
21
|
+
}
|
|
22
|
+
export function todayView(db, now, filter) {
|
|
23
|
+
const todayIso = localToday(now);
|
|
24
|
+
const packedToday = encodePackedDate(todayIso);
|
|
25
|
+
const tf = tagFilter(db, filter);
|
|
26
|
+
// Membership + comparator per the UI-oracle research (lab, 2026-07-04;
|
|
27
|
+
// docs/lab/today-order-research.md, two reproducing runs + exact live
|
|
28
|
+
// reconciliation: 405 − 12 suppressed = 393 = the UI's own count):
|
|
29
|
+
// - a DUE DEADLINE pulls an item into Today even from the Inbox, unless a
|
|
30
|
+
// FUTURE startDate suppresses it (F-DL-TODAY / F-DL-FUTURE-START) or
|
|
31
|
+
// the user dismissed the nag (deadlineSuppressionDate stores the
|
|
32
|
+
// dismissed deadline; all 12 live absentees carried it);
|
|
33
|
+
// - order = newest-entry cohorts first: todayIndexReferenceDate DESC
|
|
34
|
+
// (the date the item ENTERED Today: its startDate, or its deadline for
|
|
35
|
+
// deadline-driven members), then todayIndex ASC, then uuid (observed
|
|
36
|
+
// stable tiebreak).
|
|
37
|
+
const rows = fetchTaskRows(db, `${OPEN} AND (
|
|
38
|
+
(t.startDate IS NOT NULL AND t.startDate <= ? AND t.start IN (1, 2))
|
|
39
|
+
OR (t.deadline IS NOT NULL AND t.deadline <= ? AND t.startDate IS NULL
|
|
40
|
+
AND (t.deadlineSuppressionDate IS NULL OR t.deadlineSuppressionDate < t.deadline))
|
|
41
|
+
)${tf.sql}
|
|
42
|
+
ORDER BY t.startBucket ASC,
|
|
43
|
+
COALESCE(t.todayIndexReferenceDate, t.startDate, t.deadline) DESC,
|
|
44
|
+
t.todayIndex ASC, t.uuid ASC`, [packedToday, packedToday, ...tf.binds]);
|
|
45
|
+
const items = materialize(db, rows);
|
|
46
|
+
// Evening membership expires daily: raw startBucket=1 counts only while
|
|
47
|
+
// startDate is exactly today; stale evening items belong to Today proper.
|
|
48
|
+
const isEvening = (i) => i.todaySection === "evening" && i.startDate === todayIso;
|
|
49
|
+
const dueOrOverdue = items.filter((i) => i.deadline !== null && i.deadline <= todayIso).length;
|
|
50
|
+
return {
|
|
51
|
+
today: items.filter((i) => !isEvening(i)),
|
|
52
|
+
evening: items.filter(isEvening),
|
|
53
|
+
badge: { dueOrOverdue, other: items.length - dueOrOverdue },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function inboxView(db, filter) {
|
|
57
|
+
const tf = tagFilter(db, filter);
|
|
58
|
+
const rows = fetchTaskRows(db, `${OPEN} AND t.start = 0${tf.sql} ORDER BY t."index" ASC`, tf.binds);
|
|
59
|
+
return materialize(db, rows);
|
|
60
|
+
}
|
|
61
|
+
/** An item's own anytime membership: unscheduled-active, or dated <= today. */
|
|
62
|
+
const ANYTIME_SELF = (col) => `((${col}.start = 1 AND (${col}.startDate IS NULL OR ${col}.startDate <= ?))
|
|
63
|
+
OR (${col}.start = 2 AND ${col}.startDate IS NOT NULL AND ${col}.startDate <= ?))`;
|
|
64
|
+
/**
|
|
65
|
+
* The item's effective project: its own link, or its heading's project for
|
|
66
|
+
* headed children (heading rows carry the project link).
|
|
67
|
+
*/
|
|
68
|
+
const EFF_PROJECT = `COALESCE(t.project, (SELECT h.project FROM TMTask h WHERE h.uuid = t.heading))`;
|
|
69
|
+
/**
|
|
70
|
+
* Container cascade (live-verified against the UI, 2026-07-09): a to-do
|
|
71
|
+
* inside a project that is NOT itself anytime-visible (someday or
|
|
72
|
+
* future-scheduled, logged, or trashed) is absent from Anytime regardless of
|
|
73
|
+
* the to-do's own start state — the project row alone represents it.
|
|
74
|
+
* Projects and container-less to-dos pass through. Two binds (packedToday ×2).
|
|
75
|
+
*/
|
|
76
|
+
const PROJECT_ANYTIME_ACTIVE = `(${EFF_PROJECT} IS NULL OR EXISTS (
|
|
77
|
+
SELECT 1 FROM TMTask p WHERE p.uuid = ${EFF_PROJECT}
|
|
78
|
+
AND p.trashed = 0 AND p.status = 0 AND ${ANYTIME_SELF("p")}))`;
|
|
79
|
+
export function anytimeView(db, now, filter) {
|
|
80
|
+
const packedToday = encodePackedDate(localToday(now));
|
|
81
|
+
const tf = tagFilter(db, filter);
|
|
82
|
+
// Mirrors UI membership: every active item, including Today members
|
|
83
|
+
// (starred in the UI) and pending-promotion rows (start=2, past-dated) —
|
|
84
|
+
// MINUS children of non-active containers (the project cascade).
|
|
85
|
+
const rows = fetchTaskRows(db, `${OPEN} AND ${ANYTIME_SELF("t")}
|
|
86
|
+
AND ${PROJECT_ANYTIME_ACTIVE}${tf.sql} ORDER BY t."index" ASC`, [packedToday, packedToday, packedToday, packedToday, ...tf.binds]);
|
|
87
|
+
return groupBySidebar(db, materialize(db, rows));
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Arranges view members into the UI's flat sidebar-mirroring order: the
|
|
91
|
+
* area-less block first (direct to-dos, then each top-level project followed
|
|
92
|
+
* by its members), then each area by its sidebar index (direct to-dos, then
|
|
93
|
+
* its projects). Project and area order here mirrors the sidebar exactly —
|
|
94
|
+
* both read the same "index" columns.
|
|
95
|
+
*/
|
|
96
|
+
function groupBySidebar(db, items) {
|
|
97
|
+
if (items.length === 0)
|
|
98
|
+
return [];
|
|
99
|
+
const inList = (n) => Array.from({ length: n }, () => "?").join(", ");
|
|
100
|
+
// Headed children: resolve heading -> project.
|
|
101
|
+
const headingUuids = [
|
|
102
|
+
...new Set(items.flatMap((i) => (i.type === "to-do" && i.heading !== null ? [i.heading.uuid] : []))),
|
|
103
|
+
];
|
|
104
|
+
const headingProject = new Map();
|
|
105
|
+
if (headingUuids.length > 0) {
|
|
106
|
+
for (const row of db
|
|
107
|
+
.prepare(`SELECT uuid, project FROM TMTask WHERE uuid IN (${inList(headingUuids.length)})`)
|
|
108
|
+
.all(...headingUuids)) {
|
|
109
|
+
headingProject.set(row.uuid, row.project);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const effProject = (i) => i.type !== "to-do"
|
|
113
|
+
? null
|
|
114
|
+
: (i.project?.uuid ??
|
|
115
|
+
(i.heading !== null ? (headingProject.get(i.heading.uuid) ?? null) : null));
|
|
116
|
+
// Sidebar rank + title for areas; index + area for every referenced project
|
|
117
|
+
// (a tag-filtered list can contain a child whose project row didn't match).
|
|
118
|
+
const areaRows = db
|
|
119
|
+
.prepare(`SELECT uuid, title, "index" FROM TMArea ORDER BY "index" ASC, uuid ASC`)
|
|
120
|
+
.all();
|
|
121
|
+
const areaRank = new Map(areaRows.map((a, rank) => [a.uuid, rank]));
|
|
122
|
+
const areaTitle = new Map(areaRows.map((a) => [a.uuid, a.title ?? ""]));
|
|
123
|
+
const projectUuids = [
|
|
124
|
+
...new Set([
|
|
125
|
+
...items.flatMap((i) => (i.type === "project" ? [i.uuid] : [])),
|
|
126
|
+
...items.flatMap((i) => {
|
|
127
|
+
const p = effProject(i);
|
|
128
|
+
return p === null ? [] : [p];
|
|
129
|
+
}),
|
|
130
|
+
]),
|
|
131
|
+
];
|
|
132
|
+
const projectMeta = new Map();
|
|
133
|
+
if (projectUuids.length > 0) {
|
|
134
|
+
for (const row of db
|
|
135
|
+
.prepare(`SELECT uuid, "index", area FROM TMTask WHERE uuid IN (${inList(projectUuids.length)})`)
|
|
136
|
+
.all(...projectUuids)) {
|
|
137
|
+
projectMeta.set(row.uuid, { index: row.index ?? 0, area: row.area });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const sortKey = (i) => {
|
|
141
|
+
const project = i.type === "project" ? i.uuid : effProject(i);
|
|
142
|
+
const meta = project === null ? undefined : projectMeta.get(project);
|
|
143
|
+
const area = i.area?.uuid ?? meta?.area ?? null;
|
|
144
|
+
return {
|
|
145
|
+
areaRank: area === null ? -1 : (areaRank.get(area) ?? areaRows.length),
|
|
146
|
+
area: area ?? "",
|
|
147
|
+
inProject: project === null ? 0 : 1,
|
|
148
|
+
projectIndex: meta?.index ?? 0,
|
|
149
|
+
project: project ?? "",
|
|
150
|
+
headerFirst: i.type === "project" ? 0 : 1,
|
|
151
|
+
index: i.index,
|
|
152
|
+
uuid: i.uuid,
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
const keyed = items.map((item) => ({ item, k: sortKey(item) }));
|
|
156
|
+
keyed.sort((a, b) => a.k.areaRank - b.k.areaRank ||
|
|
157
|
+
a.k.area.localeCompare(b.k.area) ||
|
|
158
|
+
a.k.inProject - b.k.inProject ||
|
|
159
|
+
a.k.projectIndex - b.k.projectIndex ||
|
|
160
|
+
a.k.project.localeCompare(b.k.project) ||
|
|
161
|
+
a.k.headerFirst - b.k.headerFirst ||
|
|
162
|
+
a.k.index - b.k.index ||
|
|
163
|
+
a.k.uuid.localeCompare(b.k.uuid));
|
|
164
|
+
const sections = [];
|
|
165
|
+
for (const { item, k } of keyed) {
|
|
166
|
+
const areaUuid = k.area === "" ? null : k.area;
|
|
167
|
+
const last = sections.at(-1);
|
|
168
|
+
if (last === undefined || (last.area?.uuid ?? null) !== areaUuid) {
|
|
169
|
+
sections.push({
|
|
170
|
+
area: areaUuid === null ? null : { uuid: areaUuid, title: areaTitle.get(areaUuid) ?? "" },
|
|
171
|
+
items: [],
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
sections.at(-1)?.items.push(item);
|
|
175
|
+
}
|
|
176
|
+
return sections;
|
|
177
|
+
}
|
|
178
|
+
/** The UI's star marker in Anytime: the item is also a Today member. */
|
|
179
|
+
export function isTodayMember(item, now) {
|
|
180
|
+
return item.startDate !== null && item.startDate <= localToday(now);
|
|
181
|
+
}
|
|
182
|
+
export function upcomingView(db, now, filter) {
|
|
183
|
+
const packedToday = encodePackedDate(localToday(now));
|
|
184
|
+
const tf = tagFilter(db, filter);
|
|
185
|
+
const rows = fetchTaskRows(db, `${OPEN} AND t.start = 2 AND t.startDate IS NOT NULL AND t.startDate > ?${tf.sql}
|
|
186
|
+
ORDER BY t.startDate ASC, t."index" ASC`, [packedToday, ...tf.binds]);
|
|
187
|
+
const items = materialize(db, rows);
|
|
188
|
+
if (filter?.repeats === false)
|
|
189
|
+
return items;
|
|
190
|
+
// UI parity: repeating templates surface at their app-materialized next
|
|
191
|
+
// occurrence (rt1_nextInstanceStartDate). Fixed rules only — after-
|
|
192
|
+
// completion templates carry no next date until the prior instance
|
|
193
|
+
// resolves; paused templates are excluded. The occurrence deadline follows
|
|
194
|
+
// the instance-validated model: deadline = startDate − rule.startOffsetDays.
|
|
195
|
+
const templateRows = fetchTaskRows(db, `t.type IN (0, 1) AND t.trashed = 0 AND t.status = 0
|
|
196
|
+
AND (t.rt1_recurrenceRule IS NOT NULL OR t.repeater IS NOT NULL)
|
|
197
|
+
AND t.rt1_instanceCreationPaused = 0
|
|
198
|
+
AND t.rt1_nextInstanceStartDate IS NOT NULL AND t.rt1_nextInstanceStartDate > ?${tf.sql}
|
|
199
|
+
ORDER BY t.rt1_nextInstanceStartDate ASC, t."index" ASC`, [packedToday, ...tf.binds]);
|
|
200
|
+
const horizon = Math.max(1, Math.min(10, Math.trunc(filter?.horizon ?? 1)));
|
|
201
|
+
const rawByUuid = new Map(templateRows.map((r) => [r.uuid, r.rt1_recurrenceRule]));
|
|
202
|
+
const occurrences = materialize(db, templateRows).flatMap((template) => {
|
|
203
|
+
const startDate = template.repeating.nextOccurrence ?? null;
|
|
204
|
+
if (startDate === null)
|
|
205
|
+
return [];
|
|
206
|
+
// Only the rule-derived deadline is real: the template row's own deadline
|
|
207
|
+
// column carries app-internal sentinels (4001-01-01 observed live).
|
|
208
|
+
let rule = null;
|
|
209
|
+
const raw = rawByUuid.get(template.uuid);
|
|
210
|
+
if (raw !== null && raw !== undefined) {
|
|
211
|
+
try {
|
|
212
|
+
rule = decodeRecurrenceRule(raw);
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// undecodable rule (future Things build) → occurrence without a derived deadline
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (rule === null || horizon === 1 || rule.type !== "fixed") {
|
|
219
|
+
const deadline = rule !== null && rule.startOffsetDays < 0
|
|
220
|
+
? addDaysIso(startDate, -rule.startOffsetDays)
|
|
221
|
+
: null;
|
|
222
|
+
return [{ ...template, startDate, deadline }];
|
|
223
|
+
}
|
|
224
|
+
// horizon > 1: later occurrences PROJECTED from the decoded rule,
|
|
225
|
+
// anchored on the app's own materialized next instance.
|
|
226
|
+
return projectOccurrences(rule, startDate, { count: horizon }).map((o) => ({
|
|
227
|
+
...template,
|
|
228
|
+
startDate: o.startDate,
|
|
229
|
+
deadline: o.deadline,
|
|
230
|
+
}));
|
|
231
|
+
});
|
|
232
|
+
return [...items, ...occurrences].toSorted((a, b) => (a.startDate ?? "").localeCompare(b.startDate ?? "") ||
|
|
233
|
+
a.index - b.index ||
|
|
234
|
+
a.uuid.localeCompare(b.uuid));
|
|
235
|
+
}
|
|
236
|
+
export function somedayView(db, now, filter) {
|
|
237
|
+
const tf = tagFilter(db, filter);
|
|
238
|
+
const packedToday = encodePackedDate(localToday(now));
|
|
239
|
+
// Default membership excludes ALL project children (the UI shows only
|
|
240
|
+
// container-less someday to-dos, area members, and someday project rows);
|
|
241
|
+
// the toggle adds someday children of anytime-ACTIVE projects only.
|
|
242
|
+
const withActiveChildren = filter?.activeProjectItems === true;
|
|
243
|
+
const childArm = withActiveChildren
|
|
244
|
+
? `EXISTS (SELECT 1 FROM TMTask p WHERE p.uuid = ${EFF_PROJECT}
|
|
245
|
+
AND p.trashed = 0 AND p.status = 0 AND ${ANYTIME_SELF("p")})`
|
|
246
|
+
: "0";
|
|
247
|
+
const rows = fetchTaskRows(db, `${OPEN} AND t.start = 2 AND t.startDate IS NULL
|
|
248
|
+
AND (${EFF_PROJECT} IS NULL OR ${childArm})${tf.sql} ORDER BY t."index" ASC`, [...(withActiveChildren ? [packedToday, packedToday] : []), ...tf.binds]);
|
|
249
|
+
return groupBySidebar(db, materialize(db, rows));
|
|
250
|
+
}
|
|
251
|
+
export function logbookView(db, options) {
|
|
252
|
+
const limit = options?.limit ?? 100;
|
|
253
|
+
const tf = tagFilter(db, options);
|
|
254
|
+
const rows = fetchTaskRows(db, `${LIVE} AND t.status IN (2, 3)${tf.sql} ORDER BY t.stopDate DESC LIMIT ?`, [...tf.binds, limit]);
|
|
255
|
+
return materialize(db, rows);
|
|
256
|
+
}
|
|
257
|
+
export function trashView(db, options) {
|
|
258
|
+
const limit = options?.limit ?? 200;
|
|
259
|
+
const rows = fetchTaskRows(db, `t.type IN (0, 1) AND t.trashed = 1 AND ${NOT_TEMPLATE}
|
|
260
|
+
ORDER BY t.userModificationDate DESC LIMIT ?`, [limit]);
|
|
261
|
+
return materialize(db, rows);
|
|
262
|
+
}
|
|
263
|
+
export function projectsView(db, options) {
|
|
264
|
+
const where = options?.areaUuid
|
|
265
|
+
? `${OPEN} AND t.type = 1 AND t.area = ? ORDER BY t."index" ASC`
|
|
266
|
+
: `${OPEN} AND t.type = 1 ORDER BY t."index" ASC`;
|
|
267
|
+
const rows = fetchTaskRows(db, where, options?.areaUuid ? [options.areaUuid] : []);
|
|
268
|
+
return materialize(db, rows);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Everything that changed since a moment — created or modified TMTask rows,
|
|
272
|
+
* INCLUDING trashed, logged, and repeating-template rows (an agent syncing
|
|
273
|
+
* state needs to see deletions and template edits too; check `trashed`,
|
|
274
|
+
* `status`, and `repeating.isTemplate` on each item). Caveats: TMArea/TMTag
|
|
275
|
+
* carry no modification dates, and checklist-item edits do not bump the
|
|
276
|
+
* parent task — those changes are invisible here.
|
|
277
|
+
*/
|
|
278
|
+
export function changesView(db, options) {
|
|
279
|
+
const limit = options.limit ?? 200;
|
|
280
|
+
const sinceEpoch = options.since.getTime() / 1000;
|
|
281
|
+
const rows = fetchTaskRows(db, `t.type IN (0, 1) AND t.userModificationDate > ?
|
|
282
|
+
ORDER BY t.userModificationDate DESC LIMIT ?`, [sinceEpoch, limit]);
|
|
283
|
+
return materialize(db, rows).map((item, i) => ({
|
|
284
|
+
...item,
|
|
285
|
+
changeKind: (rows[i]?.creationDate ?? 0) > sinceEpoch ? "created" : "modified",
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
export function searchView(db, query, options) {
|
|
289
|
+
const limit = options?.limit ?? 50;
|
|
290
|
+
const needle = `%${query}%`;
|
|
291
|
+
const where = [`${NOT_TEMPLATE} AND (t.title LIKE ? OR t.notes LIKE ?)`];
|
|
292
|
+
const binds = [needle, needle];
|
|
293
|
+
where.push(options?.type === "to-do"
|
|
294
|
+
? "t.type = 0"
|
|
295
|
+
: options?.type === "project"
|
|
296
|
+
? "t.type = 1"
|
|
297
|
+
: "t.type IN (0, 1)");
|
|
298
|
+
// Scope: open + untrashed by default; --logged/--trashed widen; --all is
|
|
299
|
+
// the legacy include-everything behavior.
|
|
300
|
+
if (options?.all !== true) {
|
|
301
|
+
const statuses = options?.logged === true ? "(0, 2, 3)" : "(0)";
|
|
302
|
+
where.push(`t.status IN ${statuses}`);
|
|
303
|
+
if (options?.trashed !== true)
|
|
304
|
+
where.push("t.trashed = 0");
|
|
305
|
+
}
|
|
306
|
+
if (options?.project !== undefined) {
|
|
307
|
+
const uuid = resolveProjectUuid(db, options.project);
|
|
308
|
+
// Children incl. headed ones (heading rows carry the project link).
|
|
309
|
+
where.push("(t.project = ? OR t.heading IN (SELECT uuid FROM TMTask WHERE type = 2 AND project = ?))");
|
|
310
|
+
binds.push(uuid, uuid);
|
|
311
|
+
}
|
|
312
|
+
if (options?.area !== undefined) {
|
|
313
|
+
const uuid = resolveAreaUuid(db, options.area);
|
|
314
|
+
where.push("t.area = ?");
|
|
315
|
+
binds.push(uuid);
|
|
316
|
+
}
|
|
317
|
+
const tf = tagFilter(db, options);
|
|
318
|
+
const rows = fetchTaskRows(db, `${where.join(" AND ")}${tf.sql}
|
|
319
|
+
ORDER BY t.userModificationDate DESC LIMIT ?`, [...binds, ...tf.binds, limit]);
|
|
320
|
+
return materialize(db, rows);
|
|
321
|
+
}
|
|
322
|
+
//# sourceMappingURL=views.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"views.js","sourceRoot":"","sources":["../../src/read/views.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared parameter vocabulary — the exact wording every surface (CLI option
|
|
3
|
+
* help, MCP tool schemas) uses for recurring parameter formats, so a format
|
|
4
|
+
* learned on one surface transfers verbatim to the others. Only vocabulary
|
|
5
|
+
* is shared; tool/command PROSE is written per surface. Style rules:
|
|
6
|
+
* docs/design/surface-copy.md.
|
|
7
|
+
*/
|
|
8
|
+
/** Accepted `when` scheduling values. */
|
|
9
|
+
export declare const WHEN_VALUES = "today | evening | anytime | someday | YYYY-MM-DD";
|
|
10
|
+
/** Calendar-date parameter format (deadlines, dated `when`). */
|
|
11
|
+
export declare const DATE_FORMAT = "YYYY-MM-DD";
|
|
12
|
+
/** Reminder time-of-day parameter format. */
|
|
13
|
+
export declare const REMINDER_FORMAT = "HH:mm (24-hour)";
|
|
14
|
+
/** How projects, areas, and tags may be referenced. */
|
|
15
|
+
export declare const REF_FORMAT = "uuid or unique name";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared parameter vocabulary — the exact wording every surface (CLI option
|
|
3
|
+
* help, MCP tool schemas) uses for recurring parameter formats, so a format
|
|
4
|
+
* learned on one surface transfers verbatim to the others. Only vocabulary
|
|
5
|
+
* is shared; tool/command PROSE is written per surface. Style rules:
|
|
6
|
+
* docs/design/surface-copy.md.
|
|
7
|
+
*/
|
|
8
|
+
/** Accepted `when` scheduling values. */
|
|
9
|
+
export const WHEN_VALUES = "today | evening | anytime | someday | YYYY-MM-DD";
|
|
10
|
+
/** Calendar-date parameter format (deadlines, dated `when`). */
|
|
11
|
+
export const DATE_FORMAT = "YYYY-MM-DD";
|
|
12
|
+
/** Reminder time-of-day parameter format. */
|
|
13
|
+
export const REMINDER_FORMAT = "HH:mm (24-hour)";
|
|
14
|
+
/** How projects, areas, and tags may be referenced. */
|
|
15
|
+
export const REF_FORMAT = "uuid or unique name";
|
|
16
|
+
//# sourceMappingURL=surface-copy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"surface-copy.js","sourceRoot":"","sources":["../src/surface-copy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,yCAAyC;AACzC,MAAM,CAAC,MAAM,WAAW,GAAG,kDAAkD,CAAC;AAE9E,gEAAgE;AAChE,MAAM,CAAC,MAAM,WAAW,GAAG,YAAY,CAAC;AAExC,6CAA6C;AAC7C,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AAEjD,uDAAuD;AACvD,MAAM,CAAC,MAAM,UAAU,GAAG,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type AutomationProbeStatus = "granted" | "denied" | "pending" | "app-not-running" | "inconclusive";
|
|
2
|
+
export interface AutomationProbeResult {
|
|
3
|
+
status: AutomationProbeStatus;
|
|
4
|
+
detail: string;
|
|
5
|
+
}
|
|
6
|
+
export interface AutomationProbeDeps {
|
|
7
|
+
isAppRunning?: () => boolean;
|
|
8
|
+
/** Test seam: run the osascript probe; throws like execFileSync on failure. */
|
|
9
|
+
run?: (script: string, timeoutMs: number) => string;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function probeAutomation(deps?: AutomationProbeDeps): AutomationProbeResult;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Active Automation-consent probe: send the smallest possible AppleScript
|
|
3
|
+
* query to Things and classify the outcome. OPT-IN because the probe itself
|
|
4
|
+
* is a consent-requiring call — on an unauthorized machine it makes macOS
|
|
5
|
+
* show the Automation prompt (useful during onboarding, unwanted everywhere
|
|
6
|
+
* else). Skipped when Things is not running so a diagnostic never launches
|
|
7
|
+
* the app.
|
|
8
|
+
*/
|
|
9
|
+
import { execFileSync } from "node:child_process";
|
|
10
|
+
const PROBE_SCRIPT = 'tell application "Things3" to count of areas';
|
|
11
|
+
function defaultIsAppRunning() {
|
|
12
|
+
try {
|
|
13
|
+
execFileSync("pgrep", ["-x", "Things3"], { stdio: "ignore" });
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function defaultRun(script, timeoutMs) {
|
|
21
|
+
return execFileSync("osascript", ["-e", script], { encoding: "utf8", timeout: timeoutMs });
|
|
22
|
+
}
|
|
23
|
+
export function probeAutomation(deps = {}) {
|
|
24
|
+
if (!(deps.isAppRunning ?? defaultIsAppRunning)()) {
|
|
25
|
+
return {
|
|
26
|
+
status: "app-not-running",
|
|
27
|
+
detail: "Things is not running — the probe was skipped so a diagnostic never launches the " +
|
|
28
|
+
"app. Launch Things and re-run.",
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
(deps.run ?? defaultRun)(PROBE_SCRIPT, deps.timeoutMs ?? 8000);
|
|
33
|
+
return { status: "granted", detail: "automation of Things is authorized for this process." };
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const e = err;
|
|
37
|
+
const stderr = typeof e.stderr === "string" ? e.stderr : err instanceof Error ? err.message : String(err);
|
|
38
|
+
if (e.killed === true || e.signal === "SIGTERM") {
|
|
39
|
+
return {
|
|
40
|
+
status: "pending",
|
|
41
|
+
detail: "the probe timed out — the shape of an unanswered macOS consent dialog. Check the " +
|
|
42
|
+
"machine's screen for an Automation prompt and approve it.",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
if (/-1743|not authori[sz]ed to send apple events/i.test(stderr)) {
|
|
46
|
+
return {
|
|
47
|
+
status: "denied",
|
|
48
|
+
detail: "macOS declined the Apple Event (-1743): Automation permission for this process " +
|
|
49
|
+
"(or the app hosting it) is missing or was denied. Grant it under System Settings " +
|
|
50
|
+
"> Privacy & Security > Automation, or see docs/setup.md for headless setups.",
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
status: "inconclusive",
|
|
55
|
+
detail: `the probe failed for another reason: ${stderr.trim() || "unknown error"}`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=automation-probe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"automation-probe.js","sourceRoot":"","sources":["../../src/write/automation-probe.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAqBlD,MAAM,YAAY,GAAG,8CAA8C,CAAC;AAEpE,SAAS,mBAAmB;IAC1B,IAAI,CAAC;QACH,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,MAAc,EAAE,SAAiB;IACnD,OAAO,YAAY,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;AAC7F,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAA4B,EAAE;IAC5D,IAAI,CAAC,CAAC,IAAI,CAAC,YAAY,IAAI,mBAAmB,CAAC,EAAE,EAAE,CAAC;QAClD,OAAO;YACL,MAAM,EAAE,iBAAiB;YACzB,MAAM,EACJ,mFAAmF;gBACnF,gCAAgC;SACnC,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,CAAC,IAAI,CAAC,GAAG,IAAI,UAAU,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;QAC/D,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,sDAAsD,EAAE,CAAC;IAC/F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,GAAqE,CAAC;QAChF,MAAM,MAAM,GACV,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7F,IAAI,CAAC,CAAC,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAChD,OAAO;gBACL,MAAM,EAAE,SAAS;gBACjB,MAAM,EACJ,mFAAmF;oBACnF,2DAA2D;aAC9D,CAAC;QACJ,CAAC;QACD,IAAI,+CAA+C,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACjE,OAAO;gBACL,MAAM,EAAE,QAAQ;gBAChB,MAAM,EACJ,iFAAiF;oBACjF,mFAAmF;oBACnF,8EAA8E;aACjF,CAAC;QACJ,CAAC;QACD,OAAO;YACL,MAAM,EAAE,cAAc;YACtB,MAAM,EAAE,wCAAwC,MAAM,CAAC,IAAI,EAAE,IAAI,eAAe,EAAE;SACnF,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch mutations: N ops through the SAME pipeline as single mutations —
|
|
3
|
+
* every op individually pre-read, guarded, verified, and audited. The wins
|
|
4
|
+
* are amortization (one process, one DB handle, one config load) and a
|
|
5
|
+
* per-op result stream; there is deliberately NO transactional semantics
|
|
6
|
+
* (the app's surfaces have none to offer). Ops run SEQUENTIALLY: the
|
|
7
|
+
* mutation lock serializes them anyway, and create-probe verification must
|
|
8
|
+
* never race.
|
|
9
|
+
*/
|
|
10
|
+
import { type OperationKind } from "./operations.ts";
|
|
11
|
+
import { type WriteDeps, type WriteOptions } from "./pipeline.ts";
|
|
12
|
+
import { type ReorderResult } from "./reorder.ts";
|
|
13
|
+
/** One line of a batch: the op kind, its params, and per-op options. */
|
|
14
|
+
export interface BatchOp {
|
|
15
|
+
op: OperationKind;
|
|
16
|
+
params: Record<string, unknown>;
|
|
17
|
+
/** Per-op acknowledgements/overrides (a safe subset of WriteOptions). */
|
|
18
|
+
options?: {
|
|
19
|
+
acknowledgeChecklistReset?: boolean;
|
|
20
|
+
acknowledgeProjectReopen?: boolean;
|
|
21
|
+
dangerouslyPermanent?: boolean;
|
|
22
|
+
acknowledgeTagSubtree?: boolean;
|
|
23
|
+
vector?: WriteOptions["vector"];
|
|
24
|
+
verifyTimeoutMs?: number;
|
|
25
|
+
maxDisruption?: WriteOptions["maxDisruption"];
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export type BatchItemOutcome = ReorderResult | {
|
|
29
|
+
kind: "invalid";
|
|
30
|
+
op: string;
|
|
31
|
+
detail: string;
|
|
32
|
+
} | {
|
|
33
|
+
kind: "skipped";
|
|
34
|
+
op: string;
|
|
35
|
+
detail: string;
|
|
36
|
+
};
|
|
37
|
+
export interface BatchItemResult {
|
|
38
|
+
index: number;
|
|
39
|
+
op: string;
|
|
40
|
+
outcome: BatchItemOutcome;
|
|
41
|
+
}
|
|
42
|
+
export interface BatchOptions {
|
|
43
|
+
/** Stop at the first non-ok outcome; remaining ops report kind "skipped". */
|
|
44
|
+
failFast?: boolean;
|
|
45
|
+
/** Plan every op without executing (each result is its dry-run plan). */
|
|
46
|
+
dryRun?: boolean;
|
|
47
|
+
actor?: string;
|
|
48
|
+
}
|
|
49
|
+
/** True when an outcome should be treated as a failure for --fail-fast/exit. */
|
|
50
|
+
export declare function outcomeFailed(outcome: BatchItemOutcome): boolean;
|
|
51
|
+
export declare function runBatch(deps: WriteDeps, ops: BatchOp[], options?: BatchOptions, onResult?: (result: BatchItemResult) => void): Promise<BatchItemResult[]>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch mutations: N ops through the SAME pipeline as single mutations —
|
|
3
|
+
* every op individually pre-read, guarded, verified, and audited. The wins
|
|
4
|
+
* are amortization (one process, one DB handle, one config load) and a
|
|
5
|
+
* per-op result stream; there is deliberately NO transactional semantics
|
|
6
|
+
* (the app's surfaces have none to offer). Ops run SEQUENTIALLY: the
|
|
7
|
+
* mutation lock serializes them anyway, and create-probe verification must
|
|
8
|
+
* never race.
|
|
9
|
+
*/
|
|
10
|
+
import { OPERATION_KINDS } from "./operations.js";
|
|
11
|
+
import { runMutation } from "./pipeline.js";
|
|
12
|
+
import { runReorder } from "./reorder.js";
|
|
13
|
+
const KNOWN_OPS = new Set(OPERATION_KINDS);
|
|
14
|
+
/** True when an outcome should be treated as a failure for --fail-fast/exit. */
|
|
15
|
+
export function outcomeFailed(outcome) {
|
|
16
|
+
return outcome.kind !== "ok" && outcome.kind !== "dry-run";
|
|
17
|
+
}
|
|
18
|
+
export async function runBatch(deps, ops, options = {}, onResult) {
|
|
19
|
+
const results = [];
|
|
20
|
+
let halted = false;
|
|
21
|
+
for (let index = 0; index < ops.length; index++) {
|
|
22
|
+
const entry = ops[index];
|
|
23
|
+
let outcome;
|
|
24
|
+
if (halted) {
|
|
25
|
+
outcome = {
|
|
26
|
+
kind: "skipped",
|
|
27
|
+
op: String(entry?.op),
|
|
28
|
+
detail: "skipped after earlier failure (--fail-fast)",
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
else if (typeof entry !== "object" || entry === null || typeof entry.op !== "string") {
|
|
32
|
+
outcome = {
|
|
33
|
+
kind: "invalid",
|
|
34
|
+
op: String(entry?.op),
|
|
35
|
+
detail: "each op needs {op, params}",
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
else if (!KNOWN_OPS.has(entry.op)) {
|
|
39
|
+
outcome = {
|
|
40
|
+
kind: "invalid",
|
|
41
|
+
op: entry.op,
|
|
42
|
+
detail: `unknown op "${entry.op}" — see \`things capabilities\``,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
else if (typeof entry.params !== "object" || entry.params === null) {
|
|
46
|
+
outcome = { kind: "invalid", op: entry.op, detail: "params must be an object" };
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const writeOptions = {
|
|
50
|
+
...(entry.options?.acknowledgeChecklistReset !== undefined && {
|
|
51
|
+
acknowledgeChecklistReset: entry.options.acknowledgeChecklistReset,
|
|
52
|
+
}),
|
|
53
|
+
...(entry.options?.acknowledgeProjectReopen !== undefined && {
|
|
54
|
+
acknowledgeProjectReopen: entry.options.acknowledgeProjectReopen,
|
|
55
|
+
}),
|
|
56
|
+
...(entry.options?.dangerouslyPermanent !== undefined && {
|
|
57
|
+
dangerouslyPermanent: entry.options.dangerouslyPermanent,
|
|
58
|
+
}),
|
|
59
|
+
...(entry.options?.acknowledgeTagSubtree !== undefined && {
|
|
60
|
+
acknowledgeTagSubtree: entry.options.acknowledgeTagSubtree,
|
|
61
|
+
}),
|
|
62
|
+
...(entry.options?.vector !== undefined && { vector: entry.options.vector }),
|
|
63
|
+
...(entry.options?.verifyTimeoutMs !== undefined && {
|
|
64
|
+
verifyTimeoutMs: entry.options.verifyTimeoutMs,
|
|
65
|
+
}),
|
|
66
|
+
...(entry.options?.maxDisruption !== undefined && {
|
|
67
|
+
maxDisruption: entry.options.maxDisruption,
|
|
68
|
+
}),
|
|
69
|
+
...(options.dryRun === true && { dryRun: true }),
|
|
70
|
+
...(options.actor !== undefined && { actor: options.actor }),
|
|
71
|
+
};
|
|
72
|
+
try {
|
|
73
|
+
// Params arrive as parsed JSON; the pipeline's pre-read + guards are
|
|
74
|
+
// the runtime validators (loud on bad shapes), same as single ops.
|
|
75
|
+
outcome =
|
|
76
|
+
entry.op === "reorder"
|
|
77
|
+
? await runReorder(deps, entry.params, writeOptions)
|
|
78
|
+
: await runMutation(deps, entry.op, entry.params, writeOptions);
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
// Param-shape errors (exclusive combos etc.) surface per-op, not fatally.
|
|
82
|
+
outcome = {
|
|
83
|
+
kind: "invalid",
|
|
84
|
+
op: entry.op,
|
|
85
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const result = { index, op: String(entry?.op), outcome };
|
|
90
|
+
results.push(result);
|
|
91
|
+
onResult?.(result);
|
|
92
|
+
if (options.failFast === true && !halted && outcomeFailed(outcome))
|
|
93
|
+
halted = true;
|
|
94
|
+
}
|
|
95
|
+
return results;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=batch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/write/batch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The operation × vector support table — lab-validated matrices flattened
|
|
3
|
+
* for discovery. Shared by `things capabilities`, the MCP capabilities tool,
|
|
4
|
+
* and library consumers.
|
|
5
|
+
*/
|
|
6
|
+
import { type OperationKind } from "./operations.ts";
|
|
7
|
+
import type { VectorId, VectorSupport } from "./vectors/types.ts";
|
|
8
|
+
export interface CapabilityEntry {
|
|
9
|
+
op: OperationKind;
|
|
10
|
+
vectors: ({
|
|
11
|
+
vector: VectorId;
|
|
12
|
+
} & (VectorSupport | {
|
|
13
|
+
support: "no";
|
|
14
|
+
}))[];
|
|
15
|
+
}
|
|
16
|
+
export declare function capabilitiesTable(op?: OperationKind): CapabilityEntry[];
|