mneme-ai 2.48.0 → 2.49.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,50 @@
1
+ /**
2
+ * v2.49.0 — AUTO-ALIAS RESOLVER.
3
+ *
4
+ * Wild idea: the WIRING LAG class isn't just "feature shipped but CLI verb
5
+ * missing" — it's ALSO "feature shipped but user typed a NATURAL ALIAS
6
+ * that doesn't exist". v2.48 shipped `mneme dev_tooling detect`; user
7
+ * tried `mneme dev` / `mneme detect` / `mneme tool_detect` and got
8
+ * cryptic `unknown command`. That's wiring lag at the keyboard surface.
9
+ *
10
+ * This module kills the class STRUCTURALLY:
11
+ * 1. Levenshtein-based fuzzy match against all known top-level verbs
12
+ * 2. Top-3 suggestions printed when user types unknown verb
13
+ * 3. Heat-map ledger of misses → next release adds them as real aliases
14
+ * 4. Intent-router fallback for natural-language phrases
15
+ *
16
+ * Pure deterministic except for the file-write to the heat-map ledger.
17
+ * Defensive — never throws.
18
+ */
19
+ /**
20
+ * Classic Levenshtein with single-char + transposition + similar-key
21
+ * discounts. O(m·n) DP — fine for command names (typically ≤ 20 chars).
22
+ */
23
+ export declare function levenshteinDistance(a: string, b: string): number;
24
+ export interface Suggestion {
25
+ command: string;
26
+ distance: number;
27
+ /** Heuristic: does user's verb START WITH the command (or vice versa)? */
28
+ prefixMatch: boolean;
29
+ /** Distance normalized to candidate length (0=identical, 1=totally different). */
30
+ normalizedDistance: number;
31
+ }
32
+ /**
33
+ * Return top-N suggestions for `typed` from `known` commands, sorted by
34
+ * (prefixMatch desc, distance asc, normalizedDistance asc).
35
+ */
36
+ export declare function suggestCommands(typed: string, known: ReadonlyArray<string>, opts?: {
37
+ topN?: number;
38
+ maxDistance?: number;
39
+ }): Suggestion[];
40
+ /**
41
+ * Append a missed-verb to the heat-map ledger so future releases can
42
+ * pre-add as a real alias. Never throws; best-effort write only.
43
+ */
44
+ export declare function logMissedAlias(repoRoot: string, verb: string): void;
45
+ /**
46
+ * Print a friendly suggestion block to stderr. Returns the suggested
47
+ * command if there's a clear winner (distance ≤ 2), else null.
48
+ */
49
+ export declare function printSuggestions(typed: string, suggestions: Suggestion[]): string | null;
50
+ //# sourceMappingURL=alias_resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias_resolver.d.ts","sourceRoot":"","sources":["../src/alias_resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAyBhE;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,WAAW,EAAE,OAAO,CAAC;IACrB,kFAAkF;IAClF,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,EAC5B,IAAI,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACjD,UAAU,EAAE,CAoBd;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAQnE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,MAAM,GAAG,IAAI,CA0BxF"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * v2.49.0 — AUTO-ALIAS RESOLVER.
3
+ *
4
+ * Wild idea: the WIRING LAG class isn't just "feature shipped but CLI verb
5
+ * missing" — it's ALSO "feature shipped but user typed a NATURAL ALIAS
6
+ * that doesn't exist". v2.48 shipped `mneme dev_tooling detect`; user
7
+ * tried `mneme dev` / `mneme detect` / `mneme tool_detect` and got
8
+ * cryptic `unknown command`. That's wiring lag at the keyboard surface.
9
+ *
10
+ * This module kills the class STRUCTURALLY:
11
+ * 1. Levenshtein-based fuzzy match against all known top-level verbs
12
+ * 2. Top-3 suggestions printed when user types unknown verb
13
+ * 3. Heat-map ledger of misses → next release adds them as real aliases
14
+ * 4. Intent-router fallback for natural-language phrases
15
+ *
16
+ * Pure deterministic except for the file-write to the heat-map ledger.
17
+ * Defensive — never throws.
18
+ */
19
+ import { existsSync, mkdirSync, appendFileSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ /**
22
+ * Classic Levenshtein with single-char + transposition + similar-key
23
+ * discounts. O(m·n) DP — fine for command names (typically ≤ 20 chars).
24
+ */
25
+ export function levenshteinDistance(a, b) {
26
+ if (!a || !b)
27
+ return Math.max(a?.length ?? 0, b?.length ?? 0);
28
+ a = a.toLowerCase();
29
+ b = b.toLowerCase();
30
+ if (a === b)
31
+ return 0;
32
+ const m = a.length;
33
+ const n = b.length;
34
+ const d = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
35
+ for (let i = 0; i <= m; i++)
36
+ d[i][0] = i;
37
+ for (let j = 0; j <= n; j++)
38
+ d[0][j] = j;
39
+ for (let i = 1; i <= m; i++) {
40
+ for (let j = 1; j <= n; j++) {
41
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
42
+ d[i][j] = Math.min(d[i - 1][j] + 1, // deletion
43
+ d[i][j - 1] + 1, // insertion
44
+ d[i - 1][j - 1] + cost);
45
+ // Damerau transposition discount
46
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
47
+ d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);
48
+ }
49
+ }
50
+ }
51
+ return d[m][n];
52
+ }
53
+ /**
54
+ * Return top-N suggestions for `typed` from `known` commands, sorted by
55
+ * (prefixMatch desc, distance asc, normalizedDistance asc).
56
+ */
57
+ export function suggestCommands(typed, known, opts = {}) {
58
+ const topN = opts.topN ?? 5;
59
+ const maxDistance = opts.maxDistance ?? 10;
60
+ const t = (typed ?? "").toLowerCase();
61
+ if (!t)
62
+ return [];
63
+ const scored = [];
64
+ for (const cmd of known) {
65
+ const c = cmd.toLowerCase();
66
+ const dist = levenshteinDistance(t, c);
67
+ if (dist > maxDistance)
68
+ continue;
69
+ const prefixMatch = c.startsWith(t) || t.startsWith(c);
70
+ const normalizedDistance = c.length === 0 ? 1 : dist / Math.max(c.length, t.length);
71
+ scored.push({ command: cmd, distance: dist, prefixMatch, normalizedDistance });
72
+ }
73
+ scored.sort((a, b) => {
74
+ if (a.prefixMatch !== b.prefixMatch)
75
+ return a.prefixMatch ? -1 : 1;
76
+ if (a.distance !== b.distance)
77
+ return a.distance - b.distance;
78
+ return a.normalizedDistance - b.normalizedDistance;
79
+ });
80
+ return scored.slice(0, topN);
81
+ }
82
+ /**
83
+ * Append a missed-verb to the heat-map ledger so future releases can
84
+ * pre-add as a real alias. Never throws; best-effort write only.
85
+ */
86
+ export function logMissedAlias(repoRoot, verb) {
87
+ if (!repoRoot || !verb)
88
+ return;
89
+ try {
90
+ const dir = join(repoRoot, ".mneme");
91
+ if (!existsSync(dir))
92
+ mkdirSync(dir, { recursive: true });
93
+ const path = join(dir, "alias_misses.jsonl");
94
+ appendFileSync(path, JSON.stringify({ at: new Date().toISOString(), verb }) + "\n");
95
+ }
96
+ catch { /* defensive */ }
97
+ }
98
+ /**
99
+ * Print a friendly suggestion block to stderr. Returns the suggested
100
+ * command if there's a clear winner (distance ≤ 2), else null.
101
+ */
102
+ export function printSuggestions(typed, suggestions) {
103
+ if (suggestions.length === 0) {
104
+ process.stderr.write(`\n❓ Unknown command: ${JSON.stringify(typed)}\n`);
105
+ process.stderr.write(` Run \`mneme --help\` to see all available commands.\n\n`);
106
+ return null;
107
+ }
108
+ const winner = suggestions[0];
109
+ if (winner.distance <= 2 || winner.prefixMatch) {
110
+ process.stderr.write(`\n❓ Unknown command: ${JSON.stringify(typed)}\n\n`);
111
+ process.stderr.write(` Did you mean \`mneme ${winner.command}\`?\n`);
112
+ if (suggestions.length > 1) {
113
+ process.stderr.write(`\n Other closest matches:\n`);
114
+ for (const s of suggestions.slice(1, 4)) {
115
+ process.stderr.write(` • mneme ${s.command} (distance ${s.distance})\n`);
116
+ }
117
+ }
118
+ process.stderr.write(`\n Tip: set MNEME_AUTO_ALIAS=1 to auto-run the best match next time.\n\n`);
119
+ return winner.command;
120
+ }
121
+ process.stderr.write(`\n❓ Unknown command: ${JSON.stringify(typed)}\n`);
122
+ process.stderr.write(` Closest matches:\n`);
123
+ for (const s of suggestions.slice(0, 4)) {
124
+ process.stderr.write(` • mneme ${s.command} (distance ${s.distance})\n`);
125
+ }
126
+ process.stderr.write(`\n Run \`mneme --help\` for the full command list.\n\n`);
127
+ return null;
128
+ }
129
+ //# sourceMappingURL=alias_resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alias_resolver.js","sourceRoot":"","sources":["../src/alias_resolver.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAuIA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA8sJvD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAuIA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6yJvD"}
package/dist/index.js CHANGED
@@ -4526,6 +4526,73 @@ export async function run(argv) {
4526
4526
  registerArgusCommand(program);
4527
4527
  // v2.46.0 — NEMESIS (Anti-Identity-Lie Engine + EU AI Act Article 50)
4528
4528
  registerNemesisCommand(program);
4529
+ // v2.49.0 — B5 MULTI-ALIAS + F7 probe-coverage CLI + AUTO-ALIAS RESOLVER.
4530
+ // Closes wiring-lag-of-wiring-lag-fix: v2.48 shipped one verb; users
4531
+ // typed natural aliases (dev/detect/tool_detect) — all unknown. v2.49
4532
+ // wires every alias to the same handler.
4533
+ const devToolingDetect = async (path) => {
4534
+ try {
4535
+ const core = await import("@mneme-ai/core");
4536
+ const r = core.autoInit.detectDevTooling(path);
4537
+ process.stdout.write(JSON.stringify({ ok: true, path, result: r }, null, 2) + "\n");
4538
+ }
4539
+ catch (e) {
4540
+ process.stdout.write(JSON.stringify({ ok: false, error: e.message }) + "\n");
4541
+ process.exitCode = 1;
4542
+ }
4543
+ };
4544
+ // Aliases: `mneme detect`, `mneme tool_detect`, `mneme dev` (with no
4545
+ // sub) — all route to dev-tooling detect on current CWD.
4546
+ for (const alias of ["detect", "tool_detect"]) {
4547
+ program
4548
+ .command(alias)
4549
+ .description(`v2.49 alias for \`mneme dev_tooling detect\` — detect AI-dev scratch folder vs customer git repo.`)
4550
+ .option("--path <dir>", "Folder to check (default cwd).")
4551
+ .action(async (opts) => devToolingDetect(opts.path ?? process.cwd()));
4552
+ }
4553
+ // `mneme dev` parent — has `detect` subcommand AND default action.
4554
+ const devParent = program
4555
+ .command("dev")
4556
+ .description("v2.49 short alias for `mneme dev_tooling` — short-form access to DEV-TOOLING DETECTOR + RETROACTIVE CLEANSE.")
4557
+ .option("--path <dir>", "Folder to check (default cwd).")
4558
+ .action(async (opts) => devToolingDetect(opts.path ?? process.cwd()));
4559
+ devParent.command("detect")
4560
+ .description("Detect AI-dev folder.")
4561
+ .option("--path <dir>", "Folder.")
4562
+ .action(async (opts) => devToolingDetect(opts.path ?? process.cwd()));
4563
+ // v2.49.0 — F7 surface: `mneme release check` + `mneme probe coverage`.
4564
+ const releaseParent = program.command("release").description("v2.49 — release-time gates including MANDATORY probe-coverage check.");
4565
+ releaseParent.command("check")
4566
+ .description("Run the probe-coverage gate (refuses tag when new tool lacks TRUTH GATE probe binding).")
4567
+ .action(async () => {
4568
+ try {
4569
+ const core = await import("@mneme-ai/core");
4570
+ const r = core.releaseGate.crossCheckFromDisk(process.cwd());
4571
+ process.stdout.write(JSON.stringify(r, null, 2) + "\n");
4572
+ if (!r.ok)
4573
+ process.exitCode = 1;
4574
+ }
4575
+ catch (e) {
4576
+ process.stdout.write(JSON.stringify({ ok: false, error: e.message }) + "\n");
4577
+ process.exitCode = 1;
4578
+ }
4579
+ });
4580
+ const probeParent = program.command("probe").description("v2.49 — TRUTH GATE probe utilities.");
4581
+ probeParent.command("coverage")
4582
+ .description("Cross-check tool catalog vs claim catalog; report uncovered tools.")
4583
+ .action(async () => {
4584
+ try {
4585
+ const core = await import("@mneme-ai/core");
4586
+ const r = core.releaseGate.crossCheckFromDisk(process.cwd());
4587
+ process.stdout.write(JSON.stringify(r, null, 2) + "\n");
4588
+ if (!r.ok)
4589
+ process.exitCode = 1;
4590
+ }
4591
+ catch (e) {
4592
+ process.stdout.write(JSON.stringify({ ok: false, error: e.message }) + "\n");
4593
+ process.exitCode = 1;
4594
+ }
4595
+ });
4529
4596
  // v2.48.0 — Top-level `mneme dev_tooling` CLI (B5 fix: WIRING LAG class).
4530
4597
  // v2.45 shipped detectDevTooling() in core; v2.47 exposed it as MCP +
4531
4598
  // `mneme nemesis detect_tooling` subcommand — but users expect the
@@ -4753,8 +4820,45 @@ export async function run(argv) {
4753
4820
  }
4754
4821
  }
4755
4822
  }
4756
- // Restore writeErr so the genuine error surfaces.
4823
+ // v2.49.0 AUTO-ALIAS RESOLVER. Before bailing with a cryptic
4824
+ // "unknown command" error, intercept the message + run Levenshtein
4825
+ // fuzzy match against all registered top-level verbs + print
4826
+ // suggestions. Closes the wiring-lag-at-keyboard-surface class.
4757
4827
  restoreWriteErr();
4828
+ const unknownMatch = /unknown command (?:'|")([^'"]+)(?:'|")/i.exec(message);
4829
+ if (unknownMatch && unknownMatch[1]) {
4830
+ const typed = unknownMatch[1];
4831
+ try {
4832
+ const { suggestCommands, printSuggestions, logMissedAlias } = await import("./alias_resolver.js");
4833
+ // Gather all registered top-level command names.
4834
+ const known = [];
4835
+ for (const c of program.commands) {
4836
+ const name = (c.name?.() ?? c._name);
4837
+ if (name)
4838
+ known.push(name);
4839
+ }
4840
+ const suggestions = suggestCommands(typed, known, { topN: 5 });
4841
+ const winner = printSuggestions(typed, suggestions);
4842
+ try {
4843
+ logMissedAlias(process.cwd(), typed);
4844
+ }
4845
+ catch { /* */ }
4846
+ // Optional auto-run via env var
4847
+ if (winner && process.env["MNEME_AUTO_ALIAS"] === "1") {
4848
+ process.stderr.write(`\n→ MNEME_AUTO_ALIAS=1 set — auto-running \`mneme ${winner}\`...\n\n`);
4849
+ const restArgs = argv.slice(argv.findIndex((a) => a === typed) + 1);
4850
+ try {
4851
+ await program.parseAsync(["node", "mneme", winner, ...restArgs]);
4852
+ process.exit(0);
4853
+ }
4854
+ catch {
4855
+ process.exit(1);
4856
+ }
4857
+ }
4858
+ process.exit(1);
4859
+ }
4860
+ catch { /* fall through to generic error */ }
4861
+ }
4758
4862
  ui.error(message);
4759
4863
  process.exit(1);
4760
4864
  }