@hasna/mementos 0.4.32 → 0.4.33

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/dist/mcp/index.js CHANGED
@@ -6368,6 +6368,42 @@ server.tool("memory_forget", "Delete a memory by ID or key", {
6368
6368
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6369
6369
  }
6370
6370
  });
6371
+ server.tool("memory_stale", "Find memories not accessed recently. Useful for cleanup or review.", {
6372
+ days: exports_external.coerce.number().optional(),
6373
+ project_id: exports_external.string().optional(),
6374
+ agent_id: exports_external.string().optional(),
6375
+ limit: exports_external.coerce.number().optional()
6376
+ }, async (args) => {
6377
+ try {
6378
+ const days = args.days || 30;
6379
+ const db = getDatabase();
6380
+ const conditions = [
6381
+ "status = 'active'",
6382
+ `(accessed_at IS NULL OR accessed_at < datetime('now', '-${days} days'))`,
6383
+ "pinned = 0"
6384
+ ];
6385
+ const params = [];
6386
+ if (args.project_id) {
6387
+ conditions.push("project_id = ?");
6388
+ params.push(args.project_id);
6389
+ }
6390
+ if (args.agent_id) {
6391
+ conditions.push("agent_id = ?");
6392
+ params.push(args.agent_id);
6393
+ }
6394
+ const limit = args.limit || 20;
6395
+ const rows = db.query(`SELECT id, key, value, importance, scope, category, accessed_at, access_count FROM memories WHERE ${conditions.join(" AND ")} ORDER BY COALESCE(accessed_at, created_at) ASC LIMIT ?`).all(...params, limit);
6396
+ if (rows.length === 0) {
6397
+ return { content: [{ type: "text", text: `No stale memories found (last accessed > ${days} days ago).` }] };
6398
+ }
6399
+ const lines = rows.map((m) => `[${m.importance}] ${m.key} (${m.scope}/${m.category}) \u2014 last accessed: ${m.accessed_at?.slice(0, 10) || "never"}, ${m.access_count} reads`);
6400
+ return { content: [{ type: "text", text: `${rows.length} stale memor${rows.length === 1 ? "y" : "ies"} (not accessed in ${days}+ days):
6401
+ ${lines.join(`
6402
+ `)}` }] };
6403
+ } catch (e) {
6404
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
6405
+ }
6406
+ });
6371
6407
  server.tool("memory_search", "Search memories by keyword across key, value, summary, and tags", {
6372
6408
  query: exports_external.string(),
6373
6409
  scope: exports_external.enum(["global", "shared", "private"]).optional(),
@@ -7351,6 +7387,17 @@ var FULL_SCHEMAS = {
7351
7387
  },
7352
7388
  example: '{"key":"old-preference","scope":"global"}'
7353
7389
  },
7390
+ memory_stale: {
7391
+ description: "Find memories not accessed recently \u2014 useful for cleanup review (same pattern as get_stale_tasks in todos).",
7392
+ category: "memory",
7393
+ params: {
7394
+ days: { type: "number", description: "Stale threshold in days (default 30)" },
7395
+ project_id: { type: "string", description: "Filter by project" },
7396
+ agent_id: { type: "string", description: "Filter by agent" },
7397
+ limit: { type: "number", description: "Max results (default 20)" }
7398
+ },
7399
+ example: '{"days":14,"project_id":"proj-uuid"}'
7400
+ },
7354
7401
  memory_search: {
7355
7402
  description: "Full-text search across key, value, summary, and tags.",
7356
7403
  category: "memory",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AA2qCH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA6H9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAosCH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CA6H9C"}
@@ -2293,6 +2293,30 @@ addRoute("GET", "/api/activity", (_req, url) => {
2293
2293
  `).all(...params);
2294
2294
  return json({ activity: rows, days, total: rows.reduce((s, r) => s + r.memories_created, 0) });
2295
2295
  });
2296
+ addRoute("GET", "/api/memories/stale", (_req, url) => {
2297
+ const q = getSearchParams(url);
2298
+ const days = Math.min(parseInt(q["days"] || "30", 10), 365);
2299
+ const projectId = q["project_id"];
2300
+ const agentId = q["agent_id"];
2301
+ const limit = Math.min(parseInt(q["limit"] || "20", 10), 100);
2302
+ const db = getDatabase();
2303
+ const conds = [
2304
+ "status = 'active'",
2305
+ `(accessed_at IS NULL OR accessed_at < datetime('now', '-${days} days'))`,
2306
+ "pinned = 0"
2307
+ ];
2308
+ const params = [];
2309
+ if (projectId) {
2310
+ conds.push("project_id = ?");
2311
+ params.push(projectId);
2312
+ }
2313
+ if (agentId) {
2314
+ conds.push("agent_id = ?");
2315
+ params.push(agentId);
2316
+ }
2317
+ const rows = db.query(`SELECT id, key, value, importance, scope, category, accessed_at, access_count, created_at FROM memories WHERE ${conds.join(" AND ")} ORDER BY COALESCE(accessed_at, created_at) ASC LIMIT ?`).all(...params, limit);
2318
+ return json({ memories: rows, count: rows.length, days });
2319
+ });
2296
2320
  addRoute("GET", "/api/report", (_req, url) => {
2297
2321
  const q = getSearchParams(url);
2298
2322
  const days = Math.min(parseInt(q["days"] || "7", 10), 365);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/mementos",
3
- "version": "0.4.32",
3
+ "version": "0.4.33",
4
4
  "description": "Universal memory system for AI agents - CLI + MCP server + library API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",