memoclaw 1.5.0 → 1.6.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 +381 -62
  2. package/package.json +2 -1
package/dist/cli.mjs CHANGED
@@ -5208,8 +5208,124 @@ function privateKeyToAccount(privateKey, options = {}) {
5208
5208
  source: "privateKey"
5209
5209
  };
5210
5210
  }
5211
+ // src/args.ts
5212
+ var BOOLEAN_FLAGS = new Set([
5213
+ "help",
5214
+ "version",
5215
+ "raw",
5216
+ "json",
5217
+ "quiet",
5218
+ "dryRun",
5219
+ "verbose",
5220
+ "noColor"
5221
+ ]);
5222
+ var SHORT_FLAGS = {
5223
+ "-h": "help",
5224
+ "-v": "version",
5225
+ "-j": "json",
5226
+ "-q": "quiet",
5227
+ "-n": "namespace",
5228
+ "-l": "limit",
5229
+ "-t": "tags",
5230
+ "-o": "output"
5231
+ };
5232
+ function parseArgs(args) {
5233
+ const result = { _: [] };
5234
+ let i = 0;
5235
+ while (i < args.length) {
5236
+ const arg = args[i];
5237
+ if (arg[0] === "-" && arg[1] !== "-" && arg.length >= 2) {
5238
+ if (arg.length === 2 && SHORT_FLAGS[arg]) {
5239
+ const key = SHORT_FLAGS[arg];
5240
+ if (BOOLEAN_FLAGS.has(key)) {
5241
+ result[key] = true;
5242
+ i++;
5243
+ } else {
5244
+ const next = args[i + 1];
5245
+ if (next !== undefined && !next.startsWith("-")) {
5246
+ result[key] = next;
5247
+ i += 2;
5248
+ } else {
5249
+ result[key] = true;
5250
+ i++;
5251
+ }
5252
+ }
5253
+ } else if (arg.length > 2 && !SHORT_FLAGS[arg]) {
5254
+ const chars = arg.slice(1).split("");
5255
+ let allValid = true;
5256
+ for (const ch of chars) {
5257
+ const flag = `-${ch}`;
5258
+ if (!SHORT_FLAGS[flag]) {
5259
+ allValid = false;
5260
+ break;
5261
+ }
5262
+ }
5263
+ if (allValid) {
5264
+ for (let ci = 0;ci < chars.length; ci++) {
5265
+ const flag = `-${chars[ci]}`;
5266
+ const key = SHORT_FLAGS[flag];
5267
+ if (BOOLEAN_FLAGS.has(key)) {
5268
+ result[key] = true;
5269
+ } else if (ci === chars.length - 1) {
5270
+ const next = args[i + 1];
5271
+ if (next !== undefined && !next.startsWith("-")) {
5272
+ result[key] = next;
5273
+ i++;
5274
+ } else {
5275
+ result[key] = true;
5276
+ }
5277
+ } else {
5278
+ result[key] = true;
5279
+ }
5280
+ }
5281
+ i++;
5282
+ } else {
5283
+ result._.push(arg);
5284
+ i++;
5285
+ }
5286
+ } else {
5287
+ result._.push(arg);
5288
+ i++;
5289
+ }
5290
+ } else if (arg === "--") {
5291
+ result._.push(...args.slice(i + 1));
5292
+ break;
5293
+ } else if (arg.startsWith("--")) {
5294
+ const eqIdx = arg.indexOf("=");
5295
+ let key;
5296
+ let inlineValue;
5297
+ if (eqIdx !== -1) {
5298
+ key = arg.slice(2, eqIdx).replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
5299
+ inlineValue = arg.slice(eqIdx + 1);
5300
+ } else {
5301
+ key = arg.slice(2).replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
5302
+ }
5303
+ if (inlineValue !== undefined) {
5304
+ result[key] = inlineValue;
5305
+ i++;
5306
+ } else if (BOOLEAN_FLAGS.has(key)) {
5307
+ result[key] = true;
5308
+ i++;
5309
+ } else {
5310
+ const next = args[i + 1];
5311
+ if (next !== undefined && (!next.startsWith("--") || /^--?\d/.test(next))) {
5312
+ result[key] = next;
5313
+ i += 2;
5314
+ } else {
5315
+ result[key] = true;
5316
+ i++;
5317
+ }
5318
+ }
5319
+ } else {
5320
+ result._.push(arg);
5321
+ i++;
5322
+ }
5323
+ }
5324
+ return result;
5325
+ }
5326
+
5211
5327
  // src/cli.ts
5212
- var VERSION = "1.5.0";
5328
+ var VERSION = "1.6.0";
5213
5329
  var API_URL = process.env.MEMOCLAW_URL || "https://api.memoclaw.com";
5214
5330
  var PRIVATE_KEY = process.env.MEMOCLAW_PRIVATE_KEY;
5215
5331
  var NO_COLOR = !!process.env.NO_COLOR || !process.stdout.isTTY;
@@ -5260,57 +5376,6 @@ async function getWalletAuthHeader() {
5260
5376
  const signature = await account.signMessage({ message });
5261
5377
  return `${account.address}:${timestamp}:${signature}`;
5262
5378
  }
5263
- var BOOLEAN_FLAGS = new Set([
5264
- "help",
5265
- "version",
5266
- "raw",
5267
- "json",
5268
- "quiet",
5269
- "dryRun",
5270
- "verbose"
5271
- ]);
5272
- function parseArgs(args) {
5273
- const result = { _: [] };
5274
- let i = 0;
5275
- while (i < args.length) {
5276
- const arg = args[i];
5277
- if (arg === "-h" || arg === "--help") {
5278
- result.help = true;
5279
- i++;
5280
- } else if (arg === "-v" || arg === "--version") {
5281
- result.version = true;
5282
- i++;
5283
- } else if (arg === "-q" || arg === "--quiet") {
5284
- result.quiet = true;
5285
- i++;
5286
- } else if (arg === "-j" || arg === "--json") {
5287
- result.json = true;
5288
- i++;
5289
- } else if (arg === "--") {
5290
- result._.push(...args.slice(i + 1));
5291
- break;
5292
- } else if (arg.startsWith("--")) {
5293
- const key = arg.slice(2).replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
5294
- if (BOOLEAN_FLAGS.has(key)) {
5295
- result[key] = true;
5296
- i++;
5297
- } else {
5298
- const next = args[i + 1];
5299
- if (next !== undefined && !next.startsWith("--")) {
5300
- result[key] = next;
5301
- i += 2;
5302
- } else {
5303
- result[key] = true;
5304
- i++;
5305
- }
5306
- }
5307
- } else {
5308
- result._.push(arg);
5309
- i++;
5310
- }
5311
- }
5312
- return result;
5313
- }
5314
5379
  async function readStdin() {
5315
5380
  if (process.stdin.isTTY)
5316
5381
  return null;
@@ -5374,6 +5439,11 @@ function table(rows, columns) {
5374
5439
  console.log(line);
5375
5440
  }
5376
5441
  }
5442
+ function progressBar(current, total, width = 30) {
5443
+ const pct = Math.min(current / total, 1);
5444
+ const filled = Math.round(pct * width);
5445
+ return `${c.green}${"█".repeat(filled)}${c.dim}${"░".repeat(width - filled)}${c.reset} ${current}/${total}`;
5446
+ }
5377
5447
  async function request(method, path, body = null) {
5378
5448
  const url = `${API_URL}${path}`;
5379
5449
  const headers = { "Content-Type": "application/json" };
@@ -5426,7 +5496,7 @@ async function request(method, path, body = null) {
5426
5496
  }
5427
5497
  async function cmdStore(content, opts) {
5428
5498
  const body = { content };
5429
- if (opts.importance)
5499
+ if (opts.importance != null && opts.importance !== true)
5430
5500
  body.importance = parseFloat(opts.importance);
5431
5501
  if (opts.tags)
5432
5502
  body.metadata = { tags: opts.tags.split(",").map((t) => t.trim()) };
@@ -5443,9 +5513,9 @@ async function cmdStore(content, opts) {
5443
5513
  }
5444
5514
  async function cmdRecall(query, opts) {
5445
5515
  const body = { query };
5446
- if (opts.limit)
5516
+ if (opts.limit != null && opts.limit !== true)
5447
5517
  body.limit = parseInt(opts.limit);
5448
- if (opts.minSimilarity)
5518
+ if (opts.minSimilarity != null && opts.minSimilarity !== true)
5449
5519
  body.min_similarity = parseFloat(opts.minSimilarity);
5450
5520
  if (opts.namespace)
5451
5521
  body.namespace = opts.namespace;
@@ -5454,6 +5524,11 @@ async function cmdRecall(query, opts) {
5454
5524
  const result = await request("POST", "/v1/recall", body);
5455
5525
  if (outputJson) {
5456
5526
  out(result);
5527
+ } else if (opts.raw) {
5528
+ const memories = result.memories || [];
5529
+ for (const mem of memories) {
5530
+ console.log(mem.content);
5531
+ }
5457
5532
  } else {
5458
5533
  const memories = result.memories || [];
5459
5534
  if (memories.length === 0) {
@@ -5476,9 +5551,9 @@ async function cmdRecall(query, opts) {
5476
5551
  }
5477
5552
  async function cmdList(opts) {
5478
5553
  const params = new URLSearchParams;
5479
- if (opts.limit)
5554
+ if (opts.limit != null && opts.limit !== true)
5480
5555
  params.set("limit", opts.limit);
5481
- if (opts.offset)
5556
+ if (opts.offset != null && opts.offset !== true)
5482
5557
  params.set("offset", opts.offset);
5483
5558
  if (opts.namespace)
5484
5559
  params.set("namespace", opts.namespace);
@@ -5510,6 +5585,30 @@ async function cmdList(opts) {
5510
5585
  }
5511
5586
  }
5512
5587
  }
5588
+ async function cmdGet(id) {
5589
+ const result = await request("GET", `/v1/memories/${id}`);
5590
+ if (outputJson) {
5591
+ out(result);
5592
+ } else {
5593
+ const mem = result.memory || result;
5594
+ console.log(`${c.bold}ID:${c.reset} ${mem.id || id}`);
5595
+ console.log(`${c.bold}Content:${c.reset} ${mem.content}`);
5596
+ if (mem.importance !== undefined)
5597
+ console.log(`${c.bold}Importance:${c.reset} ${mem.importance}`);
5598
+ if (mem.namespace)
5599
+ console.log(`${c.bold}Namespace:${c.reset} ${mem.namespace}`);
5600
+ if (mem.metadata?.tags?.length)
5601
+ console.log(`${c.bold}Tags:${c.reset} ${mem.metadata.tags.join(", ")}`);
5602
+ if (mem.memory_type)
5603
+ console.log(`${c.bold}Type:${c.reset} ${mem.memory_type}`);
5604
+ if (mem.created_at)
5605
+ console.log(`${c.bold}Created:${c.reset} ${new Date(mem.created_at).toLocaleString()}`);
5606
+ if (mem.updated_at)
5607
+ console.log(`${c.bold}Updated:${c.reset} ${new Date(mem.updated_at).toLocaleString()}`);
5608
+ if (mem.pinned)
5609
+ console.log(`${c.bold}Pinned:${c.reset} ${c.green}yes${c.reset}`);
5610
+ }
5611
+ }
5513
5612
  async function cmdDelete(id) {
5514
5613
  const result = await request("DELETE", `/v1/memories/${id}`);
5515
5614
  if (outputJson) {
@@ -5520,7 +5619,7 @@ async function cmdDelete(id) {
5520
5619
  }
5521
5620
  async function cmdSuggested(opts) {
5522
5621
  const params = new URLSearchParams;
5523
- if (opts.limit)
5622
+ if (opts.limit != null && opts.limit !== true)
5524
5623
  params.set("limit", opts.limit);
5525
5624
  if (opts.namespace)
5526
5625
  params.set("namespace", opts.namespace);
@@ -5555,7 +5654,7 @@ async function cmdUpdate(id, opts) {
5555
5654
  const body = {};
5556
5655
  if (opts.content)
5557
5656
  body.content = opts.content;
5558
- if (opts.importance)
5657
+ if (opts.importance != null && opts.importance !== true)
5559
5658
  body.importance = parseFloat(opts.importance);
5560
5659
  if (opts.memoryType)
5561
5660
  body.memory_type = opts.memoryType;
@@ -5621,7 +5720,7 @@ async function cmdConsolidate(opts) {
5621
5720
  const body = {};
5622
5721
  if (opts.namespace)
5623
5722
  body.namespace = opts.namespace;
5624
- if (opts.minSimilarity)
5723
+ if (opts.minSimilarity != null && opts.minSimilarity !== true)
5625
5724
  body.min_similarity = parseFloat(opts.minSimilarity);
5626
5725
  if (opts.mode)
5627
5726
  body.mode = opts.mode;
@@ -5779,7 +5878,7 @@ async function cmdImport(opts) {
5779
5878
  await request("POST", "/v1/store", body);
5780
5879
  imported++;
5781
5880
  if (!outputQuiet) {
5782
- process.stderr.write(`${c.dim}Imported ${imported}/${memories.length}...${c.reset}\r`);
5881
+ process.stderr.write(`\r ${progressBar(imported, memories.length)}`);
5783
5882
  }
5784
5883
  } catch (e) {
5785
5884
  failed++;
@@ -5838,6 +5937,7 @@ async function cmdCompletions(shell) {
5838
5937
  "store",
5839
5938
  "recall",
5840
5939
  "list",
5940
+ "get",
5841
5941
  "update",
5842
5942
  "delete",
5843
5943
  "ingest",
@@ -5849,7 +5949,9 @@ async function cmdCompletions(shell) {
5849
5949
  "export",
5850
5950
  "import",
5851
5951
  "stats",
5852
- "completions"
5952
+ "browse",
5953
+ "completions",
5954
+ "config"
5853
5955
  ];
5854
5956
  if (shell === "bash") {
5855
5957
  console.log(`# Add to ~/.bashrc:
@@ -5878,6 +5980,186 @@ ${commands.map((cmd) => `complete -c memoclaw -n '__fish_use_subcommand' -a '${c
5878
5980
  throw new Error(`Unknown shell: ${shell}. Supported: bash, zsh, fish`);
5879
5981
  }
5880
5982
  }
5983
+ async function cmdConfig(subcmd, rest) {
5984
+ if (subcmd === "show" || !subcmd) {
5985
+ const config = {
5986
+ MEMOCLAW_URL: API_URL,
5987
+ MEMOCLAW_PRIVATE_KEY: PRIVATE_KEY ? `${PRIVATE_KEY.slice(0, 6)}…${PRIVATE_KEY.slice(-4)}` : "(not set)",
5988
+ NO_COLOR: process.env.NO_COLOR || "(not set)",
5989
+ DEBUG: process.env.DEBUG || "(not set)"
5990
+ };
5991
+ if (outputJson) {
5992
+ out(config);
5993
+ } else {
5994
+ console.log(`${c.bold}MemoClaw Configuration${c.reset}`);
5995
+ console.log(`${c.dim}${"─".repeat(50)}${c.reset}`);
5996
+ for (const [key, val] of Object.entries(config)) {
5997
+ const isSet = !val.includes("not set");
5998
+ console.log(` ${c.cyan}${key.padEnd(24)}${c.reset} ${isSet ? val : `${c.dim}${val}${c.reset}`}`);
5999
+ }
6000
+ console.log(`
6001
+ ${c.dim}Set via environment variables or .env file${c.reset}`);
6002
+ }
6003
+ } else if (subcmd === "check") {
6004
+ const issues = [];
6005
+ if (!PRIVATE_KEY)
6006
+ issues.push("MEMOCLAW_PRIVATE_KEY is not set");
6007
+ else if (!PRIVATE_KEY.startsWith("0x"))
6008
+ issues.push("MEMOCLAW_PRIVATE_KEY should start with 0x");
6009
+ else if (PRIVATE_KEY.length !== 66)
6010
+ issues.push(`MEMOCLAW_PRIVATE_KEY has wrong length (${PRIVATE_KEY.length}, expected 66)`);
6011
+ if (outputJson) {
6012
+ out({ valid: issues.length === 0, issues });
6013
+ } else {
6014
+ if (issues.length === 0) {
6015
+ success("Configuration looks good!");
6016
+ try {
6017
+ const acct = getAccount();
6018
+ info(`Wallet address: ${acct.address}`);
6019
+ } catch {}
6020
+ } else {
6021
+ for (const issue of issues) {
6022
+ console.log(`${c.red}✗${c.reset} ${issue}`);
6023
+ }
6024
+ }
6025
+ }
6026
+ } else {
6027
+ throw new Error("Usage: config [show|check]");
6028
+ }
6029
+ }
6030
+ async function cmdBrowse(opts) {
6031
+ const readline = await import("readline");
6032
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
6033
+ const prompt = (q) => new Promise((r) => rl.question(q, r));
6034
+ console.log(`${c.bold}MemoClaw Interactive Browser${c.reset} ${c.dim}(type "help" or "q" to quit)${c.reset}`);
6035
+ if (opts.namespace)
6036
+ console.log(`${c.dim}Namespace: ${opts.namespace}${c.reset}`);
6037
+ console.log();
6038
+ let offset = 0;
6039
+ const limit = 10;
6040
+ while (true) {
6041
+ const input = (await prompt(`${c.cyan}memoclaw>${c.reset} `)).trim();
6042
+ if (!input)
6043
+ continue;
6044
+ if (input === "q" || input === "quit" || input === "exit")
6045
+ break;
6046
+ const parts = input.split(/\s+/);
6047
+ const browsCmd = parts[0];
6048
+ const browseArgs = parts.slice(1).join(" ");
6049
+ try {
6050
+ switch (browsCmd) {
6051
+ case "help":
6052
+ console.log(`${c.bold}Commands:${c.reset}
6053
+ list / ls List memories (paginated)
6054
+ next / n Next page
6055
+ prev / p Previous page
6056
+ get <id> Show memory details
6057
+ recall <query> Search memories
6058
+ store <content> Store a new memory
6059
+ delete <id> Delete a memory
6060
+ stats Show stats
6061
+ q / quit Exit browser`);
6062
+ break;
6063
+ case "list":
6064
+ case "ls": {
6065
+ offset = 0;
6066
+ const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
6067
+ if (opts.namespace)
6068
+ params.set("namespace", opts.namespace);
6069
+ const result = await request("GET", `/v1/memories?${params}`);
6070
+ const memories = result.memories || result.data || [];
6071
+ if (memories.length === 0) {
6072
+ console.log(`${c.dim}No memories.${c.reset}`);
6073
+ break;
6074
+ }
6075
+ for (const m of memories) {
6076
+ const text = m.content?.length > 60 ? m.content.slice(0, 60) + "…" : m.content || "";
6077
+ console.log(` ${c.cyan}${(m.id || "?").slice(0, 8)}${c.reset} ${text}`);
6078
+ }
6079
+ console.log(`${c.dim}─ showing ${offset + 1}-${offset + memories.length}${result.total ? ` of ${result.total}` : ""}${c.reset}`);
6080
+ break;
6081
+ }
6082
+ case "next":
6083
+ case "n":
6084
+ offset += limit;
6085
+ {
6086
+ const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
6087
+ if (opts.namespace)
6088
+ params.set("namespace", opts.namespace);
6089
+ const result = await request("GET", `/v1/memories?${params}`);
6090
+ const memories = result.memories || result.data || [];
6091
+ if (memories.length === 0) {
6092
+ console.log(`${c.dim}No more memories.${c.reset}`);
6093
+ offset = Math.max(0, offset - limit);
6094
+ break;
6095
+ }
6096
+ for (const m of memories) {
6097
+ const text = m.content?.length > 60 ? m.content.slice(0, 60) + "…" : m.content || "";
6098
+ console.log(` ${c.cyan}${(m.id || "?").slice(0, 8)}${c.reset} ${text}`);
6099
+ }
6100
+ console.log(`${c.dim}─ showing ${offset + 1}-${offset + memories.length}${result.total ? ` of ${result.total}` : ""}${c.reset}`);
6101
+ }
6102
+ break;
6103
+ case "prev":
6104
+ case "p":
6105
+ offset = Math.max(0, offset - limit);
6106
+ {
6107
+ const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
6108
+ if (opts.namespace)
6109
+ params.set("namespace", opts.namespace);
6110
+ const result = await request("GET", `/v1/memories?${params}`);
6111
+ const memories = result.memories || result.data || [];
6112
+ for (const m of memories) {
6113
+ const text = m.content?.length > 60 ? m.content.slice(0, 60) + "…" : m.content || "";
6114
+ console.log(` ${c.cyan}${(m.id || "?").slice(0, 8)}${c.reset} ${text}`);
6115
+ }
6116
+ console.log(`${c.dim}─ showing ${offset + 1}-${offset + memories.length}${result.total ? ` of ${result.total}` : ""}${c.reset}`);
6117
+ }
6118
+ break;
6119
+ case "get":
6120
+ if (!browseArgs) {
6121
+ console.log(`${c.red}Usage: get <id>${c.reset}`);
6122
+ break;
6123
+ }
6124
+ await cmdGet(browseArgs);
6125
+ break;
6126
+ case "recall":
6127
+ case "search":
6128
+ if (!browseArgs) {
6129
+ console.log(`${c.red}Usage: recall <query>${c.reset}`);
6130
+ break;
6131
+ }
6132
+ await cmdRecall(browseArgs, opts);
6133
+ break;
6134
+ case "store":
6135
+ if (!browseArgs) {
6136
+ console.log(`${c.red}Usage: store <content>${c.reset}`);
6137
+ break;
6138
+ }
6139
+ await cmdStore(browseArgs, opts);
6140
+ break;
6141
+ case "delete":
6142
+ case "rm":
6143
+ if (!browseArgs) {
6144
+ console.log(`${c.red}Usage: delete <id>${c.reset}`);
6145
+ break;
6146
+ }
6147
+ await cmdDelete(browseArgs);
6148
+ break;
6149
+ case "stats":
6150
+ await cmdStats(opts);
6151
+ break;
6152
+ default:
6153
+ console.log(`${c.dim}Unknown command. Type "help" for available commands.${c.reset}`);
6154
+ }
6155
+ } catch (e) {
6156
+ console.log(`${c.red}Error:${c.reset} ${e.message}`);
6157
+ }
6158
+ console.log();
6159
+ }
6160
+ rl.close();
6161
+ console.log(`${c.dim}Bye!${c.reset}`);
6162
+ }
5881
6163
  function printHelp(command) {
5882
6164
  if (command) {
5883
6165
  const subHelp = {
@@ -5932,6 +6214,25 @@ Show memory statistics and account info.
5932
6214
 
5933
6215
  Options:
5934
6216
  --namespace <name> Filter by namespace`,
6217
+ get: `${c.bold}memoclaw get${c.reset} <id>
6218
+
6219
+ Retrieve a single memory by its ID.`,
6220
+ config: `${c.bold}memoclaw config${c.reset} [show|check]
6221
+
6222
+ Show or validate your MemoClaw configuration.
6223
+
6224
+ Subcommands:
6225
+ show Display current configuration (default)
6226
+ check Validate configuration and test connectivity`,
6227
+ browse: `${c.bold}memoclaw browse${c.reset} [options]
6228
+
6229
+ Interactive memory browser (REPL). Explore, search, and manage
6230
+ memories in a persistent session.
6231
+
6232
+ Options:
6233
+ --namespace <name> Filter by namespace
6234
+
6235
+ Commands inside browser: list, get, recall, store, delete, stats, next, prev`,
5935
6236
  completions: `${c.bold}memoclaw completions${c.reset} <bash|zsh|fish>
5936
6237
 
5937
6238
  Generate shell completion scripts.
@@ -5956,6 +6257,7 @@ ${c.bold}Commands:${c.reset}
5956
6257
  ${c.cyan}store${c.reset} "content" Store a memory (also accepts stdin)
5957
6258
  ${c.cyan}recall${c.reset} "query" Search memories by similarity
5958
6259
  ${c.cyan}list${c.reset} List memories in a table
6260
+ ${c.cyan}get${c.reset} <id> Get a single memory by ID
5959
6261
  ${c.cyan}update${c.reset} <id> Update a memory
5960
6262
  ${c.cyan}delete${c.reset} <id> Delete a memory
5961
6263
  ${c.cyan}ingest${c.reset} Ingest raw text into memories
@@ -5968,12 +6270,18 @@ ${c.bold}Commands:${c.reset}
5968
6270
  ${c.cyan}export${c.reset} Export all memories as JSON
5969
6271
  ${c.cyan}import${c.reset} Import memories from JSON
5970
6272
  ${c.cyan}completions${c.reset} <shell> Generate shell completions
6273
+ ${c.cyan}browse${c.reset} Interactive memory browser (REPL)
6274
+ ${c.cyan}config${c.reset} [show|check] Show or validate configuration
5971
6275
 
5972
6276
  ${c.bold}Global Options:${c.reset}
5973
6277
  -h, --help Show help (use with command for details)
5974
6278
  -v, --version Show version
5975
6279
  -j, --json Output as JSON (machine-readable)
5976
6280
  -q, --quiet Suppress non-essential output
6281
+ -n, --namespace <name> Filter/set namespace
6282
+ -l, --limit <n> Limit results
6283
+ -t, --tags <a,b> Comma-separated tags
6284
+ --raw Raw output (content only, for piping)
5977
6285
 
5978
6286
  ${c.bold}Environment:${c.reset}
5979
6287
  MEMOCLAW_PRIVATE_KEY Wallet private key for auth + payments
@@ -6031,6 +6339,11 @@ try {
6031
6339
  case "list":
6032
6340
  await cmdList(args);
6033
6341
  break;
6342
+ case "get":
6343
+ if (!rest[0])
6344
+ throw new Error("Memory ID required");
6345
+ await cmdGet(rest[0]);
6346
+ break;
6034
6347
  case "update":
6035
6348
  if (!rest[0])
6036
6349
  throw new Error("Memory ID required");
@@ -6086,6 +6399,12 @@ try {
6086
6399
  throw new Error("Shell required: bash, zsh, or fish");
6087
6400
  await cmdCompletions(rest[0]);
6088
6401
  break;
6402
+ case "browse":
6403
+ await cmdBrowse(args);
6404
+ break;
6405
+ case "config":
6406
+ await cmdConfig(rest[0], rest.slice(1));
6407
+ break;
6089
6408
  case "help":
6090
6409
  printHelp(rest[0]);
6091
6410
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "memoclaw",
3
- "version": "1.5.0",
3
+ "version": "1.6.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": {
@@ -11,6 +11,7 @@
11
11
  ],
12
12
  "scripts": {
13
13
  "build": "bun build src/cli.ts --outfile=dist/cli.mjs --target=node",
14
+ "test": "bun test",
14
15
  "prepublishOnly": "bun run build"
15
16
  },
16
17
  "keywords": [