@batalabs/virlow-mcp-core 3.18.0 → 3.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/LICENSE +8 -18
  2. package/README.md +1 -1
  3. package/dist/api.d.ts +32 -0
  4. package/dist/api.d.ts.map +1 -1
  5. package/dist/api.js +38 -5
  6. package/dist/api.js.map +1 -1
  7. package/dist/attrs-extract.d.ts +48 -0
  8. package/dist/attrs-extract.d.ts.map +1 -0
  9. package/dist/attrs-extract.js +153 -0
  10. package/dist/attrs-extract.js.map +1 -0
  11. package/dist/attrs.d.ts +445 -0
  12. package/dist/attrs.d.ts.map +1 -0
  13. package/dist/attrs.js +604 -0
  14. package/dist/attrs.js.map +1 -0
  15. package/dist/cjs/api.d.ts +32 -0
  16. package/dist/cjs/api.js +38 -5
  17. package/dist/cjs/attrs-extract.d.ts +47 -0
  18. package/dist/cjs/attrs-extract.js +159 -0
  19. package/dist/cjs/attrs.d.ts +444 -0
  20. package/dist/cjs/attrs.js +635 -0
  21. package/dist/cjs/index.d.ts +5 -1
  22. package/dist/cjs/index.js +22 -1
  23. package/dist/cjs/memories.d.ts +79 -1
  24. package/dist/cjs/memories.js +249 -15
  25. package/dist/cjs/memory-graph.d.ts +105 -0
  26. package/dist/cjs/memory-graph.js +270 -0
  27. package/dist/cjs/memory-note.d.ts +57 -0
  28. package/dist/cjs/memory-note.js +174 -10
  29. package/dist/cjs/memory-secrets.d.ts +19 -0
  30. package/dist/cjs/memory-secrets.js +108 -0
  31. package/dist/cjs/notes.d.ts +208 -2
  32. package/dist/cjs/notes.js +721 -12
  33. package/dist/http/index.d.ts +4 -0
  34. package/dist/http/index.d.ts.map +1 -0
  35. package/dist/http/index.js +3 -0
  36. package/dist/http/index.js.map +1 -0
  37. package/dist/http/local-origin.d.ts +61 -0
  38. package/dist/http/local-origin.d.ts.map +1 -0
  39. package/dist/http/local-origin.js +92 -0
  40. package/dist/http/local-origin.js.map +1 -0
  41. package/dist/http/server.d.ts +39 -0
  42. package/dist/http/server.d.ts.map +1 -0
  43. package/dist/http/server.js +131 -0
  44. package/dist/http/server.js.map +1 -0
  45. package/dist/index.d.ts +5 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +2 -0
  48. package/dist/index.js.map +1 -1
  49. package/dist/memories.d.ts +79 -1
  50. package/dist/memories.d.ts.map +1 -1
  51. package/dist/memories.js +249 -15
  52. package/dist/memories.js.map +1 -1
  53. package/dist/memory-graph.d.ts +106 -0
  54. package/dist/memory-graph.d.ts.map +1 -0
  55. package/dist/memory-graph.js +258 -0
  56. package/dist/memory-graph.js.map +1 -0
  57. package/dist/memory-note.d.ts +57 -0
  58. package/dist/memory-note.d.ts.map +1 -1
  59. package/dist/memory-note.js +170 -10
  60. package/dist/memory-note.js.map +1 -1
  61. package/dist/memory-secrets.d.ts +20 -0
  62. package/dist/memory-secrets.d.ts.map +1 -0
  63. package/dist/memory-secrets.js +103 -0
  64. package/dist/memory-secrets.js.map +1 -0
  65. package/dist/notes.d.ts +208 -2
  66. package/dist/notes.d.ts.map +1 -1
  67. package/dist/notes.js +722 -13
  68. package/dist/notes.js.map +1 -1
  69. package/dist/tools.d.ts +8 -2
  70. package/dist/tools.d.ts.map +1 -1
  71. package/dist/tools.js +465 -10
  72. package/dist/tools.js.map +1 -1
  73. package/package.json +21 -5
@@ -0,0 +1,258 @@
1
+ /** The matching key for a name: case, spacing and a leading article do not
2
+ * make a different entity. */
3
+ export function entityKey(name) {
4
+ return name
5
+ .trim()
6
+ .toLowerCase()
7
+ .replace(/\s+/g, ' ')
8
+ .replace(/^the /, '');
9
+ }
10
+ /**
11
+ * Predicates where one side holds one value at a time, so a new fact ends
12
+ * the old one. Which side matters:
13
+ * - one object per subject: a person works at one place, reports to one
14
+ * manager (Dana works_at Acme, then Dana works_at Initech);
15
+ * - one subject per object: a project has one lead (Dana leads Atlas, then
16
+ * Sam leads Atlas).
17
+ * Anything else accumulates (prefers, uses, knows).
18
+ */
19
+ export const ONE_OBJECT_PER_SUBJECT = new Set([
20
+ 'led_by',
21
+ 'owned_by',
22
+ 'managed_by',
23
+ 'reports_to',
24
+ 'works_at',
25
+ 'lives_in',
26
+ 'based_in',
27
+ 'located_in',
28
+ 'role',
29
+ 'status',
30
+ 'title',
31
+ ]);
32
+ export const ONE_SUBJECT_PER_OBJECT = new Set(['leads', 'owns', 'manages']);
33
+ /** Either kind: a predicate that holds one value at a time. */
34
+ export const SINGLE_VALUED = new Set([...ONE_OBJECT_PER_SUBJECT, ...ONE_SUBJECT_PER_OBJECT]);
35
+ /** snake_case, so "Works at" and "works_at" are one predicate. */
36
+ export function normalizePredicate(p) {
37
+ return p
38
+ .trim()
39
+ .toLowerCase()
40
+ .replace(/[\s-]+/g, '_')
41
+ .replace(/[^a-z0-9_]/g, '');
42
+ }
43
+ /** A date or ISO timestamp as comparable milliseconds; bare dates are the
44
+ * start of that UTC day. */
45
+ function when(value) {
46
+ if (!value)
47
+ return null;
48
+ const t = Date.parse(value.length === 10 ? `${value}T00:00:00Z` : value);
49
+ return Number.isNaN(t) ? null : t;
50
+ }
51
+ /** Whether a span held at `at`: started on or before it, ended after it. */
52
+ export function heldAt(from, to, at) {
53
+ const start = when(from);
54
+ const end = when(to);
55
+ if (start !== null && start > at)
56
+ return false;
57
+ if (end !== null && end <= at)
58
+ return false;
59
+ return true;
60
+ }
61
+ /**
62
+ * Whether a memory's fact held at `at`. It starts at `valid_from`, else the
63
+ * earliest date its relations give (a fact about "since January" learned
64
+ * today started in January), else when it was learned.
65
+ */
66
+ export function memoryHeldAt(memory, at) {
67
+ const relationStarts = (memory.meta.relations ?? [])
68
+ .map((r) => r.from)
69
+ .filter((f) => !!f && when(f) !== null)
70
+ .sort((a, b) => when(a) - when(b));
71
+ const start = memory.meta.validFrom ?? relationStarts[0] ?? memory.meta.created;
72
+ return heldAt(start, memory.meta.validTo, at);
73
+ }
74
+ export function buildGraph(memories) {
75
+ const entities = new Map();
76
+ const spellings = new Map();
77
+ const edges = [];
78
+ const touch = (name, memoryId) => {
79
+ const key = entityKey(name);
80
+ let entity = entities.get(key);
81
+ if (!entity) {
82
+ entity = { key, name: name.trim(), memoryIds: new Set(), edges: [] };
83
+ entities.set(key, entity);
84
+ spellings.set(key, new Map());
85
+ }
86
+ entity.memoryIds.add(memoryId);
87
+ const counts = spellings.get(key);
88
+ counts.set(name.trim(), (counts.get(name.trim()) ?? 0) + 1);
89
+ return entity;
90
+ };
91
+ for (const memory of memories) {
92
+ for (const name of memory.meta.about ?? [])
93
+ touch(name, memory.id);
94
+ for (const relation of memory.meta.relations ?? []) {
95
+ const edge = { ...relation, p: normalizePredicate(relation.p), memoryId: memory.id };
96
+ edges.push(edge);
97
+ touch(relation.s, memory.id).edges.push(edge);
98
+ // The object is an entity only if something else names it as one;
99
+ // "async standups" as the object of prefers stays a literal.
100
+ const objectKey = entityKey(relation.o);
101
+ if (entities.has(objectKey) || isEntityLike(relation.o)) {
102
+ touch(relation.o, memory.id).edges.push(edge);
103
+ }
104
+ }
105
+ }
106
+ for (const [key, counts] of spellings) {
107
+ const [best] = [...counts.entries()].sort((a, b) => b[1] - a[1]);
108
+ if (best)
109
+ entities.get(key).name = best[0];
110
+ }
111
+ return { entities, edges };
112
+ }
113
+ /** A capitalised name reads as an entity (Atlas, Dana Whitfield, Fly.io);
114
+ * a lower-case phrase reads as a value (async standups, dark mode). */
115
+ function isEntityLike(value) {
116
+ return /^[A-Z0-9]/.test(value.trim());
117
+ }
118
+ /** Entities named in a piece of text (a prompt, a query), longest names
119
+ * first so "Dana Whitfield" wins over "Dana". Whole words only. */
120
+ export function entitiesMentioned(graph, text) {
121
+ // Dots survive only inside a name (Fly.io); a full stop after a word
122
+ // would otherwise hide the word.
123
+ const haystack = ` ${text
124
+ .toLowerCase()
125
+ .replace(/[^a-z0-9.\s]/g, ' ')
126
+ .replace(/\.(?![a-z0-9])|(?<![a-z0-9])\./g, ' ')
127
+ .replace(/\s+/g, ' ')} `;
128
+ const found = [];
129
+ const byLength = [...graph.entities.values()].sort((a, b) => b.key.length - a.key.length);
130
+ let remaining = haystack;
131
+ for (const entity of byLength) {
132
+ const needle = ` ${entity.key} `;
133
+ if (entity.key.length < 2 || !remaining.includes(needle))
134
+ continue;
135
+ found.push(entity);
136
+ remaining = remaining.split(needle).join(' ');
137
+ }
138
+ return found;
139
+ }
140
+ /** Entities one relation away from any of `from`. */
141
+ export function neighbours(graph, from) {
142
+ const seen = new Set(from.map((e) => e.key));
143
+ const result = [];
144
+ for (const entity of from) {
145
+ for (const edge of entity.edges) {
146
+ for (const end of [edge.s, edge.o]) {
147
+ const key = entityKey(end);
148
+ const other = graph.entities.get(key);
149
+ if (other && !seen.has(key)) {
150
+ seen.add(key);
151
+ result.push(other);
152
+ }
153
+ }
154
+ }
155
+ }
156
+ return result;
157
+ }
158
+ /** How much the graph and recency move a similarity score. Small on
159
+ * purpose: similarity still decides, the graph breaks ties and pulls in
160
+ * facts that share an entity with the query but none of its words. */
161
+ export const DIRECT_BOOST = 0.15;
162
+ export const NEIGHBOUR_BOOST = 0.07;
163
+ const RECENCY_WEIGHT = 0.08;
164
+ const RECENCY_HORIZON_DAYS = 365;
165
+ export function rankMemories(graph, query, scored, opts) {
166
+ const at = opts.at ?? Date.now();
167
+ const direct = entitiesMentioned(graph, query);
168
+ const near = neighbours(graph, direct);
169
+ const directIds = new Set(direct.flatMap((e) => [...e.memoryIds]));
170
+ const nearIds = new Set(near.flatMap((e) => [...e.memoryIds]));
171
+ return scored
172
+ .filter(({ memory }) => opts.includeHistory || memoryHeldAt(memory, at))
173
+ .map((item) => {
174
+ let score = item.similarity;
175
+ if (directIds.has(item.memory.id))
176
+ score += DIRECT_BOOST;
177
+ else if (nearIds.has(item.memory.id))
178
+ score += NEIGHBOUR_BOOST;
179
+ const updated = Date.parse(item.memory.updatedAt);
180
+ if (!Number.isNaN(updated)) {
181
+ const ageDays = Math.max(0, (at - updated) / 86_400_000);
182
+ score -= RECENCY_WEIGHT * Math.min(1, ageDays / RECENCY_HORIZON_DAYS);
183
+ }
184
+ return { ...item, score };
185
+ })
186
+ .sort((a, b) => b.score - a.score)
187
+ .slice(0, opts.limit);
188
+ }
189
+ /**
190
+ * Current edges a new relation replaces: same subject and single-valued
191
+ * predicate, a different object, still holding when the new one starts.
192
+ */
193
+ export function supersededBy(graph, relation, at) {
194
+ const p = normalizePredicate(relation.p);
195
+ const s = entityKey(relation.s);
196
+ const o = entityKey(relation.o);
197
+ const bySubject = ONE_OBJECT_PER_SUBJECT.has(p);
198
+ const byObject = ONE_SUBJECT_PER_OBJECT.has(p);
199
+ if (!bySubject && !byObject)
200
+ return [];
201
+ return graph.edges.filter((edge) => {
202
+ if (edge.p !== p || !heldAt(edge.from, edge.to, at))
203
+ return false;
204
+ const es = entityKey(edge.s);
205
+ const eo = entityKey(edge.o);
206
+ if (es === s && eo === o)
207
+ return false;
208
+ return bySubject ? es === s : eo === o;
209
+ });
210
+ }
211
+ /**
212
+ * Housekeeping findings for a tidy pass: memories linked to nothing, names
213
+ * that look like one entity spelled two ways, and single-valued predicates
214
+ * holding two values at once.
215
+ */
216
+ export function graphHealth(graph, memories, at = Date.now()) {
217
+ const unlinked = memories
218
+ .filter((m) => !(m.meta.about?.length || m.meta.relations?.length))
219
+ .map((m) => m.id);
220
+ const names = [...graph.entities.values()];
221
+ const possibleDuplicates = [];
222
+ for (let i = 0; i < names.length; i++) {
223
+ for (let j = i + 1; j < names.length; j++) {
224
+ const a = names[i].key;
225
+ const b = names[j].key;
226
+ const [short, long] = a.length <= b.length ? [a, b] : [b, a];
227
+ // "dana" and "dana whitfield": one name is the first word(s) of the other.
228
+ if (short.length >= 3 && long.startsWith(`${short} `)) {
229
+ possibleDuplicates.push([names[i].name, names[j].name]);
230
+ }
231
+ }
232
+ }
233
+ const contradictions = [];
234
+ // Keyed on the side that must be unique: the subject for works_at, the
235
+ // object for leads. `values` are the other side.
236
+ const current = new Map();
237
+ for (const edge of graph.edges) {
238
+ if (!SINGLE_VALUED.has(edge.p) || !heldAt(edge.from, edge.to, at))
239
+ continue;
240
+ const bySubject = ONE_OBJECT_PER_SUBJECT.has(edge.p);
241
+ const anchor = bySubject ? edge.s : edge.o;
242
+ const key = `${entityKey(anchor)}|${edge.p}`;
243
+ if (!current.has(key))
244
+ current.set(key, { anchor, predicate: edge.p, values: new Set() });
245
+ current.get(key).values.add(bySubject ? edge.o : edge.s);
246
+ }
247
+ for (const [key, { anchor, predicate, values }] of current) {
248
+ if (values.size < 2)
249
+ continue;
250
+ contradictions.push({
251
+ subject: graph.entities.get(key.split('|')[0])?.name ?? anchor,
252
+ predicate,
253
+ objects: [...values],
254
+ });
255
+ }
256
+ return { unlinked, possibleDuplicates, contradictions };
257
+ }
258
+ //# sourceMappingURL=memory-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-graph.js","sourceRoot":"","sources":["../src/memory-graph.ts"],"names":[],"mappings":"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"}
@@ -14,10 +14,51 @@ export interface MemoryMeta {
14
14
  confidence?: string;
15
15
  /** ISO timestamp of the first write; never overwritten by later updates. */
16
16
  created?: string;
17
+ /**
18
+ * `html` when the fact was written in the app's rich editor, so the body
19
+ * after the frontmatter is TipTap HTML rather than plain text. Absent
20
+ * means plain text, which is what the connector always writes: AI tools
21
+ * read and write text, and the app renders it as paragraphs.
22
+ */
23
+ format?: 'html';
24
+ /**
25
+ * The graph: the entities this fact is about (people, projects, places,
26
+ * tools), by name. Names are matched case-insensitively across memories,
27
+ * so every memory that says "Atlas" is about the same Atlas.
28
+ */
29
+ about?: string[];
30
+ /** Typed links the fact asserts, e.g. Sam leads Atlas. A relation lives on
31
+ * the memory that asserted it, so every edge has a source to open, check
32
+ * or delete. */
33
+ relations?: MemoryRelation[];
34
+ /** When the fact became true (YYYY-MM-DD or ISO). Absent: when it was
35
+ * learned (`created`). */
36
+ validFrom?: string;
37
+ /** When the fact stopped being true. Facts are ended, never deleted, when
38
+ * they are superseded, so history stays answerable. */
39
+ validTo?: string;
40
+ /** The memory that replaced this one, when one did. */
41
+ supersededBy?: string;
42
+ }
43
+ /**
44
+ * One edge: subject, predicate, object. `p` is a short verb phrase in
45
+ * snake_case ("leads", "works_at", "prefers"); `o` is an entity name or a
46
+ * literal ("async standups"). `from` and `to` bound when it held.
47
+ */
48
+ export interface MemoryRelation {
49
+ s: string;
50
+ p: string;
51
+ o: string;
52
+ from?: string;
53
+ to?: string;
17
54
  }
18
55
  export interface ParsedMemoryNote {
56
+ /** The fact as plain text: what AI tools read, what gets embedded. For an
57
+ * HTML body, its text with line breaks and list markers kept. */
19
58
  fact: string;
20
59
  meta: MemoryMeta;
60
+ /** The body as written, when `meta.format` is `html`. */
61
+ html?: string;
21
62
  }
22
63
  /**
23
64
  * The note type a memory is written as.
@@ -36,6 +77,20 @@ export declare const MEMORY_NOTE_TYPE = "memory";
36
77
  * (or a test) can build a legacy body and confirm it still reads.
37
78
  */
38
79
  export declare function toCodeEnvelope(body: string): string;
80
+ /**
81
+ * A rich fact as text an AI can read: one line per paragraph, heading or
82
+ * list item, list items marked, code and inline marks reduced to their text.
83
+ * Entities are decoded, so a fact that talks about `<p>` tags reads back as
84
+ * exactly that.
85
+ */
86
+ export declare function memoryHtmlToText(html: string): string;
87
+ /**
88
+ * Plain text as the rich editor's HTML: a paragraph per blank-line-separated
89
+ * block, single line breaks kept, everything escaped. Used to open a
90
+ * connector-written (plain) memory in the editor.
91
+ */
92
+ export declare function memoryTextToHtml(text: string): string;
93
+ export declare function looksLikeHtml(fact: string): boolean;
39
94
  /**
40
95
  * Split a decrypted note body into its fact and metadata.
41
96
  *
@@ -50,6 +105,8 @@ export declare function parseMemoryNote(decryptedContent: string): ParsedMemoryN
50
105
  * there is no metadata to record.
51
106
  */
52
107
  export declare function serializeMemoryBody(fact: string, meta: MemoryMeta): string;
108
+ /** The app's rich editor output, marked as HTML. */
109
+ export declare function serializeMemoryHtml(html: string, meta: MemoryMeta): string;
53
110
  /**
54
111
  * Metadata for an update: named keys win, unnamed keys carry forward, and
55
112
  * `created` is pinned to the first write so an in-place dedupe merge cannot
@@ -1 +1 @@
1
- {"version":3,"file":"memory-note.d.ts","sourceRoot":"","sources":["../src/memory-note.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;CAClB;AAOD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,WAAW,CAAC;AAEzC;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAiDD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,gBAAgB,CAgC1E;AAUD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAsB1E;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,UAAU,CAW/E"}
1
+ {"version":3,"file":"memory-note.d.ts","sourceRoot":"","sources":["../src/memory-note.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB;;qBAEiB;IACjB,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;IAC7B;+BAC2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;4DACwD;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B;sEACkE;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAqDD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,WAAW,CAAC;AAEzC;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAsED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBrD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMrD;AAYD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEnD;AASD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,gBAAgB,EAAE,MAAM,GAAG,gBAAgB,CAgC1E;AAUD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAO1E;AAED,oDAAoD;AACpD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAE1E;AAkCD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,UAAU,GAAG,UAAU,CAgB/E"}
@@ -1,6 +1,55 @@
1
1
  import { parse as parseYaml } from 'yaml';
2
+ import { decodeEntities } from './attrs-extract.js';
2
3
  /** Serialisation order, so a rewrite of unchanged metadata is a no-op diff. */
3
- const KEY_ORDER = ['source', 'tags', 'confidence', 'created'];
4
+ const KEY_ORDER = [
5
+ 'source',
6
+ 'tags',
7
+ 'confidence',
8
+ 'created',
9
+ 'format',
10
+ 'about',
11
+ 'relations',
12
+ 'validFrom',
13
+ 'validTo',
14
+ 'supersededBy',
15
+ ];
16
+ /** The frontmatter key for each field: snake_case on disk, as a person
17
+ * editing the YAML would write it. */
18
+ const YAML_KEY = {
19
+ validFrom: 'valid_from',
20
+ validTo: 'valid_to',
21
+ supersededBy: 'superseded_by',
22
+ };
23
+ /** A date field as a string: YAML reads an unquoted date as a Date. */
24
+ function dateField(value) {
25
+ if (typeof value === 'string' && value.trim() !== '')
26
+ return value.trim();
27
+ if (value instanceof Date && !Number.isNaN(value.getTime())) {
28
+ const iso = value.toISOString();
29
+ // A bare date comes back as midnight UTC; keep it a date.
30
+ return iso.endsWith('T00:00:00.000Z') ? iso.slice(0, 10) : iso;
31
+ }
32
+ return undefined;
33
+ }
34
+ function coerceRelation(raw) {
35
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
36
+ return null;
37
+ const r = raw;
38
+ const text = (v) => (typeof v === 'string' && v.trim() !== '' ? v.trim() : null);
39
+ const s = text(r.s);
40
+ const p = text(r.p);
41
+ const o = text(r.o);
42
+ if (!s || !p || !o)
43
+ return null;
44
+ const relation = { s, p, o };
45
+ const from = dateField(r.from);
46
+ const to = dateField(r.to);
47
+ if (from)
48
+ relation.from = from;
49
+ if (to)
50
+ relation.to = to;
51
+ return relation;
52
+ }
4
53
  const FENCE = '---';
5
54
  /**
6
55
  * The note type a memory is written as.
@@ -59,8 +108,86 @@ function coerceMeta(raw) {
59
108
  // YAML parses unquoted ISO timestamps into Dates.
60
109
  meta.created = raw.created.toISOString();
61
110
  }
111
+ if (raw.format === 'html')
112
+ meta.format = 'html';
113
+ if (Array.isArray(raw.about)) {
114
+ const about = raw.about.filter((a) => typeof a === 'string' && a.trim() !== '');
115
+ if (about.length > 0)
116
+ meta.about = about.map((a) => a.trim());
117
+ }
118
+ if (Array.isArray(raw.relations)) {
119
+ // One malformed relation is dropped; its neighbours survive.
120
+ const relations = raw.relations
121
+ .map(coerceRelation)
122
+ .filter((r) => r !== null);
123
+ if (relations.length > 0)
124
+ meta.relations = relations;
125
+ }
126
+ const validFrom = dateField(raw.valid_from);
127
+ if (validFrom)
128
+ meta.validFrom = validFrom;
129
+ const validTo = dateField(raw.valid_to);
130
+ if (validTo)
131
+ meta.validTo = validTo;
132
+ if (typeof raw.superseded_by === 'string' && raw.superseded_by !== '') {
133
+ meta.supersededBy = raw.superseded_by;
134
+ }
62
135
  return meta;
63
136
  }
137
+ /**
138
+ * A rich fact as text an AI can read: one line per paragraph, heading or
139
+ * list item, list items marked, code and inline marks reduced to their text.
140
+ * Entities are decoded, so a fact that talks about `<p>` tags reads back as
141
+ * exactly that.
142
+ */
143
+ export function memoryHtmlToText(html) {
144
+ const text = html
145
+ .replace(/<br\s*\/?>/gi, '\n')
146
+ // A list item's paragraph is the item, not a paragraph of its own.
147
+ .replace(/<li[^>]*>\s*(<p[^>]*>)?/gi, '- ')
148
+ .replace(/(<\/p>)?\s*<\/li>/gi, '\n')
149
+ .replace(/<\/(p|h[1-6]|blockquote|pre|ul|ol|table)>/gi, '\n\n')
150
+ .replace(/<\/tr>/gi, '\n')
151
+ .replace(/<\/(td|th)>/gi, ' ')
152
+ .replace(/<[^>]+>/g, '');
153
+ return decodeEntities(text)
154
+ .split('\n')
155
+ .map((line) => line.replace(/[ \t]+$/, ''))
156
+ .join('\n')
157
+ .replace(/\n{3,}/g, '\n\n')
158
+ .trim();
159
+ }
160
+ /**
161
+ * Plain text as the rich editor's HTML: a paragraph per blank-line-separated
162
+ * block, single line breaks kept, everything escaped. Used to open a
163
+ * connector-written (plain) memory in the editor.
164
+ */
165
+ export function memoryTextToHtml(text) {
166
+ const escape = (s) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
167
+ const blocks = text.split(/\n{2,}/).filter((b) => b.trim() !== '');
168
+ if (blocks.length === 0)
169
+ return '<p></p>';
170
+ return blocks.map((b) => `<p>${b.split('\n').map(escape).join('<br>')}</p>`).join('');
171
+ }
172
+ /**
173
+ * A plain-text fact that is really HTML: it opens and closes with a block
174
+ * tag. AI tools told that Virlow notes are HTML sometimes write a memory the
175
+ * same way, without the `format` marker the app adds, and it then showed its
176
+ * tags as text. A fact that merely mentions a tag ("every paragraph in
177
+ * <p>") does not start and end with one, so it stays text.
178
+ */
179
+ const BLOCK = '(p|ul|ol|h[1-6]|blockquote|pre|table|div)';
180
+ const OPENS_WITH_BLOCK = new RegExp(`^\\s*<${BLOCK}[\\s>]`, 'i');
181
+ const CLOSES_WITH_BLOCK = new RegExp(`</${BLOCK}>\\s*$`, 'i');
182
+ export function looksLikeHtml(fact) {
183
+ return OPENS_WITH_BLOCK.test(fact) && CLOSES_WITH_BLOCK.test(fact);
184
+ }
185
+ function plainOrHtml(fact, meta) {
186
+ if (meta.format === 'html' || looksLikeHtml(fact)) {
187
+ return { fact: memoryHtmlToText(fact), meta, html: fact };
188
+ }
189
+ return { fact, meta };
190
+ }
64
191
  /**
65
192
  * Split a decrypted note body into its fact and metadata.
66
193
  *
@@ -75,19 +202,19 @@ export function parseMemoryNote(decryptedContent) {
75
202
  // a plain note dropped into the folder by hand — still reads correctly.
76
203
  const body = unwrapEnvelope(decryptedContent);
77
204
  if (!body.startsWith(`${FENCE}\n`))
78
- return { fact: body, meta: {} };
205
+ return plainOrHtml(body, {});
79
206
  // Only the first fence pair is frontmatter; --- lines inside the fact are
80
207
  // ordinary content.
81
208
  const close = body.indexOf(`\n${FENCE}\n`, FENCE.length);
82
209
  if (close === -1)
83
- return { fact: body, meta: {} };
210
+ return plainOrHtml(body, {});
84
211
  const front = body.slice(FENCE.length + 1, close);
85
212
  const fact = body.slice(close + FENCE.length + 2);
86
213
  // An empty fence is the marker `serializeMemoryBody` writes when a fact
87
214
  // would otherwise be misread as its own frontmatter. Strip it and keep the
88
215
  // fact whole.
89
216
  if (front.trim() === '')
90
- return { fact, meta: {} };
217
+ return plainOrHtml(fact, {});
91
218
  let raw;
92
219
  try {
93
220
  raw = parseYaml(front);
@@ -98,7 +225,7 @@ export function parseMemoryNote(decryptedContent) {
98
225
  if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
99
226
  return { fact: body, meta: {} };
100
227
  }
101
- return { fact, meta: coerceMeta(raw) };
228
+ return plainOrHtml(fact, coerceMeta(raw));
102
229
  }
103
230
  function yamlScalar(value) {
104
231
  // Quote anything YAML would otherwise reinterpret (or that would break the
@@ -112,19 +239,42 @@ function yamlScalar(value) {
112
239
  * there is no metadata to record.
113
240
  */
114
241
  export function serializeMemoryBody(fact, meta) {
242
+ // Plain text, always: `format` describes the body, so it is dropped here
243
+ // rather than carried forward from the memory being updated. An AI
244
+ // rewriting a rich memory writes text, and the marker must not survive
245
+ // onto a body it no longer describes.
246
+ const { format: _format, ...plain } = meta;
247
+ return writeBody(fact, plain);
248
+ }
249
+ /** The app's rich editor output, marked as HTML. */
250
+ export function serializeMemoryHtml(html, meta) {
251
+ return writeBody(html, { ...meta, format: 'html' });
252
+ }
253
+ function writeBody(fact, meta) {
115
254
  const lines = [];
116
255
  for (const key of KEY_ORDER) {
117
256
  const value = meta[key];
118
257
  if (value === undefined)
119
258
  continue;
120
- if (key === 'tags') {
121
- const tags = value;
122
- if (tags.length === 0)
259
+ const name = YAML_KEY[key] ?? key;
260
+ if (key === 'tags' || key === 'about') {
261
+ const list = value;
262
+ if (list.length === 0)
263
+ continue;
264
+ lines.push(`${name}: [${list.map(yamlScalar).join(', ')}]`);
265
+ }
266
+ else if (key === 'relations') {
267
+ const relations = value;
268
+ if (relations.length === 0)
123
269
  continue;
124
- lines.push(`tags: [${tags.map(yamlScalar).join(', ')}]`);
270
+ // Flow style, one relation per line: JSON is valid YAML, and this
271
+ // keeps each edge readable and editable by hand.
272
+ lines.push(`${name}:`);
273
+ for (const r of relations)
274
+ lines.push(` - ${JSON.stringify(r)}`);
125
275
  }
126
276
  else {
127
- lines.push(`${key}: ${yamlScalar(value)}`);
277
+ lines.push(`${name}: ${yamlScalar(value)}`);
128
278
  }
129
279
  }
130
280
  if (lines.length === 0) {
@@ -148,6 +298,16 @@ export function mergeMeta(existing, changes) {
148
298
  merged.tags = [...changes.tags];
149
299
  if (changes.confidence !== undefined)
150
300
  merged.confidence = changes.confidence;
301
+ if (changes.about !== undefined)
302
+ merged.about = [...changes.about];
303
+ if (changes.relations !== undefined)
304
+ merged.relations = changes.relations.map((r) => ({ ...r }));
305
+ if (changes.validFrom !== undefined)
306
+ merged.validFrom = changes.validFrom;
307
+ if (changes.validTo !== undefined)
308
+ merged.validTo = changes.validTo;
309
+ if (changes.supersededBy !== undefined)
310
+ merged.supersededBy = changes.supersededBy;
151
311
  // Pinned to the first write, so an in-place dedupe merge cannot make an old
152
312
  // memory look newly created.
153
313
  if (changes.created !== undefined && existing.created === undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"memory-note.js","sourceRoot":"","sources":["../src/memory-note.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory-note.js","sourceRoot":"","sources":["../src/memory-note.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Refuses memories that contain credentials, before anything is written.
3
+ *
4
+ * Memories are captured automatically, so the rule cannot depend on the AI
5
+ * remembering not to save a key: a memory is encrypted, but it is recalled
6
+ * into prompts and shown in the app, and a secret has no business in either.
7
+ * The check is on-device and returns a reason, so the AI can say what it
8
+ * left out instead of retrying with the secret reworded.
9
+ *
10
+ * Deliberately narrow: patterns that are credentials with near certainty,
11
+ * plus long high-entropy tokens. A false positive costs one memory; a false
12
+ * negative puts a live key into every future prompt that recalls it.
13
+ */
14
+ /** What secret the text holds, or null when it holds none. */
15
+ export declare function findSecret(text: string): string | null;
16
+ export declare class SecretInMemoryError extends Error {
17
+ constructor(what: string);
18
+ }
19
+ export declare function assertNoSecret(...texts: string[]): void;
20
+ //# sourceMappingURL=memory-secrets.d.ts.map