@hasna/mementos 0.4.17 → 0.4.20

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
@@ -5376,6 +5376,28 @@ function cleanExpiredMemories(db) {
5376
5376
  }
5377
5377
  return count;
5378
5378
  }
5379
+ function getMemoryVersions(memoryId, db) {
5380
+ const d = db || getDatabase();
5381
+ try {
5382
+ const rows = d.query("SELECT * FROM memory_versions WHERE memory_id = ? ORDER BY version ASC").all(memoryId);
5383
+ return rows.map((row) => ({
5384
+ id: row["id"],
5385
+ memory_id: row["memory_id"],
5386
+ version: row["version"],
5387
+ value: row["value"],
5388
+ importance: row["importance"],
5389
+ scope: row["scope"],
5390
+ category: row["category"],
5391
+ tags: JSON.parse(row["tags"] || "[]"),
5392
+ summary: row["summary"] || null,
5393
+ pinned: !!row["pinned"],
5394
+ status: row["status"],
5395
+ created_at: row["created_at"]
5396
+ }));
5397
+ } catch {
5398
+ return [];
5399
+ }
5400
+ }
5379
5401
 
5380
5402
  // src/lib/search.ts
5381
5403
  function parseMemoryRow2(row) {
@@ -6144,6 +6166,35 @@ server.tool("memory_get", "Get a single memory by ID.", {
6144
6166
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6145
6167
  }
6146
6168
  });
6169
+ server.tool("memory_versions", "Get version history for a memory. Shows what changed across updates.", {
6170
+ id: exports_external.string()
6171
+ }, async (args) => {
6172
+ try {
6173
+ const id = resolveId(args.id);
6174
+ const memory = getMemory(id);
6175
+ if (!memory) {
6176
+ return { content: [{ type: "text", text: `Memory not found: ${args.id}` }] };
6177
+ }
6178
+ const versions = getMemoryVersions(id);
6179
+ if (versions.length === 0) {
6180
+ return { content: [{ type: "text", text: `No version history for "${memory.key}" (current: v${memory.version})` }] };
6181
+ }
6182
+ const lines = versions.map((v) => `v${v.version} [${v.created_at.slice(0, 16)}] scope=${v.scope} importance=${v.importance} status=${v.status}
6183
+ value: ${v.value.slice(0, 120)}${v.value.length > 120 ? "..." : ""}`);
6184
+ return {
6185
+ content: [{
6186
+ type: "text",
6187
+ text: `Version history for "${memory.key}" (${versions.length} version${versions.length === 1 ? "" : "s"}, current: v${memory.version}):
6188
+
6189
+ ${lines.join(`
6190
+
6191
+ `)}`
6192
+ }]
6193
+ };
6194
+ } catch (e) {
6195
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
6196
+ }
6197
+ });
6147
6198
  server.tool("memory_list", "List memories. Default: compact lines. full=true for complete JSON objects.", {
6148
6199
  scope: exports_external.enum(["global", "shared", "private"]).optional(),
6149
6200
  category: exports_external.enum(["preference", "fact", "knowledge", "history"]).optional(),
@@ -6357,6 +6408,49 @@ server.tool("memory_stats", "Get aggregate statistics about stored memories", {}
6357
6408
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6358
6409
  }
6359
6410
  });
6411
+ server.tool("memory_activity", "Get daily memory creation activity over N days.", {
6412
+ days: exports_external.coerce.number().optional(),
6413
+ scope: exports_external.enum(["global", "shared", "private"]).optional(),
6414
+ agent_id: exports_external.string().optional(),
6415
+ project_id: exports_external.string().optional()
6416
+ }, async (args) => {
6417
+ try {
6418
+ const days = Math.min(args.days || 30, 365);
6419
+ const db = getDatabase();
6420
+ const conditions = ["status = 'active'"];
6421
+ const params = [];
6422
+ if (args.scope) {
6423
+ conditions.push("scope = ?");
6424
+ params.push(args.scope);
6425
+ }
6426
+ if (args.agent_id) {
6427
+ conditions.push("agent_id = ?");
6428
+ params.push(args.agent_id);
6429
+ }
6430
+ if (args.project_id) {
6431
+ conditions.push("project_id = ?");
6432
+ params.push(args.project_id);
6433
+ }
6434
+ const where = conditions.slice(1).map((c) => `AND ${c}`).join(" ");
6435
+ const rows = db.query(`
6436
+ SELECT date(created_at) AS date, COUNT(*) AS memories_created
6437
+ FROM memories
6438
+ WHERE status = 'active' AND date(created_at) >= date('now', '-${days} days') ${where}
6439
+ GROUP BY date(created_at)
6440
+ ORDER BY date ASC
6441
+ `).all(...params);
6442
+ if (rows.length === 0) {
6443
+ return { content: [{ type: "text", text: `No memory activity in last ${days} days.` }] };
6444
+ }
6445
+ const total = rows.reduce((s, r) => s + r.memories_created, 0);
6446
+ const lines = rows.map((r) => `${r.date}: ${r.memories_created} memor${r.memories_created === 1 ? "y" : "ies"}`);
6447
+ return { content: [{ type: "text", text: `Memory activity (last ${days} days \u2014 ${total} total):
6448
+ ${lines.join(`
6449
+ `)}` }] };
6450
+ } catch (e) {
6451
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
6452
+ }
6453
+ });
6360
6454
  server.tool("memory_export", "Export memories as JSON", {
6361
6455
  scope: exports_external.enum(["global", "shared", "private"]).optional(),
6362
6456
  category: exports_external.enum(["preference", "fact", "knowledge", "history"]).optional(),
@@ -7040,6 +7134,14 @@ var FULL_SCHEMAS = {
7040
7134
  },
7041
7135
  example: '{"key":"preferred-language","value":"TypeScript","scope":"global","importance":8,"tags":["language","preference"]}'
7042
7136
  },
7137
+ memory_versions: {
7138
+ description: "Get full version history for a memory \u2014 all past values, scopes, importance scores.",
7139
+ category: "memory",
7140
+ params: {
7141
+ id: { type: "string", description: "Memory ID (partial OK)", required: true }
7142
+ },
7143
+ example: '{"id":"abc12345"}'
7144
+ },
7043
7145
  memory_get: {
7044
7146
  description: "Get a single memory by ID (partial IDs resolved).",
7045
7147
  category: "memory",
@@ -7146,6 +7248,17 @@ var FULL_SCHEMAS = {
7146
7248
  },
7147
7249
  example: '{"query":"typescript","scope":"global","limit":10}'
7148
7250
  },
7251
+ memory_activity: {
7252
+ description: "Get daily memory creation counts over N days (max 365). Like 'git log --stat' for memories.",
7253
+ category: "memory",
7254
+ params: {
7255
+ days: { type: "number", description: "Number of days to look back (default 30)" },
7256
+ scope: { type: "string", description: "Filter by scope", enum: ["global", "shared", "private"] },
7257
+ agent_id: { type: "string", description: "Filter by agent" },
7258
+ project_id: { type: "string", description: "Filter by project" }
7259
+ },
7260
+ example: '{"days":14,"project_id":"proj-uuid"}'
7261
+ },
7149
7262
  memory_stats: {
7150
7263
  description: "Aggregate statistics: total, by scope, by category, pinned, expired counts.",
7151
7264
  category: "memory",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAulCH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAkH9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAkoCH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAkH9C"}
@@ -1456,6 +1456,28 @@ function cleanExpiredMemories(db) {
1456
1456
  }
1457
1457
  return count;
1458
1458
  }
1459
+ function getMemoryVersions(memoryId, db) {
1460
+ const d = db || getDatabase();
1461
+ try {
1462
+ const rows = d.query("SELECT * FROM memory_versions WHERE memory_id = ? ORDER BY version ASC").all(memoryId);
1463
+ return rows.map((row) => ({
1464
+ id: row["id"],
1465
+ memory_id: row["memory_id"],
1466
+ version: row["version"],
1467
+ value: row["value"],
1468
+ importance: row["importance"],
1469
+ scope: row["scope"],
1470
+ category: row["category"],
1471
+ tags: JSON.parse(row["tags"] || "[]"),
1472
+ summary: row["summary"] || null,
1473
+ pinned: !!row["pinned"],
1474
+ status: row["status"],
1475
+ created_at: row["created_at"]
1476
+ }));
1477
+ } catch {
1478
+ return [];
1479
+ }
1480
+ }
1459
1481
 
1460
1482
  // src/lib/search.ts
1461
1483
  function parseMemoryRow2(row) {
@@ -2217,6 +2239,43 @@ addRoute("GET", "/api/memories/stats", (_req) => {
2217
2239
  stats.by_agent[row.agent_id] = row.c;
2218
2240
  return json(stats);
2219
2241
  });
2242
+ addRoute("GET", "/api/activity", (_req, url) => {
2243
+ const q = getSearchParams(url);
2244
+ const days = Math.min(parseInt(q["days"] || "30", 10), 365);
2245
+ const scope = q["scope"];
2246
+ const agentId = q["agent_id"];
2247
+ const projectId = q["project_id"];
2248
+ const db = getDatabase();
2249
+ const conditions = ["status = 'active'"];
2250
+ const params = [];
2251
+ if (scope) {
2252
+ conditions.push("scope = ?");
2253
+ params.push(scope);
2254
+ }
2255
+ if (agentId) {
2256
+ conditions.push("agent_id = ?");
2257
+ params.push(agentId);
2258
+ }
2259
+ if (projectId) {
2260
+ conditions.push("project_id = ?");
2261
+ params.push(projectId);
2262
+ }
2263
+ const where = conditions.map((c) => `AND ${c}`).join(" ");
2264
+ const rows = db.query(`
2265
+ SELECT
2266
+ date(created_at) AS date,
2267
+ COUNT(*) AS memories_created,
2268
+ SUM(CASE WHEN scope = 'global' THEN 1 ELSE 0 END) AS global_count,
2269
+ SUM(CASE WHEN scope = 'shared' THEN 1 ELSE 0 END) AS shared_count,
2270
+ SUM(CASE WHEN scope = 'private' THEN 1 ELSE 0 END) AS private_count,
2271
+ AVG(importance) AS avg_importance
2272
+ FROM memories
2273
+ WHERE date(created_at) >= date('now', '-${days} days') ${where}
2274
+ GROUP BY date(created_at)
2275
+ ORDER BY date ASC
2276
+ `).all(...params);
2277
+ return json({ activity: rows, days, total: rows.reduce((s, r) => s + r.memories_created, 0) });
2278
+ });
2220
2279
  addRoute("POST", "/api/memories/search", async (req) => {
2221
2280
  const body = await readJson(req);
2222
2281
  if (!body || typeof body["query"] !== "string") {
@@ -2441,6 +2500,13 @@ addRoute("PATCH", "/api/memories/:id", async (req, _url, params) => {
2441
2500
  throw e;
2442
2501
  }
2443
2502
  });
2503
+ addRoute("GET", "/api/memories/:id/versions", (_req, _url, params) => {
2504
+ const memory = getMemory(params["id"]);
2505
+ if (!memory)
2506
+ return errorResponse("Memory not found", 404);
2507
+ const versions = getMemoryVersions(memory.id);
2508
+ return json({ versions, count: versions.length, current_version: memory.version });
2509
+ });
2444
2510
  addRoute("DELETE", "/api/memories/:id", (_req, _url, params) => {
2445
2511
  const deleted = deleteMemory(params["id"]);
2446
2512
  if (!deleted) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/mementos",
3
- "version": "0.4.17",
3
+ "version": "0.4.20",
4
4
  "description": "Universal memory system for AI agents - CLI + MCP server + library API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",