@mneme-ai/core 2.24.0 → 2.25.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 (37) hide show
  1. package/dist/codegraph/builder.d.ts +27 -0
  2. package/dist/codegraph/builder.d.ts.map +1 -0
  3. package/dist/codegraph/builder.js +309 -0
  4. package/dist/codegraph/builder.js.map +1 -0
  5. package/dist/codegraph/codegraph.test.d.ts +2 -0
  6. package/dist/codegraph/codegraph.test.d.ts.map +1 -0
  7. package/dist/codegraph/codegraph.test.js +179 -0
  8. package/dist/codegraph/codegraph.test.js.map +1 -0
  9. package/dist/codegraph/drift.d.ts +27 -0
  10. package/dist/codegraph/drift.d.ts.map +1 -0
  11. package/dist/codegraph/drift.js +126 -0
  12. package/dist/codegraph/drift.js.map +1 -0
  13. package/dist/codegraph/index.d.ts +10 -0
  14. package/dist/codegraph/index.d.ts.map +1 -0
  15. package/dist/codegraph/index.js +10 -0
  16. package/dist/codegraph/index.js.map +1 -0
  17. package/dist/codegraph/merkle.d.ts +40 -0
  18. package/dist/codegraph/merkle.d.ts.map +1 -0
  19. package/dist/codegraph/merkle.js +68 -0
  20. package/dist/codegraph/merkle.js.map +1 -0
  21. package/dist/codegraph/query.d.ts +14 -0
  22. package/dist/codegraph/query.d.ts.map +1 -0
  23. package/dist/codegraph/query.js +56 -0
  24. package/dist/codegraph/query.js.map +1 -0
  25. package/dist/codegraph/store.d.ts +37 -0
  26. package/dist/codegraph/store.d.ts.map +1 -0
  27. package/dist/codegraph/store.js +133 -0
  28. package/dist/codegraph/store.js.map +1 -0
  29. package/dist/codegraph/types.d.ts +140 -0
  30. package/dist/codegraph/types.d.ts.map +1 -0
  31. package/dist/codegraph/types.js +39 -0
  32. package/dist/codegraph/types.js.map +1 -0
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +9 -0
  36. package/dist/index.js.map +1 -1
  37. package/package.json +1 -1
@@ -0,0 +1,27 @@
1
+ /**
2
+ * v2.25.0 — LIVING SOUL CODEGRAPH builder.
3
+ *
4
+ * Walks the repo (respecting .gitignore via the existing chunker pattern)
5
+ * and extracts:
6
+ * - file nodes
7
+ * - exported symbols (function / class / const / type / interface)
8
+ * - import edges (file → file or file → external dep)
9
+ * - export edges (file → symbol)
10
+ *
11
+ * Uses lightweight regex parsing — fast (~10ms per file) + zero TypeScript
12
+ * compiler dependency. Tradeoff: misses dynamic imports, computed names,
13
+ * and complex re-exports. v2.25.x can swap in a real AST parser.
14
+ *
15
+ * Why regex-not-AST: Mneme's positioning is anti-LLM-lock-in; we ship
16
+ * primitives that work offline + cross-platform + with zero peer deps.
17
+ * A regex parser ships now; AST upgrade is opt-in.
18
+ */
19
+ import type { CodeGraph, BuildOptions } from "./types.js";
20
+ /**
21
+ * Build a LIVING SOUL codegraph for a repo. Pure-IO (no spawn), runs
22
+ * sequentially. For 1000-file TS repo, expected ~2-4 seconds cold.
23
+ */
24
+ export declare function buildGraph(repoRoot: string, opts?: BuildOptions): CodeGraph;
25
+ /** Convenience: derive a stable HMAC signature for a full graph snapshot. */
26
+ export declare function graphSignature(graph: CodeGraph): string;
27
+ //# sourceMappingURL=builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../src/codegraph/builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAMH,OAAO,KAAK,EACV,SAAS,EAAsB,YAAY,EAC5C,MAAM,YAAY,CAAC;AA2IpB;;;GAGG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,YAAiB,GAAG,SAAS,CA8I/E;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAQvD"}
@@ -0,0 +1,309 @@
1
+ /**
2
+ * v2.25.0 — LIVING SOUL CODEGRAPH builder.
3
+ *
4
+ * Walks the repo (respecting .gitignore via the existing chunker pattern)
5
+ * and extracts:
6
+ * - file nodes
7
+ * - exported symbols (function / class / const / type / interface)
8
+ * - import edges (file → file or file → external dep)
9
+ * - export edges (file → symbol)
10
+ *
11
+ * Uses lightweight regex parsing — fast (~10ms per file) + zero TypeScript
12
+ * compiler dependency. Tradeoff: misses dynamic imports, computed names,
13
+ * and complex re-exports. v2.25.x can swap in a real AST parser.
14
+ *
15
+ * Why regex-not-AST: Mneme's positioning is anti-LLM-lock-in; we ship
16
+ * primitives that work offline + cross-platform + with zero peer deps.
17
+ * A regex parser ships now; AST upgrade is opt-in.
18
+ */
19
+ import { existsSync, readdirSync, statSync, readFileSync } from "node:fs";
20
+ import { createHash, createHmac } from "node:crypto";
21
+ import { join, relative, resolve, dirname, extname, sep, posix } from "node:path";
22
+ import { canon } from "./types.js";
23
+ import { chainEdges } from "./store.js";
24
+ import { merkleRoot } from "./merkle.js";
25
+ const HMAC_KEY = process.env["MNEME_CODEGRAPH_KEY"] ?? "mneme-codegraph-v1";
26
+ const DEFAULT_EXCLUDE = new Set([
27
+ "node_modules", ".git", "dist", "build", ".next", ".turbo",
28
+ ".cache", "coverage", ".mneme", ".vscode", ".idea", "out",
29
+ ]);
30
+ const TS_JS_EXT = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
31
+ /** Stable id helpers. */
32
+ function shortHash(s) {
33
+ return createHash("sha256").update(s).digest("hex").slice(0, 12);
34
+ }
35
+ function nodeId(kind, path, symbol) {
36
+ const key = `${kind}|${path}|${symbol ?? ""}`;
37
+ return `${kind}:${shortHash(key)}`;
38
+ }
39
+ function edgeId(srcId, dstId, kind) {
40
+ return shortHash(`${srcId}>${dstId}>${kind}`);
41
+ }
42
+ function toPosix(p) {
43
+ return p.split(sep).join("/");
44
+ }
45
+ function* walk(dir, repoRoot, opts) {
46
+ let entries;
47
+ try {
48
+ entries = readdirSync(dir);
49
+ }
50
+ catch {
51
+ return;
52
+ }
53
+ for (const name of entries) {
54
+ if (opts.exclude.has(name))
55
+ continue;
56
+ if (name.startsWith(".") && opts.exclude.has(name))
57
+ continue;
58
+ const full = join(dir, name);
59
+ let stat;
60
+ try {
61
+ stat = statSync(full);
62
+ }
63
+ catch {
64
+ continue;
65
+ }
66
+ if (stat.isDirectory()) {
67
+ yield* walk(full, repoRoot, opts);
68
+ }
69
+ else if (stat.isFile()) {
70
+ if (stat.size > opts.maxBytes)
71
+ continue;
72
+ const rel = toPosix(relative(repoRoot, full));
73
+ const ext = extname(name).toLowerCase();
74
+ if (!TS_JS_EXT.has(ext))
75
+ continue;
76
+ yield rel;
77
+ }
78
+ }
79
+ }
80
+ // ─── regex parsers ─────────────────────────────────────────────────
81
+ // import { X, Y } from "./foo"
82
+ // import X from "./foo"
83
+ // import * as X from "./foo"
84
+ // import "./foo"
85
+ const IMPORT_RE = /import(?:\s+(?:\*\s+as\s+\w+|\{[^}]*\}|\w+)(?:\s*,\s*(?:\*\s+as\s+\w+|\{[^}]*\}|\w+))*\s+from)?\s*['"]([^'"]+)['"]/g;
86
+ const DYN_IMPORT_RE = /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
87
+ const REQUIRE_RE = /\brequire\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
88
+ // Exported declarations
89
+ const EXPORT_FN_RE = /^export\s+(?:async\s+)?function\s+(\w+)/gm;
90
+ const EXPORT_CLASS_RE = /^export\s+(?:abstract\s+)?class\s+(\w+)/gm;
91
+ const EXPORT_CONST_RE = /^export\s+(?:const|let|var)\s+(\w+)/gm;
92
+ const EXPORT_TYPE_RE = /^export\s+type\s+(\w+)/gm;
93
+ const EXPORT_INTERFACE_RE = /^export\s+interface\s+(\w+)/gm;
94
+ const EXPORT_DEFAULT_RE = /^export\s+default\s+(?:async\s+function\s+(\w+)?|class\s+(\w+)?|(\w+))/gm;
95
+ // re-exports: `export { X } from "./foo"`
96
+ const EXPORT_REEXPORT_RE = /^export\s+(?:\{[^}]*\}|\*\s+(?:as\s+\w+\s+)?)\s+from\s+['"]([^'"]+)['"]/gm;
97
+ function parseFile(content) {
98
+ const imports = new Set();
99
+ for (const re of [IMPORT_RE, DYN_IMPORT_RE, REQUIRE_RE, EXPORT_REEXPORT_RE]) {
100
+ re.lastIndex = 0;
101
+ let m;
102
+ while ((m = re.exec(content)) !== null) {
103
+ const spec = m[1];
104
+ if (spec)
105
+ imports.add(spec);
106
+ }
107
+ }
108
+ const exports = [];
109
+ const collect = (re, kind) => {
110
+ re.lastIndex = 0;
111
+ let m;
112
+ while ((m = re.exec(content)) !== null) {
113
+ const idx = m.index;
114
+ const line = content.slice(0, idx).split("\n").length;
115
+ // EXPORT_DEFAULT_RE has 3 capture groups; pick the first non-null
116
+ const sym = m[1] ?? m[2] ?? m[3];
117
+ if (sym)
118
+ exports.push({ kind, symbol: sym, line });
119
+ }
120
+ };
121
+ collect(EXPORT_FN_RE, "function");
122
+ collect(EXPORT_CLASS_RE, "class");
123
+ collect(EXPORT_CONST_RE, "constant");
124
+ collect(EXPORT_TYPE_RE, "type");
125
+ collect(EXPORT_INTERFACE_RE, "interface");
126
+ collect(EXPORT_DEFAULT_RE, "function"); // default export — best-effort
127
+ return { imports: [...imports], exports };
128
+ }
129
+ /** Resolve a relative import spec to a repo-relative path (best-effort). */
130
+ function resolveImport(fromFile, spec, knownFiles) {
131
+ if (!spec.startsWith("."))
132
+ return null; // external
133
+ const fromDir = dirname(fromFile);
134
+ const baseAbs = posix.normalize(posix.join(fromDir, spec));
135
+ // Try common extensions
136
+ const candidates = [
137
+ baseAbs,
138
+ baseAbs + ".ts", baseAbs + ".tsx", baseAbs + ".js", baseAbs + ".jsx",
139
+ baseAbs + ".mjs", baseAbs + ".cjs",
140
+ posix.join(baseAbs, "index.ts"), posix.join(baseAbs, "index.tsx"),
141
+ posix.join(baseAbs, "index.js"), posix.join(baseAbs, "index.jsx"),
142
+ // .js → .ts (TypeScript NodeNext: import "./foo.js" actually means foo.ts)
143
+ baseAbs.endsWith(".js") ? baseAbs.replace(/\.js$/, ".ts") : "",
144
+ baseAbs.endsWith(".js") ? baseAbs.replace(/\.js$/, ".tsx") : "",
145
+ baseAbs.endsWith(".jsx") ? baseAbs.replace(/\.jsx$/, ".tsx") : "",
146
+ ].filter(Boolean);
147
+ for (const c of candidates) {
148
+ if (knownFiles.has(c))
149
+ return c;
150
+ }
151
+ return null;
152
+ }
153
+ /**
154
+ * Build a LIVING SOUL codegraph for a repo. Pure-IO (no spawn), runs
155
+ * sequentially. For 1000-file TS repo, expected ~2-4 seconds cold.
156
+ */
157
+ export function buildGraph(repoRoot, opts = {}) {
158
+ const exclude = new Set(opts.exclude ?? [...DEFAULT_EXCLUDE]);
159
+ const maxBytes = opts.maxBytes ?? 500_000;
160
+ const touchedBy = opts.touchedBy ?? "mneme-daemon";
161
+ // Walk to discover files first (so we can resolve relative imports).
162
+ const files = [];
163
+ for (const rel of walk(repoRoot, repoRoot, { exclude, maxBytes, include: opts.include })) {
164
+ files.push(rel);
165
+ }
166
+ const knownFiles = new Set(files);
167
+ const nodes = new Map();
168
+ const edges = new Map();
169
+ const builtAt = new Date().toISOString();
170
+ // Detect current commit (best-effort).
171
+ let commit = "WORKING-TREE";
172
+ try {
173
+ const headPath = resolve(repoRoot, ".git", "HEAD");
174
+ if (existsSync(headPath)) {
175
+ const head = readFileSync(headPath, "utf8").trim();
176
+ if (head.startsWith("ref: ")) {
177
+ const ref = head.slice(5);
178
+ const refPath = resolve(repoRoot, ".git", ref);
179
+ if (existsSync(refPath))
180
+ commit = readFileSync(refPath, "utf8").trim();
181
+ }
182
+ else {
183
+ commit = head;
184
+ }
185
+ }
186
+ }
187
+ catch { /* best-effort */ }
188
+ for (const rel of files) {
189
+ const fileNode = {
190
+ id: nodeId("file", rel),
191
+ kind: "file",
192
+ path: rel,
193
+ lang: extname(rel).slice(1),
194
+ };
195
+ nodes.set(fileNode.id, fileNode);
196
+ let content;
197
+ try {
198
+ content = readFileSync(resolve(repoRoot, rel), "utf8");
199
+ }
200
+ catch {
201
+ continue;
202
+ }
203
+ const { imports, exports } = parseFile(content);
204
+ // Exported symbol nodes + export edges
205
+ for (const ex of exports) {
206
+ const symNode = {
207
+ id: nodeId(ex.kind, rel, ex.symbol),
208
+ kind: ex.kind,
209
+ path: rel,
210
+ symbol: ex.symbol,
211
+ line: ex.line,
212
+ lang: extname(rel).slice(1),
213
+ };
214
+ nodes.set(symNode.id, symNode);
215
+ const e = {
216
+ id: edgeId(fileNode.id, symNode.id, "exports"),
217
+ src: fileNode.id,
218
+ dst: symNode.id,
219
+ kind: "exports",
220
+ confidence: 1,
221
+ lastSeen: builtAt,
222
+ touchedBy,
223
+ firstSeenCommit: commit,
224
+ hmac: "", // filled below by chainEdges
225
+ };
226
+ edges.set(e.id, e);
227
+ }
228
+ // Import edges
229
+ for (const spec of imports) {
230
+ const resolved = resolveImport(rel, spec, knownFiles);
231
+ let dstId;
232
+ if (resolved) {
233
+ dstId = nodeId("file", resolved);
234
+ // Resolved file node may not exist if it was a duplicate; ensure it.
235
+ if (!nodes.has(dstId)) {
236
+ nodes.set(dstId, {
237
+ id: dstId,
238
+ kind: "file",
239
+ path: resolved,
240
+ lang: extname(resolved).slice(1),
241
+ });
242
+ }
243
+ }
244
+ else {
245
+ // external dep → "external" node
246
+ dstId = nodeId("external", spec);
247
+ if (!nodes.has(dstId)) {
248
+ nodes.set(dstId, {
249
+ id: dstId,
250
+ kind: "external",
251
+ path: spec,
252
+ });
253
+ }
254
+ }
255
+ const e = {
256
+ id: edgeId(fileNode.id, dstId, "imports"),
257
+ src: fileNode.id,
258
+ dst: dstId,
259
+ kind: "imports",
260
+ confidence: resolved ? 1 : 0.7,
261
+ lastSeen: builtAt,
262
+ touchedBy,
263
+ firstSeenCommit: commit,
264
+ hmac: "",
265
+ };
266
+ edges.set(e.id, e);
267
+ }
268
+ }
269
+ // Chain edges in canonical (id-sorted) order so the hmac sequence is
270
+ // deterministic across machines.
271
+ const sortedEdges = [...edges.values()].sort((a, b) => a.id.localeCompare(b.id));
272
+ chainEdges(sortedEdges);
273
+ // Rewrite back to the map with chained edges (preserving the order).
274
+ edges.clear();
275
+ for (const e of sortedEdges)
276
+ edges.set(e.id, e);
277
+ // Merkle root over chained edges.
278
+ const root = merkleRoot(sortedEdges);
279
+ // Stats
280
+ const byKind = {};
281
+ for (const n of nodes.values())
282
+ byKind[n.kind] = (byKind[n.kind] ?? 0) + 1;
283
+ for (const e of edges.values())
284
+ byKind[`edge:${e.kind}`] = (byKind[`edge:${e.kind}`] ?? 0) + 1;
285
+ return {
286
+ repoRoot,
287
+ commit,
288
+ builtAt,
289
+ nodes,
290
+ edges,
291
+ merkleRoot: root,
292
+ stats: {
293
+ nodes: nodes.size,
294
+ edges: edges.size,
295
+ byKind,
296
+ },
297
+ };
298
+ }
299
+ /** Convenience: derive a stable HMAC signature for a full graph snapshot. */
300
+ export function graphSignature(graph) {
301
+ const payload = {
302
+ commit: graph.commit,
303
+ merkleRoot: graph.merkleRoot,
304
+ nodeCount: graph.nodes.size,
305
+ edgeCount: graph.edges.size,
306
+ };
307
+ return createHmac("sha256", HMAC_KEY).update(canon(payload)).digest("hex").slice(0, 32);
308
+ }
309
+ //# sourceMappingURL=builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builder.js","sourceRoot":"","sources":["../../src/codegraph/builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=codegraph.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegraph.test.d.ts","sourceRoot":"","sources":["../../src/codegraph/codegraph.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,179 @@
1
+ // v2.25.0 — LIVING SOUL CODEGRAPH unit tests.
2
+ import { describe, it, expect, beforeEach } from "vitest";
3
+ import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+ import { buildGraph, graphSignature, verifyChain, chainEdges, merkleRoot, leafHash, __EMPTY_ROOT_SENTINEL, query, neighbours, markVaccineWarning, detectDrift, edgesTouchedBy, writeSnapshot, readSnapshot, } from "./index.js";
7
+ function mkTinyRepo() {
8
+ const dir = mkdtempSync(join(tmpdir(), "mneme-codegraph-test-"));
9
+ // src/a.ts: imports ./b + ./external
10
+ // src/b.ts: exports function foo
11
+ // src/c.ts: imports ./b, calls foo (we won't extract call edges in v2.25.0; just imports)
12
+ mkdirSync(join(dir, "src"), { recursive: true });
13
+ writeFileSync(join(dir, "src", "a.ts"), `import { foo } from "./b.js";\nimport pkg from "some-external";\nexport function alpha() { return foo(); }\n`);
14
+ writeFileSync(join(dir, "src", "b.ts"), `export function foo() { return 1; }\nexport const X = 42;\nexport interface Bar { y: number }\n`);
15
+ writeFileSync(join(dir, "src", "c.ts"), `import { foo } from "./b.js";\nexport class Cee {}\n`);
16
+ return dir;
17
+ }
18
+ describe("codegraph — builder", () => {
19
+ let repo;
20
+ beforeEach(() => { repo = mkTinyRepo(); });
21
+ it("builds the graph with expected node + edge counts", () => {
22
+ const g = buildGraph(repo);
23
+ // 3 file nodes + 1 external + symbols (alpha / foo / X / Bar / Cee = 5)
24
+ expect(g.nodes.size).toBeGreaterThanOrEqual(8);
25
+ // imports: a→b, a→external, c→b = 3 ; exports: alpha + foo + X + Bar + Cee = 5
26
+ expect(g.edges.size).toBeGreaterThanOrEqual(8);
27
+ expect(g.merkleRoot).toMatch(/^[0-9a-f]{64}$/);
28
+ expect(g.merkleRoot).not.toBe(__EMPTY_ROOT_SENTINEL);
29
+ });
30
+ it("merkle root is deterministic across rebuilds", () => {
31
+ const a = buildGraph(repo);
32
+ const b = buildGraph(repo);
33
+ expect(a.merkleRoot).toBe(b.merkleRoot);
34
+ });
35
+ it("graphSignature is stable across rebuilds (same commit + edge set)", () => {
36
+ const a = buildGraph(repo);
37
+ const b = buildGraph(repo);
38
+ expect(graphSignature(a)).toBe(graphSignature(b));
39
+ });
40
+ it("file edges reach the right symbols", () => {
41
+ const g = buildGraph(repo);
42
+ const exportEdges = [...g.edges.values()].filter((e) => e.kind === "exports");
43
+ const symbols = exportEdges.map((e) => g.nodes.get(e.dst)?.symbol).filter(Boolean);
44
+ expect(symbols).toEqual(expect.arrayContaining(["foo", "alpha", "X", "Bar", "Cee"]));
45
+ });
46
+ });
47
+ describe("codegraph — HMAC chain", () => {
48
+ it("verifyChain accepts a freshly-chained edge list", () => {
49
+ const repo = mkTinyRepo();
50
+ const g = buildGraph(repo);
51
+ const edges = [...g.edges.values()].sort((a, b) => a.id.localeCompare(b.id));
52
+ const r = verifyChain(edges);
53
+ expect(r.ok).toBe(true);
54
+ });
55
+ it("verifyChain detects a tampered edge", () => {
56
+ const repo = mkTinyRepo();
57
+ const g = buildGraph(repo);
58
+ const edges = [...g.edges.values()].sort((a, b) => a.id.localeCompare(b.id));
59
+ // tamper: change confidence on the middle edge but DON'T re-chain
60
+ const mid = Math.floor(edges.length / 2);
61
+ edges[mid].confidence = 0.0001;
62
+ const r = verifyChain(edges);
63
+ expect(r.ok).toBe(false);
64
+ });
65
+ it("verifyChain detects an inserted edge", () => {
66
+ const repo = mkTinyRepo();
67
+ const g = buildGraph(repo);
68
+ const edges = [...g.edges.values()].sort((a, b) => a.id.localeCompare(b.id));
69
+ const fake = {
70
+ id: "fake",
71
+ src: "x",
72
+ dst: "y",
73
+ kind: "imports",
74
+ confidence: 1,
75
+ lastSeen: new Date().toISOString(),
76
+ hmac: "deadbeef",
77
+ };
78
+ edges.splice(1, 0, fake);
79
+ const r = verifyChain(edges);
80
+ expect(r.ok).toBe(false);
81
+ });
82
+ });
83
+ describe("codegraph — Merkle", () => {
84
+ it("empty edge list returns the sentinel", () => {
85
+ expect(merkleRoot([])).toBe(__EMPTY_ROOT_SENTINEL);
86
+ });
87
+ it("single edge yields a stable leaf hash", () => {
88
+ const e = {
89
+ id: "abc",
90
+ src: "x",
91
+ dst: "y",
92
+ kind: "imports",
93
+ confidence: 1,
94
+ lastSeen: "2026-05-22T00:00:00.000Z",
95
+ hmac: "ignored-for-leaf",
96
+ };
97
+ const leaf = leafHash(e);
98
+ expect(leaf).toMatch(/^[0-9a-f]{64}$/);
99
+ // root over 1 edge = the leaf hash itself
100
+ expect(merkleRoot([e])).toBe(leaf);
101
+ });
102
+ it("changing any edge field changes the root", () => {
103
+ const repo = mkTinyRepo();
104
+ const g1 = buildGraph(repo);
105
+ const edges1 = [...g1.edges.values()].sort((a, b) => a.id.localeCompare(b.id));
106
+ const edges2 = JSON.parse(JSON.stringify(edges1));
107
+ edges2[0].kind = "calls"; // mutate
108
+ chainEdges(edges2); // re-chain
109
+ expect(merkleRoot(edges1)).not.toBe(merkleRoot(edges2));
110
+ });
111
+ });
112
+ describe("codegraph — query", () => {
113
+ it("filters nodes by kind", () => {
114
+ const repo = mkTinyRepo();
115
+ const g = buildGraph(repo);
116
+ const r = query(g, { kind: "function" });
117
+ expect(r.nodes.every((n) => n.kind === "function")).toBe(true);
118
+ expect(r.nodes.length).toBeGreaterThan(0);
119
+ });
120
+ it("filters edges by warningsOnly", () => {
121
+ const repo = mkTinyRepo();
122
+ const g = buildGraph(repo);
123
+ const first = [...g.edges.values()][0];
124
+ markVaccineWarning(g, first.id, "hallucinated by AI X");
125
+ const r = query(g, { warningsOnly: true });
126
+ expect(r.edges.length).toBe(1);
127
+ expect(r.edges[0].vaccineWarning).toBe(true);
128
+ });
129
+ it("neighbours returns incoming + outgoing", () => {
130
+ const repo = mkTinyRepo();
131
+ const g = buildGraph(repo);
132
+ const fileB = [...g.nodes.values()].find((n) => n.kind === "file" && n.path.endsWith("b.ts"));
133
+ const nb = neighbours(g, fileB.id);
134
+ expect(nb.node?.id).toBe(fileB.id);
135
+ // b.ts has 2 incoming imports (from a + c) and 3 outgoing exports (foo, X, Bar)
136
+ expect(nb.incoming.length).toBeGreaterThanOrEqual(2);
137
+ expect(nb.outgoing.length).toBeGreaterThanOrEqual(3);
138
+ });
139
+ });
140
+ describe("codegraph — drift", () => {
141
+ it("reports zero drift on a freshly-built graph", () => {
142
+ const repo = mkTinyRepo();
143
+ const g = buildGraph(repo);
144
+ const d = detectDrift(g);
145
+ expect(d.events.length).toBe(0);
146
+ expect(d.brokenEdges).toBe(0);
147
+ });
148
+ it("detects drift when a file is deleted", () => {
149
+ const repo = mkTinyRepo();
150
+ const g = buildGraph(repo);
151
+ rmSync(join(repo, "src", "b.ts"));
152
+ const d = detectDrift(g);
153
+ expect(d.events.length).toBeGreaterThan(0);
154
+ expect(d.brokenEdges).toBeGreaterThan(0);
155
+ // The b.ts deletion breaks: a → b imports, c → b imports, and exports edges from b
156
+ expect(d.missingFiles).toBeGreaterThanOrEqual(1);
157
+ });
158
+ it("edgesTouchedBy returns edges that involve the changed paths", () => {
159
+ const repo = mkTinyRepo();
160
+ const g = buildGraph(repo);
161
+ const touched = edgesTouchedBy(g, ["src/b.ts"]);
162
+ // src/b.ts is imported by a + c, AND has 3 export edges → ≥ 5 edges
163
+ expect(touched.length).toBeGreaterThanOrEqual(5);
164
+ });
165
+ });
166
+ describe("codegraph — snapshot round-trip", () => {
167
+ it("writes and reads back the same graph", () => {
168
+ const repo = mkTinyRepo();
169
+ const g = buildGraph(repo);
170
+ writeSnapshot(repo, g);
171
+ const re = readSnapshot(repo);
172
+ expect(re).not.toBeNull();
173
+ expect(re.merkleRoot).toBe(g.merkleRoot);
174
+ expect(re.nodes.size).toBe(g.nodes.size);
175
+ expect(re.edges.size).toBe(g.edges.size);
176
+ expect(re.commit).toBe(g.commit);
177
+ });
178
+ });
179
+ //# sourceMappingURL=codegraph.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegraph.test.js","sourceRoot":"","sources":["../../src/codegraph/codegraph.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * v2.25.0 — Drift sentinel for LIVING SOUL codegraph.
3
+ *
4
+ * Compares the persisted snapshot against the current working tree and
5
+ * emits one DriftEvent per broken edge:
6
+ * - file deleted (src or dst missing)
7
+ * - file renamed (symbol moved to another path)
8
+ * - edge stale (file mtime > builtAt by > N hours)
9
+ *
10
+ * Pure-IO; no daemon required. The daemon can call this on every tick
11
+ * + fan-out severity ≥ "high" events to the notifier so the user gets
12
+ * a heads-up before the AI starts editing the wrong file.
13
+ */
14
+ import type { CodeGraph, DriftEvent, CodeEdge } from "./types.js";
15
+ export interface DriftSummary {
16
+ events: DriftEvent[];
17
+ brokenEdges: number;
18
+ staleEdges: number;
19
+ missingFiles: number;
20
+ }
21
+ /** Scan the graph against the current working tree. */
22
+ export declare function detectDrift(graph: CodeGraph, opts?: {
23
+ record?: boolean;
24
+ }): DriftSummary;
25
+ /** Filter edges that would BREAK if a file is renamed/deleted. */
26
+ export declare function edgesTouchedBy(graph: CodeGraph, paths: string[]): CodeEdge[];
27
+ //# sourceMappingURL=drift.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift.d.ts","sourceRoot":"","sources":["../../src/codegraph/drift.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKlE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,uDAAuD;AACvD,wBAAgB,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,YAAY,CAkF3F;AAED,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAU5E"}