@danielmarbach/mnemonic-mcp 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@ All notable changes to `mnemonic` will be documented in this file.
4
4
 
5
5
  The format is loosely based on Keep a Changelog and uses semver-style version headings.
6
6
 
7
+ ## [0.17.0] - 2026-03-25
8
+
9
+ ### Added
10
+
11
+ - Active session project cache (`src/cache.ts`): notes and embeddings are cached in memory after the first access within an MCP session, so repeated calls to `recall`, `get`, and `project_memory_summary` skip redundant storage reads.
12
+ - The cache is invalidated automatically on every write-path tool (`remember`, `update`, `forget`, `relate`, `unrelate`, `move_memory`, `consolidate`, `sync`) and on branch switch.
13
+
14
+ ## [0.16.0] - 2026-03-24
15
+
16
+ ### Added
17
+
18
+ - Bounded 1-hop relationship expansion layer (`src/relationships.ts`): `recall`, `project_memory_summary`, and `get` now surface direct related notes as compact previews, scored by same-project priority, anchor status, recency, and confidence.
19
+ - `recall` automatically attaches relationship previews to top results (top 1 by default, top 3 when result count is small). Previews appear in both text and structured output.
20
+ - `project_memory_summary` orientation entries (`primaryEntry` and `suggestedNext`) include bounded relationship previews, including the fallback primaryEntry when no anchor notes exist.
21
+ - `get` accepts an optional `includeRelationships` parameter; when true, each returned note includes a bounded 1-hop relationship preview in both text and structured output.
22
+
23
+ ### Changed
24
+
25
+ - `RecallResult.results` entries now include an optional `relationships` field (`RelationshipPreview`).
26
+ - `GetResult.notes` entries now include an optional `relationships` field (`RelationshipPreview`).
27
+ - `OrientationNote` now includes an optional `relationships` field (`RelationshipPreview`).
28
+ - `discover_tags` now defaults to note-oriented tag suggestions using title/content/query context, returning bounded `recommendedTags`; broader inventory output is now explicit via `mode: "browse"`.
29
+
7
30
  ## [0.15.0] - 2026-03-23
8
31
 
9
32
  ### Added
package/README.md CHANGED
@@ -23,6 +23,7 @@ mnemonic is at the inception stage. The storage format (frontmatter schema, vaul
23
23
 
24
24
  - Hundreds to low thousands of notes: excellent fit.
25
25
  - Several thousand: often fine, depending on note size, machine speed, and embedding throughput.
26
+ - Within a session, notes and embeddings are cached after first access — repeated `recall`, `get`, and `project_memory_summary` calls skip storage reads regardless of vault size.
26
27
  - Very large collections: expect pain points around reindex time, recall latency, and git churn.
27
28
  - Many concurrent writers or massive scale: consider a dedicated database and indexing layer instead.
28
29
 
@@ -429,10 +430,10 @@ Imported notes are written to the main vault with `lifecycle: permanent` and `sc
429
430
  |-----------------------------|--------------------------------------------------------------------------|
430
431
  | `consolidate` | Merge multiple notes into one with relationship to sources |
431
432
  | `detect_project` | Resolve `cwd` to stable project id via git remote URL |
432
- | `discover_tags` | List existing tags with usage counts and examples for consistent terminology |
433
+ | `discover_tags` | Suggest canonical tags for a note using title/content/query context; `mode: "browse"` opts into broader inventory output |
433
434
  | `execute_migration` | Execute a named migration (supports dry-run) |
434
435
  | `forget` | Delete note + embedding, git commit + push, cleanup relationships |
435
- | `get` | Fetch one or more notes by exact id |
436
+ | `get` | Fetch one or more notes by exact id; `includeRelationships: true` adds bounded 1-hop previews |
436
437
  | `get_project_identity` | Show effective project identity and remote override |
437
438
  | `get_project_memory_policy` | Show saved write scope, consolidation mode, and protected-branch settings |
438
439
  | `list` | List notes filtered by scope/tags/storage |
@@ -0,0 +1,66 @@
1
+ import type { Note, EmbeddingRecord } from "./storage.js";
2
+ import type { NoteProjection } from "./structured-content.js";
3
+ import type { Vault } from "./vault.js";
4
+ interface VaultCache {
5
+ notesById: Map<string, Note>;
6
+ noteList: Note[];
7
+ embeddings: EmbeddingRecord[];
8
+ }
9
+ export interface SessionProjectCache {
10
+ projectId: string;
11
+ /** Per-vault caches keyed by vaultPath. Built lazily per vault on first access. */
12
+ vaultCaches: Map<string, VaultCache>;
13
+ /** Projection cache shared across all cached vaults for this project. */
14
+ projectionsById: Map<string, NoteProjection>;
15
+ /** ISO timestamp of when this cache entry was first created. */
16
+ lastBuiltAt: string;
17
+ }
18
+ /**
19
+ * Discard the entire active project cache.
20
+ *
21
+ * Call this after any mutation that modifies notes, embeddings, or relationships
22
+ * so the next read rebuilds from storage. Safe to call when no cache exists (no-op).
23
+ */
24
+ export declare function invalidateActiveProjectCache(): void;
25
+ /**
26
+ * Return the active project cache for the given projectId without triggering a build.
27
+ * Returns undefined when no cache exists or the cached project is different.
28
+ */
29
+ export declare function getActiveProjectCache(projectId: string): SessionProjectCache | undefined;
30
+ /**
31
+ * Get the full note list for a vault from the session cache, building it lazily if needed.
32
+ *
33
+ * When the vault cache is first built, notes AND embeddings are loaded together so
34
+ * both are available for subsequent calls at no extra I/O cost.
35
+ *
36
+ * Fail-soft: returns `undefined` on error. Callers must fall back to direct storage access.
37
+ */
38
+ export declare function getOrBuildVaultNoteList(projectId: string, vault: Vault): Promise<Note[] | undefined>;
39
+ /**
40
+ * Get the embeddings list for a vault from the session cache, building it lazily if needed.
41
+ *
42
+ * When the vault cache is first built, notes AND embeddings are loaded together so
43
+ * both are available for subsequent calls at no extra I/O cost.
44
+ *
45
+ * Fail-soft: returns `undefined` on error. Callers must fall back to direct storage access.
46
+ */
47
+ export declare function getOrBuildVaultEmbeddings(projectId: string, vault: Vault): Promise<EmbeddingRecord[] | undefined>;
48
+ /**
49
+ * Look up a single note from an already-built vault cache.
50
+ * Returns `undefined` when the vault cache has not been built yet or the note is not found.
51
+ * Does NOT trigger a cache build — callers should use `getOrBuildVaultNoteList` or
52
+ * `getOrBuildVaultEmbeddings` to ensure the vault cache is warm first.
53
+ */
54
+ export declare function getSessionCachedNote(projectId: string, vaultPath: string, noteId: string): Note | undefined;
55
+ /**
56
+ * Retrieve a cached projection for a note.
57
+ * Returns `undefined` when no cache or projection exists.
58
+ */
59
+ export declare function getSessionCachedProjection(projectId: string, noteId: string): NoteProjection | undefined;
60
+ /**
61
+ * Store a projection in the session cache.
62
+ * No-op when no active cache exists for this project.
63
+ */
64
+ export declare function setSessionCachedProjection(projectId: string, noteId: string, projection: NoteProjection): void;
65
+ export {};
66
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,UAAU,UAAU;IAClB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC7B,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjB,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,yEAAyE;IACzE,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC7C,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;CACrB;AAqCD;;;;;GAKG;AACH,wBAAgB,4BAA4B,IAAI,IAAI,CAKnD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAIxF;AAED;;;;;;;GAOG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,KAAK,GACX,OAAO,CAAC,IAAI,EAAE,GAAG,SAAS,CAAC,CA6B7B;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,KAAK,GACX,OAAO,CAAC,eAAe,EAAE,GAAG,SAAS,CAAC,CA6BxC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,IAAI,GAAG,SAAS,CAIlB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,cAAc,GAAG,SAAS,CAI5B;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,cAAc,GACzB,IAAI,CAIN"}
package/build/cache.js ADDED
@@ -0,0 +1,149 @@
1
+ import { performance } from "perf_hooks";
2
+ // ── Module-level singleton ─────────────────────────────────────────────────────
3
+ const sessionCaches = {};
4
+ // ── Internal helpers ───────────────────────────────────────────────────────────
5
+ function debugLog(event, message) {
6
+ console.error(`[${event}] ${message}`);
7
+ }
8
+ function ensureActiveProjectCache(projectId) {
9
+ const current = sessionCaches.activeProject;
10
+ if (current?.projectId === projectId) {
11
+ return current;
12
+ }
13
+ // Different project (or first use): create fresh cache
14
+ if (current) {
15
+ debugLog("cache:invalidate", `switching project from=${current.projectId} to=${projectId}`);
16
+ }
17
+ const fresh = {
18
+ projectId,
19
+ vaultCaches: new Map(),
20
+ projectionsById: new Map(),
21
+ lastBuiltAt: new Date().toISOString(),
22
+ };
23
+ sessionCaches.activeProject = fresh;
24
+ return fresh;
25
+ }
26
+ // ── Public API ─────────────────────────────────────────────────────────────────
27
+ /**
28
+ * Discard the entire active project cache.
29
+ *
30
+ * Call this after any mutation that modifies notes, embeddings, or relationships
31
+ * so the next read rebuilds from storage. Safe to call when no cache exists (no-op).
32
+ */
33
+ export function invalidateActiveProjectCache() {
34
+ if (sessionCaches.activeProject) {
35
+ debugLog("cache:invalidate", `project=${sessionCaches.activeProject.projectId}`);
36
+ sessionCaches.activeProject = undefined;
37
+ }
38
+ }
39
+ /**
40
+ * Return the active project cache for the given projectId without triggering a build.
41
+ * Returns undefined when no cache exists or the cached project is different.
42
+ */
43
+ export function getActiveProjectCache(projectId) {
44
+ const cache = sessionCaches.activeProject;
45
+ if (cache?.projectId === projectId)
46
+ return cache;
47
+ return undefined;
48
+ }
49
+ /**
50
+ * Get the full note list for a vault from the session cache, building it lazily if needed.
51
+ *
52
+ * When the vault cache is first built, notes AND embeddings are loaded together so
53
+ * both are available for subsequent calls at no extra I/O cost.
54
+ *
55
+ * Fail-soft: returns `undefined` on error. Callers must fall back to direct storage access.
56
+ */
57
+ export async function getOrBuildVaultNoteList(projectId, vault) {
58
+ const vaultPath = vault.storage.vaultPath;
59
+ const cache = ensureActiveProjectCache(projectId);
60
+ const existing = cache.vaultCaches.get(vaultPath);
61
+ if (existing) {
62
+ debugLog("cache:hit", `project=${projectId} vault=${vaultPath} notes=${existing.noteList.length}`);
63
+ return existing.noteList;
64
+ }
65
+ debugLog("cache:miss", `project=${projectId} vault=${vaultPath}`);
66
+ try {
67
+ const t0 = performance.now();
68
+ const [noteList, embeddings] = await Promise.all([
69
+ vault.storage.listNotes(),
70
+ vault.storage.listEmbeddings(),
71
+ ]);
72
+ const notesById = new Map(noteList.map((n) => [n.id, n]));
73
+ cache.vaultCaches.set(vaultPath, { notesById, noteList, embeddings });
74
+ const ms = (performance.now() - t0).toFixed(1);
75
+ debugLog("cache:build", `project=${projectId} vault=${vaultPath} notes=${noteList.length} embeddings=${embeddings.length} time=${ms}ms`);
76
+ return noteList;
77
+ }
78
+ catch (err) {
79
+ debugLog("cache:fallback", `project=${projectId} vault=${vaultPath} error=${String(err)}`);
80
+ return undefined;
81
+ }
82
+ }
83
+ /**
84
+ * Get the embeddings list for a vault from the session cache, building it lazily if needed.
85
+ *
86
+ * When the vault cache is first built, notes AND embeddings are loaded together so
87
+ * both are available for subsequent calls at no extra I/O cost.
88
+ *
89
+ * Fail-soft: returns `undefined` on error. Callers must fall back to direct storage access.
90
+ */
91
+ export async function getOrBuildVaultEmbeddings(projectId, vault) {
92
+ const vaultPath = vault.storage.vaultPath;
93
+ const cache = ensureActiveProjectCache(projectId);
94
+ const existing = cache.vaultCaches.get(vaultPath);
95
+ if (existing) {
96
+ debugLog("cache:hit", `project=${projectId} vault=${vaultPath} embeddings=${existing.embeddings.length}`);
97
+ return existing.embeddings;
98
+ }
99
+ debugLog("cache:miss", `project=${projectId} vault=${vaultPath}`);
100
+ try {
101
+ const t0 = performance.now();
102
+ const [noteList, embeddings] = await Promise.all([
103
+ vault.storage.listNotes(),
104
+ vault.storage.listEmbeddings(),
105
+ ]);
106
+ const notesById = new Map(noteList.map((n) => [n.id, n]));
107
+ cache.vaultCaches.set(vaultPath, { notesById, noteList, embeddings });
108
+ const ms = (performance.now() - t0).toFixed(1);
109
+ debugLog("cache:build", `project=${projectId} vault=${vaultPath} notes=${noteList.length} embeddings=${embeddings.length} time=${ms}ms`);
110
+ return embeddings;
111
+ }
112
+ catch (err) {
113
+ debugLog("cache:fallback", `project=${projectId} vault=${vaultPath} error=${String(err)}`);
114
+ return undefined;
115
+ }
116
+ }
117
+ /**
118
+ * Look up a single note from an already-built vault cache.
119
+ * Returns `undefined` when the vault cache has not been built yet or the note is not found.
120
+ * Does NOT trigger a cache build — callers should use `getOrBuildVaultNoteList` or
121
+ * `getOrBuildVaultEmbeddings` to ensure the vault cache is warm first.
122
+ */
123
+ export function getSessionCachedNote(projectId, vaultPath, noteId) {
124
+ const cache = sessionCaches.activeProject;
125
+ if (!cache || cache.projectId !== projectId)
126
+ return undefined;
127
+ return cache.vaultCaches.get(vaultPath)?.notesById.get(noteId);
128
+ }
129
+ /**
130
+ * Retrieve a cached projection for a note.
131
+ * Returns `undefined` when no cache or projection exists.
132
+ */
133
+ export function getSessionCachedProjection(projectId, noteId) {
134
+ const cache = sessionCaches.activeProject;
135
+ if (!cache || cache.projectId !== projectId)
136
+ return undefined;
137
+ return cache.projectionsById.get(noteId);
138
+ }
139
+ /**
140
+ * Store a projection in the session cache.
141
+ * No-op when no active cache exists for this project.
142
+ */
143
+ export function setSessionCachedProjection(projectId, noteId, projection) {
144
+ const cache = sessionCaches.activeProject;
145
+ if (!cache || cache.projectId !== projectId)
146
+ return;
147
+ cache.projectionsById.set(noteId, projection);
148
+ }
149
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}