things-api 0.14.0 → 0.16.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 +4 -4
- package/dist/audit/schema.d.ts +8 -0
- package/dist/audit/schema.js.map +1 -1
- package/dist/cli/commands/area.js +1 -1
- package/dist/cli/commands/install-skill.js +9 -2
- package/dist/cli/commands/install-skill.js.map +1 -1
- package/dist/cli/commands/project.js +1 -1
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/reads.js +73 -4
- package/dist/cli/commands/reads.js.map +1 -1
- package/dist/cli/commands/repeat-flags.d.ts +11 -1
- package/dist/cli/commands/repeat-flags.js +23 -0
- package/dist/cli/commands/repeat-flags.js.map +1 -1
- package/dist/cli/commands/todo.js +50 -3
- package/dist/cli/commands/todo.js.map +1 -1
- package/dist/cli/commands/writes.js +202 -61
- package/dist/cli/commands/writes.js.map +1 -1
- package/dist/cli/glyphs.js +9 -10
- package/dist/cli/glyphs.js.map +1 -1
- package/dist/cli/help.js +18 -13
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/read-driver.d.ts +9 -3
- package/dist/cli/read-driver.js +3 -1
- package/dist/cli/read-driver.js.map +1 -1
- package/dist/cli/render.d.ts +33 -2
- package/dist/cli/render.js +60 -9
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/skill.d.ts +24 -0
- package/dist/cli/skill.js +40 -0
- package/dist/cli/skill.js.map +1 -1
- package/dist/client.d.ts +88 -15
- package/dist/client.js +31 -5
- package/dist/client.js.map +1 -1
- package/dist/contracts.d.ts +13 -2
- package/dist/contracts.js +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +187 -36
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/entities.d.ts +97 -40
- package/dist/model/entities.js +0 -4
- package/dist/model/entities.js.map +1 -1
- package/dist/model/mappers.js +24 -43
- package/dist/model/mappers.js.map +1 -1
- package/dist/read/area-view.js +6 -6
- package/dist/read/area-view.js.map +1 -1
- package/dist/read/detail.js +51 -3
- package/dist/read/detail.js.map +1 -1
- package/dist/read/filter-contract.d.ts +1 -1
- package/dist/read/filter-contract.js +3 -0
- package/dist/read/filter-contract.js.map +1 -1
- package/dist/read/log-boundary.d.ts +46 -2
- package/dist/read/log-boundary.js +43 -2
- package/dist/read/log-boundary.js.map +1 -1
- package/dist/read/predicates.d.ts +13 -0
- package/dist/read/predicates.js +13 -0
- package/dist/read/predicates.js.map +1 -1
- package/dist/read/project-view.js +5 -5
- package/dist/read/project-view.js.map +1 -1
- package/dist/read/queries.d.ts +12 -0
- package/dist/read/queries.js +14 -0
- package/dist/read/queries.js.map +1 -1
- package/dist/read/search-rank.js +2 -2
- package/dist/read/search-rank.js.map +1 -1
- package/dist/read/shape.d.ts +30 -26
- package/dist/read/shape.js +130 -101
- package/dist/read/shape.js.map +1 -1
- package/dist/read/snapshot.js +2 -2
- package/dist/read/snapshot.js.map +1 -1
- package/dist/read/stage.d.ts +36 -18
- package/dist/read/stage.js +30 -13
- package/dist/read/stage.js.map +1 -1
- package/dist/read/views.d.ts +62 -0
- package/dist/read/views.js +134 -14
- package/dist/read/views.js.map +1 -1
- package/dist/surface-copy.d.ts +2 -2
- package/dist/surface-copy.js +2 -2
- package/dist/write/batch.d.ts +28 -3
- package/dist/write/batch.js +162 -46
- package/dist/write/batch.js.map +1 -1
- package/dist/write/clear-reminder.js +3 -1
- package/dist/write/clear-reminder.js.map +1 -1
- package/dist/write/clone.d.ts +4 -0
- package/dist/write/clone.js +531 -0
- package/dist/write/clone.js.map +1 -0
- package/dist/write/commands.js +196 -29
- package/dist/write/commands.js.map +1 -1
- package/dist/write/guards.d.ts +1 -1
- package/dist/write/guards.js +44 -12
- package/dist/write/guards.js.map +1 -1
- package/dist/write/make-repeating-project.d.ts +2 -3
- package/dist/write/make-repeating-project.js +2 -73
- package/dist/write/make-repeating-project.js.map +1 -1
- package/dist/write/move.js +53 -1
- package/dist/write/move.js.map +1 -1
- package/dist/write/operations.d.ts +134 -11
- package/dist/write/operations.js +5 -1
- package/dist/write/operations.js.map +1 -1
- package/dist/write/pipeline.d.ts +38 -0
- package/dist/write/pipeline.js +71 -6
- package/dist/write/pipeline.js.map +1 -1
- package/dist/write/pre-state.d.ts +41 -0
- package/dist/write/pre-state.js +71 -8
- package/dist/write/pre-state.js.map +1 -1
- package/dist/write/preserve-modified.d.ts +55 -0
- package/dist/write/preserve-modified.js +106 -0
- package/dist/write/preserve-modified.js.map +1 -0
- package/dist/write/promote-clone.d.ts +32 -0
- package/dist/write/promote-clone.js +620 -0
- package/dist/write/promote-clone.js.map +1 -0
- package/dist/write/reorder.js +49 -2
- package/dist/write/reorder.js.map +1 -1
- package/dist/write/resolution-timestamps.js +29 -7
- package/dist/write/resolution-timestamps.js.map +1 -1
- package/dist/write/reversibility.js +32 -14
- package/dist/write/reversibility.js.map +1 -1
- package/dist/write/scope-guard.js +2 -0
- package/dist/write/scope-guard.js.map +1 -1
- package/dist/write/undo.d.ts +12 -2
- package/dist/write/undo.js +145 -22
- package/dist/write/undo.js.map +1 -1
- package/dist/write/vectors/applescript.js +9 -0
- package/dist/write/vectors/applescript.js.map +1 -1
- package/dist/write/vectors/simulator.js +242 -10
- package/dist/write/vectors/simulator.js.map +1 -1
- package/dist/write/vectors/ui-certification.d.ts +1 -1
- package/dist/write/vectors/ui-certification.js +10 -3
- package/dist/write/vectors/ui-certification.js.map +1 -1
- package/dist/write/verify/delta.d.ts +55 -10
- package/dist/write/verify/delta.js +73 -10
- package/dist/write/verify/delta.js.map +1 -1
- package/package.json +1 -1
- package/schema/envelope.schema.json +25 -0
- package/skills/things-cli/SKILL.md +10 -7
- package/skills/things-cli/references/banner.md +1 -1
- package/skills/things-cli/references/contracts.md +17 -9
- package/skills/things-cli/references/{model.md → data-model.md} +5 -2
- package/skills/things-cli/references/ordering.md +2 -0
|
@@ -20,6 +20,14 @@ export const REVERSIBILITY = {
|
|
|
20
20
|
class: "reversible",
|
|
21
21
|
note: "inverse deletes the duplicated project to the Trash",
|
|
22
22
|
},
|
|
23
|
+
"todo.clone": {
|
|
24
|
+
class: "reversible",
|
|
25
|
+
note: "inverse trashes the minted clone to-do (single leg); irreversible only if the clone's uuid was never discovered",
|
|
26
|
+
},
|
|
27
|
+
"project.clone": {
|
|
28
|
+
class: "reversible",
|
|
29
|
+
note: "inverse trashes the minted clone project (and the children it carried) to the Trash; irreversible only if the clone's uuid was never discovered",
|
|
30
|
+
},
|
|
23
31
|
"area.add": {
|
|
24
32
|
class: "reversible",
|
|
25
33
|
ack: "permanent",
|
|
@@ -58,12 +66,12 @@ export const REVERSIBILITY = {
|
|
|
58
66
|
// ---- delete / restore ---------------------------------------------------
|
|
59
67
|
"todo.delete": {
|
|
60
68
|
class: "reversible-with-loss",
|
|
61
|
-
note: "inverse restores from the Trash but lands in the Inbox DE-SCHEDULED (E15) — the prior list/schedule was not captured by the delete",
|
|
69
|
+
note: "inverse restores from the Trash but lands in the Inbox DE-SCHEDULED (E15) — the prior list/schedule was not captured by the delete. EXCEPTION: deleting a repeating TEMPLATE is IRREVERSIBLE headlessly (the app forbids restoring a template out to a list, AS 301) — no undo token is emitted and the result discloses Trash ▸ Put Back as the only revival (SERDEL S2/S3, ruling 2026-08-13)",
|
|
62
70
|
},
|
|
63
71
|
"todo.restore": { class: "reversible", note: "inverse re-deletes the to-do to the Trash" },
|
|
64
72
|
"project.delete": {
|
|
65
73
|
class: "reversible",
|
|
66
|
-
note: "inverse restores the project IN PLACE (P06) — schedule/area/children keep their state",
|
|
74
|
+
note: "inverse restores the project IN PLACE (P06) — schedule/area/children keep their state. EXCEPTION: deleting a repeating project TEMPLATE is IRREVERSIBLE headlessly (Put Back only) — no undo token, disclosed in the result (ruling 2026-08-13)",
|
|
67
75
|
},
|
|
68
76
|
"project.restore": { class: "reversible", note: "inverse re-deletes the project to the Trash" },
|
|
69
77
|
// ---- field updates ------------------------------------------------------
|
|
@@ -164,22 +172,10 @@ export const REVERSIBILITY = {
|
|
|
164
172
|
class: "irreversible",
|
|
165
173
|
note: "a created heading has no headless delete surface (heading delete is interactive-only) — archive it in the app instead",
|
|
166
174
|
},
|
|
167
|
-
"todo.make-repeating": {
|
|
168
|
-
class: "irreversible",
|
|
169
|
-
note: "making a to-do repeat is an identity REPLACEMENT (UI2-a): the original uuid is destroyed and a new template row is born — there is no un-repeat that restores the original",
|
|
170
|
-
},
|
|
171
175
|
"todo.convert-to-project": {
|
|
172
176
|
class: "irreversible",
|
|
173
177
|
note: "converting a to-do to a project is an identity REPLACEMENT (UI2-d): the to-do uuid is destroyed and a new project uuid is born (notes preserved); the app offers no convert-back",
|
|
174
178
|
},
|
|
175
|
-
"project.make-repeating": {
|
|
176
|
-
class: "irreversible",
|
|
177
|
-
note: "making a project repeat is an identity REPLACEMENT (UIC4-b): the original project uuid is destroyed and a new template project is born (area preserved, start normalized to someday) — there is no un-repeat that restores the original",
|
|
178
|
-
},
|
|
179
|
-
"project.add-repeating": {
|
|
180
|
-
class: "irreversible",
|
|
181
|
-
note: "the composite CREATES a project then promotes it (identity replacement, UIC4-b): the created uuid is destroyed by the promote and a new repeating template is born — no automated inverse captures it; delete the resulting repeating project in the app",
|
|
182
|
-
},
|
|
183
179
|
"project.promote-heading": {
|
|
184
180
|
class: "irreversible",
|
|
185
181
|
note: "promoting a heading to a project is an identity REPLACEMENT (UI2-d): the heading uuid is destroyed, a new project is promoted into the parent's area and children reparent; no convert-back",
|
|
@@ -200,6 +196,23 @@ export const REVERSIBILITY = {
|
|
|
200
196
|
class: "conditional",
|
|
201
197
|
note: "the project's rule mutates in place (identity preserved, UIC2-a); re-drives reschedule with the captured prior rule (same faithfulness boundary as todo.reschedule-repeat) — invertible when the prior rule was captured, decodable, and dialog-expressible; irreversible otherwise. A per-instance reminder time is not restored",
|
|
202
198
|
},
|
|
199
|
+
// ---- promote-via-clone (make/add-repeating) → undo is trash-both (+restore) --
|
|
200
|
+
"todo.make-repeating": {
|
|
201
|
+
class: "reversible-with-loss",
|
|
202
|
+
note: "promote-via-clone: the minted template + its current instance are the inverse's target — undo TRASHES BOTH (the SERDEL trash-both) and restores the original to-do from the Trash (it lands in the Inbox DE-SCHEDULED, E15). The trashed template leaves no tombstone and its own un-delete is GUI-only (Trash ▸ Put Back), so this undo cannot itself be undone headlessly",
|
|
203
|
+
},
|
|
204
|
+
"project.make-repeating": {
|
|
205
|
+
class: "reversible-with-loss",
|
|
206
|
+
note: "promote-via-clone: undo TRASHES the minted template + its current instance (trash-both) and restores the original project IN PLACE (P06). The trashed template leaves no tombstone and its own un-delete is GUI-only (Put Back), so this undo cannot itself be undone headlessly",
|
|
207
|
+
},
|
|
208
|
+
"todo.add-repeating": {
|
|
209
|
+
class: "reversible",
|
|
210
|
+
note: "the composite creates a to-do then promotes it; undo TRASHES the minted template + its current instance (SERDEL trash-both) — the whole created series moves to the Trash. Re-creating the series is GUI-only (the template leaves no tombstone; use Trash ▸ Put Back), so this undo is not itself headlessly undoable",
|
|
211
|
+
},
|
|
212
|
+
"project.add-repeating": {
|
|
213
|
+
class: "reversible",
|
|
214
|
+
note: "the composite creates a project then promotes it; undo TRASHES the minted template + its current instance (SERDEL trash-both) — the whole created series moves to the Trash. Re-creating the series is GUI-only, so this undo is not itself headlessly undoable",
|
|
215
|
+
},
|
|
203
216
|
// ---- ui-vector reversible pairs -----------------------------------------
|
|
204
217
|
"todo.pause-repeat": {
|
|
205
218
|
class: "reversible",
|
|
@@ -217,6 +230,11 @@ export const REVERSIBILITY = {
|
|
|
217
230
|
class: "reversible",
|
|
218
231
|
note: "inverse pauses the project's repeat (UIC2-a): resume clears the paused flag, pause re-sets it",
|
|
219
232
|
},
|
|
233
|
+
// ---- irreversible: the log-move boundary only advances ------------------
|
|
234
|
+
"log-now": {
|
|
235
|
+
class: "irreversible",
|
|
236
|
+
note: "logging moves completed items into the Logbook by advancing the log-move boundary (TMSettings.manualLogDate); no official surface can rewind it (TIMEZ/settings-stamp laws), so there is no inverse. Nothing is deleted — the items simply become logged",
|
|
237
|
+
},
|
|
220
238
|
};
|
|
221
239
|
/** The ops whose class is `irreversible` — must equal undo.ts's IRREVERSIBLE keys. */
|
|
222
240
|
export function irreversibleOps() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reversibility.js","sourceRoot":"","sources":["../../src/write/reversibility.ts"],"names":[],"mappings":"AA0CA;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAA8C;IACtE,4EAA4E;IAC5E,UAAU,EAAE;QACV,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,uHAAuH;KAC9H;IACD,gBAAgB,EAAE;QAChB,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,kGAAkG;KACzG;IACD,aAAa,EAAE;QACb,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,wEAAwE;KAC/E;IACD,mBAAmB,EAAE;QACnB,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,qDAAqD;KAC5D;IACD,UAAU,EAAE;QACV,KAAK,EAAE,YAAY;QACnB,GAAG,EAAE,WAAW;QAChB,IAAI,EAAE,qGAAqG;KAC5G;IACD,SAAS,EAAE;QACT,KAAK,EAAE,YAAY;QACnB,GAAG,EAAE,WAAW;QAChB,IAAI,EAAE,mGAAmG;KAC1G;IAED,4EAA4E;IAC5E,eAAe,EAAE;QACf,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,yFAAyF;KAChG;IACD,aAAa,EAAE;QACb,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,0DAA0D;KACjE;IACD,aAAa,EAAE;QACb,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,mEAAmE;KAC1E;IACD,kBAAkB,EAAE;QAClB,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,+FAA+F;KACtG;IACD,gBAAgB,EAAE;QAChB,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,2FAA2F;KAClG;IACD,gBAAgB,EAAE;QAChB,KAAK,EAAE,YAAY;QACnB,IAAI,EAAE,2HAA2H;KAClI;IAED,4EAA4E;IAC5E,aAAa,EAAE;QACb,KAAK,EAAE,sBAAsB;QAC7B,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"reversibility.js","sourceRoot":"","sources":["../../src/write/reversibility.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,6 +26,8 @@ export function evaluateScope(db, op, params, pre, scope) {
|
|
|
26
26
|
return blocked("the sidebar area order is global, above any container scope");
|
|
27
27
|
case "trash.empty":
|
|
28
28
|
return blocked("emptying the Trash permanently deletes every trashed item library-wide, including ones outside the active scope");
|
|
29
|
+
case "log-now":
|
|
30
|
+
return blocked("logging moves every completed item library-wide into the Logbook, including ones outside the active scope");
|
|
29
31
|
case "tag.update":
|
|
30
32
|
return blocked("renaming or re-nesting a tag changes shared state visible to every tagged item across the whole library");
|
|
31
33
|
case "tag.delete":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scope-guard.js","sourceRoot":"","sources":["../../src/write/scope-guard.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"scope-guard.js","sourceRoot":"","sources":["../../src/write/scope-guard.ts"],"names":[],"mappings":"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"}
|
package/dist/write/undo.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export interface UndoStep {
|
|
|
24
24
|
/**
|
|
25
25
|
* STRUCTURAL axes this step overwrites (getField paths into the decoded
|
|
26
26
|
* target: `status`, `trashed`, `project`/`project.uuid`, `area`/`area.uuid`,
|
|
27
|
-
* `heading.uuid`, `start`/`startDate`/`
|
|
27
|
+
* `heading.uuid`, `start`/`startDate`/`today`/`evening`). Before executing,
|
|
28
28
|
* `checkStepPrecondition` verifies the target's CURRENT value on each still
|
|
29
29
|
* equals the recorded `observed` after-value — an out-of-band move/status/
|
|
30
30
|
* schedule change already there blocks rather than being clobbered. Set only
|
|
@@ -123,10 +123,20 @@ export declare function scanAuditIntegrity(records: AuditRecord[]): AuditIntegri
|
|
|
123
123
|
* The undoable targets to unwind, NEWEST FIRST (undo unwinds a stack).
|
|
124
124
|
*
|
|
125
125
|
* - `txn` wins when present: the ONE record whose undo token matches (or an
|
|
126
|
-
* empty array — the caller distinguishes not-found from already-undone).
|
|
126
|
+
* empty array — the caller distinguishes not-found from already-undone). The
|
|
127
|
+
* already-undone exclusion below does NOT apply to `--txn`: surgical targeting
|
|
128
|
+
* keeps the loud "already undone" error (runUndo raises it before selecting).
|
|
127
129
|
* - otherwise the last `last` records, optionally narrowed to actor `by`
|
|
128
130
|
* (exact match; "*"/undefined = every actor). `by` NEVER matches an
|
|
129
131
|
* `undo:<actor>` record — those are excluded from undoability entirely.
|
|
132
|
+
*
|
|
133
|
+
* ALREADY-UNDONE records are EXCLUDED from `--last`/`--by` selection (Change 3),
|
|
134
|
+
* so `--last N` always means "the N newest NOT-YET-undone mutations" and a
|
|
135
|
+
* repeated `undo --last N` walks progressively deeper into history instead of
|
|
136
|
+
* re-selecting the same records (whose inverses would trip the precondition
|
|
137
|
+
* guard). IRREVERSIBLE records are NOT excluded — they were never undone, so
|
|
138
|
+
* they keep COUNTING toward N and being reported every pass (reaching silently
|
|
139
|
+
* past one to undo something older would be a dangerous surprise).
|
|
130
140
|
*/
|
|
131
141
|
export declare function selectUndoTargets(records: AuditRecord[], selector?: UndoSelector): AuditRecord[];
|
|
132
142
|
export declare const IRREVERSIBLE: Partial<Record<string, string>>;
|
package/dist/write/undo.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* `observed` after-values: CONTENT fields (title/notes/deadline/reminder/
|
|
28
28
|
* tags, keyed 1:1 to the inverse step's params) and the STRUCTURAL axes each
|
|
29
29
|
* step names in its `guardFields` — status, container (project/area/
|
|
30
|
-
* heading), schedule (start/startDate/
|
|
30
|
+
* heading), schedule (start/startDate/today/evening), and trashed state. A
|
|
31
31
|
* field an out-of-band edit already moved is NOT clobbered — the step is
|
|
32
32
|
* refused (blocked, naming what moved) and unwinding stops.
|
|
33
33
|
* `--acknowledge-out-of-band-changes` (MCP `acknowledge_out_of_band_changes`)
|
|
@@ -46,6 +46,7 @@ import { localToday } from "../model/dates.js";
|
|
|
46
46
|
import { getField } from "./verify/delta.js";
|
|
47
47
|
import { isRepeatingTemplate, loadTarget } from "./pre-state.js";
|
|
48
48
|
import { isUiDriveOp } from "./operations.js";
|
|
49
|
+
import { restoreModDates } from "./preserve-modified.js";
|
|
49
50
|
import { ruleToInverseParams } from "./repeat-rule.js";
|
|
50
51
|
import { runMutation } from "./pipeline.js";
|
|
51
52
|
import { runReorder } from "./reorder.js";
|
|
@@ -141,14 +142,39 @@ export function scanAuditIntegrity(records) {
|
|
|
141
142
|
}
|
|
142
143
|
return { orphanedIntents, newestOrphanIntent };
|
|
143
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* The set of mutation undo-tokens that have ALREADY been undone: derived from
|
|
147
|
+
* the inverse records on the trail (an `ok` record under an `undo:*` actor whose
|
|
148
|
+
* `undoOf` back-references the mutation it reversed). This is the same linkage
|
|
149
|
+
* the `--txn` already-undone check reads, generalized to a set.
|
|
150
|
+
*/
|
|
151
|
+
function undoneTokens(records) {
|
|
152
|
+
const undone = new Set();
|
|
153
|
+
for (const r of records) {
|
|
154
|
+
if (r.result === "ok" && r.actor.startsWith("undo:") && typeof r.undoOf === "string") {
|
|
155
|
+
undone.add(r.undoOf);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return undone;
|
|
159
|
+
}
|
|
144
160
|
/**
|
|
145
161
|
* The undoable targets to unwind, NEWEST FIRST (undo unwinds a stack).
|
|
146
162
|
*
|
|
147
163
|
* - `txn` wins when present: the ONE record whose undo token matches (or an
|
|
148
|
-
* empty array — the caller distinguishes not-found from already-undone).
|
|
164
|
+
* empty array — the caller distinguishes not-found from already-undone). The
|
|
165
|
+
* already-undone exclusion below does NOT apply to `--txn`: surgical targeting
|
|
166
|
+
* keeps the loud "already undone" error (runUndo raises it before selecting).
|
|
149
167
|
* - otherwise the last `last` records, optionally narrowed to actor `by`
|
|
150
168
|
* (exact match; "*"/undefined = every actor). `by` NEVER matches an
|
|
151
169
|
* `undo:<actor>` record — those are excluded from undoability entirely.
|
|
170
|
+
*
|
|
171
|
+
* ALREADY-UNDONE records are EXCLUDED from `--last`/`--by` selection (Change 3),
|
|
172
|
+
* so `--last N` always means "the N newest NOT-YET-undone mutations" and a
|
|
173
|
+
* repeated `undo --last N` walks progressively deeper into history instead of
|
|
174
|
+
* re-selecting the same records (whose inverses would trip the precondition
|
|
175
|
+
* guard). IRREVERSIBLE records are NOT excluded — they were never undone, so
|
|
176
|
+
* they keep COUNTING toward N and being reported every pass (reaching silently
|
|
177
|
+
* past one to undo something older would be a dangerous surprise).
|
|
152
178
|
*/
|
|
153
179
|
export function selectUndoTargets(records, selector = {}) {
|
|
154
180
|
const undoable = undoableRecords(records);
|
|
@@ -156,9 +182,11 @@ export function selectUndoTargets(records, selector = {}) {
|
|
|
156
182
|
const match = undoable.find((r) => undoToken(r) === selector.txn);
|
|
157
183
|
return match === undefined ? [] : [match];
|
|
158
184
|
}
|
|
185
|
+
const undone = undoneTokens(records);
|
|
186
|
+
const notUndone = undoable.filter((r) => !undone.has(undoToken(r)));
|
|
159
187
|
const byActor = selector.by === undefined || selector.by === "*"
|
|
160
|
-
?
|
|
161
|
-
:
|
|
188
|
+
? notUndone
|
|
189
|
+
: notUndone.filter((r) => r.actor === selector.by);
|
|
162
190
|
return byActor.slice(-Math.max(1, selector.last ?? 1)).toReversed();
|
|
163
191
|
}
|
|
164
192
|
/**
|
|
@@ -209,17 +237,13 @@ export const IRREVERSIBLE = {
|
|
|
209
237
|
"area.delete": "areas are deleted permanently — there is nothing to restore (A25)",
|
|
210
238
|
"tag.delete": "tags are deleted permanently — assignments already cascaded (A26)",
|
|
211
239
|
"trash.empty": "emptying the Trash hard-deletes every row — nothing to restore (A27)",
|
|
240
|
+
"log-now": "logging advances the log-move boundary (manualLogDate) to move completed items into the " +
|
|
241
|
+
"Logbook; no official surface can rewind the boundary (TIMEZ/settings-stamp), so there is " +
|
|
242
|
+
"no inverse — nothing is deleted, the items are simply logged",
|
|
212
243
|
"project.add-heading": "a created heading can only be removed by deleting it, which has no headless surface " +
|
|
213
244
|
"(heading delete is interactive-only) — archive it in the app instead",
|
|
214
|
-
"todo.make-repeating": "making a to-do repeat is an identity replacement (UI2-a): the original uuid is destroyed " +
|
|
215
|
-
"and a new template row is born — there is no un-repeat that restores the original",
|
|
216
245
|
"todo.convert-to-project": "converting a to-do to a project is an identity replacement (UI2-d): the to-do uuid is " +
|
|
217
246
|
"destroyed and a new project is born — the app offers no convert-back",
|
|
218
|
-
"project.make-repeating": "making a project repeat is an identity replacement (UIC4-b): the original project uuid is " +
|
|
219
|
-
"destroyed and a new template project is born — there is no un-repeat that restores the original",
|
|
220
|
-
"project.add-repeating": "the composite creates a project then promotes it (identity replacement, UIC4-b): the " +
|
|
221
|
-
"created uuid is destroyed by the promote and a new repeating template is born — delete the " +
|
|
222
|
-
"resulting repeating project in the app",
|
|
223
247
|
"project.promote-heading": "promoting a heading to a project is an identity replacement (UI2-d): the heading uuid is " +
|
|
224
248
|
"destroyed and a new project is born — no convert-back",
|
|
225
249
|
"project.move-heading-to-project": "moving a heading to another project is app-reversible (move it back) but has no wired " +
|
|
@@ -264,13 +288,15 @@ function decodedRuleOf(record) {
|
|
|
264
288
|
}
|
|
265
289
|
/**
|
|
266
290
|
* Reconstruct the scheduling step that restores a to-do's pre-op placement
|
|
267
|
-
* from the captured pre-values (start / startDate /
|
|
291
|
+
* from the captured pre-values (start / startDate / evening-marker / reminder).
|
|
268
292
|
*/
|
|
269
293
|
function scheduleSteps(uuid, record, todayIso, op = "todo.update") {
|
|
270
294
|
const notes = [];
|
|
271
295
|
const start = preField(record, "start");
|
|
272
296
|
const startDate = preField(record, "startDate");
|
|
273
|
-
|
|
297
|
+
// Pre-op Today placement rides the presence-keyed `evening` marker (the retired
|
|
298
|
+
// `todaySection` word is gone): `evening === true` ⇔ the former "evening".
|
|
299
|
+
const wasEvening = preField(record, "evening") === true;
|
|
274
300
|
const reminder = preField(record, "reminder");
|
|
275
301
|
// start === "inbox" is a to-do-only pre-state (projects never live in the
|
|
276
302
|
// Inbox), so the move step below stays a todo.move.
|
|
@@ -285,10 +311,10 @@ function scheduleSteps(uuid, record, todayIso, op = "todo.update") {
|
|
|
285
311
|
// startDate == today maps back to the today/evening keywords (which also
|
|
286
312
|
// keep the reminder-clear path open); other dates restore literally.
|
|
287
313
|
if (startDate === todayIso)
|
|
288
|
-
when =
|
|
314
|
+
when = wasEvening ? "evening" : "today";
|
|
289
315
|
else {
|
|
290
316
|
when = startDate;
|
|
291
|
-
if (
|
|
317
|
+
if (wasEvening) {
|
|
292
318
|
notes.push("the item was a STALE evening entry (past startDate) — the date is restored but " +
|
|
293
319
|
"the evening bucket cannot be (bucket placement is today-only)");
|
|
294
320
|
}
|
|
@@ -559,6 +585,71 @@ export function planUndo(record, now, allRecords = [], current) {
|
|
|
559
585
|
notes,
|
|
560
586
|
};
|
|
561
587
|
}
|
|
588
|
+
// A clone (todo.clone / project.clone): the summary record heads the txn whose
|
|
589
|
+
// legs (the base add, checklist checks, terminal-state flips) are ordinary
|
|
590
|
+
// `leg`-role mutations excluded from independent undo. The single undoable unit
|
|
591
|
+
// is the whole clone, and its inverse is trashing the minted root — a project
|
|
592
|
+
// clone's minted children ride to the Trash with it (shallow delete), so no
|
|
593
|
+
// per-child inverse is replayed (the child uuids are captured on the record for
|
|
594
|
+
// the audit trail, not for undo).
|
|
595
|
+
case "todo.clone": {
|
|
596
|
+
if (uuid === null)
|
|
597
|
+
return irreversible("the clone's uuid was never discovered");
|
|
598
|
+
return {
|
|
599
|
+
target,
|
|
600
|
+
kind: "invertible",
|
|
601
|
+
steps: [{ op: "todo.delete", params: { uuid } }],
|
|
602
|
+
notes,
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
case "project.clone": {
|
|
606
|
+
if (uuid === null)
|
|
607
|
+
return irreversible("the clone's uuid was never discovered");
|
|
608
|
+
notes.push("the cloned project (and every child it minted) moves to the Trash");
|
|
609
|
+
return {
|
|
610
|
+
target,
|
|
611
|
+
kind: "invertible",
|
|
612
|
+
steps: [{ op: "project.delete", params: { uuid } }],
|
|
613
|
+
notes,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
// Promote-via-clone (make/add-repeating): the SUMMARY record captured the
|
|
617
|
+
// minted template, its current instance, and — for make-repeating — the
|
|
618
|
+
// trashed original. Undo is the SERDEL trash-both (delete BOTH rows — a
|
|
619
|
+
// template delete is a plain, publicly-allowed delete now, ruling 2026-08-13),
|
|
620
|
+
// then (make-repeating only) restore the original from the Trash. This undo
|
|
621
|
+
// cannot itself be undone headlessly — a trashed template's only revival is
|
|
622
|
+
// the app's Trash ▸ Put Back (SERDEL S2/S3) — disclosed here.
|
|
623
|
+
case "todo.make-repeating":
|
|
624
|
+
case "project.make-repeating":
|
|
625
|
+
case "todo.add-repeating":
|
|
626
|
+
case "project.add-repeating": {
|
|
627
|
+
const obs = record.observed ?? {};
|
|
628
|
+
const templateUuid = obs["templateUuid"];
|
|
629
|
+
if (typeof templateUuid !== "string") {
|
|
630
|
+
return irreversible("the minted template uuid was not captured on this record — remove the repeating " +
|
|
631
|
+
"series in the Things app (delete the template, then its current instance)");
|
|
632
|
+
}
|
|
633
|
+
const kind = record.op.startsWith("project.") ? "project" : "todo";
|
|
634
|
+
const deleteOp = kind === "project" ? "project.delete" : "todo.delete";
|
|
635
|
+
const restoreOp = kind === "project" ? "project.restore" : "todo.restore";
|
|
636
|
+
const steps = [{ op: deleteOp, params: { uuid: templateUuid } }];
|
|
637
|
+
const instanceUuid = obs["instanceUuid"];
|
|
638
|
+
if (typeof instanceUuid === "string" && instanceUuid !== templateUuid) {
|
|
639
|
+
steps.push({ op: deleteOp, params: { uuid: instanceUuid } });
|
|
640
|
+
}
|
|
641
|
+
const originalUuid = obs["originalUuid"];
|
|
642
|
+
if (typeof originalUuid === "string") {
|
|
643
|
+
steps.push({ op: restoreOp, params: { uuid: originalUuid } });
|
|
644
|
+
notes.push(kind === "todo"
|
|
645
|
+
? "the original to-do is restored from the Trash — it lands in the Inbox de-scheduled (E15)"
|
|
646
|
+
: "the original project is restored from the Trash in place (P06)");
|
|
647
|
+
}
|
|
648
|
+
notes.push("removing the series trashes the minted template AND its current instance (trash-both, " +
|
|
649
|
+
"SERDEL); this undo cannot itself be undone headlessly — a trashed template's only " +
|
|
650
|
+
"revival is the app's Trash ▸ Put Back");
|
|
651
|
+
return { target, kind: "invertible", steps, notes };
|
|
652
|
+
}
|
|
562
653
|
case "area.add": {
|
|
563
654
|
if (uuid === null)
|
|
564
655
|
return irreversible("the created uuid was never discovered");
|
|
@@ -735,7 +826,8 @@ export function planUndo(record, now, allRecords = [], current) {
|
|
|
735
826
|
const requestedWhen = (record.requested["when"] ?? record.requested["reminder"]) !== undefined;
|
|
736
827
|
// Schedule axes the restore overwrites — guarded against the recorded
|
|
737
828
|
// after-state so an out-of-band re-schedule blocks rather than clobbers.
|
|
738
|
-
|
|
829
|
+
// Today placement is the `today`/`evening` markers (todaySection retired).
|
|
830
|
+
const scheduleGuard = ["start", "startDate", "today", "evening"];
|
|
739
831
|
let scheduleMerged = false;
|
|
740
832
|
if (requestedWhen) {
|
|
741
833
|
const schedule = scheduleSteps(uuid, record, todayIso);
|
|
@@ -799,7 +891,7 @@ export function planUndo(record, now, allRecords = [], current) {
|
|
|
799
891
|
op: "project.update",
|
|
800
892
|
params,
|
|
801
893
|
...(projectScheduleMerged && {
|
|
802
|
-
options: { guardFields: ["start", "startDate", "
|
|
894
|
+
options: { guardFields: ["start", "startDate", "today", "evening"] },
|
|
803
895
|
}),
|
|
804
896
|
},
|
|
805
897
|
],
|
|
@@ -996,10 +1088,10 @@ export function planUndo(record, now, allRecords = [], current) {
|
|
|
996
1088
|
// the generalized WG-7 guard would refuse (and re-completing is wrong)
|
|
997
1089
|
// otherwise. A creation-date restore is status-safe.
|
|
998
1090
|
if (typeof stoppedPre === "string")
|
|
999
|
-
patch["
|
|
1091
|
+
patch["completedAt"] = stoppedPre;
|
|
1000
1092
|
if (typeof createdPre === "string")
|
|
1001
|
-
patch["
|
|
1002
|
-
if (patch["
|
|
1093
|
+
patch["createdAt"] = createdPre;
|
|
1094
|
+
if (patch["completedAt"] === undefined && patch["createdAt"] === undefined) {
|
|
1003
1095
|
return irreversible("the pre-op timestamps were not captured");
|
|
1004
1096
|
}
|
|
1005
1097
|
notes.push("timestamps restore at DAY precision (noon local) — the original sub-day time is " +
|
|
@@ -1326,7 +1418,7 @@ export function planUndo(record, now, allRecords = [], current) {
|
|
|
1326
1418
|
"date to attach to; re-schedule it, then re-add the reminder");
|
|
1327
1419
|
}
|
|
1328
1420
|
const when = startDate === todayIso
|
|
1329
|
-
? current.
|
|
1421
|
+
? current.derived.evening === true
|
|
1330
1422
|
? "evening"
|
|
1331
1423
|
: "today"
|
|
1332
1424
|
: startDate;
|
|
@@ -1464,7 +1556,8 @@ const AXIS_LABEL = {
|
|
|
1464
1556
|
"heading.uuid": "heading",
|
|
1465
1557
|
start: "schedule",
|
|
1466
1558
|
startDate: "schedule",
|
|
1467
|
-
|
|
1559
|
+
today: "schedule",
|
|
1560
|
+
evening: "schedule",
|
|
1468
1561
|
};
|
|
1469
1562
|
/**
|
|
1470
1563
|
* NOT GUARDED (no captured after-state to compare against, so left unguarded —
|
|
@@ -1614,6 +1707,14 @@ export async function runUndo(deps, auditDirPath, options = {}, onItem) {
|
|
|
1614
1707
|
break;
|
|
1615
1708
|
}
|
|
1616
1709
|
}
|
|
1710
|
+
// Preview the symmetric umd-restore (a --preserve-modified original).
|
|
1711
|
+
if (record.preModDates !== undefined) {
|
|
1712
|
+
const n = Object.values(record.preModDates).filter((v) => typeof v === "number").length;
|
|
1713
|
+
if (n > 0) {
|
|
1714
|
+
plan.notes.push(`would restore the modification date on ${n} row(s) after the inverse (this undo ` +
|
|
1715
|
+
"stays off the changes/watch timeline, symmetric with the --preserve-modified original)");
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1617
1718
|
item = { plan, results: preview, outcome: "dry-run" };
|
|
1618
1719
|
}
|
|
1619
1720
|
else {
|
|
@@ -1670,6 +1771,28 @@ export async function runUndo(deps, auditDirPath, options = {}, onItem) {
|
|
|
1670
1771
|
break;
|
|
1671
1772
|
}
|
|
1672
1773
|
}
|
|
1774
|
+
// Symmetric umd-restore (2026-08-13 ruling): a forward op that ran with
|
|
1775
|
+
// --preserve-modified recorded each touched row's pre-write
|
|
1776
|
+
// userModificationDate on `preModDates`. After the inverse legs land, put
|
|
1777
|
+
// those umd values back (floor(preUmd)) so the UNDO is ALSO off the
|
|
1778
|
+
// changes/watch timeline — matching the forward op's silence. Best-effort:
|
|
1779
|
+
// a failed restore is disclosed, never fatal (the inverse already stands).
|
|
1780
|
+
// Records without preModDates (the default) are untouched.
|
|
1781
|
+
if (!failed && record.preModDates !== undefined) {
|
|
1782
|
+
const umdTargets = Object.entries(record.preModDates)
|
|
1783
|
+
.filter((e) => typeof e[1] === "number")
|
|
1784
|
+
.map(([tUuid, preUmd]) => ({ uuid: tUuid, preUmd }));
|
|
1785
|
+
if (umdTargets.length > 0) {
|
|
1786
|
+
const restore = await restoreModDates(deps.db, deps.vectors, umdTargets);
|
|
1787
|
+
if (restore.restored > 0) {
|
|
1788
|
+
plan.notes.push(`restored the modification date on ${restore.restored} row(s) so this undo stays ` +
|
|
1789
|
+
"off the changes/watch timeline (symmetric with the --preserve-modified original)");
|
|
1790
|
+
}
|
|
1791
|
+
for (const f of restore.failures) {
|
|
1792
|
+
plan.notes.push(`could not restore the modification date on ${f.uuid}: ${f.detail} (non-fatal)`);
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1673
1796
|
const okCount = results.filter((r) => r.kind === "ok").length;
|
|
1674
1797
|
item = {
|
|
1675
1798
|
plan,
|