hmem-mcp 7.0.5 → 7.1.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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Your AI forgets everything between sessions. **hmem fixes that.**
4
4
 
5
- One `read_memory()` call. 5k tokens. Your agent knows every project, every past mistake, every decision you ever made together — across sessions, devices, and AI providers. No setup per conversation. No "let me re-read the codebase." It just *remembers*.
5
+ One `load_project()` call. 5k tokens. Your agent knows everything important about a project, every past mistake, every decision you ever made together — across sessions, devices, and AI providers. No setup per conversation. No "let me re-read the codebase." It just *remembers*.
6
6
 
7
7
  ---
8
8
 
@@ -0,0 +1,9 @@
1
+ /**
2
+ * cli-stats.ts
3
+ *
4
+ * Shows per-project token size estimates and global memory stats.
5
+ * Helps identify projects approaching the curation threshold (R0018: >4k tokens = trigger).
6
+ *
7
+ * Usage: hmem stats [project-id]
8
+ */
9
+ export declare function printStats(filterProject?: string): Promise<void>;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * cli-stats.ts
3
+ *
4
+ * Shows per-project token size estimates and global memory stats.
5
+ * Helps identify projects approaching the curation threshold (R0018: >4k tokens = trigger).
6
+ *
7
+ * Usage: hmem stats [project-id]
8
+ */
9
+ import path from "node:path";
10
+ import { resolveEnvDefaults } from "./cli-env.js";
11
+ import { HmemStore } from "./hmem-store.js";
12
+ import { loadHmemConfig } from "./hmem-config.js";
13
+ const C = {
14
+ green: "\x1b[01;32m",
15
+ yellow: "\x1b[01;33m",
16
+ red: "\x1b[01;31m",
17
+ cyan: "\x1b[00;36m",
18
+ gray: "\x1b[00;90m",
19
+ white: "\x1b[00;37m",
20
+ bold: "\x1b[01m",
21
+ reset: "\x1b[00m",
22
+ };
23
+ // R0018 thresholds (chars, not tokens — 1 token ≈ 4 chars)
24
+ const RED_THRESHOLD = 16_000; // ~4k tokens
25
+ const YELLOW_THRESHOLD = 14_000; // ~3.5k tokens
26
+ function sizeColor(chars) {
27
+ if (chars >= RED_THRESHOLD)
28
+ return C.red;
29
+ if (chars >= YELLOW_THRESHOLD)
30
+ return C.yellow;
31
+ return C.green;
32
+ }
33
+ function sizeLabel(chars) {
34
+ const tokens = Math.round(chars / 4);
35
+ if (tokens >= 1000)
36
+ return `~${(tokens / 1000).toFixed(1)}k tokens`;
37
+ return `~${tokens} tokens`;
38
+ }
39
+ function relativeDate(iso) {
40
+ if (!iso)
41
+ return "never";
42
+ const diff = Date.now() - new Date(iso).getTime();
43
+ const days = Math.floor(diff / 86_400_000);
44
+ if (days === 0)
45
+ return "today";
46
+ if (days === 1)
47
+ return "yesterday";
48
+ if (days < 30)
49
+ return `${days}d ago`;
50
+ return `${Math.floor(days / 30)}mo ago`;
51
+ }
52
+ export async function printStats(filterProject) {
53
+ resolveEnvDefaults();
54
+ const hmemPath = process.env.HMEM_PATH;
55
+ if (!hmemPath) {
56
+ console.error("HMEM_PATH not set.");
57
+ process.exit(1);
58
+ }
59
+ const dir = path.dirname(hmemPath);
60
+ const config = loadHmemConfig(dir);
61
+ const store = new HmemStore(hmemPath, config);
62
+ const global = store.stats();
63
+ const projects = store.projectTokenStats();
64
+ const totalTokens = Math.round(global.totalChars / 4);
65
+ console.log(`\n${C.bold}hmem stats${C.reset} ${C.gray}${path.basename(hmemPath)}${C.reset}`);
66
+ console.log(`${C.gray}${"─".repeat(60)}${C.reset}`);
67
+ console.log(` Total entries : ${C.white}${global.total}${C.reset}`);
68
+ console.log(` Total size : ${C.white}${totalTokens >= 1000 ? (totalTokens / 1000).toFixed(0) + "k" : totalTokens} tokens${C.reset} ${C.gray}(${(global.totalChars / 1024).toFixed(0)} KB)${C.reset}`);
69
+ if (global.staleCount > 0) {
70
+ console.log(` Stale (60d+) : ${C.yellow}${global.staleCount} entries${C.reset}`);
71
+ }
72
+ const prefixOrder = ["P", "L", "T", "E", "D", "R", "O", "I", "H", "M", "S", "N", "C", "A"];
73
+ const prefixLine = prefixOrder
74
+ .filter(p => global.byPrefix[p])
75
+ .map(p => `${C.gray}${p}${C.reset}${C.white}${global.byPrefix[p]}${C.reset}`)
76
+ .join(" ");
77
+ console.log(` By prefix : ${prefixLine}`);
78
+ const filtered = filterProject
79
+ ? projects.filter(p => p.id.toLowerCase() === filterProject.toLowerCase())
80
+ : projects;
81
+ if (filtered.length === 0) {
82
+ console.log(`\n ${C.gray}No matching projects.${C.reset}\n`);
83
+ return;
84
+ }
85
+ console.log(`\n${C.bold}Projects — load_project size estimate${C.reset} ${C.gray}(R0018: >4k = curate)${C.reset}`);
86
+ console.log(`${C.gray}${"─".repeat(60)}${C.reset}`);
87
+ for (const p of filtered) {
88
+ const color = sizeColor(p.estChars);
89
+ const flag = p.estChars >= RED_THRESHOLD ? " 🔴" : p.estChars >= YELLOW_THRESHOLD ? " 🟡" : "";
90
+ const activeMarker = p.active ? ` ${C.cyan}●${C.reset}` : "";
91
+ const label = sizeLabel(p.estChars);
92
+ const date = relativeDate(p.lastAccessed);
93
+ const idPart = `${C.cyan}${p.id}${C.reset}`;
94
+ const namePart = p.title.length > 28 ? p.title.substring(0, 27) + "…" : p.title.padEnd(28);
95
+ const sizePart = `${color}${label}${C.reset}${flag}`;
96
+ const datePart = `${C.gray}${date}${C.reset}`;
97
+ console.log(` ${idPart}${activeMarker} ${namePart} ${sizePart} ${datePart}`);
98
+ }
99
+ console.log(`\n${C.gray}Thresholds: 🟡 ~3.5k tokens 🔴 ~4k tokens${C.reset}\n`);
100
+ }
101
+ //# sourceMappingURL=cli-stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-stats.js","sourceRoot":"","sources":["../src/cli-stats.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -62,6 +62,11 @@ switch (command) {
62
62
  await summarizeSession(process.argv[3] || "");
63
63
  break;
64
64
  }
65
+ case "stats": {
66
+ const { printStats } = await import("./cli-stats.js");
67
+ await printStats(process.argv[3]);
68
+ break;
69
+ }
65
70
  case "delete": {
66
71
  const { deleteEntry } = await import("./cli-delete.js");
67
72
  await deleteEntry(process.argv.slice(3));
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -309,6 +309,17 @@ export declare class HmemStore {
309
309
  totalChars: number;
310
310
  staleCount: number;
311
311
  };
312
+ /**
313
+ * Per-project token size estimates for `hmem stats`.
314
+ * Measures load_project payload size: level_1 + all node content/titles at depth ≤ 3.
315
+ */
316
+ projectTokenStats(): Array<{
317
+ id: string;
318
+ title: string;
319
+ estChars: number;
320
+ lastAccessed: string | null;
321
+ active: number;
322
+ }>;
312
323
  /**
313
324
  * Update specific fields of an existing root entry (curator use only).
314
325
  */
@@ -655,8 +655,21 @@ export class HmemStore {
655
655
  const searchTerm = opts.search.replace(/"/g, "").trim();
656
656
  if (!searchTerm)
657
657
  return [];
658
- // FTS5 phrase match all words must appear in the text
659
- const ftsMatch = `"${searchTerm}"`;
658
+ // Stopwords that pollute BM25 rankings in code/memory context
659
+ const FTS_STOPWORDS = new Set([
660
+ "the", "a", "an", "and", "or", "in", "of", "to", "with", "on", "for", "is", "are", "was", "were", "be", "been",
661
+ "add", "added", "fix", "fixed", "update", "updates", "updated", "run", "running", "using", "use", "used",
662
+ "test", "tests", "done", "make", "made", "new", "get", "set", "has", "have", "had", "its",
663
+ "der", "die", "das", "ein", "eine", "und", "oder", "von", "zu", "mit", "auf", "ist", "sind", "hat", "haben",
664
+ ]);
665
+ const words = searchTerm.split(/\s+/)
666
+ .map(w => w.replace(/[^a-zA-Z0-9äöüÄÖÜß_-]/g, ""))
667
+ .filter(w => w.length > 1 && !FTS_STOPWORDS.has(w.toLowerCase()));
668
+ // Multi-word: AND match on individual tokens (better recall than phrase match)
669
+ // Single-word or all-stopwords: fall back to phrase match on original term
670
+ const ftsMatch = words.length >= 2
671
+ ? words.map(w => `"${w}"`).join(" ")
672
+ : `"${searchTerm}"`;
660
673
  const ftsRows = this.db.prepare("SELECT rm.root_id, rm.node_id FROM hmem_fts_rowid_map rm " +
661
674
  "JOIN hmem_fts fts ON fts.rowid = rm.fts_rowid " +
662
675
  "WHERE hmem_fts MATCH ?").all(ftsMatch);
@@ -1673,6 +1686,34 @@ export class HmemStore {
1673
1686
  const staleCount = this.db.prepare("SELECT COUNT(*) as c FROM memories WHERE seq > 0 AND prefix != 'O' AND irrelevant != 1 AND obsolete != 1 AND last_accessed < datetime('now', '-60 days')").get().c;
1674
1687
  return { total, byPrefix, totalChars: memChars + nodeChars, staleCount };
1675
1688
  }
1689
+ /**
1690
+ * Per-project token size estimates for `hmem stats`.
1691
+ * Measures load_project payload size: level_1 + all node content/titles at depth ≤ 3.
1692
+ */
1693
+ projectTokenStats() {
1694
+ const rows = this.db.prepare(`
1695
+ SELECT
1696
+ m.id,
1697
+ m.title,
1698
+ m.last_accessed,
1699
+ m.active,
1700
+ COALESCE(LENGTH(m.level_1), 0) + COALESCE((
1701
+ SELECT SUM(LENGTH(COALESCE(n.title,'')) + LENGTH(COALESCE(n.content,'')))
1702
+ FROM memory_nodes n
1703
+ WHERE n.root_id = m.id AND n.depth <= 3
1704
+ ), 0) AS est_chars
1705
+ FROM memories m
1706
+ WHERE m.prefix = 'P' AND m.obsolete != 1 AND m.irrelevant != 1 AND m.seq > 0
1707
+ ORDER BY m.last_accessed DESC NULLS LAST
1708
+ `).all();
1709
+ return rows.map(r => ({
1710
+ id: r.id,
1711
+ title: (r.title ?? "").split("|")[0].trim(),
1712
+ estChars: r.est_chars ?? 0,
1713
+ lastAccessed: r.last_accessed ?? null,
1714
+ active: r.active ?? 0,
1715
+ }));
1716
+ }
1676
1717
  /**
1677
1718
  * Update specific fields of an existing root entry (curator use only).
1678
1719
  */