mneme-ai 0.16.0 → 0.18.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.
@@ -0,0 +1,29 @@
1
+ export interface ForensicsMatchOptions {
2
+ cwd: string;
3
+ commitHash: string;
4
+ authorEmail: string;
5
+ json?: boolean;
6
+ }
7
+ export declare function forensicsMatchCommand(opts: ForensicsMatchOptions): Promise<number>;
8
+ export interface ForensicsAttributeOptions {
9
+ cwd: string;
10
+ commitHash: string;
11
+ topN?: number;
12
+ json?: boolean;
13
+ }
14
+ export declare function forensicsAttributeCommand(opts: ForensicsAttributeOptions): Promise<number>;
15
+ export interface ForensicsVulnsOptions {
16
+ cwd: string;
17
+ since?: string;
18
+ topN?: number;
19
+ json?: boolean;
20
+ }
21
+ export declare function forensicsVulnsCommand(opts: ForensicsVulnsOptions): Promise<number>;
22
+ export interface ForensicsAnomalyOptions {
23
+ cwd: string;
24
+ threshold?: number;
25
+ topN?: number;
26
+ json?: boolean;
27
+ }
28
+ export declare function forensicsAnomalyCommand(opts: ForensicsAnomalyOptions): Promise<number>;
29
+ //# sourceMappingURL=forensics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forensics.d.ts","sourceRoot":"","sources":["../../src/commands/forensics.ts"],"names":[],"mappings":"AAwEA,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuFxF;AAID,MAAM,WAAW,yBAAyB;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,yBAAyB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAuGjB;AAID,MAAM,WAAW,qBAAqB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoJxF;AAID,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,uBAAuB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAoGjB"}
@@ -0,0 +1,472 @@
1
+ /**
2
+ * `mneme forensics` — applied forensic science for code.
3
+ *
4
+ * Subcommands:
5
+ * match <commit> <author> — STR-loci LR matching, ENFSI verbal scale
6
+ * attribute <commit> — anonymous attribution: rank candidates by LR
7
+ * vulns — pattern-match security vulnerabilities in history
8
+ * anomaly — insider-threat detection (compromised credentials)
9
+ *
10
+ * Pure data extraction lives in @mneme-ai/core/forensics. This file
11
+ * does the CLI plumbing + rendering.
12
+ */
13
+ import kleur from "kleur";
14
+ import { git, store, forensics, util, } from "@mneme-ai/core";
15
+ import { dbPath } from "../paths.js";
16
+ import { ui, header, section, severityBadge, logMeter, meter, emptyState, nextSteps, verdictBadge, kv, pill, } from "../ui.js";
17
+ // Shared withStore wrapper inline (mirrors insights-cli pattern)
18
+ async function withStore(cwd, f) {
19
+ if (!(await git.isGitRepo(cwd))) {
20
+ ui.error("Not in a git repo. Run `mneme init` first.");
21
+ return 1;
22
+ }
23
+ const meta = await git.getRepoMeta(cwd);
24
+ const s = new store.MnemeStore(dbPath(meta.rootPath));
25
+ if (s.countCommits() === 0) {
26
+ ui.error("Memory is empty. Run `mneme index` first.");
27
+ s.close();
28
+ return 1;
29
+ }
30
+ try {
31
+ return await f(s);
32
+ }
33
+ finally {
34
+ s.close();
35
+ }
36
+ }
37
+ // Map forensic severity strings to UI Level type
38
+ const sevToLevel = {
39
+ critical: "critical",
40
+ high: "high",
41
+ medium: "medium",
42
+ low: "low",
43
+ info: "info",
44
+ };
45
+ export async function forensicsMatchCommand(opts) {
46
+ const result = await withStore(opts.cwd, (s) => {
47
+ const allCommits = util.loadAllCommits(s);
48
+ const evidenceCommit = allCommits.find((c) => c.hash.startsWith(opts.commitHash)) ?? null;
49
+ if (!evidenceCommit)
50
+ return { error: `Commit ${opts.commitHash} not found in index.` };
51
+ const byAuthor = new Map();
52
+ for (const c of allCommits) {
53
+ const a = c.authorEmail.toLowerCase();
54
+ const arr = byAuthor.get(a);
55
+ if (arr)
56
+ arr.push(c);
57
+ else
58
+ byAuthor.set(a, [c]);
59
+ }
60
+ const profiles = [];
61
+ for (const [, list] of byAuthor)
62
+ profiles.push(forensics.extractLoci(list));
63
+ const population = forensics.buildPopulationStats(profiles);
64
+ const evidenceLoci = forensics.extractLoci([evidenceCommit]);
65
+ const suspectCommits = byAuthor.get(opts.authorEmail.toLowerCase());
66
+ if (!suspectCommits || suspectCommits.length < 5) {
67
+ return { error: `Author ${opts.authorEmail} has fewer than 5 commits — not enough baseline.` };
68
+ }
69
+ const suspectLoci = forensics.extractLoci(suspectCommits);
70
+ const report = forensics.compareLoci(evidenceLoci, suspectLoci, population);
71
+ return { evidenceCommit, suspect: opts.authorEmail, report, suspectCommits: suspectCommits.length };
72
+ });
73
+ if (typeof result === "number")
74
+ return result;
75
+ if ("error" in result) {
76
+ ui.error(result.error ?? "Unknown error");
77
+ return 1;
78
+ }
79
+ if (opts.json) {
80
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
81
+ return 0;
82
+ }
83
+ ui.banner();
84
+ process.stdout.write(header("🧬", "Forensic Match — STR-loci likelihood ratio", "Bayesian author attribution · ENFSI 2015 verbal scale") + "\n\n");
85
+ process.stdout.write(kv("commit", `${kleur.bold(result.evidenceCommit.shortHash)} ${kleur.gray(result.evidenceCommit.subject)}`) + "\n");
86
+ process.stdout.write(kv("suspect", `${kleur.bold(result.suspect)} ${kleur.gray(`(${result.suspectCommits} prior commits)`)}`) + "\n\n");
87
+ const lr = result.report.combinedLR;
88
+ process.stdout.write(section("✦ Combined Likelihood Ratio") + "\n");
89
+ process.stdout.write(` ${kleur.bold("LR")} = ${kleur.bold(lr.toExponential(2))} ${kleur.gray(`log10 = ${result.report.log10LR}`)}\n`);
90
+ process.stdout.write(` ${verdictBadge(result.report.verdict)}\n`);
91
+ process.stdout.write(` ${kleur.gray(verdictPlainEnglish(result.report.verdict, result.suspect))}\n\n`);
92
+ process.stdout.write(section("◆ Per-locus contribution", "(12 STR loci · meter shows log-LR)") + "\n\n");
93
+ // Sort: largest |log-LR| first — drives the eye to the most informative loci.
94
+ const sortedLoci = [...result.report.perLocus].sort((a, b) => Math.abs(Math.log10(b.lr)) - Math.abs(Math.log10(a.lr)));
95
+ for (const l of sortedLoci) {
96
+ process.stdout.write(` ${logMeter(l.lr)} ${kleur.bold(l.name.padEnd(20))} ${kleur.gray("LR=")}${formatLR(l.lr).padStart(9)}\n`);
97
+ process.stdout.write(` ${kleur.gray(l.note)}\n`);
98
+ }
99
+ process.stdout.write("\n");
100
+ // ─── Smart next steps ────────────────────────────────────────────
101
+ const isMatch = lr >= 100;
102
+ const isAgainst = lr <= 0.01;
103
+ const acts = [];
104
+ if (isAgainst) {
105
+ acts.push({
106
+ cmd: `mneme forensics attribute ${result.evidenceCommit.shortHash} --top 5`,
107
+ why: "Strong evidence against this suspect — find the most-likely actual author.",
108
+ });
109
+ }
110
+ else if (!isMatch) {
111
+ acts.push({
112
+ cmd: `mneme forensics attribute ${result.evidenceCommit.shortHash} --top 5`,
113
+ why: "LR is uninformative — let attribute rank ALL authors by likelihood.",
114
+ });
115
+ }
116
+ acts.push({
117
+ cmd: `mneme forensics anomaly --threshold 1.5`,
118
+ why: "Hunt for OTHER suspicious commits in history (insider-threat scan).",
119
+ });
120
+ process.stdout.write(nextSteps(acts) + "\n\n");
121
+ return 0;
122
+ }
123
+ export async function forensicsAttributeCommand(opts) {
124
+ const result = await withStore(opts.cwd, (s) => {
125
+ const allCommits = util.loadAllCommits(s);
126
+ const evidenceCommit = allCommits.find((c) => c.hash.startsWith(opts.commitHash)) ?? null;
127
+ if (!evidenceCommit)
128
+ return { error: `Commit ${opts.commitHash} not found in index.` };
129
+ const byAuthor = new Map();
130
+ for (const c of allCommits) {
131
+ const a = c.authorEmail.toLowerCase();
132
+ const arr = byAuthor.get(a);
133
+ if (arr)
134
+ arr.push(c);
135
+ else
136
+ byAuthor.set(a, [c]);
137
+ }
138
+ const profiles = [];
139
+ for (const [, list] of byAuthor)
140
+ profiles.push(forensics.extractLoci(list));
141
+ const population = forensics.buildPopulationStats(profiles);
142
+ const evidenceLoci = forensics.extractLoci([evidenceCommit]);
143
+ const candidates = [];
144
+ for (const [author, list] of byAuthor) {
145
+ if (list.length < 5)
146
+ continue;
147
+ const suspectLoci = forensics.extractLoci(list);
148
+ const report = forensics.compareLoci(evidenceLoci, suspectLoci, population);
149
+ candidates.push({ author, commitCount: list.length, report });
150
+ }
151
+ candidates.sort((a, b) => b.report.combinedLR - a.report.combinedLR);
152
+ return { evidenceCommit, candidates };
153
+ });
154
+ if (typeof result === "number")
155
+ return result;
156
+ if ("error" in result) {
157
+ ui.error(result.error ?? "Unknown error");
158
+ return 1;
159
+ }
160
+ if (opts.json) {
161
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
162
+ return 0;
163
+ }
164
+ ui.banner();
165
+ process.stdout.write(header("🧬", "Forensic Attribution — anonymous commit → most likely author", "Bayesian ranking across ALL authors with ≥5 prior commits") + "\n\n");
166
+ process.stdout.write(kv("commit", `${kleur.bold(result.evidenceCommit.shortHash)} ${kleur.gray(result.evidenceCommit.subject)}`) + "\n\n");
167
+ if (result.candidates.length === 0) {
168
+ process.stdout.write(emptyState("Not enough author history to attribute.", [
169
+ "Need ≥5 prior commits per author for a baseline profile.",
170
+ "Run `mneme index` if you've added commits since the last index.",
171
+ ]));
172
+ return 0;
173
+ }
174
+ // ─── Top-line insight (the "AI from the future" feel) ───────────
175
+ const top = result.candidates[0];
176
+ const second = result.candidates[1];
177
+ const ratio = second ? top.report.combinedLR / Math.max(second.report.combinedLR, 1e-9) : Infinity;
178
+ const insightStr = (() => {
179
+ if (top.report.combinedLR >= 1000 && (!second || ratio >= 100)) {
180
+ return `🎯 ${kleur.bold(top.author)} is the overwhelming match (LR ratio vs runner-up: ${ratio.toExponential(1)}).`;
181
+ }
182
+ if (top.report.combinedLR >= 100) {
183
+ return `🎯 ${kleur.bold(top.author)} is the most-likely author — strong support, but ${ratio < 10 ? "the runner-up is close" : "well above the field"}.`;
184
+ }
185
+ if (top.report.combinedLR >= 2) {
186
+ return `⚠ Weak signal — top candidate ${kleur.bold(top.author)} only modestly above population, treat as a hint not proof.`;
187
+ }
188
+ return `🌫 Inconclusive — no candidate's loci match the evidence with meaningful support.`;
189
+ })();
190
+ process.stdout.write(` ${insightStr}\n\n`);
191
+ process.stdout.write(section("◆ Ranked candidates") + "\n\n");
192
+ const showN = Math.min(opts.topN ?? 5, result.candidates.length);
193
+ for (let i = 0; i < showN; i++) {
194
+ const c = result.candidates[i];
195
+ const lr = c.report.combinedLR;
196
+ const rank = `#${i + 1}`;
197
+ process.stdout.write(` ${kleur.bold(rank.padStart(3))} ${kleur.bold(c.author.padEnd(32))} ${kleur.gray("LR=")}${formatLR(lr).padStart(10)} ${verdictBadge(c.report.verdict)}\n`);
198
+ process.stdout.write(` ${logMeter(lr)} ${kleur.gray(`${c.commitCount} prior commits · log10(LR)=${c.report.log10LR}`)}\n\n`);
199
+ }
200
+ process.stdout.write(nextSteps([
201
+ {
202
+ cmd: `mneme forensics match ${result.evidenceCommit.shortHash} ${top.author}`,
203
+ why: `See per-locus breakdown for the top candidate.`,
204
+ },
205
+ {
206
+ cmd: `mneme dna ${top.author} --depth 5`,
207
+ why: `Inspect the top candidate's coding DNA fingerprint.`,
208
+ },
209
+ ]) + "\n\n");
210
+ return 0;
211
+ }
212
+ export async function forensicsVulnsCommand(opts) {
213
+ if (!(await git.isGitRepo(opts.cwd))) {
214
+ ui.error("Not in a git repo. Run `mneme init` first.");
215
+ return 1;
216
+ }
217
+ const meta = await git.getRepoMeta(opts.cwd);
218
+ // Use git directly so we don't require an index — vulnerability
219
+ // hunting works on raw commit history.
220
+ const sinceArg = opts.since ? ["--since", opts.since] : [];
221
+ const log = await git.execGitOk(["log", "-n", String(opts.topN ?? 500), ...sinceArg, "--no-color", "--pretty=format:::commit::%H::%aI::%an::%ae::%s"], { cwd: meta.rootPath });
222
+ const inputs = [];
223
+ for (const line of log.split("\n")) {
224
+ if (!line.startsWith("::commit::"))
225
+ continue;
226
+ const parts = line.split("::");
227
+ const hash = parts[2] ?? "";
228
+ if (!hash)
229
+ continue;
230
+ const commit = {
231
+ hash,
232
+ shortHash: hash.slice(0, 7),
233
+ authorName: parts[4] ?? "",
234
+ authorEmail: parts[5] ?? "",
235
+ authorDate: parts[3] ?? "",
236
+ committerDate: parts[3] ?? "",
237
+ subject: parts.slice(6).join("::"),
238
+ body: "",
239
+ files: [],
240
+ parents: [],
241
+ };
242
+ let diff = "";
243
+ try {
244
+ diff = await git.execGitOk(["show", "--no-color", "--pretty=format:", hash], {
245
+ cwd: meta.rootPath,
246
+ });
247
+ }
248
+ catch {
249
+ // ignore — skip diff if it fails
250
+ }
251
+ inputs.push({ commit, diff });
252
+ }
253
+ const report = forensics.huntVulnerabilities(inputs);
254
+ if (opts.json) {
255
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
256
+ return 0;
257
+ }
258
+ ui.banner();
259
+ process.stdout.write(header("🛡", "Vulnerability Hunt — pattern-matched security findings", "11 CWE-aligned classes · scans full diff bodies, additions only") + "\n\n");
260
+ // ─── Scan summary ─────────────────────────────────────────────────
261
+ const totalSev = report.bySeverity.critical + report.bySeverity.high;
262
+ const summaryLine = (() => {
263
+ if (report.hits.length === 0) {
264
+ return `${kleur.green("✓")} No vulnerable patterns detected in ${kleur.bold(String(report.scanned))} commits.`;
265
+ }
266
+ if (totalSev > 0) {
267
+ return `${kleur.red("⚠")} ${kleur.red().bold(String(totalSev))} critical/high finding(s) across ${kleur.bold(String(report.scanned))} commits — investigate immediately.`;
268
+ }
269
+ return `${kleur.yellow("!")} ${kleur.bold(String(report.hits.length))} candidate(s) found across ${kleur.bold(String(report.scanned))} commits — review before action.`;
270
+ })();
271
+ process.stdout.write(` ${summaryLine}\n\n`);
272
+ if (report.hits.length === 0) {
273
+ if (report.silentFixes.length > 0) {
274
+ process.stdout.write(section("◐ Silent fixes", `(security-keyword commits with no rule hits — verify intent)`) + "\n\n");
275
+ for (const sf of report.silentFixes.slice(0, 5)) {
276
+ process.stdout.write(` ${kleur.gray("●")} ${kleur.bold(sf.shortHash)} ${kleur.gray(sf.authorDate.slice(0, 10))} ${sf.subject}\n`);
277
+ }
278
+ process.stdout.write("\n");
279
+ }
280
+ return 0;
281
+ }
282
+ // Severity tally with percentage bars
283
+ process.stdout.write(section("✦ By severity") + "\n");
284
+ const sevOrder = ["critical", "high", "medium", "low", "info"];
285
+ const maxCount = Math.max(...sevOrder.map((s) => report.bySeverity[s]));
286
+ for (const s of sevOrder) {
287
+ const n = report.bySeverity[s];
288
+ if (n === 0)
289
+ continue;
290
+ const ratio = maxCount > 0 ? n / maxCount : 0;
291
+ process.stdout.write(` ${severityBadge(s)} ${meter(ratio, { width: 12, level: s })} ${kleur.bold(String(n).padStart(4))}\n`);
292
+ }
293
+ process.stdout.write("\n");
294
+ // CWE breakdown — group hits by reference (CWE)
295
+ const byCwe = new Map();
296
+ for (const h of report.hits) {
297
+ byCwe.set(h.reference, (byCwe.get(h.reference) ?? 0) + 1);
298
+ }
299
+ if (byCwe.size > 1) {
300
+ process.stdout.write(section("◇ By CWE class", "(top 5)") + "\n");
301
+ const topCwes = [...byCwe.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5);
302
+ for (const [cwe, n] of topCwes) {
303
+ process.stdout.write(` ${kleur.cyan(cwe.padEnd(12))} ${kleur.bold(String(n).padStart(3))}\n`);
304
+ }
305
+ process.stdout.write("\n");
306
+ }
307
+ // Top hits
308
+ process.stdout.write(section("◆ Top findings") + "\n\n");
309
+ const sevWeight = {
310
+ critical: 0, high: 1, medium: 2, low: 3, info: 4,
311
+ };
312
+ const sortedHits = [...report.hits].sort((a, b) => {
313
+ const w = sevWeight[a.severity] - sevWeight[b.severity];
314
+ if (w !== 0)
315
+ return w;
316
+ return b.commit.authorDate.localeCompare(a.commit.authorDate);
317
+ });
318
+ for (const h of sortedHits.slice(0, 20)) {
319
+ const fix = h.looksLikeFix ? ` ${pill("fixed", "ok")}` : "";
320
+ process.stdout.write(` ${severityBadge(sevToLevel[h.severity] ?? "info")} ${kleur.bold(h.commit.shortHash)} ${kleur.gray(h.commit.authorDate.slice(0, 10))} ${kleur.cyan(h.reference)}${fix}\n`);
321
+ process.stdout.write(` ${h.summary}\n`);
322
+ process.stdout.write(` ${kleur.gray("evidence: " + truncateOneLine(h.evidence, 100))}\n\n`);
323
+ }
324
+ // Silent fixes (security-keyword commits without hits)
325
+ if (report.silentFixes.length > 0) {
326
+ process.stdout.write(section("◐ Silent fixes", `(${report.silentFixes.length} commit(s) mention security but no patterns matched — verify intent)`) + "\n\n");
327
+ for (const sf of report.silentFixes.slice(0, 5)) {
328
+ process.stdout.write(` ${kleur.gray("●")} ${kleur.bold(sf.shortHash)} ${kleur.gray(sf.authorDate.slice(0, 10))} ${sf.subject}\n`);
329
+ }
330
+ process.stdout.write("\n");
331
+ }
332
+ process.stdout.write(nextSteps([
333
+ {
334
+ cmd: `mneme forensics anomaly --threshold 1.5`,
335
+ why: `Cross-reference: which commits are BOTH vulnerable AND anomalous?`,
336
+ },
337
+ {
338
+ cmd: `mneme forensics vulns --json | jq '.hits[] | select(.severity=="critical")'`,
339
+ why: `Pipe critical findings to your tracker.`,
340
+ },
341
+ ]) + "\n\n");
342
+ return 0;
343
+ }
344
+ export async function forensicsAnomalyCommand(opts) {
345
+ const result = await withStore(opts.cwd, (s) => {
346
+ const allCommits = util.loadAllCommits(s);
347
+ const fileChanges = util.loadAllFileChanges(s);
348
+ const baselines = forensics.buildBaselines(allCommits, fileChanges);
349
+ const findings = forensics.detectAnomalies(allCommits, baselines, fileChanges, opts.threshold ?? 0.9);
350
+ return { findings, scanned: allCommits.length, baselines: baselines.size };
351
+ });
352
+ if (typeof result === "number")
353
+ return result;
354
+ if (opts.json) {
355
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
356
+ return 0;
357
+ }
358
+ ui.banner();
359
+ process.stdout.write(header("🕵", "Anomaly Detection — insider-threat / credential-compromise hunt", "Per-author baselines · 4-axis deviation: TIME · FILES · STYLE · SIZE") + "\n\n");
360
+ const counts = countBySeverity(result.findings);
361
+ const topLine = (() => {
362
+ if (result.findings.length === 0) {
363
+ return `${kleur.green("✓")} No anomalous commits detected at threshold ${kleur.bold((opts.threshold ?? 0.9).toFixed(2))} across ${kleur.bold(String(result.scanned))} commits.`;
364
+ }
365
+ if (counts.critical > 0) {
366
+ return `${kleur.red("⚠")} ${kleur.red().bold(String(counts.critical))} CRITICAL anomalies across ${kleur.bold(String(result.baselines))} authors — verify identities out-of-band.`;
367
+ }
368
+ return `${kleur.yellow("!")} ${kleur.bold(String(result.findings.length))} anomalous commit(s) — review before merge.`;
369
+ })();
370
+ process.stdout.write(` ${topLine}\n\n`);
371
+ if (result.findings.length === 0) {
372
+ process.stdout.write(emptyState("Clean — no commits exceeded the deviation threshold.", [
373
+ `Lower threshold to investigate borderline cases: --threshold 0.5`,
374
+ `Run after every push as part of CI for continuous oversight.`,
375
+ ]));
376
+ return 0;
377
+ }
378
+ // Severity tally
379
+ process.stdout.write(section("✦ By severity") + "\n");
380
+ const sevs = [
381
+ { key: "critical", level: "critical" },
382
+ { key: "high", level: "high" },
383
+ { key: "medium", level: "medium" },
384
+ { key: "low", level: "low" },
385
+ ];
386
+ const maxC = Math.max(counts.critical, counts.high, counts.medium, counts.low, 1);
387
+ for (const { key, level } of sevs) {
388
+ const n = counts[key];
389
+ if (n === 0)
390
+ continue;
391
+ process.stdout.write(` ${severityBadge(level)} ${meter(n / maxC, { width: 12, level })} ${kleur.bold(String(n).padStart(4))}\n`);
392
+ }
393
+ process.stdout.write("\n");
394
+ process.stdout.write(section("⚠ Anomalous commits", "(sorted by deviation)") + "\n\n");
395
+ for (const f of result.findings.slice(0, opts.topN ?? 10)) {
396
+ const c = f.commit;
397
+ const sevLevel = sevToLevel[f.severity] ?? "info";
398
+ process.stdout.write(` ${severityBadge(sevLevel)} ${kleur.bold(c.shortHash)} ${kleur.gray(c.authorDate.slice(0, 16) + " · " + c.authorName)}\n`);
399
+ process.stdout.write(` ${kleur.bold(`deviation = ${f.totalDeviation.toFixed(2)}`)} ${kleur.gray(`(≈ ${f.approxSigma}σ)`)}\n`);
400
+ process.stdout.write(` ${kleur.white(c.subject)}\n`);
401
+ for (const a of f.axes) {
402
+ if (a.score < 0.1)
403
+ continue;
404
+ // Each axis maps 0..1 onto the meter directly with auto color.
405
+ const axisLevel = a.score >= 0.8 ? "critical" : a.score >= 0.5 ? "high" : a.score >= 0.3 ? "medium" : "low";
406
+ process.stdout.write(` ${meter(a.score, { width: 10, level: axisLevel })} ${kleur.cyan(a.axis.padEnd(6))} ${kleur.gray(a.note)}\n`);
407
+ }
408
+ process.stdout.write(` ${kleur.yellow("→ " + f.recommendation)}\n\n`);
409
+ }
410
+ // Smart next steps based on top finding
411
+ const topFinding = result.findings[0];
412
+ process.stdout.write(nextSteps([
413
+ {
414
+ cmd: `mneme forensics match ${topFinding.commit.shortHash} ${topFinding.commit.authorEmail}`,
415
+ why: `Verify the top anomaly's author with STR-loci LR matching.`,
416
+ },
417
+ {
418
+ cmd: `mneme forensics vulns --since ${topFinding.commit.authorDate.slice(0, 10)}`,
419
+ why: `Cross-reference vulnerabilities introduced around the anomalous window.`,
420
+ },
421
+ ]) + "\n\n");
422
+ return 0;
423
+ }
424
+ // ─── helpers ──────────────────────────────────────────────────────────
425
+ function countBySeverity(findings) {
426
+ const c = { critical: 0, high: 0, medium: 0, low: 0 };
427
+ for (const f of findings) {
428
+ if (f.severity in c)
429
+ c[f.severity]++;
430
+ }
431
+ return c;
432
+ }
433
+ function formatLR(lr) {
434
+ if (lr >= 0.01 && lr < 1000)
435
+ return lr.toFixed(2);
436
+ return lr.toExponential(2);
437
+ }
438
+ function truncateOneLine(s, n) {
439
+ const oneLine = s.replace(/\s+/g, " ").trim();
440
+ if (oneLine.length <= n)
441
+ return oneLine;
442
+ return oneLine.slice(0, n - 1) + "…";
443
+ }
444
+ function verdictPlainEnglish(verdict, suspect) {
445
+ const v = verdict.toLowerCase();
446
+ if (v.includes("extremely strong support against")) {
447
+ return `In plain English: this is overwhelming evidence ${suspect} did NOT write this commit.`;
448
+ }
449
+ if (v.includes("very strong support against")) {
450
+ return `In plain English: very strong evidence ${suspect} is NOT the author.`;
451
+ }
452
+ if (v.includes("strong support against")) {
453
+ return `In plain English: ${suspect} is unlikely to be the author.`;
454
+ }
455
+ if (v.includes("moderate support against") || v.includes("weak support against")) {
456
+ return `In plain English: weak signal that ${suspect} is not the author — not conclusive.`;
457
+ }
458
+ if (v === "uninformative") {
459
+ return `In plain English: the evidence doesn't favor or rule out ${suspect}. Need more loci or context.`;
460
+ }
461
+ if (v.includes("extremely strong support")) {
462
+ return `In plain English: overwhelming evidence ${suspect} wrote this commit.`;
463
+ }
464
+ if (v.includes("very strong support")) {
465
+ return `In plain English: very strong evidence ${suspect} is the author.`;
466
+ }
467
+ if (v.includes("strong support")) {
468
+ return `In plain English: strong support that ${suspect} wrote this commit.`;
469
+ }
470
+ return `In plain English: the loci weakly favor ${suspect} as the author.`;
471
+ }
472
+ //# sourceMappingURL=forensics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forensics.js","sourceRoot":"","sources":["../../src/commands/forensics.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"guardian.d.ts","sourceRoot":"","sources":["../../src/commands/guardian.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAoFjB"}
1
+ {"version":3,"file":"guardian.d.ts","sourceRoot":"","sources":["../../src/commands/guardian.ts"],"names":[],"mappings":"AA2CA,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,MAAM,CAAC,CAsFjB"}
@@ -24,7 +24,7 @@ import { writeFileSync, existsSync, mkdirSync, appendFileSync, readFileSync } fr
24
24
  import { dirname } from "node:path";
25
25
  import { git, store, guardian, indexer, util, } from "@mneme-ai/core";
26
26
  import { dbPath } from "../paths.js";
27
- import { ui } from "../ui.js";
27
+ import { ui, header, kv, pill, section, severityBadge, } from "../ui.js";
28
28
  export async function guardianCommand(opts) {
29
29
  if (!(await git.isGitRepo(opts.cwd))) {
30
30
  ui.error("Not in a git repo. Run `mneme init` first.");
@@ -37,12 +37,11 @@ export async function guardianCommand(opts) {
37
37
  const maxIter = opts.maxIterations ?? (watch ? Infinity : 1);
38
38
  if (!opts.json) {
39
39
  ui.banner();
40
- process.stdout.write(`\n ${kleur.bold().cyan("🛡 Guardian — 24/7 self-healing daemon")}\n`);
41
- process.stdout.write(` ${kleur.gray("".repeat(64))}\n\n`);
42
- process.stdout.write(` ${kleur.gray("mode ")} ${watch ? kleur.green("watch") : kleur.cyan("once")}\n`);
43
- process.stdout.write(` ${kleur.gray("apply ")} ${apply ? kleur.green("yes (auto-fix enabled)") : kleur.yellow("no (observe-only)")}\n`);
40
+ process.stdout.write(header("🛡", "Guardian — 24/7 self-healing daemon", "diagnose → fix → learn loop · safe by default") + "\n\n");
41
+ process.stdout.write(kv("mode", watch ? pill("WATCH", "ok") : pill("ONCE", "low")) + "\n");
42
+ process.stdout.write(kv("apply", apply ? pill("AUTO-FIX", "ok") : pill("OBSERVE-ONLY", "warn")) + "\n");
44
43
  if (watch) {
45
- process.stdout.write(` ${kleur.gray("interval")} ${opts.intervalSeconds ?? 300}s\n`);
44
+ process.stdout.write(kv("interval", `${opts.intervalSeconds ?? 300}s`) + "\n");
46
45
  }
47
46
  process.stdout.write("\n");
48
47
  }
@@ -171,47 +170,37 @@ async function collectInput(cwd, rootPath, lastQualityScore) {
171
170
  }
172
171
  function renderTick(iteration, report) {
173
172
  const ts = report.generatedAt.replace("T", " ").slice(0, 19);
174
- process.stdout.write(` ${kleur.gray("┄┄┄ tick #" + iteration + " · " + ts)}\n`);
173
+ const tickLabel = `tick #${iteration}`;
174
+ process.stdout.write(` ${kleur.gray(`┄┄┄ ${tickLabel} · ${ts} ┄┄┄`)}\n`);
175
175
  if (report.findings.length === 0) {
176
- process.stdout.write(` ${kleur.green("✓")} ${kleur.gray("all systems healthy — no findings")}\n`);
176
+ process.stdout.write(` ${kleur.green("✓")} ${kleur.green("All systems healthy — no findings.")}\n\n`);
177
177
  return;
178
178
  }
179
179
  for (const f of report.findings) {
180
- const sev = severityColor(f.severity);
180
+ const sev = (f.severity in { critical: 0, high: 0, medium: 0, low: 0, info: 0 }
181
+ ? f.severity
182
+ : "info");
181
183
  const policy = policyLabel(f.policy);
182
- process.stdout.write(` ${sev} ${policy} ${f.message}\n`);
184
+ process.stdout.write(` ${severityBadge(sev)} ${policy} ${f.message}\n`);
183
185
  if (f.suggestedAction) {
184
186
  process.stdout.write(` ${kleur.gray("→")} ${kleur.cyan(f.suggestedAction)}\n`);
185
187
  }
186
188
  }
187
- process.stdout.write(` ${kleur.gray(`(${report.summary.findings} findings · ${report.summary.autoActions} auto · ${report.summary.recommendations} suggested)`)}\n`);
188
- }
189
- function severityColor(sev) {
190
- switch (sev) {
191
- case "critical":
192
- return kleur.red().bold("CRIT");
193
- case "high":
194
- return kleur.red("HIGH");
195
- case "medium":
196
- return kleur.yellow("MED ");
197
- case "low":
198
- return kleur.cyan("LOW ");
199
- default:
200
- return kleur.gray(sev);
201
- }
189
+ process.stdout.write(`\n ${kleur.gray(`summary: ${report.summary.findings} findings · ${report.summary.autoActions} auto · ${report.summary.recommendations} suggested`)}\n\n`);
202
190
  }
203
191
  function policyLabel(policy) {
204
192
  switch (policy) {
205
193
  case "auto":
206
- return kleur.green().bold("[AUTO] ");
194
+ return pill("AUTO", "ok");
207
195
  case "recommended":
208
- return kleur.cyan().bold("[SUGGEST]");
196
+ return pill("SUGGEST", "low");
209
197
  case "observe":
210
- return kleur.gray("[OBSERVE]");
198
+ return pill("OBSERVE", "info");
211
199
  default:
212
- return kleur.gray(`[${policy}]`);
200
+ return pill(policy, "info");
213
201
  }
214
202
  }
203
+ void section;
215
204
  function appendLog(rootPath, entry) {
216
205
  const logDir = `${rootPath}/.mneme`;
217
206
  if (!existsSync(logDir))