mneme-ai 2.75.2 → 2.77.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,63 @@
1
+ /**
2
+ * v2.77.0 — INTERACTIVE TUI core (pure, dependency-free, fully testable).
3
+ *
4
+ * The driver (commands/ui.ts) owns raw-mode stdin + the alt-screen; everything
5
+ * here is pure: load the capability catalog, fuzzy-filter/rank it, fold a
6
+ * keypress into new state, and render state → lines. Pure functions = the TUI
7
+ * logic is unit-tested without a terminal.
8
+ *
9
+ * Design goal: the user types plain language ("how do I check if a claim is
10
+ * true") and the right capability surfaces — zero command memorization. New
11
+ * tools appear automatically because the list is the live MNEME_COMMAND_CATALOG.
12
+ */
13
+ export interface CapItem {
14
+ command: string;
15
+ alias?: string;
16
+ since: string;
17
+ what: string;
18
+ when: string;
19
+ group: string;
20
+ }
21
+ export interface UiState {
22
+ query: string;
23
+ all: CapItem[];
24
+ filtered: CapItem[];
25
+ selected: number;
26
+ scrollTop: number;
27
+ listRows: number;
28
+ mode: "browse" | "output";
29
+ output?: string;
30
+ outputTitle?: string;
31
+ }
32
+ export type UiAction = {
33
+ type: "none";
34
+ } | {
35
+ type: "quit";
36
+ } | {
37
+ type: "run";
38
+ item: CapItem;
39
+ };
40
+ export interface KeyEvent {
41
+ name?: string;
42
+ ctrl?: boolean;
43
+ sequence?: string;
44
+ }
45
+ /** Normalize a raw manifest entry into a CapItem (defensive). */
46
+ export declare function toCapItem(raw: unknown): CapItem | null;
47
+ export declare function loadCatalog(rawList: unknown[]): CapItem[];
48
+ /** Filter + rank. Empty query → all (stable). Multi-term = AND (every term
49
+ * must match somewhere); score = sum of per-term best scores. */
50
+ export declare function filterItems(all: CapItem[], query: string): CapItem[];
51
+ export declare function initState(all: CapItem[], listRows: number): UiState;
52
+ /** Fold a keypress into new state + an action for the driver to perform.
53
+ * Pure: same (state, key) → same (state, action). */
54
+ export declare function reduce(state: UiState, key: KeyEvent): {
55
+ state: UiState;
56
+ action: UiAction;
57
+ };
58
+ /** Does this catalog command take arguments (placeholders) or is it MCP-only?
59
+ * Such commands can't be run blind from the TUI — we show the template. */
60
+ export declare function isParameterless(item: CapItem): boolean;
61
+ /** The shell argv (after "mneme") for a parameterless command. */
62
+ export declare function shellArgsFor(item: CapItem): string[];
63
+ //# sourceMappingURL=tui_core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui_core.d.ts","sourceRoot":"","sources":["../../src/ui/tui_core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,OAAO,EAAE,CAAC;IACf,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEnC,MAAM,WAAW,QAAQ;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAID,iEAAiE;AACjE,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAYtD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,CAMzD;AAqBD;kEACkE;AAClE,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,EAAE,CAYpE;AAID,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnE;AAqBD;sDACsD;AACtD,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAA;CAAE,CA2B1F;AAID;4EAC4E;AAC5E,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAKtD;AAED,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,EAAE,CAEpD"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * v2.77.0 — INTERACTIVE TUI core (pure, dependency-free, fully testable).
3
+ *
4
+ * The driver (commands/ui.ts) owns raw-mode stdin + the alt-screen; everything
5
+ * here is pure: load the capability catalog, fuzzy-filter/rank it, fold a
6
+ * keypress into new state, and render state → lines. Pure functions = the TUI
7
+ * logic is unit-tested without a terminal.
8
+ *
9
+ * Design goal: the user types plain language ("how do I check if a claim is
10
+ * true") and the right capability surfaces — zero command memorization. New
11
+ * tools appear automatically because the list is the live MNEME_COMMAND_CATALOG.
12
+ */
13
+ /* ── catalog ─────────────────────────────────────────────────────────── */
14
+ /** Normalize a raw manifest entry into a CapItem (defensive). */
15
+ export function toCapItem(raw) {
16
+ if (!raw || typeof raw !== "object")
17
+ return null;
18
+ const r = raw;
19
+ if (typeof r.command !== "string" || r.command.length === 0)
20
+ return null;
21
+ return {
22
+ command: r.command,
23
+ alias: typeof r.alias === "string" ? r.alias : undefined,
24
+ since: typeof r.since === "string" ? r.since : "?",
25
+ what: typeof r.what === "string" ? r.what : "",
26
+ when: typeof r.when === "string" ? r.when : "",
27
+ group: typeof r.group === "string" ? r.group : "core",
28
+ };
29
+ }
30
+ export function loadCatalog(rawList) {
31
+ const out = [];
32
+ for (const r of rawList ?? []) {
33
+ const c = toCapItem(r);
34
+ if (c)
35
+ out.push(c);
36
+ }
37
+ // De-dup by command; stable.
38
+ const seen = new Set();
39
+ return out.filter((c) => (seen.has(c.command) ? false : (seen.add(c.command), true)));
40
+ }
41
+ /* ── fuzzy filter + ranking ──────────────────────────────────────────── */
42
+ /** Score one item against one lowercased term. Higher = better; 0 = no match.
43
+ * Weights: command-name >> alias > group > what > when. */
44
+ function scoreTerm(item, term) {
45
+ const cmd = item.command.toLowerCase();
46
+ const alias = (item.alias ?? "").toLowerCase();
47
+ const what = item.what.toLowerCase();
48
+ const when = item.when.toLowerCase();
49
+ const group = item.group.toLowerCase();
50
+ let s = 0;
51
+ if (cmd.includes(term))
52
+ s = Math.max(s, cmd.startsWith(term) || cmd.includes(" " + term) ? 100 : 70);
53
+ if (alias && alias.includes(term))
54
+ s = Math.max(s, 60);
55
+ if (group.includes(term))
56
+ s = Math.max(s, 40);
57
+ if (what.includes(term))
58
+ s = Math.max(s, 25);
59
+ if (when.includes(term))
60
+ s = Math.max(s, 12);
61
+ return s;
62
+ }
63
+ /** Filter + rank. Empty query → all (stable). Multi-term = AND (every term
64
+ * must match somewhere); score = sum of per-term best scores. */
65
+ export function filterItems(all, query) {
66
+ const q = query.trim().toLowerCase();
67
+ if (q.length === 0)
68
+ return all.slice();
69
+ const terms = q.split(/\s+/).filter(Boolean);
70
+ const scored = [];
71
+ for (const item of all) {
72
+ let total = 0;
73
+ let ok = true;
74
+ for (const t of terms) {
75
+ const s = scoreTerm(item, t);
76
+ if (s === 0) {
77
+ ok = false;
78
+ break;
79
+ }
80
+ total += s;
81
+ }
82
+ if (ok)
83
+ scored.push({ item, score: total });
84
+ }
85
+ scored.sort((a, b) => (b.score - a.score) || a.item.command.localeCompare(b.item.command));
86
+ return scored.map((s) => s.item);
87
+ }
88
+ /* ── state ───────────────────────────────────────────────────────────── */
89
+ export function initState(all, listRows) {
90
+ return { query: "", all, filtered: all.slice(), selected: 0, scrollTop: 0, listRows: Math.max(1, listRows), mode: "browse" };
91
+ }
92
+ function clampScroll(s) {
93
+ // Keep selected within the visible window.
94
+ let scrollTop = s.scrollTop;
95
+ if (s.selected < scrollTop)
96
+ scrollTop = s.selected;
97
+ else if (s.selected >= scrollTop + s.listRows)
98
+ scrollTop = s.selected - s.listRows + 1;
99
+ scrollTop = Math.max(0, Math.min(scrollTop, Math.max(0, s.filtered.length - s.listRows)));
100
+ return { ...s, scrollTop };
101
+ }
102
+ function refilter(s) {
103
+ const filtered = filterItems(s.all, s.query);
104
+ return clampScroll({ ...s, filtered, selected: filtered.length === 0 ? 0 : Math.min(s.selected, filtered.length - 1) });
105
+ }
106
+ /** True for a single printable character we should append to the query. */
107
+ function isPrintable(k) {
108
+ return !k.ctrl && typeof k.sequence === "string" && k.sequence.length === 1 && k.sequence >= " " && k.sequence !== "\x7f";
109
+ }
110
+ /** Fold a keypress into new state + an action for the driver to perform.
111
+ * Pure: same (state, key) → same (state, action). */
112
+ export function reduce(state, key) {
113
+ // Output pane: any key returns to browse.
114
+ if (state.mode === "output") {
115
+ return { state: { ...state, mode: "browse", output: undefined, outputTitle: undefined }, action: { type: "none" } };
116
+ }
117
+ const name = key.name ?? "";
118
+ if (key.ctrl && (name === "c"))
119
+ return { state, action: { type: "quit" } };
120
+ switch (name) {
121
+ case "escape":
122
+ // Esc clears the query first; a second Esc (empty query) quits.
123
+ if (state.query.length > 0)
124
+ return { state: refilter({ ...state, query: "" }), action: { type: "none" } };
125
+ return { state, action: { type: "quit" } };
126
+ case "return": {
127
+ const item = state.filtered[state.selected];
128
+ return item ? { state, action: { type: "run", item } } : { state, action: { type: "none" } };
129
+ }
130
+ case "up": return { state: clampScroll({ ...state, selected: Math.max(0, state.selected - 1) }), action: { type: "none" } };
131
+ case "down": return { state: clampScroll({ ...state, selected: Math.min(Math.max(0, state.filtered.length - 1), state.selected + 1) }), action: { type: "none" } };
132
+ case "pageup": return { state: clampScroll({ ...state, selected: Math.max(0, state.selected - state.listRows) }), action: { type: "none" } };
133
+ case "pagedown": return { state: clampScroll({ ...state, selected: Math.min(Math.max(0, state.filtered.length - 1), state.selected + state.listRows) }), action: { type: "none" } };
134
+ case "home": return { state: clampScroll({ ...state, selected: 0 }), action: { type: "none" } };
135
+ case "end": return { state: clampScroll({ ...state, selected: Math.max(0, state.filtered.length - 1) }), action: { type: "none" } };
136
+ case "backspace": return { state: state.query.length > 0 ? refilter({ ...state, query: state.query.slice(0, -1) }) : state, action: { type: "none" } };
137
+ default:
138
+ if (isPrintable(key))
139
+ return { state: refilter({ ...state, query: state.query + key.sequence }), action: { type: "none" } };
140
+ return { state, action: { type: "none" } };
141
+ }
142
+ }
143
+ /* ── run classification ──────────────────────────────────────────────── */
144
+ /** Does this catalog command take arguments (placeholders) or is it MCP-only?
145
+ * Such commands can't be run blind from the TUI — we show the template. */
146
+ export function isParameterless(item) {
147
+ const c = item.command;
148
+ if (/[.]/.test(c.split(" ")[0] ?? ""))
149
+ return false; // mneme.x.y MCP tool, not a shell verb
150
+ if (/[<\[]/.test(c))
151
+ return false; // has <arg> / [opt]
152
+ return /^mneme\s+\S/.test(c); // a real `mneme <verb...>` shell command
153
+ }
154
+ /** The shell argv (after "mneme") for a parameterless command. */
155
+ export function shellArgsFor(item) {
156
+ return item.command.replace(/^mneme\s+/, "").trim().split(/\s+/).filter(Boolean);
157
+ }
158
+ //# sourceMappingURL=tui_core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui_core.js","sourceRoot":"","sources":["../../src/ui/tui_core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * v2.77.0 — INTERACTIVE TUI renderer (pure: state → lines). No terminal needed
3
+ * to test layout; the driver just joins these lines + paints the screen.
4
+ */
5
+ import type { UiState } from "./tui_core.js";
6
+ /** Visible width ignoring ANSI (good enough for our ASCII + a few emoji). */
7
+ export declare function stripAnsi(s: string): string;
8
+ export declare function truncate(s: string, width: number): string;
9
+ /** Render the whole frame as an array of lines (each padded to `cols`). */
10
+ export declare function renderFrame(state: UiState, cols: number, rows: number, version?: string): string[];
11
+ //# sourceMappingURL=tui_render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui_render.d.ts","sourceRoot":"","sources":["../../src/ui/tui_render.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAW,MAAM,eAAe,CAAC;AAUtD,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAA6C;AAEzF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIzD;AAeD,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,SAAM,GAAG,MAAM,EAAE,CA2C/F"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * v2.77.0 — INTERACTIVE TUI renderer (pure: state → lines). No terminal needed
3
+ * to test layout; the driver just joins these lines + paints the screen.
4
+ */
5
+ import { isParameterless } from "./tui_core.js";
6
+ const ESC = "\x1b[";
7
+ const INV = `${ESC}7m`; // inverse (selected row)
8
+ const DIM = `${ESC}2m`;
9
+ const BOLD = `${ESC}1m`;
10
+ const CYAN = `${ESC}36m`;
11
+ const RST = `${ESC}0m`;
12
+ /** Visible width ignoring ANSI (good enough for our ASCII + a few emoji). */
13
+ export function stripAnsi(s) { return s.replace(/\x1b\[[0-9;]*m/g, ""); }
14
+ export function truncate(s, width) {
15
+ const plain = stripAnsi(s);
16
+ if (plain.length <= width)
17
+ return s + " ".repeat(Math.max(0, width - plain.length));
18
+ return plain.slice(0, Math.max(0, width - 1)) + "…";
19
+ }
20
+ function wrap(s, width, maxLines) {
21
+ const words = s.split(/\s+/);
22
+ const lines = [];
23
+ let cur = "";
24
+ for (const w of words) {
25
+ if ((cur + (cur ? " " : "") + w).length > width) {
26
+ if (cur)
27
+ lines.push(cur);
28
+ cur = w;
29
+ }
30
+ else
31
+ cur += (cur ? " " : "") + w;
32
+ if (lines.length >= maxLines)
33
+ break;
34
+ }
35
+ if (cur && lines.length < maxLines)
36
+ lines.push(cur);
37
+ return lines.slice(0, maxLines);
38
+ }
39
+ /** Render the whole frame as an array of lines (each padded to `cols`). */
40
+ export function renderFrame(state, cols, rows, version = "?") {
41
+ const W = Math.max(40, cols);
42
+ if (state.mode === "output")
43
+ return renderOutput(state, W, rows);
44
+ const lines = [];
45
+ // 0 — title
46
+ lines.push(truncate(`${BOLD}${CYAN}⏳ Mneme${RST}${DIM} — interactive · type to search · ↑↓ move · Enter run · Esc clear/quit${RST} ${DIM}v${version}${RST}`, W));
47
+ // 1 — search box
48
+ const count = `${DIM}(${state.filtered.length}/${state.all.length})${RST}`;
49
+ lines.push(truncate(`${BOLD}🔎 ${RST}${state.query}${BOLD}▏${RST} ${count}`, W));
50
+ lines.push(truncate(`${DIM}${"─".repeat(W)}${RST}`, W));
51
+ // list window
52
+ const win = state.filtered.slice(state.scrollTop, state.scrollTop + state.listRows);
53
+ if (win.length === 0) {
54
+ lines.push(truncate(`${DIM} no capability matches “${state.query}” — try fewer / different words${RST}`, W));
55
+ for (let i = 1; i < state.listRows; i++)
56
+ lines.push(" ".repeat(W));
57
+ }
58
+ else {
59
+ for (let i = 0; i < state.listRows; i++) {
60
+ const item = win[i];
61
+ if (!item) {
62
+ lines.push(" ".repeat(W));
63
+ continue;
64
+ }
65
+ const isSel = state.scrollTop + i === state.selected;
66
+ const tag = `${DIM}[${item.group}]${RST}`;
67
+ const body = `${isSel ? "▶ " : " "}${item.command}`;
68
+ const row = truncate(`${body} ${tag}`, W);
69
+ lines.push(isSel ? `${INV}${truncate(body + " [" + item.group + "]", W)}${RST}` : row);
70
+ }
71
+ }
72
+ // detail pane for the selected item
73
+ lines.push(truncate(`${DIM}${"─".repeat(W)}${RST}`, W));
74
+ const sel = state.filtered[state.selected];
75
+ if (sel) {
76
+ lines.push(truncate(`${BOLD}${sel.command}${RST} ${DIM}· ${sel.group} · since ${sel.since}${RST}`, W));
77
+ for (const l of wrap(sel.what, W - 2, 3))
78
+ lines.push(truncate(" " + l, W));
79
+ if (sel.when)
80
+ for (const l of wrap(`when: ${sel.when}`, W - 2, 2))
81
+ lines.push(truncate(` ${DIM}${l}${RST}`, W));
82
+ lines.push(truncate(runHint(sel), W));
83
+ }
84
+ // footer
85
+ lines.push(truncate(`${DIM}${"─".repeat(W)}${RST}`, W));
86
+ lines.push(truncate(`${DIM}↑↓ navigate · PgUp/PgDn · type to search · Enter ${isParameterless(sel ?? {}) ? "run" : "show usage"} · Esc clear/quit${RST}`, W));
87
+ return lines;
88
+ }
89
+ function runHint(item) {
90
+ if (isParameterless(item))
91
+ return ` ${CYAN}↵ Enter${RST}${DIM} runs this now${RST}`;
92
+ if (/^[a-z_]+\.[a-z_]/i.test(item.command.split(" ")[0] ?? ""))
93
+ return ` ${DIM}MCP tool — call from your AI agent: ${item.command}${RST}`;
94
+ return ` ${DIM}needs arguments — run: ${item.command}${RST}`;
95
+ }
96
+ function renderOutput(state, W, rows) {
97
+ const lines = [];
98
+ lines.push(truncate(`${BOLD}${CYAN}▶ ${state.outputTitle ?? "output"}${RST}`, W));
99
+ lines.push(truncate(`${DIM}${"─".repeat(W)}${RST}`, W));
100
+ const body = (state.output ?? "").split(/\r?\n/);
101
+ const max = Math.max(3, rows - 4);
102
+ for (let i = 0; i < max; i++)
103
+ lines.push(truncate(body[i] ?? "", W));
104
+ lines.push(truncate(`${DIM}— press any key to return to the menu —${RST}`, W));
105
+ return lines;
106
+ }
107
+ //# sourceMappingURL=tui_render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui_render.js","sourceRoot":"","sources":["../../src/ui/tui_render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * v2.76.0 — Windows-tolerant `--json` argument parser.
3
+ *
4
+ * THE BUG. `mneme <family> <action> --json '{"a":1}'` works in bash, but on
5
+ * Windows the user shells through cmd.exe, which:
6
+ * • does NOT treat single quotes as quoting → the arg arrives as the literal
7
+ * string `'{"a":1}'` (surrounding single quotes included) → JSON.parse fails;
8
+ * • can strip the inner double quotes from `--json "{\"a\":1}"` → `{a:1}`.
9
+ * Either way, programmatic integration on Windows was painful (the only reliable
10
+ * path was `node <binpath> ... ` with shell:false). This helper makes the raw
11
+ * `--json` value robust by trying, in order:
12
+ * 0. JSON.parse as-is
13
+ * 1. strip ONE layer of surrounding matching quotes cmd left literal (' " `)
14
+ * 2. JSON5-lite repair: single-quoted strings → double-quoted; bare
15
+ * identifier keys → quoted (handles cmd that dropped the inner quotes)
16
+ *
17
+ * Pure + dependency-free. Never throws — returns a structured result so the
18
+ * caller can print a helpful hint (use a file / stdin) on total failure.
19
+ */
20
+ export interface JsonArgOk {
21
+ ok: true;
22
+ value: unknown;
23
+ repaired: boolean;
24
+ }
25
+ export interface JsonArgErr {
26
+ ok: false;
27
+ error: string;
28
+ }
29
+ export type JsonArgResult = JsonArgOk | JsonArgErr;
30
+ export declare function parseJsonArg(raw: unknown): JsonArgResult;
31
+ //# sourceMappingURL=json_arg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json_arg.d.ts","sourceRoot":"","sources":["../../src/util/json_arg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,SAAS;IAAG,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;CAAE;AAC3E,MAAM,WAAW,UAAU;IAAG,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;CAAE;AACzD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AAiBnD,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,CA0BxD"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * v2.76.0 — Windows-tolerant `--json` argument parser.
3
+ *
4
+ * THE BUG. `mneme <family> <action> --json '{"a":1}'` works in bash, but on
5
+ * Windows the user shells through cmd.exe, which:
6
+ * • does NOT treat single quotes as quoting → the arg arrives as the literal
7
+ * string `'{"a":1}'` (surrounding single quotes included) → JSON.parse fails;
8
+ * • can strip the inner double quotes from `--json "{\"a\":1}"` → `{a:1}`.
9
+ * Either way, programmatic integration on Windows was painful (the only reliable
10
+ * path was `node <binpath> ... ` with shell:false). This helper makes the raw
11
+ * `--json` value robust by trying, in order:
12
+ * 0. JSON.parse as-is
13
+ * 1. strip ONE layer of surrounding matching quotes cmd left literal (' " `)
14
+ * 2. JSON5-lite repair: single-quoted strings → double-quoted; bare
15
+ * identifier keys → quoted (handles cmd that dropped the inner quotes)
16
+ *
17
+ * Pure + dependency-free. Never throws — returns a structured result so the
18
+ * caller can print a helpful hint (use a file / stdin) on total failure.
19
+ */
20
+ function tryParse(s) {
21
+ try {
22
+ return JSON.parse(s);
23
+ }
24
+ catch {
25
+ return undefined;
26
+ }
27
+ }
28
+ /** JSON5-lite: convert single-quoted strings to double-quoted + quote bare keys.
29
+ * Best-effort string surgery for cmd-mangled JSON; only used as a last resort
30
+ * after strict parses fail, so it can never corrupt already-valid JSON. */
31
+ function repair(s) {
32
+ return s
33
+ // 'value' / 'key' → "value" / "key" (single-quoted tokens with no escapes)
34
+ .replace(/'([^'\\]*)'/g, '"$1"')
35
+ // {key: ,key: → {"key": ,"key": (bare identifier keys)
36
+ .replace(/([{,]\s*)([A-Za-z_$][\w$]*)\s*:/g, '$1"$2":');
37
+ }
38
+ export function parseJsonArg(raw) {
39
+ if (typeof raw !== "string")
40
+ return { ok: false, error: "value is not a string" };
41
+ let s = raw.trim();
42
+ if (s.length === 0)
43
+ return { ok: false, error: "empty --json value" };
44
+ // 0. strict, as-is.
45
+ let v = tryParse(s);
46
+ if (v !== undefined)
47
+ return { ok: true, value: v, repaired: false };
48
+ // 1. strip ONE layer of surrounding matching quotes (the cmd.exe single-quote case).
49
+ const q = s[0];
50
+ if ((q === "'" || q === '"' || q === "`") && s[s.length - 1] === q && s.length >= 2) {
51
+ const inner = s.slice(1, -1);
52
+ v = tryParse(inner);
53
+ if (v !== undefined)
54
+ return { ok: true, value: v, repaired: true };
55
+ s = inner; // keep the unwrapped form for the repair pass
56
+ }
57
+ // 2. JSON5-lite repair (single-quoted / unquoted-key JSON).
58
+ v = tryParse(repair(s));
59
+ if (v !== undefined)
60
+ return { ok: true, value: v, repaired: true };
61
+ return {
62
+ ok: false,
63
+ error: "could not parse --json (even after Windows-shell quote repair). On cmd.exe, prefer the explicit --<field> flags, or pass the payload via a file/stdin.",
64
+ };
65
+ }
66
+ //# sourceMappingURL=json_arg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json_arg.js","sourceRoot":"","sources":["../../src/util/json_arg.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,SAAS,QAAQ,CAAC,CAAS;IACzB,IAAI,CAAC;QAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,SAAS,CAAC;IAAC,CAAC;AAC3D,CAAC;AAED;;4EAE4E;AAC5E,SAAS,MAAM,CAAC,CAAS;IACvB,OAAO,CAAC;QACN,+EAA+E;SAC9E,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC;QAChC,6DAA6D;SAC5D,OAAO,CAAC,kCAAkC,EAAE,SAAS,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC;IAClF,IAAI,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IACnB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC;IAEtE,oBAAoB;IACpB,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IAEpE,qFAAqF;IACrF,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACf,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACpF,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QACpB,IAAI,CAAC,KAAK,SAAS;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;QACnE,CAAC,GAAG,KAAK,CAAC,CAAC,8CAA8C;IAC3D,CAAC;IAED,4DAA4D;IAC5D,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACxB,IAAI,CAAC,KAAK,SAAS;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAEnE,OAAO;QACL,EAAE,EAAE,KAAK;QACT,KAAK,EAAE,wJAAwJ;KAChK,CAAC;AACJ,CAAC"}