@batalabs/virlow-mcp-core 3.11.4

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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/dist/api.d.ts +118 -0
  4. package/dist/api.d.ts.map +1 -0
  5. package/dist/api.js +109 -0
  6. package/dist/api.js.map +1 -0
  7. package/dist/embedding-cache.d.ts +34 -0
  8. package/dist/embedding-cache.d.ts.map +1 -0
  9. package/dist/embedding-cache.js +108 -0
  10. package/dist/embedding-cache.js.map +1 -0
  11. package/dist/exposure.d.ts +42 -0
  12. package/dist/exposure.d.ts.map +1 -0
  13. package/dist/exposure.js +74 -0
  14. package/dist/exposure.js.map +1 -0
  15. package/dist/index.d.ts +16 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +10 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/memories-enabled.d.ts +16 -0
  20. package/dist/memories-enabled.d.ts.map +1 -0
  21. package/dist/memories-enabled.js +29 -0
  22. package/dist/memories-enabled.js.map +1 -0
  23. package/dist/memories.d.ts +86 -0
  24. package/dist/memories.d.ts.map +1 -0
  25. package/dist/memories.js +350 -0
  26. package/dist/memories.js.map +1 -0
  27. package/dist/memory-note.d.ts +45 -0
  28. package/dist/memory-note.d.ts.map +1 -0
  29. package/dist/memory-note.js +144 -0
  30. package/dist/memory-note.js.map +1 -0
  31. package/dist/memory-tree.d.ts +28 -0
  32. package/dist/memory-tree.d.ts.map +1 -0
  33. package/dist/memory-tree.js +68 -0
  34. package/dist/memory-tree.js.map +1 -0
  35. package/dist/notes.d.ts +109 -0
  36. package/dist/notes.d.ts.map +1 -0
  37. package/dist/notes.js +234 -0
  38. package/dist/notes.js.map +1 -0
  39. package/dist/vault.d.ts +35 -0
  40. package/dist/vault.d.ts.map +1 -0
  41. package/dist/vault.js +73 -0
  42. package/dist/vault.js.map +1 -0
  43. package/package.json +43 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Whether the user has switched AI memories on, read fresh from the account.
3
+ *
4
+ * Deliberately not cached for the session. Turning the switch *on* being slow
5
+ * is an inconvenience; turning it *off* being slow is a privacy control that
6
+ * does not work. A user who switches memories off in the app expects the next
7
+ * tool call to respect it, not the next time they happen to restart their
8
+ * editor — and they would have no way to discover the difference.
9
+ *
10
+ * The cost is one GET alongside operations that already list folders, page
11
+ * through notes, decrypt, and embed.
12
+ */
13
+ export async function memoriesAllowed(api) {
14
+ try {
15
+ const me = await api.me();
16
+ // An API that predates the column omits the field. Treat an unknown answer
17
+ // as "not enabled": this decides whether an AI may record facts about the
18
+ // user, and guessing yes is the expensive direction to be wrong in.
19
+ return me.memoriesEnabled === true;
20
+ }
21
+ catch {
22
+ // Fail closed. A network blip briefly disabling memories is a far better
23
+ // failure than a revoked setting continuing to work.
24
+ return false;
25
+ }
26
+ }
27
+ export const MEMORIES_DISABLED_MESSAGE = 'AI memories are switched off for this account. Turn on "AI memories" in ' +
28
+ 'Settings → Security in the Virlow app to use this tool.';
29
+ //# sourceMappingURL=memories-enabled.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memories-enabled.js","sourceRoot":"","sources":["../src/memories-enabled.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAc;IAClD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC;QAC1B,2EAA2E;QAC3E,0EAA0E;QAC1E,oEAAoE;QACpE,OAAO,EAAE,CAAC,eAAe,KAAK,IAAI,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;QACzE,qDAAqD;QACrD,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,yBAAyB,GACpC,0EAA0E;IAC1E,yDAAyD,CAAC"}
@@ -0,0 +1,86 @@
1
+ import { type Embedder } from '@batalabs/virlow-memory';
2
+ import { type VirlowApi } from './api';
3
+ import type { EmbeddingCache } from './embedding-cache';
4
+ import { type MemoryMeta } from './memory-note';
5
+ import type { Vault } from './vault';
6
+ export declare const SYNC_PAGE_LIMIT = 100;
7
+ export interface CachedMemory {
8
+ id: string;
9
+ label: string;
10
+ text: string;
11
+ meta: MemoryMeta;
12
+ namespace?: string;
13
+ folderId: string;
14
+ embedding: Float32Array;
15
+ updatedAt: string;
16
+ }
17
+ export interface SimilarMemory {
18
+ id: string;
19
+ label: string;
20
+ text: string;
21
+ similarity: number;
22
+ }
23
+ export type SyncResult = {
24
+ added: number;
25
+ updated: number;
26
+ removed: number;
27
+ embedded: number;
28
+ };
29
+ export declare class MemoryStore {
30
+ private readonly api;
31
+ private readonly vault;
32
+ private readonly embedder;
33
+ private readonly cacheFactory;
34
+ private readonly cache;
35
+ private tree;
36
+ private embeddings;
37
+ private embeddingsLoaded;
38
+ private syncInFlight;
39
+ private mutationChain;
40
+ /** Bumped every time clear() runs (i.e. every lock). Operations capture it
41
+ * at the top and re-check before every cache write, so anything still
42
+ * awaiting the network or a decrypt when the vault locked can never write
43
+ * decrypted plaintext back into a cache the user just emptied. */
44
+ private epoch;
45
+ constructor(api: VirlowApi, vault: Vault, embedder: Embedder, cacheFactory: (userId: string) => EmbeddingCache);
46
+ clear(): void;
47
+ get size(): number;
48
+ /** Concurrent callers share one in-flight sync so two overlapping tool
49
+ * calls never double up on network, decrypt, or embedding work. */
50
+ sync(): Promise<SyncResult>;
51
+ private doSync;
52
+ add(label: string, text: string, namespace?: string, meta?: MemoryMeta): Promise<{
53
+ action: 'stored' | 'updated';
54
+ id: string;
55
+ similar: SimilarMemory[];
56
+ }>;
57
+ search(query: string, namespace?: string, limit?: number): Promise<Array<Omit<CachedMemory, 'embedding' | 'folderId' | 'updatedAt'> & {
58
+ similarity: number;
59
+ }>>;
60
+ /** Requires a prior sync() in the same unlock to have populated the cache. */
61
+ list(namespace?: string): CachedMemory[];
62
+ update(id: string, changes: {
63
+ label?: string;
64
+ text?: string;
65
+ meta?: MemoryMeta;
66
+ }): Promise<void>;
67
+ /** Trashes the note — recoverable from the app's Trash, never hard-deleted. */
68
+ delete(id: string): Promise<void>;
69
+ /** Dedupe and search candidates: the named namespace plus the global root. */
70
+ private candidatesFor;
71
+ /** Create or update a memory note, encrypting through the note field
72
+ * helpers. `noteId === null` creates. */
73
+ private writeNote;
74
+ private decryptRow;
75
+ private requireTree;
76
+ private requireEmbeddings;
77
+ /** Persisting after a lock would write vectors the user just cleared. */
78
+ private saveEmbeddings;
79
+ private requireSession;
80
+ /** Serializes add/update/delete so two overlapping mutation tool calls never
81
+ * interleave — two concurrent near-duplicate adds must run their
82
+ * dedupe-check-then-write critical section one at a time, or both would miss
83
+ * the other's pending write and both create. */
84
+ private enqueue;
85
+ }
86
+ //# sourceMappingURL=memories.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memories.d.ts","sourceRoot":"","sources":["../src/memories.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,QAAQ,EACd,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAA0C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC/E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAErC,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,YAAY,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAIF,qBAAa,WAAW;IAepB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAjB/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmC;IACzD,OAAO,CAAC,IAAI,CAA2B;IACvC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,aAAa,CAAuC;IAE5D;;;sEAGkE;IAClE,OAAO,CAAC,KAAK,CAAK;gBAGC,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,cAAc;IAKnE,KAAK,IAAI,IAAI;IAQb,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;uEACmE;IACnE,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC;YAOb,MAAM;IA+FpB,GAAG,CACD,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,MAAM,EAClB,IAAI,GAAE,UAAe,GACpB,OAAO,CAAC;QAAE,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,aAAa,EAAE,CAAA;KAAE,CAAC;IAwE5E,MAAM,CACV,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,SAAK,GACT,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,GAAG,UAAU,GAAG,WAAW,CAAC,GAAG;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAkBtG,8EAA8E;IAC9E,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,EAAE;IAOxC,MAAM,CACJ,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,UAAU,CAAA;KAAE,GAC5D,OAAO,CAAC,IAAI,CAAC;IAyBhB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYjC,8EAA8E;IAC9E,OAAO,CAAC,aAAa;IAYrB;6CACyC;YAC3B,SAAS;YAiCT,UAAU;YAWV,WAAW;YAKX,iBAAiB;IAS/B,yEAAyE;YAC3D,cAAc;IAK5B,OAAO,CAAC,cAAc;IAMtB;;;oDAGgD;IAChD,OAAO,CAAC,OAAO;CAKhB"}
@@ -0,0 +1,350 @@
1
+ import { bytesToBase64, decryptNoteFields, encryptNoteFields, } from '@batalabs/virlow-crypto';
2
+ import { findDuplicate, findSimilar, rankBySimilarity, } from '@batalabs/virlow-memory';
3
+ import { ApiError } from './api';
4
+ import { mergeMeta, parseMemoryNote, serializeMemoryBody, toCodeEnvelope, } from './memory-note';
5
+ import { ensureNamespace, resolveMemoryTree } from './memory-tree';
6
+ export const SYNC_PAGE_LIMIT = 100;
7
+ const round3 = (n) => Math.round(n * 1000) / 1000;
8
+ export class MemoryStore {
9
+ api;
10
+ vault;
11
+ embedder;
12
+ cacheFactory;
13
+ cache = new Map();
14
+ tree = null;
15
+ embeddings = null;
16
+ embeddingsLoaded = false;
17
+ syncInFlight = null;
18
+ mutationChain = Promise.resolve();
19
+ /** Bumped every time clear() runs (i.e. every lock). Operations capture it
20
+ * at the top and re-check before every cache write, so anything still
21
+ * awaiting the network or a decrypt when the vault locked can never write
22
+ * decrypted plaintext back into a cache the user just emptied. */
23
+ epoch = 0;
24
+ constructor(api, vault, embedder, cacheFactory) {
25
+ this.api = api;
26
+ this.vault = vault;
27
+ this.embedder = embedder;
28
+ this.cacheFactory = cacheFactory;
29
+ this.vault.onLock = () => this.clear();
30
+ }
31
+ clear() {
32
+ this.cache.clear();
33
+ this.tree = null;
34
+ this.embeddings = null;
35
+ this.embeddingsLoaded = false;
36
+ this.epoch++;
37
+ }
38
+ get size() {
39
+ return this.cache.size;
40
+ }
41
+ /** Concurrent callers share one in-flight sync so two overlapping tool
42
+ * calls never double up on network, decrypt, or embedding work. */
43
+ sync() {
44
+ this.syncInFlight ??= this.doSync().finally(() => {
45
+ this.syncInFlight = null;
46
+ });
47
+ return this.syncInFlight;
48
+ }
49
+ async doSync() {
50
+ const key = this.requireSession();
51
+ const startEpoch = this.epoch;
52
+ const result = { added: 0, updated: 0, removed: 0, embedded: 0 };
53
+ const tree = await this.requireTree();
54
+ const embeddings = await this.requireEmbeddings(key);
55
+ const seen = new Set();
56
+ for (const folderId of tree.folderIds()) {
57
+ let page = 1;
58
+ for (;;) {
59
+ let batch;
60
+ try {
61
+ batch = await this.api.listNotes({
62
+ folderId,
63
+ deleted: false,
64
+ page,
65
+ limit: SYNC_PAGE_LIMIT,
66
+ });
67
+ }
68
+ catch (err) {
69
+ // The folder was deleted between resolving the tree and walking it.
70
+ // Drop the stale tree so the next sync re-resolves, and move on.
71
+ if (err instanceof ApiError && err.status === 404) {
72
+ this.tree = null;
73
+ break;
74
+ }
75
+ throw err;
76
+ }
77
+ for (const row of batch.notes) {
78
+ // Hidden notes are segregated in the app; they are not memories.
79
+ if (row.hidden === true)
80
+ continue;
81
+ seen.add(row.id);
82
+ const existing = this.cache.get(row.id);
83
+ if (existing && existing.updatedAt === row.updatedAt) {
84
+ // Unchanged, but it may have been dragged to another subfolder.
85
+ if (existing.folderId !== folderId) {
86
+ const moved = {
87
+ ...existing,
88
+ folderId,
89
+ ...namespaceField(tree.namespaceOf(folderId)),
90
+ };
91
+ if (this.epoch === startEpoch)
92
+ this.cache.set(row.id, moved);
93
+ result.updated++;
94
+ }
95
+ continue;
96
+ }
97
+ const { title, content } = await this.decryptRow(key, row);
98
+ const { fact, meta } = parseMemoryNote(content);
99
+ let embedding = embeddings.get(row.id, row.updatedAt);
100
+ if (!embedding) {
101
+ embedding = await this.embedder.embed(embeddingInput(title, fact));
102
+ result.embedded++;
103
+ }
104
+ if (this.epoch !== startEpoch)
105
+ continue;
106
+ embeddings.set(row.id, row.updatedAt, embedding);
107
+ this.cache.set(row.id, {
108
+ id: row.id,
109
+ label: title,
110
+ text: fact,
111
+ meta,
112
+ folderId,
113
+ ...namespaceField(tree.namespaceOf(folderId)),
114
+ embedding,
115
+ updatedAt: row.updatedAt,
116
+ });
117
+ if (existing)
118
+ result.updated++;
119
+ else
120
+ result.added++;
121
+ }
122
+ if (page >= batch.pagination.pages || batch.notes.length === 0)
123
+ break;
124
+ page++;
125
+ }
126
+ }
127
+ // Anything no longer in the tree was trashed, hidden, or moved out of the
128
+ // memories folder: it stops being a memory.
129
+ if (this.epoch === startEpoch) {
130
+ for (const id of [...this.cache.keys()]) {
131
+ if (seen.has(id))
132
+ continue;
133
+ this.cache.delete(id);
134
+ embeddings.delete(id);
135
+ result.removed++;
136
+ }
137
+ await embeddings.save(key);
138
+ }
139
+ return result;
140
+ }
141
+ add(label, text, namespace, meta = {}) {
142
+ return this.enqueue(async () => {
143
+ await this.sync();
144
+ const key = this.requireSession();
145
+ const startEpoch = this.epoch;
146
+ const embedding = await this.embedder.embed(embeddingInput(label, text));
147
+ const candidates = this.candidatesFor(namespace);
148
+ const hit = findDuplicate(embedding, candidates);
149
+ if (hit) {
150
+ // Same memory said again: fold it into the existing note rather than
151
+ // accumulating near-identical copies. Its metadata carries forward.
152
+ const existing = this.cache.get(hit.id);
153
+ const merged = mergeMeta(existing.meta, meta);
154
+ const row = await this.writeNote(key, hit.id, label, text, merged);
155
+ if (this.epoch === startEpoch) {
156
+ this.cache.set(hit.id, {
157
+ ...existing,
158
+ label,
159
+ text,
160
+ meta: merged,
161
+ embedding,
162
+ updatedAt: row.updatedAt,
163
+ });
164
+ this.embeddings?.set(hit.id, row.updatedAt, embedding);
165
+ await this.saveEmbeddings(key, startEpoch);
166
+ }
167
+ return { action: 'updated', id: hit.id, similar: [] };
168
+ }
169
+ const tree = await this.requireTree();
170
+ const folderId = namespace !== undefined
171
+ ? await ensureNamespace(this.api, tree, namespace)
172
+ : tree.rootId;
173
+ const stamped = {
174
+ ...meta,
175
+ source: meta.source ?? 'virlow-mcp',
176
+ created: meta.created ?? new Date().toISOString(),
177
+ };
178
+ const row = await this.writeNote(key, null, label, text, stamped, folderId);
179
+ if (this.epoch === startEpoch) {
180
+ this.cache.set(row.id, {
181
+ id: row.id,
182
+ label,
183
+ text,
184
+ meta: stamped,
185
+ folderId,
186
+ ...namespaceField(tree.namespaceOf(folderId)),
187
+ embedding,
188
+ updatedAt: row.updatedAt,
189
+ });
190
+ this.embeddings?.set(row.id, row.updatedAt, embedding);
191
+ await this.saveEmbeddings(key, startEpoch);
192
+ }
193
+ // Close enough to be worth mentioning, not close enough to merge.
194
+ const similar = findSimilar(embedding, candidates).map(({ id, similarity }) => {
195
+ const memory = this.cache.get(id);
196
+ return {
197
+ id,
198
+ label: memory.label,
199
+ text: memory.text,
200
+ similarity: round3(similarity),
201
+ };
202
+ });
203
+ return { action: 'stored', id: row.id, similar };
204
+ });
205
+ }
206
+ async search(query, namespace, limit = 10) {
207
+ await this.sync();
208
+ this.requireSession();
209
+ const embedding = await this.embedder.embed(query);
210
+ const ranked = rankBySimilarity(embedding, this.candidatesFor(namespace), limit);
211
+ return ranked.map(({ id, similarity }) => {
212
+ const memory = this.cache.get(id);
213
+ return {
214
+ id,
215
+ label: memory.label,
216
+ text: memory.text,
217
+ meta: memory.meta,
218
+ ...namespaceField(memory.namespace),
219
+ similarity: round3(similarity),
220
+ };
221
+ });
222
+ }
223
+ /** Requires a prior sync() in the same unlock to have populated the cache. */
224
+ list(namespace) {
225
+ this.requireSession();
226
+ return [...this.cache.values()].filter((m) => namespace === undefined || m.namespace === namespace || m.namespace === undefined);
227
+ }
228
+ update(id, changes) {
229
+ return this.enqueue(async () => {
230
+ // Sync first: without it a cache miss (fresh unlock, or a memory this
231
+ // device never saw) would overwrite the server note with defaults and
232
+ // wipe its metadata. If the id is still missing afterwards it genuinely
233
+ // does not exist — never guess-write over it.
234
+ await this.sync();
235
+ const key = this.requireSession();
236
+ const startEpoch = this.epoch;
237
+ const existing = this.cache.get(id);
238
+ if (!existing)
239
+ throw new Error(`Memory ${id} not found`);
240
+ const label = changes.label ?? existing.label;
241
+ const text = changes.text ?? existing.text;
242
+ const meta = mergeMeta(existing.meta, changes.meta ?? {});
243
+ const row = await this.writeNote(key, id, label, text, meta);
244
+ const embedding = await this.embedder.embed(embeddingInput(label, text));
245
+ if (this.epoch !== startEpoch)
246
+ return;
247
+ this.cache.set(id, { ...existing, label, text, meta, embedding, updatedAt: row.updatedAt });
248
+ this.embeddings?.set(id, row.updatedAt, embedding);
249
+ await this.saveEmbeddings(key, startEpoch);
250
+ });
251
+ }
252
+ /** Trashes the note — recoverable from the app's Trash, never hard-deleted. */
253
+ delete(id) {
254
+ return this.enqueue(async () => {
255
+ const key = this.requireSession();
256
+ const startEpoch = this.epoch;
257
+ await this.api.updateNote(id, { deleted: true });
258
+ if (this.epoch !== startEpoch)
259
+ return;
260
+ this.cache.delete(id);
261
+ this.embeddings?.delete(id);
262
+ await this.saveEmbeddings(key, startEpoch);
263
+ });
264
+ }
265
+ /** Dedupe and search candidates: the named namespace plus the global root. */
266
+ candidatesFor(namespace) {
267
+ const result = [];
268
+ for (const memory of this.cache.values()) {
269
+ if (memory.namespace === namespace || memory.namespace === undefined) {
270
+ result.push({ id: memory.id, embedding: memory.embedding });
271
+ }
272
+ }
273
+ return result;
274
+ }
275
+ /** Create or update a memory note, encrypting through the note field
276
+ * helpers. `noteId === null` creates. */
277
+ async writeNote(key, noteId, label, text, meta, folderId) {
278
+ const body = toCodeEnvelope(serializeMemoryBody(text, meta));
279
+ const salt = bytesToBase64(crypto.getRandomValues(new Uint8Array(32)));
280
+ const { encryptedTitle, encryptedContent, iv } = await encryptNoteFields(key, label, body);
281
+ const write = {
282
+ title: '[ENCRYPTED]',
283
+ content: '[ENCRYPTED]',
284
+ encryptedTitle,
285
+ encryptedContent,
286
+ iv,
287
+ salt,
288
+ type: 'code',
289
+ // Mirrored so the app can filter memories by tag. The frontmatter stays
290
+ // the source of truth; this column follows it on every write we make.
291
+ tags: meta.tags ?? [],
292
+ };
293
+ if (folderId !== undefined)
294
+ write.folderId = folderId;
295
+ return noteId === null
296
+ ? this.api.createNote(write)
297
+ : this.api.updateNote(noteId, write);
298
+ }
299
+ async decryptRow(key, row) {
300
+ if (row.encryptedTitle && row.encryptedContent && row.iv) {
301
+ return decryptNoteFields(key, row.encryptedTitle, row.encryptedContent, row.iv);
302
+ }
303
+ // A legacy plaintext note the user filed under Memories by hand.
304
+ return { title: row.title, content: row.content };
305
+ }
306
+ async requireTree() {
307
+ this.tree ??= await resolveMemoryTree(this.api);
308
+ return this.tree;
309
+ }
310
+ async requireEmbeddings(key) {
311
+ this.embeddings ??= this.cacheFactory(this.vault.session.userId);
312
+ if (!this.embeddingsLoaded) {
313
+ await this.embeddings.load(key);
314
+ this.embeddingsLoaded = true;
315
+ }
316
+ return this.embeddings;
317
+ }
318
+ /** Persisting after a lock would write vectors the user just cleared. */
319
+ async saveEmbeddings(key, startEpoch) {
320
+ if (this.epoch !== startEpoch)
321
+ return;
322
+ await this.embeddings?.save(key);
323
+ }
324
+ requireSession() {
325
+ const key = this.vault.session.key;
326
+ this.vault.touch();
327
+ return key;
328
+ }
329
+ /** Serializes add/update/delete so two overlapping mutation tool calls never
330
+ * interleave — two concurrent near-duplicate adds must run their
331
+ * dedupe-check-then-write critical section one at a time, or both would miss
332
+ * the other's pending write and both create. */
333
+ enqueue(fn) {
334
+ const next = this.mutationChain.then(fn, fn);
335
+ this.mutationChain = next.catch(() => { });
336
+ return next;
337
+ }
338
+ }
339
+ /** The metadata is deliberately excluded: it is near-identical boilerplate
340
+ * across the corpus, so embedding it would raise the similarity floor
341
+ * everywhere and quietly change what the dedupe thresholds mean. */
342
+ function embeddingInput(label, fact) {
343
+ return `${label}\n${fact}`;
344
+ }
345
+ /** `exactOptionalPropertyTypes` forbids assigning undefined to an optional
346
+ * property, so an absent namespace omits the key entirely. */
347
+ function namespaceField(namespace) {
348
+ return namespace === undefined ? {} : { namespace };
349
+ }
350
+ //# sourceMappingURL=memories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memories.js","sourceRoot":"","sources":["../src/memories.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Metadata carried in a memory note's YAML frontmatter. Every key is optional.
3
+ *
4
+ * Deliberately absent: `id`, `label`, and `namespace`. The note id, the note
5
+ * title, and the containing subfolder already own those, and duplicating them
6
+ * here would create a second source of truth that goes stale the moment the
7
+ * user renames or drags the note in the app.
8
+ */
9
+ export interface MemoryMeta {
10
+ /** Which agent or tool wrote the memory. */
11
+ source?: string;
12
+ tags?: string[];
13
+ /** Free-form: 'high', '0.8' — stored and editable, nothing ranks on it yet. */
14
+ confidence?: string;
15
+ /** ISO timestamp of the first write; never overwritten by later updates. */
16
+ created?: string;
17
+ }
18
+ export interface ParsedMemoryNote {
19
+ fact: string;
20
+ meta: MemoryMeta;
21
+ }
22
+ /** The app's code editor stores content as this envelope; `code` is what the
23
+ * user sees and edits in Monaco. */
24
+ export declare function toCodeEnvelope(body: string): string;
25
+ /**
26
+ * Split a decrypted note body into its fact and metadata.
27
+ *
28
+ * Total by construction: a missing fence, unparseable YAML, frontmatter that
29
+ * is not a mapping, or a note that was never a memory note at all all yield
30
+ * `{ fact: <the whole body>, meta: {} }`. A human edits these by hand, so a
31
+ * syntax error must cost them a bit of metadata, never the memory.
32
+ */
33
+ export declare function parseMemoryNote(decryptedContent: string): ParsedMemoryNote;
34
+ /**
35
+ * Canonical memory body: frontmatter then the fact, or just the fact when
36
+ * there is no metadata to record.
37
+ */
38
+ export declare function serializeMemoryBody(fact: string, meta: MemoryMeta): string;
39
+ /**
40
+ * Metadata for an update: named keys win, unnamed keys carry forward, and
41
+ * `created` is pinned to the first write so an in-place dedupe merge cannot
42
+ * make an old memory look new.
43
+ */
44
+ export declare function mergeMeta(existing: MemoryMeta, changes: MemoryMeta): MemoryMeta;
45
+ //# sourceMappingURL=memory-note.d.ts.map
@@ -0,0 +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;oCACoC;AACpC,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"}