things-api 0.12.0 → 0.14.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 +2 -2
- package/dist/cli/canonical-ref.d.ts +21 -0
- package/dist/cli/canonical-ref.js +23 -0
- package/dist/cli/canonical-ref.js.map +1 -0
- package/dist/cli/commands/area.d.ts +5 -5
- package/dist/cli/commands/area.js +39 -18
- package/dist/cli/commands/area.js.map +1 -1
- package/dist/cli/commands/install-skill.d.ts +2 -2
- package/dist/cli/commands/install-skill.js +29 -0
- package/dist/cli/commands/install-skill.js.map +1 -1
- package/dist/cli/commands/mcp.js +12 -1
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/project.js +74 -22
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/reads.d.ts +5 -1
- package/dist/cli/commands/reads.js +31 -15
- package/dist/cli/commands/reads.js.map +1 -1
- package/dist/cli/commands/setup.js +11 -4
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/show.js +51 -32
- package/dist/cli/commands/show.js.map +1 -1
- package/dist/cli/commands/todo.js +2 -2
- package/dist/cli/commands/todo.js.map +1 -1
- package/dist/cli/commands/writes.js +138 -67
- package/dist/cli/commands/writes.js.map +1 -1
- package/dist/cli/did-you-mean.js +19 -5
- package/dist/cli/did-you-mean.js.map +1 -1
- package/dist/cli/dry-run.d.ts +55 -0
- package/dist/cli/dry-run.js +92 -0
- package/dist/cli/dry-run.js.map +1 -0
- package/dist/cli/glyphs.d.ts +9 -2
- package/dist/cli/glyphs.js +11 -5
- package/dist/cli/glyphs.js.map +1 -1
- package/dist/cli/help.js +7 -6
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +7 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/read-driver.d.ts +47 -7
- package/dist/cli/read-driver.js +43 -21
- package/dist/cli/read-driver.js.map +1 -1
- package/dist/cli/ref-render.d.ts +14 -0
- package/dist/cli/ref-render.js +9 -0
- package/dist/cli/ref-render.js.map +1 -0
- package/dist/cli/render.d.ts +39 -25
- package/dist/cli/render.js +102 -62
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/resolve-invocation.d.ts +5 -3
- package/dist/cli/resolve-invocation.js +13 -4
- package/dist/cli/resolve-invocation.js.map +1 -1
- package/dist/client.d.ts +100 -32
- package/dist/client.js +63 -19
- package/dist/client.js.map +1 -1
- package/dist/contracts.d.ts +34 -33
- package/dist/contracts.js +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/db/baselines/db-v26.js +4 -1
- package/dist/db/baselines/db-v26.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +192 -139
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/dates.d.ts +26 -0
- package/dist/model/dates.js +46 -4
- package/dist/model/dates.js.map +1 -1
- package/dist/model/entities.d.ts +11 -1
- package/dist/model/entities.js.map +1 -1
- package/dist/model/mappers.js +3 -0
- package/dist/model/mappers.js.map +1 -1
- package/dist/model/serialize.js +15 -3
- package/dist/model/serialize.js.map +1 -1
- package/dist/read/area-filter.d.ts +2 -2
- package/dist/read/area-filter.js +3 -3
- package/dist/read/area-filter.js.map +1 -1
- package/dist/read/project-view.d.ts +76 -1
- package/dist/read/project-view.js +80 -9
- package/dist/read/project-view.js.map +1 -1
- package/dist/read/queries.d.ts +71 -2
- package/dist/read/queries.js +199 -10
- package/dist/read/queries.js.map +1 -1
- package/dist/read/scope.d.ts +2 -2
- package/dist/read/scope.js +3 -3
- package/dist/read/scope.js.map +1 -1
- package/dist/read/shape.d.ts +87 -9
- package/dist/read/shape.js +483 -124
- package/dist/read/shape.js.map +1 -1
- package/dist/read/show-target.js +52 -33
- package/dist/read/show-target.js.map +1 -1
- package/dist/read/truncation.d.ts +73 -7
- package/dist/read/truncation.js +62 -29
- package/dist/read/truncation.js.map +1 -1
- package/dist/read/views.d.ts +20 -7
- package/dist/read/views.js +7 -7
- package/dist/read/views.js.map +1 -1
- package/dist/surface-copy.d.ts +13 -0
- package/dist/surface-copy.js +13 -0
- package/dist/surface-copy.js.map +1 -1
- package/dist/write/batch.js +0 -1
- package/dist/write/batch.js.map +1 -1
- package/dist/write/commands.d.ts +25 -1
- package/dist/write/commands.js +259 -122
- package/dist/write/commands.js.map +1 -1
- package/dist/write/guards.js +27 -11
- package/dist/write/guards.js.map +1 -1
- package/dist/write/move.d.ts +34 -9
- package/dist/write/move.js +730 -78
- package/dist/write/move.js.map +1 -1
- package/dist/write/operations.d.ts +50 -20
- package/dist/write/operations.js +2 -2
- package/dist/write/operations.js.map +1 -1
- package/dist/write/pipeline.js +25 -4
- package/dist/write/pipeline.js.map +1 -1
- package/dist/write/pre-state.d.ts +58 -28
- package/dist/write/pre-state.js +247 -49
- package/dist/write/pre-state.js.map +1 -1
- package/dist/write/reorder.js +266 -32
- package/dist/write/reorder.js.map +1 -1
- package/dist/write/resolution-timestamps.d.ts +34 -0
- package/dist/write/resolution-timestamps.js +286 -0
- package/dist/write/resolution-timestamps.js.map +1 -0
- package/dist/write/reversibility.js +5 -5
- package/dist/write/reversibility.js.map +1 -1
- package/dist/write/scope-guard.js +0 -5
- package/dist/write/scope-guard.js.map +1 -1
- package/dist/write/undo.d.ts +0 -6
- package/dist/write/undo.js +44 -4
- package/dist/write/undo.js.map +1 -1
- package/dist/write/vectors/applescript.js +14 -4
- package/dist/write/vectors/applescript.js.map +1 -1
- package/dist/write/vectors/url-scheme.js +0 -8
- package/dist/write/vectors/url-scheme.js.map +1 -1
- package/dist/write/verify/delta.d.ts +16 -2
- package/dist/write/verify/delta.js +21 -2
- package/dist/write/verify/delta.js.map +1 -1
- package/package.json +1 -1
- package/schema/envelope.schema.json +16 -78
- package/skills/things-cli/SKILL.md +10 -6
- package/skills/things-cli/references/contracts.md +3 -2
- package/skills/things-cli/references/errors.md +9 -1
- package/skills/things-cli/references/model.md +9 -7
- package/skills/things-cli/references/ordering.md +36 -10
|
@@ -433,9 +433,15 @@ function emitMoveResult(result, opts, meta) {
|
|
|
433
433
|
: result.refusal === "unsupported"
|
|
434
434
|
? ExitCode.Unsupported
|
|
435
435
|
: ExitCode.Blocked;
|
|
436
|
+
// A hoisted placement block names its hazard — surface it with the canonical
|
|
437
|
+
// `blocked:<hazard>` code + `BLOCKED (<hazard>)` copy, exactly as a direct
|
|
438
|
+
// `things reorder` hazard block does (emitResult "blocked" case).
|
|
439
|
+
const jsonCode = result.hazard !== undefined
|
|
440
|
+
? blockedCode({ hazard: result.hazard, reason: "hazard" })
|
|
441
|
+
: result.refusal;
|
|
436
442
|
if (opts.json) {
|
|
437
443
|
process.stdout.write(`${JSON.stringify(errorEnvelope({
|
|
438
|
-
code:
|
|
444
|
+
code: jsonCode,
|
|
439
445
|
message: result.detail,
|
|
440
446
|
...(result.remediation !== undefined && { remediation: result.remediation }),
|
|
441
447
|
...(result.candidates !== undefined && {
|
|
@@ -444,7 +450,12 @@ function emitMoveResult(result, opts, meta) {
|
|
|
444
450
|
}, meta))}\n`);
|
|
445
451
|
}
|
|
446
452
|
else {
|
|
447
|
-
|
|
453
|
+
const prefix = result.refusal === "usage"
|
|
454
|
+
? "error"
|
|
455
|
+
: result.hazard !== undefined
|
|
456
|
+
? `BLOCKED (${result.hazard})`
|
|
457
|
+
: result.refusal.toUpperCase();
|
|
458
|
+
process.stderr.write(`${prefix}: ${result.detail}\n` +
|
|
448
459
|
(result.remediation !== undefined ? ` remediation: ${result.remediation}\n` : ""));
|
|
449
460
|
}
|
|
450
461
|
process.exitCode = code;
|
|
@@ -540,6 +551,38 @@ function addPositionFlags(cmd) {
|
|
|
540
551
|
.option("--before <ref>", "place the block immediately before this item (same bucket)")
|
|
541
552
|
.option("--after <ref>", "place the block immediately after this item (same bucket)");
|
|
542
553
|
}
|
|
554
|
+
/**
|
|
555
|
+
* The universal-`reorder` anchor grammar (spec §7 ratified vocabulary):
|
|
556
|
+
* --start / --end / --before / --after. `--start`/`--end` name the block's top/
|
|
557
|
+
* bottom slot in its scope; --before/--after anchor against a sibling.
|
|
558
|
+
*/
|
|
559
|
+
function addReorderPositionFlags(cmd) {
|
|
560
|
+
return cmd
|
|
561
|
+
.option("--start", "place the block at the start of its scope")
|
|
562
|
+
.option("--end", "place the block at the end of its scope")
|
|
563
|
+
.option("--before <ref>", "place the block immediately before this item")
|
|
564
|
+
.option("--after <ref>", "place the block immediately after this item");
|
|
565
|
+
}
|
|
566
|
+
/** Build a MovePosition from the reorder --start/--end/--before/--after flags. */
|
|
567
|
+
function reorderPosition(opts) {
|
|
568
|
+
const chosen = [
|
|
569
|
+
opts["start"] === true,
|
|
570
|
+
opts["end"] === true,
|
|
571
|
+
opts["before"] !== undefined,
|
|
572
|
+
opts["after"] !== undefined,
|
|
573
|
+
].filter(Boolean).length;
|
|
574
|
+
if (chosen > 1)
|
|
575
|
+
return "conflict";
|
|
576
|
+
if (opts["start"] === true)
|
|
577
|
+
return { at: "first" };
|
|
578
|
+
if (opts["end"] === true)
|
|
579
|
+
return { at: "last" };
|
|
580
|
+
if (opts["before"] !== undefined)
|
|
581
|
+
return { before: opts["before"] };
|
|
582
|
+
if (opts["after"] !== undefined)
|
|
583
|
+
return { after: opts["after"] };
|
|
584
|
+
return undefined;
|
|
585
|
+
}
|
|
543
586
|
/** One TTY line for a bulk-add batch item (the human, non-JSON multi rendering). */
|
|
544
587
|
function addResultLine(r) {
|
|
545
588
|
const o = r.outcome;
|
|
@@ -658,6 +701,8 @@ export function registerWriteCommands(program) {
|
|
|
658
701
|
.option("--project <ref>", "destination project (uuid or unique name)")
|
|
659
702
|
.option("--area <ref>", "destination area (uuid or unique name)")
|
|
660
703
|
.option("--heading <name>", "existing heading in the destination project")
|
|
704
|
+
.option("--created-at <iso>", "born with this creation timestamp (ISO date or datetime; a date is noon in the effective zone)")
|
|
705
|
+
.option("--completed-at <iso>", "born completed (in the Logbook) with this completion timestamp (ISO date or datetime); drop --when/--reminder")
|
|
661
706
|
.option("--acknowledge-project-reopen", "allow adding into a completed/canceled project")
|
|
662
707
|
.option("--stdin", "read newline-delimited titles from stdin (blank lines skipped); exclusive with title arguments")
|
|
663
708
|
.option("--id-only", "print only the new uuid(s), one per line in creation order, and nothing else (exclusive with --json)"))).action(async (titles, opts) => {
|
|
@@ -695,6 +740,8 @@ export function registerWriteCommands(program) {
|
|
|
695
740
|
...(project !== undefined && { project }),
|
|
696
741
|
...(area !== undefined && { area }),
|
|
697
742
|
...(opts["heading"] !== undefined && { heading: opts["heading"] }),
|
|
743
|
+
...(opts["createdAt"] !== undefined && { createdAt: opts["createdAt"] }),
|
|
744
|
+
...(opts["completedAt"] !== undefined && { completedAt: opts["completedAt"] }),
|
|
698
745
|
});
|
|
699
746
|
const ackReopen = opts["acknowledgeProjectReopen"] !== undefined
|
|
700
747
|
? { acknowledgeProjectReopen: opts["acknowledgeProjectReopen"] }
|
|
@@ -772,7 +819,9 @@ export function registerWriteCommands(program) {
|
|
|
772
819
|
.option("--reminder <HH:mm>", "set a reminder (24h); requires --when today|evening|date")
|
|
773
820
|
.option("--clear-reminder", "clear the reminder (works while scheduled today|evening)")
|
|
774
821
|
.option("--deadline <date>", "YYYY-MM-DD")
|
|
775
|
-
.option("--clear-deadline", "remove the deadline")
|
|
822
|
+
.option("--clear-deadline", "remove the deadline")
|
|
823
|
+
.option("--created-at <iso>", "rewrite the creation timestamp (ISO date or datetime; a date is noon in the effective zone); status-safe")
|
|
824
|
+
.option("--completed-at <iso>", "rewrite the completion timestamp of an already-resolved to-do (a canceled one stays canceled); open to-dos are refused — use complete/cancel")).action(async (uuid, opts) => {
|
|
776
825
|
const notesModes = ["notes", "appendNotes", "prependNotes"].filter((k) => opts[k] !== undefined);
|
|
777
826
|
if (notesModes.length > 1) {
|
|
778
827
|
usageError(opts, "--notes, --append-notes, --prepend-notes are exclusive");
|
|
@@ -796,19 +845,30 @@ export function registerWriteCommands(program) {
|
|
|
796
845
|
...(opts["clearReminder"] === true && { reminder: null }),
|
|
797
846
|
...(opts["deadline"] !== undefined && { deadline: opts["deadline"] }),
|
|
798
847
|
...(opts["clearDeadline"] === true && { deadline: null }),
|
|
848
|
+
...(opts["createdAt"] !== undefined && { createdAt: opts["createdAt"] }),
|
|
849
|
+
...(opts["completedAt"] !== undefined && { completedAt: opts["completedAt"] }),
|
|
799
850
|
}, writeOptionsFrom(opts)));
|
|
800
851
|
});
|
|
801
|
-
for (const [
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
852
|
+
for (const verb of ["complete", "cancel"]) {
|
|
853
|
+
const method = verb === "complete" ? "completeTodo" : "cancelTodo";
|
|
854
|
+
const stampNote = verb === "complete"
|
|
855
|
+
? "resolving it first if needed, then backdating"
|
|
856
|
+
: "keeping it canceled via the certified flip legs";
|
|
806
857
|
addWriteFlags(todo
|
|
807
858
|
.command(`${verb} <uuid>`)
|
|
808
|
-
.description(`${verb[0]?.toUpperCase()}${verb.slice(1)} a to-do. Not available for repeating to-dos
|
|
809
|
-
|
|
859
|
+
.description(`${verb[0]?.toUpperCase()}${verb.slice(1)} a to-do. Not available for repeating to-dos. ` +
|
|
860
|
+
'--completed-at sets the completion timestamp (also the "Completed on" stamp for a canceled ' +
|
|
861
|
+
`item), ${stampNote} — a multi-leg sequence, disclosed in the result and --dry-run.`)
|
|
862
|
+
.option("--completed-at <iso>", "completion timestamp (ISO date or datetime; a date is noon in the effective zone)")).action(async (uuid, opts) => {
|
|
863
|
+
const resolution = opts["completedAt"] !== undefined ? { completedAt: opts["completedAt"] } : {};
|
|
864
|
+
await runWrite(opts, (c) => c.write[method](uuid, resolution, writeOptionsFrom(opts)));
|
|
810
865
|
});
|
|
811
866
|
}
|
|
867
|
+
addWriteFlags(todo
|
|
868
|
+
.command("reopen <uuid>")
|
|
869
|
+
.description("Reopen a to-do. Not available for repeating to-dos.")).action(async (uuid, opts) => {
|
|
870
|
+
await runWrite(opts, (c) => c.write.reopenTodo(uuid, writeOptionsFrom(opts)));
|
|
871
|
+
});
|
|
812
872
|
addPositionFlags(addWriteFlags(todo
|
|
813
873
|
.command("move <refs...>")
|
|
814
874
|
.description("Move one or more to-dos as an ordered block (the argument order is the order they " +
|
|
@@ -975,35 +1035,10 @@ export function registerWriteCommands(program) {
|
|
|
975
1035
|
return;
|
|
976
1036
|
await runWrite(opts, (c) => c.write.clearReminder(uuid, writeOptionsFrom(opts)));
|
|
977
1037
|
});
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
"canceled. The Logbook re-sorts to the new date.")
|
|
983
|
-
.option("--completed-on <date>", "YYYY-MM-DD — new completion date")
|
|
984
|
-
.option("--created-on <date>", "YYYY-MM-DD — new creation date")).action(async (uuid, opts) => {
|
|
985
|
-
await runWrite(opts, (c) => c.write.backdateTodo(uuid, {
|
|
986
|
-
...(opts["completedOn"] !== undefined && {
|
|
987
|
-
completionDate: opts["completedOn"],
|
|
988
|
-
}),
|
|
989
|
-
...(opts["createdOn"] !== undefined && { creationDate: opts["createdOn"] }),
|
|
990
|
-
}, writeOptionsFrom(opts)));
|
|
991
|
-
});
|
|
992
|
-
addWriteFlags(todo
|
|
993
|
-
.command("add-logged <title>")
|
|
994
|
-
.description("Create a to-do directly in the Logbook: completed, with the given past " +
|
|
995
|
-
"completion date (and optionally a past creation date). For importing history " +
|
|
996
|
-
"from another system.")
|
|
997
|
-
.requiredOption("--completed-on <date>", "YYYY-MM-DD — completion date (required)")
|
|
998
|
-
.option("--created-on <date>", "YYYY-MM-DD — creation date (must be <= completed-on)")
|
|
999
|
-
.option("--notes <text>", "notes body")).action(async (title, opts) => {
|
|
1000
|
-
await runWrite(opts, (c) => c.write.addLoggedTodo({
|
|
1001
|
-
title,
|
|
1002
|
-
completionDate: opts["completedOn"],
|
|
1003
|
-
...(opts["createdOn"] !== undefined && { creationDate: opts["createdOn"] }),
|
|
1004
|
-
...(opts["notes"] !== undefined && { notes: opts["notes"] }),
|
|
1005
|
-
}, writeOptionsFrom(opts)));
|
|
1006
|
-
});
|
|
1038
|
+
// NB: the bespoke `todo backdate` / `todo add-logged` commands were removed
|
|
1039
|
+
// (plan PR A). Backdated creation and Logbook import are now `todo add
|
|
1040
|
+
// --created-at/--completed-at`; rewriting an existing item's timestamps is
|
|
1041
|
+
// `todo update --created-at/--completed-at` (or complete/cancel --completed-at).
|
|
1007
1042
|
// --- ui vector: GUI-driven transforms (two-key gated) --------------------
|
|
1008
1043
|
const REPEAT_FREQ_HELP = "daily | weekly | monthly | yearly";
|
|
1009
1044
|
const REPEAT_INTERVAL_HELP = "every N units (1–99)";
|
|
@@ -1288,7 +1323,9 @@ export function registerWriteCommands(program) {
|
|
|
1288
1323
|
.option("--area <ref>", "destination area (uuid or unique name)")
|
|
1289
1324
|
.option("--when <value>", "today | evening | anytime | someday | YYYY-MM-DD")
|
|
1290
1325
|
.option("--deadline <date>", "YYYY-MM-DD")
|
|
1291
|
-
.option("--todo <title>", "initial child to-do, repeatable (seeds the new project)", collect, [])
|
|
1326
|
+
.option("--todo <title>", "initial child to-do, repeatable (seeds the new project)", collect, [])
|
|
1327
|
+
.option("--created-at <iso>", "born with this creation timestamp (ISO date or datetime; a date is noon in the effective zone)")
|
|
1328
|
+
.option("--completed-at <iso>", "born completed (in the Logbook) with this completion timestamp; cannot seed open child to-dos (§5b)")).action(async (title, opts) => {
|
|
1292
1329
|
const todos = opts["todo"];
|
|
1293
1330
|
const area = containerRef(opts["area"]);
|
|
1294
1331
|
await runWrite(opts, (c) => c.write.addProject({
|
|
@@ -1298,6 +1335,8 @@ export function registerWriteCommands(program) {
|
|
|
1298
1335
|
...(opts["when"] !== undefined && { when: opts["when"] }),
|
|
1299
1336
|
...(opts["deadline"] !== undefined && { deadline: opts["deadline"] }),
|
|
1300
1337
|
...(todos.length > 0 && { todos }),
|
|
1338
|
+
...(opts["createdAt"] !== undefined && { createdAt: opts["createdAt"] }),
|
|
1339
|
+
...(opts["completedAt"] !== undefined && { completedAt: opts["completedAt"] }),
|
|
1301
1340
|
}, writeOptionsFrom(opts)));
|
|
1302
1341
|
});
|
|
1303
1342
|
addWriteFlags(project
|
|
@@ -1316,6 +1355,8 @@ export function registerWriteCommands(program) {
|
|
|
1316
1355
|
.option("--clear-reminder", "clear the reminder (works while scheduled today|evening)")
|
|
1317
1356
|
.option("--deadline <date>", "YYYY-MM-DD")
|
|
1318
1357
|
.option("--clear-deadline", "remove the deadline")
|
|
1358
|
+
.option("--created-at <iso>", "rewrite the creation timestamp (ISO date or datetime; a date is noon in the effective zone); status-safe")
|
|
1359
|
+
.option("--completed-at <iso>", "rewrite the completion timestamp of an already-resolved project (a canceled one stays canceled); open projects are refused — use complete/cancel")
|
|
1319
1360
|
.action(async (uuid, opts) => {
|
|
1320
1361
|
const notesModes = ["notes", "appendNotes", "prependNotes"].filter((k) => opts[k] !== undefined);
|
|
1321
1362
|
if (notesModes.length > 1) {
|
|
@@ -1342,6 +1383,10 @@ export function registerWriteCommands(program) {
|
|
|
1342
1383
|
...(opts["clearReminder"] === true && { reminder: null }),
|
|
1343
1384
|
...(opts["deadline"] !== undefined && { deadline: opts["deadline"] }),
|
|
1344
1385
|
...(opts["clearDeadline"] === true && { deadline: null }),
|
|
1386
|
+
...(opts["createdAt"] !== undefined && { createdAt: opts["createdAt"] }),
|
|
1387
|
+
...(opts["completedAt"] !== undefined && {
|
|
1388
|
+
completedAt: opts["completedAt"],
|
|
1389
|
+
}),
|
|
1345
1390
|
}, writeOptionsFrom(opts)));
|
|
1346
1391
|
});
|
|
1347
1392
|
addCreateTagsFlag(addWriteFlags(project
|
|
@@ -1396,9 +1441,17 @@ export function registerWriteCommands(program) {
|
|
|
1396
1441
|
.command("cancel <ref>")
|
|
1397
1442
|
.description("Cancel a project (target by uuid or unique name). Canceling also cancels its open " +
|
|
1398
1443
|
"to-dos, so an explicit --children policy is required; already-completed children " +
|
|
1399
|
-
"are never altered."
|
|
1400
|
-
|
|
1401
|
-
|
|
1444
|
+
"are never altered. --completed-at sets the completion timestamp and keeps the project " +
|
|
1445
|
+
"canceled via the certified flip legs (multi-leg, disclosed); it is refused while the " +
|
|
1446
|
+
"project still has open children.")
|
|
1447
|
+
.requiredOption("--children <policy>", "require-resolved (error if open to-dos remain) | auto-cancel (cancel them too)")
|
|
1448
|
+
.option("--completed-at <iso>", "completion timestamp (ISO date or datetime; a date is noon in the effective zone)")).action(async (uuid, opts) => {
|
|
1449
|
+
await runWrite(opts, (c) => c.write.cancelProject(uuid, {
|
|
1450
|
+
children: opts.children,
|
|
1451
|
+
...(opts["completedAt"] !== undefined && {
|
|
1452
|
+
completedAt: opts["completedAt"],
|
|
1453
|
+
}),
|
|
1454
|
+
}, writeOptionsFrom(opts)));
|
|
1402
1455
|
});
|
|
1403
1456
|
addWriteFlags(project
|
|
1404
1457
|
.command("reopen <ref>")
|
|
@@ -1464,9 +1517,16 @@ export function registerWriteCommands(program) {
|
|
|
1464
1517
|
addWriteFlags(project
|
|
1465
1518
|
.command("complete <ref>")
|
|
1466
1519
|
.description("Complete a project (target by uuid or unique name). Completing also completes its " +
|
|
1467
|
-
"open to-dos, so an explicit --children policy is required."
|
|
1468
|
-
|
|
1469
|
-
|
|
1520
|
+
"open to-dos, so an explicit --children policy is required. --completed-at sets the " +
|
|
1521
|
+
"completion timestamp and backdates it (multi-leg, disclosed).")
|
|
1522
|
+
.requiredOption("--children <policy>", "require-resolved (error if open to-dos remain) | auto-complete (complete them too)")
|
|
1523
|
+
.option("--completed-at <iso>", "completion timestamp (ISO date or datetime; a date is noon in the effective zone)")).action(async (uuid, opts) => {
|
|
1524
|
+
await runWrite(opts, (c) => c.write.completeProject(uuid, {
|
|
1525
|
+
children: opts.children,
|
|
1526
|
+
...(opts["completedAt"] !== undefined && {
|
|
1527
|
+
completedAt: opts["completedAt"],
|
|
1528
|
+
}),
|
|
1529
|
+
}, writeOptionsFrom(opts)));
|
|
1470
1530
|
});
|
|
1471
1531
|
addWriteFlags(project
|
|
1472
1532
|
.command("delete <ref>")
|
|
@@ -1806,27 +1866,30 @@ export function registerWriteCommands(program) {
|
|
|
1806
1866
|
client?.close();
|
|
1807
1867
|
}
|
|
1808
1868
|
});
|
|
1809
|
-
|
|
1869
|
+
addReorderPositionFlags(addDriveGuiFlag(addWriteFlags(program
|
|
1810
1870
|
.command("reorder <refs...>")
|
|
1811
|
-
.description("
|
|
1812
|
-
"
|
|
1813
|
-
"
|
|
1814
|
-
"
|
|
1815
|
-
"
|
|
1816
|
-
"
|
|
1817
|
-
"
|
|
1818
|
-
"
|
|
1819
|
-
"
|
|
1820
|
-
"
|
|
1821
|
-
"
|
|
1822
|
-
"
|
|
1823
|
-
"
|
|
1824
|
-
"`
|
|
1825
|
-
.option("--in <target>", "
|
|
1826
|
-
"inbox,
|
|
1827
|
-
|
|
1871
|
+
.description("The ONE reorder verb — rearrange to-dos, projects, headings, OR sidebar areas IN " +
|
|
1872
|
+
"PLACE (REARRANGES, never changes membership; to change what an item belongs to use " +
|
|
1873
|
+
"`things todo move` / `things project move`). All operands must be ONE kind (only " +
|
|
1874
|
+
"to-dos and projects intermix, and only on the shared Today/Evening/day axes); a " +
|
|
1875
|
+
"mixed-kind set, a cross-container set, and a non-member anchor each fail closed with " +
|
|
1876
|
+
"one precise message. Argument order is the resulting order; unmentioned siblings " +
|
|
1877
|
+
"keep theirs. Bare (no position) assembles the named items as a block at the " +
|
|
1878
|
+
"EARLIEST one's current slot; --start/--end/--before/--after position the block. A " +
|
|
1879
|
+
"Today/Evening member also has an index slot in its container, so a set sharing BOTH " +
|
|
1880
|
+
"axes is ambiguous — pass --in to say which. HEADINGS: same-project heading " +
|
|
1881
|
+
"re-ranking runs the native heading-block wire; an archived heading is reorderable " +
|
|
1882
|
+
"but repositioning it brings it back to open (disclosed). AREAS: this drives the " +
|
|
1883
|
+
"local Things app (sidebar drag). `things area reorder` and `things project " +
|
|
1884
|
+
"move-heading` remain as kind-specific spellings.")
|
|
1885
|
+
.option("--in <target>", "to-dos/projects only — name the axis to reorder on: today | evening | anytime | " +
|
|
1886
|
+
"someday | inbox, a project/area/heading ref (uuid or unique title), upcoming (the " +
|
|
1887
|
+
"one future day the set shares), or a YYYY-MM-DD day-block. A stage-list or container " +
|
|
1888
|
+
"axis sorts one KIND at a time; only today | evening | upcoming | a day-block " +
|
|
1889
|
+
"intermix both kinds.")))).action(async (refs, opts) => {
|
|
1890
|
+
const position = reorderPosition(opts);
|
|
1828
1891
|
if (position === "conflict") {
|
|
1829
|
-
usageError(opts, "pass at most one of --
|
|
1892
|
+
usageError(opts, "pass at most one of --start / --end / --before / --after");
|
|
1830
1893
|
return;
|
|
1831
1894
|
}
|
|
1832
1895
|
const request = {
|
|
@@ -1834,7 +1897,7 @@ export function registerWriteCommands(program) {
|
|
|
1834
1897
|
...(position !== undefined && { position }),
|
|
1835
1898
|
...(opts["in"] !== undefined && { in: opts["in"] }),
|
|
1836
1899
|
};
|
|
1837
|
-
await runMoveCmd(opts, (c) => c.write.
|
|
1900
|
+
await runMoveCmd(opts, (c) => c.write.reorderAny(request, writeOptionsFrom(opts)));
|
|
1838
1901
|
});
|
|
1839
1902
|
program
|
|
1840
1903
|
.command("capabilities")
|
|
@@ -1903,7 +1966,7 @@ export function registerWriteCommands(program) {
|
|
|
1903
1966
|
.description("Persist a config key: profile | maxDisruption | actor | auditEnabled | " +
|
|
1904
1967
|
"accepted-fingerprint | certified-app-version | allow-experimental | bounce-enabled | " +
|
|
1905
1968
|
"bounce-max-items | ui-enabled | scope")
|
|
1906
|
-
.action((key, value) => {
|
|
1969
|
+
.action((key, value, opts) => {
|
|
1907
1970
|
const map = {
|
|
1908
1971
|
profile: "profile",
|
|
1909
1972
|
maxDisruption: "maxDisruption",
|
|
@@ -1931,6 +1994,14 @@ export function registerWriteCommands(program) {
|
|
|
1931
1994
|
target === "uiEnabled"
|
|
1932
1995
|
? value === "true"
|
|
1933
1996
|
: value;
|
|
1997
|
+
// Universal `--dry-run` (../dry-run.ts): `config set` writes local config
|
|
1998
|
+
// state (not the Things DB), so it honors the flag with an honest preview —
|
|
1999
|
+
// the key is still validated above, but nothing is persisted. Exit 0.
|
|
2000
|
+
if (opts.dryRun === true) {
|
|
2001
|
+
process.stdout.write(`DRY RUN would set ${key} = ${String(parsed)} (nothing written)\n`);
|
|
2002
|
+
process.exitCode = ExitCode.Ok;
|
|
2003
|
+
return;
|
|
2004
|
+
}
|
|
1934
2005
|
saveConfigKey(target, parsed);
|
|
1935
2006
|
process.stdout.write(`set ${key} = ${String(parsed)}\n`);
|
|
1936
2007
|
// A stored scope jails EVERY process on this host — including this
|