memoclaw 1.5.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.
- package/dist/cli.mjs +531 -63
- package/package.json +2 -1
package/dist/cli.mjs
CHANGED
|
@@ -5208,8 +5208,127 @@ 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
|
+
"force",
|
|
5222
|
+
"count",
|
|
5223
|
+
"wide"
|
|
5224
|
+
]);
|
|
5225
|
+
var SHORT_FLAGS = {
|
|
5226
|
+
"-h": "help",
|
|
5227
|
+
"-v": "version",
|
|
5228
|
+
"-j": "json",
|
|
5229
|
+
"-q": "quiet",
|
|
5230
|
+
"-n": "namespace",
|
|
5231
|
+
"-l": "limit",
|
|
5232
|
+
"-t": "tags",
|
|
5233
|
+
"-o": "output"
|
|
5234
|
+
};
|
|
5235
|
+
function parseArgs(args) {
|
|
5236
|
+
const result = { _: [] };
|
|
5237
|
+
let i = 0;
|
|
5238
|
+
while (i < args.length) {
|
|
5239
|
+
const arg = args[i];
|
|
5240
|
+
if (arg[0] === "-" && arg[1] !== "-" && arg.length >= 2) {
|
|
5241
|
+
if (arg.length === 2 && SHORT_FLAGS[arg]) {
|
|
5242
|
+
const key = SHORT_FLAGS[arg];
|
|
5243
|
+
if (BOOLEAN_FLAGS.has(key)) {
|
|
5244
|
+
result[key] = true;
|
|
5245
|
+
i++;
|
|
5246
|
+
} else {
|
|
5247
|
+
const next = args[i + 1];
|
|
5248
|
+
if (next !== undefined && !next.startsWith("-")) {
|
|
5249
|
+
result[key] = next;
|
|
5250
|
+
i += 2;
|
|
5251
|
+
} else {
|
|
5252
|
+
result[key] = true;
|
|
5253
|
+
i++;
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
5256
|
+
} else if (arg.length > 2 && !SHORT_FLAGS[arg]) {
|
|
5257
|
+
const chars = arg.slice(1).split("");
|
|
5258
|
+
let allValid = true;
|
|
5259
|
+
for (const ch of chars) {
|
|
5260
|
+
const flag = `-${ch}`;
|
|
5261
|
+
if (!SHORT_FLAGS[flag]) {
|
|
5262
|
+
allValid = false;
|
|
5263
|
+
break;
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5266
|
+
if (allValid) {
|
|
5267
|
+
for (let ci = 0;ci < chars.length; ci++) {
|
|
5268
|
+
const flag = `-${chars[ci]}`;
|
|
5269
|
+
const key = SHORT_FLAGS[flag];
|
|
5270
|
+
if (BOOLEAN_FLAGS.has(key)) {
|
|
5271
|
+
result[key] = true;
|
|
5272
|
+
} else if (ci === chars.length - 1) {
|
|
5273
|
+
const next = args[i + 1];
|
|
5274
|
+
if (next !== undefined && !next.startsWith("-")) {
|
|
5275
|
+
result[key] = next;
|
|
5276
|
+
i++;
|
|
5277
|
+
} else {
|
|
5278
|
+
result[key] = true;
|
|
5279
|
+
}
|
|
5280
|
+
} else {
|
|
5281
|
+
result[key] = true;
|
|
5282
|
+
}
|
|
5283
|
+
}
|
|
5284
|
+
i++;
|
|
5285
|
+
} else {
|
|
5286
|
+
result._.push(arg);
|
|
5287
|
+
i++;
|
|
5288
|
+
}
|
|
5289
|
+
} else {
|
|
5290
|
+
result._.push(arg);
|
|
5291
|
+
i++;
|
|
5292
|
+
}
|
|
5293
|
+
} else if (arg === "--") {
|
|
5294
|
+
result._.push(...args.slice(i + 1));
|
|
5295
|
+
break;
|
|
5296
|
+
} else if (arg.startsWith("--")) {
|
|
5297
|
+
const eqIdx = arg.indexOf("=");
|
|
5298
|
+
let key;
|
|
5299
|
+
let inlineValue;
|
|
5300
|
+
if (eqIdx !== -1) {
|
|
5301
|
+
key = arg.slice(2, eqIdx).replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
|
|
5302
|
+
inlineValue = arg.slice(eqIdx + 1);
|
|
5303
|
+
} else {
|
|
5304
|
+
key = arg.slice(2).replace(/-([a-z])/g, (_, ch) => ch.toUpperCase());
|
|
5305
|
+
}
|
|
5306
|
+
if (inlineValue !== undefined) {
|
|
5307
|
+
result[key] = inlineValue;
|
|
5308
|
+
i++;
|
|
5309
|
+
} else if (BOOLEAN_FLAGS.has(key)) {
|
|
5310
|
+
result[key] = true;
|
|
5311
|
+
i++;
|
|
5312
|
+
} else {
|
|
5313
|
+
const next = args[i + 1];
|
|
5314
|
+
if (next !== undefined && (!next.startsWith("--") || /^--?\d/.test(next))) {
|
|
5315
|
+
result[key] = next;
|
|
5316
|
+
i += 2;
|
|
5317
|
+
} else {
|
|
5318
|
+
result[key] = true;
|
|
5319
|
+
i++;
|
|
5320
|
+
}
|
|
5321
|
+
}
|
|
5322
|
+
} else {
|
|
5323
|
+
result._.push(arg);
|
|
5324
|
+
i++;
|
|
5325
|
+
}
|
|
5326
|
+
}
|
|
5327
|
+
return result;
|
|
5328
|
+
}
|
|
5329
|
+
|
|
5211
5330
|
// src/cli.ts
|
|
5212
|
-
var VERSION = "1.
|
|
5331
|
+
var VERSION = "1.7.0";
|
|
5213
5332
|
var API_URL = process.env.MEMOCLAW_URL || "https://api.memoclaw.com";
|
|
5214
5333
|
var PRIVATE_KEY = process.env.MEMOCLAW_PRIVATE_KEY;
|
|
5215
5334
|
var NO_COLOR = !!process.env.NO_COLOR || !process.stdout.isTTY;
|
|
@@ -5260,57 +5379,6 @@ async function getWalletAuthHeader() {
|
|
|
5260
5379
|
const signature = await account.signMessage({ message });
|
|
5261
5380
|
return `${account.address}:${timestamp}:${signature}`;
|
|
5262
5381
|
}
|
|
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
5382
|
async function readStdin() {
|
|
5315
5383
|
if (process.stdin.isTTY)
|
|
5316
5384
|
return null;
|
|
@@ -5374,6 +5442,11 @@ function table(rows, columns) {
|
|
|
5374
5442
|
console.log(line);
|
|
5375
5443
|
}
|
|
5376
5444
|
}
|
|
5445
|
+
function progressBar(current, total, width = 30) {
|
|
5446
|
+
const pct = Math.min(current / total, 1);
|
|
5447
|
+
const filled = Math.round(pct * width);
|
|
5448
|
+
return `${c.green}${"█".repeat(filled)}${c.dim}${"░".repeat(width - filled)}${c.reset} ${current}/${total}`;
|
|
5449
|
+
}
|
|
5377
5450
|
async function request(method, path, body = null) {
|
|
5378
5451
|
const url = `${API_URL}${path}`;
|
|
5379
5452
|
const headers = { "Content-Type": "application/json" };
|
|
@@ -5382,7 +5455,21 @@ async function request(method, path, body = null) {
|
|
|
5382
5455
|
options.body = JSON.stringify(body);
|
|
5383
5456
|
const walletAuth = await getWalletAuthHeader();
|
|
5384
5457
|
headers["x-wallet-auth"] = walletAuth;
|
|
5385
|
-
let res
|
|
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
|
+
}
|
|
5386
5473
|
const freeTierRemaining = res.headers.get("x-free-tier-remaining");
|
|
5387
5474
|
if (freeTierRemaining !== null && process.env.DEBUG) {
|
|
5388
5475
|
console.error(`${c.dim}Free tier remaining: ${freeTierRemaining}${c.reset}`);
|
|
@@ -5426,7 +5513,7 @@ async function request(method, path, body = null) {
|
|
|
5426
5513
|
}
|
|
5427
5514
|
async function cmdStore(content, opts) {
|
|
5428
5515
|
const body = { content };
|
|
5429
|
-
if (opts.importance)
|
|
5516
|
+
if (opts.importance != null && opts.importance !== true)
|
|
5430
5517
|
body.importance = parseFloat(opts.importance);
|
|
5431
5518
|
if (opts.tags)
|
|
5432
5519
|
body.metadata = { tags: opts.tags.split(",").map((t) => t.trim()) };
|
|
@@ -5443,9 +5530,9 @@ async function cmdStore(content, opts) {
|
|
|
5443
5530
|
}
|
|
5444
5531
|
async function cmdRecall(query, opts) {
|
|
5445
5532
|
const body = { query };
|
|
5446
|
-
if (opts.limit)
|
|
5533
|
+
if (opts.limit != null && opts.limit !== true)
|
|
5447
5534
|
body.limit = parseInt(opts.limit);
|
|
5448
|
-
if (opts.minSimilarity)
|
|
5535
|
+
if (opts.minSimilarity != null && opts.minSimilarity !== true)
|
|
5449
5536
|
body.min_similarity = parseFloat(opts.minSimilarity);
|
|
5450
5537
|
if (opts.namespace)
|
|
5451
5538
|
body.namespace = opts.namespace;
|
|
@@ -5454,6 +5541,11 @@ async function cmdRecall(query, opts) {
|
|
|
5454
5541
|
const result = await request("POST", "/v1/recall", body);
|
|
5455
5542
|
if (outputJson) {
|
|
5456
5543
|
out(result);
|
|
5544
|
+
} else if (opts.raw) {
|
|
5545
|
+
const memories = result.memories || [];
|
|
5546
|
+
for (const mem of memories) {
|
|
5547
|
+
console.log(mem.content);
|
|
5548
|
+
}
|
|
5457
5549
|
} else {
|
|
5458
5550
|
const memories = result.memories || [];
|
|
5459
5551
|
if (memories.length === 0) {
|
|
@@ -5476,9 +5568,9 @@ async function cmdRecall(query, opts) {
|
|
|
5476
5568
|
}
|
|
5477
5569
|
async function cmdList(opts) {
|
|
5478
5570
|
const params = new URLSearchParams;
|
|
5479
|
-
if (opts.limit)
|
|
5571
|
+
if (opts.limit != null && opts.limit !== true)
|
|
5480
5572
|
params.set("limit", opts.limit);
|
|
5481
|
-
if (opts.offset)
|
|
5573
|
+
if (opts.offset != null && opts.offset !== true)
|
|
5482
5574
|
params.set("offset", opts.offset);
|
|
5483
5575
|
if (opts.namespace)
|
|
5484
5576
|
params.set("namespace", opts.namespace);
|
|
@@ -5510,6 +5602,30 @@ async function cmdList(opts) {
|
|
|
5510
5602
|
}
|
|
5511
5603
|
}
|
|
5512
5604
|
}
|
|
5605
|
+
async function cmdGet(id) {
|
|
5606
|
+
const result = await request("GET", `/v1/memories/${id}`);
|
|
5607
|
+
if (outputJson) {
|
|
5608
|
+
out(result);
|
|
5609
|
+
} else {
|
|
5610
|
+
const mem = result.memory || result;
|
|
5611
|
+
console.log(`${c.bold}ID:${c.reset} ${mem.id || id}`);
|
|
5612
|
+
console.log(`${c.bold}Content:${c.reset} ${mem.content}`);
|
|
5613
|
+
if (mem.importance !== undefined)
|
|
5614
|
+
console.log(`${c.bold}Importance:${c.reset} ${mem.importance}`);
|
|
5615
|
+
if (mem.namespace)
|
|
5616
|
+
console.log(`${c.bold}Namespace:${c.reset} ${mem.namespace}`);
|
|
5617
|
+
if (mem.metadata?.tags?.length)
|
|
5618
|
+
console.log(`${c.bold}Tags:${c.reset} ${mem.metadata.tags.join(", ")}`);
|
|
5619
|
+
if (mem.memory_type)
|
|
5620
|
+
console.log(`${c.bold}Type:${c.reset} ${mem.memory_type}`);
|
|
5621
|
+
if (mem.created_at)
|
|
5622
|
+
console.log(`${c.bold}Created:${c.reset} ${new Date(mem.created_at).toLocaleString()}`);
|
|
5623
|
+
if (mem.updated_at)
|
|
5624
|
+
console.log(`${c.bold}Updated:${c.reset} ${new Date(mem.updated_at).toLocaleString()}`);
|
|
5625
|
+
if (mem.pinned)
|
|
5626
|
+
console.log(`${c.bold}Pinned:${c.reset} ${c.green}yes${c.reset}`);
|
|
5627
|
+
}
|
|
5628
|
+
}
|
|
5513
5629
|
async function cmdDelete(id) {
|
|
5514
5630
|
const result = await request("DELETE", `/v1/memories/${id}`);
|
|
5515
5631
|
if (outputJson) {
|
|
@@ -5520,7 +5636,7 @@ async function cmdDelete(id) {
|
|
|
5520
5636
|
}
|
|
5521
5637
|
async function cmdSuggested(opts) {
|
|
5522
5638
|
const params = new URLSearchParams;
|
|
5523
|
-
if (opts.limit)
|
|
5639
|
+
if (opts.limit != null && opts.limit !== true)
|
|
5524
5640
|
params.set("limit", opts.limit);
|
|
5525
5641
|
if (opts.namespace)
|
|
5526
5642
|
params.set("namespace", opts.namespace);
|
|
@@ -5555,7 +5671,7 @@ async function cmdUpdate(id, opts) {
|
|
|
5555
5671
|
const body = {};
|
|
5556
5672
|
if (opts.content)
|
|
5557
5673
|
body.content = opts.content;
|
|
5558
|
-
if (opts.importance)
|
|
5674
|
+
if (opts.importance != null && opts.importance !== true)
|
|
5559
5675
|
body.importance = parseFloat(opts.importance);
|
|
5560
5676
|
if (opts.memoryType)
|
|
5561
5677
|
body.memory_type = opts.memoryType;
|
|
@@ -5621,7 +5737,7 @@ async function cmdConsolidate(opts) {
|
|
|
5621
5737
|
const body = {};
|
|
5622
5738
|
if (opts.namespace)
|
|
5623
5739
|
body.namespace = opts.namespace;
|
|
5624
|
-
if (opts.minSimilarity)
|
|
5740
|
+
if (opts.minSimilarity != null && opts.minSimilarity !== true)
|
|
5625
5741
|
body.min_similarity = parseFloat(opts.minSimilarity);
|
|
5626
5742
|
if (opts.mode)
|
|
5627
5743
|
body.mode = opts.mode;
|
|
@@ -5779,7 +5895,7 @@ async function cmdImport(opts) {
|
|
|
5779
5895
|
await request("POST", "/v1/store", body);
|
|
5780
5896
|
imported++;
|
|
5781
5897
|
if (!outputQuiet) {
|
|
5782
|
-
process.stderr.write(
|
|
5898
|
+
process.stderr.write(`\r ${progressBar(imported, memories.length)}`);
|
|
5783
5899
|
}
|
|
5784
5900
|
} catch (e) {
|
|
5785
5901
|
failed++;
|
|
@@ -5833,11 +5949,99 @@ async function cmdStats(opts) {
|
|
|
5833
5949
|
}
|
|
5834
5950
|
}
|
|
5835
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
|
+
}
|
|
5836
6039
|
async function cmdCompletions(shell) {
|
|
5837
6040
|
const commands = [
|
|
5838
6041
|
"store",
|
|
5839
6042
|
"recall",
|
|
5840
6043
|
"list",
|
|
6044
|
+
"get",
|
|
5841
6045
|
"update",
|
|
5842
6046
|
"delete",
|
|
5843
6047
|
"ingest",
|
|
@@ -5849,7 +6053,12 @@ async function cmdCompletions(shell) {
|
|
|
5849
6053
|
"export",
|
|
5850
6054
|
"import",
|
|
5851
6055
|
"stats",
|
|
5852
|
-
"
|
|
6056
|
+
"browse",
|
|
6057
|
+
"completions",
|
|
6058
|
+
"config",
|
|
6059
|
+
"graph",
|
|
6060
|
+
"purge",
|
|
6061
|
+
"count"
|
|
5853
6062
|
];
|
|
5854
6063
|
if (shell === "bash") {
|
|
5855
6064
|
console.log(`# Add to ~/.bashrc:
|
|
@@ -5878,6 +6087,186 @@ ${commands.map((cmd) => `complete -c memoclaw -n '__fish_use_subcommand' -a '${c
|
|
|
5878
6087
|
throw new Error(`Unknown shell: ${shell}. Supported: bash, zsh, fish`);
|
|
5879
6088
|
}
|
|
5880
6089
|
}
|
|
6090
|
+
async function cmdConfig(subcmd, rest) {
|
|
6091
|
+
if (subcmd === "show" || !subcmd) {
|
|
6092
|
+
const config = {
|
|
6093
|
+
MEMOCLAW_URL: API_URL,
|
|
6094
|
+
MEMOCLAW_PRIVATE_KEY: PRIVATE_KEY ? `${PRIVATE_KEY.slice(0, 6)}…${PRIVATE_KEY.slice(-4)}` : "(not set)",
|
|
6095
|
+
NO_COLOR: process.env.NO_COLOR || "(not set)",
|
|
6096
|
+
DEBUG: process.env.DEBUG || "(not set)"
|
|
6097
|
+
};
|
|
6098
|
+
if (outputJson) {
|
|
6099
|
+
out(config);
|
|
6100
|
+
} else {
|
|
6101
|
+
console.log(`${c.bold}MemoClaw Configuration${c.reset}`);
|
|
6102
|
+
console.log(`${c.dim}${"─".repeat(50)}${c.reset}`);
|
|
6103
|
+
for (const [key, val] of Object.entries(config)) {
|
|
6104
|
+
const isSet = !val.includes("not set");
|
|
6105
|
+
console.log(` ${c.cyan}${key.padEnd(24)}${c.reset} ${isSet ? val : `${c.dim}${val}${c.reset}`}`);
|
|
6106
|
+
}
|
|
6107
|
+
console.log(`
|
|
6108
|
+
${c.dim}Set via environment variables or .env file${c.reset}`);
|
|
6109
|
+
}
|
|
6110
|
+
} else if (subcmd === "check") {
|
|
6111
|
+
const issues = [];
|
|
6112
|
+
if (!PRIVATE_KEY)
|
|
6113
|
+
issues.push("MEMOCLAW_PRIVATE_KEY is not set");
|
|
6114
|
+
else if (!PRIVATE_KEY.startsWith("0x"))
|
|
6115
|
+
issues.push("MEMOCLAW_PRIVATE_KEY should start with 0x");
|
|
6116
|
+
else if (PRIVATE_KEY.length !== 66)
|
|
6117
|
+
issues.push(`MEMOCLAW_PRIVATE_KEY has wrong length (${PRIVATE_KEY.length}, expected 66)`);
|
|
6118
|
+
if (outputJson) {
|
|
6119
|
+
out({ valid: issues.length === 0, issues });
|
|
6120
|
+
} else {
|
|
6121
|
+
if (issues.length === 0) {
|
|
6122
|
+
success("Configuration looks good!");
|
|
6123
|
+
try {
|
|
6124
|
+
const acct = getAccount();
|
|
6125
|
+
info(`Wallet address: ${acct.address}`);
|
|
6126
|
+
} catch {}
|
|
6127
|
+
} else {
|
|
6128
|
+
for (const issue of issues) {
|
|
6129
|
+
console.log(`${c.red}✗${c.reset} ${issue}`);
|
|
6130
|
+
}
|
|
6131
|
+
}
|
|
6132
|
+
}
|
|
6133
|
+
} else {
|
|
6134
|
+
throw new Error("Usage: config [show|check]");
|
|
6135
|
+
}
|
|
6136
|
+
}
|
|
6137
|
+
async function cmdBrowse(opts) {
|
|
6138
|
+
const readline = await import("readline");
|
|
6139
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
6140
|
+
const prompt = (q) => new Promise((r) => rl.question(q, r));
|
|
6141
|
+
console.log(`${c.bold}MemoClaw Interactive Browser${c.reset} ${c.dim}(type "help" or "q" to quit)${c.reset}`);
|
|
6142
|
+
if (opts.namespace)
|
|
6143
|
+
console.log(`${c.dim}Namespace: ${opts.namespace}${c.reset}`);
|
|
6144
|
+
console.log();
|
|
6145
|
+
let offset = 0;
|
|
6146
|
+
const limit = 10;
|
|
6147
|
+
while (true) {
|
|
6148
|
+
const input = (await prompt(`${c.cyan}memoclaw>${c.reset} `)).trim();
|
|
6149
|
+
if (!input)
|
|
6150
|
+
continue;
|
|
6151
|
+
if (input === "q" || input === "quit" || input === "exit")
|
|
6152
|
+
break;
|
|
6153
|
+
const parts = input.split(/\s+/);
|
|
6154
|
+
const browsCmd = parts[0];
|
|
6155
|
+
const browseArgs = parts.slice(1).join(" ");
|
|
6156
|
+
try {
|
|
6157
|
+
switch (browsCmd) {
|
|
6158
|
+
case "help":
|
|
6159
|
+
console.log(`${c.bold}Commands:${c.reset}
|
|
6160
|
+
list / ls List memories (paginated)
|
|
6161
|
+
next / n Next page
|
|
6162
|
+
prev / p Previous page
|
|
6163
|
+
get <id> Show memory details
|
|
6164
|
+
recall <query> Search memories
|
|
6165
|
+
store <content> Store a new memory
|
|
6166
|
+
delete <id> Delete a memory
|
|
6167
|
+
stats Show stats
|
|
6168
|
+
q / quit Exit browser`);
|
|
6169
|
+
break;
|
|
6170
|
+
case "list":
|
|
6171
|
+
case "ls": {
|
|
6172
|
+
offset = 0;
|
|
6173
|
+
const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
|
|
6174
|
+
if (opts.namespace)
|
|
6175
|
+
params.set("namespace", opts.namespace);
|
|
6176
|
+
const result = await request("GET", `/v1/memories?${params}`);
|
|
6177
|
+
const memories = result.memories || result.data || [];
|
|
6178
|
+
if (memories.length === 0) {
|
|
6179
|
+
console.log(`${c.dim}No memories.${c.reset}`);
|
|
6180
|
+
break;
|
|
6181
|
+
}
|
|
6182
|
+
for (const m of memories) {
|
|
6183
|
+
const text = m.content?.length > 60 ? m.content.slice(0, 60) + "…" : m.content || "";
|
|
6184
|
+
console.log(` ${c.cyan}${(m.id || "?").slice(0, 8)}${c.reset} ${text}`);
|
|
6185
|
+
}
|
|
6186
|
+
console.log(`${c.dim}─ showing ${offset + 1}-${offset + memories.length}${result.total ? ` of ${result.total}` : ""}${c.reset}`);
|
|
6187
|
+
break;
|
|
6188
|
+
}
|
|
6189
|
+
case "next":
|
|
6190
|
+
case "n":
|
|
6191
|
+
offset += limit;
|
|
6192
|
+
{
|
|
6193
|
+
const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
|
|
6194
|
+
if (opts.namespace)
|
|
6195
|
+
params.set("namespace", opts.namespace);
|
|
6196
|
+
const result = await request("GET", `/v1/memories?${params}`);
|
|
6197
|
+
const memories = result.memories || result.data || [];
|
|
6198
|
+
if (memories.length === 0) {
|
|
6199
|
+
console.log(`${c.dim}No more memories.${c.reset}`);
|
|
6200
|
+
offset = Math.max(0, offset - limit);
|
|
6201
|
+
break;
|
|
6202
|
+
}
|
|
6203
|
+
for (const m of memories) {
|
|
6204
|
+
const text = m.content?.length > 60 ? m.content.slice(0, 60) + "…" : m.content || "";
|
|
6205
|
+
console.log(` ${c.cyan}${(m.id || "?").slice(0, 8)}${c.reset} ${text}`);
|
|
6206
|
+
}
|
|
6207
|
+
console.log(`${c.dim}─ showing ${offset + 1}-${offset + memories.length}${result.total ? ` of ${result.total}` : ""}${c.reset}`);
|
|
6208
|
+
}
|
|
6209
|
+
break;
|
|
6210
|
+
case "prev":
|
|
6211
|
+
case "p":
|
|
6212
|
+
offset = Math.max(0, offset - limit);
|
|
6213
|
+
{
|
|
6214
|
+
const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
|
|
6215
|
+
if (opts.namespace)
|
|
6216
|
+
params.set("namespace", opts.namespace);
|
|
6217
|
+
const result = await request("GET", `/v1/memories?${params}`);
|
|
6218
|
+
const memories = result.memories || result.data || [];
|
|
6219
|
+
for (const m of memories) {
|
|
6220
|
+
const text = m.content?.length > 60 ? m.content.slice(0, 60) + "…" : m.content || "";
|
|
6221
|
+
console.log(` ${c.cyan}${(m.id || "?").slice(0, 8)}${c.reset} ${text}`);
|
|
6222
|
+
}
|
|
6223
|
+
console.log(`${c.dim}─ showing ${offset + 1}-${offset + memories.length}${result.total ? ` of ${result.total}` : ""}${c.reset}`);
|
|
6224
|
+
}
|
|
6225
|
+
break;
|
|
6226
|
+
case "get":
|
|
6227
|
+
if (!browseArgs) {
|
|
6228
|
+
console.log(`${c.red}Usage: get <id>${c.reset}`);
|
|
6229
|
+
break;
|
|
6230
|
+
}
|
|
6231
|
+
await cmdGet(browseArgs);
|
|
6232
|
+
break;
|
|
6233
|
+
case "recall":
|
|
6234
|
+
case "search":
|
|
6235
|
+
if (!browseArgs) {
|
|
6236
|
+
console.log(`${c.red}Usage: recall <query>${c.reset}`);
|
|
6237
|
+
break;
|
|
6238
|
+
}
|
|
6239
|
+
await cmdRecall(browseArgs, opts);
|
|
6240
|
+
break;
|
|
6241
|
+
case "store":
|
|
6242
|
+
if (!browseArgs) {
|
|
6243
|
+
console.log(`${c.red}Usage: store <content>${c.reset}`);
|
|
6244
|
+
break;
|
|
6245
|
+
}
|
|
6246
|
+
await cmdStore(browseArgs, opts);
|
|
6247
|
+
break;
|
|
6248
|
+
case "delete":
|
|
6249
|
+
case "rm":
|
|
6250
|
+
if (!browseArgs) {
|
|
6251
|
+
console.log(`${c.red}Usage: delete <id>${c.reset}`);
|
|
6252
|
+
break;
|
|
6253
|
+
}
|
|
6254
|
+
await cmdDelete(browseArgs);
|
|
6255
|
+
break;
|
|
6256
|
+
case "stats":
|
|
6257
|
+
await cmdStats(opts);
|
|
6258
|
+
break;
|
|
6259
|
+
default:
|
|
6260
|
+
console.log(`${c.dim}Unknown command. Type "help" for available commands.${c.reset}`);
|
|
6261
|
+
}
|
|
6262
|
+
} catch (e) {
|
|
6263
|
+
console.log(`${c.red}Error:${c.reset} ${e.message}`);
|
|
6264
|
+
}
|
|
6265
|
+
console.log();
|
|
6266
|
+
}
|
|
6267
|
+
rl.close();
|
|
6268
|
+
console.log(`${c.dim}Bye!${c.reset}`);
|
|
6269
|
+
}
|
|
5881
6270
|
function printHelp(command) {
|
|
5882
6271
|
if (command) {
|
|
5883
6272
|
const subHelp = {
|
|
@@ -5932,6 +6321,50 @@ Show memory statistics and account info.
|
|
|
5932
6321
|
|
|
5933
6322
|
Options:
|
|
5934
6323
|
--namespace <name> Filter by namespace`,
|
|
6324
|
+
get: `${c.bold}memoclaw get${c.reset} <id>
|
|
6325
|
+
|
|
6326
|
+
Retrieve a single memory by its ID.`,
|
|
6327
|
+
config: `${c.bold}memoclaw config${c.reset} [show|check]
|
|
6328
|
+
|
|
6329
|
+
Show or validate your MemoClaw configuration.
|
|
6330
|
+
|
|
6331
|
+
Subcommands:
|
|
6332
|
+
show Display current configuration (default)
|
|
6333
|
+
check Validate configuration and test connectivity`,
|
|
6334
|
+
browse: `${c.bold}memoclaw browse${c.reset} [options]
|
|
6335
|
+
|
|
6336
|
+
Interactive memory browser (REPL). Explore, search, and manage
|
|
6337
|
+
memories in a persistent session.
|
|
6338
|
+
|
|
6339
|
+
Options:
|
|
6340
|
+
--namespace <name> Filter by namespace
|
|
6341
|
+
|
|
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`,
|
|
5935
6368
|
completions: `${c.bold}memoclaw completions${c.reset} <bash|zsh|fish>
|
|
5936
6369
|
|
|
5937
6370
|
Generate shell completion scripts.
|
|
@@ -5956,6 +6389,7 @@ ${c.bold}Commands:${c.reset}
|
|
|
5956
6389
|
${c.cyan}store${c.reset} "content" Store a memory (also accepts stdin)
|
|
5957
6390
|
${c.cyan}recall${c.reset} "query" Search memories by similarity
|
|
5958
6391
|
${c.cyan}list${c.reset} List memories in a table
|
|
6392
|
+
${c.cyan}get${c.reset} <id> Get a single memory by ID
|
|
5959
6393
|
${c.cyan}update${c.reset} <id> Update a memory
|
|
5960
6394
|
${c.cyan}delete${c.reset} <id> Delete a memory
|
|
5961
6395
|
${c.cyan}ingest${c.reset} Ingest raw text into memories
|
|
@@ -5968,12 +6402,23 @@ ${c.bold}Commands:${c.reset}
|
|
|
5968
6402
|
${c.cyan}export${c.reset} Export all memories as JSON
|
|
5969
6403
|
${c.cyan}import${c.reset} Import memories from JSON
|
|
5970
6404
|
${c.cyan}completions${c.reset} <shell> Generate shell completions
|
|
6405
|
+
${c.cyan}browse${c.reset} Interactive memory browser (REPL)
|
|
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
|
|
5971
6410
|
|
|
5972
6411
|
${c.bold}Global Options:${c.reset}
|
|
5973
6412
|
-h, --help Show help (use with command for details)
|
|
5974
6413
|
-v, --version Show version
|
|
5975
6414
|
-j, --json Output as JSON (machine-readable)
|
|
5976
6415
|
-q, --quiet Suppress non-essential output
|
|
6416
|
+
-n, --namespace <name> Filter/set namespace
|
|
6417
|
+
-l, --limit <n> Limit results
|
|
6418
|
+
-t, --tags <a,b> Comma-separated tags
|
|
6419
|
+
--raw Raw output (content only, for piping)
|
|
6420
|
+
--force Skip confirmation prompts
|
|
6421
|
+
--timeout <seconds> Request timeout (default: 30)
|
|
5977
6422
|
|
|
5978
6423
|
${c.bold}Environment:${c.reset}
|
|
5979
6424
|
MEMOCLAW_PRIVATE_KEY Wallet private key for auth + payments
|
|
@@ -6009,6 +6454,7 @@ if (args.help) {
|
|
|
6009
6454
|
printHelp(cmd);
|
|
6010
6455
|
process.exit(0);
|
|
6011
6456
|
}
|
|
6457
|
+
var TIMEOUT_MS = args.timeout ? parseInt(args.timeout) * 1000 : 30000;
|
|
6012
6458
|
try {
|
|
6013
6459
|
switch (cmd) {
|
|
6014
6460
|
case "store": {
|
|
@@ -6031,6 +6477,11 @@ try {
|
|
|
6031
6477
|
case "list":
|
|
6032
6478
|
await cmdList(args);
|
|
6033
6479
|
break;
|
|
6480
|
+
case "get":
|
|
6481
|
+
if (!rest[0])
|
|
6482
|
+
throw new Error("Memory ID required");
|
|
6483
|
+
await cmdGet(rest[0]);
|
|
6484
|
+
break;
|
|
6034
6485
|
case "update":
|
|
6035
6486
|
if (!rest[0])
|
|
6036
6487
|
throw new Error("Memory ID required");
|
|
@@ -6086,6 +6537,23 @@ try {
|
|
|
6086
6537
|
throw new Error("Shell required: bash, zsh, or fish");
|
|
6087
6538
|
await cmdCompletions(rest[0]);
|
|
6088
6539
|
break;
|
|
6540
|
+
case "browse":
|
|
6541
|
+
await cmdBrowse(args);
|
|
6542
|
+
break;
|
|
6543
|
+
case "config":
|
|
6544
|
+
await cmdConfig(rest[0], rest.slice(1));
|
|
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;
|
|
6089
6557
|
case "help":
|
|
6090
6558
|
printHelp(rest[0]);
|
|
6091
6559
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memoclaw",
|
|
3
|
-
"version": "1.
|
|
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": {
|
|
@@ -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": [
|