things-api 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +6 -3
  2. package/dist/cli/commands/area.d.ts +23 -0
  3. package/dist/cli/commands/area.js +164 -33
  4. package/dist/cli/commands/area.js.map +1 -1
  5. package/dist/cli/commands/project.d.ts +19 -0
  6. package/dist/cli/commands/project.js +142 -29
  7. package/dist/cli/commands/project.js.map +1 -1
  8. package/dist/cli/commands/reads.d.ts +10 -51
  9. package/dist/cli/commands/reads.js +454 -268
  10. package/dist/cli/commands/reads.js.map +1 -1
  11. package/dist/cli/commands/show.d.ts +9 -0
  12. package/dist/cli/commands/show.js +169 -0
  13. package/dist/cli/commands/show.js.map +1 -0
  14. package/dist/cli/commands/snapshot.js +1 -1
  15. package/dist/cli/commands/snapshot.js.map +1 -1
  16. package/dist/cli/commands/todo.d.ts +9 -0
  17. package/dist/cli/commands/todo.js +101 -16
  18. package/dist/cli/commands/todo.js.map +1 -1
  19. package/dist/cli/commands/writes.js +55 -1
  20. package/dist/cli/commands/writes.js.map +1 -1
  21. package/dist/cli/did-you-mean.d.ts +29 -0
  22. package/dist/cli/did-you-mean.js +53 -0
  23. package/dist/cli/did-you-mean.js.map +1 -0
  24. package/dist/cli/glyphs.d.ts +95 -0
  25. package/dist/cli/glyphs.js +282 -0
  26. package/dist/cli/glyphs.js.map +1 -0
  27. package/dist/cli/main.js +11 -1
  28. package/dist/cli/main.js.map +1 -1
  29. package/dist/cli/period.d.ts +32 -0
  30. package/dist/cli/period.js +129 -0
  31. package/dist/cli/period.js.map +1 -0
  32. package/dist/cli/read-driver.d.ts +76 -0
  33. package/dist/cli/read-driver.js +181 -0
  34. package/dist/cli/read-driver.js.map +1 -0
  35. package/dist/cli/render.d.ts +182 -0
  36. package/dist/cli/render.js +585 -0
  37. package/dist/cli/render.js.map +1 -0
  38. package/dist/cli/resolve-invocation.d.ts +78 -0
  39. package/dist/cli/resolve-invocation.js +178 -0
  40. package/dist/cli/resolve-invocation.js.map +1 -0
  41. package/dist/cli/shell-quote.d.ts +9 -0
  42. package/dist/cli/shell-quote.js +12 -0
  43. package/dist/cli/shell-quote.js.map +1 -0
  44. package/dist/cli/style.d.ts +5 -0
  45. package/dist/cli/style.js +5 -0
  46. package/dist/cli/style.js.map +1 -1
  47. package/dist/client.d.ts +45 -39
  48. package/dist/client.js +11 -74
  49. package/dist/client.js.map +1 -1
  50. package/dist/contracts.d.ts +66 -1
  51. package/dist/contracts.js +1 -1
  52. package/dist/contracts.js.map +1 -1
  53. package/dist/db/baselines/db-v26.js +7 -5
  54. package/dist/db/baselines/db-v26.js.map +1 -1
  55. package/dist/db/schema.d.ts +1 -1
  56. package/dist/db/schema.js +7 -1
  57. package/dist/db/schema.js.map +1 -1
  58. package/dist/mcp/server.js +227 -44
  59. package/dist/mcp/server.js.map +1 -1
  60. package/dist/model/entities.d.ts +21 -0
  61. package/dist/model/entities.js.map +1 -1
  62. package/dist/model/mappers.js +17 -1
  63. package/dist/model/mappers.js.map +1 -1
  64. package/dist/model/occurrences.d.ts +6 -1
  65. package/dist/model/occurrences.js +9 -2
  66. package/dist/model/occurrences.js.map +1 -1
  67. package/dist/model/recurrence.d.ts +30 -2
  68. package/dist/model/recurrence.js +20 -0
  69. package/dist/model/recurrence.js.map +1 -1
  70. package/dist/read/area-view.js +21 -5
  71. package/dist/read/area-view.js.map +1 -1
  72. package/dist/read/caps.d.ts +14 -0
  73. package/dist/read/caps.js +21 -0
  74. package/dist/read/caps.js.map +1 -0
  75. package/dist/read/detail.js +12 -2
  76. package/dist/read/detail.js.map +1 -1
  77. package/dist/read/log-boundary.d.ts +29 -0
  78. package/dist/read/log-boundary.js +38 -0
  79. package/dist/read/log-boundary.js.map +1 -0
  80. package/dist/read/pagination.d.ts +104 -0
  81. package/dist/read/pagination.js +208 -0
  82. package/dist/read/pagination.js.map +1 -0
  83. package/dist/read/predicates.d.ts +31 -0
  84. package/dist/read/predicates.js +48 -0
  85. package/dist/read/predicates.js.map +1 -0
  86. package/dist/read/project-view.js +28 -3
  87. package/dist/read/project-view.js.map +1 -1
  88. package/dist/read/queries.d.ts +21 -3
  89. package/dist/read/queries.js +35 -8
  90. package/dist/read/queries.js.map +1 -1
  91. package/dist/read/search-rank.d.ts +36 -0
  92. package/dist/read/search-rank.js +31 -0
  93. package/dist/read/search-rank.js.map +1 -0
  94. package/dist/read/show-target.d.ts +25 -0
  95. package/dist/read/show-target.js +41 -0
  96. package/dist/read/show-target.js.map +1 -0
  97. package/dist/read/sidebar-order.d.ts +19 -0
  98. package/dist/read/sidebar-order.js +92 -0
  99. package/dist/read/sidebar-order.js.map +1 -0
  100. package/dist/read/snapshot.js +2 -0
  101. package/dist/read/snapshot.js.map +1 -1
  102. package/dist/read/views.d.ts +64 -8
  103. package/dist/read/views.js +290 -155
  104. package/dist/read/views.js.map +1 -1
  105. package/dist/surface-copy.d.ts +23 -0
  106. package/dist/surface-copy.js +23 -0
  107. package/dist/surface-copy.js.map +1 -1
  108. package/dist/write/automation-probe.js +14 -6
  109. package/dist/write/automation-probe.js.map +1 -1
  110. package/dist/write/capabilities.d.ts +3 -0
  111. package/dist/write/capabilities.js +3 -0
  112. package/dist/write/capabilities.js.map +1 -1
  113. package/dist/write/checklist.d.ts +50 -0
  114. package/dist/write/checklist.js +61 -0
  115. package/dist/write/checklist.js.map +1 -0
  116. package/dist/write/clear-reminder.d.ts +3 -0
  117. package/dist/write/clear-reminder.js +205 -0
  118. package/dist/write/clear-reminder.js.map +1 -0
  119. package/dist/write/commands.js +122 -8
  120. package/dist/write/commands.js.map +1 -1
  121. package/dist/write/edit-checklist.d.ts +3 -0
  122. package/dist/write/edit-checklist.js +184 -0
  123. package/dist/write/edit-checklist.js.map +1 -0
  124. package/dist/write/failure-hints.d.ts +7 -0
  125. package/dist/write/failure-hints.js +25 -2
  126. package/dist/write/failure-hints.js.map +1 -1
  127. package/dist/write/guards.d.ts +1 -1
  128. package/dist/write/guards.js +16 -0
  129. package/dist/write/guards.js.map +1 -1
  130. package/dist/write/operations.d.ts +32 -1
  131. package/dist/write/operations.js +3 -0
  132. package/dist/write/operations.js.map +1 -1
  133. package/dist/write/pipeline.d.ts +3 -0
  134. package/dist/write/pipeline.js +23 -1
  135. package/dist/write/pipeline.js.map +1 -1
  136. package/dist/write/reversibility.d.ts +46 -0
  137. package/dist/write/reversibility.js +164 -0
  138. package/dist/write/reversibility.js.map +1 -0
  139. package/dist/write/undo.d.ts +29 -2
  140. package/dist/write/undo.js +357 -9
  141. package/dist/write/undo.js.map +1 -1
  142. package/dist/write/vectors/registry.js +2 -1
  143. package/dist/write/vectors/registry.js.map +1 -1
  144. package/dist/write/vectors/shortcuts.d.ts +9 -0
  145. package/dist/write/vectors/shortcuts.js +90 -0
  146. package/dist/write/vectors/shortcuts.js.map +1 -0
  147. package/dist/write/vectors/types.d.ts +11 -3
  148. package/dist/write/vectors/url-scheme.js +16 -0
  149. package/dist/write/vectors/url-scheme.js.map +1 -1
  150. package/dist/write/verify/delta.d.ts +1 -1
  151. package/dist/write/verify/delta.js +1 -1
  152. package/dist/write/verify/delta.js.map +1 -1
  153. package/package.json +1 -1
  154. package/shortcuts/things-proxy-find-items.shortcut +0 -0
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The single command router (docs/design/cli-grammar.md). Takes raw user argv
3
+ * (already stripped of the node/script prefix) and applies the precedence
4
+ * chain — registered command/alias → view keyword → reference — returning a
5
+ * normalized dispatch that `main.ts` feeds to commander. This replaces the
6
+ * former `expandShorthand` argv hack, the per-command keyword rewrites, and
7
+ * the hidden `--via-shorthand` marker.
8
+ *
9
+ * The resolver is argv-level and NEVER touches the database: it decides the
10
+ * command SHAPE. Reference resolution (uuid prefix → share link → tiered name
11
+ * match) happens later in `classifyShowTarget`, which needs the db. When a
12
+ * form's canonical command is only knowable after that resolution (bare noun,
13
+ * uuid/share-link routing), the `show`/`open` action fills `canonical` in via
14
+ * `setInvocationCanonical`; the view-keyword rewrite knows it immediately.
15
+ */
16
+ import type { Command } from "commander";
17
+ /**
18
+ * The type namespaces whose `show` verb takes a reference and may be omitted:
19
+ * `things area Hobbies` → `things area show Hobbies`. Restricted to the three
20
+ * TYPE groups — `config show` also exists but takes no reference, so `config`
21
+ * is deliberately excluded. Registered subcommands (verbs) always win over
22
+ * this sugar (the reserved-word rule).
23
+ */
24
+ export declare const IMPLIED_SHOW_NAMESPACES: Set<string>;
25
+ /**
26
+ * `show`'s keyword vocabulary: EVERY list-view command name. `things show <kw>`
27
+ * dispatches to the identical `things <kw>` command. Wider than the app's URL
28
+ * ids because `show` renders our own views — the plurals are real commands too.
29
+ */
30
+ export declare const SHOW_KEYWORDS: Set<string>;
31
+ /**
32
+ * `open`'s keyword vocabulary: ONLY the app's verified URL-scheme show ids.
33
+ * `open`'s vocabulary belongs to the app (it hands the id straight to
34
+ * `things:///show?id=<kw>`), so the plurals — which have no app list screen —
35
+ * are deliberately excluded and rejected with a tailored error.
36
+ */
37
+ export declare const OPEN_KEYWORDS: Set<string>;
38
+ export type InvocationForm =
39
+ /** A registered command/alias, or a flag-led/empty argv — nothing normalized. */
40
+ "canonical"
41
+ /** `things <subject>` — the verb `show` was omitted. */
42
+ | "bare-noun"
43
+ /** `things <type> <subject>` — the `show` verb inside a type namespace was omitted. */
44
+ | "namespace-show"
45
+ /** `things show <ref>` — explicit loose router by reference. */
46
+ | "loose-show"
47
+ /** `things open <ref>` — explicit loose router by reference. */
48
+ | "loose-open"
49
+ /** `things show <view-keyword>` — rewritten to the `<view-keyword>` command. */
50
+ | "show-keyword";
51
+ export interface ResolvedInvocation {
52
+ form: InvocationForm;
53
+ /** Normalized argv handed to commander (`from: "user"`). */
54
+ argv: string[];
55
+ /**
56
+ * The canonical runnable command string, once known. Set at resolve time for
57
+ * `show-keyword`; filled in by the `show` action after reference resolution
58
+ * for the ref-routing forms; stays null for canonical invocations (and for
59
+ * loose forms whose result is not a routing sugar worth echoing).
60
+ */
61
+ canonical: string | null;
62
+ /** The subject/reference token (for the action to build the typed canonical). */
63
+ ref: string | null;
64
+ }
65
+ /** The invocation the current process is running (null before `resolveInvocation`). */
66
+ export declare function getInvocation(): ResolvedInvocation | null;
67
+ /**
68
+ * Record the canonical command a ref-routing form resolved to, so the renderer
69
+ * can echo it and stamp `meta.resolvedCommand`. No-op when the form is not a
70
+ * routing sugar (canonical invocations echo nothing).
71
+ */
72
+ export declare function setInvocationCanonical(canonical: string): void;
73
+ /**
74
+ * Classify raw user argv into a normalized dispatch and record it as the
75
+ * current invocation. Idempotent per process; called once by `runCli` (and by
76
+ * the in-process test harnesses) before commander parses.
77
+ */
78
+ export declare function resolveInvocation(program: Command, args: string[]): ResolvedInvocation;
@@ -0,0 +1,178 @@
1
+ import { shellQuote } from "./shell-quote.js";
2
+ /**
3
+ * The type namespaces whose `show` verb takes a reference and may be omitted:
4
+ * `things area Hobbies` → `things area show Hobbies`. Restricted to the three
5
+ * TYPE groups — `config show` also exists but takes no reference, so `config`
6
+ * is deliberately excluded. Registered subcommands (verbs) always win over
7
+ * this sugar (the reserved-word rule).
8
+ */
9
+ export const IMPLIED_SHOW_NAMESPACES = new Set(["area", "project", "todo"]);
10
+ /**
11
+ * `show`'s keyword vocabulary: EVERY list-view command name. `things show <kw>`
12
+ * dispatches to the identical `things <kw>` command. Wider than the app's URL
13
+ * ids because `show` renders our own views — the plurals are real commands too.
14
+ */
15
+ export const SHOW_KEYWORDS = new Set([
16
+ "inbox",
17
+ "today",
18
+ "anytime",
19
+ "upcoming",
20
+ "someday",
21
+ "logbook",
22
+ "trash",
23
+ "projects",
24
+ "areas",
25
+ "tags",
26
+ ]);
27
+ /**
28
+ * `open`'s keyword vocabulary: ONLY the app's verified URL-scheme show ids.
29
+ * `open`'s vocabulary belongs to the app (it hands the id straight to
30
+ * `things:///show?id=<kw>`), so the plurals — which have no app list screen —
31
+ * are deliberately excluded and rejected with a tailored error.
32
+ */
33
+ export const OPEN_KEYWORDS = new Set([
34
+ "inbox",
35
+ "today",
36
+ "anytime",
37
+ "upcoming",
38
+ "someday",
39
+ "logbook",
40
+ "trash",
41
+ ]);
42
+ let current = null;
43
+ /** The invocation the current process is running (null before `resolveInvocation`). */
44
+ export function getInvocation() {
45
+ return current;
46
+ }
47
+ /**
48
+ * Record the canonical command a ref-routing form resolved to, so the renderer
49
+ * can echo it and stamp `meta.resolvedCommand`. No-op when the form is not a
50
+ * routing sugar (canonical invocations echo nothing).
51
+ */
52
+ export function setInvocationCanonical(canonical) {
53
+ if (current !== null)
54
+ current.canonical = canonical;
55
+ }
56
+ /**
57
+ * Classify raw user argv into a normalized dispatch and record it as the
58
+ * current invocation. Idempotent per process; called once by `runCli` (and by
59
+ * the in-process test harnesses) before commander parses.
60
+ */
61
+ export function resolveInvocation(program, args) {
62
+ current = classify(program, args);
63
+ return current;
64
+ }
65
+ /**
66
+ * Skip over LEADING GLOBAL-STYLE FLAGS to find the token being classified, so
67
+ * `things --json Hobbies` routes exactly like `things Hobbies --json`. Only
68
+ * the global read options are recognized here — `--json` (boolean) and `--db`
69
+ * (value-taking: its value is skipped too, never misread as the subject).
70
+ * Any other leading flag returns null — an unknown flag keeps the plain
71
+ * fall-through to commander (which reports it), rather than guessing whether
72
+ * the next token is that flag's value or the subject.
73
+ */
74
+ function indexPastLeadingFlags(args) {
75
+ let i = 0;
76
+ while (i < args.length) {
77
+ const tok = args[i] ?? "";
78
+ if (!tok.startsWith("-"))
79
+ return i;
80
+ if (tok === "--json") {
81
+ i += 1;
82
+ }
83
+ else if (tok === "--db") {
84
+ i += 2; // skip the flag AND its value
85
+ }
86
+ else if (tok.startsWith("--db=")) {
87
+ i += 1;
88
+ }
89
+ else {
90
+ return null; // unknown leading flag — commander's to handle
91
+ }
92
+ }
93
+ return i; // flags only, no subject (e.g. bare `things --json`)
94
+ }
95
+ /** The registered subcommand names + aliases of a command group (empty when the group is unknown). */
96
+ function subcommandsOf(program, groupName) {
97
+ const group = program.commands.find((c) => c.name() === groupName || c.aliases().includes(groupName));
98
+ const names = new Set();
99
+ if (group === undefined)
100
+ return names;
101
+ for (const sub of group.commands) {
102
+ names.add(sub.name());
103
+ for (const alias of sub.aliases())
104
+ names.add(alias);
105
+ }
106
+ return names;
107
+ }
108
+ function classify(program, args) {
109
+ const at = indexPastLeadingFlags(args);
110
+ const first = at === null ? undefined : args[at];
111
+ // An empty, flags-only, or unknown-flag-led argv is commander's to handle
112
+ // (help, --version, error).
113
+ if (first === undefined) {
114
+ return { form: "canonical", argv: args, canonical: null, ref: null };
115
+ }
116
+ const known = new Set(["help"]);
117
+ for (const c of program.commands) {
118
+ known.add(c.name());
119
+ for (const alias of c.aliases())
120
+ known.add(alias);
121
+ }
122
+ if (at !== 0) {
123
+ // A registered command reached THROUGH leading flags stays untouched:
124
+ // program-level flags before a command were an error before and stay one.
125
+ if (known.has(first)) {
126
+ return { form: "canonical", argv: args, canonical: null, ref: null };
127
+ }
128
+ // Precedence 3 through leading global flags: a bare-noun subject routes
129
+ // through `show` with the flags left in place — commander accepts options
130
+ // before arguments on the subcommand.
131
+ return { form: "bare-noun", argv: ["show", ...args], canonical: null, ref: first };
132
+ }
133
+ // Precedence 1: a registered command/alias always wins (names are reserved).
134
+ if (known.has(first)) {
135
+ if (first === "show") {
136
+ const second = args[1];
137
+ // Precedence 2 (show): a view keyword routes to that view command.
138
+ if (second !== undefined && SHOW_KEYWORDS.has(second.toLowerCase())) {
139
+ const kw = second.toLowerCase();
140
+ return {
141
+ form: "show-keyword",
142
+ argv: [kw, ...args.slice(2)],
143
+ canonical: `things ${kw}`,
144
+ ref: kw,
145
+ };
146
+ }
147
+ return { form: "loose-show", argv: args, canonical: null, ref: second ?? null };
148
+ }
149
+ if (first === "open") {
150
+ // Precedence 2 (open) is handled in the action: keyword launching and the
151
+ // plural-not-openable error both need the keyword sets, and open renders
152
+ // no card to anchor an echo to.
153
+ return { form: "loose-open", argv: args, canonical: null, ref: args[1] ?? null };
154
+ }
155
+ // Namespace implied-show: inside a TYPE group with a `show` verb, a first
156
+ // token that is not one of the group's registered subcommands is a subject
157
+ // with the verb omitted — `things area Hobbies` → `things area show
158
+ // Hobbies`. Registered verbs win (reserved-word rule); a flag or an absent
159
+ // token leaves the bare group command to commander (help / usage error).
160
+ if (at === 0 && IMPLIED_SHOW_NAMESPACES.has(first)) {
161
+ const second = args[1];
162
+ if (second !== undefined &&
163
+ !second.startsWith("-") &&
164
+ !subcommandsOf(program, first).has(second)) {
165
+ return {
166
+ form: "namespace-show",
167
+ argv: [first, "show", ...args.slice(1)],
168
+ canonical: `things ${first} show ${shellQuote(second)}`,
169
+ ref: second,
170
+ };
171
+ }
172
+ }
173
+ return { form: "canonical", argv: args, canonical: null, ref: null };
174
+ }
175
+ // Precedence 3: not a command — a bare-noun reference, routed through `show`.
176
+ return { form: "bare-noun", argv: ["show", ...args], canonical: null, ref: first };
177
+ }
178
+ //# sourceMappingURL=resolve-invocation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-invocation.js","sourceRoot":"","sources":["../../src/cli/resolve-invocation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shell-safe rendering of a single argument for a reconstructed `things …`
3
+ * command string (truncation footers, the normalized-form echo, the
4
+ * did-you-mean suggestion). A plain word is left bare; anything with spaces or
5
+ * shell metacharacters is double-quoted with the hazardous characters escaped.
6
+ * Lives in its own leaf module so both the read driver and the argv resolver
7
+ * can share ONE quoting rule (they must agree — the echo is contract-tested).
8
+ */
9
+ export declare function shellQuote(v: string): string;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Shell-safe rendering of a single argument for a reconstructed `things …`
3
+ * command string (truncation footers, the normalized-form echo, the
4
+ * did-you-mean suggestion). A plain word is left bare; anything with spaces or
5
+ * shell metacharacters is double-quoted with the hazardous characters escaped.
6
+ * Lives in its own leaf module so both the read driver and the argv resolver
7
+ * can share ONE quoting rule (they must agree — the echo is contract-tested).
8
+ */
9
+ export function shellQuote(v) {
10
+ return /^[\w./@:+-]+$/.test(v) ? v : `"${v.replace(/(["\\$`])/g, "\\$1")}"`;
11
+ }
12
+ //# sourceMappingURL=shell-quote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-quote.js","sourceRoot":"","sources":["../../src/cli/shell-quote.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,GAAG,CAAC;AAC9E,CAAC"}
@@ -1,8 +1,13 @@
1
1
  export declare const bold: (s: string) => string;
2
2
  export declare const dim: (s: string) => string;
3
3
  export declare const underline: (s: string) => string;
4
+ /** Strikethrough (SGR 9) — enhancement only; state must also live in a glyph. */
5
+ export declare const strike: (s: string) => string;
4
6
  export declare const red: (s: string) => string;
7
+ export declare const green: (s: string) => string;
5
8
  export declare const blue: (s: string) => string;
9
+ /** Bright-blue (SGR 94) — the palette's "light blue"; still theme-remapped. */
10
+ export declare const brightBlue: (s: string) => string;
6
11
  export declare const yellow: (s: string) => string;
7
12
  export declare const magenta: (s: string) => string;
8
13
  export declare const cyan: (s: string) => string;
package/dist/cli/style.js CHANGED
@@ -19,8 +19,13 @@ const wrap = (open, close) => (s) => ENABLED ? `\u001b[${open}m${s}\u001b[${clos
19
19
  export const bold = wrap(1, 22);
20
20
  export const dim = wrap(2, 22);
21
21
  export const underline = wrap(4, 24);
22
+ /** Strikethrough (SGR 9) — enhancement only; state must also live in a glyph. */
23
+ export const strike = wrap(9, 29);
22
24
  export const red = wrap(31, 39);
25
+ export const green = wrap(32, 39);
23
26
  export const blue = wrap(34, 39);
27
+ /** Bright-blue (SGR 94) — the palette's "light blue"; still theme-remapped. */
28
+ export const brightBlue = wrap(94, 39);
24
29
  export const yellow = wrap(33, 39);
25
30
  export const magenta = wrap(35, 39);
26
31
  export const cyan = wrap(36, 39);
@@ -1 +1 @@
1
- {"version":3,"file":"style.js","sourceRoot":"","sources":["../../src/cli/style.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,SAAS,YAAY;IACnB,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACxD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACzC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,KAAK,GAAG,CAAC;IAC9C,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC;AACvC,CAAC;AAED,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;AAE/B,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,EAAE,CAAC,CAAC,CAAS,EAAE,EAAE,CAC1D,OAAO,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAEtD,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC/B,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAChC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACnC,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"style.js","sourceRoot":"","sources":["../../src/cli/style.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,SAAS,YAAY;IACnB,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACxD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACzC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,KAAK,GAAG,CAAC;IAC9C,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC;AACvC,CAAC;AAED,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;AAE/B,MAAM,IAAI,GAAG,CAAC,IAAY,EAAE,KAAa,EAAE,EAAE,CAAC,CAAC,CAAS,EAAE,EAAE,CAC1D,OAAO,CAAC,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,UAAU,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAEtD,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAC/B,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACrC,iFAAiF;AACjF,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClC,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAChC,MAAM,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAClC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACjC,+EAA+E;AAC/E,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACvC,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACnC,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC"}
package/dist/client.d.ts CHANGED
@@ -9,12 +9,14 @@ import type { AnyTask, Area, Project, Tag } from "./model/entities.ts";
9
9
  import { type AreaView } from "./read/area-view.ts";
10
10
  import { type ProjectView } from "./read/project-view.ts";
11
11
  import { type Snapshot } from "./read/snapshot.ts";
12
- import { type ChangedItem, type ListItem, type SearchOptions, type SidebarSection, type SomedayFilter, type TodayView, type UpcomingFilter, type ViewFilter } from "./read/views.ts";
13
- import type { AreaAddParams, AreaUpdateParams, ChecklistItemSpec, ContainerRef, ProjectCancelParams, OperationKind, OperationParamsMap, ProjectAddParams, ProjectCompleteParams, ProjectUpdateParams, ReorderParams, TagAddParams, TagUpdateParams, HeadingArchiveParams, HeadingUnarchiveParams, TodoAddLoggedParams, TodoAddParams, TodoBackdateParams, TodoMoveParams, TodoUpdateParams } from "./write/operations.ts";
12
+ import { type ShowTarget } from "./read/show-target.ts";
13
+ import { type ChangedItem, type LiteSearchResult, type ListItem, type LogbookFilter, type SearchOptions, type SearchResultItem, type SidebarSection, type SomedayFilter, type TodayView, type UpcomingFilter, type ViewFilter } from "./read/views.ts";
14
+ import type { AreaAddParams, AreaUpdateParams, ContainerRef, ProjectCancelParams, OperationKind, OperationParamsMap, ProjectAddParams, ProjectCompleteParams, ProjectUpdateParams, ReorderParams, TagAddParams, TagUpdateParams, HeadingArchiveParams, HeadingUnarchiveParams, TodoAddLoggedParams, TodoAddParams, TodoBackdateParams, TodoMoveParams, TodoUpdateParams } from "./write/operations.ts";
14
15
  import { type MutationResult, type WriteOptions } from "./write/pipeline.ts";
15
16
  import { type BatchItemResult, type BatchOp, type BatchOptions } from "./write/batch.ts";
16
17
  import { type EnvironmentTracker } from "./write/environment.ts";
17
18
  import { type HeadingArchiveResult, type HeadingUnarchiveResult } from "./write/heading.ts";
19
+ import type { ChecklistEdit } from "./write/checklist.ts";
18
20
  import { type ReorderResult } from "./write/reorder.ts";
19
21
  import { type UndoItemResult, type UndoOptions } from "./write/undo.ts";
20
22
  import { type ProjectReopenOptions, type ProjectReopenResult } from "./write/reopen.ts";
@@ -48,16 +50,18 @@ export interface ThingsClient {
48
50
  anytime(filter?: ViewFilter): SidebarSection[];
49
51
  upcoming(filter?: UpcomingFilter): ListItem[];
50
52
  someday(filter?: SomedayFilter): SidebarSection[];
51
- logbook(options?: {
52
- limit?: number;
53
- tag?: string;
54
- exactTag?: boolean;
55
- }): ListItem[];
53
+ logbook(options?: LogbookFilter): ListItem[];
56
54
  trash(options?: {
57
- limit?: number;
55
+ limit?: number | null;
58
56
  }): ListItem[];
57
+ /**
58
+ * Projects in sidebar order. LATER (someday + future-scheduled) projects
59
+ * are excluded by default — `later: true` appends them after the active
60
+ * block of their group (loose block / area), never intermingled.
61
+ */
59
62
  projects(options?: {
60
63
  areaUuid?: string;
64
+ later?: boolean;
61
65
  }): Project[];
62
66
  /** Composite project view. Targets by uuid, unique name, or uuid prefix. */
63
67
  projectView(ref: string): ProjectView;
@@ -65,13 +69,28 @@ export interface ThingsClient {
65
69
  areaView(ref: string): AreaView;
66
70
  areas(): Area[];
67
71
  tags(): Tag[];
68
- search(query: string, options?: SearchOptions): ListItem[];
72
+ search(query: string, options?: SearchOptions): SearchResultItem[];
73
+ /**
74
+ * Did-you-mean fallback: case-insensitive title-only substring match over
75
+ * areas/projects/to-dos (open + untrashed), ordered and capped. `type`
76
+ * scopes to one class.
77
+ */
78
+ liteTitleSearch(query: string, options?: {
79
+ type?: "to-do" | "project" | "area";
80
+ limit?: number;
81
+ }): LiteSearchResult;
69
82
  /** Rows created/modified since a moment — incl. trashed/logged/templates. */
70
83
  changes(options: {
71
84
  since: Date;
72
- limit?: number;
85
+ limit?: number | null;
73
86
  }): ChangedItem[];
74
87
  byUuid(uuid: string): AnyTask | null;
88
+ /**
89
+ * Classify a loose reference (uuid, >=6-char prefix, share link, or
90
+ * area name) into the resource class that has a show view. Headings
91
+ * resolve to their containing project (viaHeading: true).
92
+ */
93
+ showTarget(ref: string): ShowTarget;
75
94
  snapshot(): Snapshot;
76
95
  };
77
96
  write: {
@@ -93,6 +112,14 @@ export interface ThingsClient {
93
112
  duplicateTodo(uuid: string, options?: WriteOptions): Promise<MutationResult>;
94
113
  /** Restore a TRASHED to-do: it returns to the Inbox, de-scheduled. */
95
114
  restoreTodo(uuid: string, options?: WriteOptions): Promise<MutationResult>;
115
+ /**
116
+ * Clear a to-do's time-of-day reminder while keeping its scheduled date.
117
+ * Uses the Things proxy shortcuts when installed (in place, and the only
118
+ * path for repeating to-dos); without them, a non-repeating dated to-do
119
+ * falls back to a URL re-schedule that briefly moves it to Today and back.
120
+ * Reversible with `undo`. Force a path with `vector: "shortcuts" | "url-scheme"`.
121
+ */
122
+ clearReminder(uuid: string, options?: WriteOptions): Promise<MutationResult>;
96
123
  /**
97
124
  * Rewrite a to-do's completion and/or creation timestamp to noon (local)
98
125
  * on the given date. Completion requires the to-do to be completed or
@@ -104,6 +131,12 @@ export interface ThingsClient {
104
131
  * completion (and optionally creation) timestamps.
105
132
  */
106
133
  addLoggedTodo(params: TodoAddLoggedParams, options?: WriteOptions): Promise<MutationResult>;
134
+ /**
135
+ * Create a heading inside an EXISTING project; the new heading's uuid is
136
+ * on the result. Delivered through the Things proxy shortcuts (run
137
+ * `things setup shortcuts` once first).
138
+ */
139
+ createHeading(project: ContainerRef, title: string, options?: WriteOptions): Promise<MutationResult>;
107
140
  /** Rename a heading in place (works on archived headings too). */
108
141
  renameHeading(uuid: string, title: string, options?: WriteOptions): Promise<MutationResult>;
109
142
  /**
@@ -173,33 +206,6 @@ export interface ThingsClient {
173
206
  };
174
207
  close(): void;
175
208
  }
176
- /** One granular checklist edit; every other item's checked state is preserved. */
177
- /**
178
- * Target for an existing checklist item: by `item` (title) or `index`
179
- * (1-based). Provide exactly one. Title matching is best-effort on duplicates
180
- * (docs/design/reference-resolution.md); index is exact.
181
- */
182
- export interface ChecklistTarget {
183
- item?: string;
184
- /** 1-based position; overrides `item` when both are given. */
185
- index?: number;
186
- }
187
- export type ChecklistEdit = {
188
- action: "add";
189
- title: string; /** 1-based insert position (default: append). */
190
- at?: number;
191
- } | ({
192
- action: "remove";
193
- } & ChecklistTarget) | ({
194
- action: "check";
195
- } & ChecklistTarget) | ({
196
- action: "uncheck";
197
- } & ChecklistTarget) | ({
198
- action: "rename";
199
- title: string;
200
- } & ChecklistTarget) | ({
201
- action: "move"; /** 1-based target position. */
202
- to: number;
203
- } & ChecklistTarget);
204
- export declare function applyChecklistEdit(items: ChecklistItemSpec[], edit: ChecklistEdit): ChecklistItemSpec[];
209
+ export type { ChecklistEdit, ChecklistTarget, ChecklistItemAction } from "./write/checklist.ts";
210
+ export { applyChecklistEdit } from "./write/checklist.ts";
205
211
  export declare function openThings(options?: OpenOptions): ThingsClient;
package/dist/client.js CHANGED
@@ -11,76 +11,20 @@ import { resolveProjectUuid, resolveTaskUuidPrefix } from "./read/queries.js";
11
11
  import { areaView } from "./read/area-view.js";
12
12
  import { projectView } from "./read/project-view.js";
13
13
  import { snapshotView } from "./read/snapshot.js";
14
+ import { classifyShowTarget } from "./read/show-target.js";
14
15
  import { areasView, tagsView } from "./read/tags.js";
15
- import { anytimeView, changesView, inboxView, logbookView, projectsView, searchView, somedayView, todayView, trashView, upcomingView, } from "./read/views.js";
16
+ import { anytimeView, changesView, inboxView, liteTitleSearch, logbookView, projectsView, searchView, somedayView, todayView, trashView, upcomingView, } from "./read/views.js";
16
17
  import { readAuthToken, runMutation, } from "./write/pipeline.js";
17
18
  import { runBatch } from "./write/batch.js";
18
19
  import { createEnvironmentTracker } from "./write/environment.js";
19
20
  import { runHeadingArchive, runHeadingUnarchive, } from "./write/heading.js";
21
+ import { runClearReminder } from "./write/clear-reminder.js";
22
+ import { runEditChecklist } from "./write/edit-checklist.js";
20
23
  import { runReorder } from "./write/reorder.js";
21
24
  import { runUndo } from "./write/undo.js";
22
25
  import { runProjectReopen, } from "./write/reopen.js";
23
26
  import { defaultVectors } from "./write/vectors/registry.js";
24
- /**
25
- * Resolve a checklist target to an array index. `index` (1-based) is exact.
26
- * A title resolves best-effort: unique → that item; duplicates → the first on
27
- * which the action is meaningful (check → first unchecked, uncheck → first
28
- * checked, others → first match). Loud only when nothing matches / index is
29
- * out of range.
30
- */
31
- function checklistTarget(items, edit) {
32
- if (edit.index !== undefined) {
33
- const i = edit.index - 1;
34
- if (i < 0 || i >= items.length) {
35
- throw new RangeError(`checklist index ${edit.index} is out of range (1..${items.length})`);
36
- }
37
- return i;
38
- }
39
- const ref = edit.item;
40
- if (ref === undefined)
41
- throw new RangeError("give a checklist item title or 1-based index");
42
- const matches = items.map((c, i) => ({ c, i })).filter(({ c }) => c.title === ref);
43
- if (matches.length === 0)
44
- throw new RangeError(`no checklist item titled "${ref}"`);
45
- if (matches.length === 1)
46
- return matches[0].i;
47
- const meaningful = edit.action === "check"
48
- ? matches.find(({ c }) => !c.completed)
49
- : edit.action === "uncheck"
50
- ? matches.find(({ c }) => c.completed)
51
- : undefined;
52
- return (meaningful ?? matches[0] ?? { i: 0 }).i;
53
- }
54
- export function applyChecklistEdit(items, edit) {
55
- const next = items.map((c) => ({ ...c }));
56
- switch (edit.action) {
57
- case "add": {
58
- const at = edit.at === undefined ? next.length : Math.max(0, Math.min(next.length, edit.at - 1));
59
- next.splice(at, 0, { title: edit.title, completed: false });
60
- return next;
61
- }
62
- case "remove":
63
- next.splice(checklistTarget(next, edit), 1);
64
- return next;
65
- case "check":
66
- case "uncheck": {
67
- const target = next[checklistTarget(next, edit)];
68
- target.completed = edit.action === "check";
69
- return next;
70
- }
71
- case "rename": {
72
- const target = next[checklistTarget(next, edit)];
73
- target.title = edit.title;
74
- return next;
75
- }
76
- case "move": {
77
- const from = checklistTarget(next, edit);
78
- const [moved] = next.splice(from, 1);
79
- next.splice(Math.max(0, Math.min(next.length, edit.to - 1)), 0, moved);
80
- return next;
81
- }
82
- }
83
- }
27
+ export { applyChecklistEdit } from "./write/checklist.js";
84
28
  export function openThings(options = {}) {
85
29
  const located = locateThingsDb(options.dbPath ? { dbPath: options.dbPath } : undefined);
86
30
  const conn = openConnection(located.path);
@@ -135,12 +79,14 @@ export function openThings(options = {}) {
135
79
  logbook: (o) => logbookView(conn.db, o),
136
80
  trash: (o) => trashView(conn.db, o),
137
81
  projects: (o) => projectsView(conn.db, o),
138
- projectView: (ref) => projectView(conn.db, resolveProjectUuid(conn.db, ref), now()),
82
+ projectView: (ref) => projectView(conn.db, resolveProjectUuid(conn.db, ref, { trashed: true }), now()),
139
83
  areaView: (ref) => areaView(conn.db, ref, now()),
140
84
  areas: () => areasView(conn.db),
141
85
  tags: () => tagsView(conn.db),
142
86
  search: (query, o) => searchView(conn.db, query, o),
87
+ liteTitleSearch: (query, o) => liteTitleSearch(conn.db, query, o),
143
88
  changes: (o) => changesView(conn.db, o),
89
+ showTarget: (ref) => classifyShowTarget(conn.db, ref),
144
90
  byUuid: (uuid) => {
145
91
  // Prefix-friendly: unknown refs keep the null contract; ambiguity throws.
146
92
  try {
@@ -175,22 +121,13 @@ export function openThings(options = {}) {
175
121
  restoreTodo: (uuid, o) => run("todo.restore", { uuid }, o),
176
122
  backdateTodo: (uuid, dates, o) => run("todo.backdate", { uuid, ...dates }, o),
177
123
  addLoggedTodo: (params, o) => run("todo.add-logged", params, o),
124
+ createHeading: (project, title, o) => run("heading.create", { project, title }, o),
178
125
  renameHeading: (uuid, title, o) => run("heading.rename", { uuid, title }, o),
126
+ clearReminder: (uuid, o) => runClearReminder(writeDeps, { uuid }, o ?? {}),
179
127
  archiveHeading: (uuid, policy, o) => runHeadingArchive(writeDeps, { uuid, ...policy }, o ?? {}),
180
128
  unarchiveHeading: (uuid, policy, o) => runHeadingUnarchive(writeDeps, { uuid, ...policy }, o ?? {}),
181
129
  detachTodo: (uuid, o) => run("todo.move", { uuid, detach: true }, o),
182
- editChecklist(uuid, edit, o) {
183
- const current = byUuid(conn.db, uuid);
184
- if (current === null || current.type !== "to-do") {
185
- throw new RangeError(`no to-do with uuid ${uuid}`);
186
- }
187
- const items = (current.checklist ?? []).map((c) => ({
188
- title: c.title,
189
- completed: c.status === "completed",
190
- }));
191
- const next = applyChecklistEdit(items, edit);
192
- return run("todo.replace-checklist", { uuid, items: next }, { ...o, acknowledgeChecklistReset: true });
193
- },
130
+ editChecklist: (uuid, edit, o) => runEditChecklist(writeDeps, uuid, edit, o ?? {}),
194
131
  addProject: (params, o) => run("project.add", params, o),
195
132
  updateProject: (uuid, patch, o) => run("project.update", { uuid, ...patch }, o),
196
133
  completeProject: (uuid, policy, o) => run("project.complete", { uuid, children: policy.children }, o),