shabti 2.2.0 → 2.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shabti",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Agent Memory OS — semantic memory for AI agents",
5
5
  "type": "module",
6
6
  "main": "native.cjs",
@@ -9,6 +9,7 @@ export function registerStore(program) {
9
9
  .option("-n, --namespace <ns>", "Namespace for the entry")
10
10
  .option("-s, --session <id>", "Session ID")
11
11
  .option("-t, --tags <tags>", "Comma-separated tags")
12
+ .option("--ttl <seconds>", "Time-to-live in seconds (auto-expires after this duration)")
12
13
  .action(async (content, opts) => {
13
14
  try {
14
15
  const engine = createEngine();
@@ -16,6 +17,7 @@ export function registerStore(program) {
16
17
  if (opts.namespace) options.namespace = opts.namespace;
17
18
  if (opts.session) options.sessionId = opts.session;
18
19
  if (opts.tags) options.tags = opts.tags.split(",").map((t) => t.trim());
20
+ if (opts.ttl) options.ttlSeconds = parseInt(opts.ttl, 10);
19
21
 
20
22
  // Model versioning check
21
23
  const currentModelId = engine.modelId();
package/src/index.js CHANGED
@@ -79,6 +79,23 @@ function buildProgram() {
79
79
  registerStatus(program);
80
80
  registerStore(program);
81
81
 
82
+ program
83
+ .command("gc")
84
+ .description("Garbage collect expired memory entries")
85
+ .action(async () => {
86
+ const { createEngine } = await import("./core/engine.js");
87
+ const { success, error: showError } = await import("./utils/style.js");
88
+ try {
89
+ const engine = createEngine();
90
+ const removed = await engine.gc();
91
+ success(`GC complete: ${removed} expired entries removed`);
92
+ await engine.shutdown();
93
+ } catch (err) {
94
+ showError(err.message);
95
+ process.exitCode = 1;
96
+ }
97
+ });
98
+
82
99
  program
83
100
  .command("mcp-config")
84
101
  .description("Print MCP server configuration JSON for Claude Code / Cursor")
package/src/mcp/server.js CHANGED
@@ -24,6 +24,10 @@ const TOOLS = [
24
24
  items: { type: "string" },
25
25
  description: "Tags to associate with the memory",
26
26
  },
27
+ ttl: {
28
+ type: "integer",
29
+ description: "Time-to-live in seconds (entry auto-expires after this duration)",
30
+ },
27
31
  },
28
32
  required: ["content"],
29
33
  },
@@ -69,6 +73,14 @@ const TOOLS = [
69
73
  },
70
74
  },
71
75
  },
76
+ {
77
+ name: "memory_gc",
78
+ description: "Garbage collect expired memory entries (removes entries past their TTL)",
79
+ inputSchema: {
80
+ type: "object",
81
+ properties: {},
82
+ },
83
+ },
72
84
  {
73
85
  name: "memory_status",
74
86
  description: "Get the current status of the memory engine",
@@ -191,6 +203,7 @@ async function handleToolsCall(id, params) {
191
203
  const opts = {};
192
204
  if (args.namespace) opts.namespace = args.namespace;
193
205
  if (args.tags) opts.tags = args.tags;
206
+ if (args.ttl) opts.ttlSeconds = args.ttl;
194
207
  const result = await eng.store(content, opts);
195
208
  return respond(id, {
196
209
  content: [
@@ -293,6 +306,25 @@ async function handleToolsCall(id, params) {
293
306
  }
294
307
  }
295
308
 
309
+ if (name === "memory_gc") {
310
+ if (!eng) {
311
+ return respondError(id, -32603, "Engine not available");
312
+ }
313
+ try {
314
+ const removed = await eng.gc();
315
+ return respond(id, {
316
+ content: [
317
+ {
318
+ type: "text",
319
+ text: JSON.stringify({ removed }, null, 2),
320
+ },
321
+ ],
322
+ });
323
+ } catch (err) {
324
+ return respondError(id, -32603, err.message);
325
+ }
326
+ }
327
+
296
328
  respondError(id, -32601, `Unknown tool: ${name}`);
297
329
  }
298
330
 
@@ -9,6 +9,7 @@ const COMMANDS = {
9
9
  "/history": "Show conversation history",
10
10
  "/remember": "Store a memory (e.g. /remember Tokyo is the capital of Japan)",
11
11
  "/recall": "Search memories (e.g. /recall capital of Japan)",
12
+ "/gc": "Garbage collect expired memory entries",
12
13
  };
13
14
 
14
15
  /**
@@ -75,6 +76,9 @@ export function handleSlashCommand(cmd, args, session, rl, engine = null) {
75
76
  case "/recall":
76
77
  return handleRecall(args, engine);
77
78
 
79
+ case "/gc":
80
+ return handleGc(engine);
81
+
78
82
  default:
79
83
  return false;
80
84
  }
@@ -136,3 +140,20 @@ async function handleRecall(query, engine) {
136
140
  console.log();
137
141
  return true;
138
142
  }
143
+
144
+ async function handleGc(engine) {
145
+ if (!engine) {
146
+ console.log();
147
+ warn("Memory engine not available. Start Qdrant to enable memory features.");
148
+ console.log();
149
+ return true;
150
+ }
151
+ try {
152
+ const removed = await engine.gc();
153
+ success(`GC complete: ${removed} expired entries removed`);
154
+ } catch (err) {
155
+ error(`Failed to run GC: ${err.message}`);
156
+ }
157
+ console.log();
158
+ return true;
159
+ }