@hasna/mementos 0.4.3 → 0.4.5

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/cli/index.js CHANGED
@@ -2595,6 +2595,9 @@ function getProject(idOrPath, db) {
2595
2595
  if (row)
2596
2596
  return parseProjectRow(row);
2597
2597
  row = d.query("SELECT * FROM projects WHERE path = ?").get(idOrPath);
2598
+ if (row)
2599
+ return parseProjectRow(row);
2600
+ row = d.query("SELECT * FROM projects WHERE LOWER(name) = ?").get(idOrPath.toLowerCase());
2598
2601
  if (row)
2599
2602
  return parseProjectRow(row);
2600
2603
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/db/projects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAejD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,EACrB,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAyBT;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,GAAG,IAAI,CAchB;AAED,wBAAgB,YAAY,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,EAAE,CAMrD"}
1
+ {"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/db/projects.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAejD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,EACrB,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAyBT;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,GAAG,IAAI,CAoBhB;AAED,wBAAgB,YAAY,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,EAAE,CAMrD"}
package/dist/index.js CHANGED
@@ -524,6 +524,9 @@ function getProject(idOrPath, db) {
524
524
  if (row)
525
525
  return parseProjectRow(row);
526
526
  row = d.query("SELECT * FROM projects WHERE path = ?").get(idOrPath);
527
+ if (row)
528
+ return parseProjectRow(row);
529
+ row = d.query("SELECT * FROM projects WHERE LOWER(name) = ?").get(idOrPath.toLowerCase());
527
530
  if (row)
528
531
  return parseProjectRow(row);
529
532
  return null;
package/dist/mcp/index.js CHANGED
@@ -4502,6 +4502,9 @@ function getProject(idOrPath, db) {
4502
4502
  if (row)
4503
4503
  return parseProjectRow(row);
4504
4504
  row = d.query("SELECT * FROM projects WHERE path = ?").get(idOrPath);
4505
+ if (row)
4506
+ return parseProjectRow(row);
4507
+ row = d.query("SELECT * FROM projects WHERE LOWER(name) = ?").get(idOrPath.toLowerCase());
4505
4508
  if (row)
4506
4509
  return parseProjectRow(row);
4507
4510
  return null;
@@ -6126,6 +6129,21 @@ ${formatMemory(best.memory)}`
6126
6129
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6127
6130
  }
6128
6131
  });
6132
+ server.tool("memory_get", "Get a single memory by ID.", {
6133
+ id: exports_external.string()
6134
+ }, async (args) => {
6135
+ try {
6136
+ const id = resolveId(args.id);
6137
+ const memory = getMemory(id);
6138
+ if (!memory) {
6139
+ return { content: [{ type: "text", text: `Memory not found: ${args.id}` }] };
6140
+ }
6141
+ touchMemory(memory.id);
6142
+ return { content: [{ type: "text", text: formatMemory(memory) }] };
6143
+ } catch (e) {
6144
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
6145
+ }
6146
+ });
6129
6147
  server.tool("memory_list", "List memories. Default: compact lines. full=true for complete JSON objects.", {
6130
6148
  scope: exports_external.enum(["global", "shared", "private"]).optional(),
6131
6149
  category: exports_external.enum(["preference", "fact", "knowledge", "history"]).optional(),
@@ -6347,6 +6365,7 @@ server.tool("memory_inject", "Get memory context for system prompt injection. Se
6347
6365
  max_tokens: exports_external.coerce.number().optional(),
6348
6366
  categories: exports_external.array(exports_external.enum(["preference", "fact", "knowledge", "history"])).optional(),
6349
6367
  min_importance: exports_external.coerce.number().optional(),
6368
+ format: exports_external.enum(["xml", "markdown", "compact", "json"]).optional(),
6350
6369
  raw: exports_external.boolean().optional()
6351
6370
  }, async (args) => {
6352
6371
  try {
@@ -6400,8 +6419,16 @@ server.tool("memory_inject", "Get memory context for system prompt injection. Se
6400
6419
  const charBudget = maxTokens * 4;
6401
6420
  const lines = [];
6402
6421
  let totalChars = 0;
6422
+ const fmt = args.format ?? (args.raw ? "compact" : "xml");
6403
6423
  for (const m of unique) {
6404
- const line = `- [${m.scope}/${m.category}] ${m.key}: ${m.value}`;
6424
+ let line;
6425
+ if (fmt === "compact") {
6426
+ line = `${m.key}: ${m.value}`;
6427
+ } else if (fmt === "json") {
6428
+ line = JSON.stringify({ key: m.key, value: m.value, scope: m.scope, category: m.category, importance: m.importance });
6429
+ } else {
6430
+ line = `- [${m.scope}/${m.category}] ${m.key}: ${m.value}`;
6431
+ }
6405
6432
  if (totalChars + line.length > charBudget)
6406
6433
  break;
6407
6434
  lines.push(line);
@@ -6411,11 +6438,23 @@ server.tool("memory_inject", "Get memory context for system prompt injection. Se
6411
6438
  if (lines.length === 0) {
6412
6439
  return { content: [{ type: "text", text: "No relevant memories found for injection." }] };
6413
6440
  }
6414
- const context = args.raw ? lines.join(`
6415
- `) : `<agent-memories>
6441
+ let context;
6442
+ if (fmt === "compact") {
6443
+ context = lines.join(`
6444
+ `);
6445
+ } else if (fmt === "json") {
6446
+ context = `[${lines.join(",")}]`;
6447
+ } else if (fmt === "markdown") {
6448
+ context = `## Agent Memories
6449
+
6450
+ ${lines.join(`
6451
+ `)}`;
6452
+ } else {
6453
+ context = `<agent-memories>
6416
6454
  ${lines.join(`
6417
6455
  `)}
6418
6456
  </agent-memories>`;
6457
+ }
6419
6458
  return { content: [{ type: "text", text: context }] };
6420
6459
  } catch (e) {
6421
6460
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
@@ -6563,6 +6602,29 @@ ${lines.join(`
6563
6602
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
6564
6603
  }
6565
6604
  });
6605
+ server.tool("get_project", "Get a project by ID, path, or name.", {
6606
+ id: exports_external.string()
6607
+ }, async (args) => {
6608
+ try {
6609
+ const project = getProject(args.id);
6610
+ if (!project) {
6611
+ return { content: [{ type: "text", text: `Project not found: ${args.id}` }] };
6612
+ }
6613
+ return {
6614
+ content: [{
6615
+ type: "text",
6616
+ text: `Project:
6617
+ ID: ${project.id}
6618
+ Name: ${project.name}
6619
+ Path: ${project.path}
6620
+ Description: ${project.description || "-"}
6621
+ Created: ${project.created_at}`
6622
+ }]
6623
+ };
6624
+ } catch (e) {
6625
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
6626
+ }
6627
+ });
6566
6628
  server.tool("bulk_forget", "Delete multiple memories by IDs", {
6567
6629
  ids: exports_external.array(exports_external.string())
6568
6630
  }, async (args) => {
@@ -6887,6 +6949,14 @@ var FULL_SCHEMAS = {
6887
6949
  },
6888
6950
  example: '{"key":"preferred-language","value":"TypeScript","scope":"global","importance":8,"tags":["language","preference"]}'
6889
6951
  },
6952
+ memory_get: {
6953
+ description: "Get a single memory by ID (partial IDs resolved).",
6954
+ category: "memory",
6955
+ params: {
6956
+ id: { type: "string", description: "Memory ID (full or partial)", required: true }
6957
+ },
6958
+ example: '{"id":"abc12345"}'
6959
+ },
6890
6960
  memory_recall: {
6891
6961
  description: "Recall a memory by exact key. Falls back to fuzzy search if no exact match.",
6892
6962
  category: "memory",
@@ -7000,9 +7070,10 @@ var FULL_SCHEMAS = {
7000
7070
  max_tokens: { type: "number", description: "Approximate token budget (default 500)" },
7001
7071
  categories: { type: "array", description: "Categories to include (default: preference, fact, knowledge)", items: { type: "string", enum: ["preference", "fact", "knowledge", "history"] } },
7002
7072
  min_importance: { type: "number", description: "Minimum importance (default 3)" },
7003
- raw: { type: "boolean", description: "true=plain lines only, false=wrapped in <agent-memories> tags" }
7073
+ format: { type: "string", description: "Output format: xml (default, <agent-memories>), compact (key: value, ~60% smaller), markdown, json", enum: ["xml", "compact", "markdown", "json"] },
7074
+ raw: { type: "boolean", description: "Deprecated: use format=compact instead. true=plain lines only" }
7004
7075
  },
7005
- example: '{"project_id":"proj-uuid","max_tokens":300,"min_importance":5}'
7076
+ example: '{"project_id":"proj-uuid","max_tokens":300,"min_importance":5,"format":"compact"}'
7006
7077
  },
7007
7078
  memory_context: {
7008
7079
  description: "Get active memories for the current context (agent/project/scope).",
@@ -7077,6 +7148,14 @@ var FULL_SCHEMAS = {
7077
7148
  params: {},
7078
7149
  example: "{}"
7079
7150
  },
7151
+ get_project: {
7152
+ description: "Get a project by ID, path, or name.",
7153
+ category: "project",
7154
+ params: {
7155
+ id: { type: "string", description: "Project ID, path, or name", required: true }
7156
+ },
7157
+ example: '{"id":"open-mementos"}'
7158
+ },
7080
7159
  bulk_forget: {
7081
7160
  description: "Delete multiple memories by IDs in one call.",
7082
7161
  category: "bulk",
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AA45BH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAoG9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAy+BH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAoG9C"}
@@ -495,6 +495,9 @@ function getProject(idOrPath, db) {
495
495
  if (row)
496
496
  return parseProjectRow(row);
497
497
  row = d.query("SELECT * FROM projects WHERE path = ?").get(idOrPath);
498
+ if (row)
499
+ return parseProjectRow(row);
500
+ row = d.query("SELECT * FROM projects WHERE LOWER(name) = ?").get(idOrPath.toLowerCase());
498
501
  if (row)
499
502
  return parseProjectRow(row);
500
503
  return null;
@@ -2176,6 +2179,45 @@ addRoute("POST", "/api/memories/import", async (req) => {
2176
2179
  }
2177
2180
  return json({ imported, errors, total: memoriesArr.length }, 201);
2178
2181
  });
2182
+ addRoute("POST", "/api/memories/bulk-forget", async (req) => {
2183
+ const body = await readJson(req);
2184
+ if (!body || !Array.isArray(body["ids"])) {
2185
+ return errorResponse("Missing required field: ids (array)", 400);
2186
+ }
2187
+ const ids = body["ids"];
2188
+ let deleted = 0;
2189
+ for (const id of ids) {
2190
+ try {
2191
+ if (deleteMemory(id))
2192
+ deleted++;
2193
+ } catch {}
2194
+ }
2195
+ return json({ deleted, total: ids.length });
2196
+ });
2197
+ addRoute("POST", "/api/memories/bulk-update", async (req) => {
2198
+ const body = await readJson(req);
2199
+ if (!body || !Array.isArray(body["ids"])) {
2200
+ return errorResponse("Missing required fields: ids (array)", 400);
2201
+ }
2202
+ const ids = body["ids"];
2203
+ const { ids: _ids, ...fields } = body;
2204
+ let updated = 0;
2205
+ const errors = [];
2206
+ for (const id of ids) {
2207
+ try {
2208
+ const memory = getMemory(id);
2209
+ if (memory) {
2210
+ updateMemory(id, { ...fields, version: memory.version });
2211
+ updated++;
2212
+ } else {
2213
+ errors.push(`Memory not found: ${id}`);
2214
+ }
2215
+ } catch (e) {
2216
+ errors.push(`Failed ${id}: ${e instanceof Error ? e.message : String(e)}`);
2217
+ }
2218
+ }
2219
+ return json({ updated, errors, total: ids.length });
2220
+ });
2179
2221
  addRoute("POST", "/api/memories/clean", () => {
2180
2222
  const cleaned = cleanExpiredMemories();
2181
2223
  return json({ cleaned });
@@ -2297,6 +2339,19 @@ addRoute("POST", "/api/projects", async (req) => {
2297
2339
  const project = registerProject(body["name"], body["path"], body["description"], body["memory_prefix"]);
2298
2340
  return json(project, 201);
2299
2341
  });
2342
+ addRoute("GET", "/api/projects/:id", (_req, _url, params) => {
2343
+ const project = getProject(params["id"]);
2344
+ if (!project)
2345
+ return errorResponse("Project not found", 404);
2346
+ return json(project);
2347
+ });
2348
+ addRoute("GET", "/api/projects/:id/agents", (_req, _url, params) => {
2349
+ const project = getProject(params["id"]);
2350
+ if (!project)
2351
+ return errorResponse("Project not found", 404);
2352
+ const agents = listAgentsByProject(project.id);
2353
+ return json({ agents, count: agents.length });
2354
+ });
2300
2355
  addRoute("GET", "/api/inject", (_req, url) => {
2301
2356
  const q = getSearchParams(url);
2302
2357
  const maxTokens = q["max_tokens"] ? parseInt(q["max_tokens"], 10) : 500;
@@ -2353,8 +2408,16 @@ addRoute("GET", "/api/inject", (_req, url) => {
2353
2408
  const charBudget = maxTokens * 4;
2354
2409
  const lines = [];
2355
2410
  let totalChars = 0;
2411
+ const format = q["format"] || "xml";
2356
2412
  for (const m of unique) {
2357
- const line = `- [${m.scope}/${m.category}] ${m.key}: ${m.value}`;
2413
+ let line;
2414
+ if (format === "compact") {
2415
+ line = `${m.key}: ${m.value}`;
2416
+ } else if (format === "json") {
2417
+ line = JSON.stringify({ key: m.key, value: m.value, scope: m.scope, category: m.category, importance: m.importance });
2418
+ } else {
2419
+ line = `- [${m.scope}/${m.category}] ${m.key}: ${m.value}`;
2420
+ }
2358
2421
  if (totalChars + line.length > charBudget)
2359
2422
  break;
2360
2423
  lines.push(line);
@@ -2364,10 +2427,23 @@ addRoute("GET", "/api/inject", (_req, url) => {
2364
2427
  if (lines.length === 0) {
2365
2428
  return json({ context: "", memories_count: 0 });
2366
2429
  }
2367
- const context = `<agent-memories>
2430
+ let context;
2431
+ if (format === "compact") {
2432
+ context = lines.join(`
2433
+ `);
2434
+ } else if (format === "json") {
2435
+ context = `[${lines.join(",")}]`;
2436
+ } else if (format === "markdown") {
2437
+ context = `## Agent Memories
2438
+
2439
+ ${lines.join(`
2440
+ `)}`;
2441
+ } else {
2442
+ context = `<agent-memories>
2368
2443
  ${lines.join(`
2369
2444
  `)}
2370
2445
  </agent-memories>`;
2446
+ }
2371
2447
  return json({ context, memories_count: lines.length });
2372
2448
  });
2373
2449
  addRoute("GET", "/api/entities", (_req, url) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/mementos",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "Universal memory system for AI agents - CLI + MCP server + library API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",