@mneme-ai/core 0.8.3 → 0.9.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 (144) hide show
  1. package/dist/entities/go-parser.d.ts +47 -0
  2. package/dist/entities/go-parser.d.ts.map +1 -0
  3. package/dist/entities/go-parser.js +315 -0
  4. package/dist/entities/go-parser.js.map +1 -0
  5. package/dist/entities/go-parser.test.d.ts +2 -0
  6. package/dist/entities/go-parser.test.d.ts.map +1 -0
  7. package/dist/entities/go-parser.test.js +147 -0
  8. package/dist/entities/go-parser.test.js.map +1 -0
  9. package/dist/entities/index.d.ts +1 -0
  10. package/dist/entities/index.d.ts.map +1 -1
  11. package/dist/entities/index.js +1 -0
  12. package/dist/entities/index.js.map +1 -1
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/indexer/indexer.d.ts +12 -0
  18. package/dist/indexer/indexer.d.ts.map +1 -1
  19. package/dist/indexer/indexer.js +28 -1
  20. package/dist/indexer/indexer.js.map +1 -1
  21. package/dist/insights/decisions.d.ts +38 -0
  22. package/dist/insights/decisions.d.ts.map +1 -0
  23. package/dist/insights/decisions.js +125 -0
  24. package/dist/insights/decisions.js.map +1 -0
  25. package/dist/insights/decisions.test.d.ts +2 -0
  26. package/dist/insights/decisions.test.d.ts.map +1 -0
  27. package/dist/insights/decisions.test.js +141 -0
  28. package/dist/insights/decisions.test.js.map +1 -0
  29. package/dist/insights/dream.d.ts +71 -0
  30. package/dist/insights/dream.d.ts.map +1 -0
  31. package/dist/insights/dream.js +235 -0
  32. package/dist/insights/dream.js.map +1 -0
  33. package/dist/insights/dream.test.d.ts +2 -0
  34. package/dist/insights/dream.test.d.ts.map +1 -0
  35. package/dist/insights/dream.test.js +127 -0
  36. package/dist/insights/dream.test.js.map +1 -0
  37. package/dist/insights/index.d.ts +16 -0
  38. package/dist/insights/index.d.ts.map +1 -0
  39. package/dist/insights/index.js +16 -0
  40. package/dist/insights/index.js.map +1 -0
  41. package/dist/insights/obsidian.d.ts +42 -0
  42. package/dist/insights/obsidian.d.ts.map +1 -0
  43. package/dist/insights/obsidian.js +263 -0
  44. package/dist/insights/obsidian.js.map +1 -0
  45. package/dist/insights/obsidian.test.d.ts +2 -0
  46. package/dist/insights/obsidian.test.d.ts.map +1 -0
  47. package/dist/insights/obsidian.test.js +241 -0
  48. package/dist/insights/obsidian.test.js.map +1 -0
  49. package/dist/insights/stack-trace.d.ts +40 -0
  50. package/dist/insights/stack-trace.d.ts.map +1 -0
  51. package/dist/insights/stack-trace.js +127 -0
  52. package/dist/insights/stack-trace.js.map +1 -0
  53. package/dist/insights/stack-trace.test.d.ts +2 -0
  54. package/dist/insights/stack-trace.test.d.ts.map +1 -0
  55. package/dist/insights/stack-trace.test.js +103 -0
  56. package/dist/insights/stack-trace.test.js.map +1 -0
  57. package/dist/insights/story.d.ts +34 -0
  58. package/dist/insights/story.d.ts.map +1 -0
  59. package/dist/insights/story.js +100 -0
  60. package/dist/insights/story.js.map +1 -0
  61. package/dist/insights/story.test.d.ts +2 -0
  62. package/dist/insights/story.test.d.ts.map +1 -0
  63. package/dist/insights/story.test.js +99 -0
  64. package/dist/insights/story.test.js.map +1 -0
  65. package/dist/insights/suggest.d.ts +29 -0
  66. package/dist/insights/suggest.d.ts.map +1 -0
  67. package/dist/insights/suggest.js +93 -0
  68. package/dist/insights/suggest.js.map +1 -0
  69. package/dist/insights/suggest.test.d.ts +2 -0
  70. package/dist/insights/suggest.test.d.ts.map +1 -0
  71. package/dist/insights/suggest.test.js +71 -0
  72. package/dist/insights/suggest.test.js.map +1 -0
  73. package/dist/insights/who-knows.d.ts +48 -0
  74. package/dist/insights/who-knows.d.ts.map +1 -0
  75. package/dist/insights/who-knows.js +96 -0
  76. package/dist/insights/who-knows.js.map +1 -0
  77. package/dist/insights/who-knows.test.d.ts +2 -0
  78. package/dist/insights/who-knows.test.d.ts.map +1 -0
  79. package/dist/insights/who-knows.test.js +47 -0
  80. package/dist/insights/who-knows.test.js.map +1 -0
  81. package/dist/retrieve/index.d.ts +2 -0
  82. package/dist/retrieve/index.d.ts.map +1 -1
  83. package/dist/retrieve/index.js +2 -0
  84. package/dist/retrieve/index.js.map +1 -1
  85. package/dist/retrieve/intent.d.ts +32 -0
  86. package/dist/retrieve/intent.d.ts.map +1 -0
  87. package/dist/retrieve/intent.js +104 -0
  88. package/dist/retrieve/intent.js.map +1 -0
  89. package/dist/retrieve/intent.test.d.ts +2 -0
  90. package/dist/retrieve/intent.test.d.ts.map +1 -0
  91. package/dist/retrieve/intent.test.js +106 -0
  92. package/dist/retrieve/intent.test.js.map +1 -0
  93. package/dist/retrieve/search.d.ts +30 -0
  94. package/dist/retrieve/search.d.ts.map +1 -1
  95. package/dist/retrieve/search.js +48 -0
  96. package/dist/retrieve/search.js.map +1 -1
  97. package/dist/retrieve/search.test.js +84 -1
  98. package/dist/retrieve/search.test.js.map +1 -1
  99. package/dist/retrieve/synthesize.d.ts +57 -0
  100. package/dist/retrieve/synthesize.d.ts.map +1 -0
  101. package/dist/retrieve/synthesize.js +160 -0
  102. package/dist/retrieve/synthesize.js.map +1 -0
  103. package/dist/retrieve/synthesize.test.d.ts +2 -0
  104. package/dist/retrieve/synthesize.test.d.ts.map +1 -0
  105. package/dist/retrieve/synthesize.test.js +116 -0
  106. package/dist/retrieve/synthesize.test.js.map +1 -0
  107. package/dist/store/schema.d.ts +2 -2
  108. package/dist/store/schema.d.ts.map +1 -1
  109. package/dist/store/schema.js +55 -1
  110. package/dist/store/schema.js.map +1 -1
  111. package/dist/store/sqlite.test.js +1 -1
  112. package/dist/util/index.d.ts +2 -0
  113. package/dist/util/index.d.ts.map +1 -1
  114. package/dist/util/index.js +2 -1
  115. package/dist/util/index.js.map +1 -1
  116. package/dist/util/redact.d.ts +58 -0
  117. package/dist/util/redact.d.ts.map +1 -0
  118. package/dist/util/redact.js +129 -0
  119. package/dist/util/redact.js.map +1 -0
  120. package/dist/util/redact.test.d.ts +2 -0
  121. package/dist/util/redact.test.d.ts.map +1 -0
  122. package/dist/util/redact.test.js +148 -0
  123. package/dist/util/redact.test.js.map +1 -0
  124. package/dist/wisdom/calibrator.d.ts +43 -0
  125. package/dist/wisdom/calibrator.d.ts.map +1 -0
  126. package/dist/wisdom/calibrator.js +120 -0
  127. package/dist/wisdom/calibrator.js.map +1 -0
  128. package/dist/wisdom/feedback.d.ts +45 -0
  129. package/dist/wisdom/feedback.d.ts.map +1 -0
  130. package/dist/wisdom/feedback.js +116 -0
  131. package/dist/wisdom/feedback.js.map +1 -0
  132. package/dist/wisdom/index.d.ts +15 -0
  133. package/dist/wisdom/index.d.ts.map +1 -0
  134. package/dist/wisdom/index.js +15 -0
  135. package/dist/wisdom/index.js.map +1 -0
  136. package/dist/wisdom/types.d.ts +67 -0
  137. package/dist/wisdom/types.d.ts.map +1 -0
  138. package/dist/wisdom/types.js +20 -0
  139. package/dist/wisdom/types.js.map +1 -0
  140. package/dist/wisdom/wisdom.test.d.ts +2 -0
  141. package/dist/wisdom/wisdom.test.d.ts.map +1 -0
  142. package/dist/wisdom/wisdom.test.js +144 -0
  143. package/dist/wisdom/wisdom.test.js.map +1 -0
  144. package/package.json +1 -1
@@ -0,0 +1,116 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { synthesize } from "./synthesize.js";
3
+ const sampleCommit = (hash, subject, body = "", author = "alice", date = "2024-08-12") => ({
4
+ hash,
5
+ shortHash: hash.slice(0, 7),
6
+ authorName: author,
7
+ authorEmail: `${author}@example.com`,
8
+ authorDate: `${date}T00:00:00Z`,
9
+ committerDate: `${date}T00:00:00Z`,
10
+ subject,
11
+ body,
12
+ parents: [],
13
+ files: [],
14
+ });
15
+ const result = (hash, score, subject = "test commit", body = "") => ({
16
+ commit: sampleCommit(hash, subject, body),
17
+ score,
18
+ matchedChunks: [],
19
+ });
20
+ describe("synthesize — no LLM (extractive fallback)", () => {
21
+ it("returns no-context answer when confidence is none", async () => {
22
+ const r = await synthesize("vague query", [], "none");
23
+ expect(r.source).toBe("no-context");
24
+ expect(r.evidenceCommitHashes).toEqual([]);
25
+ expect(r.answer.toLowerCase()).toContain("no strong context");
26
+ });
27
+ it("returns no-context answer when results array is empty", async () => {
28
+ const r = await synthesize("any query", [], "high");
29
+ expect(r.source).toBe("no-context");
30
+ });
31
+ it("returns extractive answer when no enricher is provided", async () => {
32
+ const r = await synthesize("stripe bigint", [
33
+ result("abc1234", 0.05, "Fix Stripe BigInt overflow"),
34
+ result("def5678", 0.03, "Add observability for parseAmount"),
35
+ ], "high");
36
+ expect(r.source).toBe("extractive");
37
+ expect(r.answer).toContain("abc1234");
38
+ expect(r.evidenceCommitHashes).toEqual(["abc1234", "def5678"]);
39
+ });
40
+ it("extractive answer uses different phrasing per confidence level", async () => {
41
+ const high = await synthesize("q", [result("abc1234", 0.05, "subject")], "high");
42
+ const medium = await synthesize("q", [result("abc1234", 0.05, "subject")], "medium");
43
+ const low = await synthesize("q", [result("abc1234", 0.05, "subject")], "low");
44
+ expect(high.answer).toContain("most likely");
45
+ expect(medium.answer.toLowerCase()).toContain("possibly");
46
+ expect(low.answer.toLowerCase()).toContain("verify");
47
+ });
48
+ it("extractive answer adapts to result count (1, 2, 3+)", async () => {
49
+ const one = await synthesize("q", [result("abc1234", 0.05, "s1")], "high");
50
+ const two = await synthesize("q", [result("abc1234", 0.05, "s1"), result("def5678", 0.04, "s2")], "high");
51
+ const three = await synthesize("q", [
52
+ result("abc1234", 0.05, "s1"),
53
+ result("def5678", 0.04, "s2"),
54
+ result("ghi9012", 0.03, "s3"),
55
+ ], "high");
56
+ expect(one.answer).toContain("abc1234");
57
+ expect(one.answer).not.toContain("and");
58
+ expect(two.answer).toContain("and");
59
+ expect(three.answer).toContain("also");
60
+ });
61
+ });
62
+ describe("synthesize — with LLM (enricher branch)", () => {
63
+ const fakeEnricher = (returnText) => ({
64
+ name: "fake",
65
+ enrich: async () => ({ text: returnText }),
66
+ });
67
+ it("uses LLM output when enricher succeeds", async () => {
68
+ const r = await synthesize("why does X exist?", [result("abc1234", 0.05, "subj")], "high", fakeEnricher("X exists because of Y. See `abc1234`."));
69
+ expect(r.source).toBe("llm");
70
+ expect(r.answer).toContain("X exists because of Y");
71
+ });
72
+ it("falls back to extractive when LLM throws", async () => {
73
+ const failingEnricher = {
74
+ name: "fake-fail",
75
+ enrich: async () => {
76
+ throw new Error("ollama not reachable");
77
+ },
78
+ };
79
+ const r = await synthesize("q", [result("abc1234", 0.05, "subj")], "high", failingEnricher);
80
+ expect(r.source).toBe("extractive");
81
+ expect(r.answer).toContain("abc1234");
82
+ });
83
+ it("falls back to extractive when LLM returns empty", async () => {
84
+ const r = await synthesize("q", [result("abc1234", 0.05, "subj")], "high", fakeEnricher(" "));
85
+ expect(r.source).toBe("extractive");
86
+ });
87
+ it('strips leading "Answer:" if the model echoed it', async () => {
88
+ const r = await synthesize("q", [result("abc1234", 0.05, "subj")], "high", fakeEnricher('Answer: X is a thing because of Y.'));
89
+ expect(r.answer).not.toMatch(/^answer:/i);
90
+ expect(r.answer).toContain("X is a thing");
91
+ });
92
+ it("strips wrapping quotes if any", async () => {
93
+ const r = await synthesize("q", [result("abc1234", 0.05, "subj")], "high", fakeEnricher('"X exists because Y."'));
94
+ expect(r.answer).not.toMatch(/^"/);
95
+ expect(r.answer).not.toMatch(/"$/);
96
+ });
97
+ it("strips trailing 'Sources:' / 'Citations:' blocks", async () => {
98
+ const r = await synthesize("q", [result("abc1234", 0.05, "subj")], "high", fakeEnricher("X exists because Y.\n\nSources: abc1234, def5678"));
99
+ expect(r.answer.toLowerCase()).not.toContain("sources:");
100
+ });
101
+ it("evidenceCommitHashes is always populated when results > 0", async () => {
102
+ const r = await synthesize("q", [result("abc1234", 0.05), result("def5678", 0.03)], "high", fakeEnricher("answer"));
103
+ expect(r.evidenceCommitHashes).toEqual(["abc1234", "def5678"]);
104
+ });
105
+ });
106
+ describe("synthesize — durationMs and bookkeeping", () => {
107
+ it("durationMs is non-negative", async () => {
108
+ const r = await synthesize("q", [], "none");
109
+ expect(r.durationMs).toBeGreaterThanOrEqual(0);
110
+ });
111
+ it("echoes the confidence label", async () => {
112
+ const r = await synthesize("q", [result("abc1234", 0.05, "s")], "medium");
113
+ expect(r.confidence).toBe("medium");
114
+ });
115
+ });
116
+ //# sourceMappingURL=synthesize.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synthesize.test.js","sourceRoot":"","sources":["../../src/retrieve/synthesize.test.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,6 @@
6
6
  * Phase 3 — incidents, correlations
7
7
  * Phase 4 — graph_snapshots (for temporal viz)
8
8
  */
9
- export declare const SCHEMA_VERSION = 1;
10
- export declare const SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS commits (\n hash TEXT PRIMARY KEY,\n short_hash TEXT NOT NULL,\n author_name TEXT NOT NULL,\n author_email TEXT NOT NULL,\n author_date TEXT NOT NULL,\n committer_date TEXT NOT NULL,\n subject TEXT NOT NULL,\n body TEXT NOT NULL,\n parents TEXT NOT NULL,\n pr_number INTEGER,\n pr_title TEXT,\n pr_body TEXT,\n issue_refs TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_commits_author_date ON commits(author_date);\nCREATE INDEX IF NOT EXISTS idx_commits_pr ON commits(pr_number);\n\nCREATE TABLE IF NOT EXISTS file_changes (\n commit_hash TEXT NOT NULL,\n path TEXT NOT NULL,\n change_kind TEXT NOT NULL,\n insertions INTEGER NOT NULL DEFAULT 0,\n deletions INTEGER NOT NULL DEFAULT 0,\n PRIMARY KEY (commit_hash, path),\n FOREIGN KEY (commit_hash) REFERENCES commits(hash) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_file_changes_path ON file_changes(path);\n\nCREATE TABLE IF NOT EXISTS chunks (\n id TEXT PRIMARY KEY,\n commit_hash TEXT NOT NULL,\n kind TEXT NOT NULL,\n text TEXT NOT NULL,\n embedding BLOB,\n embedding_model TEXT,\n FOREIGN KEY (commit_hash) REFERENCES commits(hash) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_chunks_commit ON chunks(commit_hash);\nCREATE INDEX IF NOT EXISTS idx_chunks_kind ON chunks(kind);\n\nCREATE VIRTUAL TABLE IF NOT EXISTS chunks_fts USING fts5(\n id UNINDEXED,\n commit_hash UNINDEXED,\n text,\n tokenize = 'porter unicode61'\n);\n\n-- Phase 2: entity graph\nCREATE TABLE IF NOT EXISTS entities (\n id TEXT PRIMARY KEY,\n kind TEXT NOT NULL,\n name TEXT NOT NULL,\n file_path TEXT NOT NULL,\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n signature TEXT,\n language TEXT NOT NULL,\n embedding BLOB\n);\nCREATE INDEX IF NOT EXISTS idx_entities_file ON entities(file_path);\nCREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);\n\n-- Phase 3: incidents and correlations (the moat)\nCREATE TABLE IF NOT EXISTS incidents (\n id TEXT PRIMARY KEY,\n source TEXT NOT NULL,\n external_id TEXT,\n title TEXT NOT NULL,\n occurred_at TEXT NOT NULL,\n resolved_at TEXT,\n severity TEXT NOT NULL,\n affected_files TEXT,\n stack_frames TEXT,\n url TEXT,\n metadata TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_incidents_occurred ON incidents(occurred_at);\nCREATE INDEX IF NOT EXISTS idx_incidents_source ON incidents(source);\n\nCREATE TABLE IF NOT EXISTS correlations (\n id TEXT PRIMARY KEY,\n from_kind TEXT NOT NULL,\n from_id TEXT NOT NULL,\n to_kind TEXT NOT NULL,\n to_id TEXT NOT NULL,\n weight REAL NOT NULL,\n reason TEXT NOT NULL,\n evidence TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_corr_from ON correlations(from_kind, from_id);\nCREATE INDEX IF NOT EXISTS idx_corr_to ON correlations(to_kind, to_id);\n\n-- Phase 4: temporal graph snapshots\nCREATE TABLE IF NOT EXISTS graph_snapshots (\n id TEXT PRIMARY KEY,\n taken_at TEXT NOT NULL,\n payload BLOB NOT NULL\n);\n\n-- WILD #1: AI-synthesized notes for commits with poor messages.\n-- The original commit is never modified. The synthesized note is searched\n-- alongside the original chunks but always marked as kind='synthesized'\n-- so users can verify against the underlying diff.\nCREATE TABLE IF NOT EXISTS synthesized_notes (\n commit_hash TEXT PRIMARY KEY,\n note TEXT NOT NULL,\n model TEXT NOT NULL,\n diff_chars INTEGER NOT NULL,\n created_at TEXT NOT NULL,\n FOREIGN KEY (commit_hash) REFERENCES commits(hash) ON DELETE CASCADE\n);\n";
9
+ export declare const SCHEMA_VERSION = 2;
10
+ export declare const SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS meta (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS commits (\n hash TEXT PRIMARY KEY,\n short_hash TEXT NOT NULL,\n author_name TEXT NOT NULL,\n author_email TEXT NOT NULL,\n author_date TEXT NOT NULL,\n committer_date TEXT NOT NULL,\n subject TEXT NOT NULL,\n body TEXT NOT NULL,\n parents TEXT NOT NULL,\n pr_number INTEGER,\n pr_title TEXT,\n pr_body TEXT,\n issue_refs TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_commits_author_date ON commits(author_date);\nCREATE INDEX IF NOT EXISTS idx_commits_pr ON commits(pr_number);\n\nCREATE TABLE IF NOT EXISTS file_changes (\n commit_hash TEXT NOT NULL,\n path TEXT NOT NULL,\n change_kind TEXT NOT NULL,\n insertions INTEGER NOT NULL DEFAULT 0,\n deletions INTEGER NOT NULL DEFAULT 0,\n PRIMARY KEY (commit_hash, path),\n FOREIGN KEY (commit_hash) REFERENCES commits(hash) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_file_changes_path ON file_changes(path);\n\nCREATE TABLE IF NOT EXISTS chunks (\n id TEXT PRIMARY KEY,\n commit_hash TEXT NOT NULL,\n kind TEXT NOT NULL,\n text TEXT NOT NULL,\n embedding BLOB,\n embedding_model TEXT,\n FOREIGN KEY (commit_hash) REFERENCES commits(hash) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS idx_chunks_commit ON chunks(commit_hash);\nCREATE INDEX IF NOT EXISTS idx_chunks_kind ON chunks(kind);\n\nCREATE VIRTUAL TABLE IF NOT EXISTS chunks_fts USING fts5(\n id UNINDEXED,\n commit_hash UNINDEXED,\n text,\n tokenize = 'porter unicode61'\n);\n\n-- Phase 2: entity graph\nCREATE TABLE IF NOT EXISTS entities (\n id TEXT PRIMARY KEY,\n kind TEXT NOT NULL,\n name TEXT NOT NULL,\n file_path TEXT NOT NULL,\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n signature TEXT,\n language TEXT NOT NULL,\n embedding BLOB\n);\nCREATE INDEX IF NOT EXISTS idx_entities_file ON entities(file_path);\nCREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);\n\n-- Phase 3: incidents and correlations (the moat)\nCREATE TABLE IF NOT EXISTS incidents (\n id TEXT PRIMARY KEY,\n source TEXT NOT NULL,\n external_id TEXT,\n title TEXT NOT NULL,\n occurred_at TEXT NOT NULL,\n resolved_at TEXT,\n severity TEXT NOT NULL,\n affected_files TEXT,\n stack_frames TEXT,\n url TEXT,\n metadata TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_incidents_occurred ON incidents(occurred_at);\nCREATE INDEX IF NOT EXISTS idx_incidents_source ON incidents(source);\n\nCREATE TABLE IF NOT EXISTS correlations (\n id TEXT PRIMARY KEY,\n from_kind TEXT NOT NULL,\n from_id TEXT NOT NULL,\n to_kind TEXT NOT NULL,\n to_id TEXT NOT NULL,\n weight REAL NOT NULL,\n reason TEXT NOT NULL,\n evidence TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_corr_from ON correlations(from_kind, from_id);\nCREATE INDEX IF NOT EXISTS idx_corr_to ON correlations(to_kind, to_id);\n\n-- Phase 4: temporal graph snapshots\nCREATE TABLE IF NOT EXISTS graph_snapshots (\n id TEXT PRIMARY KEY,\n taken_at TEXT NOT NULL,\n payload BLOB NOT NULL\n);\n\n-- WILD #1: AI-synthesized notes for commits with poor messages.\n-- The original commit is never modified. The synthesized note is searched\n-- alongside the original chunks but always marked as kind='synthesized'\n-- so users can verify against the underlying diff.\nCREATE TABLE IF NOT EXISTS synthesized_notes (\n commit_hash TEXT PRIMARY KEY,\n note TEXT NOT NULL,\n model TEXT NOT NULL,\n diff_chars INTEGER NOT NULL,\n created_at TEXT NOT NULL,\n FOREIGN KEY (commit_hash) REFERENCES commits(hash) ON DELETE CASCADE\n);\n\n-- Phase 4 - Wisdom Mutant Engine\n-- The \"always-learning\" loop. Three append-only tables that record what the\n-- system saw, what it tried, and how well it worked. Per-repo, never leaves\n-- the machine. Honest contract: every recommendation in mneme adapt and\n-- every threshold in mneme ask is traceable back to a row here.\n\n-- Every query records its result-set fingerprint. was_helpful is set later,\n-- either by the user (--feedback up/down) or by an implicit signal (the\n-- query was not re-run with a refined version within 60s, or one of the\n-- returned commits was navigated to via mneme why).\nCREATE TABLE IF NOT EXISTS wisdom_feedback (\n id TEXT PRIMARY KEY,\n query TEXT NOT NULL,\n result_hashes TEXT NOT NULL, -- JSON array of commit hashes returned\n top_score REAL, -- top RRF score at query time\n was_helpful INTEGER, -- 1=yes, 0=no, NULL=unknown\n source TEXT NOT NULL, -- 'explicit' | 'implicit-reuse' | 'implicit-revisit'\n semantic_weight REAL, -- the search config that produced this result\n min_sem_cosine REAL,\n rrf_k INTEGER,\n created_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS idx_feedback_created ON wisdom_feedback(created_at);\nCREATE INDEX IF NOT EXISTS idx_feedback_helpful ON wisdom_feedback(was_helpful);\n\n-- The current calibration of search/retrieval knobs. One row per knob.\n-- Updated by the auto-calibrator after evaluating against the feedback set.\nCREATE TABLE IF NOT EXISTS wisdom_calibration (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL, -- JSON\n metric_value REAL, -- the metric this calibration achieved\n metric_name TEXT, -- e.g. \"hit_rate\", \"recall_at_3\"\n calibrated_at TEXT NOT NULL,\n notes TEXT\n);\n\n-- Append-only history of self-eval runs. Lets the user (and any auditor)\n-- see whether quality is trending up or down over time.\nCREATE TABLE IF NOT EXISTS wisdom_eval_run (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n ran_at TEXT NOT NULL,\n variant TEXT NOT NULL, -- 'baseline' | 'reranked' | 'calibrated' | ...\n recall_at_3 REAL NOT NULL,\n mrr REAL NOT NULL,\n ndcg_at_10 REAL,\n hit_rate REAL NOT NULL,\n semantic_weight REAL,\n min_sem_cosine REAL,\n rrf_k INTEGER,\n num_queries INTEGER NOT NULL,\n notes TEXT\n);\nCREATE INDEX IF NOT EXISTS idx_eval_ran_at ON wisdom_eval_run(ran_at);\n";
11
11
  //# sourceMappingURL=schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/store/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,eAAO,MAAM,UAAU,i/GAsHtB,CAAC"}
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/store/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,IAAI,CAAC;AAEhC,eAAO,MAAM,UAAU,g4LA4KtB,CAAC"}
@@ -6,7 +6,7 @@
6
6
  * Phase 3 — incidents, correlations
7
7
  * Phase 4 — graph_snapshots (for temporal viz)
8
8
  */
9
- export const SCHEMA_VERSION = 1;
9
+ export const SCHEMA_VERSION = 2;
10
10
  export const SCHEMA_SQL = `
11
11
  CREATE TABLE IF NOT EXISTS meta (
12
12
  key TEXT PRIMARY KEY,
@@ -125,5 +125,59 @@ CREATE TABLE IF NOT EXISTS synthesized_notes (
125
125
  created_at TEXT NOT NULL,
126
126
  FOREIGN KEY (commit_hash) REFERENCES commits(hash) ON DELETE CASCADE
127
127
  );
128
+
129
+ -- Phase 4 - Wisdom Mutant Engine
130
+ -- The "always-learning" loop. Three append-only tables that record what the
131
+ -- system saw, what it tried, and how well it worked. Per-repo, never leaves
132
+ -- the machine. Honest contract: every recommendation in mneme adapt and
133
+ -- every threshold in mneme ask is traceable back to a row here.
134
+
135
+ -- Every query records its result-set fingerprint. was_helpful is set later,
136
+ -- either by the user (--feedback up/down) or by an implicit signal (the
137
+ -- query was not re-run with a refined version within 60s, or one of the
138
+ -- returned commits was navigated to via mneme why).
139
+ CREATE TABLE IF NOT EXISTS wisdom_feedback (
140
+ id TEXT PRIMARY KEY,
141
+ query TEXT NOT NULL,
142
+ result_hashes TEXT NOT NULL, -- JSON array of commit hashes returned
143
+ top_score REAL, -- top RRF score at query time
144
+ was_helpful INTEGER, -- 1=yes, 0=no, NULL=unknown
145
+ source TEXT NOT NULL, -- 'explicit' | 'implicit-reuse' | 'implicit-revisit'
146
+ semantic_weight REAL, -- the search config that produced this result
147
+ min_sem_cosine REAL,
148
+ rrf_k INTEGER,
149
+ created_at TEXT NOT NULL
150
+ );
151
+ CREATE INDEX IF NOT EXISTS idx_feedback_created ON wisdom_feedback(created_at);
152
+ CREATE INDEX IF NOT EXISTS idx_feedback_helpful ON wisdom_feedback(was_helpful);
153
+
154
+ -- The current calibration of search/retrieval knobs. One row per knob.
155
+ -- Updated by the auto-calibrator after evaluating against the feedback set.
156
+ CREATE TABLE IF NOT EXISTS wisdom_calibration (
157
+ key TEXT PRIMARY KEY,
158
+ value TEXT NOT NULL, -- JSON
159
+ metric_value REAL, -- the metric this calibration achieved
160
+ metric_name TEXT, -- e.g. "hit_rate", "recall_at_3"
161
+ calibrated_at TEXT NOT NULL,
162
+ notes TEXT
163
+ );
164
+
165
+ -- Append-only history of self-eval runs. Lets the user (and any auditor)
166
+ -- see whether quality is trending up or down over time.
167
+ CREATE TABLE IF NOT EXISTS wisdom_eval_run (
168
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
169
+ ran_at TEXT NOT NULL,
170
+ variant TEXT NOT NULL, -- 'baseline' | 'reranked' | 'calibrated' | ...
171
+ recall_at_3 REAL NOT NULL,
172
+ mrr REAL NOT NULL,
173
+ ndcg_at_10 REAL,
174
+ hit_rate REAL NOT NULL,
175
+ semantic_weight REAL,
176
+ min_sem_cosine REAL,
177
+ rrf_k INTEGER,
178
+ num_queries INTEGER NOT NULL,
179
+ notes TEXT
180
+ );
181
+ CREATE INDEX IF NOT EXISTS idx_eval_ran_at ON wisdom_eval_run(ran_at);
128
182
  `;
129
183
  //# sourceMappingURL=schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/store/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsHzB,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/store/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4KzB,CAAC"}
@@ -32,7 +32,7 @@ const sampleCommit = (over = {}) => ({
32
32
  });
33
33
  describe("MnemeStore — schema + roundtrip", () => {
34
34
  it("initializes with schema_version meta key", () => {
35
- expect(store.getMeta("schema_version")).toBe("1");
35
+ expect(store.getMeta("schema_version")).toBe("2");
36
36
  });
37
37
  it("upserts and retrieves a commit losslessly", () => {
38
38
  const c = sampleCommit();
@@ -4,10 +4,12 @@
4
4
  */
5
5
  import type { Commit } from "../types.js";
6
6
  import type { MnemeStore } from "../store/sqlite.js";
7
+ export * from "./redact.js";
7
8
  /** Load every commit from the store, oldest first, with its file list. */
8
9
  export declare function loadAllCommits(s: MnemeStore): Commit[];
9
10
  /** Load commits within a date range. */
10
11
  export declare function loadCommitsBetween(s: MnemeStore, sinceIso?: string, untilIso?: string): Commit[];
12
+ export declare function rowToCommit(r: Record<string, unknown>, s: MnemeStore): Commit;
11
13
  /** Stable hash of a string list — used for hash-chain ledger entries + cluster ids. */
12
14
  export declare function sha256Hex(...parts: string[]): Promise<string>;
13
15
  /** Cosine similarity for Float32Arrays. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,EAAE,CAKtD;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAChC,CAAC,EAAE,UAAU,EACb,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,EAAE,CAcV;AAsBD,uFAAuF;AACvF,wBAAsB,SAAS,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAGnE;AAED,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAclE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,cAAc,aAAa,CAAC;AAE5B,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,EAAE,CAKtD;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAChC,CAAC,EAAE,UAAU,EACb,QAAQ,CAAC,EAAE,MAAM,EACjB,QAAQ,CAAC,EAAE,MAAM,GAChB,MAAM,EAAE,CAcV;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,UAAU,GAAG,MAAM,CAkB7E;AAED,uFAAuF;AACvF,wBAAsB,SAAS,CAAC,GAAG,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAGnE;AAED,2CAA2C;AAC3C,wBAAgB,SAAS,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAclE"}
@@ -1,3 +1,4 @@
1
+ export * from "./redact.js";
1
2
  /** Load every commit from the store, oldest first, with its file list. */
2
3
  export function loadAllCommits(s) {
3
4
  const rows = s.db
@@ -21,7 +22,7 @@ export function loadCommitsBetween(s, sinceIso, untilIso) {
21
22
  const rows = s.db.prepare(sql).all(...params);
22
23
  return rows.map((r) => rowToCommit(r, s));
23
24
  }
24
- function rowToCommit(r, s) {
25
+ export function rowToCommit(r, s) {
25
26
  const hash = String(r.hash);
26
27
  return {
27
28
  hash,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/util/index.ts"],"names":[],"mappings":"AAOA,cAAc,aAAa,CAAC;AAE5B,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,CAAa;IAC1C,MAAM,IAAI,GAAG,CAAC,CAAC,EAAE;SACd,OAAO,CAAC,gDAAgD,CAAC;SACzD,GAAG,EAAoC,CAAC;IAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,wCAAwC;AACxC,MAAM,UAAU,kBAAkB,CAChC,CAAa,EACb,QAAiB,EACjB,QAAiB;IAEjB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC;IACD,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/B,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC;IACD,MAAM,GAAG,GAAG,wBAAwB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,2BAA2B,CAAC;IACnH,MAAM,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAmC,CAAC;IAChF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,CAA0B,EAAE,CAAa;IACnE,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5B,OAAO;QACL,IAAI;QACJ,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;QACjC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;QACnC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC;QACjC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC;QACvC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QAC1B,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QACvD,KAAK,EAAE,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC;QAC7B,QAAQ,EAAE,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;QACnE,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;QACpD,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;QACjD,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;KACvE,CAAC;AACJ,CAAC;AAED,uFAAuF;AACvF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAG,KAAe;IAChD,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IACnD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,SAAS,CAAC,CAAe,EAAE,CAAe;IACxD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC;IACpC,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACjB,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACjB,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC;QACf,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;QACd,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAChB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5C,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC;AACvC,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Secret redaction layer — regex scrubber for common credential formats.
3
+ *
4
+ * Used before any text leaves the machine (sent to remote embedder, written
5
+ * to logs, exported via `mneme ledger`). The redactor strips matches from
6
+ * the *text Mneme processes* — your actual git history is never modified.
7
+ *
8
+ * Why this lives in `core/util` and not in a separate package: every code
9
+ * path that touches a remote service (embedder, LLM provider, observability
10
+ * adapter) must run through it, and "import from a sibling package" is too
11
+ * easy to forget. Keeping it adjacent to types.ts makes it the obvious choice.
12
+ *
13
+ * Coverage rationale:
14
+ * - High-confidence patterns (AWS, GitHub, Stripe, OpenAI, Anthropic, Slack,
15
+ * GitLab, npm, Google API, private keys, JWT) — built-in, ON by default.
16
+ * - Lower-confidence (generic `password=` lines, hex blobs that may be hashes)
17
+ * — opt-in via { aggressive: true } because false-positive rate matters
18
+ * when redacting commit text that may legitimately contain hex commit hashes.
19
+ */
20
+ export interface RedactionRule {
21
+ /** Stable name shown in audit logs and counters. */
22
+ name: string;
23
+ /** Pattern that matches the secret. The *whole match* is replaced. */
24
+ pattern: RegExp;
25
+ /** What to put in place of the match. Default: `<REDACTED:${name}>`. */
26
+ replacement?: string;
27
+ }
28
+ export interface RedactOptions {
29
+ /** Add lower-confidence patterns (generic password=, hex blobs ≥ 40 chars). */
30
+ aggressive?: boolean;
31
+ /** Append custom rules (or override built-ins by name). */
32
+ extraRules?: RedactionRule[];
33
+ /** Disable specific built-in rules by name. */
34
+ disableRules?: string[];
35
+ }
36
+ export interface RedactionResult {
37
+ /** Text with every match replaced. */
38
+ text: string;
39
+ /** Per-rule hit count for audit reporting. Zero-count rules are omitted. */
40
+ hits: Record<string, number>;
41
+ }
42
+ /**
43
+ * Redact every match of every active rule from the input text.
44
+ * Returns the redacted text plus per-rule hit counts.
45
+ */
46
+ export declare function redact(text: string, opts?: RedactOptions): RedactionResult;
47
+ /**
48
+ * Returns true iff the text contains any match for any active rule. Useful
49
+ * when you want to short-circuit (e.g. refuse to send to remote embedder)
50
+ * rather than redact-and-send.
51
+ */
52
+ export declare function containsSecret(text: string, opts?: RedactOptions): boolean;
53
+ /**
54
+ * Aggregate hit counters across many redactions — useful for audit reporting
55
+ * after a full index run.
56
+ */
57
+ export declare function mergeHits(a: Record<string, number>, b: Record<string, number>): Record<string, number>;
58
+ //# sourceMappingURL=redact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../../src/util/redact.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,aAAa;IAC5B,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2DAA2D;IAC3D,UAAU,CAAC,EAAE,aAAa,EAAE,CAAC;IAC7B,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAuED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,eAAe,CAsB9E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,aAAkB,GAAG,OAAO,CAE9E;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAItG"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Secret redaction layer — regex scrubber for common credential formats.
3
+ *
4
+ * Used before any text leaves the machine (sent to remote embedder, written
5
+ * to logs, exported via `mneme ledger`). The redactor strips matches from
6
+ * the *text Mneme processes* — your actual git history is never modified.
7
+ *
8
+ * Why this lives in `core/util` and not in a separate package: every code
9
+ * path that touches a remote service (embedder, LLM provider, observability
10
+ * adapter) must run through it, and "import from a sibling package" is too
11
+ * easy to forget. Keeping it adjacent to types.ts makes it the obvious choice.
12
+ *
13
+ * Coverage rationale:
14
+ * - High-confidence patterns (AWS, GitHub, Stripe, OpenAI, Anthropic, Slack,
15
+ * GitLab, npm, Google API, private keys, JWT) — built-in, ON by default.
16
+ * - Lower-confidence (generic `password=` lines, hex blobs that may be hashes)
17
+ * — opt-in via { aggressive: true } because false-positive rate matters
18
+ * when redacting commit text that may legitimately contain hex commit hashes.
19
+ */
20
+ /**
21
+ * Built-in rules. Ordered roughly by specificity (most specific first) so a
22
+ * GitHub PAT is recognized as a GitHub PAT and not a generic Bearer token.
23
+ *
24
+ * Each pattern uses `g` flag — `redact()` consumes the lastIndex correctly
25
+ * by re-creating from `source` + flags on every call (regex objects are
26
+ * stateful between matches; reusing them across inputs corrupts state).
27
+ */
28
+ const BUILTIN_RULES = [
29
+ // AWS — keys are stable, well-formed, and unambiguous.
30
+ { name: "aws-access-key-id", pattern: /\b(AKIA|ASIA)[0-9A-Z]{16}\b/g },
31
+ { name: "aws-secret-access-key", pattern: /\b(?<![A-Za-z0-9+/])[A-Za-z0-9+/]{40}(?![A-Za-z0-9+/])\b/g },
32
+ // GitHub — modern format, all variants. github_pat_ is the new fine-grained one.
33
+ { name: "github-pat", pattern: /\bgh[pousr]_[A-Za-z0-9]{36,255}\b/g },
34
+ { name: "github-pat-fine-grained", pattern: /\bgithub_pat_[A-Za-z0-9_]{82,}\b/g },
35
+ // GitLab
36
+ { name: "gitlab-pat", pattern: /\bglpat-[A-Za-z0-9_-]{20,}\b/g },
37
+ // OpenAI / Anthropic / generic sk-* keys
38
+ { name: "anthropic-key", pattern: /\bsk-ant-[A-Za-z0-9_-]{32,}\b/g },
39
+ { name: "openai-key", pattern: /\bsk-[A-Za-z0-9]{20,}\b/g },
40
+ // Stripe — live and test
41
+ { name: "stripe-key", pattern: /\b(?:sk|pk|rk)_(?:live|test)_[0-9A-Za-z]{20,}\b/g },
42
+ // Slack
43
+ { name: "slack-token", pattern: /\bxox[abprs]-[0-9A-Za-z-]{10,}\b/g },
44
+ // Google API (AIza prefix)
45
+ { name: "google-api-key", pattern: /\bAIza[0-9A-Za-z_-]{35}\b/g },
46
+ // npm token (modern format)
47
+ { name: "npm-token", pattern: /\bnpm_[A-Za-z0-9]{36}\b/g },
48
+ // JWT (header.payload.signature, all base64url)
49
+ { name: "jwt", pattern: /\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g },
50
+ // PEM-armored private keys (multiline). These leak through commit messages
51
+ // and PR descriptions surprisingly often when copy/paste goes wrong.
52
+ {
53
+ name: "pem-private-key",
54
+ pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
55
+ },
56
+ // Generic bearer tokens (RFC 6750). Less specific — placed last so it does
57
+ // not eat more specific patterns above.
58
+ { name: "bearer-token", pattern: /\bBearer\s+[A-Za-z0-9._~+/-]{20,}=*\b/g },
59
+ ];
60
+ /** Lower-confidence rules — gated behind `aggressive: true`. */
61
+ const AGGRESSIVE_RULES = [
62
+ // password=... in commit text. Conservative bounds prevent eating commit messages.
63
+ // Lookbehind excludes alphanumerics (so "subpassword=..." doesn't fire) but
64
+ // *allows* `_` and `-` (so "DB_PASSWORD=..." and "API-KEY=..." both match —
65
+ // \b alone doesn't, because regex \b treats `_` as a word character).
66
+ {
67
+ name: "password-assignment",
68
+ pattern: /(?<![A-Za-z0-9])(?:password|passwd|pwd|api[_-]?key|secret|token)\s*[:=]\s*['"]?[^\s'"]{8,}['"]?/gi,
69
+ },
70
+ // Long hex blobs (likely a key or hash). Bounded to avoid eating short SHAs.
71
+ // Note: 40-char SHA1 hashes will match — false positives are expected here.
72
+ {
73
+ name: "hex-blob",
74
+ pattern: /\b[0-9a-fA-F]{64,}\b/g,
75
+ },
76
+ ];
77
+ /**
78
+ * Redact every match of every active rule from the input text.
79
+ * Returns the redacted text plus per-rule hit counts.
80
+ */
81
+ export function redact(text, opts = {}) {
82
+ if (!text)
83
+ return { text, hits: {} };
84
+ const disabled = new Set(opts.disableRules ?? []);
85
+ const rules = [];
86
+ for (const r of BUILTIN_RULES)
87
+ if (!disabled.has(r.name))
88
+ rules.push(r);
89
+ if (opts.aggressive)
90
+ for (const r of AGGRESSIVE_RULES)
91
+ if (!disabled.has(r.name))
92
+ rules.push(r);
93
+ if (opts.extraRules)
94
+ for (const r of opts.extraRules)
95
+ rules.push(r);
96
+ const hits = {};
97
+ let out = text;
98
+ for (const rule of rules) {
99
+ // Re-create regex per-call to avoid lastIndex pollution from prior runs.
100
+ const re = new RegExp(rule.pattern.source, rule.pattern.flags.includes("g") ? rule.pattern.flags : rule.pattern.flags + "g");
101
+ let count = 0;
102
+ out = out.replace(re, () => {
103
+ count += 1;
104
+ return rule.replacement ?? `<REDACTED:${rule.name}>`;
105
+ });
106
+ if (count > 0)
107
+ hits[rule.name] = count;
108
+ }
109
+ return { text: out, hits };
110
+ }
111
+ /**
112
+ * Returns true iff the text contains any match for any active rule. Useful
113
+ * when you want to short-circuit (e.g. refuse to send to remote embedder)
114
+ * rather than redact-and-send.
115
+ */
116
+ export function containsSecret(text, opts = {}) {
117
+ return Object.keys(redact(text, opts).hits).length > 0;
118
+ }
119
+ /**
120
+ * Aggregate hit counters across many redactions — useful for audit reporting
121
+ * after a full index run.
122
+ */
123
+ export function mergeHits(a, b) {
124
+ const out = { ...a };
125
+ for (const [k, v] of Object.entries(b))
126
+ out[k] = (out[k] ?? 0) + v;
127
+ return out;
128
+ }
129
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../../src/util/redact.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=redact.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.test.d.ts","sourceRoot":"","sources":["../../src/util/redact.test.ts"],"names":[],"mappings":""}