things-api 0.9.0 → 0.11.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 +57 -12
- package/dist/audit/log.js +56 -2
- package/dist/audit/log.js.map +1 -1
- package/dist/audit/schema.d.ts +26 -8
- package/dist/audit/schema.js +42 -1
- package/dist/audit/schema.js.map +1 -1
- package/dist/cli/clock.d.ts +8 -0
- package/dist/cli/clock.js +24 -0
- package/dist/cli/clock.js.map +1 -0
- package/dist/cli/commands/area.d.ts +26 -3
- package/dist/cli/commands/area.js +129 -75
- package/dist/cli/commands/area.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +1 -1
- package/dist/cli/commands/doctor.js +44 -5
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/install-skill.d.ts +45 -0
- package/dist/cli/commands/install-skill.js +207 -0
- package/dist/cli/commands/install-skill.js.map +1 -0
- package/dist/cli/commands/mcp.js +23 -4
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/project.d.ts +18 -1
- package/dist/cli/commands/project.js +74 -35
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/reads.d.ts +15 -2
- package/dist/cli/commands/reads.js +459 -165
- package/dist/cli/commands/reads.js.map +1 -1
- package/dist/cli/commands/repeat-flags.d.ts +20 -0
- package/dist/cli/commands/repeat-flags.js +76 -0
- package/dist/cli/commands/repeat-flags.js.map +1 -0
- package/dist/cli/commands/setup.js +8 -4
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/show.js +53 -30
- package/dist/cli/commands/show.js.map +1 -1
- package/dist/cli/commands/todo.d.ts +1 -1
- package/dist/cli/commands/todo.js +20 -13
- package/dist/cli/commands/todo.js.map +1 -1
- package/dist/cli/commands/writes.js +388 -161
- package/dist/cli/commands/writes.js.map +1 -1
- package/dist/cli/did-you-mean.d.ts +1 -1
- package/dist/cli/excess-args.d.ts +15 -0
- package/dist/cli/excess-args.js +51 -0
- package/dist/cli/excess-args.js.map +1 -0
- package/dist/cli/glyphs.d.ts +55 -2
- package/dist/cli/glyphs.js +114 -21
- package/dist/cli/glyphs.js.map +1 -1
- package/dist/cli/help.d.ts +54 -0
- package/dist/cli/help.js +405 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/main.js +64 -26
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/move-hint.d.ts +45 -0
- package/dist/cli/move-hint.js +196 -0
- package/dist/cli/move-hint.js.map +1 -0
- package/dist/cli/period.d.ts +9 -8
- package/dist/cli/period.js +56 -30
- package/dist/cli/period.js.map +1 -1
- package/dist/cli/read-driver.d.ts +26 -19
- package/dist/cli/read-driver.js +77 -33
- package/dist/cli/read-driver.js.map +1 -1
- package/dist/cli/render.d.ts +92 -28
- package/dist/cli/render.js +333 -103
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/resolve-invocation.d.ts +42 -4
- package/dist/cli/resolve-invocation.js +97 -14
- package/dist/cli/resolve-invocation.js.map +1 -1
- package/dist/cli/skill-check.d.ts +21 -0
- package/dist/cli/skill-check.js +82 -0
- package/dist/cli/skill-check.js.map +1 -0
- package/dist/cli/skill.d.ts +62 -0
- package/dist/cli/skill.js +142 -0
- package/dist/cli/skill.js.map +1 -0
- package/dist/cli/tag-filters.d.ts +63 -0
- package/dist/cli/tag-filters.js +59 -0
- package/dist/cli/tag-filters.js.map +1 -0
- package/dist/cli/verb-hint.d.ts +25 -0
- package/dist/cli/verb-hint.js +163 -0
- package/dist/cli/verb-hint.js.map +1 -0
- package/dist/cli/version.d.ts +4 -0
- package/dist/cli/version.js +18 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/cli/width.d.ts +135 -0
- package/dist/cli/width.js +313 -0
- package/dist/cli/width.js.map +1 -0
- package/dist/client.d.ts +160 -24
- package/dist/client.js +132 -19
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.js +3 -0
- package/dist/config.js.map +1 -1
- package/dist/contracts.d.ts +97 -17
- package/dist/contracts.js +44 -1
- package/dist/contracts.js.map +1 -1
- package/dist/db/fingerprint.d.ts +12 -0
- package/dist/db/fingerprint.js +15 -1
- package/dist/db/fingerprint.js.map +1 -1
- package/dist/db/locate.js +1 -1
- package/dist/db/locate.js.map +1 -1
- package/dist/diagnose.d.ts +63 -0
- package/dist/diagnose.js +38 -1
- package/dist/diagnose.js.map +1 -1
- package/dist/index.d.ts +36 -5
- package/dist/index.js +38 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +9 -1
- package/dist/mcp/server.js +1038 -436
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/clock.d.ts +61 -0
- package/dist/model/clock.js +71 -0
- package/dist/model/clock.js.map +1 -0
- package/dist/model/dates.d.ts +26 -3
- package/dist/model/dates.js +84 -3
- package/dist/model/dates.js.map +1 -1
- package/dist/model/entities.d.ts +48 -10
- package/dist/model/entities.js.map +1 -1
- package/dist/model/mappers.d.ts +9 -2
- package/dist/model/mappers.js +32 -9
- package/dist/model/mappers.js.map +1 -1
- package/dist/model/serialize.d.ts +28 -0
- package/dist/model/serialize.js +80 -0
- package/dist/model/serialize.js.map +1 -0
- package/dist/model/when-sugar.d.ts +47 -0
- package/dist/model/when-sugar.js +45 -0
- package/dist/model/when-sugar.js.map +1 -0
- package/dist/read/area-view.d.ts +8 -1
- package/dist/read/area-view.js +55 -17
- package/dist/read/area-view.js.map +1 -1
- package/dist/read/detail.d.ts +1 -1
- package/dist/read/detail.js +11 -4
- package/dist/read/detail.js.map +1 -1
- package/dist/read/filter-contract.d.ts +117 -0
- package/dist/read/filter-contract.js +78 -0
- package/dist/read/filter-contract.js.map +1 -0
- package/dist/read/log-boundary.d.ts +1 -1
- package/dist/read/log-boundary.js +13 -3
- package/dist/read/log-boundary.js.map +1 -1
- package/dist/read/predicates.d.ts +30 -0
- package/dist/read/predicates.js +30 -0
- package/dist/read/predicates.js.map +1 -1
- package/dist/read/project-view.d.ts +12 -1
- package/dist/read/project-view.js +45 -12
- package/dist/read/project-view.js.map +1 -1
- package/dist/read/queries.d.ts +152 -7
- package/dist/read/queries.js +277 -36
- package/dist/read/queries.js.map +1 -1
- package/dist/read/sections.d.ts +51 -0
- package/dist/read/sections.js +37 -0
- package/dist/read/sections.js.map +1 -0
- package/dist/read/sidebar-order.js +2 -1
- package/dist/read/sidebar-order.js.map +1 -1
- package/dist/read/snapshot.d.ts +1 -1
- package/dist/read/snapshot.js +9 -2
- package/dist/read/snapshot.js.map +1 -1
- package/dist/read/tags.d.ts +27 -3
- package/dist/read/tags.js +83 -12
- package/dist/read/tags.js.map +1 -1
- package/dist/read/truncation.d.ts +71 -0
- package/dist/read/{pagination.js → truncation.js} +103 -94
- package/dist/read/truncation.js.map +1 -0
- package/dist/read/views.d.ts +147 -22
- package/dist/read/views.js +282 -80
- package/dist/read/views.js.map +1 -1
- package/dist/surface-copy.d.ts +19 -0
- package/dist/surface-copy.js +32 -0
- package/dist/surface-copy.js.map +1 -1
- package/dist/sync-health.d.ts +78 -0
- package/dist/sync-health.js +312 -0
- package/dist/sync-health.js.map +1 -0
- package/dist/write/accessibility-probe.d.ts +12 -0
- package/dist/write/accessibility-probe.js +71 -0
- package/dist/write/accessibility-probe.js.map +1 -0
- package/dist/write/automation-probe.d.ts +8 -1
- package/dist/write/automation-probe.js +16 -1
- package/dist/write/automation-probe.js.map +1 -1
- package/dist/write/batch.js +5 -2
- package/dist/write/batch.js.map +1 -1
- package/dist/write/capabilities.d.ts +8 -0
- package/dist/write/capabilities.js +13 -6
- package/dist/write/capabilities.js.map +1 -1
- package/dist/write/commands.d.ts +3 -1
- package/dist/write/commands.js +602 -49
- package/dist/write/commands.js.map +1 -1
- package/dist/write/edit-checklist.js +3 -2
- package/dist/write/edit-checklist.js.map +1 -1
- package/dist/write/guards.d.ts +2 -7
- package/dist/write/guards.js +87 -6
- package/dist/write/guards.js.map +1 -1
- package/dist/write/heading.js +2 -0
- package/dist/write/heading.js.map +1 -1
- package/dist/write/lock.d.ts +40 -2
- package/dist/write/lock.js +91 -14
- package/dist/write/lock.js.map +1 -1
- package/dist/write/make-repeating-project.d.ts +4 -0
- package/dist/write/make-repeating-project.js +253 -0
- package/dist/write/make-repeating-project.js.map +1 -0
- package/dist/write/operations.d.ts +145 -1
- package/dist/write/operations.js +48 -0
- package/dist/write/operations.js.map +1 -1
- package/dist/write/pipeline.d.ts +73 -2
- package/dist/write/pipeline.js +218 -43
- package/dist/write/pipeline.js.map +1 -1
- package/dist/write/planner.js +8 -1
- package/dist/write/planner.js.map +1 -1
- package/dist/write/pre-state.d.ts +105 -3
- package/dist/write/pre-state.js +144 -3
- package/dist/write/pre-state.js.map +1 -1
- package/dist/write/recurrence-rule-blob.d.ts +65 -0
- package/dist/write/recurrence-rule-blob.js +150 -0
- package/dist/write/recurrence-rule-blob.js.map +1 -0
- package/dist/write/reopen.js +3 -2
- package/dist/write/reopen.js.map +1 -1
- package/dist/write/reorder.js +27 -17
- package/dist/write/reorder.js.map +1 -1
- package/dist/write/repeat-rule.d.ts +22 -0
- package/dist/write/repeat-rule.js +258 -0
- package/dist/write/repeat-rule.js.map +1 -0
- package/dist/write/reversibility.js +49 -0
- package/dist/write/reversibility.js.map +1 -1
- package/dist/write/tag-refs.d.ts +47 -0
- package/dist/write/tag-refs.js +126 -0
- package/dist/write/tag-refs.js.map +1 -0
- package/dist/write/undo.d.ts +74 -5
- package/dist/write/undo.js +493 -80
- package/dist/write/undo.js.map +1 -1
- package/dist/write/vectors/registry.d.ts +15 -1
- package/dist/write/vectors/registry.js +65 -2
- package/dist/write/vectors/registry.js.map +1 -1
- package/dist/write/vectors/simulator.d.ts +44 -0
- package/dist/write/vectors/simulator.js +1136 -0
- package/dist/write/vectors/simulator.js.map +1 -0
- package/dist/write/vectors/types.d.ts +154 -3
- package/dist/write/vectors/ui-certification.d.ts +54 -0
- package/dist/write/vectors/ui-certification.js +43 -0
- package/dist/write/vectors/ui-certification.js.map +1 -0
- package/dist/write/vectors/ui-drag.d.ts +188 -0
- package/dist/write/vectors/ui-drag.js +1095 -0
- package/dist/write/vectors/ui-drag.js.map +1 -0
- package/dist/write/vectors/ui-recipes.d.ts +83 -0
- package/dist/write/vectors/ui-recipes.js +610 -0
- package/dist/write/vectors/ui-recipes.js.map +1 -0
- package/dist/write/vectors/ui.d.ts +152 -0
- package/dist/write/vectors/ui.js +704 -0
- package/dist/write/vectors/ui.js.map +1 -0
- package/dist/write/verify/delta.d.ts +141 -4
- package/dist/write/verify/delta.js +199 -21
- package/dist/write/verify/delta.js.map +1 -1
- package/dist/write/verify/poller.d.ts +7 -1
- package/dist/write/verify/poller.js +21 -1
- package/dist/write/verify/poller.js.map +1 -1
- package/package.json +18 -3
- package/skills/things-cli/SKILL.md +53 -0
- package/skills/things-cli/references/contracts.md +41 -0
- package/skills/things-cli/references/gui.md +11 -0
- package/skills/things-cli/references/model.md +51 -0
- package/dist/cli/exit-codes.d.ts +0 -26
- package/dist/cli/exit-codes.js +0 -26
- package/dist/cli/exit-codes.js.map +0 -1
- package/dist/cli/output.d.ts +0 -42
- package/dist/cli/output.js +0 -16
- package/dist/cli/output.js.map +0 -1
- package/dist/read/pagination.d.ts +0 -104
- package/dist/read/pagination.js.map +0 -1
package/dist/read/detail.js
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import { mapChecklistItem, mapHeading, mapProject, mapTodo, } from "../model/mappers.js";
|
|
2
2
|
import { decodeRecurrenceRule } from "../model/recurrence.js";
|
|
3
|
+
import { encodePackedDate, localToday } from "../model/dates.js";
|
|
3
4
|
import { fetchChecklistRows, fetchTagsForTasks, fetchTaskByUuid, makeHeadingProjectResolver, makeRefResolver, } from "./queries.js";
|
|
4
5
|
import { logBoundary, markLogged } from "./log-boundary.js";
|
|
5
6
|
import { inheritedTagsFor } from "./tags.js";
|
|
6
|
-
|
|
7
|
+
// `now`/`zone` supply the evaluation clock used to gate `todaySection` to
|
|
8
|
+
// Today members (see mappers.mapTodaySection). They default to the host clock —
|
|
9
|
+
// matching this module's existing logBoundary default; the client facade passes
|
|
10
|
+
// the injected clock so a pinned-clock `show` reads under the consumer's Today.
|
|
11
|
+
export function byUuid(db, uuid, now = new Date(), zone) {
|
|
7
12
|
const row = fetchTaskByUuid(db, uuid);
|
|
8
13
|
if (!row)
|
|
9
14
|
return null;
|
|
10
|
-
return materializeOne(db, row);
|
|
15
|
+
return materializeOne(db, row, encodePackedDate(localToday(now, zone)));
|
|
11
16
|
}
|
|
12
|
-
function materializeOne(db, row) {
|
|
17
|
+
function materializeOne(db, row, packedToday) {
|
|
13
18
|
const refs = makeRefResolver(db);
|
|
14
19
|
if (row.type === 2)
|
|
15
20
|
return mapHeading(row, refs);
|
|
16
21
|
const tags = fetchTagsForTasks(db, [row.uuid]).get(row.uuid) ?? [];
|
|
17
|
-
const entity = row.type === 1
|
|
22
|
+
const entity = row.type === 1
|
|
23
|
+
? mapProject(row, refs, tags, packedToday)
|
|
24
|
+
: mapTodo(row, refs, tags, packedToday);
|
|
18
25
|
markLogged([entity], logBoundary(db));
|
|
19
26
|
entity.inheritedTags = inheritedTagsFor(db, row);
|
|
20
27
|
if (entity.type === "to-do") {
|
package/dist/read/detail.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detail.js","sourceRoot":"","sources":["../../src/read/detail.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,OAAO,GAER,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,eAAe,EACf,0BAA0B,EAC1B,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,MAAM,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"detail.js","sourceRoot":"","sources":["../../src/read/detail.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The per-view filter contract — the ONE declarative statement of which read
|
|
3
|
+
* filters each view honors, plus the shared predicates that enforce them. Both
|
|
4
|
+
* consumer surfaces (CLI commands, MCP tools) derive their per-view guards from
|
|
5
|
+
* this table instead of hand-coding view lists, so a filter's applicability is
|
|
6
|
+
* stated once and can never drift between surfaces.
|
|
7
|
+
*
|
|
8
|
+
* The table says, per view: whether the `overdue` content scope applies; what
|
|
9
|
+
* tag semantics the view carries (inheritance-inclusive `inherited`, container-
|
|
10
|
+
* direct `direct`, or `rejected` where the view has no per-row tags to filter);
|
|
11
|
+
* the bound model the view truncates under (`flat` row cap, `grouped` per-block
|
|
12
|
+
* caps, or `none`); and whether the view offers the status-widening flags
|
|
13
|
+
* (search's logged/trashed/all) that `overdue` refuses to combine with.
|
|
14
|
+
*
|
|
15
|
+
* The exact usage-error COPY stays surface-owned (consumer voice differs per
|
|
16
|
+
* surface — CLI `--tag`, MCP `tag`; docs/design/surface-copy.md): a surface
|
|
17
|
+
* hands {@link validateViewArgs} its own phrasing via {@link FilterVocab}, and
|
|
18
|
+
* this module owns only the DECISION of which message applies.
|
|
19
|
+
*/
|
|
20
|
+
import type { ViewFilter } from "./views.ts";
|
|
21
|
+
/** Every read view whose filter applicability the contract governs. */
|
|
22
|
+
export type ViewName = "today" | "inbox" | "anytime" | "someday" | "upcoming" | "logbook" | "trash" | "search" | "changes" | "projects" | "areas" | "project-show" | "area-show";
|
|
23
|
+
/**
|
|
24
|
+
* How a view's tag filter behaves:
|
|
25
|
+
* - `inherited` — FLAT views: a `--tag` matches direct OR container-inherited
|
|
26
|
+
* membership (plus hierarchy descendants).
|
|
27
|
+
* - `direct` — CONTAINER views (`project show`, `area show`): a `--tag` matches
|
|
28
|
+
* a tag carried DIRECTLY on the row (the container's own inherited tags are
|
|
29
|
+
* suppressed, since every child inherits them).
|
|
30
|
+
* - `rejected` — the view has no per-row tag list to filter (an area list row,
|
|
31
|
+
* a tag list row, the changes feed); tag flags do not apply.
|
|
32
|
+
*/
|
|
33
|
+
export type TagSemantics = "inherited" | "direct" | "rejected";
|
|
34
|
+
/** The truncation model a view bounds under. */
|
|
35
|
+
export type BoundModel = "flat" | "grouped" | "none";
|
|
36
|
+
/** One row of {@link FILTER_CONTRACT}: a single view's filter applicability. */
|
|
37
|
+
export interface ViewFilterSpec {
|
|
38
|
+
/** Whether the `overdue` content scope (open, past-deadline) applies. */
|
|
39
|
+
readonly overdue: boolean;
|
|
40
|
+
/** The view's tag-filter semantics. */
|
|
41
|
+
readonly tag: TagSemantics;
|
|
42
|
+
/** The bound model the view truncates under. */
|
|
43
|
+
readonly bound: BoundModel;
|
|
44
|
+
/**
|
|
45
|
+
* Whether the view offers the status-widening flags (logged/trashed/all).
|
|
46
|
+
* Only `search` does; `overdue` refuses to combine with them there.
|
|
47
|
+
*/
|
|
48
|
+
readonly statusWidening: boolean;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The single source of truth for read-filter applicability, one row per view.
|
|
52
|
+
* Consumed by both surfaces' per-view guards (CLI command actions, MCP tool
|
|
53
|
+
* handlers) so no surface hand-maintains its own view list.
|
|
54
|
+
*/
|
|
55
|
+
export declare const FILTER_CONTRACT: Record<ViewName, ViewFilterSpec>;
|
|
56
|
+
/**
|
|
57
|
+
* The three universal tag-filter inputs in their canonical (CLI-flag) spelling.
|
|
58
|
+
* The CLI's parsed options match this verbatim; the MCP surface maps its
|
|
59
|
+
* snake_case inputs (`exact_tag`) onto it before calling the shared predicates.
|
|
60
|
+
*/
|
|
61
|
+
export interface TagPresence {
|
|
62
|
+
tag?: readonly string[] | undefined;
|
|
63
|
+
exactTag?: boolean | undefined;
|
|
64
|
+
untagged?: boolean | undefined;
|
|
65
|
+
}
|
|
66
|
+
/** True when any tag-PRESENCE flag was passed (a positive filter, not a negation). */
|
|
67
|
+
export declare function hasTagPresence(a: TagPresence): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* True when the tag flags are mutually incoherent: the `untagged` negation
|
|
70
|
+
* inverts a tag presence, so it does not combine with a tag-presence flag. A
|
|
71
|
+
* pure predicate — each surface emits its own usage error in its own voice.
|
|
72
|
+
*/
|
|
73
|
+
export declare function tagFlagConflict(a: TagPresence): boolean;
|
|
74
|
+
/** Build the {@link ViewFilter} tag fields from the parsed flags (empty keys omitted). */
|
|
75
|
+
export declare function tagFilterFields(a: TagPresence): ViewFilter;
|
|
76
|
+
/** The parsed read-filter inputs {@link validateViewArgs} inspects. */
|
|
77
|
+
export interface FilterArgs extends TagPresence {
|
|
78
|
+
overdue?: boolean | undefined;
|
|
79
|
+
/** search only: the status-widening flags overdue refuses to combine with. */
|
|
80
|
+
logged?: boolean | undefined;
|
|
81
|
+
trashed?: boolean | undefined;
|
|
82
|
+
all?: boolean | undefined;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The surface's exact usage-error copy for each conflict {@link validateViewArgs}
|
|
86
|
+
* can detect. Built per call by the surface (it knows the view/kind and its own
|
|
87
|
+
* flag spellings), so the SHARED module decides WHICH message applies while the
|
|
88
|
+
* message text stays consumer-voiced per surface.
|
|
89
|
+
*/
|
|
90
|
+
export interface FilterVocab {
|
|
91
|
+
/** `untagged` combined with a tag-presence flag. */
|
|
92
|
+
untaggedConflict: string;
|
|
93
|
+
/** `overdue` passed to a view that does not honor it. */
|
|
94
|
+
overdueRejected: string;
|
|
95
|
+
/** `overdue` combined with a status-widening flag (search). */
|
|
96
|
+
overdueStatusWiden: string;
|
|
97
|
+
}
|
|
98
|
+
/** {@link validateViewArgs} outcome: the built filter, or the usage message to emit. */
|
|
99
|
+
export type ViewValidation = {
|
|
100
|
+
ok: true;
|
|
101
|
+
filter: ViewFilter;
|
|
102
|
+
} | {
|
|
103
|
+
ok: false;
|
|
104
|
+
message: string;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Validate a view's filter arguments against {@link FILTER_CONTRACT} and, when
|
|
108
|
+
* coherent, build the {@link ViewFilter} tag+overdue portion. The checks (and
|
|
109
|
+
* their precedence) live here so both surfaces stay in lockstep; the surface
|
|
110
|
+
* supplies its own exact copy via {@link FilterVocab}.
|
|
111
|
+
*
|
|
112
|
+
* Does NOT enforce tag-REJECTION (a view refusing tag flags outright): that
|
|
113
|
+
* lives at the two call sites that currently reject — the areas/projects/tags
|
|
114
|
+
* collection listers — so this stays a pure no-op for the flat/container views
|
|
115
|
+
* that merely ignore tags on a sub-path (e.g. `trash`).
|
|
116
|
+
*/
|
|
117
|
+
export declare function validateViewArgs(view: ViewName, args: FilterArgs, vocab: FilterVocab): ViewValidation;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single source of truth for read-filter applicability, one row per view.
|
|
3
|
+
* Consumed by both surfaces' per-view guards (CLI command actions, MCP tool
|
|
4
|
+
* handlers) so no surface hand-maintains its own view list.
|
|
5
|
+
*/
|
|
6
|
+
export const FILTER_CONTRACT = {
|
|
7
|
+
// Current-work flat views: overdue applies, tags are inheritance-inclusive.
|
|
8
|
+
today: { overdue: true, tag: "inherited", bound: "flat", statusWidening: false },
|
|
9
|
+
inbox: { overdue: true, tag: "inherited", bound: "flat", statusWidening: false },
|
|
10
|
+
// Grouped catalogues: overdue applies, per-block caps.
|
|
11
|
+
anytime: { overdue: true, tag: "inherited", bound: "grouped", statusWidening: false },
|
|
12
|
+
someday: { overdue: true, tag: "inherited", bound: "grouped", statusWidening: false },
|
|
13
|
+
// Forward-looking / closed-item flat views: overdue deliberately does NOT apply.
|
|
14
|
+
upcoming: { overdue: false, tag: "inherited", bound: "flat", statusWidening: false },
|
|
15
|
+
logbook: { overdue: false, tag: "inherited", bound: "flat", statusWidening: false },
|
|
16
|
+
trash: { overdue: false, tag: "rejected", bound: "flat", statusWidening: false },
|
|
17
|
+
// Search: overdue applies but refuses the status-widening flags.
|
|
18
|
+
search: { overdue: true, tag: "inherited", bound: "flat", statusWidening: true },
|
|
19
|
+
// Sync feed: neither overdue nor tags apply.
|
|
20
|
+
changes: { overdue: false, tag: "rejected", bound: "flat", statusWidening: false },
|
|
21
|
+
// Projects LIST is a FLAT view — each project row filtered by its own
|
|
22
|
+
// (inheritance-inclusive) tags; overdue keeps past-deadline projects.
|
|
23
|
+
projects: { overdue: true, tag: "inherited", bound: "none", statusWidening: false },
|
|
24
|
+
// Areas LIST rows carry no deadline and no per-row tag filter.
|
|
25
|
+
areas: { overdue: false, tag: "rejected", bound: "none", statusWidening: false },
|
|
26
|
+
// Single-container views: overdue and DIRECT-tag filtering apply to children.
|
|
27
|
+
"project-show": { overdue: true, tag: "direct", bound: "grouped", statusWidening: false },
|
|
28
|
+
"area-show": { overdue: true, tag: "direct", bound: "grouped", statusWidening: false },
|
|
29
|
+
};
|
|
30
|
+
/** True when any tag-PRESENCE flag was passed (a positive filter, not a negation). */
|
|
31
|
+
export function hasTagPresence(a) {
|
|
32
|
+
return (a.tag?.length ?? 0) > 0 || a.exactTag === true;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* True when the tag flags are mutually incoherent: the `untagged` negation
|
|
36
|
+
* inverts a tag presence, so it does not combine with a tag-presence flag. A
|
|
37
|
+
* pure predicate — each surface emits its own usage error in its own voice.
|
|
38
|
+
*/
|
|
39
|
+
export function tagFlagConflict(a) {
|
|
40
|
+
return a.untagged === true && hasTagPresence(a);
|
|
41
|
+
}
|
|
42
|
+
/** Build the {@link ViewFilter} tag fields from the parsed flags (empty keys omitted). */
|
|
43
|
+
export function tagFilterFields(a) {
|
|
44
|
+
return {
|
|
45
|
+
...(a.tag !== undefined && a.tag.length > 0 && { tags: [...a.tag] }),
|
|
46
|
+
...(a.exactTag === true && { exactTag: true }),
|
|
47
|
+
...(a.untagged === true && { untagged: true }),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Validate a view's filter arguments against {@link FILTER_CONTRACT} and, when
|
|
52
|
+
* coherent, build the {@link ViewFilter} tag+overdue portion. The checks (and
|
|
53
|
+
* their precedence) live here so both surfaces stay in lockstep; the surface
|
|
54
|
+
* supplies its own exact copy via {@link FilterVocab}.
|
|
55
|
+
*
|
|
56
|
+
* Does NOT enforce tag-REJECTION (a view refusing tag flags outright): that
|
|
57
|
+
* lives at the two call sites that currently reject — the areas/projects/tags
|
|
58
|
+
* collection listers — so this stays a pure no-op for the flat/container views
|
|
59
|
+
* that merely ignore tags on a sub-path (e.g. `trash`).
|
|
60
|
+
*/
|
|
61
|
+
export function validateViewArgs(view, args, vocab) {
|
|
62
|
+
const spec = FILTER_CONTRACT[view];
|
|
63
|
+
if (tagFlagConflict(args))
|
|
64
|
+
return { ok: false, message: vocab.untaggedConflict };
|
|
65
|
+
if (args.overdue === true && !spec.overdue) {
|
|
66
|
+
return { ok: false, message: vocab.overdueRejected };
|
|
67
|
+
}
|
|
68
|
+
if (args.overdue === true &&
|
|
69
|
+
spec.statusWidening &&
|
|
70
|
+
(args.logged === true || args.trashed === true || args.all === true)) {
|
|
71
|
+
return { ok: false, message: vocab.overdueStatusWiden };
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
ok: true,
|
|
75
|
+
filter: { ...tagFilterFields(args), ...(args.overdue === true && { overdue: true }) },
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=filter-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter-contract.js","sourceRoot":"","sources":["../../src/read/filter-contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* FORWARD past the interval's own edge.
|
|
21
21
|
*/
|
|
22
22
|
import type { DatabaseSync } from "node:sqlite";
|
|
23
|
-
export declare function logBoundary(db: DatabaseSync, now?: Date): Date;
|
|
23
|
+
export declare function logBoundary(db: DatabaseSync, now?: Date, zone?: string): Date;
|
|
24
24
|
/** Stamp `logged` on mapped entities (closed AND at/before the boundary). */
|
|
25
25
|
export declare function markLogged<T extends {
|
|
26
26
|
status: string;
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
import { dayBoundInstant, localToday } from "../model/dates.js";
|
|
2
|
+
// `zone` (optional IANA zone) is threaded so the daily/weekly/monthly sweep
|
|
3
|
+
// edge is the CONSUMER'S local midnight, not the host's — byte-identical to a
|
|
4
|
+
// bare `new Date(now); setHours(0,…)` when absent. logInterval=0 (immediately,
|
|
5
|
+
// the golden default) is zone-independent (the boundary is `now`).
|
|
6
|
+
export function logBoundary(db, now = new Date(), zone) {
|
|
2
7
|
const row = db.prepare("SELECT logInterval, manualLogDate FROM TMSettings").get();
|
|
3
8
|
const manual = row?.manualLogDate != null ? new Date(row.manualLogDate * 1000) : null;
|
|
4
|
-
const startOfDay =
|
|
5
|
-
|
|
9
|
+
const startOfDay = zone === undefined
|
|
10
|
+
? (() => {
|
|
11
|
+
const d = new Date(now);
|
|
12
|
+
d.setHours(0, 0, 0, 0);
|
|
13
|
+
return d;
|
|
14
|
+
})()
|
|
15
|
+
: dayBoundInstant(localToday(now, zone), "start", zone);
|
|
6
16
|
let auto;
|
|
7
17
|
switch (row?.logInterval ?? 0) {
|
|
8
18
|
case 0:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-boundary.js","sourceRoot":"","sources":["../../src/read/log-boundary.ts"],"names":[],"mappings":"AAuBA,MAAM,UAAU,WAAW,CAAC,EAAgB,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE;
|
|
1
|
+
{"version":3,"file":"log-boundary.js","sourceRoot":"","sources":["../../src/read/log-boundary.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEhE,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAC/E,mEAAmE;AACnE,MAAM,UAAU,WAAW,CAAC,EAAgB,EAAE,GAAG,GAAG,IAAI,IAAI,EAAE,EAAE,IAAa;IAC3E,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,mDAAmD,CAAC,CAAC,GAAG,EAElE,CAAC;IACd,MAAM,MAAM,GAAG,GAAG,EAAE,aAAa,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtF,MAAM,UAAU,GACd,IAAI,KAAK,SAAS;QAChB,CAAC,CAAC,CAAC,GAAS,EAAE;YACV,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;YACxB,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;YACvB,OAAO,CAAC,CAAC;QACX,CAAC,CAAC,EAAE;QACN,CAAC,CAAC,eAAe,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC5D,IAAI,IAAU,CAAC;IACf,QAAQ,GAAG,EAAE,WAAW,IAAI,CAAC,EAAE,CAAC;QAC9B,KAAK,CAAC;YACJ,IAAI,GAAG,GAAG,CAAC;YACX,MAAM;QACR,KAAK,CAAC;YACJ,IAAI,GAAG,UAAU,CAAC;YAClB,MAAM;QACR,KAAK,CAAC,CAAC,CAAC,CAAC;YACP,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YACpC,IAAI,GAAG,CAAC,CAAC;YACT,MAAM;QACR,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC;YACP,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACb,IAAI,GAAG,CAAC,CAAC;YACT,MAAM;QACR,CAAC;QACD;YACE,IAAI,GAAG,MAAM,IAAI,GAAG,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1D,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,UAAU,CACxB,KAAU,EACV,QAAc;IAEd,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,IAAI,IAAI,CAAC,OAAO,IAAI,QAAQ,CAAC;IAC5F,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -2,6 +2,36 @@
|
|
|
2
2
|
export declare const LIVE = "t.type IN (0, 1) AND t.trashed = 0 AND (t.rt1_recurrenceRule IS NULL AND t.repeater IS NULL)";
|
|
3
3
|
/** {@link LIVE} restricted to open (status = 0) rows. */
|
|
4
4
|
export declare const OPEN = "t.type IN (0, 1) AND t.trashed = 0 AND (t.rt1_recurrenceRule IS NULL AND t.repeater IS NULL) AND t.status = 0";
|
|
5
|
+
/**
|
|
6
|
+
* The GUI-visible set: open rows PLUS closed (completed/canceled) rows the
|
|
7
|
+
* periodic log-move sweep has NOT yet carried to the Logbook — completion ≠
|
|
8
|
+
* logged (src/read/log-boundary.ts). A closed row keeps its slot in its list
|
|
9
|
+
* until the sweep passes it, exactly as the GUI keeps it checked in place; it
|
|
10
|
+
* leaves when the sweep boundary advances past its stopDate (boundary-relative,
|
|
11
|
+
* no new state). This is {@link LIVE} widened to that set: swept iff
|
|
12
|
+
* status IN (2,3) AND stopDate IS NOT NULL AND stopDate <= boundary — the
|
|
13
|
+
* negation of the {@link markLogged} `logged` predicate, so an included closed
|
|
14
|
+
* row always materializes with `logged=false`. Mirrors the project/area card
|
|
15
|
+
* precedent (project-view.ts / area-view.ts keep a closed-but-unswept row
|
|
16
|
+
* checked in place). ONE bind: the log boundary as epoch seconds
|
|
17
|
+
* (logBoundary(db, now).getTime() / 1000). Ruling 2026-07-14 (Mike): GUI parity
|
|
18
|
+
* — `today` and `anytime` show checked-but-unswept rows.
|
|
19
|
+
*/
|
|
20
|
+
export declare const OPEN_OR_UNSWEPT = "t.type IN (0, 1) AND t.trashed = 0 AND (t.rt1_recurrenceRule IS NULL AND t.repeater IS NULL) AND NOT (t.status IN (2, 3) AND t.stopDate IS NOT NULL AND t.stopDate <= ?)";
|
|
21
|
+
/**
|
|
22
|
+
* The `--overdue` content scope: OPEN items whose deadline falls strictly
|
|
23
|
+
* BEFORE today. Due-TODAY is deliberately NOT overdue (`<`, not `<=`) —
|
|
24
|
+
* mirroring the app's own Today badge split, where a deadline EQUAL to today
|
|
25
|
+
* reads as "due" and only an EARLIER deadline reads as "overdue". One bind:
|
|
26
|
+
* today as a packed-date int (encodePackedDate(localToday(now))), so the
|
|
27
|
+
* boundary rides the same injected clock every other view uses — never a
|
|
28
|
+
* hardcoded date. The `t.status = 0` clause re-tightens the OPEN_OR_UNSWEPT
|
|
29
|
+
* views (today/anytime) so a checked-but-unswept row that happens to sit past
|
|
30
|
+
* a deadline is excluded — overdue is remaining, OPEN work. Trash exclusion is
|
|
31
|
+
* the hosting view's job (every view this composes into already drops trashed
|
|
32
|
+
* and derived-trashed rows), so it is not repeated here.
|
|
33
|
+
*/
|
|
34
|
+
export declare const OVERDUE = "t.deadline IS NOT NULL AND t.deadline < ? AND t.status = 0";
|
|
5
35
|
/** An item's own anytime membership: unscheduled-active, or dated <= today. */
|
|
6
36
|
export declare const ANYTIME_SELF: (col: string) => string;
|
|
7
37
|
/**
|
package/dist/read/predicates.js
CHANGED
|
@@ -12,6 +12,36 @@ import { NOT_TEMPLATE } from "./queries.js";
|
|
|
12
12
|
export const LIVE = `t.type IN (0, 1) AND t.trashed = 0 AND ${NOT_TEMPLATE}`;
|
|
13
13
|
/** {@link LIVE} restricted to open (status = 0) rows. */
|
|
14
14
|
export const OPEN = `${LIVE} AND t.status = 0`;
|
|
15
|
+
/**
|
|
16
|
+
* The GUI-visible set: open rows PLUS closed (completed/canceled) rows the
|
|
17
|
+
* periodic log-move sweep has NOT yet carried to the Logbook — completion ≠
|
|
18
|
+
* logged (src/read/log-boundary.ts). A closed row keeps its slot in its list
|
|
19
|
+
* until the sweep passes it, exactly as the GUI keeps it checked in place; it
|
|
20
|
+
* leaves when the sweep boundary advances past its stopDate (boundary-relative,
|
|
21
|
+
* no new state). This is {@link LIVE} widened to that set: swept iff
|
|
22
|
+
* status IN (2,3) AND stopDate IS NOT NULL AND stopDate <= boundary — the
|
|
23
|
+
* negation of the {@link markLogged} `logged` predicate, so an included closed
|
|
24
|
+
* row always materializes with `logged=false`. Mirrors the project/area card
|
|
25
|
+
* precedent (project-view.ts / area-view.ts keep a closed-but-unswept row
|
|
26
|
+
* checked in place). ONE bind: the log boundary as epoch seconds
|
|
27
|
+
* (logBoundary(db, now).getTime() / 1000). Ruling 2026-07-14 (Mike): GUI parity
|
|
28
|
+
* — `today` and `anytime` show checked-but-unswept rows.
|
|
29
|
+
*/
|
|
30
|
+
export const OPEN_OR_UNSWEPT = `${LIVE} AND NOT (t.status IN (2, 3) AND t.stopDate IS NOT NULL AND t.stopDate <= ?)`;
|
|
31
|
+
/**
|
|
32
|
+
* The `--overdue` content scope: OPEN items whose deadline falls strictly
|
|
33
|
+
* BEFORE today. Due-TODAY is deliberately NOT overdue (`<`, not `<=`) —
|
|
34
|
+
* mirroring the app's own Today badge split, where a deadline EQUAL to today
|
|
35
|
+
* reads as "due" and only an EARLIER deadline reads as "overdue". One bind:
|
|
36
|
+
* today as a packed-date int (encodePackedDate(localToday(now))), so the
|
|
37
|
+
* boundary rides the same injected clock every other view uses — never a
|
|
38
|
+
* hardcoded date. The `t.status = 0` clause re-tightens the OPEN_OR_UNSWEPT
|
|
39
|
+
* views (today/anytime) so a checked-but-unswept row that happens to sit past
|
|
40
|
+
* a deadline is excluded — overdue is remaining, OPEN work. Trash exclusion is
|
|
41
|
+
* the hosting view's job (every view this composes into already drops trashed
|
|
42
|
+
* and derived-trashed rows), so it is not repeated here.
|
|
43
|
+
*/
|
|
44
|
+
export const OVERDUE = `t.deadline IS NOT NULL AND t.deadline < ? AND t.status = 0`;
|
|
15
45
|
/** An item's own anytime membership: unscheduled-active, or dated <= today. */
|
|
16
46
|
export const ANYTIME_SELF = (col) => `((${col}.start = 1 AND (${col}.startDate IS NULL OR ${col}.startDate <= ?))
|
|
17
47
|
OR (${col}.start = 2 AND ${col}.startDate IS NOT NULL AND ${col}.startDate <= ?))`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"predicates.js","sourceRoot":"","sources":["../../src/read/predicates.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,oFAAoF;AACpF,MAAM,CAAC,MAAM,IAAI,GAAG,0CAA0C,YAAY,EAAE,CAAC;AAE7E,yDAAyD;AACzD,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,IAAI,mBAAmB,CAAC;AAE/C,+EAA+E;AAC/E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAAU,EAAE,CAClD,KAAK,GAAG,mBAAmB,GAAG,yBAAyB,GAAG;UAClD,GAAG,kBAAkB,GAAG,8BAA8B,GAAG,mBAAmB,CAAC;AAEvF;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,gFAAgF,CAAC;AAE5G;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,WAAW;6CACR,WAAW;8CACV,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAEpE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;;QAE3B,WAAW;+CAC4B,WAAW,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"predicates.js","sourceRoot":"","sources":["../../src/read/predicates.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,oFAAoF;AACpF,MAAM,CAAC,MAAM,IAAI,GAAG,0CAA0C,YAAY,EAAE,CAAC;AAE7E,yDAAyD;AACzD,MAAM,CAAC,MAAM,IAAI,GAAG,GAAG,IAAI,mBAAmB,CAAC;AAE/C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,IAAI,8EAA8E,CAAC;AAErH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,4DAA4D,CAAC;AAEpF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAAU,EAAE,CAClD,KAAK,GAAG,mBAAmB,GAAG,yBAAyB,GAAG;UAClD,GAAG,kBAAkB,GAAG,8BAA8B,GAAG,mBAAmB,CAAC;AAEvF;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,gFAAgF,CAAC;AAE5G;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,WAAW;6CACR,WAAW;8CACV,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAEpE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG;;QAE3B,WAAW;+CAC4B,WAAW,uBAAuB,CAAC"}
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { DatabaseSync } from "node:sqlite";
|
|
11
11
|
import type { Heading, IsoDateGroup, Project, Todo } from "../model/entities.ts";
|
|
12
|
+
import { type ViewFilter } from "./views.ts";
|
|
12
13
|
export interface ProjectView {
|
|
13
14
|
project: Project;
|
|
14
15
|
/** Open, unscheduled/current children not under a heading, by index. */
|
|
@@ -27,8 +28,18 @@ export interface ProjectView {
|
|
|
27
28
|
};
|
|
28
29
|
logged: Todo[];
|
|
29
30
|
trashed: Todo[];
|
|
31
|
+
/**
|
|
32
|
+
* PLOG1 (additive): count of untrashed OPEN (status=0) children this project
|
|
33
|
+
* still holds while it is ITSELF completed or canceled — including once swept
|
|
34
|
+
* to the Logbook. Such items are invisible in every live app view (Today /
|
|
35
|
+
* Anytime / Inbox / Upcoming), reachable only by drilling into this card
|
|
36
|
+
* (the app's GUI "Put Back" into a completed parent can strand them —
|
|
37
|
+
* docs/lab/plog1-research.md). 0 when the project is open, or holds no such
|
|
38
|
+
* child.
|
|
39
|
+
*/
|
|
40
|
+
openChildrenWhileResolved: number;
|
|
30
41
|
}
|
|
31
42
|
export declare class ProjectNotFoundError extends Error {
|
|
32
43
|
constructor(uuid: string);
|
|
33
44
|
}
|
|
34
|
-
export declare function projectView(db: DatabaseSync, uuid: string, now?: Date): ProjectView;
|
|
45
|
+
export declare function projectView(db: DatabaseSync, uuid: string, now?: Date, filter?: ViewFilter, zone?: string): ProjectView;
|
|
@@ -2,37 +2,58 @@ import { encodePackedDate, localToday, decodePackedDate } from "../model/dates.j
|
|
|
2
2
|
import { mapHeading, mapProject, mapTodo } from "../model/mappers.js";
|
|
3
3
|
import { fetchTagsForTasks, fetchTaskByUuid, fetchTaskRows, makeRefResolver } from "./queries.js";
|
|
4
4
|
import { logBoundary, markLogged } from "./log-boundary.js";
|
|
5
|
+
import { OVERDUE } from "./predicates.js";
|
|
5
6
|
import { inheritedTagsFor } from "./tags.js";
|
|
7
|
+
import { tagFilter } from "./views.js";
|
|
6
8
|
export class ProjectNotFoundError extends Error {
|
|
7
9
|
constructor(uuid) {
|
|
8
10
|
super(`no project with uuid ${uuid}`);
|
|
9
11
|
this.name = "ProjectNotFoundError";
|
|
10
12
|
}
|
|
11
13
|
}
|
|
12
|
-
export function projectView(db, uuid, now) {
|
|
14
|
+
export function projectView(db, uuid, now, filter = {}, zone) {
|
|
15
|
+
const overdue = filter.overdue === true;
|
|
13
16
|
const projectRow = fetchTaskByUuid(db, uuid);
|
|
14
17
|
if (!projectRow || projectRow.type !== 1)
|
|
15
18
|
throw new ProjectNotFoundError(uuid);
|
|
16
19
|
const refs = makeRefResolver(db);
|
|
20
|
+
// The view's injected clock — gates `todaySection` to Today members in the
|
|
21
|
+
// mapper AND drives the scheduled/overdue bucketing below.
|
|
22
|
+
const packedToday = encodePackedDate(localToday(now, zone));
|
|
17
23
|
const tagsOf = (rows) => fetchTagsForTasks(db, rows.map((r) => r.uuid));
|
|
18
24
|
const projectTags = tagsOf([projectRow]);
|
|
19
|
-
const project = mapProject(projectRow, refs, projectTags.get(projectRow.uuid) ?? []);
|
|
25
|
+
const project = mapProject(projectRow, refs, projectTags.get(projectRow.uuid) ?? [], packedToday);
|
|
20
26
|
// The card view surfaces area-inherited tags (the UI's tag filter honors them).
|
|
21
27
|
project.inheritedTags = inheritedTagsFor(db, projectRow);
|
|
22
28
|
const headingRows = fetchTaskRows(db, `t.type = 2 AND t.project = ? AND t.trashed = 0 ORDER BY t."index" ASC`, [uuid]);
|
|
23
29
|
const headings = headingRows.map((h) => mapHeading(h, refs));
|
|
30
|
+
// OWN-DEADLINE UNIFORM: `--overdue` narrows the child TO-DOS to those whose
|
|
31
|
+
// OWN deadline is overdue (open, strictly before today) via the shared
|
|
32
|
+
// OVERDUE predicate — NO recursion into anything, and the project header
|
|
33
|
+
// itself always renders. Headings that keep no surviving child collapse
|
|
34
|
+
// (below). Its single packed-today bind trails the two uuid binds.
|
|
35
|
+
const overdueSql = overdue ? ` AND ${OVERDUE}` : "";
|
|
36
|
+
const overdueBinds = overdue ? [encodePackedDate(localToday(now, zone))] : [];
|
|
37
|
+
// Tag scope (§9a): the child to-dos are filtered by a tag carried DIRECTLY on
|
|
38
|
+
// the row — the container semantics. The project's own tags are inherited by
|
|
39
|
+
// EVERY child, so an inheritance-inclusive `--tag` would be vacuous here;
|
|
40
|
+
// suppressing the container hop makes `--tag` mean "children with this tag on
|
|
41
|
+
// themselves" (still descendant-expanded), and `--untagged` "children with no
|
|
42
|
+
// direct tag". No recursion; the header always renders. The tag binds trail
|
|
43
|
+
// the two uuid binds and lead the overdue bind, matching their left-to-right
|
|
44
|
+
// order in the SQL.
|
|
45
|
+
const tf = tagFilter(db, filter, { container: true });
|
|
24
46
|
const childRows = fetchTaskRows(db, `t.type = 0 AND (t.project = ? OR t.heading IN (
|
|
25
47
|
SELECT uuid FROM TMTask WHERE type = 2 AND project = ?
|
|
26
|
-
))
|
|
27
|
-
ORDER BY t."index" ASC`, [uuid, uuid]);
|
|
48
|
+
))${tf.sql}${overdueSql}
|
|
49
|
+
ORDER BY t."index" ASC`, [uuid, uuid, ...tf.binds, ...overdueBinds]);
|
|
28
50
|
const childTags = tagsOf(childRows);
|
|
29
|
-
const boundary = logBoundary(db, now);
|
|
51
|
+
const boundary = logBoundary(db, now, zone);
|
|
30
52
|
const todos = childRows.map((r) => ({
|
|
31
53
|
row: r,
|
|
32
|
-
todo: mapTodo(r, refs, childTags.get(r.uuid) ?? []),
|
|
54
|
+
todo: mapTodo(r, refs, childTags.get(r.uuid) ?? [], packedToday),
|
|
33
55
|
}));
|
|
34
56
|
markLogged([project, ...todos.map((t) => t.todo)], boundary);
|
|
35
|
-
const packedToday = encodePackedDate(localToday(now));
|
|
36
57
|
const active = [];
|
|
37
58
|
const byHeading = new Map();
|
|
38
59
|
const scheduledRows = [];
|
|
@@ -40,6 +61,10 @@ export function projectView(db, uuid, now) {
|
|
|
40
61
|
const someday = [];
|
|
41
62
|
const logged = [];
|
|
42
63
|
const trashed = [];
|
|
64
|
+
// Every untrashed, non-template OPEN child, regardless of which bucket it
|
|
65
|
+
// lands in below — surfaced (only when the project is itself resolved) as
|
|
66
|
+
// the PLOG1 stranded-open-child count.
|
|
67
|
+
let openChildren = 0;
|
|
43
68
|
for (const { row, todo } of todos) {
|
|
44
69
|
if (row.trashed === 1) {
|
|
45
70
|
trashed.push(todo);
|
|
@@ -49,6 +74,8 @@ export function projectView(db, uuid, now) {
|
|
|
49
74
|
repeating.push(todo);
|
|
50
75
|
continue;
|
|
51
76
|
}
|
|
77
|
+
if (row.status === 0)
|
|
78
|
+
openChildren += 1;
|
|
52
79
|
if (row.status !== 0) {
|
|
53
80
|
// Completion ≠ logged: closed items the log-move sweep has not
|
|
54
81
|
// passed stay checked IN PLACE (their heading / the active block),
|
|
@@ -90,23 +117,29 @@ export function projectView(db, uuid, now) {
|
|
|
90
117
|
logged.sort((a, b) => (b.stopped?.getTime() ?? 0) - (a.stopped?.getTime() ?? 0));
|
|
91
118
|
const scheduled = [];
|
|
92
119
|
// Within a day the UI sorts by todayIndex ASC (Upcoming drag order).
|
|
93
|
-
for (const { date, todo } of scheduledRows.
|
|
120
|
+
for (const { date, todo } of scheduledRows.toSorted((a, b) => a.date.localeCompare(b.date) || a.ti - b.ti)) {
|
|
94
121
|
const last = scheduled[scheduled.length - 1];
|
|
95
122
|
if (last && last.date === date)
|
|
96
123
|
last.items.push(todo);
|
|
97
124
|
else
|
|
98
125
|
scheduled.push({ date, items: [todo] });
|
|
99
126
|
}
|
|
127
|
+
// Under any content scope (`--overdue` or a tag filter), a heading whose
|
|
128
|
+
// children were all filtered out collapses rather than rendering an empty
|
|
129
|
+
// section; a heading with a surviving child is kept. With no scope active
|
|
130
|
+
// every heading renders (its own empty state).
|
|
131
|
+
const contentScoped = overdue || tf.sql !== "";
|
|
132
|
+
const headingGroups = headings
|
|
133
|
+
.map((heading) => ({ heading, items: byHeading.get(heading.uuid) ?? [] }))
|
|
134
|
+
.filter((g) => !contentScoped || g.items.length > 0);
|
|
100
135
|
return {
|
|
101
136
|
project,
|
|
102
137
|
active,
|
|
103
|
-
headings:
|
|
104
|
-
heading,
|
|
105
|
-
items: byHeading.get(heading.uuid) ?? [],
|
|
106
|
-
})),
|
|
138
|
+
headings: headingGroups,
|
|
107
139
|
later: { scheduled, repeating, someday },
|
|
108
140
|
logged,
|
|
109
141
|
trashed,
|
|
142
|
+
openChildrenWhileResolved: project.status === "open" ? 0 : openChildren,
|
|
110
143
|
};
|
|
111
144
|
}
|
|
112
145
|
//# sourceMappingURL=project-view.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-view.js","sourceRoot":"","sources":["../../src/read/project-view.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEnF,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAgB,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAClG,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"project-view.js","sourceRoot":"","sources":["../../src/read/project-view.ts"],"names":[],"mappings":"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"}
|