memhook 0.2.2 → 0.3.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,280 @@
1
+ /**
2
+ * `memhook tail` — a pretty, live view of the JSONL routing log.
3
+ *
4
+ * This is the human-facing twin of `tail -f ~/.claude/logs/memhook.log | jq`:
5
+ * it reads the SAME frozen log the router writes (docs/SPECIFICATION.md §14 —
6
+ * "the memhook tail TUI parses it"), and renders each routing decision as a
7
+ * colourised row. It only ever READS the log, so it can never affect the hook.
8
+ *
9
+ * No TUI framework, no dependency: the layout is plain column padding + the
10
+ * `src/ansi.ts` styler, which degrades to clean text when stdout is not a TTY
11
+ * (so `memhook tail --no-follow > report.txt` is well-behaved).
12
+ *
13
+ * Pure rendering (`parseLogLine`, `formatRow`, the stats reducer) is split from
14
+ * the follow-loop shell so the formatting is unit-tested without a terminal.
15
+ */
16
+ import { existsSync, openSync, readSync, closeSync, readFileSync, statSync } from "node:fs";
17
+ import { loadConfig } from "./config.js";
18
+ import { MEMHOOK_VERSION } from "./version.js";
19
+ import { makeAnsi, padStart, padEnd, truncate } from "./ansi.js";
20
+ function asInt(v) {
21
+ return typeof v === "number" && Number.isFinite(v) ? Math.floor(v) : 0;
22
+ }
23
+ /** Parse one JSONL line into a `LogRow`, or null if it isn't a usable entry. */
24
+ export function parseLogLine(line) {
25
+ let obj;
26
+ try {
27
+ obj = JSON.parse(line);
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ if (typeof obj !== "object" || obj === null || Array.isArray(obj))
33
+ return null;
34
+ const o = obj;
35
+ if (typeof o["status"] !== "string")
36
+ return null;
37
+ const selected = Array.isArray(o["selected"])
38
+ ? o["selected"].filter((x) => typeof x === "string")
39
+ : [];
40
+ return {
41
+ ts: typeof o["ts"] === "string" ? o["ts"] : "",
42
+ promptPreview: typeof o["prompt_preview"] === "string" ? o["prompt_preview"] : "",
43
+ selected,
44
+ latencyMs: asInt(o["latency_ms"]),
45
+ tokensIn: asInt(o["tokens_in"]),
46
+ tokensOut: asInt(o["tokens_out"]),
47
+ status: o["status"],
48
+ model: typeof o["model"] === "string" ? o["model"] : null,
49
+ };
50
+ }
51
+ const STATUS_STYLE = {
52
+ ok: { label: "ok", color: "green" },
53
+ cache_hit: { label: "cache", color: "cyan" },
54
+ pre_filter_skip: { label: "skip", color: "gray" },
55
+ empty_selection: { label: "empty", color: "yellow" },
56
+ all_unfound: { label: "unfound", color: "yellow" },
57
+ no_catalog: { label: "no catalog", color: "red" },
58
+ no_api_key: { label: "no key", color: "red" },
59
+ api_no_response: { label: "api err", color: "red" },
60
+ api_no_content: { label: "api err", color: "red" },
61
+ parse_invalid: { label: "bad json", color: "red" },
62
+ provider_init_failed: { label: "init err", color: "red" },
63
+ };
64
+ function styleFor(status) {
65
+ return STATUS_STYLE[status] ?? { label: status, color: "gray" };
66
+ }
67
+ const STATUS_W = Math.max(...Object.values(STATUS_STYLE).map((s) => s.label.length));
68
+ /** HH:MM:SS from an ISO timestamp, or the raw value clipped if unparseable. */
69
+ export function formatTime(ts) {
70
+ const m = ts.match(/T(\d{2}:\d{2}:\d{2})/);
71
+ return m?.[1] ?? truncate(ts, 8).padEnd(8);
72
+ }
73
+ /** Compact latency: "142ms" under a second, "2.0s" above. */
74
+ export function formatLatency(ms) {
75
+ if (ms <= 0)
76
+ return "0ms";
77
+ if (ms < 1000)
78
+ return `${ms}ms`;
79
+ return `${(ms / 1000).toFixed(1)}s`;
80
+ }
81
+ /** Right-most column: which model handled the entry (mirrors the mockup). */
82
+ export function modelCell(row) {
83
+ if (row.status === "pre_filter_skip")
84
+ return "dropped";
85
+ if (row.status === "cache_hit")
86
+ return "—";
87
+ // Statuses that never reached the provider have no model to show.
88
+ if (row.status === "no_catalog" || row.status === "no_api_key")
89
+ return "—";
90
+ return row.model ?? "—";
91
+ }
92
+ const LAT_W = 6;
93
+ const MODEL_W = 18;
94
+ /**
95
+ * Render one log row to one or two lines: the primary row (time · status ·
96
+ * prompt · latency · model) plus, when memories were injected, a dim secondary
97
+ * line listing them — the whole reason memhook exists is to see WHICH memories
98
+ * were picked.
99
+ */
100
+ export function formatRow(row, ansi, columns = 80) {
101
+ const st = styleFor(row.status);
102
+ const time = ansi.dim(formatTime(row.ts));
103
+ const status = ansi.style(st.color, padEnd(st.label, STATUS_W));
104
+ const latency = ansi.dim(padStart(formatLatency(row.latencyMs), LAT_W));
105
+ const model = ansi.dim(truncate(modelCell(row), MODEL_W));
106
+ // Prompt preview fills the space left between the fixed columns. The budget
107
+ // is constant per row (5 two-col gaps + time + status + latency + a reserved
108
+ // model column) so latency and model line up vertically across every row —
109
+ // the preview never borrows from the model column's width.
110
+ const fixed = 2 * 5 + 8 + STATUS_W + LAT_W + MODEL_W;
111
+ const previewW = Math.max(12, columns - fixed);
112
+ const preview = row.promptPreview
113
+ ? ansi.style("white", `"${truncate(row.promptPreview, previewW - 2)}"`)
114
+ : ansi.dim('""');
115
+ const main = ` ${time} ${status} ${padEnd(preview, previewW)} ${latency} ${model}`;
116
+ if (row.selected.length === 0)
117
+ return main;
118
+ const trimmed = row.selected.map((f) => f.replace(/\.md$/, ""));
119
+ const files = ansi.dim(` ↳ ${truncate(trimmed.join(" · "), Math.max(20, columns - 8))}`);
120
+ return `${main}\n${files}`;
121
+ }
122
+ export function emptyStats() {
123
+ return { count: 0, byStatus: {}, latencies: [] };
124
+ }
125
+ export function accumulate(stats, row) {
126
+ stats.count++;
127
+ stats.byStatus[row.status] = (stats.byStatus[row.status] ?? 0) + 1;
128
+ // Percentiles only over rows that actually called the provider (skips/cache
129
+ // hits sit near 0ms and would flatten the distribution).
130
+ if (row.latencyMs > 0)
131
+ stats.latencies.push(row.latencyMs);
132
+ }
133
+ function percentile(sorted, p) {
134
+ if (sorted.length === 0)
135
+ return 0;
136
+ const idx = Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1);
137
+ return sorted[Math.max(0, idx)] ?? 0;
138
+ }
139
+ export function summarize(stats) {
140
+ const ok = stats.byStatus["ok"] ?? 0;
141
+ const cache = stats.byStatus["cache_hit"] ?? 0;
142
+ const delivered = ok + cache;
143
+ const sorted = [...stats.latencies].sort((a, b) => a - b);
144
+ return {
145
+ count: stats.count,
146
+ cachePct: delivered > 0 ? Math.round((cache / delivered) * 100) : 0,
147
+ okPct: stats.count > 0 ? Math.round((delivered / stats.count) * 100) : 0,
148
+ p50: percentile(sorted, 50),
149
+ p95: percentile(sorted, 95),
150
+ };
151
+ }
152
+ // ── header / footer ──────────────────────────────────────────────────────────
153
+ function divider(ansi, columns) {
154
+ return ansi.dim(" " + "─".repeat(Math.max(10, Math.min(columns - 2, 72))));
155
+ }
156
+ export function formatHeader(info, ansi, columns = 80) {
157
+ const live = info.follow ? ansi.green("● live") : ansi.dim("○ snapshot");
158
+ const title = ansi.bold("memhook");
159
+ const who = ansi.dim(`${info.provider} · ${info.model}`);
160
+ const ver = ansi.dim(`v${info.version}`);
161
+ const lines = [
162
+ ` ${title} ${live} ${who} ${ver}`,
163
+ ansi.dim(` ${info.logPath}`),
164
+ divider(ansi, columns),
165
+ ];
166
+ if (info.follow)
167
+ lines.push(ansi.dim(" ⌃C to quit"));
168
+ return lines.join("\n");
169
+ }
170
+ export function formatFooter(stats, ansi, columns = 80) {
171
+ const s = summarize(stats);
172
+ const noun = s.count === 1 ? "prompt" : "prompts";
173
+ const parts = [
174
+ ansi.bold(`${s.count} ${noun}`),
175
+ `${s.cachePct}% cache`,
176
+ `${s.okPct}% delivered`,
177
+ `p50 ${s.p50}ms`,
178
+ `p95 ${s.p95}ms`,
179
+ ];
180
+ return `${divider(ansi, columns)}\n ${parts.join(ansi.dim(" · "))}`;
181
+ }
182
+ // ── pure helpers shared with the follow loop ────────────────────────────────
183
+ /** Last `n` non-empty lines of `text`. */
184
+ export function tailLines(text, n) {
185
+ const lines = text.split("\n").filter((l) => l.trim() !== "");
186
+ return n >= lines.length ? lines : lines.slice(lines.length - n);
187
+ }
188
+ function passesFilter(row, filter) {
189
+ return filter === null || filter.has(row.status);
190
+ }
191
+ const POLL_MS = 300;
192
+ function sleep(ms) {
193
+ return new Promise((r) => setTimeout(r, ms));
194
+ }
195
+ /** Read `len` bytes at `offset` from `path` as utf8 (best-effort). */
196
+ function readChunk(path, offset, len) {
197
+ const fd = openSync(path, "r");
198
+ try {
199
+ const buf = Buffer.alloc(len);
200
+ const read = readSync(fd, buf, 0, len, offset);
201
+ return buf.toString("utf8", 0, read);
202
+ }
203
+ finally {
204
+ closeSync(fd);
205
+ }
206
+ }
207
+ export async function runTail(opts, env = process.env) {
208
+ const config = loadConfig(env);
209
+ const logPath = opts.file ?? config.logging.jsonlPath;
210
+ const ansi = makeAnsi({ isTTY: Boolean(process.stdout.isTTY), env });
211
+ const columns = process.stdout.columns ?? 80;
212
+ const filter = opts.status && opts.status.length > 0 ? new Set(opts.status) : null;
213
+ const out = (s) => void process.stdout.write(s + "\n");
214
+ out(formatHeader({
215
+ version: MEMHOOK_VERSION,
216
+ provider: config.provider.type,
217
+ model: config.provider.model,
218
+ logPath,
219
+ follow: !opts.noFollow,
220
+ }, ansi, columns));
221
+ const stats = emptyStats();
222
+ const render = (line) => {
223
+ const row = parseLogLine(line);
224
+ if (!row)
225
+ return;
226
+ accumulate(stats, row);
227
+ if (passesFilter(row, filter))
228
+ out(formatRow(row, ansi, columns));
229
+ };
230
+ // Initial tail of the existing log.
231
+ if (existsSync(logPath)) {
232
+ for (const line of tailLines(readFileSync(logPath, "utf8"), opts.lines))
233
+ render(line);
234
+ }
235
+ if (opts.noFollow) {
236
+ out(formatFooter(stats, ansi, columns));
237
+ return 0;
238
+ }
239
+ // Follow by polling (robust + cross-platform; fs.watch semantics vary by OS).
240
+ let stop = false;
241
+ const stopped = new Promise((resolve) => {
242
+ process.once("SIGINT", () => {
243
+ stop = true;
244
+ resolve();
245
+ });
246
+ });
247
+ if (!existsSync(logPath))
248
+ out(ansi.dim(" waiting for the first prompt…"));
249
+ let offset = existsSync(logPath) ? statSync(logPath).size : 0;
250
+ let buffer = "";
251
+ while (!stop) {
252
+ await Promise.race([sleep(POLL_MS), stopped]);
253
+ if (stop)
254
+ break;
255
+ try {
256
+ if (!existsSync(logPath))
257
+ continue;
258
+ const size = statSync(logPath).size;
259
+ if (size < offset) {
260
+ offset = 0; // truncated / rotated
261
+ buffer = "";
262
+ }
263
+ if (size > offset) {
264
+ buffer += readChunk(logPath, offset, size - offset);
265
+ offset = size;
266
+ const parts = buffer.split("\n");
267
+ buffer = parts.pop() ?? "";
268
+ for (const line of parts)
269
+ if (line.trim() !== "")
270
+ render(line);
271
+ }
272
+ }
273
+ catch {
274
+ // Transient (file rotated out from under us) — retry next tick.
275
+ }
276
+ }
277
+ out("\n" + formatFooter(stats, ansi, columns));
278
+ return 0;
279
+ }
280
+ //# sourceMappingURL=tail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tail.js","sourceRoot":"","sources":["../../src/tail.ts"],"names":[],"mappings":"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"}
@@ -9,5 +9,5 @@
9
9
  * the literal in lockstep with `package.json` + `.release-please-manifest.json`.
10
10
  * Do not bump it by hand.
11
11
  */
12
- export declare const MEMHOOK_VERSION = "0.2.2";
12
+ export declare const MEMHOOK_VERSION = "0.3.0";
13
13
  //# sourceMappingURL=version.d.ts.map
@@ -9,5 +9,5 @@
9
9
  * the literal in lockstep with `package.json` + `.release-please-manifest.json`.
10
10
  * Do not bump it by hand.
11
11
  */
12
- export const MEMHOOK_VERSION = "0.2.2"; // x-release-please-version
12
+ export const MEMHOOK_VERSION = "0.3.0"; // x-release-please-version
13
13
  //# sourceMappingURL=version.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memhook",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "Semantic memory router for Claude Code — picks relevant feedbacks & rules per prompt via Haiku, injects them as additionalContext.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -17,7 +17,11 @@
17
17
  "claude-code",
18
18
  "claude",
19
19
  "anthropic",
20
+ "openai",
21
+ "ollama",
22
+ "llm",
20
23
  "memory",
24
+ "context",
21
25
  "hook",
22
26
  "userpromptsubmit",
23
27
  "semantic-router",