@graview/core 0.1.54 → 0.1.56

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 (208) hide show
  1. package/dist/alias-findings.d.ts +40 -0
  2. package/dist/alias-findings.d.ts.map +1 -0
  3. package/dist/alias-findings.js +95 -0
  4. package/dist/alias-findings.js.map +1 -0
  5. package/dist/app.d.ts +13 -0
  6. package/dist/app.d.ts.map +1 -1
  7. package/dist/app.js.map +1 -1
  8. package/dist/arranging.d.ts +6 -1
  9. package/dist/arranging.d.ts.map +1 -1
  10. package/dist/arranging.js +21 -3
  11. package/dist/arranging.js.map +1 -1
  12. package/dist/capabilities.js +1 -1
  13. package/dist/capabilities.js.map +1 -1
  14. package/dist/catalog.d.ts +32 -0
  15. package/dist/catalog.d.ts.map +1 -1
  16. package/dist/catalog.js +17 -1
  17. package/dist/catalog.js.map +1 -1
  18. package/dist/check.d.ts +2 -0
  19. package/dist/check.d.ts.map +1 -1
  20. package/dist/check.js +2 -0
  21. package/dist/check.js.map +1 -1
  22. package/dist/cli/check/aliases.d.ts +11 -0
  23. package/dist/cli/check/aliases.d.ts.map +1 -0
  24. package/dist/cli/check/aliases.js +17 -0
  25. package/dist/cli/check/aliases.js.map +1 -0
  26. package/dist/cli/check/context.d.ts +2 -0
  27. package/dist/cli/check/context.d.ts.map +1 -1
  28. package/dist/cli/check/context.js.map +1 -1
  29. package/dist/cli/check/index.d.ts +2 -0
  30. package/dist/cli/check/index.d.ts.map +1 -1
  31. package/dist/cli/check/index.js +2 -0
  32. package/dist/cli/check/index.js.map +1 -1
  33. package/dist/cli/check/jobs.d.ts +12 -0
  34. package/dist/cli/check/jobs.d.ts.map +1 -0
  35. package/dist/cli/check/jobs.js +25 -0
  36. package/dist/cli/check/jobs.js.map +1 -0
  37. package/dist/cli/check.d.ts +13 -0
  38. package/dist/cli/check.d.ts.map +1 -1
  39. package/dist/cli/check.js +25 -2
  40. package/dist/cli/check.js.map +1 -1
  41. package/dist/cli/describe.d.ts.map +1 -1
  42. package/dist/cli/describe.js +41 -0
  43. package/dist/cli/describe.js.map +1 -1
  44. package/dist/cli/document-schema.d.ts.map +1 -1
  45. package/dist/cli/document-schema.js +7 -0
  46. package/dist/cli/document-schema.js.map +1 -1
  47. package/dist/compose.d.ts +99 -0
  48. package/dist/compose.d.ts.map +1 -0
  49. package/dist/compose.js +245 -0
  50. package/dist/compose.js.map +1 -0
  51. package/dist/conformance/fixtures.d.ts.map +1 -1
  52. package/dist/conformance/fixtures.js +15 -5
  53. package/dist/conformance/fixtures.js.map +1 -1
  54. package/dist/days.d.ts +14 -1
  55. package/dist/days.d.ts.map +1 -1
  56. package/dist/days.js +17 -2
  57. package/dist/days.js.map +1 -1
  58. package/dist/document/brand-check.d.ts.map +1 -1
  59. package/dist/document/brand-check.js +6 -2
  60. package/dist/document/brand-check.js.map +1 -1
  61. package/dist/document/compile-checked.d.ts.map +1 -1
  62. package/dist/document/compile-checked.js +11 -5
  63. package/dist/document/compile-checked.js.map +1 -1
  64. package/dist/document/compiled.d.ts.map +1 -1
  65. package/dist/document/compiled.js +20 -4
  66. package/dist/document/compiled.js.map +1 -1
  67. package/dist/document/design-findings.d.ts +32 -0
  68. package/dist/document/design-findings.d.ts.map +1 -0
  69. package/dist/document/design-findings.js +593 -0
  70. package/dist/document/design-findings.js.map +1 -0
  71. package/dist/document/edit.d.ts +1 -1
  72. package/dist/document/edit.d.ts.map +1 -1
  73. package/dist/document/edit.js +303 -16
  74. package/dist/document/edit.js.map +1 -1
  75. package/dist/document/field-spec.d.ts.map +1 -1
  76. package/dist/document/field-spec.js +3 -2
  77. package/dist/document/field-spec.js.map +1 -1
  78. package/dist/document/findings.d.ts +8 -2
  79. package/dist/document/findings.d.ts.map +1 -1
  80. package/dist/document/findings.js +4 -3
  81. package/dist/document/findings.js.map +1 -1
  82. package/dist/document/graview-template.d.ts +3 -3
  83. package/dist/document/purpose-spec.d.ts +37 -0
  84. package/dist/document/purpose-spec.d.ts.map +1 -0
  85. package/dist/document/purpose-spec.js +41 -0
  86. package/dist/document/purpose-spec.js.map +1 -0
  87. package/dist/document/schema.d.ts +29 -11
  88. package/dist/document/schema.d.ts.map +1 -1
  89. package/dist/document/schema.js +26 -0
  90. package/dist/document/schema.js.map +1 -1
  91. package/dist/document/template.js +2 -2
  92. package/dist/document/template.js.map +1 -1
  93. package/dist/document/to-document.d.ts.map +1 -1
  94. package/dist/document/to-document.js +5 -1
  95. package/dist/document/to-document.js.map +1 -1
  96. package/dist/document.schema.json +146 -2
  97. package/dist/friction-record.d.ts +52 -0
  98. package/dist/friction-record.d.ts.map +1 -0
  99. package/dist/friction-record.js +36 -0
  100. package/dist/friction-record.js.map +1 -0
  101. package/dist/friction.d.ts +209 -0
  102. package/dist/friction.d.ts.map +1 -0
  103. package/dist/friction.js +302 -0
  104. package/dist/friction.js.map +1 -0
  105. package/dist/import/coerce.d.ts.map +1 -1
  106. package/dist/import/coerce.js +3 -1
  107. package/dist/import/coerce.js.map +1 -1
  108. package/dist/import/rows.d.ts +8 -0
  109. package/dist/import/rows.d.ts.map +1 -1
  110. package/dist/import/rows.js +19 -3
  111. package/dist/import/rows.js.map +1 -1
  112. package/dist/index.d.ts +5 -1
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +5 -1
  115. package/dist/index.js.map +1 -1
  116. package/dist/job-findings.d.ts +39 -0
  117. package/dist/job-findings.d.ts.map +1 -0
  118. package/dist/job-findings.js +171 -0
  119. package/dist/job-findings.js.map +1 -0
  120. package/dist/job-shape.d.ts +57 -0
  121. package/dist/job-shape.d.ts.map +1 -0
  122. package/dist/job-shape.js +5 -0
  123. package/dist/job-shape.js.map +1 -0
  124. package/dist/jobs.d.ts +62 -0
  125. package/dist/jobs.d.ts.map +1 -0
  126. package/dist/jobs.js +112 -0
  127. package/dist/jobs.js.map +1 -0
  128. package/dist/learn.d.ts +151 -0
  129. package/dist/learn.d.ts.map +1 -0
  130. package/dist/learn.js +520 -0
  131. package/dist/learn.js.map +1 -0
  132. package/dist/mutations/arg-shape.d.ts +2 -0
  133. package/dist/mutations/arg-shape.d.ts.map +1 -1
  134. package/dist/mutations/arg-shape.js +2 -2
  135. package/dist/mutations/arg-shape.js.map +1 -1
  136. package/dist/mutations/define-mutation.d.ts.map +1 -1
  137. package/dist/mutations/define-mutation.js +25 -2
  138. package/dist/mutations/define-mutation.js.map +1 -1
  139. package/dist/mutations/derive-edits.d.ts.map +1 -1
  140. package/dist/mutations/derive-edits.js +17 -3
  141. package/dist/mutations/derive-edits.js.map +1 -1
  142. package/dist/mutations/derive-relations.d.ts +8 -3
  143. package/dist/mutations/derive-relations.d.ts.map +1 -1
  144. package/dist/mutations/derive-relations.js +18 -7
  145. package/dist/mutations/derive-relations.js.map +1 -1
  146. package/dist/mutations/form.d.ts +2 -0
  147. package/dist/mutations/form.d.ts.map +1 -1
  148. package/dist/mutations/form.js +1 -1
  149. package/dist/mutations/form.js.map +1 -1
  150. package/dist/mutations/types.d.ts +7 -0
  151. package/dist/mutations/types.d.ts.map +1 -1
  152. package/dist/ops/tidying.d.ts.map +1 -1
  153. package/dist/ops/tidying.js +3 -0
  154. package/dist/ops/tidying.js.map +1 -1
  155. package/dist/schema/choice-words.d.ts +16 -0
  156. package/dist/schema/choice-words.d.ts.map +1 -0
  157. package/dist/schema/choice-words.js +31 -0
  158. package/dist/schema/choice-words.js.map +1 -0
  159. package/dist/schema/define-node.d.ts +2 -1
  160. package/dist/schema/define-node.d.ts.map +1 -1
  161. package/dist/schema/define-node.js +3 -15
  162. package/dist/schema/define-node.js.map +1 -1
  163. package/dist/schema/humanize.d.ts +3 -0
  164. package/dist/schema/humanize.d.ts.map +1 -0
  165. package/dist/schema/humanize.js +18 -0
  166. package/dist/schema/humanize.js.map +1 -0
  167. package/dist/schema/json-schema.d.ts.map +1 -1
  168. package/dist/schema/json-schema.js +2 -1
  169. package/dist/schema/json-schema.js.map +1 -1
  170. package/dist/schema/reading.d.ts.map +1 -1
  171. package/dist/schema/reading.js +10 -2
  172. package/dist/schema/reading.js.map +1 -1
  173. package/dist/schema/types.d.ts +9 -0
  174. package/dist/schema/types.d.ts.map +1 -1
  175. package/dist/search.d.ts.map +1 -1
  176. package/dist/search.js +2 -0
  177. package/dist/search.js.map +1 -1
  178. package/dist/sync/connection.js +1 -1
  179. package/dist/theme/accent.d.ts.map +1 -1
  180. package/dist/theme/accent.js +2 -2
  181. package/dist/theme/accent.js.map +1 -1
  182. package/dist/theme/derive.d.ts +10 -1
  183. package/dist/theme/derive.d.ts.map +1 -1
  184. package/dist/theme/derive.js +1 -1
  185. package/dist/theme/derive.js.map +1 -1
  186. package/dist/theme/ground-check.d.ts +12 -0
  187. package/dist/theme/ground-check.d.ts.map +1 -1
  188. package/dist/theme/ground-check.js +37 -11
  189. package/dist/theme/ground-check.js.map +1 -1
  190. package/dist/theme/ground.d.ts +28 -7
  191. package/dist/theme/ground.d.ts.map +1 -1
  192. package/dist/theme/ground.js +62 -18
  193. package/dist/theme/ground.js.map +1 -1
  194. package/dist/tidying.d.ts +10 -0
  195. package/dist/tidying.d.ts.map +1 -1
  196. package/dist/tidying.js +17 -0
  197. package/dist/tidying.js.map +1 -1
  198. package/dist/version.d.ts +1 -1
  199. package/dist/version.js +1 -1
  200. package/dist/when-typed.d.ts +7 -0
  201. package/dist/when-typed.d.ts.map +1 -1
  202. package/dist/when-typed.js +24 -0
  203. package/dist/when-typed.js.map +1 -1
  204. package/dist/words.d.ts +1 -1
  205. package/dist/words.d.ts.map +1 -1
  206. package/dist/words.js +1 -1
  207. package/dist/words.js.map +1 -1
  208. package/package.json +17 -1
@@ -0,0 +1,171 @@
1
+ import { listFieldsOf } from "./arrangement.js";
2
+ import { documentRelationActOf } from "./document/relation-acts.js";
3
+ import { error } from "./document/findings.js";
4
+ import { PurposeSpec } from "./document/purpose-spec.js";
5
+ import { documentListFields } from "./kind-list.js";
6
+ import { derivedActOf, givenWhenNeverArchived } from "./mutations/derived-names.js";
7
+ import { deriveMutations, subjectKindsOf } from "./mutations/derive-edits.js";
8
+ import { linkedEdges, localEdges } from "./schema/linked.js";
9
+ import { analyzeExpr } from "./document/expr/analyze.js";
10
+ import { ExprSyntaxError, parseExpr } from "./document/expr/parse.js";
11
+ import { gridSortOf } from "./grid-sort.js";
12
+ import { MOST_JOBS } from "./job-shape.js";
13
+ const quotedList = (names) => [...names].map((name) => `"${name}"`).join(", ") || "none";
14
+ /** What is wrong with one job's `where`, said in sentences, or nothing. */
15
+ function whereProblems(job, kind, world) {
16
+ if (job.where === undefined)
17
+ return [];
18
+ let shape;
19
+ try {
20
+ shape = analyzeExpr(parseExpr(job.where));
21
+ }
22
+ catch (e) {
23
+ if (!(e instanceof ExprSyntaxError))
24
+ throw e;
25
+ return [`its where does not read: ${e.sentence} (at character ${e.at + 1})`];
26
+ }
27
+ const problems = [];
28
+ for (const fn of shape.unknownFunctions)
29
+ problems.push(`its where calls "${fn}", which is not a function the rule language knows`);
30
+ const edges = new Set([...world.kinds.values()].flatMap((k) => [...k.edges]));
31
+ for (const name of shape.names) {
32
+ if (name.startsWith("$") || name === "id" || name === "label" || kind.fields[name] || kind.edges.has(name) || kind.computed.includes(name))
33
+ continue;
34
+ problems.push(`its where reads "${name}", and ${job.kind} has no field, relation or computed field called that`);
35
+ }
36
+ for (const edge of shape.edges)
37
+ if (!edges.has(edge))
38
+ problems.push(`its where walks "${edge}", which is not a relation any kind declares`);
39
+ for (const swept of shape.sweeps)
40
+ if (!world.kinds.has(swept))
41
+ problems.push(`its where reads all('${swept}'), and "${swept}" is not a kind of this app`);
42
+ return problems;
43
+ }
44
+ /** Every finding about an app's jobs, in the order they stand. */
45
+ export function jobFindings(purpose, world) {
46
+ const jobs = purpose?.jobs ?? [];
47
+ const out = [];
48
+ if (jobs.length > MOST_JOBS) {
49
+ out.push({ code: "jobs-too-many", message: `The app declares ${jobs.length} jobs; at most ${MOST_JOBS} say what its people come to do.`, fix: `Keep the ${MOST_JOBS} that matter most, and fold the rest into them.` });
50
+ }
51
+ const named = new Map();
52
+ jobs.forEach((job, index) => {
53
+ const said = `The job "${job.name}"`;
54
+ const first = named.get(job.name);
55
+ if (first !== undefined)
56
+ out.push({ code: "job-name-taken", index, key: "name", message: `${said} is declared twice (jobs ${first} and ${index}).`, fix: "Give each job a name of its own." });
57
+ else
58
+ named.set(job.name, index);
59
+ const kind = world.kinds.get(job.kind);
60
+ if (!kind) {
61
+ out.push({ code: "job-kind", index, key: "kind", message: `${said} is answered by "${job.kind}", which is not a kind of this app.`, fix: `Name one of its kinds: ${quotedList(world.kinds.keys())}.` });
62
+ }
63
+ else {
64
+ for (const problem of whereProblems(job, kind, world))
65
+ out.push({ code: "job-where", index, key: "where", message: `${said} cannot be answered: ${problem}.`, fix: `Write it in the rule language over the fields of "${job.kind}" (${quotedList(Object.keys(kind.fields))}) and relations.` });
66
+ if (job.sort !== undefined) {
67
+ const sortable = ["label", ...Object.entries(kind.fields).filter(([, field]) => field.type !== "other").map(([name]) => name), ...kind.computed];
68
+ const by = gridSortOf(job.sort)?.by;
69
+ if (by === undefined || !sortable.includes(by)) {
70
+ const field = by === undefined ? undefined : kind.fields[by];
71
+ out.push({
72
+ code: "job-sort",
73
+ index,
74
+ key: "sort",
75
+ message: `${said} cannot be sorted by "${by ?? ""}": ${field ? "it is a field no list sorts by (a list, a file, a picture)" : `${job.kind} has no field or computed field called that`}.`,
76
+ fix: `Sort by ${quotedList(sortable)}.`,
77
+ });
78
+ }
79
+ }
80
+ }
81
+ if (job.act !== undefined) {
82
+ const on = world.actOn(job.act);
83
+ if (on === undefined)
84
+ out.push({ code: "job-act", index, key: "act", message: `${said} names "${job.act}" as what people do next, which is not an act of this app.`, fix: "Name an act whose subject is the job's kind, or leave act out." });
85
+ else if (kind && !on.includes(job.kind)) {
86
+ out.push({
87
+ code: "job-act-kind",
88
+ index,
89
+ key: "act",
90
+ message: `${said} names "${job.act}" as what people do next with its "${job.kind}" records, and "${job.act}" ${on.length === 0 ? "acts on no record" : `acts on ${quotedList(on)}`}.`,
91
+ fix: `Name an act that acts on "${job.kind}" records, or leave act out.`,
92
+ });
93
+ }
94
+ }
95
+ for (const role of job.roles ?? []) {
96
+ if (world.roles.has(role))
97
+ continue;
98
+ out.push({ code: "job-role", index, key: "roles", message: `${said} is for "${role}", which is not one of the app's roles.`, fix: world.roles.size > 0 ? `Name one of ${quotedList(world.roles)}, or leave roles out for everybody.` : "The app declares no roles; leave roles out, and the job is everybody's." });
99
+ }
100
+ });
101
+ return out;
102
+ }
103
+ /** A job finding's place in a document: `purpose.jobs.2.where`, or `purpose.jobs` for the list. */
104
+ export const documentJobPath = (finding) => `purpose.jobs${finding.index === undefined ? "" : `.${finding.index}${finding.key ? `.${finding.key}` : ""}`}`;
105
+ /** A document's jobs, judged with its own sentences at its own paths: what `compileDocument` and `graview check` say of one. */
106
+ export function documentJobFindings(document) {
107
+ if (document.purpose === undefined)
108
+ return [];
109
+ // The shape first, said as the compiler says a document's: a purpose that is not one is judged no further.
110
+ const parsed = PurposeSpec.safeParse(document.purpose);
111
+ if (!parsed.success) {
112
+ return parsed.error.issues.map((issue) => {
113
+ const path = ["purpose", ...issue.path.map(String)].join(".");
114
+ const keys = issue.keys;
115
+ return keys ? error("unknown-key", path, `${keys.map((k) => `"${k}"`).join(", ")} ${keys.length === 1 ? "is" : "are"} not part of a Graview document here`, "a purpose says for and jobs; a job says name, ask, kind, where, sort, act and roles") : error("shape", path, issue.message);
116
+ });
117
+ }
118
+ if (!document.purpose.jobs)
119
+ return [];
120
+ return jobFindings(document.purpose, jobWorldOfDocument(document)).map((finding) => error(finding.code, documentJobPath(finding), finding.message, finding.fix));
121
+ }
122
+ /** The roles a policy and its sights name, beside the ones declared. */
123
+ function rolesNamed(declared, parts) {
124
+ return new Set([...(declared ?? []), ...parts.flatMap((part) => (part.roles === "*" ? [] : part.roles))]);
125
+ }
126
+ /** What a compiled or TypeScript app's jobs may name: its kinds, every act it has (derived ones too) and its roles. */
127
+ export function jobWorldOfApp(app) {
128
+ const schema = app.schema;
129
+ const kinds = new Map();
130
+ for (const kind of schema.kinds) {
131
+ const definition = schema.tryDefinition(kind);
132
+ kinds.set(kind, { ...listFieldsOf(schema, kind), edges: new Set(Object.keys(definition?.edges ?? {})) });
133
+ }
134
+ const declared = app.mutations ?? [];
135
+ const acts = new Map([...declared, ...deriveMutations(schema, declared)].map((mutation) => [mutation.name, mutation]));
136
+ const policy = app.policy;
137
+ return {
138
+ kinds,
139
+ actOn: (name) => {
140
+ const mutation = acts.get(name);
141
+ return mutation ? subjectKindsOf(schema, mutation) : undefined;
142
+ },
143
+ roles: rolesNamed(policy?.roles, [...(policy?.grants ?? []), ...(policy?.sees ?? [])]),
144
+ };
145
+ }
146
+ /** What a document's jobs may name, read off the document alone: what an edit judges a job by before anything is compiled. */
147
+ export function jobWorldOfDocument(document) {
148
+ const kinds = new Map();
149
+ for (const [kind, spec] of Object.entries(document.kinds)) {
150
+ const listed = documentListFields(spec);
151
+ // A relation to another app's kind is kept in a field of the record that links (FR-171): read like a relation, sorted by nothing.
152
+ const linked = Object.fromEntries([...linkedEdges(spec.edges).keys()].map((name) => [name, { type: "other" }]));
153
+ kinds.set(kind, { fields: { ...listed.fields, ...linked }, computed: listed.computed, edges: new Set(Object.keys(localEdges(spec.edges))) });
154
+ }
155
+ const acts = document.acts ?? {};
156
+ return {
157
+ kinds,
158
+ actOn: (name) => {
159
+ const act = acts[name];
160
+ if (act)
161
+ return [act.on ?? []].flat();
162
+ const derived = derivedActOf(name);
163
+ if (derived && document.kinds[derived.kind] && (document.kinds[derived.kind].archives !== false || givenWhenNeverArchived(derived.act)))
164
+ return [derived.kind];
165
+ const relation = documentRelationActOf(name, document.kinds);
166
+ return relation ? [relation.kind] : undefined;
167
+ },
168
+ roles: rolesNamed(document.roles, [...(document.policy?.grants ?? []), ...(document.policy?.sees ?? [])]),
169
+ };
170
+ }
171
+ //# sourceMappingURL=job-findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-findings.js","sourceRoot":"","sources":["../src/job-findings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * WHO AN APP IS FOR AND WHAT THEY COME TO DO (Roadmap f-app-jobs).
3
+ *
4
+ * purpose: {
5
+ * for: "The couple and their planner, mostly on phones",
6
+ * jobs: [{ name: "unbooked-soon", ask: "What's still unbooked and due this month?",
7
+ * kind: "vendor", where: "status != 'booked' and due <= today() + 30", sort: "due", act: "book" }],
8
+ * }
9
+ *
10
+ * Until now nothing in a declaration said whom it served or what they come
11
+ * to it to find out, so every look was assembled field by field from a type
12
+ * table. A job is that question in the people's own words, and the answer as
13
+ * the framework can work it out: the records of one kind that a rule-language
14
+ * condition holds for (`where`, the record as its subject, as a computed field
15
+ * reads), in an order (`sort`, as a kind's list takes one), with the act
16
+ * people usually take next on one (`act`), for some roles or everybody.
17
+ *
18
+ * The same shape in a document (`purpose`) and in `defineApp({ purpose })`:
19
+ * `where` is the rule language's words in both, so a TypeScript app's jobs
20
+ * are judged and answered exactly as a document's are. `graview check` holds
21
+ * each to the declaration (`job-*`); `@graview/core/jobs` resolves them
22
+ * (`jobsOf`) and answers one as a seat may see it (`answerJob`).
23
+ */
24
+ export interface AppPurpose {
25
+ /** Who uses the app and where, in words: "The couple and their planner, mostly on phones". 1–300 characters. */
26
+ readonly for?: string;
27
+ /** What they come to do, at most twelve. */
28
+ readonly jobs?: readonly JobDeclaration[];
29
+ }
30
+ /** A job's order: a field, a computed field or `label`, lowest first — or `{ by, direction }`. */
31
+ export type JobSort = string | {
32
+ readonly by: string;
33
+ readonly direction?: "asc" | "desc";
34
+ };
35
+ export interface JobDeclaration {
36
+ /** Kebab-case, unique among the app's jobs, like an act's name: "unbooked-soon". */
37
+ readonly name: string;
38
+ /** The question in the people's own words: "What's still unbooked and due this month?" 1–200 characters. */
39
+ readonly ask: string;
40
+ /** The kind whose records answer it. */
41
+ readonly kind: string;
42
+ /** Which of them, in the rule language with the record as subject: "status != 'booked' and due <= today() + 30". Every one, unsaid. */
43
+ readonly where?: string;
44
+ /** The order the answer comes in. As they are stored, unsaid. */
45
+ readonly sort?: JobSort;
46
+ /** The act people usually take next on one: an act whose subject is the kind. */
47
+ readonly act?: string;
48
+ /** The roles the job is for. Everybody, unsaid. */
49
+ readonly roles?: readonly string[];
50
+ }
51
+ /** Whether a job is for a seat holding these roles: one that names no roles is everybody's. */
52
+ export declare const jobIsFor: (job: {
53
+ readonly roles?: readonly string[];
54
+ }, held: readonly string[] | undefined) => boolean;
55
+ /** The most jobs an app declares: past a dozen, the app is no longer saying what matters most. */
56
+ export declare const MOST_JOBS = 12;
57
+ //# sourceMappingURL=job-shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-shape.d.ts","sourceRoot":"","sources":["../src/job-shape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,WAAW,UAAU;IACzB,gHAAgH;IAChH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CAC3C;AAED,kGAAkG;AAClG,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;CAAE,CAAC;AAE5F,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4GAA4G;IAC5G,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,wCAAwC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uIAAuI;IACvI,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,iFAAiF;IACjF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,mDAAmD;IACnD,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,+FAA+F;AAC/F,eAAO,MAAM,QAAQ,GAAI,KAAK;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAAE,MAAM,SAAS,MAAM,EAAE,GAAG,SAAS,KAAG,OACA,CAAC;AAE7G,kGAAkG;AAClG,eAAO,MAAM,SAAS,KAAK,CAAC"}
@@ -0,0 +1,5 @@
1
+ /** Whether a job is for a seat holding these roles: one that names no roles is everybody's. */
2
+ export const jobIsFor = (job, held) => job.roles === undefined || job.roles.length === 0 || job.roles.some((role) => (held ?? []).includes(role));
3
+ /** The most jobs an app declares: past a dozen, the app is no longer saying what matters most. */
4
+ export const MOST_JOBS = 12;
5
+ //# sourceMappingURL=job-shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-shape.js","sourceRoot":"","sources":["../src/job-shape.ts"],"names":[],"mappings":"AAkDA,+FAA+F;AAC/F,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,GAA2C,EAAE,IAAmC,EAAW,EAAE,CACpH,GAAG,CAAC,KAAK,KAAK,SAAS,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AAE7G,kGAAkG;AAClG,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC"}
package/dist/jobs.d.ts ADDED
@@ -0,0 +1,62 @@
1
+ /**
2
+ * `@graview/core/jobs` — WHAT AN APP'S PEOPLE COME TO DO, ANSWERED
3
+ * (Roadmap f-app-jobs).
4
+ *
5
+ * `jobsOf(app)` reads the declaration's `purpose.jobs` in their whole form —
6
+ * each order said with its direction, the kind's plural beside it — and
7
+ * `jobsFor` narrows them to a seat's roles. `answerJob(store, job,
8
+ * principal)` answers one AS THAT SEAT SEES THE APP: the records of the
9
+ * job's kind its `where` holds for, read through `store.seenBy(principal)`,
10
+ * so a record kept from the seat is never counted, never sorted and never
11
+ * named, and a field kept from it reads as nothing.
12
+ *
13
+ * An entry of its own: a page that draws no job carries none of it, and the
14
+ * checker's sentences about jobs (`job-*`) are `graview check`'s.
15
+ */
16
+ import type { GraviewApp } from "./app.js";
17
+ import { type JobDeclaration } from "./job-shape.js";
18
+ import type { Principal } from "./permissions/types.js";
19
+ import type { AnySchema } from "./schema/schema.js";
20
+ import type { Store } from "./store.js";
21
+ export type { AppPurpose, JobDeclaration, JobSort } from "./job-shape.js";
22
+ export { jobIsFor, MOST_JOBS } from "./job-shape.js";
23
+ /** A job in its whole form: its order said with a direction, and what its kind is called. */
24
+ export interface ResolvedJob {
25
+ readonly name: string;
26
+ readonly ask: string;
27
+ readonly kind: string;
28
+ /** The kind's records, as people say them: "Vendors". */
29
+ readonly plural: string;
30
+ readonly where?: string;
31
+ readonly sort?: {
32
+ readonly by: string;
33
+ readonly direction: "asc" | "desc";
34
+ };
35
+ readonly act?: string;
36
+ readonly roles?: readonly string[];
37
+ }
38
+ /** A job answered: how many records, and which, in its order. */
39
+ export interface JobAnswer {
40
+ readonly count: number;
41
+ readonly ids: readonly string[];
42
+ }
43
+ /**
44
+ * THE APP'S JOBS, RESOLVED, in the order declared. A job over a kind the app
45
+ * does not have is left out: the checker says so (`job-kind`), and nothing
46
+ * could answer it.
47
+ */
48
+ export declare function jobsOf<S extends AnySchema>(app: GraviewApp<S>): readonly ResolvedJob[];
49
+ /** The jobs a seat holding these roles comes to do: the ones naming one of its roles, and the ones naming none. */
50
+ export declare function jobsFor<J extends {
51
+ readonly roles?: readonly string[];
52
+ }>(jobs: readonly J[], principal: Pick<Principal, "roles">): readonly J[];
53
+ /**
54
+ * A JOB ANSWERED AS THIS SEAT SEES IT: the live records of its kind the seat
55
+ * may see, those its `where` holds for (each read under the language's
56
+ * budget; one it cannot be read for is not counted), in its order — by a
57
+ * field, a computed field or `label`, the ones with none last — and their
58
+ * ids. A kind kept from the seat answers nothing; so does a `where` that
59
+ * does not parse.
60
+ */
61
+ export declare function answerJob<S extends AnySchema>(given: Store<S>, job: Pick<JobDeclaration, "kind" | "where" | "sort">, principal: Principal): JobAnswer;
62
+ //# sourceMappingURL=jobs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.d.ts","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAM3C,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAErD,6FAA6F;AAC7F,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC;IAC5E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpC;AAED,iEAAiE;AACjE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,SAAS,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,SAAS,WAAW,EAAE,CAoBtF;AAED,mHAAmH;AACnH,wBAAgB,OAAO,CAAC,CAAC,SAAS;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE,CAE/I;AAuBD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC,EAAE,SAAS,EAAE,SAAS,GAAG,SAAS,CAoCrJ"}
package/dist/jobs.js ADDED
@@ -0,0 +1,112 @@
1
+ import { shapesFor } from "./document/computed-values.js";
2
+ import { evaluateExpr, ExprEvalError, NodeSet } from "./document/expr/evaluate.js";
3
+ import { ExprSyntaxError, parseExpr } from "./document/expr/parse.js";
4
+ import { gridSortOf, sortForGrid } from "./grid-sort.js";
5
+ import { jobIsFor } from "./job-shape.js";
6
+ import { labelOf, pluralOf } from "./schema/define-node.js";
7
+ export { jobIsFor, MOST_JOBS } from "./job-shape.js";
8
+ /**
9
+ * THE APP'S JOBS, RESOLVED, in the order declared. A job over a kind the app
10
+ * does not have is left out: the checker says so (`job-kind`), and nothing
11
+ * could answer it.
12
+ */
13
+ export function jobsOf(app) {
14
+ const kinds = new Set(app.schema.kinds);
15
+ // A document compiled without the checker reads its purpose loosely: what is not a job is no job.
16
+ const declared = Array.isArray(app.purpose?.jobs) ? app.purpose.jobs : [];
17
+ return declared.flatMap((job) => {
18
+ if (typeof job !== "object" || job === null || typeof job.name !== "string" || typeof job.ask !== "string" || !kinds.has(job.kind))
19
+ return [];
20
+ const sort = gridSortOf(job.sort);
21
+ return [
22
+ {
23
+ name: job.name,
24
+ ask: job.ask,
25
+ kind: job.kind,
26
+ plural: pluralOf(app.schema, job.kind),
27
+ ...(job.where !== undefined ? { where: job.where } : {}),
28
+ ...(sort ? { sort } : {}),
29
+ ...(job.act !== undefined ? { act: job.act } : {}),
30
+ ...(job.roles && job.roles.length > 0 ? { roles: [...job.roles] } : {}),
31
+ },
32
+ ];
33
+ });
34
+ }
35
+ /** The jobs a seat holding these roles comes to do: the ones naming one of its roles, and the ones naming none. */
36
+ export function jobsFor(jobs, principal) {
37
+ return jobs.filter((job) => jobIsFor(job, principal.roles));
38
+ }
39
+ const PARSED = new Map();
40
+ /** An expression parsed once; one that does not parse is null (the checker said why). */
41
+ function parsed(source) {
42
+ if (!PARSED.has(source)) {
43
+ try {
44
+ PARSED.set(source, parseExpr(source));
45
+ }
46
+ catch (e) {
47
+ if (!(e instanceof ExprSyntaxError))
48
+ throw e;
49
+ PARSED.set(source, null);
50
+ }
51
+ }
52
+ return PARSED.get(source);
53
+ }
54
+ /** Whether a value the language gives counts as yes. */
55
+ const holds = (value) => (value instanceof NodeSet ? value.nodes.length > 0 : Array.isArray(value) ? value.length > 0 : Boolean(value));
56
+ /** A value to order by: a record as its name, a set as how many. */
57
+ const orderable = (schema, value) => value instanceof NodeSet ? value.nodes.length : value !== null && typeof value === "object" && !Array.isArray(value) ? labelOf(schema.tryDefinition(value.kind), value) : value;
58
+ /**
59
+ * A JOB ANSWERED AS THIS SEAT SEES IT: the live records of its kind the seat
60
+ * may see, those its `where` holds for (each read under the language's
61
+ * budget; one it cannot be read for is not counted), in its order — by a
62
+ * field, a computed field or `label`, the ones with none last — and their
63
+ * ids. A kind kept from the seat answers nothing; so does a `where` that
64
+ * does not parse.
65
+ */
66
+ export function answerJob(given, job, principal) {
67
+ const store = given;
68
+ if (store.kindsKeptFrom(principal).has(job.kind) || !store.schema.tryDefinition(job.kind))
69
+ return { count: 0, ids: [] };
70
+ const seen = store.seenBy(principal);
71
+ const graph = seen.graph;
72
+ const schema = seen.schema;
73
+ const kinds = shapesFor(schema);
74
+ const today = seen.today?.();
75
+ const read = (expr, node) => evaluateExpr(expr, { graph, subject: node, kinds, ...(today ? { today } : {}) });
76
+ const where = job.where === undefined ? undefined : parsed(job.where);
77
+ if (where === null)
78
+ return { count: 0, ids: [] };
79
+ const records = graph.nodesOfKind(job.kind).filter((node) => {
80
+ if (!where)
81
+ return true;
82
+ try {
83
+ return holds(read(where, node));
84
+ }
85
+ catch (e) {
86
+ if (!(e instanceof ExprEvalError))
87
+ throw e;
88
+ return false;
89
+ }
90
+ });
91
+ const sort = gridSortOf(job.sort);
92
+ const key = sort && sort.by !== "label" ? parsed(sort.by) : undefined;
93
+ const ordered = !sort
94
+ ? records
95
+ : sortForGrid(records, sort, (node) => {
96
+ if (sort.by === "label")
97
+ return labelOf(schema.tryDefinition(node.kind), node);
98
+ if (!key)
99
+ return undefined;
100
+ try {
101
+ return orderable(schema, read(key, node));
102
+ }
103
+ catch (e) {
104
+ if (!(e instanceof ExprEvalError))
105
+ throw e;
106
+ return undefined;
107
+ }
108
+ });
109
+ const ids = ordered.map((node) => node.id);
110
+ return { count: ids.length, ids };
111
+ }
112
+ //# sourceMappingURL=jobs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobs.js","sourceRoot":"","sources":["../src/jobs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * `@graview/core/learn` — APPS IMPROVE FROM USE (Roadmap f-learned-suggestions).
3
+ *
4
+ * The app's own actor ("Graview, tidying") suggests changes to records and
5
+ * a person accepts or declines each (`@graview/core/tidying`). This is the
6
+ * same actor suggesting changes to the APP — the declaration — from
7
+ * evidence of use: the words people searched with and found nothing
8
+ * (`@graview/core/friction`), the values a text field keeps repeating and
9
+ * the dates written into one (the records), the same two acts taken one
10
+ * after the other on one record (the op log), a place nobody opens (counts
11
+ * a host passes), and an agent's tool calls that went wrong.
12
+ *
13
+ * Each is offered only when at least `minPeople` distinct people show it —
14
+ * never one person's habit — and each is a suggestion, never a change:
15
+ * `learnFromUse` reads and writes nothing, `acceptAppSuggestion` applies a
16
+ * suggestion's edits through `editDocument` as one change with its lineage
17
+ * (`{ basis, suggestion }`), and `declineAppSuggestion` is a decision a host
18
+ * keeps (`LearnedStore`; `graview serve` keeps `learned.json` beside the
19
+ * store) and hands back as `declined`, so the same suggestion — by its
20
+ * `key`, stable across runs — is never offered again.
21
+ *
22
+ * Its own entry: a page draws nothing with it, and it reaches the editor.
23
+ */
24
+ import { type DocumentEdit, type EditOptions, type Fill } from "./document/edit.js";
25
+ import type { Finding } from "./document/findings.js";
26
+ import type { GraviewDocument } from "./document/schema.js";
27
+ import type { FrictionEvent } from "./friction.js";
28
+ import { type Lineage } from "./ops/lineage.js";
29
+ import type { Author, Operation } from "./ops/types.js";
30
+ /** One change to the app the actor suggests: its edits, what it would do and why, and how many people showed it. */
31
+ export interface AppSuggestion {
32
+ /** Who it is, the same on every run: a decline holds by it. At most 120 characters. */
33
+ readonly key: string;
34
+ /** The edits that make it, as `editDocument` takes them. */
35
+ readonly edits: readonly DocumentEdit[];
36
+ /** What it would change, in a sentence. */
37
+ readonly said: string;
38
+ /** What it is based on, in a sentence: the lineage's `basis` once accepted. */
39
+ readonly why: string;
40
+ /** How many distinct people showed it, and how many times. */
41
+ readonly evidence: {
42
+ readonly people: number;
43
+ readonly times: number;
44
+ };
45
+ }
46
+ /** A record, as the graph holds it. */
47
+ export type LearnedRecord = {
48
+ readonly id: string;
49
+ readonly kind: string;
50
+ } & Readonly<Record<string, unknown>>;
51
+ /** A person's answer to a suggestion, kept where the host keeps the app's other state. */
52
+ export interface LearnedDecision {
53
+ readonly key: string;
54
+ readonly answer: "accepted" | "declined";
55
+ readonly at: string;
56
+ readonly by?: Author;
57
+ /** What the suggestion would have changed, as it was said. */
58
+ readonly said?: string;
59
+ }
60
+ export interface LearnInput {
61
+ /** The app, as a document (`documentOf(app) ?? toDocument(app).document`). */
62
+ readonly document: GraviewDocument;
63
+ /** What people could not do, as the host keeps it (`friction.json` beside a served store). */
64
+ readonly friction?: readonly FrictionEvent[];
65
+ /** The store's op log: who wrote what, and the acts people take one after another. */
66
+ readonly log?: readonly Operation[];
67
+ /** The graph's records: the values a field keeps. Who wrote each is read from `log`. */
68
+ readonly records?: readonly LearnedRecord[];
69
+ /** What was answered before — decisions, or their keys alone — never offered again. */
70
+ readonly declined?: readonly (string | {
71
+ readonly key: string;
72
+ })[];
73
+ /**
74
+ * HOW MANY PEOPLE OPENED EACH PLACE, by its slug (`placeSlug(title)`), over
75
+ * a window the host chose. The framework does not see a place open; a host
76
+ * with analytics passes the counts. A declared place at 0 while another
77
+ * was opened by `minPeople` or more is suggested hidden.
78
+ */
79
+ readonly opens?: Readonly<Record<string, number>>;
80
+ /** The fewest distinct people a suggestion rests on: 3 unsaid, never fewer than 2. */
81
+ readonly minPeople?: number;
82
+ }
83
+ /** What the actor learned: the suggestions, and what it saw and could not suggest, with why. */
84
+ export interface Learned {
85
+ readonly suggestions: readonly AppSuggestion[];
86
+ readonly skipped: readonly {
87
+ readonly key: string;
88
+ readonly why: string;
89
+ }[];
90
+ }
91
+ /** The judge's name on what it suggests and what an accepted suggestion changes (`lineage.actor`). */
92
+ export declare const LEARNING_ACTOR = "learns from use";
93
+ /** The suggestions, with what the actor saw and could not suggest, and why. */
94
+ export declare function learningFrom(input: LearnInput): Learned;
95
+ /**
96
+ * WHAT THE APP'S OWN ACTOR SUGGESTS CHANGING IN THE APP, from evidence of
97
+ * use. Reads and writes nothing; a person accepts each
98
+ * (`acceptAppSuggestion`) or declines it (`declineAppSuggestion`).
99
+ */
100
+ export declare function learnFromUse(input: LearnInput): AppSuggestion[];
101
+ export interface AnswerOptions {
102
+ /** Who answered. */
103
+ readonly by?: Author;
104
+ /** When, as an ISO time; now unsaid. */
105
+ readonly at?: string;
106
+ }
107
+ export type AcceptedSuggestion = {
108
+ readonly ok: true;
109
+ readonly document: GraviewDocument;
110
+ /** What the edits did, in the editor's words. */
111
+ readonly said: readonly string[];
112
+ /** Values for records already there, for the migration (`editDocument`'s). */
113
+ readonly fills: readonly Fill[];
114
+ /** What the change is based on: the suggestion's why, and its key. */
115
+ readonly lineage: Lineage;
116
+ /** The answer, for the host to keep beside its other decisions. */
117
+ readonly decision: LearnedDecision;
118
+ } | {
119
+ readonly ok: false;
120
+ readonly findings: readonly Finding[];
121
+ };
122
+ /**
123
+ * ACCEPT A SUGGESTION: its edits applied to the document through
124
+ * `editDocument`, as one change, carrying its lineage — `{ basis: why,
125
+ * suggestion: key }` — and the decision the host keeps. The caller compiles,
126
+ * checks and keeps the document as it keeps any other change; an edit that
127
+ * no longer applies is refused with the editor's findings.
128
+ */
129
+ export declare function acceptAppSuggestion(document: GraviewDocument, suggestion: AppSuggestion, options?: AnswerOptions & EditOptions): AcceptedSuggestion;
130
+ /** DECLINE A SUGGESTION: the decision a host keeps and hands back as `declined`, so it is never offered again. Changes nothing. */
131
+ export declare function declineAppSuggestion(suggestion: AppSuggestion | string, options?: AnswerOptions): LearnedDecision;
132
+ /**
133
+ * WHERE A HOST KEEPS WHAT PEOPLE ANSWERED: append and read back.
134
+ * `memoryLearned` here; `fileLearned` (`learned.json` beside the store,
135
+ * where `graview serve` keeps the friction log) in `@graview/ship`; a host's
136
+ * own anywhere — Graview Cloud beside an app's document versions.
137
+ */
138
+ export interface LearnedStore {
139
+ add(decision: LearnedDecision): void | Promise<void>;
140
+ list(): readonly LearnedDecision[] | Promise<readonly LearnedDecision[]>;
141
+ }
142
+ /** A store that answers at once. */
143
+ export interface HeldLearned extends LearnedStore {
144
+ add(decision: LearnedDecision): void;
145
+ list(): readonly LearnedDecision[];
146
+ }
147
+ /** The decisions kept, one per key: the latest answer stands. */
148
+ export declare function keptDecisions(decisions: readonly LearnedDecision[]): readonly LearnedDecision[];
149
+ /** Answers kept in memory for as long as the process runs. */
150
+ export declare function memoryLearned(): HeldLearned;
151
+ //# sourceMappingURL=learn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"learn.d.ts","sourceRoot":"","sources":["../src/learn.ts"],"names":[],"mappings":"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"}