mneme-ai 0.8.3

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 (107) hide show
  1. package/README.md +45 -0
  2. package/bin/mneme.js +2 -0
  3. package/dist/commands/adapt.d.ts +6 -0
  4. package/dist/commands/adapt.d.ts.map +1 -0
  5. package/dist/commands/adapt.js +219 -0
  6. package/dist/commands/adapt.js.map +1 -0
  7. package/dist/commands/ask.d.ts +8 -0
  8. package/dist/commands/ask.d.ts.map +1 -0
  9. package/dist/commands/ask.js +76 -0
  10. package/dist/commands/ask.js.map +1 -0
  11. package/dist/commands/blast.d.ts +8 -0
  12. package/dist/commands/blast.d.ts.map +1 -0
  13. package/dist/commands/blast.js +132 -0
  14. package/dist/commands/blast.js.map +1 -0
  15. package/dist/commands/clones.d.ts +19 -0
  16. package/dist/commands/clones.d.ts.map +1 -0
  17. package/dist/commands/clones.js +155 -0
  18. package/dist/commands/clones.js.map +1 -0
  19. package/dist/commands/conscience.d.ts +15 -0
  20. package/dist/commands/conscience.d.ts.map +1 -0
  21. package/dist/commands/conscience.js +202 -0
  22. package/dist/commands/conscience.js.map +1 -0
  23. package/dist/commands/correlate.d.ts +18 -0
  24. package/dist/commands/correlate.d.ts.map +1 -0
  25. package/dist/commands/correlate.js +173 -0
  26. package/dist/commands/correlate.js.map +1 -0
  27. package/dist/commands/echo.d.ts +16 -0
  28. package/dist/commands/echo.d.ts.map +1 -0
  29. package/dist/commands/echo.js +175 -0
  30. package/dist/commands/echo.js.map +1 -0
  31. package/dist/commands/genius.d.ts +13 -0
  32. package/dist/commands/genius.d.ts.map +1 -0
  33. package/dist/commands/genius.js +213 -0
  34. package/dist/commands/genius.js.map +1 -0
  35. package/dist/commands/heal.d.ts +22 -0
  36. package/dist/commands/heal.d.ts.map +1 -0
  37. package/dist/commands/heal.js +160 -0
  38. package/dist/commands/heal.js.map +1 -0
  39. package/dist/commands/index-cmd.d.ts +9 -0
  40. package/dist/commands/index-cmd.d.ts.map +1 -0
  41. package/dist/commands/index-cmd.js +74 -0
  42. package/dist/commands/index-cmd.js.map +1 -0
  43. package/dist/commands/init.d.ts +6 -0
  44. package/dist/commands/init.d.ts.map +1 -0
  45. package/dist/commands/init.js +34 -0
  46. package/dist/commands/init.js.map +1 -0
  47. package/dist/commands/mcp.d.ts +4 -0
  48. package/dist/commands/mcp.d.ts.map +1 -0
  49. package/dist/commands/mcp.js +10 -0
  50. package/dist/commands/mcp.js.map +1 -0
  51. package/dist/commands/palimpsest.d.ts +22 -0
  52. package/dist/commands/palimpsest.d.ts.map +1 -0
  53. package/dist/commands/palimpsest.js +164 -0
  54. package/dist/commands/palimpsest.js.map +1 -0
  55. package/dist/commands/status.d.ts +4 -0
  56. package/dist/commands/status.d.ts.map +1 -0
  57. package/dist/commands/status.js +49 -0
  58. package/dist/commands/status.js.map +1 -0
  59. package/dist/commands/teach.d.ts +16 -0
  60. package/dist/commands/teach.d.ts.map +1 -0
  61. package/dist/commands/teach.js +237 -0
  62. package/dist/commands/teach.js.map +1 -0
  63. package/dist/commands/teach.test.d.ts +2 -0
  64. package/dist/commands/teach.test.d.ts.map +1 -0
  65. package/dist/commands/teach.test.js +44 -0
  66. package/dist/commands/teach.test.js.map +1 -0
  67. package/dist/commands/why.d.ts +12 -0
  68. package/dist/commands/why.d.ts.map +1 -0
  69. package/dist/commands/why.js +85 -0
  70. package/dist/commands/why.js.map +1 -0
  71. package/dist/commands/wild-features.d.ts +42 -0
  72. package/dist/commands/wild-features.d.ts.map +1 -0
  73. package/dist/commands/wild-features.js +483 -0
  74. package/dist/commands/wild-features.js.map +1 -0
  75. package/dist/commands/wild-stubs.d.ts +6 -0
  76. package/dist/commands/wild-stubs.d.ts.map +1 -0
  77. package/dist/commands/wild-stubs.js +112 -0
  78. package/dist/commands/wild-stubs.js.map +1 -0
  79. package/dist/commands/wisdom.d.ts +13 -0
  80. package/dist/commands/wisdom.d.ts.map +1 -0
  81. package/dist/commands/wisdom.js +94 -0
  82. package/dist/commands/wisdom.js.map +1 -0
  83. package/dist/config.d.ts +26 -0
  84. package/dist/config.d.ts.map +1 -0
  85. package/dist/config.js +28 -0
  86. package/dist/config.js.map +1 -0
  87. package/dist/index.d.ts +2 -0
  88. package/dist/index.d.ts.map +1 -0
  89. package/dist/index.js +371 -0
  90. package/dist/index.js.map +1 -0
  91. package/dist/meditations.d.ts +24 -0
  92. package/dist/meditations.d.ts.map +1 -0
  93. package/dist/meditations.js +120 -0
  94. package/dist/meditations.js.map +1 -0
  95. package/dist/meditations.test.d.ts +2 -0
  96. package/dist/meditations.test.d.ts.map +1 -0
  97. package/dist/meditations.test.js +70 -0
  98. package/dist/meditations.test.js.map +1 -0
  99. package/dist/paths.d.ts +7 -0
  100. package/dist/paths.d.ts.map +1 -0
  101. package/dist/paths.js +14 -0
  102. package/dist/paths.js.map +1 -0
  103. package/dist/ui.d.ts +12 -0
  104. package/dist/ui.d.ts.map +1 -0
  105. package/dist/ui.js +30 -0
  106. package/dist/ui.js.map +1 -0
  107. package/package.json +46 -0
@@ -0,0 +1,175 @@
1
+ import kleur from "kleur";
2
+ import { git, store, util } from "@mneme-ai/core";
3
+ import { dbPath } from "../paths.js";
4
+ import { ui } from "../ui.js";
5
+ /**
6
+ * `mneme echo` — given an incident (id or freeform), find the most similar
7
+ * past incidents in the store. Helps on-call answer "have we seen this before?"
8
+ * before they spend an hour reinventing the postmortem.
9
+ */
10
+ export async function echoCommand(opts) {
11
+ if (!opts.id && !opts.query) {
12
+ return printUsage();
13
+ }
14
+ if (!(await git.isGitRepo(opts.cwd))) {
15
+ ui.error("Not in a git repo. Run `mneme init` first.");
16
+ return 1;
17
+ }
18
+ const meta = await git.getRepoMeta(opts.cwd);
19
+ const s = new store.MnemeStore(dbPath(meta.rootPath));
20
+ const all = loadAllIncidents(s);
21
+ if (all.length === 0) {
22
+ ui.error("No incidents indexed yet. Run `mneme correlate --source sentry --org X --project Y` first, or import from JSON.");
23
+ s.close();
24
+ return 1;
25
+ }
26
+ let target;
27
+ if (opts.id) {
28
+ const found = all.find((i) => i.id === opts.id);
29
+ if (!found) {
30
+ ui.error(`No incident with id "${opts.id}". Try \`mneme echo --query "..."\` instead.`);
31
+ s.close();
32
+ return 1;
33
+ }
34
+ target = {
35
+ title: found.title,
36
+ description: combineIncidentText(found),
37
+ sourceIncident: found,
38
+ };
39
+ }
40
+ else {
41
+ target = { title: opts.query, description: opts.query };
42
+ }
43
+ // Lexical similarity via Jaccard token overlap. Cheap, deterministic, no
44
+ // embedding dependency — good first version. Phase 2 will swap in cosine
45
+ // when incidents have embeddings.
46
+ const targetTokens = tokenize(target.description);
47
+ const scored = all
48
+ .filter((i) => !target.sourceIncident || i.id !== target.sourceIncident.id)
49
+ .map((i) => {
50
+ const tokens = tokenize(combineIncidentText(i));
51
+ return { incident: i, similarity: jaccard(targetTokens, tokens) };
52
+ })
53
+ .sort((a, b) => b.similarity - a.similarity)
54
+ .slice(0, opts.topK ?? 5);
55
+ if (opts.json) {
56
+ process.stdout.write(JSON.stringify(scored, null, 2) + "\n");
57
+ s.close();
58
+ return 0;
59
+ }
60
+ printResults(target, scored, s);
61
+ s.close();
62
+ return 0;
63
+ }
64
+ function loadAllIncidents(s) {
65
+ const rows = s.db
66
+ .prepare("SELECT * FROM incidents ORDER BY occurred_at DESC")
67
+ .all();
68
+ return rows.map((r) => ({
69
+ id: String(r.id),
70
+ source: r.source,
71
+ externalId: r.external_id ? String(r.external_id) : undefined,
72
+ title: String(r.title),
73
+ occurredAt: String(r.occurred_at),
74
+ resolvedAt: r.resolved_at ? String(r.resolved_at) : undefined,
75
+ severity: r.severity,
76
+ affectedFiles: r.affected_files ? JSON.parse(String(r.affected_files)) : undefined,
77
+ stackFrames: r.stack_frames ? JSON.parse(String(r.stack_frames)) : undefined,
78
+ url: r.url ? String(r.url) : undefined,
79
+ metadata: r.metadata ? JSON.parse(String(r.metadata)) : undefined,
80
+ }));
81
+ }
82
+ function combineIncidentText(i) {
83
+ const parts = [i.title];
84
+ if (i.affectedFiles?.length)
85
+ parts.push(...i.affectedFiles);
86
+ if (i.stackFrames?.length) {
87
+ for (const f of i.stackFrames) {
88
+ parts.push(`${f.file}:${f.line}`);
89
+ if (f.function)
90
+ parts.push(f.function);
91
+ }
92
+ }
93
+ if (i.metadata)
94
+ parts.push(JSON.stringify(i.metadata));
95
+ return parts.join(" ");
96
+ }
97
+ const STOP = new Set([
98
+ "the", "and", "for", "are", "with", "this", "that", "from", "have", "has",
99
+ "was", "were", "but", "not", "you", "your", "but", "into", "out",
100
+ ]);
101
+ function tokenize(s) {
102
+ return new Set(s
103
+ .toLowerCase()
104
+ .replace(/[^a-z0-9_/.]+/g, " ")
105
+ .split(/\s+/)
106
+ .filter((t) => t.length >= 2 && !STOP.has(t)));
107
+ }
108
+ function jaccard(a, b) {
109
+ if (a.size === 0 && b.size === 0)
110
+ return 0;
111
+ let intersection = 0;
112
+ for (const t of a)
113
+ if (b.has(t))
114
+ intersection++;
115
+ const union = a.size + b.size - intersection;
116
+ return union === 0 ? 0 : intersection / union;
117
+ }
118
+ function printResults(target, scored, s) {
119
+ ui.banner();
120
+ process.stdout.write(`${kleur.bold().cyan("echo")} ${target.title}\n\n`);
121
+ if (scored.length === 0) {
122
+ ui.warn("No similar incidents found.");
123
+ return;
124
+ }
125
+ // Look up correlations for each result so we can surface the resolution commits.
126
+ for (const { incident, similarity } of scored) {
127
+ const pct = (similarity * 100).toFixed(0) + "%";
128
+ const date = incident.occurredAt.slice(0, 10);
129
+ process.stdout.write(` ${kleur.green("●")} ${kleur.bold(incident.id)} ${kleur.gray(`[${date} · ${incident.severity}]`)} ${kleur.yellow(`${pct} similar`)}\n` +
130
+ ` ${kleur.white(incident.title)}\n`);
131
+ // Resolution commits if we have them.
132
+ const corr = s.db
133
+ .prepare(`SELECT from_id, weight, reason FROM correlations
134
+ WHERE to_kind = 'incident' AND to_id = ?
135
+ ORDER BY weight DESC LIMIT 3`)
136
+ .all(incident.id);
137
+ if (corr.length > 0) {
138
+ process.stdout.write(` ${kleur.cyan("→ resolved/triggered by:")}\n`);
139
+ for (const c of corr) {
140
+ const c2 = s.getCommit(c.from_id);
141
+ if (c2) {
142
+ process.stdout.write(` ${kleur.gray("·")} ${c2.shortHash} ${kleur.gray("·")} ${c2.subject.slice(0, 60)}\n`);
143
+ }
144
+ }
145
+ }
146
+ if (incident.url)
147
+ process.stdout.write(` ${kleur.gray(incident.url)}\n`);
148
+ process.stdout.write("\n");
149
+ }
150
+ // util import is reserved for cosine fallback when incidents get embeddings;
151
+ // suppress unused-import lint.
152
+ void util;
153
+ }
154
+ function printUsage() {
155
+ ui.banner();
156
+ process.stdout.write(`${kleur.bold().magenta("echo")} ${kleur.gray("(WILD #2)")}\n\n`);
157
+ process.stdout.write([
158
+ `Find past incidents that resemble a current one.`,
159
+ ``,
160
+ kleur.bold(`Usage:`),
161
+ ` mneme echo --id <stored-incident-id>`,
162
+ ` mneme echo --query "Stripe webhook 500 on bigint amount"`,
163
+ ``,
164
+ kleur.bold(`Options:`),
165
+ ` --id <id> stored incident id (e.g. "sentry:12345")`,
166
+ ` --query <text> freeform incident description`,
167
+ ` --top <n> top-N most similar (default 5)`,
168
+ ` --json machine-readable output`,
169
+ ``,
170
+ kleur.gray(`Echo first runs Jaccard similarity on tokenized titles, files, and stack frames.`),
171
+ kleur.gray(`When incidents have embeddings (Phase 3.5), it switches to cosine for semantic match.`),
172
+ ].join("\n") + "\n");
173
+ return 0;
174
+ }
175
+ //# sourceMappingURL=echo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"echo.js","sourceRoot":"","sources":["../../src/commands/echo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface GeniusCommandOptions {
2
+ cwd: string;
3
+ question: string;
4
+ /** Hard cap on tool steps. */
5
+ maxSteps?: number;
6
+ provider?: "auto" | "ollama" | "openai";
7
+ model?: string;
8
+ /** Print every plan step + raw output (verbose mode). */
9
+ trace?: boolean;
10
+ json?: boolean;
11
+ }
12
+ export declare function geniusCommand(opts: GeniusCommandOptions): Promise<number>;
13
+ //# sourceMappingURL=genius.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genius.d.ts","sourceRoot":"","sources":["../../src/commands/genius.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAwCD,wBAAsB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4E/E"}
@@ -0,0 +1,213 @@
1
+ /**
2
+ * `mneme genius <question>` — LLM-orchestrated multi-step agent.
3
+ *
4
+ * Mneme already exposes ~22 single-purpose CLI commands. `genius` is the
5
+ * piece that lets a question span several of them. The LLM doesn't write
6
+ * code — it picks tools and arranges them. Mneme runs the tools. The LLM
7
+ * then synthesizes a final answer from the tool outputs.
8
+ *
9
+ * Why a separate command instead of relying on Claude+MCP? Two reasons:
10
+ *
11
+ * 1. Fewer round-trips. The LLM that drives `genius` is local (Ollama by
12
+ * default), so a multi-step plan doesn't pay an MCP-per-call latency
13
+ * hit and doesn't blow a remote LLM's context window.
14
+ * 2. Self-contained. A user who has not configured Claude/Cursor can still
15
+ * ask a hard question and get a multi-step answer.
16
+ *
17
+ * The agent loop is intentionally simple:
18
+ *
19
+ * plan: send the catalog of available tools + the question →
20
+ * LLM returns JSON: [{tool, args, why}, ...]
21
+ * execute: run each step, capture stdout
22
+ * synthesize: send the question + tool outputs → LLM writes the answer
23
+ *
24
+ * No infinite loops. No tool-creates-new-tool. No magic.
25
+ */
26
+ import { spawnSync } from "node:child_process";
27
+ import { fileURLToPath } from "node:url";
28
+ import { dirname, resolve } from "node:path";
29
+ import kleur from "kleur";
30
+ import { resolveEnricher } from "@mneme-ai/embeddings";
31
+ import { ui } from "../ui.js";
32
+ const PLAN_SYSTEM_PROMPT = `You are an engineering assistant that plans which Mneme CLI commands to run to answer a question.
33
+ Output ONLY valid JSON of shape: { "steps": [{ "tool": "<command>", "args": ["..."], "why": "<one-line>" }] }.
34
+ Do NOT wrap in markdown. Do NOT add commentary. JSON only.`;
35
+ const SYNTH_SYSTEM_PROMPT = `You synthesize a concise answer from the outputs of Mneme CLI commands.
36
+ Cite specific commit hashes, PR numbers, or incident ids that appear in the tool output.
37
+ If the outputs are empty or contradictory, say so plainly.
38
+ 4-8 sentences of plain prose. No markdown headings. No bullet lists.`;
39
+ const TOOL_CATALOG = [
40
+ { tool: "ask", args: "<question text>", purpose: "natural-language search over commits + PRs" },
41
+ { tool: "why", args: "<file>:<lineStart>-<lineEnd>", purpose: "blame + originating commits for a code range" },
42
+ { tool: "search-commits", args: "<query>", purpose: "hybrid commit search (subset of ask)" },
43
+ { tool: "status", args: "", purpose: "what's indexed, embedder, db stats" },
44
+ { tool: "adapt", args: "", purpose: "repo profile + recommended next commands" },
45
+ { tool: "runaway", args: "--top 5", purpose: "files that grew silently — refactor candidates" },
46
+ { tool: "mirror", args: "", purpose: "onboarding dossier (top PRs, top contributors, top incidents)" },
47
+ { tool: "fossil", args: "--top 5", purpose: "files deleted from HEAD but still in history" },
48
+ { tool: "rumor", args: "", purpose: "tribal phrases mentioned in commits but no doc explains" },
49
+ { tool: "clones", args: "--top 3", purpose: "near-duplicate functions worth refactoring" },
50
+ { tool: "blast", args: "<commit-ref>", purpose: "predict incidents likely to follow shipping a commit" },
51
+ { tool: "palimpsest", args: "<file>:<line>", purpose: "causal chain (commit → incident → cause)" },
52
+ { tool: "conscience", args: "<file1> <file2> ...", purpose: "risk-score a PR against the repo's own history" },
53
+ { tool: "echo", args: "--query <incident text>", purpose: "find past incidents that resemble a current one" },
54
+ { tool: "ledger", args: "--since <iso>", purpose: "tamper-evident audit log of commits in range" },
55
+ ];
56
+ export async function geniusCommand(opts) {
57
+ ui.banner();
58
+ process.stdout.write(`${kleur.bold().cyan("genius")} ${kleur.gray("(AI agent — plans, runs, synthesizes)")}\n\n`);
59
+ process.stdout.write(`${kleur.bold("Q")} ${opts.question}\n\n`);
60
+ // 1. Resolve the LLM (same enricher used by `heal` / `teach`).
61
+ let enricher;
62
+ try {
63
+ enricher = await resolveEnricher({
64
+ provider: opts.provider ?? "auto",
65
+ model: opts.model,
66
+ });
67
+ }
68
+ catch (err) {
69
+ ui.error(`No LLM available: ${err.message}`);
70
+ ui.dim("Install Ollama: https://ollama.com → ollama pull llama3.2:3b");
71
+ return 1;
72
+ }
73
+ ui.step("llm", enricher.name);
74
+ // 2. PLAN
75
+ const plan = await plan_(enricher, opts.question, opts.maxSteps ?? 4);
76
+ if (!plan.length) {
77
+ ui.warn("LLM produced no plan. Falling back to a single `mneme ask` call.");
78
+ plan.push({ tool: "ask", args: [opts.question], why: "fallback: direct ask" });
79
+ }
80
+ ui.step("plan", `${plan.length} step(s)`);
81
+ for (let i = 0; i < plan.length; i++) {
82
+ const s = plan[i];
83
+ process.stdout.write(` ${kleur.gray(`${i + 1}.`)} ${kleur.cyan("mneme")} ${kleur.bold(s.tool)} ${kleur.gray(s.args.join(" "))}\n` +
84
+ ` ${kleur.gray("→ " + s.why)}\n`);
85
+ }
86
+ process.stdout.write("\n");
87
+ // 3. EXECUTE
88
+ const results = [];
89
+ for (let i = 0; i < plan.length; i++) {
90
+ const s = plan[i];
91
+ ui.step(`run ${i + 1}/${plan.length}`, `mneme ${s.tool} ${s.args.join(" ")}`);
92
+ const r = runMneme(s.tool, s.args, opts.cwd);
93
+ results.push({ ...s, stdout: r.stdout, exitCode: r.code });
94
+ if (opts.trace) {
95
+ process.stdout.write(kleur.gray(" --- output (truncated) ---\n"));
96
+ for (const line of r.stdout.split("\n").slice(0, 20)) {
97
+ process.stdout.write(kleur.gray(` ${line}\n`));
98
+ }
99
+ }
100
+ }
101
+ // 4. SYNTHESIZE
102
+ ui.step("synthesize", "asking the LLM to weave the outputs together");
103
+ const synthesis = await synthesize_(enricher, opts.question, results);
104
+ if (opts.json) {
105
+ process.stdout.write(JSON.stringify({ question: opts.question, plan: results, answer: synthesis }, null, 2) + "\n");
106
+ return 0;
107
+ }
108
+ process.stdout.write("\n" + kleur.bold().magenta("Answer") + "\n");
109
+ for (const line of wrap(synthesis, 78).split("\n")) {
110
+ process.stdout.write(` ${line}\n`);
111
+ }
112
+ process.stdout.write("\n" +
113
+ kleur.gray(" Each step above ran a real Mneme command — not a hallucination. Pass --trace to see raw outputs.") +
114
+ "\n");
115
+ return 0;
116
+ }
117
+ async function plan_(enricher, question, maxSteps) {
118
+ const catalog = TOOL_CATALOG.map((t) => `- ${t.tool}: ${t.purpose} (args: ${t.args || "(none)"})`).join("\n");
119
+ const user = `Question: ${question}
120
+
121
+ Available Mneme tools:
122
+ ${catalog}
123
+
124
+ Output JSON with at most ${maxSteps} steps. Choose the smallest plan that answers the question.
125
+ Each step's "args" must be an array of strings. If a tool needs no args, use [].`;
126
+ const out = await enricher.enrich({
127
+ system: PLAN_SYSTEM_PROMPT,
128
+ user,
129
+ temperature: 0.1,
130
+ maxTokens: 600,
131
+ });
132
+ return parsePlan(out.text, maxSteps);
133
+ }
134
+ function parsePlan(raw, maxSteps) {
135
+ // The model sometimes wraps JSON in code fences. Strip them.
136
+ const stripped = raw.replace(/^```json\s*|^```\s*|```\s*$/g, "").trim();
137
+ let parsed;
138
+ try {
139
+ parsed = JSON.parse(stripped);
140
+ }
141
+ catch {
142
+ return [];
143
+ }
144
+ if (!parsed ||
145
+ typeof parsed !== "object" ||
146
+ !Array.isArray(parsed.steps)) {
147
+ return [];
148
+ }
149
+ const steps = parsed.steps.slice(0, maxSteps);
150
+ const allowed = new Set(TOOL_CATALOG.map((t) => t.tool));
151
+ const out = [];
152
+ for (const s of steps) {
153
+ if (!s || typeof s !== "object")
154
+ continue;
155
+ const tool = String(s.tool ?? "");
156
+ if (!allowed.has(tool))
157
+ continue;
158
+ const argsRaw = s.args;
159
+ const args = Array.isArray(argsRaw) ? argsRaw.map((a) => String(a)) : [];
160
+ const why = String(s.why ?? "");
161
+ out.push({ tool, args, why });
162
+ }
163
+ return out;
164
+ }
165
+ function runMneme(tool, args, cwd) {
166
+ const here = dirname(fileURLToPath(import.meta.url));
167
+ const binAbs = resolve(here, "..", "..", "bin", "mneme.js");
168
+ const r = spawnSync(process.execPath, [binAbs, tool, ...args], {
169
+ cwd,
170
+ encoding: "utf8",
171
+ maxBuffer: 4 * 1024 * 1024,
172
+ windowsHide: true,
173
+ env: { ...process.env, NO_COLOR: "1" },
174
+ });
175
+ return { stdout: (r.stdout ?? "") + (r.stderr ?? ""), code: r.status ?? 1 };
176
+ }
177
+ async function synthesize_(enricher, question, results) {
178
+ const sections = results
179
+ .map((r, i) => {
180
+ const head = `[step ${i + 1}: mneme ${r.tool} ${r.args.join(" ")}] (exit ${r.exitCode})`;
181
+ const body = r.stdout.length > 1500 ? r.stdout.slice(0, 1500) + "\n…(truncated)" : r.stdout;
182
+ return `${head}\n${body}`;
183
+ })
184
+ .join("\n\n---\n\n");
185
+ const user = `Question: ${question}\n\nTool outputs:\n${sections}\n\nWrite the answer.`;
186
+ const out = await enricher.enrich({
187
+ system: SYNTH_SYSTEM_PROMPT,
188
+ user,
189
+ temperature: 0.2,
190
+ maxTokens: 400,
191
+ });
192
+ return out.text;
193
+ }
194
+ function wrap(s, width) {
195
+ const parts = [];
196
+ for (const para of s.split(/\n\n+/)) {
197
+ let line = "";
198
+ for (const word of para.split(/\s+/)) {
199
+ if ((line + " " + word).trim().length > width && line) {
200
+ parts.push(line);
201
+ line = word;
202
+ }
203
+ else {
204
+ line += (line ? " " : "") + word;
205
+ }
206
+ }
207
+ if (line.trim())
208
+ parts.push(line);
209
+ parts.push("");
210
+ }
211
+ return parts.join("\n").trim();
212
+ }
213
+ //# sourceMappingURL=genius.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"genius.js","sourceRoot":"","sources":["../../src/commands/genius.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface HealCommandOptions {
2
+ cwd: string;
3
+ max?: number;
4
+ /** Subject length below which a commit is considered for healing. */
5
+ subjectMinLen?: number;
6
+ /** Skip writing — just preview which commits would be healed. */
7
+ dryRun?: boolean;
8
+ provider?: "auto" | "ollama" | "openai";
9
+ model?: string;
10
+ /** Re-heal commits that already have a synthesized note. */
11
+ force?: boolean;
12
+ }
13
+ /**
14
+ * `mneme heal` — for each commit whose message gives no real signal,
15
+ * read the diff and ask an LLM to synthesize a 2-4 sentence WHY note.
16
+ *
17
+ * The original commit is never modified. The synthesized note lives in
18
+ * `synthesized_notes` and is searched as kind='synthesized' so users can
19
+ * always tell synthesized text from original text.
20
+ */
21
+ export declare function healCommand(opts: HealCommandOptions): Promise<number>;
22
+ //# sourceMappingURL=heal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heal.d.ts","sourceRoot":"","sources":["../../src/commands/heal.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuH3E"}
@@ -0,0 +1,160 @@
1
+ import kleur from "kleur";
2
+ import { git, store, enrich } from "@mneme-ai/core";
3
+ import { resolveEnricher } from "@mneme-ai/embeddings";
4
+ import { dbPath } from "../paths.js";
5
+ import { ui, formatProgress } from "../ui.js";
6
+ /**
7
+ * `mneme heal` — for each commit whose message gives no real signal,
8
+ * read the diff and ask an LLM to synthesize a 2-4 sentence WHY note.
9
+ *
10
+ * The original commit is never modified. The synthesized note lives in
11
+ * `synthesized_notes` and is searched as kind='synthesized' so users can
12
+ * always tell synthesized text from original text.
13
+ */
14
+ export async function healCommand(opts) {
15
+ ui.banner();
16
+ if (!(await git.isGitRepo(opts.cwd))) {
17
+ ui.error("Not in a git repo. Run `mneme init` first.");
18
+ return 1;
19
+ }
20
+ const meta = await git.getRepoMeta(opts.cwd);
21
+ const s = new store.MnemeStore(dbPath(meta.rootPath));
22
+ if (s.countCommits() === 0) {
23
+ ui.error("Memory is empty. Run `mneme index` first.");
24
+ s.close();
25
+ return 1;
26
+ }
27
+ // 1. Find candidate commits (poor message, missing body).
28
+ const all = loadAllCommits(s);
29
+ const subjectMinLen = opts.subjectMinLen ?? 20;
30
+ let candidates = all.filter((c) => enrich.needsHealing(c, subjectMinLen));
31
+ // Skip already-healed unless --force.
32
+ if (!opts.force) {
33
+ candidates = candidates.filter((c) => !s.getSynthesizedNote(c.hash));
34
+ }
35
+ // Cap.
36
+ const max = opts.max ?? 100;
37
+ if (candidates.length > max)
38
+ candidates = candidates.slice(0, max);
39
+ ui.step("candidates", `${candidates.length} commits with poor messages ${kleur.gray(`(of ${all.length} total)`)}`);
40
+ if (candidates.length === 0) {
41
+ ui.success("Nothing to heal — every commit already has either a real message or a synthesized note.");
42
+ s.close();
43
+ return 0;
44
+ }
45
+ if (opts.dryRun) {
46
+ process.stdout.write("\n" + kleur.bold().magenta("Would heal:") + "\n");
47
+ for (const c of candidates.slice(0, 10)) {
48
+ process.stdout.write(` ${kleur.green("●")} ${c.shortHash} ${kleur.gray(c.authorDate.slice(0, 10))} ${kleur.white(c.subject || "(empty)")}\n`);
49
+ }
50
+ if (candidates.length > 10) {
51
+ process.stdout.write(kleur.gray(` …and ${candidates.length - 10} more\n`));
52
+ }
53
+ process.stdout.write(kleur.gray("\nRun without --dry-run to synthesize notes.\n"));
54
+ s.close();
55
+ return 0;
56
+ }
57
+ // 2. Resolve enricher (Ollama by default, free + local).
58
+ ui.step("enricher", "resolving …");
59
+ let enricher;
60
+ try {
61
+ enricher = await resolveEnricher({
62
+ provider: opts.provider ?? "auto",
63
+ model: opts.model,
64
+ });
65
+ }
66
+ catch (err) {
67
+ ui.error(err.message);
68
+ ui.dim("Install Ollama (recommended): https://ollama.com");
69
+ ui.dim("Then pull a small chat model: ollama pull llama3.2:1b");
70
+ s.close();
71
+ return 1;
72
+ }
73
+ ui.dim(` using ${enricher.name}`);
74
+ // 3. For each candidate, fetch diff + neighbors + synthesize.
75
+ let synthesized = 0;
76
+ let skippedUncertain = 0;
77
+ let lastTick = 0;
78
+ for (let i = 0; i < candidates.length; i++) {
79
+ const c = candidates[i];
80
+ const now = Date.now();
81
+ if (now - lastTick > 80 || i === candidates.length - 1) {
82
+ lastTick = now;
83
+ const bar = formatProgress(i + 1, candidates.length);
84
+ ui.raw(`\r${kleur.gray("›")} healing ${bar} ${kleur.gray(c.shortHash)} `);
85
+ }
86
+ const diff = await fetchDiff(meta.rootPath, c.hash);
87
+ if (diff.length < 20)
88
+ continue; // empty/binary-only commit
89
+ const neighborSubjects = neighborsOf(all, c, 3);
90
+ const prompt = enrich.buildSynthesisPrompt({ commit: c, diff, neighborSubjects });
91
+ try {
92
+ const result = await enricher.enrich({
93
+ system: enrich.SYNTHESIZE_SYSTEM_PROMPT,
94
+ user: prompt,
95
+ temperature: 0.2,
96
+ maxTokens: 220,
97
+ });
98
+ if (enrich.isUncertain(result.text)) {
99
+ skippedUncertain++;
100
+ continue;
101
+ }
102
+ s.upsertSynthesizedNote(c.hash, result.text, result.source, diff.length);
103
+ synthesized++;
104
+ }
105
+ catch (err) {
106
+ // Network/model error — keep going, don't crash whole batch.
107
+ ui.raw("\n");
108
+ ui.warn(`heal failed for ${c.shortHash}: ${err.message}`);
109
+ }
110
+ }
111
+ ui.raw("\n");
112
+ // 4. Report.
113
+ ui.success(`Synthesized ${synthesized} notes ${kleur.gray(`· ${skippedUncertain} skipped as uncertain · ${candidates.length - synthesized - skippedUncertain} errored`)}`);
114
+ ui.dim(`Total notes in store: ${s.countSynthesizedNotes()}`);
115
+ ui.dim(`Notes are searched as kind='synthesized' alongside original chunks. Originals never modified.`);
116
+ s.close();
117
+ return 0;
118
+ }
119
+ function loadAllCommits(s) {
120
+ const rows = s.db
121
+ .prepare("SELECT * FROM commits ORDER BY author_date ASC")
122
+ .all();
123
+ return rows.map((r) => ({
124
+ hash: String(r.hash),
125
+ shortHash: String(r.short_hash),
126
+ authorName: String(r.author_name),
127
+ authorEmail: String(r.author_email),
128
+ authorDate: String(r.author_date),
129
+ committerDate: String(r.committer_date),
130
+ subject: String(r.subject),
131
+ body: String(r.body),
132
+ parents: String(r.parents).split(/\s+/).filter(Boolean),
133
+ files: s.filesForCommit(String(r.hash)),
134
+ prNumber: typeof r.pr_number === "number" ? r.pr_number : undefined,
135
+ prTitle: r.pr_title ? String(r.pr_title) : undefined,
136
+ prBody: r.pr_body ? String(r.pr_body) : undefined,
137
+ issueRefs: r.issue_refs ? JSON.parse(String(r.issue_refs)) : undefined,
138
+ }));
139
+ }
140
+ async function fetchDiff(cwd, commitHash) {
141
+ const r = await git.execGit(["show", "--format=", "--no-color", commitHash], { cwd });
142
+ if (r.code !== 0)
143
+ return "";
144
+ return r.stdout;
145
+ }
146
+ /** Pick subjects of N commits before + after the target by date. */
147
+ function neighborsOf(all, target, n) {
148
+ const idx = all.findIndex((c) => c.hash === target.hash);
149
+ if (idx < 0)
150
+ return [];
151
+ const out = [];
152
+ for (let i = Math.max(0, idx - n); i < Math.min(all.length, idx + n + 1); i++) {
153
+ if (i === idx)
154
+ continue;
155
+ if (all[i].subject)
156
+ out.push(all[i].subject);
157
+ }
158
+ return out;
159
+ }
160
+ //# sourceMappingURL=heal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heal.js","sourceRoot":"","sources":["../../src/commands/heal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export interface IndexCommandOptions {
2
+ cwd: string;
3
+ since?: string;
4
+ maxCount?: number;
5
+ embedder?: "auto" | "ollama" | "openai" | "hash";
6
+ model?: string;
7
+ }
8
+ export declare function indexCommand(opts: IndexCommandOptions): Promise<number>;
9
+ //# sourceMappingURL=index-cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-cmd.d.ts","sourceRoot":"","sources":["../../src/commands/index-cmd.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CA0E7E"}