memoclaw 1.6.0 → 1.7.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.
Files changed (2) hide show
  1. package/dist/cli.mjs +153 -4
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -5217,7 +5217,10 @@ var BOOLEAN_FLAGS = new Set([
5217
5217
  "quiet",
5218
5218
  "dryRun",
5219
5219
  "verbose",
5220
- "noColor"
5220
+ "noColor",
5221
+ "force",
5222
+ "count",
5223
+ "wide"
5221
5224
  ]);
5222
5225
  var SHORT_FLAGS = {
5223
5226
  "-h": "help",
@@ -5325,7 +5328,7 @@ function parseArgs(args) {
5325
5328
  }
5326
5329
 
5327
5330
  // src/cli.ts
5328
- var VERSION = "1.6.0";
5331
+ var VERSION = "1.7.0";
5329
5332
  var API_URL = process.env.MEMOCLAW_URL || "https://api.memoclaw.com";
5330
5333
  var PRIVATE_KEY = process.env.MEMOCLAW_PRIVATE_KEY;
5331
5334
  var NO_COLOR = !!process.env.NO_COLOR || !process.stdout.isTTY;
@@ -5452,7 +5455,21 @@ async function request(method, path, body = null) {
5452
5455
  options.body = JSON.stringify(body);
5453
5456
  const walletAuth = await getWalletAuthHeader();
5454
5457
  headers["x-wallet-auth"] = walletAuth;
5455
- let res = await fetch(url, { ...options, headers });
5458
+ let res;
5459
+ try {
5460
+ res = await fetch(url, { ...options, headers });
5461
+ } catch (e) {
5462
+ if (e.code === "ECONNREFUSED" || e.cause?.code === "ECONNREFUSED") {
5463
+ throw new Error(`Cannot connect to ${API_URL} — is the server running?`);
5464
+ }
5465
+ if (e.code === "ENOTFOUND" || e.cause?.code === "ENOTFOUND") {
5466
+ throw new Error(`DNS lookup failed for ${API_URL} — check your internet connection`);
5467
+ }
5468
+ if (e.name === "AbortError") {
5469
+ throw new Error(`Request timed out`);
5470
+ }
5471
+ throw new Error(`Network error: ${e.message}`);
5472
+ }
5456
5473
  const freeTierRemaining = res.headers.get("x-free-tier-remaining");
5457
5474
  if (freeTierRemaining !== null && process.env.DEBUG) {
5458
5475
  console.error(`${c.dim}Free tier remaining: ${freeTierRemaining}${c.reset}`);
@@ -5932,6 +5949,93 @@ async function cmdStats(opts) {
5932
5949
  }
5933
5950
  }
5934
5951
  }
5952
+ async function cmdGraph(id, opts) {
5953
+ const result = await request("GET", `/v1/memories/${id}`);
5954
+ const mem = result.memory || result;
5955
+ const relResult = await request("GET", `/v1/memories/${id}/relations`);
5956
+ const relations = relResult.relations || [];
5957
+ if (outputJson) {
5958
+ out({ memory: mem, relations });
5959
+ return;
5960
+ }
5961
+ const label = (m) => {
5962
+ const text = (m.content || "").slice(0, 40);
5963
+ return text.length < (m.content || "").length ? text + "…" : text;
5964
+ };
5965
+ const shortId = (s) => s?.slice(0, 8) || "?";
5966
+ console.log();
5967
+ console.log(` ${c.bold}${c.cyan}[${shortId(mem.id)}]${c.reset} ${label(mem)}`);
5968
+ if (relations.length === 0) {
5969
+ console.log(` ${c.dim} └── (no relations)${c.reset}`);
5970
+ } else {
5971
+ for (let i = 0;i < relations.length; i++) {
5972
+ const r = relations[i];
5973
+ const isLast = i === relations.length - 1;
5974
+ const branch = isLast ? "└" : "├";
5975
+ const typeColor = {
5976
+ contradicts: c.red,
5977
+ supersedes: c.yellow,
5978
+ supports: c.green,
5979
+ derived_from: c.magenta,
5980
+ related_to: c.blue
5981
+ }[r.relation_type] || c.dim;
5982
+ console.log(` ${c.dim} ${branch}──${c.reset} ${typeColor}${r.relation_type}${c.reset} ${c.dim}→${c.reset} ${c.cyan}[${shortId(r.target_id)}]${c.reset}`);
5983
+ }
5984
+ }
5985
+ console.log();
5986
+ }
5987
+ async function cmdPurge(opts) {
5988
+ if (!opts.force) {
5989
+ if (!process.stdin.isTTY) {
5990
+ throw new Error("Use --force to confirm purge in non-interactive mode");
5991
+ }
5992
+ const readline = await import("readline");
5993
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
5994
+ const answer = await new Promise((r) => rl.question(`${c.red}⚠ Delete ALL memories${opts.namespace ? ` in namespace "${opts.namespace}"` : ""}? Type "yes" to confirm: ${c.reset}`, r));
5995
+ rl.close();
5996
+ if (answer.trim().toLowerCase() !== "yes") {
5997
+ console.log(`${c.dim}Aborted.${c.reset}`);
5998
+ return;
5999
+ }
6000
+ }
6001
+ const params = new URLSearchParams({ limit: "100" });
6002
+ if (opts.namespace)
6003
+ params.set("namespace", opts.namespace);
6004
+ let deleted = 0;
6005
+ while (true) {
6006
+ params.set("offset", "0");
6007
+ const result = await request("GET", `/v1/memories?${params}`);
6008
+ const memories = result.memories || result.data || [];
6009
+ if (memories.length === 0)
6010
+ break;
6011
+ for (const mem of memories) {
6012
+ await request("DELETE", `/v1/memories/${mem.id}`);
6013
+ deleted++;
6014
+ if (!outputQuiet)
6015
+ process.stderr.write(`\r ${progressBar(deleted, result.total || deleted)}`);
6016
+ }
6017
+ }
6018
+ if (!outputQuiet)
6019
+ process.stderr.write(`
6020
+ `);
6021
+ if (outputJson) {
6022
+ out({ deleted });
6023
+ } else {
6024
+ success(`Purged ${deleted} memories`);
6025
+ }
6026
+ }
6027
+ async function cmdCount(opts) {
6028
+ const params = new URLSearchParams({ limit: "1" });
6029
+ if (opts.namespace)
6030
+ params.set("namespace", opts.namespace);
6031
+ const result = await request("GET", `/v1/memories?${params}`);
6032
+ const total = result.total ?? "?";
6033
+ if (outputJson) {
6034
+ out({ count: total, namespace: opts.namespace || null });
6035
+ } else {
6036
+ console.log(String(total));
6037
+ }
6038
+ }
5935
6039
  async function cmdCompletions(shell) {
5936
6040
  const commands = [
5937
6041
  "store",
@@ -5951,7 +6055,10 @@ async function cmdCompletions(shell) {
5951
6055
  "stats",
5952
6056
  "browse",
5953
6057
  "completions",
5954
- "config"
6058
+ "config",
6059
+ "graph",
6060
+ "purge",
6061
+ "count"
5955
6062
  ];
5956
6063
  if (shell === "bash") {
5957
6064
  console.log(`# Add to ~/.bashrc:
@@ -6233,6 +6340,31 @@ Options:
6233
6340
  --namespace <name> Filter by namespace
6234
6341
 
6235
6342
  Commands inside browser: list, get, recall, store, delete, stats, next, prev`,
6343
+ graph: `${c.bold}memoclaw graph${c.reset} <id>
6344
+
6345
+ Show an ASCII tree of a memory and its relations.
6346
+
6347
+ Options:
6348
+ --json Output as JSON`,
6349
+ purge: `${c.bold}memoclaw purge${c.reset} [options]
6350
+
6351
+ Delete ALL memories. Requires confirmation or --force.
6352
+
6353
+ ${c.dim}memoclaw purge --force${c.reset}
6354
+ ${c.dim}memoclaw purge --namespace old-project --force${c.reset}
6355
+
6356
+ Options:
6357
+ --force Skip confirmation prompt
6358
+ --namespace <name> Only purge memories in namespace`,
6359
+ count: `${c.bold}memoclaw count${c.reset} [options]
6360
+
6361
+ Print the total number of memories (pipe-friendly).
6362
+
6363
+ ${c.dim}memoclaw count${c.reset}
6364
+ ${c.dim}memoclaw count --namespace project1${c.reset}
6365
+
6366
+ Options:
6367
+ --namespace <name> Count only in namespace`,
6236
6368
  completions: `${c.bold}memoclaw completions${c.reset} <bash|zsh|fish>
6237
6369
 
6238
6370
  Generate shell completion scripts.
@@ -6272,6 +6404,9 @@ ${c.bold}Commands:${c.reset}
6272
6404
  ${c.cyan}completions${c.reset} <shell> Generate shell completions
6273
6405
  ${c.cyan}browse${c.reset} Interactive memory browser (REPL)
6274
6406
  ${c.cyan}config${c.reset} [show|check] Show or validate configuration
6407
+ ${c.cyan}graph${c.reset} <id> ASCII visualization of memory relations
6408
+ ${c.cyan}purge${c.reset} Delete ALL memories (requires --force or confirm)
6409
+ ${c.cyan}count${c.reset} Quick memory count
6275
6410
 
6276
6411
  ${c.bold}Global Options:${c.reset}
6277
6412
  -h, --help Show help (use with command for details)
@@ -6282,6 +6417,8 @@ ${c.bold}Global Options:${c.reset}
6282
6417
  -l, --limit <n> Limit results
6283
6418
  -t, --tags <a,b> Comma-separated tags
6284
6419
  --raw Raw output (content only, for piping)
6420
+ --force Skip confirmation prompts
6421
+ --timeout <seconds> Request timeout (default: 30)
6285
6422
 
6286
6423
  ${c.bold}Environment:${c.reset}
6287
6424
  MEMOCLAW_PRIVATE_KEY Wallet private key for auth + payments
@@ -6317,6 +6454,7 @@ if (args.help) {
6317
6454
  printHelp(cmd);
6318
6455
  process.exit(0);
6319
6456
  }
6457
+ var TIMEOUT_MS = args.timeout ? parseInt(args.timeout) * 1000 : 30000;
6320
6458
  try {
6321
6459
  switch (cmd) {
6322
6460
  case "store": {
@@ -6405,6 +6543,17 @@ try {
6405
6543
  case "config":
6406
6544
  await cmdConfig(rest[0], rest.slice(1));
6407
6545
  break;
6546
+ case "graph":
6547
+ if (!rest[0])
6548
+ throw new Error("Memory ID required");
6549
+ await cmdGraph(rest[0], args);
6550
+ break;
6551
+ case "purge":
6552
+ await cmdPurge(args);
6553
+ break;
6554
+ case "count":
6555
+ await cmdCount(args);
6556
+ break;
6408
6557
  case "help":
6409
6558
  printHelp(rest[0]);
6410
6559
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memoclaw",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "MemoClaw CLI - Memory-as-a-Service for AI agents. 1000 free calls, then x402 micropayments.",
5
5
  "type": "module",
6
6
  "bin": {