@hasna/mementos 0.10.15 → 0.10.16

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 (2) hide show
  1. package/dist/mcp/index.js +67 -0
  2. package/package.json +1 -1
package/dist/mcp/index.js CHANGED
@@ -9826,6 +9826,73 @@ ${lines.join(`
9826
9826
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
9827
9827
  }
9828
9828
  });
9829
+ server.tool("memory_health", "Comprehensive health check for memories. Detects: stale (old + 0 access), high-importance-forgotten (importance>=7 + not accessed in 60d), and possibly-superseded (newer memory with similar key). Returns actionable summary.", {
9830
+ stale_days: exports_external.coerce.number().optional().describe("Days with no access to consider a memory stale (default: 30)"),
9831
+ forgotten_days: exports_external.coerce.number().optional().describe("Days since access for high-importance memories (default: 60)"),
9832
+ project_id: exports_external.string().optional(),
9833
+ agent_id: exports_external.string().optional(),
9834
+ limit: exports_external.coerce.number().optional().describe("Max per category (default: 10)")
9835
+ }, async (args) => {
9836
+ try {
9837
+ const db = getDatabase();
9838
+ const staleDays = args.stale_days ?? 30;
9839
+ const forgottenDays = args.forgotten_days ?? 60;
9840
+ const limit = args.limit ?? 10;
9841
+ const extraWhere = [
9842
+ ...args.project_id ? ["project_id = ?"] : [],
9843
+ ...args.agent_id ? ["agent_id = ?"] : []
9844
+ ].join(" AND ");
9845
+ const extraParams = [
9846
+ ...args.project_id ? [args.project_id] : [],
9847
+ ...args.agent_id ? [args.agent_id] : []
9848
+ ];
9849
+ const base = `status = 'active' AND pinned = 0${extraWhere ? " AND " + extraWhere : ""}`;
9850
+ const stale = db.prepare(`SELECT id, key, value, importance, scope, created_at FROM memories
9851
+ WHERE ${base} AND access_count = 0 AND created_at < datetime('now', '-${staleDays} days')
9852
+ ORDER BY created_at ASC LIMIT ?`).all(...extraParams, limit);
9853
+ const forgotten = db.prepare(`SELECT id, key, value, importance, scope, accessed_at FROM memories
9854
+ WHERE ${base} AND importance >= 7
9855
+ AND (accessed_at IS NULL OR accessed_at < datetime('now', '-${forgottenDays} days'))
9856
+ ORDER BY importance DESC, COALESCE(accessed_at, created_at) ASC LIMIT ?`).all(...extraParams, limit);
9857
+ const dupes = db.prepare(`SELECT key, COUNT(*) as cnt, MAX(updated_at) as latest, MIN(created_at) as oldest
9858
+ FROM memories WHERE ${base}
9859
+ GROUP BY key HAVING cnt > 1
9860
+ ORDER BY cnt DESC LIMIT ?`).all(...extraParams, limit);
9861
+ const parts = [`Memory Health Report
9862
+ `];
9863
+ if (stale.length > 0) {
9864
+ parts.push(`\u26A0\uFE0F STALE (${stale.length}) \u2014 created ${staleDays}d+ ago, never accessed:`);
9865
+ for (const m of stale) {
9866
+ parts.push(` \u2022 [${m.importance}] ${m.key} (${m.scope}) \u2014 created ${m.created_at.slice(0, 10)}`);
9867
+ }
9868
+ parts.push("");
9869
+ }
9870
+ if (forgotten.length > 0) {
9871
+ parts.push(`\uD83D\uDD14 HIGH-IMPORTANCE FORGOTTEN (${forgotten.length}) \u2014 importance\u22657, not accessed in ${forgottenDays}d+:`);
9872
+ for (const m of forgotten) {
9873
+ parts.push(` \u2022 [${m.importance}] ${m.key} (${m.scope}) \u2014 last: ${m.accessed_at?.slice(0, 10) || "never"}`);
9874
+ }
9875
+ parts.push("");
9876
+ }
9877
+ if (dupes.length > 0) {
9878
+ parts.push(`\uD83D\uDD04 POSSIBLY SUPERSEDED (${dupes.length}) \u2014 same key with multiple versions:`);
9879
+ for (const d of dupes) {
9880
+ parts.push(` \u2022 ${d.key} \xD7 ${d.cnt} copies \u2014 newest: ${d.latest.slice(0, 10)}`);
9881
+ }
9882
+ parts.push("");
9883
+ }
9884
+ if (stale.length === 0 && forgotten.length === 0 && dupes.length === 0) {
9885
+ parts.push("\u2713 No health issues found. All memories look fresh.");
9886
+ } else {
9887
+ parts.push(`Summary: ${stale.length} stale, ${forgotten.length} forgotten, ${dupes.length} possibly-superseded.`);
9888
+ parts.push("Suggested actions: archive stale memories, review forgotten ones, merge duplicates.");
9889
+ }
9890
+ return { content: [{ type: "text", text: parts.join(`
9891
+ `) }] };
9892
+ } catch (e) {
9893
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
9894
+ }
9895
+ });
9829
9896
  server.tool("memory_search", "Search memories by keyword across key, value, summary, and tags", {
9830
9897
  query: exports_external.string(),
9831
9898
  scope: exports_external.enum(["global", "shared", "private"]).optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/mementos",
3
- "version": "0.10.15",
3
+ "version": "0.10.16",
4
4
  "description": "Universal memory system for AI agents - CLI + MCP server + library API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",