mnueron 0.5.0 → 0.6.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 (52) hide show
  1. package/INSTALL.md +125 -0
  2. package/LICENSE +28 -21
  3. package/NOTICE +164 -0
  4. package/README.md +443 -422
  5. package/dist/cli.js +114 -26
  6. package/dist/cli.js.map +1 -1
  7. package/dist/config.js +4 -1
  8. package/dist/config.js.map +1 -1
  9. package/dist/detectors/codex.js +138 -0
  10. package/dist/detectors/codex.js.map +1 -0
  11. package/dist/detectors/index.js +2 -0
  12. package/dist/detectors/index.js.map +1 -1
  13. package/dist/detectors/json_detector.js +1 -1
  14. package/dist/lib/context-engine/confidence.js +153 -0
  15. package/dist/lib/context-engine/confidence.js.map +1 -0
  16. package/dist/lib/context-engine/entities.js +179 -0
  17. package/dist/lib/context-engine/entities.js.map +1 -0
  18. package/dist/lib/context-engine/index.js +74 -0
  19. package/dist/lib/context-engine/index.js.map +1 -0
  20. package/dist/lib/context-engine/intent.js +139 -0
  21. package/dist/lib/context-engine/intent.js.map +1 -0
  22. package/dist/lib/context-engine/runbook-detector.js +206 -0
  23. package/dist/lib/context-engine/runbook-detector.js.map +1 -0
  24. package/dist/lib/date-anchors.js +351 -0
  25. package/dist/lib/date-anchors.js.map +1 -0
  26. package/dist/lib/temporal-intent.js +98 -0
  27. package/dist/lib/temporal-intent.js.map +1 -0
  28. package/dist/runbook/auto-extract.js +415 -0
  29. package/dist/runbook/auto-extract.js.map +1 -0
  30. package/dist/runbook/capture.js +214 -0
  31. package/dist/runbook/capture.js.map +1 -0
  32. package/dist/runbook/explain.js +154 -0
  33. package/dist/runbook/explain.js.map +1 -0
  34. package/dist/runbook/fingerprint.js +128 -0
  35. package/dist/runbook/fingerprint.js.map +1 -0
  36. package/dist/runbook/search.js +76 -0
  37. package/dist/runbook/search.js.map +1 -0
  38. package/dist/runbook/types.js +15 -0
  39. package/dist/runbook/types.js.map +1 -0
  40. package/dist/setup.js +32 -4
  41. package/dist/setup.js.map +1 -1
  42. package/dist/store/entity-extractor.js +69 -2
  43. package/dist/store/entity-extractor.js.map +1 -1
  44. package/dist/store/local-db.js +33 -0
  45. package/dist/store/local-db.js.map +1 -0
  46. package/dist/store/local.js +230 -229
  47. package/dist/store/local.js.map +1 -1
  48. package/dist/store/procedural.js +185 -0
  49. package/dist/store/procedural.js.map +1 -1
  50. package/dist/tools.js +222 -0
  51. package/dist/tools.js.map +1 -1
  52. package/package.json +63 -55
@@ -0,0 +1,415 @@
1
+ /**
2
+ * `mnueron runbook auto-extract` — read recent Cowork sessions and
3
+ * propose runbooks for any error→fix patterns mnueron already saw the
4
+ * AI solve in chat.
5
+ *
6
+ * The premise: every fix the user worked through with Claude is already
7
+ * in the local DB (via the `mnueron-cowork-daily-sync` scheduled task
8
+ * that runs every 4 hours). Asking the user to retype that into the
9
+ * `runbook capture` wizard is busywork. Instead, scan the recent
10
+ * memories, find error→fix pairs, hand them to an LLM to format as
11
+ * runbooks, and present a review UI with one-tap save.
12
+ *
13
+ * Pipeline:
14
+ * 1. Query memories where namespace LIKE 'claude-cowork%' since N hours ago
15
+ * 2. Group by source_ref (one session = one source_ref)
16
+ * 3. Walk each session chronologically — find error-shaped chunks
17
+ * 4. Auto-verify: a candidate counts as "fixed" if the next 1-2
18
+ * chunks don't share the same error fingerprint
19
+ * 5. LLM-extract each candidate into a structured runbook draft
20
+ * 6. Review UI: [s]ave / [e]dit-in-wizard / [k]ip per draft
21
+ * 7. Save approved drafts (with dedup against existing fingerprints)
22
+ *
23
+ * Cost: ~$0.001-0.005 per pass with Haiku, depending on session length.
24
+ * Dramatically cheaper than re-deriving the same fix two months later.
25
+ */
26
+ import { createInterface } from 'node:readline';
27
+ import { randomUUID } from 'node:crypto';
28
+ import { platform } from 'node:os';
29
+ import { loadConfig } from '../config.js';
30
+ import { openLocalDb } from '../store/local-db.js';
31
+ import { redact } from '../store/redactor.js';
32
+ import { fingerprintError } from './fingerprint.js';
33
+ const ANTHROPIC_MODEL = 'claude-haiku-4-5';
34
+ const OPENAI_MODEL = 'gpt-4o-mini';
35
+ const TIMEOUT_MS = 30000;
36
+ const MAX_EXTRACT_CHARS = 6000; // truncate per-candidate LLM context
37
+ export async function cmdRunbookAutoExtract(args) {
38
+ const opts = parseArgs(args);
39
+ const cfg = loadConfig();
40
+ const db = openLocalDb(cfg.dbPath);
41
+ console.log('');
42
+ console.log(`Scanning ${opts.namespace}* memories from the last ${opts.sinceHours}h...`);
43
+ // 1. Pull recent memories in scope
44
+ const sinceMs = Date.now() - opts.sinceHours * 60 * 60 * 1000;
45
+ const rows = db
46
+ .prepare(`SELECT id, namespace, content, source, source_ref, created_at, meta_json
47
+ FROM memories
48
+ WHERE namespace LIKE ?
49
+ AND created_at > ?
50
+ ORDER BY source_ref, created_at
51
+ LIMIT 1000`)
52
+ .all(`${opts.namespace}%`, sinceMs);
53
+ if (rows.length === 0) {
54
+ console.log('');
55
+ console.log(`No memories found in last ${opts.sinceHours}h.`);
56
+ console.log('');
57
+ console.log(`Verify Cowork import is working:`);
58
+ console.log(` npx tsx src/cli.ts import --claude-cowork --probe`);
59
+ return;
60
+ }
61
+ console.log(`Loaded ${rows.length} memory chunks across ${countDistinct(rows.map((r) => r.source_ref))} session(s).`);
62
+ // 2. Group by source_ref (one session = one source_ref)
63
+ const sessions = new Map();
64
+ for (const r of rows) {
65
+ const k = r.source_ref ?? `(no-ref-${r.id})`;
66
+ const list = sessions.get(k) ?? [];
67
+ list.push(r);
68
+ sessions.set(k, list);
69
+ }
70
+ // 3. Find candidate error→fix patterns
71
+ const candidates = [];
72
+ for (const session of sessions.values()) {
73
+ for (let i = 0; i < session.length; i++) {
74
+ const content = session[i].content;
75
+ if (!isErrorShaped(content))
76
+ continue;
77
+ const fp = fingerprintError(content);
78
+ // Auto-verify: next 1-2 chunks should NOT repeat the same fingerprint
79
+ const next = session.slice(i + 1, i + 3);
80
+ const stillFailing = next.some((t) => isErrorShaped(t.content) && fingerprintError(t.content).hash === fp.hash);
81
+ candidates.push({ session, errorIdx: i, fingerprint: fp, autoVerified: !stillFailing });
82
+ }
83
+ }
84
+ console.log(`Found ${candidates.length} candidate error→fix pattern(s).`);
85
+ // Dedup candidates against existing runbooks AND against each other
86
+ const existingHashes = new Set(db
87
+ .prepare(`SELECT error_fingerprints FROM procedural_memories WHERE error_fingerprints IS NOT NULL`)
88
+ .all()
89
+ .flatMap((r) => {
90
+ try {
91
+ const v = JSON.parse(r.error_fingerprints);
92
+ return Array.isArray(v) ? v : [];
93
+ }
94
+ catch {
95
+ return [];
96
+ }
97
+ }));
98
+ const seenInPass = new Set();
99
+ const novel = [];
100
+ for (const c of candidates) {
101
+ if (existingHashes.has(c.fingerprint.hash))
102
+ continue;
103
+ if (seenInPass.has(c.fingerprint.hash))
104
+ continue;
105
+ seenInPass.add(c.fingerprint.hash);
106
+ novel.push(c);
107
+ if (novel.length >= opts.limit)
108
+ break;
109
+ }
110
+ console.log(`${novel.length} new pattern(s) to extract (existing matches dedupped).`);
111
+ if (novel.length === 0) {
112
+ console.log('');
113
+ console.log('Either you already have runbooks for everything, or no errors were detected.');
114
+ return;
115
+ }
116
+ // 4. LLM-extract each candidate
117
+ console.log('');
118
+ console.log('Extracting drafts via LLM (this can take 30-60s)...');
119
+ const drafts = [];
120
+ for (let i = 0; i < novel.length; i++) {
121
+ const c = novel[i];
122
+ process.stdout.write(` [${i + 1}/${novel.length}] ${c.fingerprint.hash}... `);
123
+ try {
124
+ const draft = await extractDraft(c);
125
+ if (draft) {
126
+ drafts.push({ draft, candidate: c });
127
+ process.stdout.write(`✓ "${draft.name}"\n`);
128
+ }
129
+ else {
130
+ process.stdout.write('skipped (no fix found)\n');
131
+ }
132
+ }
133
+ catch (e) {
134
+ process.stdout.write(`error: ${e.message}\n`);
135
+ }
136
+ }
137
+ if (drafts.length === 0) {
138
+ console.log('');
139
+ console.log('LLM extraction returned no usable runbooks. Try again later when more chat history accumulates.');
140
+ return;
141
+ }
142
+ // 5. Review UI (unless --auto-save)
143
+ if (opts.dryRun) {
144
+ console.log('');
145
+ console.log(`Would save ${drafts.length} runbook(s):`);
146
+ for (const { draft } of drafts) {
147
+ console.log(` • [${draft.tool ?? 'unknown'}] ${draft.name} — ${draft.summary}`);
148
+ }
149
+ return;
150
+ }
151
+ let savedCount = 0;
152
+ let skippedCount = 0;
153
+ if (opts.autoSave) {
154
+ for (const { draft, candidate } of drafts) {
155
+ saveDraft(db, draft, candidate, opts.targetNs);
156
+ savedCount++;
157
+ }
158
+ }
159
+ else {
160
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
161
+ try {
162
+ console.log('');
163
+ console.log(`Review ${drafts.length} draft runbook(s):`);
164
+ console.log('');
165
+ for (const [i, { draft, candidate }] of drafts.entries()) {
166
+ console.log(`── Draft ${i + 1}/${drafts.length} ─────────────────────────────────`);
167
+ console.log(` name: ${draft.name}`);
168
+ console.log(` summary: ${draft.summary}`);
169
+ console.log(` tool: ${draft.tool ?? '(unknown)'}`);
170
+ console.log(` fingerprint: ${draft.fingerprintHash}`);
171
+ console.log(` verified: ${draft.fixWorked ? 'yes (auto)' : 'no'}`);
172
+ console.log(` command: ${draft.failingCommand.slice(0, 80)}`);
173
+ console.log(` steps (${draft.steps.length}):`);
174
+ for (const [si, s] of draft.steps.entries()) {
175
+ const code = s.code ? ` → ${s.code.slice(0, 60)}` : '';
176
+ console.log(` ${si + 1}. ${s.step}${code}`);
177
+ }
178
+ const choice = (await ask(rl, ' [s]ave / [k]ip / [a]ll remaining ? ')).trim().toLowerCase();
179
+ if (choice === 'a') {
180
+ for (const remaining of drafts.slice(i)) {
181
+ saveDraft(db, remaining.draft, remaining.candidate, opts.targetNs);
182
+ savedCount++;
183
+ }
184
+ break;
185
+ }
186
+ else if (choice === 'k' || choice === 'skip') {
187
+ skippedCount++;
188
+ }
189
+ else {
190
+ // Default = save
191
+ saveDraft(db, draft, candidate, opts.targetNs);
192
+ savedCount++;
193
+ }
194
+ console.log('');
195
+ }
196
+ }
197
+ finally {
198
+ rl.close();
199
+ }
200
+ }
201
+ console.log('');
202
+ console.log(`Done — saved ${savedCount}, skipped ${skippedCount} of ${drafts.length}.`);
203
+ if (savedCount > 0) {
204
+ console.log(`Try: mnueron runbook list --ns ${opts.targetNs}`);
205
+ }
206
+ }
207
+ // ── Helpers ─────────────────────────────────────────────────────────────────
208
+ function parseArgs(args) {
209
+ const out = {
210
+ sinceHours: 24,
211
+ namespace: 'claude-cowork',
212
+ limit: 10,
213
+ dryRun: false,
214
+ autoSave: false,
215
+ targetNs: 'mnueron',
216
+ };
217
+ for (let i = 0; i < args.length; i++) {
218
+ const a = args[i];
219
+ if (a === '--since' && args[i + 1])
220
+ out.sinceHours = Math.max(1, Number(args[++i]) || 24);
221
+ else if (a === '--from-ns' && args[i + 1])
222
+ out.namespace = args[++i];
223
+ else if (a === '--ns' && args[i + 1])
224
+ out.targetNs = args[++i];
225
+ else if (a === '--limit' && args[i + 1])
226
+ out.limit = Math.max(1, Number(args[++i]) || 10);
227
+ else if (a === '--dry-run')
228
+ out.dryRun = true;
229
+ else if (a === '--auto-save')
230
+ out.autoSave = true;
231
+ else if (a === '--help' || a === '-h') {
232
+ console.log(`mnueron runbook auto-extract — generate runbooks from recent Cowork chats
233
+
234
+ --since <hours> How far back to scan (default 24)
235
+ --from-ns <name> Source namespace prefix (default 'claude-cowork')
236
+ --ns <name> Where to save the runbooks (default 'mnueron')
237
+ --limit <n> Max drafts to extract per pass (default 10)
238
+ --dry-run List candidates without LLM extraction or save
239
+ --auto-save Skip review UI; save all extracted drafts
240
+ -h, --help Show this help`);
241
+ process.exit(0);
242
+ }
243
+ }
244
+ return out;
245
+ }
246
+ /** Heuristic: does this content look like an error/stderr block? */
247
+ function isErrorShaped(content) {
248
+ // Skip very short or very long chunks — likely not error pastes
249
+ if (!content || content.length < 30 || content.length > 8000)
250
+ return false;
251
+ return (/\b(error|fatal|failed?|exception|panic|sqlstate)\b[: \t]/i.test(content) ||
252
+ /^\s*[+>]\s*.*\n.*(~~|error|fail)/im.test(content) ||
253
+ /\btraceback\b|\bcannot find\b|\bis not recognized\b|\bnot a valid\b/i.test(content));
254
+ }
255
+ function countDistinct(arr) {
256
+ return new Set(arr.filter((x) => x != null)).size;
257
+ }
258
+ function ask(rl, prompt) {
259
+ return new Promise((resolve) => rl.question(prompt, (a) => resolve(a)));
260
+ }
261
+ /**
262
+ * Call an LLM (Haiku preferred, gpt-4o-mini fallback) with a focused
263
+ * extraction prompt. Returns null if the LLM judges the candidate too
264
+ * weak to formalize.
265
+ */
266
+ async function extractDraft(c) {
267
+ // Build LLM context: 1 chunk before error + error + 2 chunks after
268
+ const slice = c.session.slice(Math.max(0, c.errorIdx - 1), c.errorIdx + 3);
269
+ const transcript = slice
270
+ .map((r, i) => {
271
+ const role = r.source === 'cowork-user' || /^user\b/.test(r.source) ? 'USER' : 'ASSISTANT';
272
+ const marker = i === Math.min(c.errorIdx, 1) ? ' (← error chunk)' : '';
273
+ return `### ${role}${marker}\n${redact(r.content).content.slice(0, 1500)}`;
274
+ })
275
+ .join('\n\n');
276
+ const truncated = transcript.length > MAX_EXTRACT_CHARS
277
+ ? transcript.slice(0, MAX_EXTRACT_CHARS) + '\n... [truncated]'
278
+ : transcript;
279
+ const prompt = `You are extracting a "runbook" from a chat transcript between a user and an AI assistant. The user hit an error and the assistant proposed a fix.
280
+
281
+ Return STRICT JSON only, no prose. If the transcript doesn't actually contain an error+fix pair (or if the fix isn't concrete enough to act on), return {"skip": true}.
282
+
283
+ Schema:
284
+ {
285
+ "name": "short kebab-case name like 'fix-git-index-lock'",
286
+ "summary": "one sentence — what this runbook fixes",
287
+ "failingCommand": "the command the user ran that produced the error",
288
+ "errorText": "the key error message (≤200 chars; copy from the transcript)",
289
+ "steps": [
290
+ {"step": "imperative description", "code": "optional exact command/snippet"}
291
+ ],
292
+ "fixWorked": true | false,
293
+ "tool": "git" | "npm" | "supabase" | "postgres" | "typescript" | "powershell" | "docker" | "kubectl" | "python" | "node" | null
294
+ }
295
+
296
+ Transcript:
297
+ ${truncated}
298
+
299
+ Return JSON now:`;
300
+ const json = await callLLM(prompt);
301
+ if (!json)
302
+ return null;
303
+ let parsed;
304
+ try {
305
+ parsed = JSON.parse(json);
306
+ }
307
+ catch {
308
+ return null;
309
+ }
310
+ if (parsed.skip === true)
311
+ return null;
312
+ if (!parsed.name || !parsed.steps || !Array.isArray(parsed.steps) || parsed.steps.length === 0) {
313
+ return null;
314
+ }
315
+ const steps = parsed.steps
316
+ .filter((s) => s && typeof s.step === 'string')
317
+ .map((s) => ({
318
+ step: String(s.step).slice(0, 500),
319
+ ...(typeof s.code === 'string' ? { code: s.code.slice(0, 1000) } : {}),
320
+ }))
321
+ .slice(0, 30);
322
+ if (steps.length === 0)
323
+ return null;
324
+ return {
325
+ name: String(parsed.name).toLowerCase().replace(/[^a-z0-9-]+/g, '-').slice(0, 64),
326
+ summary: String(parsed.summary ?? '').slice(0, 300),
327
+ failingCommand: String(parsed.failingCommand ?? '').slice(0, 500),
328
+ errorText: c.fingerprint.redactedOriginal.slice(0, 4000),
329
+ steps,
330
+ // Trust LLM judgment, but if our auto-verify says yes too, bias to yes
331
+ fixWorked: Boolean(parsed.fixWorked) || c.autoVerified,
332
+ fingerprintHash: c.fingerprint.hash,
333
+ tool: parsed.tool ?? c.fingerprint.tool ?? undefined,
334
+ sourceSessionRef: c.session[c.errorIdx].source_ref,
335
+ };
336
+ }
337
+ /** Save a draft to procedural_memories, dedup by fingerprint. */
338
+ function saveDraft(db, draft, _candidate, targetNs) {
339
+ // One last dedup check inside the same pass
340
+ const existing = db
341
+ .prepare(`SELECT id FROM procedural_memories WHERE error_fingerprints LIKE ? LIMIT 1`)
342
+ .get(`%"${draft.fingerprintHash}"%`);
343
+ if (existing)
344
+ return; // someone else won the race; skip silently
345
+ const now = Date.now();
346
+ db.prepare(`INSERT INTO procedural_memories
347
+ (id, namespace, name, summary, steps_json, tools_json, last_used_at, use_count, created_at,
348
+ trigger_phrases, error_fingerprints, verified, verified_at, os, tool,
349
+ success_count, failure_count, error_text, failing_command)
350
+ VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(randomUUID(), targetNs, draft.name, draft.summary || `Fix for ${draft.tool ?? 'an unknown'} error`, JSON.stringify(draft.steps), JSON.stringify(draft.tool ? [draft.tool] : []), now, now, JSON.stringify([]), JSON.stringify([draft.fingerprintHash]), draft.fixWorked ? 1 : 0, draft.fixWorked ? now : null, platform(), draft.tool ?? null, draft.fixWorked ? 1 : 0, 0, draft.errorText, draft.failingCommand);
351
+ }
352
+ /**
353
+ * LLM call with Haiku preferred / OpenAI fallback. Mirrors the pattern
354
+ * in store/procedural.ts:extractProcedural so behavior + key handling
355
+ * stay consistent across the codebase.
356
+ */
357
+ async function callLLM(prompt) {
358
+ const anthropicKey = process.env.ANTHROPIC_API_KEY;
359
+ const openaiKey = process.env.OPENAI_API_KEY;
360
+ if (!anthropicKey && !openaiKey) {
361
+ throw new Error('auto-extract requires ANTHROPIC_API_KEY or OPENAI_API_KEY env var (no LLM key configured)');
362
+ }
363
+ const controller = new AbortController();
364
+ const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
365
+ try {
366
+ if (anthropicKey) {
367
+ const resp = await fetch('https://api.anthropic.com/v1/messages', {
368
+ method: 'POST',
369
+ headers: {
370
+ 'content-type': 'application/json',
371
+ 'x-api-key': anthropicKey,
372
+ 'anthropic-version': '2023-06-01',
373
+ },
374
+ body: JSON.stringify({
375
+ model: ANTHROPIC_MODEL,
376
+ max_tokens: 1500,
377
+ temperature: 0,
378
+ messages: [{ role: 'user', content: prompt }],
379
+ }),
380
+ signal: controller.signal,
381
+ });
382
+ if (!resp.ok)
383
+ throw new Error(`anthropic ${resp.status}`);
384
+ const data = (await resp.json());
385
+ const text = data.content?.[0]?.text ?? '';
386
+ return extractJsonBlob(text);
387
+ }
388
+ const resp = await fetch('https://api.openai.com/v1/chat/completions', {
389
+ method: 'POST',
390
+ headers: { 'content-type': 'application/json', authorization: `Bearer ${openaiKey}` },
391
+ body: JSON.stringify({
392
+ model: OPENAI_MODEL,
393
+ max_tokens: 1500,
394
+ temperature: 0,
395
+ messages: [{ role: 'user', content: prompt }],
396
+ response_format: { type: 'json_object' },
397
+ }),
398
+ signal: controller.signal,
399
+ });
400
+ if (!resp.ok)
401
+ throw new Error(`openai ${resp.status}`);
402
+ const data = (await resp.json());
403
+ const text = data.choices?.[0]?.message?.content ?? '';
404
+ return extractJsonBlob(text);
405
+ }
406
+ finally {
407
+ clearTimeout(timer);
408
+ }
409
+ }
410
+ /** Pull the first {...} JSON blob out of a possibly chatty LLM response. */
411
+ function extractJsonBlob(text) {
412
+ const match = text.match(/\{[\s\S]*\}/);
413
+ return match ? match[0] : null;
414
+ }
415
+ //# sourceMappingURL=auto-extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-extract.js","sourceRoot":"","sources":["../../src/runbook/auto-extract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,214 @@
1
+ /**
2
+ * `mnueron runbook capture` — interactive wizard for saving a runbook
3
+ * after the user has solved a problem.
4
+ *
5
+ * Five-prompt sequence:
6
+ * 1. The command that was failing
7
+ * 2. The error text (gets redacted automatically; user sees what was scrubbed)
8
+ * 3. The fix steps (multi-line, one step per line; blank line to end)
9
+ * 4. Did the fix actually work? (yes → verified; no → save as a failed-attempt note)
10
+ * 5. Save as a new runbook? (with dedup-prompt if a fingerprint matches existing)
11
+ *
12
+ * Storage:
13
+ * - Fingerprint of the (redacted) error is computed and stored on the
14
+ * runbook so future `mnueron explain-error` matches it.
15
+ * - Steps land in steps_json. Failing command + redacted error in the
16
+ * new failing_command + error_text columns.
17
+ * - `verified` is set to true only when the user confirmed fix worked.
18
+ * - Dedup: if an existing runbook already has this fingerprint, we
19
+ * default to UPDATING (append step, bump counters) rather than
20
+ * creating a duplicate row.
21
+ */
22
+ import { createInterface } from 'node:readline';
23
+ import { randomUUID } from 'node:crypto';
24
+ import { platform } from 'node:os';
25
+ import { loadConfig } from '../config.js';
26
+ import { openLocalDb } from '../store/local-db.js';
27
+ import { recordRunbookOutcome } from '../store/procedural.js';
28
+ import { fingerprintError } from './fingerprint.js';
29
+ export async function cmdRunbookCapture(args) {
30
+ const opts = parseArgs(args);
31
+ const cfg = loadConfig();
32
+ const db = openLocalDb(cfg.dbPath);
33
+ // ensureProceduralSchema is called inside openLocalDb — no need to call here
34
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
35
+ try {
36
+ console.log('');
37
+ console.log('mnueron runbook capture');
38
+ console.log('───────────────────────');
39
+ console.log('Five questions. Press Enter for blank to skip optional ones.');
40
+ console.log('');
41
+ const failingCommand = await ask(rl, '1. What command were you running?\n > ');
42
+ if (!failingCommand.trim()) {
43
+ console.error('A failing command is required.');
44
+ process.exit(1);
45
+ }
46
+ console.log('');
47
+ console.log('2. What error did you hit? (paste multi-line, blank line to end)');
48
+ const errorText = await askMultiLine(rl);
49
+ if (!errorText.trim()) {
50
+ console.error('Error text is required.');
51
+ process.exit(1);
52
+ }
53
+ const fp = fingerprintError(errorText);
54
+ console.log('');
55
+ console.log(` Fingerprint: ${fp.hash}${fp.tool ? ` (tool: ${fp.tool})` : ''}`);
56
+ if (fp.redactedCount > 0) {
57
+ console.log(` Redacted ${fp.redactedCount} secret${fp.redactedCount > 1 ? 's' : ''}: ${fp.redactedKinds.join(', ')} — they won't be stored.`);
58
+ }
59
+ // Dedup probe
60
+ const dedup = db
61
+ .prepare(`SELECT id, name, summary FROM procedural_memories
62
+ WHERE error_fingerprints LIKE ?
63
+ LIMIT 1`)
64
+ .get(`%"${fp.hash}"%`);
65
+ if (dedup) {
66
+ console.log('');
67
+ console.log(` ℹ Existing runbook matches this fingerprint: "${dedup.name}"`);
68
+ console.log(` ${dedup.summary}`);
69
+ const choice = await ask(rl, ' Update it instead of creating new? [Y/n] ');
70
+ if (choice.trim().toLowerCase() !== 'n') {
71
+ await updateExisting(rl, dedup.id, fp, failingCommand);
72
+ return;
73
+ }
74
+ }
75
+ console.log('');
76
+ console.log('3. What fix did you apply? (one step per line, blank line to end)');
77
+ const steps = await askSteps(rl);
78
+ if (steps.length === 0) {
79
+ console.error('At least one step is required.');
80
+ process.exit(1);
81
+ }
82
+ console.log('');
83
+ const fixWorked = await askYesNo(rl, '4. Did this fix actually resolve the issue?', true);
84
+ console.log('');
85
+ const defaultName = suggestName(fp, failingCommand);
86
+ const nameInput = await ask(rl, `5. Name for this runbook [${defaultName}]: `);
87
+ const name = nameInput.trim() || defaultName;
88
+ const summary = await ask(rl, ` One-line summary [${suggestSummary(fp, failingCommand)}]: `);
89
+ const namespace = opts.namespace ?? cfg.defaultNamespace ?? 'mnueron';
90
+ // Final confirmation
91
+ console.log('');
92
+ console.log('About to save:');
93
+ console.log(` namespace: ${namespace}`);
94
+ console.log(` name: ${name}`);
95
+ console.log(` summary: ${summary || suggestSummary(fp, failingCommand)}`);
96
+ console.log(` tool: ${fp.tool ?? '(unknown)'}`);
97
+ console.log(` fingerprint:${fp.hash}`);
98
+ console.log(` verified: ${fixWorked ? 'yes' : 'no — saved as attempted fix'}`);
99
+ console.log(` steps:`);
100
+ for (const [i, s] of steps.entries()) {
101
+ console.log(` ${i + 1}. ${s.step}${s.code ? ` → ${s.code.slice(0, 60)}` : ''}`);
102
+ }
103
+ const proceed = await askYesNo(rl, 'Save? [Y/n]', true);
104
+ if (!proceed) {
105
+ console.log('Cancelled.');
106
+ return;
107
+ }
108
+ const id = randomUUID();
109
+ const now = Date.now();
110
+ db.prepare(`INSERT INTO procedural_memories
111
+ (id, namespace, name, summary, steps_json, tools_json, last_used_at, use_count, created_at,
112
+ trigger_phrases, error_fingerprints, verified, verified_at, os, tool,
113
+ success_count, failure_count, error_text, failing_command)
114
+ VALUES (?, ?, ?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, namespace, name, summary || suggestSummary(fp, failingCommand), JSON.stringify(steps), JSON.stringify(fp.tool ? [fp.tool] : []), now, now, JSON.stringify([]), // trigger_phrases empty for MVP — LLM-extracted in Phase 2
115
+ JSON.stringify([fp.hash]), fixWorked ? 1 : 0, fixWorked ? now : null, platform(), fp.tool ?? null, fixWorked ? 1 : 0, fixWorked ? 0 : 1, fp.redactedOriginal, failingCommand);
116
+ console.log('');
117
+ console.log(`✓ Saved runbook ${id.slice(0, 8)} — "${name}"`);
118
+ if (fixWorked) {
119
+ console.log(' Marked verified. Future explain-error matches will surface this.');
120
+ }
121
+ else {
122
+ console.log(' Saved as attempted fix (failure_count=1). Capture again when you find the real fix.');
123
+ }
124
+ }
125
+ finally {
126
+ rl.close();
127
+ }
128
+ async function updateExisting(rl, runbookId, fp, failingCommand) {
129
+ console.log('');
130
+ console.log('3. What additional fix step did you apply? (blank line when done)');
131
+ const steps = await askSteps(rl);
132
+ console.log('');
133
+ const fixWorked = await askYesNo(rl, '4. Did this attempt resolve the issue?', true);
134
+ recordRunbookOutcome(db, runbookId, {
135
+ fingerprintHash: fp.hash,
136
+ outcome: fixWorked ? 'success' : 'failure',
137
+ verified: fixWorked ? true : undefined,
138
+ os: platform(),
139
+ tool: fp.tool,
140
+ failingCommand,
141
+ errorText: fp.redactedOriginal,
142
+ extraSteps: steps.length > 0 ? steps : undefined,
143
+ });
144
+ console.log('');
145
+ console.log(`✓ Updated runbook ${runbookId.slice(0, 8)}.`);
146
+ }
147
+ }
148
+ function parseArgs(args) {
149
+ const out = {};
150
+ for (let i = 0; i < args.length; i++) {
151
+ const a = args[i];
152
+ if (a === '--ns' || a === '--namespace')
153
+ out.namespace = args[++i];
154
+ else if (a === '--help' || a === '-h') {
155
+ console.log(`mnueron runbook capture — save a runbook after fixing an issue.
156
+
157
+ --ns <name> Target namespace (default from config, falls back to "mnueron")
158
+ -h, --help Show this help`);
159
+ process.exit(0);
160
+ }
161
+ }
162
+ return out;
163
+ }
164
+ function ask(rl, prompt) {
165
+ return new Promise((resolve) => rl.question(prompt, (a) => resolve(a)));
166
+ }
167
+ async function askMultiLine(rl) {
168
+ const lines = [];
169
+ while (true) {
170
+ const line = await ask(rl, ' ');
171
+ if (line === '')
172
+ break;
173
+ lines.push(line);
174
+ }
175
+ return lines.join('\n');
176
+ }
177
+ async function askSteps(rl) {
178
+ const steps = [];
179
+ let n = 1;
180
+ while (true) {
181
+ const line = await ask(rl, ` ${n}. `);
182
+ if (line.trim() === '')
183
+ break;
184
+ // Support "description → code" or "description: code"
185
+ const sepMatch = line.match(/^(.+?)\s*(?:→|->|:)\s*(.+)$/);
186
+ if (sepMatch) {
187
+ steps.push({ step: sepMatch[1].trim(), code: sepMatch[2].trim() });
188
+ }
189
+ else {
190
+ steps.push({ step: line.trim() });
191
+ }
192
+ n++;
193
+ }
194
+ return steps;
195
+ }
196
+ async function askYesNo(rl, prompt, defaultYes) {
197
+ const ans = await ask(rl, prompt + ' ');
198
+ if (!ans.trim())
199
+ return defaultYes;
200
+ return /^y(es)?$/i.test(ans.trim());
201
+ }
202
+ function suggestName(fp, failingCommand) {
203
+ // Heuristic: "fix-<tool>-<first-word-of-command>"
204
+ const cmd = failingCommand.trim().split(/\s+/)[0] || 'cmd';
205
+ const tool = fp.tool ?? cmd;
206
+ return `fix-${tool}-${fp.hash.slice(0, 6)}`;
207
+ }
208
+ function suggestSummary(fp, failingCommand) {
209
+ const cmd = failingCommand.trim().split(/\s+/).slice(0, 2).join(' ');
210
+ return fp.tool
211
+ ? `Fix ${fp.tool} error when running '${cmd}'`
212
+ : `Fix error when running '${cmd}'`;
213
+ }
214
+ //# sourceMappingURL=capture.js.map