things-api 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -5
- package/dist/audit/schema.d.ts +7 -0
- package/dist/audit/schema.js.map +1 -1
- package/dist/cli/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 +18 -11
- package/dist/cli/commands/area.js +81 -77
- package/dist/cli/commands/area.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +1 -2
- package/dist/cli/commands/doctor.js +11 -1
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/install-skill.d.ts +19 -4
- package/dist/cli/commands/install-skill.js +130 -52
- package/dist/cli/commands/install-skill.js.map +1 -1
- package/dist/cli/commands/mcp.js +21 -1
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/project.d.ts +1 -0
- package/dist/cli/commands/project.js +92 -48
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/reads.d.ts +5 -1
- package/dist/cli/commands/reads.js +110 -31
- 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 +75 -36
- 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 +795 -144
- package/dist/cli/commands/writes.js.map +1 -1
- package/dist/cli/did-you-mean.d.ts +14 -3
- package/dist/cli/did-you-mean.js +44 -7
- 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 +16 -2
- package/dist/cli/glyphs.js +60 -12
- package/dist/cli/glyphs.js.map +1 -1
- package/dist/cli/help.js +69 -13
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +8 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/move-hint.d.ts +3 -2
- package/dist/cli/move-hint.js +2 -2
- package/dist/cli/move-hint.js.map +1 -1
- package/dist/cli/read-driver.d.ts +53 -5
- package/dist/cli/read-driver.js +82 -15
- 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 +40 -14
- package/dist/cli/render.js +128 -55
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/resolve-invocation.d.ts +7 -5
- package/dist/cli/resolve-invocation.js +16 -7
- package/dist/cli/resolve-invocation.js.map +1 -1
- package/dist/cli/skill-check.d.ts +12 -6
- package/dist/cli/skill-check.js +31 -14
- package/dist/cli/skill-check.js.map +1 -1
- package/dist/cli/skill.d.ts +8 -0
- package/dist/cli/skill.js +10 -0
- package/dist/cli/skill.js.map +1 -1
- package/dist/cli/verb-hint.js +1 -1
- package/dist/cli/verb-hint.js.map +1 -1
- package/dist/client.d.ts +158 -26
- package/dist/client.js +254 -38
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +66 -2
- package/dist/config.js +120 -12
- package/dist/config.js.map +1 -1
- package/dist/contracts.d.ts +187 -28
- package/dist/contracts.js +22 -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/diagnose.d.ts +34 -2
- package/dist/diagnose.js +36 -1
- package/dist/diagnose.js.map +1 -1
- package/dist/index.d.ts +21 -8
- package/dist/index.js +26 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.js +790 -322
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/entities.d.ts +57 -4
- package/dist/model/entities.js.map +1 -1
- package/dist/model/mappers.d.ts +2 -0
- package/dist/model/mappers.js +44 -2
- package/dist/model/mappers.js.map +1 -1
- package/dist/model/recurrence.d.ts +8 -1
- package/dist/model/recurrence.js.map +1 -1
- package/dist/model/serialize.js +15 -3
- package/dist/model/serialize.js.map +1 -1
- package/dist/read/area-filter.d.ts +76 -0
- package/dist/read/area-filter.js +58 -0
- package/dist/read/area-filter.js.map +1 -0
- package/dist/read/area-view.d.ts +22 -11
- package/dist/read/area-view.js +54 -28
- package/dist/read/area-view.js.map +1 -1
- package/dist/read/detail.js +15 -8
- package/dist/read/detail.js.map +1 -1
- package/dist/read/predicates.d.ts +18 -0
- package/dist/read/predicates.js +19 -0
- package/dist/read/predicates.js.map +1 -1
- package/dist/read/project-view.d.ts +91 -15
- package/dist/read/project-view.js +135 -37
- package/dist/read/project-view.js.map +1 -1
- package/dist/read/pseudo-area.d.ts +29 -0
- package/dist/read/pseudo-area.js +27 -0
- package/dist/read/pseudo-area.js.map +1 -0
- package/dist/read/queries.d.ts +175 -19
- package/dist/read/queries.js +376 -32
- package/dist/read/queries.js.map +1 -1
- package/dist/read/scope.d.ts +126 -0
- package/dist/read/scope.js +161 -0
- package/dist/read/scope.js.map +1 -0
- package/dist/read/search-rank.d.ts +2 -5
- package/dist/read/shape.d.ts +181 -0
- package/dist/read/shape.js +737 -0
- package/dist/read/shape.js.map +1 -0
- package/dist/read/show-target.d.ts +9 -1
- package/dist/read/show-target.js +77 -17
- package/dist/read/show-target.js.map +1 -1
- package/dist/read/stage.d.ts +199 -0
- package/dist/read/stage.js +125 -0
- package/dist/read/stage.js.map +1 -0
- package/dist/read/truncation.d.ts +7 -12
- package/dist/read/truncation.js +56 -21
- package/dist/read/truncation.js.map +1 -1
- package/dist/read/views.d.ts +68 -16
- package/dist/read/views.js +206 -52
- package/dist/read/views.js.map +1 -1
- package/dist/surface-copy.d.ts +16 -0
- package/dist/surface-copy.js +16 -0
- package/dist/surface-copy.js.map +1 -1
- package/dist/write/batch.d.ts +49 -10
- package/dist/write/batch.js +423 -71
- package/dist/write/batch.js.map +1 -1
- package/dist/write/commands.js +268 -55
- package/dist/write/commands.js.map +1 -1
- package/dist/write/guards.d.ts +1 -1
- package/dist/write/guards.js +71 -10
- package/dist/write/guards.js.map +1 -1
- package/dist/write/heading.d.ts +10 -1
- package/dist/write/heading.js +35 -5
- package/dist/write/heading.js.map +1 -1
- package/dist/write/make-repeating-project.d.ts +2 -2
- package/dist/write/make-repeating-project.js +9 -9
- package/dist/write/make-repeating-project.js.map +1 -1
- package/dist/write/move.d.ts +134 -0
- package/dist/write/move.js +1874 -0
- package/dist/write/move.js.map +1 -0
- package/dist/write/operations.d.ts +105 -19
- package/dist/write/operations.js +56 -7
- package/dist/write/operations.js.map +1 -1
- package/dist/write/opid.d.ts +31 -0
- package/dist/write/opid.js +30 -0
- package/dist/write/opid.js.map +1 -0
- package/dist/write/pipeline.d.ts +70 -3
- package/dist/write/pipeline.js +198 -33
- package/dist/write/pipeline.js.map +1 -1
- package/dist/write/pre-state.d.ts +172 -8
- package/dist/write/pre-state.js +467 -25
- package/dist/write/pre-state.js.map +1 -1
- package/dist/write/reorder.d.ts +23 -3
- package/dist/write/reorder.js +2106 -86
- package/dist/write/reorder.js.map +1 -1
- package/dist/write/reversibility.js +19 -7
- package/dist/write/reversibility.js.map +1 -1
- package/dist/write/scope-guard.d.ts +31 -0
- package/dist/write/scope-guard.js +162 -0
- package/dist/write/scope-guard.js.map +1 -0
- package/dist/write/undo.js +120 -13
- package/dist/write/undo.js.map +1 -1
- package/dist/write/vectors/applescript.js +16 -7
- package/dist/write/vectors/applescript.js.map +1 -1
- package/dist/write/vectors/shortcuts.js +1 -1
- package/dist/write/vectors/shortcuts.js.map +1 -1
- package/dist/write/vectors/simulator.js +83 -27
- package/dist/write/vectors/simulator.js.map +1 -1
- package/dist/write/vectors/types.d.ts +11 -0
- package/dist/write/vectors/ui-certification.d.ts +3 -3
- package/dist/write/vectors/ui-certification.js +41 -5
- package/dist/write/vectors/ui-certification.js.map +1 -1
- package/dist/write/vectors/ui-drag.d.ts +21 -1
- package/dist/write/vectors/ui-drag.js +138 -27
- package/dist/write/vectors/ui-drag.js.map +1 -1
- package/dist/write/vectors/ui-recipes.d.ts +21 -1
- package/dist/write/vectors/ui-recipes.js +166 -7
- package/dist/write/vectors/ui-recipes.js.map +1 -1
- package/dist/write/vectors/ui.d.ts +25 -1
- package/dist/write/vectors/ui.js +142 -33
- package/dist/write/vectors/ui.js.map +1 -1
- package/dist/write/verify/delta.d.ts +17 -1
- package/dist/write/verify/delta.js +106 -29
- package/dist/write/verify/delta.js.map +1 -1
- package/package.json +7 -1
- package/schema/envelope.schema.json +397 -0
- package/skills/things-cli/SKILL.md +36 -17
- package/skills/things-cli/references/banner.md +35 -0
- package/skills/things-cli/references/contracts.md +32 -9
- package/skills/things-cli/references/errors.md +57 -0
- package/skills/things-cli/references/gui.md +1 -1
- package/skills/things-cli/references/model.md +18 -7
- package/skills/things-cli/references/ordering.md +88 -0
package/dist/cli/read-driver.js
CHANGED
|
@@ -8,8 +8,46 @@
|
|
|
8
8
|
import { getInvocation } from "./resolve-invocation.js";
|
|
9
9
|
import { dim } from "./style.js";
|
|
10
10
|
import { viewHeaderLines } from "./render.js";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { setRenderRefPromoter } from "./ref-render.js";
|
|
12
|
+
import { candidatesJson, DidYouMeanError, didYouMeanMessage, renderDidYouMean, } from "./did-you-mean.js";
|
|
13
|
+
import { ClockError, DEFAULT_LIST_LIMIT, errorEnvelope, ExitCode, okEnvelope, omitEmpty, openThings, shapeReadPayload, ReferenceResolutionError, schemaWarnings, ThingsDbNotFoundError, ThingsDbOpenError, } from "../index.js";
|
|
14
|
+
/**
|
|
15
|
+
* Kinds whose read payload is a flat list; their envelope `data` is the R1
|
|
16
|
+
* `{ items: [...] }` wrapper (data is ALWAYS a JSON object, never a bare array).
|
|
17
|
+
*/
|
|
18
|
+
const ITEMS_WRAPPER_KINDS = new Set([
|
|
19
|
+
"inbox",
|
|
20
|
+
"today",
|
|
21
|
+
"upcoming",
|
|
22
|
+
"logbook",
|
|
23
|
+
"trash",
|
|
24
|
+
"changes",
|
|
25
|
+
"search",
|
|
26
|
+
"projects",
|
|
27
|
+
"areas",
|
|
28
|
+
"tags",
|
|
29
|
+
]);
|
|
30
|
+
/**
|
|
31
|
+
* Shape a read payload into its envelope `data` object (the 1.0 contract, R1/R2):
|
|
32
|
+
* `data` is always an object. Flat lists (incl. `today`, one flat `items[]` of
|
|
33
|
+
* Today members) become `{ items }`; the sectioned catalogues (anytime/someday)
|
|
34
|
+
* become `{ sections }`; the composite cards become `{ view }`; a single-entity
|
|
35
|
+
* detail becomes `{ item }`. Everything already object-shaped (open/snapshot/…)
|
|
36
|
+
* passes through. The human-render path keeps the raw inner payload — this
|
|
37
|
+
* transform is the JSON emit boundary only. `today`'s whole-view `counts`
|
|
38
|
+
* aggregate rides `meta.counts`, not `data` (runRead), so `data` stays pure rows.
|
|
39
|
+
*/
|
|
40
|
+
export function wrapEnvelopeData(kind, data) {
|
|
41
|
+
if (ITEMS_WRAPPER_KINDS.has(kind))
|
|
42
|
+
return { items: data };
|
|
43
|
+
if (kind === "anytime" || kind === "someday")
|
|
44
|
+
return { sections: data };
|
|
45
|
+
if (kind === "area-view" || kind === "project-view")
|
|
46
|
+
return { view: data };
|
|
47
|
+
if (kind === "detail")
|
|
48
|
+
return { item: data };
|
|
49
|
+
return data;
|
|
50
|
+
}
|
|
13
51
|
/**
|
|
14
52
|
* The single usage-error emitter every command surface routes flag/argument
|
|
15
53
|
* errors through, so `--json` is honored uniformly: under `--json` a
|
|
@@ -21,7 +59,7 @@ import { ClockError, DEFAULT_LIST_LIMIT, errorEnvelope, ExitCode, okEnvelope, om
|
|
|
21
59
|
export function usageError(opts, message, details) {
|
|
22
60
|
if (opts.json === true) {
|
|
23
61
|
const meta = { dbVersion: null, fingerprint: "unknown", elapsedMs: 0 };
|
|
24
|
-
process.stdout.write(`${JSON.stringify(errorEnvelope({ code: "usage", message, ...(details !== undefined && { details }) }, meta))}\n`);
|
|
62
|
+
process.stdout.write(`${JSON.stringify(errorEnvelope({ code: "usage", message, ...(details !== undefined && { detail: details }) }, meta))}\n`);
|
|
25
63
|
}
|
|
26
64
|
else {
|
|
27
65
|
process.stderr.write(`error: ${message}\n`);
|
|
@@ -47,11 +85,20 @@ export function runRead(opts, kind, fn, render, hintBase, header) {
|
|
|
47
85
|
let client = null;
|
|
48
86
|
try {
|
|
49
87
|
client = openThings(opts.db ? { dbPath: opts.db } : {});
|
|
88
|
+
// Arm the render-time ref promoter so human list rows can promote an inline
|
|
89
|
+
// container hint's uuid prefix (TTY only — the JSON path never calls the
|
|
90
|
+
// renderers). Grouped views render inside `fn`, so this must precede it;
|
|
91
|
+
// cleared in `finally`. The `--json` envelope shapes its own refs separately.
|
|
92
|
+
if (!opts.json)
|
|
93
|
+
setRenderRefPromoter(client.refPromoter());
|
|
50
94
|
const fp = client.fingerprint();
|
|
51
95
|
// Reads never block on a schema change — they warn (design decision). The
|
|
52
96
|
// note reuses the same cached fingerprint the write path gates on.
|
|
53
|
-
const warnings =
|
|
54
|
-
|
|
97
|
+
const { data, truncation, kind: kindOverride, filter, counts, warnings: readWarnings, lines: precomputed, } = fn(client);
|
|
98
|
+
// Schema-drift advisories plus any read-specific advisories (e.g. the loose
|
|
99
|
+
// pseudo-area resolution-shadow disclosure).
|
|
100
|
+
const warnings = [...schemaWarnings(client.schemaStatus()), ...(readWarnings ?? [])];
|
|
101
|
+
const effectiveKind = kindOverride ?? kind;
|
|
55
102
|
// The canonical command a sugar invocation normalized to — known now that
|
|
56
103
|
// `fn` has resolved any reference. Present only for the routing sugars
|
|
57
104
|
// (bare noun, keyword-in-show, uuid/share-link routing); null otherwise.
|
|
@@ -59,15 +106,20 @@ export function runRead(opts, kind, fn, render, hintBase, header) {
|
|
|
59
106
|
// The clock honesty field: present only when a consumer zone / pinned now
|
|
60
107
|
// is in effect (absent = host clock, so the wire shape is unchanged).
|
|
61
108
|
const clock = client.clockMeta();
|
|
109
|
+
// The active container scope (additive): present only when the client is
|
|
110
|
+
// jailed, so an agent knows its own jail (not an oracle for what's outside).
|
|
111
|
+
const scope = client.scope;
|
|
62
112
|
const meta = {
|
|
63
113
|
dbVersion: fp.observation.databaseVersion,
|
|
64
114
|
fingerprint: fp.kind === "ok" ? "ok" : fp.kind === "drift" ? "drift" : "unknown",
|
|
65
115
|
elapsedMs: Date.now() - started,
|
|
66
116
|
...(truncation !== undefined && { truncation }),
|
|
67
|
-
...(grouped !== undefined && { grouped }),
|
|
68
117
|
...(resolvedCommand !== null && { resolvedCommand }),
|
|
69
118
|
...(warnings.length > 0 && { warnings }),
|
|
70
119
|
...(clock !== undefined && { clock }),
|
|
120
|
+
...(filter !== undefined && { filter }),
|
|
121
|
+
...(counts !== undefined && { counts }),
|
|
122
|
+
...(scope !== undefined && { scope }),
|
|
71
123
|
};
|
|
72
124
|
// Human output gets the note once on STDERR (never mixed into the piped
|
|
73
125
|
// stdout rows); the --json envelope carries it in meta.warnings instead.
|
|
@@ -79,7 +131,8 @@ export function runRead(opts, kind, fn, render, hintBase, header) {
|
|
|
79
131
|
// Omit-empty applies to the entity/data payload only (contracts.md); the
|
|
80
132
|
// envelope meta/truncation is untouched, and the human render below keeps
|
|
81
133
|
// the full, unpruned `data`.
|
|
82
|
-
|
|
134
|
+
const shaped = shapeReadPayload(effectiveKind, data, opts.full === true, client.refPromoter());
|
|
135
|
+
process.stdout.write(`${JSON.stringify(okEnvelope(effectiveKind, omitEmpty(wrapEnvelopeData(effectiveKind, shaped)), meta))}\n`);
|
|
83
136
|
}
|
|
84
137
|
else {
|
|
85
138
|
const lines = precomputed ?? render(data);
|
|
@@ -97,9 +150,16 @@ export function runRead(opts, kind, fn, render, hintBase, header) {
|
|
|
97
150
|
// sugar invocation resolved to, adjacent to the header. Same gates as the
|
|
98
151
|
// preamble (TTY-only, never in --json) — canonical invocations echo
|
|
99
152
|
// nothing because `resolvedCommand` is null for them.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
153
|
+
// The scope banner: one dim line naming the active jail, so a scoped
|
|
154
|
+
// read is never silently partial (TTY-only, never in --json). A
|
|
155
|
+
// stored-config scope must not be a mystery jail.
|
|
156
|
+
const scopeBanner = scope !== undefined && process.stdout.isTTY === true
|
|
157
|
+
? [dim(`scoped to ${scope.kind} "${scope.title}"`)]
|
|
158
|
+
: [];
|
|
159
|
+
const normalized = resolvedCommand !== null && process.stdout.isTTY === true
|
|
160
|
+
? [dim(`≡ ${resolvedCommand}`)]
|
|
161
|
+
: [];
|
|
162
|
+
const out = [...scopeBanner, ...normalized, ...withHeader];
|
|
103
163
|
process.stdout.write(`${out.join("\n")}\n`);
|
|
104
164
|
}
|
|
105
165
|
process.exitCode = ExitCode.Ok;
|
|
@@ -117,8 +177,8 @@ export function runRead(opts, kind, fn, render, hintBase, header) {
|
|
|
117
177
|
if (opts.json) {
|
|
118
178
|
process.stdout.write(`${JSON.stringify(errorEnvelope({
|
|
119
179
|
code: "not-found",
|
|
120
|
-
message: err
|
|
121
|
-
|
|
180
|
+
message: didYouMeanMessage(err),
|
|
181
|
+
detail: { candidates: candidatesJson(err) },
|
|
122
182
|
}, meta))}\n`);
|
|
123
183
|
}
|
|
124
184
|
else {
|
|
@@ -131,7 +191,7 @@ export function runRead(opts, kind, fn, render, hintBase, header) {
|
|
|
131
191
|
// usage-class failure carrying machine-readable candidates.
|
|
132
192
|
if (err instanceof ReferenceResolutionError) {
|
|
133
193
|
if (opts.json) {
|
|
134
|
-
process.stdout.write(`${JSON.stringify(errorEnvelope({ code: err.code, message: err.message,
|
|
194
|
+
process.stdout.write(`${JSON.stringify(errorEnvelope({ code: err.code, message: err.message, detail: { candidates: err.candidates } }, meta))}\n`);
|
|
135
195
|
}
|
|
136
196
|
else {
|
|
137
197
|
process.stderr.write(`error: ${err.message}\n`);
|
|
@@ -156,6 +216,7 @@ export function runRead(opts, kind, fn, render, hintBase, header) {
|
|
|
156
216
|
process.exitCode = isEnv ? ExitCode.Environment : ExitCode.Unexpected;
|
|
157
217
|
}
|
|
158
218
|
finally {
|
|
219
|
+
setRenderRefPromoter(null); // never leak a closed-DB promoter past this read
|
|
159
220
|
client?.close();
|
|
160
221
|
}
|
|
161
222
|
}
|
|
@@ -164,8 +225,14 @@ export function runRead(opts, kind, fn, render, hintBase, header) {
|
|
|
164
225
|
* turns it into human lines. Generic so `fn`'s return type flows into
|
|
165
226
|
* `render`'s parameter — the compiler verifies the renderer matches the data.
|
|
166
227
|
*/
|
|
167
|
-
export function withClient(opts, kind, fn, render
|
|
168
|
-
|
|
228
|
+
export function withClient(opts, kind, fn, render,
|
|
229
|
+
/** Optional read-specific advisories (merged into `meta.warnings` + stderr). */
|
|
230
|
+
warnings) {
|
|
231
|
+
runRead(opts, kind, (client) => {
|
|
232
|
+
const data = fn(client);
|
|
233
|
+
const w = warnings?.(client);
|
|
234
|
+
return { data, ...(w !== undefined && w.length > 0 && { warnings: w }) };
|
|
235
|
+
}, render);
|
|
169
236
|
}
|
|
170
237
|
/**
|
|
171
238
|
* Resolve the shared `--limit`/`--all` pair (flat views) into a row cap
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-driver.js","sourceRoot":"","sources":["../../src/cli/read-driver.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"read-driver.js","sourceRoot":"","sources":["../../src/cli/read-driver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The CLI's process-wide render-time ref promoter — the same module-state
|
|
3
|
+
* pattern the render clock (./clock.ts) and width fit (./width.ts) use. The read
|
|
4
|
+
* driver sets it (from `client.refPromoter()`) before rendering human output and
|
|
5
|
+
* clears it after, so the pure renderers can decide whether an INLINE container
|
|
6
|
+
* hint should promote its uuid prefix — `(Family)` → `(Family [TC9yozLk])` —
|
|
7
|
+
* using the SAME round-trip predicate the JSON `*Uuid` promotion uses (no fork).
|
|
8
|
+
* Unset (the default, and in unit tests that import the renderers directly) it is
|
|
9
|
+
* null, so a container hint stays the bare `(title)` — byte-identical output.
|
|
10
|
+
*/
|
|
11
|
+
import type { RefPromoter } from "../index.ts";
|
|
12
|
+
export declare function setRenderRefPromoter(p: RefPromoter | null): void;
|
|
13
|
+
/** The active render-time promoter, or null (host default — no inline promotion). */
|
|
14
|
+
export declare function renderRefPromoter(): RefPromoter | null;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
let promoter = null;
|
|
2
|
+
export function setRenderRefPromoter(p) {
|
|
3
|
+
promoter = p;
|
|
4
|
+
}
|
|
5
|
+
/** The active render-time promoter, or null (host default — no inline promotion). */
|
|
6
|
+
export function renderRefPromoter() {
|
|
7
|
+
return promoter;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=ref-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ref-render.js","sourceRoot":"","sources":["../../src/cli/ref-render.ts"],"names":[],"mappings":"AAYA,IAAI,QAAQ,GAAuB,IAAI,CAAC;AAExC,MAAM,UAAU,oBAAoB,CAAC,CAAqB;IACxD,QAAQ,GAAG,CAAC,CAAC;AACf,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,iBAAiB;IAC/B,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/cli/render.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* (agents and humans both need stable references); colors engage on a TTY only
|
|
8
8
|
* (../cli/style.ts).
|
|
9
9
|
*/
|
|
10
|
-
import { type GroupedLimits, type
|
|
10
|
+
import { type GroupedLimits, type ListItem, type SectionCount, type SidebarSection, type TodayView, type Truncation } from "../index.ts";
|
|
11
11
|
import { stripSgr } from "./width.ts";
|
|
12
12
|
/**
|
|
13
13
|
* A view's TTY-only title preamble: bold view name + its dim Things deep link,
|
|
@@ -39,6 +39,14 @@ export interface FormatOpts {
|
|
|
39
39
|
/** Container uuids already implied by surrounding output — their context suffix is dropped. */
|
|
40
40
|
suppressProject?: string | null;
|
|
41
41
|
suppressArea?: string | null;
|
|
42
|
+
/**
|
|
43
|
+
* Hint the row's HEADING (muted `(Heading)`) instead of its container — the
|
|
44
|
+
* project-view LOGBOOK rows, where a swept child of an OPEN heading labels its
|
|
45
|
+
* heading (the two-view asymmetry, HEADARC2-B: the in-project logged toggle
|
|
46
|
+
* labels the heading; the global Logbook labels the project). No-op on a row
|
|
47
|
+
* with no heading (falls back to the normal container/area hint).
|
|
48
|
+
*/
|
|
49
|
+
headingContext?: boolean;
|
|
42
50
|
/** Reference instant for date-relative tokens (tests pin this; defaults to now). */
|
|
43
51
|
now?: Date;
|
|
44
52
|
/** Pre-styled Today/Evening mark (★/⏾), rendered right after the box — GUI position. */
|
|
@@ -81,7 +89,7 @@ export declare function formatItem(item: ListItem, uuidWidth?: number, opts?: Fo
|
|
|
81
89
|
* effective This-Evening members (raw evening assignment counts only while
|
|
82
90
|
* startDate is exactly today — the UI's daily expiry), null otherwise.
|
|
83
91
|
*/
|
|
84
|
-
export declare function todayMark(item: ListItem
|
|
92
|
+
export declare function todayMark(item: ListItem): string | null;
|
|
85
93
|
/** Minimum displayed-prefix length: shorter prefixes collide across the DB. */
|
|
86
94
|
export declare const UUID_DISPLAY_MIN = 8;
|
|
87
95
|
/** The full-form TTY row floor — worst-case furniture + full deadline. See {@link computeFitFloors}. */
|
|
@@ -104,12 +112,28 @@ export declare function uuidDisplayWidth(items: Array<{
|
|
|
104
112
|
export declare function uuidCol(uuid: string, width: number): string;
|
|
105
113
|
export declare function renderList(items: ListItem[]): string[];
|
|
106
114
|
/**
|
|
107
|
-
* The `things today`
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* the
|
|
115
|
+
* The `things today` view. The wire is one flat `items[]` of Today members; the
|
|
116
|
+
* TTY re-projects the GUI's two render sections from each row's `when` — a
|
|
117
|
+
* Today-proper block (`when: "today"`) and a This-Evening block
|
|
118
|
+
* (`when: "evening"`). The whole-view `counts` aggregate (the app's sidebar
|
|
119
|
+
* count) renders at the TOP as card-style metadata lines (indented `key: value`,
|
|
120
|
+
* the same convention `things project show` / `things area show` use), so the
|
|
121
|
+
* section header itself stays clean (`── ★ Today ──`).
|
|
122
|
+
*
|
|
123
|
+
* The membership glyph lives in the SECTION HEADER, not on every row — a yellow ★
|
|
124
|
+
* in the Today header and a blue ⏾ in the This Evening header — so the rows drop
|
|
125
|
+
* the redundant per-item marker (the same convention that suppresses a
|
|
126
|
+
* `(project)` context inside that project's own view). Every OTHER view keeps the
|
|
127
|
+
* per-row ★/⏾, where the marker still carries information.
|
|
128
|
+
*
|
|
129
|
+
* A PROVISIONAL Today member (the wire's presence-keyed `provisional`, BANNER1
|
|
130
|
+
* law — a Today entrant the app has not yet materialized, banner-counted until
|
|
131
|
+
* acknowledged) gets a yellow `•` in the freed mark slot, mirroring the GUI's
|
|
132
|
+
* yellow "new item" pip. It is per-row (it distinguishes rows within a section,
|
|
133
|
+
* so it is NOT header-deduped like the ★) and — per the GUI — renders ONLY here,
|
|
134
|
+
* never in anytime or any other view. Derived through {@link entityProvisional},
|
|
135
|
+
* the SAME law the wire emit boundary uses, so the pip can never disagree with
|
|
136
|
+
* the emitted `provisional`.
|
|
113
137
|
*
|
|
114
138
|
* This Evening mirrors the GUI: it renders ONLY when evening items exist —
|
|
115
139
|
* a truly-empty evening has no header at all. `view` is the rows that survived
|
|
@@ -131,10 +155,12 @@ export declare function renderToday(view: TodayView, sections: SectionCount[] |
|
|
|
131
155
|
eveningOnly?: boolean;
|
|
132
156
|
}): string[];
|
|
133
157
|
/**
|
|
134
|
-
* Search rows: a standard list row, plus — for a
|
|
135
|
-
* title
|
|
136
|
-
*
|
|
137
|
-
*
|
|
158
|
+
* Search rows: a standard list row, plus — for a hit surfaced by something OTHER
|
|
159
|
+
* than its title — an indented muted matched-on line crediting WHERE the query
|
|
160
|
+
* matched (` ⤷ heading: "…"` / ` ⤷ notes: "…snippet…"` / ` ⤷ checklist: "…"`).
|
|
161
|
+
* A title match renders as a plain row with no indicator (matched where you'd
|
|
162
|
+
* expect). A heading match credits the parent project, a checklist match the
|
|
163
|
+
* parent to-do (the GUI has no bare heading/checklist row).
|
|
138
164
|
*/
|
|
139
165
|
export declare function renderSearch(items: ListItem[]): string[];
|
|
140
166
|
/** Hidden-later counts per sidebar group (null area = the loose block). */
|
|
@@ -230,7 +256,7 @@ export declare function disclosureHint(count: number, noun: string | {
|
|
|
230
256
|
* (`limits` supplies the doubling). Today members are starred. Mirrors
|
|
231
257
|
* renderSections' layout exactly.
|
|
232
258
|
*/
|
|
233
|
-
export declare function renderAnytimePreview(sections: SidebarSection[], grouped:
|
|
259
|
+
export declare function renderAnytimePreview(sections: SidebarSection[], grouped: Truncation, limits: GroupedLimits, base: string): string[];
|
|
234
260
|
/**
|
|
235
261
|
* The someday preview, mirroring the GUI (side-by-side, 2026-07-12): inside
|
|
236
262
|
* each group the project rows render as PLAIN items — `(~)` circle, count
|
|
@@ -243,4 +269,4 @@ export declare function renderAnytimePreview(sections: SidebarSection[], grouped
|
|
|
243
269
|
* When the toggle is off and such items exist, a muted bottom hint counts
|
|
244
270
|
* them and names the flag.
|
|
245
271
|
*/
|
|
246
|
-
export declare function renderSomedayPreview(sections: SidebarSection[], grouped:
|
|
272
|
+
export declare function renderSomedayPreview(sections: SidebarSection[], grouped: Truncation, limits: GroupedLimits, base: string, showActive: boolean, hiddenActiveItems: number): string[];
|
package/dist/cli/render.js
CHANGED
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
* (agents and humans both need stable references); colors engage on a TTY only
|
|
8
8
|
* (../cli/style.ts).
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { entityProvisional, entityWhen, localToday, partitionSomedaySection, splitSectionBlocks, templateStatus, REF_PREFIX_LEN, } from "../index.js";
|
|
11
11
|
import { renderNow, renderZone } from "./clock.js";
|
|
12
|
+
import { renderRefPromoter } from "./ref-render.js";
|
|
12
13
|
import { bold, dim, strike, underline } from "./style.js";
|
|
13
|
-
import { areaMark, CHECKLIST_MARK, containerLabel, countChip, dateChip, deadlineToken, eveningMoon, LEGEND, LEGEND_GROUPS, loggedDate, NOTES_MARK, projectCircle, projectTitleAccent, REMINDER_MARK, todayStar, todoBox, } from "./glyphs.js";
|
|
14
|
+
import { areaMark, CHECKLIST_MARK, containerLabel, countChip, dateChip, deadlineToken, eveningMoon, LEGEND, LEGEND_GROUPS, loggedDate, NOTES_MARK, projectCircle, projectTitleAccent, provisionalPip, REMINDER_MARK, todayStar, todoBox, } from "./glyphs.js";
|
|
14
15
|
import { FULL_MONTHS, upcomingBucket } from "./period.js";
|
|
15
16
|
import { fitRow, getFitWidth, resolveFit, stripSgr, TITLE_MIN, visibleWidth, } from "./width.js";
|
|
16
17
|
/**
|
|
@@ -52,6 +53,19 @@ export function renderLegend() {
|
|
|
52
53
|
}
|
|
53
54
|
/** Wraps a `#a #b` tag form in the row's dim styling (incl. its leading space). */
|
|
54
55
|
const styleTags = (form) => ` ${dim(form)}`;
|
|
56
|
+
/**
|
|
57
|
+
* The inline `[8charPrefix]` a container hint promotes when its bare title would
|
|
58
|
+
* NOT round-trip — the SAME predicate the JSON `*Uuid` promotion uses (the render
|
|
59
|
+
* promoter, ./ref-render.ts). Empty (bare `(title)`) when the promoter is unset
|
|
60
|
+
* (non-TTY / tests / no DB) or the title resolves back cleanly. A project/area
|
|
61
|
+
* container never carries a heading scope, so `projectUuid` stays undefined.
|
|
62
|
+
*/
|
|
63
|
+
function promotedRefBracket(ref, kind) {
|
|
64
|
+
const p = renderRefPromoter();
|
|
65
|
+
if (p === null || p.roundTrips(kind, ref.title, ref.uuid))
|
|
66
|
+
return "";
|
|
67
|
+
return ` [${ref.uuid.slice(0, REF_PREFIX_LEN)}]`;
|
|
68
|
+
}
|
|
55
69
|
/**
|
|
56
70
|
* One item line:
|
|
57
71
|
* `<uuid-prefix> <box> [★|⏾] [logged-date] [‹chip›] <title> [‹n›] [⍾] [≡] [≔] (container) #tags [⚑ deadline]`.
|
|
@@ -127,18 +141,27 @@ export function formatItem(item, uuidWidth = 0, opts = {}) {
|
|
|
127
141
|
? ` ${bold(dim("⚑"))}`
|
|
128
142
|
: "";
|
|
129
143
|
const container = item.type === "to-do" ? (item.project ?? item.headingProject ?? null) : null;
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
:
|
|
138
|
-
?
|
|
144
|
+
// A project-view LOGBOOK row hints its HEADING (the in-project logged toggle
|
|
145
|
+
// labels the heading — HEADARC2-B) rather than the suppressed project.
|
|
146
|
+
const headingHint = opts.headingContext === true && item.type === "to-do" && item.heading !== null
|
|
147
|
+
? ` (${item.heading.title})`
|
|
148
|
+
: null;
|
|
149
|
+
const context = headingHint !== null
|
|
150
|
+
? headingHint
|
|
151
|
+
: container !== null
|
|
152
|
+
? container.uuid === opts.suppressProject
|
|
139
153
|
? ""
|
|
140
|
-
:
|
|
141
|
-
|
|
154
|
+
: // The ↻ prefix (containerLabel) marks a container that is a repeating
|
|
155
|
+
// TEMPLATE project — the whole `(…)` run is dimmed below, so the mark
|
|
156
|
+
// rides the muted container styling. Areas never carry the flag. The
|
|
157
|
+
// fused uuid-prefix rides when the title would not round-trip (shared
|
|
158
|
+
// promotion predicate — the same one JSON `*Uuid` promotion uses).
|
|
159
|
+
` (${containerLabel(container.title, container.isRepeatingTemplate === true)}${promotedRefBracket(container, "project")})`
|
|
160
|
+
: item.area
|
|
161
|
+
? item.area.uuid === opts.suppressArea
|
|
162
|
+
? ""
|
|
163
|
+
: ` (${item.area.title}${promotedRefBracket(item.area, "area")})`
|
|
164
|
+
: "";
|
|
142
165
|
// width 0 (the default) means "no column" — show the full uuid untouched.
|
|
143
166
|
const shownUuid = uuidWidth > 0 ? uuidCol(item.uuid, uuidWidth) : item.uuid;
|
|
144
167
|
// Title styling composes four independent channels (docs/design/render-
|
|
@@ -167,10 +190,13 @@ export function formatItem(item, uuidWidth = 0, opts = {}) {
|
|
|
167
190
|
t = underline(t);
|
|
168
191
|
return t;
|
|
169
192
|
};
|
|
170
|
-
// GUI indicator order after the title: bell, document, checklist.
|
|
193
|
+
// GUI indicator order after the title: bell, document, checklist. The bell
|
|
194
|
+
// rides the presence-keyed `reminderLive` marker (§9n) — the SAME materialize-
|
|
195
|
+
// time gate the JSON wire's `reminder` key uses, so a stale reminder (past
|
|
196
|
+
// startDate, bell hidden in the GUI) shows no chip here either.
|
|
171
197
|
const tail = [
|
|
172
198
|
...(item.type === "project" ? [countChip(item)] : []),
|
|
173
|
-
...(item.
|
|
199
|
+
...(item.reminderLive === true ? [dim(REMINDER_MARK)] : []),
|
|
174
200
|
...(item.notes !== "" ? [dim(NOTES_MARK)] : []),
|
|
175
201
|
...(item.type === "to-do" && item.checklistItemsCount > 0 ? [dim(CHECKLIST_MARK)] : []),
|
|
176
202
|
];
|
|
@@ -208,13 +234,17 @@ export function formatItem(item, uuidWidth = 0, opts = {}) {
|
|
|
208
234
|
* effective This-Evening members (raw evening assignment counts only while
|
|
209
235
|
* startDate is exactly today — the UI's daily expiry), null otherwise.
|
|
210
236
|
*/
|
|
211
|
-
export function todayMark(item
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
|
|
237
|
+
export function todayMark(item) {
|
|
238
|
+
// Consume the ONE derived `when` (the same value the wire emits) so a row's
|
|
239
|
+
// ★/⏾ can never disagree with the emitted `when` — never re-derive membership
|
|
240
|
+
// or evening from `todaySection`/`startBucket`/`startDate`. Projects carry the
|
|
241
|
+
// Today markers exactly like to-dos (probe O12), so they pip identically.
|
|
242
|
+
const when = entityWhen(item);
|
|
243
|
+
if (when === "evening")
|
|
244
|
+
return eveningMoon();
|
|
245
|
+
if (when === "today")
|
|
246
|
+
return todayStar();
|
|
247
|
+
return null;
|
|
218
248
|
}
|
|
219
249
|
/** Minimum displayed-prefix length: shorter prefixes collide across the DB. */
|
|
220
250
|
export const UUID_DISPLAY_MIN = 8;
|
|
@@ -319,12 +349,36 @@ export function renderList(items) {
|
|
|
319
349
|
return items.length === 0 ? ["(empty)"] : items.map((i) => formatItem(i, w));
|
|
320
350
|
}
|
|
321
351
|
/**
|
|
322
|
-
* The
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
352
|
+
* The Today-view per-row mark: a provisional Today member fills the after-the-box
|
|
353
|
+
* mark slot with a yellow `•` (see {@link renderToday}). Derived through
|
|
354
|
+
* {@link entityProvisional}, the SAME law the wire emit boundary uses.
|
|
355
|
+
*/
|
|
356
|
+
const provisionalRowOpts = (i) => entityProvisional(i) ? { mark: provisionalPip() } : {};
|
|
357
|
+
/** A today row's This-Evening membership — the SAME `when` axis the wire carries. */
|
|
358
|
+
const isEveningRow = (i) => entityWhen(i) === "evening";
|
|
359
|
+
/**
|
|
360
|
+
* The `things today` view. The wire is one flat `items[]` of Today members; the
|
|
361
|
+
* TTY re-projects the GUI's two render sections from each row's `when` — a
|
|
362
|
+
* Today-proper block (`when: "today"`) and a This-Evening block
|
|
363
|
+
* (`when: "evening"`). The whole-view `counts` aggregate (the app's sidebar
|
|
364
|
+
* count) renders at the TOP as card-style metadata lines (indented `key: value`,
|
|
365
|
+
* the same convention `things project show` / `things area show` use), so the
|
|
366
|
+
* section header itself stays clean (`── ★ Today ──`).
|
|
367
|
+
*
|
|
368
|
+
* The membership glyph lives in the SECTION HEADER, not on every row — a yellow ★
|
|
369
|
+
* in the Today header and a blue ⏾ in the This Evening header — so the rows drop
|
|
370
|
+
* the redundant per-item marker (the same convention that suppresses a
|
|
371
|
+
* `(project)` context inside that project's own view). Every OTHER view keeps the
|
|
372
|
+
* per-row ★/⏾, where the marker still carries information.
|
|
373
|
+
*
|
|
374
|
+
* A PROVISIONAL Today member (the wire's presence-keyed `provisional`, BANNER1
|
|
375
|
+
* law — a Today entrant the app has not yet materialized, banner-counted until
|
|
376
|
+
* acknowledged) gets a yellow `•` in the freed mark slot, mirroring the GUI's
|
|
377
|
+
* yellow "new item" pip. It is per-row (it distinguishes rows within a section,
|
|
378
|
+
* so it is NOT header-deduped like the ★) and — per the GUI — renders ONLY here,
|
|
379
|
+
* never in anytime or any other view. Derived through {@link entityProvisional},
|
|
380
|
+
* the SAME law the wire emit boundary uses, so the pip can never disagree with
|
|
381
|
+
* the emitted `provisional`.
|
|
328
382
|
*
|
|
329
383
|
* This Evening mirrors the GUI: it renders ONLY when evening items exist —
|
|
330
384
|
* a truly-empty evening has no header at all. `view` is the rows that survived
|
|
@@ -343,30 +397,39 @@ export function renderList(items) {
|
|
|
343
397
|
* because that section is deliberately filtered out, not merely empty.
|
|
344
398
|
*/
|
|
345
399
|
export function renderToday(view, sections, base, options) {
|
|
346
|
-
//
|
|
400
|
+
// The two render sections are re-projected from each row's `when` (the SAME
|
|
401
|
+
// axis the wire carries), so the TTY split can never disagree with the JSON.
|
|
402
|
+
const todayRows = view.items.filter((i) => !isEveningRow(i));
|
|
403
|
+
const eveningRows = view.items.filter(isEveningRow);
|
|
404
|
+
// Pre-cap totals from the truncation metadata; fall back to the shown rows'
|
|
347
405
|
// own lengths when a caller hands an unbounded view with no section counts.
|
|
348
|
-
const todayTotal = sections?.find((s) => s.key === "today")?.total ??
|
|
349
|
-
const eveningTotal = sections?.find((s) => s.key === "evening")?.total ??
|
|
350
|
-
const w = uuidDisplayWidth(
|
|
406
|
+
const todayTotal = sections?.find((s) => s.key === "today")?.total ?? todayRows.length;
|
|
407
|
+
const eveningTotal = sections?.find((s) => s.key === "evening")?.total ?? eveningRows.length;
|
|
408
|
+
const w = uuidDisplayWidth(view.items);
|
|
351
409
|
const eveningOnly = options?.eveningOnly === true;
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
410
|
+
// The whole-view counts, at the TOP as card-style metadata lines (the
|
|
411
|
+
// project/area-show header convention). A `0` is meaningful, so both always show.
|
|
412
|
+
const lines = [
|
|
413
|
+
` ${dim("due/overdue:")} ${view.counts.dueOrOverdue}`,
|
|
414
|
+
` ${dim("other:")} ${view.counts.other}`,
|
|
415
|
+
];
|
|
416
|
+
if (!eveningOnly) {
|
|
417
|
+
lines.push(`${bold("──")} ${todayStar()} ${bold("Today ──")}`, ...(todayRows.length === 0
|
|
418
|
+
? ["(empty)"]
|
|
419
|
+
: todayRows.map((i) => formatItem(i, w, provisionalRowOpts(i)))));
|
|
420
|
+
}
|
|
358
421
|
if (eveningTotal > 0) {
|
|
359
422
|
// A blank line before the header matches every other grouped renderer's
|
|
360
423
|
// section spacing — but only when the Today section rendered above it. In
|
|
361
|
-
// --evening mode the header
|
|
424
|
+
// --evening mode the header follows the count lines directly, no blank.
|
|
362
425
|
if (!eveningOnly)
|
|
363
426
|
lines.push("");
|
|
364
427
|
lines.push(`${bold("──")} ${eveningMoon()} ${bold("This Evening ──")}`);
|
|
365
|
-
for (const i of
|
|
366
|
-
lines.push(formatItem(i, w));
|
|
367
|
-
const hidden = eveningTotal -
|
|
428
|
+
for (const i of eveningRows)
|
|
429
|
+
lines.push(formatItem(i, w, provisionalRowOpts(i)));
|
|
430
|
+
const hidden = eveningTotal - eveningRows.length;
|
|
368
431
|
if (hidden > 0) {
|
|
369
|
-
const more =
|
|
432
|
+
const more = eveningRows.length > 0 ? "more " : "";
|
|
370
433
|
const count = `${hidden} ${more}evening item${hidden === 1 ? "" : "s"}`;
|
|
371
434
|
// Normal Today view: the global truncation footer already carries the
|
|
372
435
|
// quantity levers (a bigger --limit / --all), so this hint is a pure
|
|
@@ -390,20 +453,25 @@ export function renderToday(view, sections, base, options) {
|
|
|
390
453
|
return lines;
|
|
391
454
|
}
|
|
392
455
|
/**
|
|
393
|
-
* Search rows: a standard list row, plus — for a
|
|
394
|
-
* title
|
|
395
|
-
*
|
|
396
|
-
*
|
|
456
|
+
* Search rows: a standard list row, plus — for a hit surfaced by something OTHER
|
|
457
|
+
* than its title — an indented muted matched-on line crediting WHERE the query
|
|
458
|
+
* matched (` ⤷ heading: "…"` / ` ⤷ notes: "…snippet…"` / ` ⤷ checklist: "…"`).
|
|
459
|
+
* A title match renders as a plain row with no indicator (matched where you'd
|
|
460
|
+
* expect). A heading match credits the parent project, a checklist match the
|
|
461
|
+
* parent to-do (the GUI has no bare heading/checklist row).
|
|
397
462
|
*/
|
|
398
463
|
export function renderSearch(items) {
|
|
399
464
|
if (items.length === 0)
|
|
400
465
|
return ["(empty)"];
|
|
401
466
|
const w = uuidDisplayWidth(items);
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
467
|
+
const lines = [];
|
|
468
|
+
for (const i of items) {
|
|
469
|
+
lines.push(formatItem(i, w));
|
|
470
|
+
const match = i.match;
|
|
471
|
+
if (match !== undefined)
|
|
472
|
+
lines.push(` ${dim(`⤷ ${match.field}: "${match.text}"`)}`);
|
|
473
|
+
}
|
|
474
|
+
return lines;
|
|
407
475
|
}
|
|
408
476
|
/**
|
|
409
477
|
* The sidebar mirror for `things projects`: loose projects first (the GUI
|
|
@@ -445,7 +513,12 @@ export function renderProjectsSidebar(items, hints) {
|
|
|
445
513
|
lines.push("");
|
|
446
514
|
lines.push(`${bold("──")} ${areaMark()} ${bold(`${group.area.title} ──`)}`);
|
|
447
515
|
}
|
|
448
|
-
lines.push(...rows.map((item) => formatItem(item, w, {
|
|
516
|
+
lines.push(...rows.map((item) => formatItem(item, w, {
|
|
517
|
+
suppressArea: group.area?.uuid ?? null,
|
|
518
|
+
// Projects can live in Today/This-Evening (probe O12) — pip them
|
|
519
|
+
// exactly like a to-do row would be in a today-aware view.
|
|
520
|
+
mark: todayMark(item),
|
|
521
|
+
})));
|
|
449
522
|
// A per-group locator count (not a standalone disclosure): it marks WHERE
|
|
450
523
|
// the hidden later projects sit; the single reveal command rides the
|
|
451
524
|
// whole-view placeholder below.
|
|
@@ -638,11 +711,11 @@ function mixedMoreLine(projects, todos, drill) {
|
|
|
638
711
|
function areaBlockFor(grouped, area) {
|
|
639
712
|
const kind = area === null ? "loose" : "area";
|
|
640
713
|
const ref = area?.uuid ?? null;
|
|
641
|
-
return grouped.blocks.find((b) => b.kind === kind && b.ref === ref);
|
|
714
|
+
return (grouped.blocks ?? []).find((b) => b.kind === kind && b.ref === ref);
|
|
642
715
|
}
|
|
643
716
|
/** A nested project block anywhere in the grouped metadata, matched by project uuid. */
|
|
644
717
|
function projectBlockFor(grouped, projectUuid) {
|
|
645
|
-
for (const b of grouped.blocks) {
|
|
718
|
+
for (const b of grouped.blocks ?? []) {
|
|
646
719
|
const hit = b.children?.find((c) => c.kind === "project" && c.ref === projectUuid);
|
|
647
720
|
if (hit !== undefined)
|
|
648
721
|
return hit;
|