memoclaw 1.4.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.
- package/dist/cli.mjs +956 -196
- package/package.json +2 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
4
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
3
5
|
|
|
4
6
|
// node_modules/viem/_esm/utils/data/isHex.js
|
|
5
7
|
function isHex(value, { strict = true } = {}) {
|
|
@@ -5206,12 +5208,143 @@ function privateKeyToAccount(privateKey, options = {}) {
|
|
|
5206
5208
|
source: "privateKey"
|
|
5207
5209
|
};
|
|
5208
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
|
+
|
|
5209
5327
|
// src/cli.ts
|
|
5328
|
+
var VERSION = "1.6.0";
|
|
5210
5329
|
var API_URL = process.env.MEMOCLAW_URL || "https://api.memoclaw.com";
|
|
5211
5330
|
var PRIVATE_KEY = process.env.MEMOCLAW_PRIVATE_KEY;
|
|
5331
|
+
var NO_COLOR = !!process.env.NO_COLOR || !process.stdout.isTTY;
|
|
5332
|
+
var c = {
|
|
5333
|
+
reset: NO_COLOR ? "" : "\x1B[0m",
|
|
5334
|
+
bold: NO_COLOR ? "" : "\x1B[1m",
|
|
5335
|
+
dim: NO_COLOR ? "" : "\x1B[2m",
|
|
5336
|
+
red: NO_COLOR ? "" : "\x1B[31m",
|
|
5337
|
+
green: NO_COLOR ? "" : "\x1B[32m",
|
|
5338
|
+
yellow: NO_COLOR ? "" : "\x1B[33m",
|
|
5339
|
+
blue: NO_COLOR ? "" : "\x1B[34m",
|
|
5340
|
+
magenta: NO_COLOR ? "" : "\x1B[35m",
|
|
5341
|
+
cyan: NO_COLOR ? "" : "\x1B[36m",
|
|
5342
|
+
gray: NO_COLOR ? "" : "\x1B[90m"
|
|
5343
|
+
};
|
|
5212
5344
|
function ensureAuth() {
|
|
5213
5345
|
if (!PRIVATE_KEY) {
|
|
5214
|
-
console.error(
|
|
5346
|
+
console.error(`${c.red}Error:${c.reset} MEMOCLAW_PRIVATE_KEY environment variable required`);
|
|
5347
|
+
console.error(`${c.dim}Set it with: export MEMOCLAW_PRIVATE_KEY=0x...${c.reset}`);
|
|
5215
5348
|
process.exit(1);
|
|
5216
5349
|
}
|
|
5217
5350
|
}
|
|
@@ -5243,33 +5376,73 @@ async function getWalletAuthHeader() {
|
|
|
5243
5376
|
const signature = await account.signMessage({ message });
|
|
5244
5377
|
return `${account.address}:${timestamp}:${signature}`;
|
|
5245
5378
|
}
|
|
5246
|
-
function
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5271
|
-
|
|
5272
|
-
|
|
5379
|
+
async function readStdin() {
|
|
5380
|
+
if (process.stdin.isTTY)
|
|
5381
|
+
return null;
|
|
5382
|
+
const chunks = [];
|
|
5383
|
+
for await (const chunk of process.stdin)
|
|
5384
|
+
chunks.push(chunk.toString());
|
|
5385
|
+
const text = chunks.join("").trim();
|
|
5386
|
+
return text || null;
|
|
5387
|
+
}
|
|
5388
|
+
var outputJson = false;
|
|
5389
|
+
var outputQuiet = false;
|
|
5390
|
+
function out(data) {
|
|
5391
|
+
if (outputQuiet)
|
|
5392
|
+
return;
|
|
5393
|
+
if (outputJson) {
|
|
5394
|
+
console.log(JSON.stringify(data, null, 2));
|
|
5395
|
+
} else if (typeof data === "string") {
|
|
5396
|
+
console.log(data);
|
|
5397
|
+
} else {
|
|
5398
|
+
console.log(JSON.stringify(data, null, 2));
|
|
5399
|
+
}
|
|
5400
|
+
}
|
|
5401
|
+
function success(msg) {
|
|
5402
|
+
if (outputQuiet)
|
|
5403
|
+
return;
|
|
5404
|
+
if (outputJson)
|
|
5405
|
+
return;
|
|
5406
|
+
console.log(`${c.green}✓${c.reset} ${msg}`);
|
|
5407
|
+
}
|
|
5408
|
+
function info(msg) {
|
|
5409
|
+
if (outputQuiet)
|
|
5410
|
+
return;
|
|
5411
|
+
if (outputJson)
|
|
5412
|
+
return;
|
|
5413
|
+
console.error(`${c.blue}ℹ${c.reset} ${msg}`);
|
|
5414
|
+
}
|
|
5415
|
+
function table(rows, columns) {
|
|
5416
|
+
if (rows.length === 0)
|
|
5417
|
+
return;
|
|
5418
|
+
if (outputJson) {
|
|
5419
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
5420
|
+
return;
|
|
5421
|
+
}
|
|
5422
|
+
if (!columns) {
|
|
5423
|
+
columns = Object.keys(rows[0]).map((k) => ({ key: k, label: k.toUpperCase() }));
|
|
5424
|
+
}
|
|
5425
|
+
for (const col of columns) {
|
|
5426
|
+
if (!col.width) {
|
|
5427
|
+
col.width = Math.max(col.label.length, ...rows.map((r) => String(r[col.key] ?? "").length));
|
|
5428
|
+
col.width = Math.min(col.width, 60);
|
|
5429
|
+
}
|
|
5430
|
+
}
|
|
5431
|
+
const header = columns.map((col) => col.label.padEnd(col.width)).join(" ");
|
|
5432
|
+
console.log(`${c.bold}${header}${c.reset}`);
|
|
5433
|
+
console.log(`${c.dim}${columns.map((col) => "─".repeat(col.width)).join("──")}${c.reset}`);
|
|
5434
|
+
for (const row of rows) {
|
|
5435
|
+
const line = columns.map((col) => {
|
|
5436
|
+
const val = String(row[col.key] ?? "");
|
|
5437
|
+
return val.length > col.width ? val.slice(0, col.width - 1) + "…" : val.padEnd(col.width);
|
|
5438
|
+
}).join(" ");
|
|
5439
|
+
console.log(line);
|
|
5440
|
+
}
|
|
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}`;
|
|
5273
5446
|
}
|
|
5274
5447
|
async function request(method, path, body = null) {
|
|
5275
5448
|
const url = `${API_URL}${path}`;
|
|
@@ -5281,10 +5454,8 @@ async function request(method, path, body = null) {
|
|
|
5281
5454
|
headers["x-wallet-auth"] = walletAuth;
|
|
5282
5455
|
let res = await fetch(url, { ...options, headers });
|
|
5283
5456
|
const freeTierRemaining = res.headers.get("x-free-tier-remaining");
|
|
5284
|
-
if (freeTierRemaining !== null) {
|
|
5285
|
-
|
|
5286
|
-
console.error(`Free tier remaining: ${freeTierRemaining}`);
|
|
5287
|
-
}
|
|
5457
|
+
if (freeTierRemaining !== null && process.env.DEBUG) {
|
|
5458
|
+
console.error(`${c.dim}Free tier remaining: ${freeTierRemaining}${c.reset}`);
|
|
5288
5459
|
}
|
|
5289
5460
|
if (res.status === 402) {
|
|
5290
5461
|
const errorBody = await res.json();
|
|
@@ -5323,93 +5494,167 @@ async function request(method, path, body = null) {
|
|
|
5323
5494
|
}
|
|
5324
5495
|
return data;
|
|
5325
5496
|
}
|
|
5326
|
-
async function
|
|
5497
|
+
async function cmdStore(content, opts) {
|
|
5327
5498
|
const body = { content };
|
|
5328
|
-
if (opts.importance)
|
|
5499
|
+
if (opts.importance != null && opts.importance !== true)
|
|
5329
5500
|
body.importance = parseFloat(opts.importance);
|
|
5330
5501
|
if (opts.tags)
|
|
5331
5502
|
body.metadata = { tags: opts.tags.split(",").map((t) => t.trim()) };
|
|
5332
5503
|
if (opts.namespace)
|
|
5333
5504
|
body.namespace = opts.namespace;
|
|
5334
5505
|
const result = await request("POST", "/v1/store", body);
|
|
5335
|
-
|
|
5506
|
+
if (outputJson) {
|
|
5507
|
+
out(result);
|
|
5508
|
+
} else {
|
|
5509
|
+
success(`Memory stored${result.id ? ` (${c.cyan}${result.id}${c.reset})` : ""}`);
|
|
5510
|
+
if (result.importance !== undefined)
|
|
5511
|
+
info(`Importance: ${result.importance}`);
|
|
5512
|
+
}
|
|
5336
5513
|
}
|
|
5337
|
-
async function
|
|
5514
|
+
async function cmdRecall(query, opts) {
|
|
5338
5515
|
const body = { query };
|
|
5339
|
-
if (opts.limit)
|
|
5516
|
+
if (opts.limit != null && opts.limit !== true)
|
|
5340
5517
|
body.limit = parseInt(opts.limit);
|
|
5341
|
-
if (opts.minSimilarity)
|
|
5518
|
+
if (opts.minSimilarity != null && opts.minSimilarity !== true)
|
|
5342
5519
|
body.min_similarity = parseFloat(opts.minSimilarity);
|
|
5343
5520
|
if (opts.namespace)
|
|
5344
5521
|
body.namespace = opts.namespace;
|
|
5345
5522
|
if (opts.tags)
|
|
5346
5523
|
body.filters = { tags: opts.tags.split(",").map((t) => t.trim()) };
|
|
5347
5524
|
const result = await request("POST", "/v1/recall", body);
|
|
5348
|
-
if (
|
|
5349
|
-
|
|
5525
|
+
if (outputJson) {
|
|
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
|
+
}
|
|
5350
5532
|
} else {
|
|
5351
5533
|
const memories = result.memories || [];
|
|
5352
5534
|
if (memories.length === 0) {
|
|
5353
|
-
console.log(
|
|
5535
|
+
console.log(`${c.dim}No memories found.${c.reset}`);
|
|
5354
5536
|
} else {
|
|
5355
5537
|
for (const mem of memories) {
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5538
|
+
const sim = mem.similarity?.toFixed(3) || "???";
|
|
5539
|
+
const simColor = (mem.similarity || 0) > 0.8 ? c.green : (mem.similarity || 0) > 0.5 ? c.yellow : c.red;
|
|
5540
|
+
console.log(`${simColor}[${sim}]${c.reset} ${mem.content}`);
|
|
5541
|
+
if (mem.metadata?.tags?.length) {
|
|
5542
|
+
console.log(` ${c.dim}tags: ${mem.metadata.tags.join(", ")}${c.reset}`);
|
|
5543
|
+
}
|
|
5544
|
+
if (mem.id) {
|
|
5545
|
+
console.log(` ${c.dim}id: ${mem.id}${c.reset}`);
|
|
5546
|
+
}
|
|
5359
5547
|
}
|
|
5548
|
+
console.log(`${c.dim}─ ${memories.length} result${memories.length !== 1 ? "s" : ""}${c.reset}`);
|
|
5360
5549
|
}
|
|
5361
5550
|
}
|
|
5362
5551
|
}
|
|
5363
|
-
async function
|
|
5552
|
+
async function cmdList(opts) {
|
|
5364
5553
|
const params = new URLSearchParams;
|
|
5365
|
-
if (opts.limit)
|
|
5554
|
+
if (opts.limit != null && opts.limit !== true)
|
|
5366
5555
|
params.set("limit", opts.limit);
|
|
5367
|
-
if (opts.offset)
|
|
5556
|
+
if (opts.offset != null && opts.offset !== true)
|
|
5368
5557
|
params.set("offset", opts.offset);
|
|
5369
5558
|
if (opts.namespace)
|
|
5370
5559
|
params.set("namespace", opts.namespace);
|
|
5371
5560
|
const result = await request("GET", `/v1/memories?${params}`);
|
|
5372
|
-
|
|
5561
|
+
if (outputJson) {
|
|
5562
|
+
out(result);
|
|
5563
|
+
} else {
|
|
5564
|
+
const memories = result.memories || result.data || [];
|
|
5565
|
+
if (memories.length === 0) {
|
|
5566
|
+
console.log(`${c.dim}No memories found.${c.reset}`);
|
|
5567
|
+
} else {
|
|
5568
|
+
const rows = memories.map((m) => ({
|
|
5569
|
+
id: m.id?.slice(0, 8) || "?",
|
|
5570
|
+
content: m.content?.length > 50 ? m.content.slice(0, 50) + "…" : m.content || "",
|
|
5571
|
+
importance: m.importance?.toFixed(2) || "-",
|
|
5572
|
+
tags: m.metadata?.tags?.join(", ") || "",
|
|
5573
|
+
created: m.created_at ? new Date(m.created_at).toLocaleDateString() : ""
|
|
5574
|
+
}));
|
|
5575
|
+
table(rows, [
|
|
5576
|
+
{ key: "id", label: "ID", width: 10 },
|
|
5577
|
+
{ key: "content", label: "CONTENT", width: 52 },
|
|
5578
|
+
{ key: "importance", label: "IMP", width: 5 },
|
|
5579
|
+
{ key: "tags", label: "TAGS", width: 20 },
|
|
5580
|
+
{ key: "created", label: "CREATED", width: 12 }
|
|
5581
|
+
]);
|
|
5582
|
+
if (result.total !== undefined) {
|
|
5583
|
+
console.log(`${c.dim}─ ${memories.length} of ${result.total} memories${c.reset}`);
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
}
|
|
5373
5587
|
}
|
|
5374
|
-
async function
|
|
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
|
+
}
|
|
5612
|
+
async function cmdDelete(id) {
|
|
5375
5613
|
const result = await request("DELETE", `/v1/memories/${id}`);
|
|
5376
|
-
|
|
5614
|
+
if (outputJson) {
|
|
5615
|
+
out(result);
|
|
5616
|
+
} else {
|
|
5617
|
+
success(`Memory ${c.cyan}${id.slice(0, 8)}…${c.reset} deleted`);
|
|
5618
|
+
}
|
|
5377
5619
|
}
|
|
5378
|
-
async function
|
|
5620
|
+
async function cmdSuggested(opts) {
|
|
5379
5621
|
const params = new URLSearchParams;
|
|
5380
|
-
if (opts.limit)
|
|
5622
|
+
if (opts.limit != null && opts.limit !== true)
|
|
5381
5623
|
params.set("limit", opts.limit);
|
|
5382
5624
|
if (opts.namespace)
|
|
5383
5625
|
params.set("namespace", opts.namespace);
|
|
5384
5626
|
if (opts.category)
|
|
5385
5627
|
params.set("category", opts.category);
|
|
5386
5628
|
const result = await request("GET", `/v1/suggested?${params}`);
|
|
5387
|
-
if (
|
|
5388
|
-
|
|
5629
|
+
if (outputJson) {
|
|
5630
|
+
out(result);
|
|
5389
5631
|
} else {
|
|
5390
5632
|
if (result.categories) {
|
|
5391
|
-
|
|
5392
|
-
console.log(
|
|
5633
|
+
const cats = Object.entries(result.categories).map(([k, v]) => `${c.bold}${k}${c.reset}=${v}`).join(" ");
|
|
5634
|
+
console.log(`Categories: ${cats}`);
|
|
5635
|
+
console.log(`${c.dim}${"─".repeat(60)}${c.reset}`);
|
|
5393
5636
|
}
|
|
5394
5637
|
const suggestions = result.suggested || [];
|
|
5395
5638
|
if (suggestions.length === 0) {
|
|
5396
|
-
console.log(
|
|
5639
|
+
console.log(`${c.dim}No suggested memories.${c.reset}`);
|
|
5397
5640
|
} else {
|
|
5398
5641
|
for (const mem of suggestions) {
|
|
5399
5642
|
const cat = mem.category?.toUpperCase() || "???";
|
|
5400
|
-
const
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5643
|
+
const catColor = { STALE: c.red, FRESH: c.green, HOT: c.yellow, DECAYING: c.magenta }[cat] || c.gray;
|
|
5644
|
+
const text = mem.content.length > 100 ? mem.content.slice(0, 100) + "…" : mem.content;
|
|
5645
|
+
console.log(`${catColor}[${cat}]${c.reset} ${c.dim}(${mem.review_score?.toFixed(2) || "?"})${c.reset} ${text}`);
|
|
5646
|
+
if (mem.metadata?.tags?.length) {
|
|
5647
|
+
console.log(` ${c.dim}tags: ${mem.metadata.tags.join(", ")}${c.reset}`);
|
|
5648
|
+
}
|
|
5404
5649
|
}
|
|
5405
5650
|
}
|
|
5406
5651
|
}
|
|
5407
5652
|
}
|
|
5408
|
-
async function
|
|
5653
|
+
async function cmdUpdate(id, opts) {
|
|
5409
5654
|
const body = {};
|
|
5410
5655
|
if (opts.content)
|
|
5411
5656
|
body.content = opts.content;
|
|
5412
|
-
if (opts.importance)
|
|
5657
|
+
if (opts.importance != null && opts.importance !== true)
|
|
5413
5658
|
body.importance = parseFloat(opts.importance);
|
|
5414
5659
|
if (opts.memoryType)
|
|
5415
5660
|
body.memory_type = opts.memoryType;
|
|
@@ -5421,10 +5666,17 @@ async function update(id, opts) {
|
|
|
5421
5666
|
body.expires_at = opts.expiresAt;
|
|
5422
5667
|
if (opts.pinned !== undefined)
|
|
5423
5668
|
body.pinned = opts.pinned === "true" || opts.pinned === true;
|
|
5669
|
+
if (Object.keys(body).length === 0) {
|
|
5670
|
+
throw new Error("No fields to update. Use --content, --importance, --tags, etc.");
|
|
5671
|
+
}
|
|
5424
5672
|
const result = await request("PATCH", `/v1/memories/${id}`, body);
|
|
5425
|
-
|
|
5673
|
+
if (outputJson) {
|
|
5674
|
+
out(result);
|
|
5675
|
+
} else {
|
|
5676
|
+
success(`Memory ${c.cyan}${id.slice(0, 8)}…${c.reset} updated`);
|
|
5677
|
+
}
|
|
5426
5678
|
}
|
|
5427
|
-
async function
|
|
5679
|
+
async function cmdIngest(opts) {
|
|
5428
5680
|
const body = {};
|
|
5429
5681
|
if (opts.text)
|
|
5430
5682
|
body.text = opts.text;
|
|
@@ -5438,18 +5690,22 @@ async function ingest(opts) {
|
|
|
5438
5690
|
body.auto_relate = opts.autoRelate !== "false";
|
|
5439
5691
|
else
|
|
5440
5692
|
body.auto_relate = true;
|
|
5441
|
-
if (!body.text
|
|
5442
|
-
const
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
body.text = chunks.join("");
|
|
5693
|
+
if (!body.text) {
|
|
5694
|
+
const stdin = await readStdin();
|
|
5695
|
+
if (stdin)
|
|
5696
|
+
body.text = stdin;
|
|
5446
5697
|
}
|
|
5447
5698
|
if (!body.text)
|
|
5448
5699
|
throw new Error("Text required (use --text or pipe via stdin)");
|
|
5449
5700
|
const result = await request("POST", "/v1/ingest", body);
|
|
5450
|
-
|
|
5701
|
+
if (outputJson) {
|
|
5702
|
+
out(result);
|
|
5703
|
+
} else {
|
|
5704
|
+
const count = result.memories_created ?? result.count ?? "?";
|
|
5705
|
+
success(`Ingested text → ${count} memories created`);
|
|
5706
|
+
}
|
|
5451
5707
|
}
|
|
5452
|
-
async function
|
|
5708
|
+
async function cmdExtract(text, opts) {
|
|
5453
5709
|
const body = { text };
|
|
5454
5710
|
if (opts.namespace)
|
|
5455
5711
|
body.namespace = opts.namespace;
|
|
@@ -5458,206 +5714,710 @@ async function extract(text, opts) {
|
|
|
5458
5714
|
if (opts.agentId)
|
|
5459
5715
|
body.agent_id = opts.agentId;
|
|
5460
5716
|
const result = await request("POST", "/v1/memories/extract", body);
|
|
5461
|
-
|
|
5717
|
+
out(result);
|
|
5462
5718
|
}
|
|
5463
|
-
async function
|
|
5719
|
+
async function cmdConsolidate(opts) {
|
|
5464
5720
|
const body = {};
|
|
5465
5721
|
if (opts.namespace)
|
|
5466
5722
|
body.namespace = opts.namespace;
|
|
5467
|
-
if (opts.minSimilarity)
|
|
5723
|
+
if (opts.minSimilarity != null && opts.minSimilarity !== true)
|
|
5468
5724
|
body.min_similarity = parseFloat(opts.minSimilarity);
|
|
5469
5725
|
if (opts.mode)
|
|
5470
5726
|
body.mode = opts.mode;
|
|
5471
5727
|
if (opts.dryRun !== undefined)
|
|
5472
5728
|
body.dry_run = true;
|
|
5473
5729
|
const result = await request("POST", "/v1/memories/consolidate", body);
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5730
|
+
if (outputJson) {
|
|
5731
|
+
out(result);
|
|
5732
|
+
} else {
|
|
5733
|
+
if (opts.dryRun) {
|
|
5734
|
+
info("Dry run — no changes applied");
|
|
5735
|
+
}
|
|
5736
|
+
const merged = result.merged_count ?? result.merged ?? "?";
|
|
5737
|
+
success(`Consolidated: ${merged} memories merged`);
|
|
5738
|
+
if (result.clusters) {
|
|
5739
|
+
info(`Clusters found: ${result.clusters.length}`);
|
|
5740
|
+
}
|
|
5741
|
+
}
|
|
5484
5742
|
}
|
|
5485
|
-
async function
|
|
5486
|
-
|
|
5487
|
-
|
|
5743
|
+
async function cmdRelations(subcmd, rest, opts) {
|
|
5744
|
+
if (subcmd === "list") {
|
|
5745
|
+
if (!rest[0])
|
|
5746
|
+
throw new Error("Memory ID required");
|
|
5747
|
+
const result = await request("GET", `/v1/memories/${rest[0]}/relations`);
|
|
5748
|
+
if (outputJson) {
|
|
5749
|
+
out(result);
|
|
5750
|
+
} else {
|
|
5751
|
+
const relations = result.relations || [];
|
|
5752
|
+
if (relations.length === 0) {
|
|
5753
|
+
console.log(`${c.dim}No relations found.${c.reset}`);
|
|
5754
|
+
} else {
|
|
5755
|
+
const rows = relations.map((r) => ({
|
|
5756
|
+
id: r.id?.slice(0, 8) || "?",
|
|
5757
|
+
type: r.relation_type || "?",
|
|
5758
|
+
target: r.target_id?.slice(0, 8) || "?"
|
|
5759
|
+
}));
|
|
5760
|
+
table(rows, [
|
|
5761
|
+
{ key: "id", label: "ID", width: 10 },
|
|
5762
|
+
{ key: "type", label: "TYPE", width: 16 },
|
|
5763
|
+
{ key: "target", label: "TARGET", width: 10 }
|
|
5764
|
+
]);
|
|
5765
|
+
}
|
|
5766
|
+
}
|
|
5767
|
+
} else if (subcmd === "create") {
|
|
5768
|
+
if (!rest[0] || !rest[1] || !rest[2])
|
|
5769
|
+
throw new Error("Usage: relations create <memory-id> <target-id> <type>");
|
|
5770
|
+
const validTypes = ["related_to", "derived_from", "contradicts", "supersedes", "supports"];
|
|
5771
|
+
if (!validTypes.includes(rest[2])) {
|
|
5772
|
+
throw new Error(`Invalid relation type "${rest[2]}". Valid: ${validTypes.join(", ")}`);
|
|
5773
|
+
}
|
|
5774
|
+
const body = { target_id: rest[1], relation_type: rest[2] };
|
|
5775
|
+
const result = await request("POST", `/v1/memories/${rest[0]}/relations`, body);
|
|
5776
|
+
if (outputJson) {
|
|
5777
|
+
out(result);
|
|
5778
|
+
} else {
|
|
5779
|
+
success(`Relation created: ${rest[0].slice(0, 8)}… ${c.cyan}${rest[2]}${c.reset} → ${rest[1].slice(0, 8)}…`);
|
|
5780
|
+
}
|
|
5781
|
+
} else if (subcmd === "delete") {
|
|
5782
|
+
if (!rest[0] || !rest[1])
|
|
5783
|
+
throw new Error("Usage: relations delete <memory-id> <relation-id>");
|
|
5784
|
+
const result = await request("DELETE", `/v1/memories/${rest[0]}/relations/${rest[1]}`);
|
|
5785
|
+
if (outputJson) {
|
|
5786
|
+
out(result);
|
|
5787
|
+
} else {
|
|
5788
|
+
success("Relation deleted");
|
|
5789
|
+
}
|
|
5790
|
+
} else {
|
|
5791
|
+
throw new Error("Usage: relations [list|create|delete]");
|
|
5792
|
+
}
|
|
5488
5793
|
}
|
|
5489
|
-
async function
|
|
5794
|
+
async function cmdStatus() {
|
|
5490
5795
|
const walletAuth = await getWalletAuthHeader();
|
|
5491
5796
|
const res = await fetch(`${API_URL}/v1/free-tier/status`, {
|
|
5492
5797
|
headers: { "x-wallet-auth": walletAuth }
|
|
5493
5798
|
});
|
|
5494
5799
|
if (res.ok) {
|
|
5495
5800
|
const data = await res.json();
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
console.log(
|
|
5801
|
+
if (outputJson) {
|
|
5802
|
+
out(data);
|
|
5803
|
+
} else {
|
|
5804
|
+
console.log(`${c.bold}Wallet:${c.reset} ${data.wallet}`);
|
|
5805
|
+
const remaining = data.free_tier_remaining ?? 0;
|
|
5806
|
+
const total = data.free_tier_total ?? 1000;
|
|
5807
|
+
const pct = Math.round(remaining / total * 100);
|
|
5808
|
+
const barLen = 20;
|
|
5809
|
+
const filled = Math.round(remaining / total * barLen);
|
|
5810
|
+
const bar = `${c.green}${"█".repeat(filled)}${c.dim}${"░".repeat(barLen - filled)}${c.reset}`;
|
|
5811
|
+
console.log(`${c.bold}Free tier:${c.reset} ${remaining}/${total} calls remaining`);
|
|
5812
|
+
console.log(` ${bar} ${pct}%`);
|
|
5813
|
+
if (remaining === 0) {
|
|
5814
|
+
console.log(`${c.yellow}→ Next calls will use x402 payment ($0.001/call)${c.reset}`);
|
|
5815
|
+
}
|
|
5500
5816
|
}
|
|
5501
5817
|
} else {
|
|
5502
5818
|
const err = await res.json();
|
|
5503
5819
|
throw new Error(err.error?.message || "Failed to get status");
|
|
5504
5820
|
}
|
|
5505
5821
|
}
|
|
5506
|
-
function
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5556
|
-
|
|
5557
|
-
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5822
|
+
async function cmdExport(opts) {
|
|
5823
|
+
const params = new URLSearchParams;
|
|
5824
|
+
if (opts.namespace)
|
|
5825
|
+
params.set("namespace", opts.namespace);
|
|
5826
|
+
params.set("limit", opts.limit || "1000");
|
|
5827
|
+
let offset = 0;
|
|
5828
|
+
const allMemories = [];
|
|
5829
|
+
const limit = parseInt(opts.limit || "1000");
|
|
5830
|
+
while (true) {
|
|
5831
|
+
params.set("offset", String(offset));
|
|
5832
|
+
const result = await request("GET", `/v1/memories?${params}`);
|
|
5833
|
+
const memories = result.memories || result.data || [];
|
|
5834
|
+
allMemories.push(...memories);
|
|
5835
|
+
if (memories.length < limit)
|
|
5836
|
+
break;
|
|
5837
|
+
offset += limit;
|
|
5838
|
+
if (!outputQuiet)
|
|
5839
|
+
process.stderr.write(`${c.dim}Fetched ${allMemories.length} memories...${c.reset}\r`);
|
|
5840
|
+
}
|
|
5841
|
+
const exportData = {
|
|
5842
|
+
version: 1,
|
|
5843
|
+
exported_at: new Date().toISOString(),
|
|
5844
|
+
count: allMemories.length,
|
|
5845
|
+
memories: allMemories
|
|
5846
|
+
};
|
|
5847
|
+
console.log(JSON.stringify(exportData, null, 2));
|
|
5848
|
+
if (!outputQuiet) {
|
|
5849
|
+
console.error(`${c.green}✓${c.reset} Exported ${allMemories.length} memories`);
|
|
5850
|
+
}
|
|
5851
|
+
}
|
|
5852
|
+
async function cmdImport(opts) {
|
|
5853
|
+
let jsonText;
|
|
5854
|
+
if (opts.file) {
|
|
5855
|
+
const fs = await import("fs");
|
|
5856
|
+
jsonText = fs.readFileSync(opts.file, "utf-8");
|
|
5857
|
+
} else {
|
|
5858
|
+
const stdin = await readStdin();
|
|
5859
|
+
if (!stdin)
|
|
5860
|
+
throw new Error("Provide --file <path> or pipe JSON via stdin");
|
|
5861
|
+
jsonText = stdin;
|
|
5862
|
+
}
|
|
5863
|
+
const data = JSON.parse(jsonText);
|
|
5864
|
+
const memories = data.memories || data;
|
|
5865
|
+
if (!Array.isArray(memories))
|
|
5866
|
+
throw new Error("Invalid format: expected { memories: [...] } or [...]");
|
|
5867
|
+
let imported = 0;
|
|
5868
|
+
let failed = 0;
|
|
5869
|
+
for (const mem of memories) {
|
|
5870
|
+
try {
|
|
5871
|
+
const body = { content: mem.content };
|
|
5872
|
+
if (mem.importance !== undefined)
|
|
5873
|
+
body.importance = mem.importance;
|
|
5874
|
+
if (mem.metadata)
|
|
5875
|
+
body.metadata = mem.metadata;
|
|
5876
|
+
if (mem.namespace || opts.namespace)
|
|
5877
|
+
body.namespace = mem.namespace || opts.namespace;
|
|
5878
|
+
await request("POST", "/v1/store", body);
|
|
5879
|
+
imported++;
|
|
5880
|
+
if (!outputQuiet) {
|
|
5881
|
+
process.stderr.write(`\r ${progressBar(imported, memories.length)}`);
|
|
5882
|
+
}
|
|
5883
|
+
} catch (e) {
|
|
5884
|
+
failed++;
|
|
5885
|
+
if (process.env.DEBUG)
|
|
5886
|
+
console.error(`Failed to import: ${e.message}`);
|
|
5887
|
+
}
|
|
5888
|
+
}
|
|
5889
|
+
if (!outputQuiet)
|
|
5890
|
+
process.stderr.write(`
|
|
5891
|
+
`);
|
|
5892
|
+
if (outputJson) {
|
|
5893
|
+
out({ imported, failed, total: memories.length });
|
|
5894
|
+
} else {
|
|
5895
|
+
success(`Imported ${imported}/${memories.length} memories${failed ? ` (${c.red}${failed} failed${c.reset})` : ""}`);
|
|
5896
|
+
}
|
|
5897
|
+
}
|
|
5898
|
+
async function cmdStats(opts) {
|
|
5899
|
+
const params = new URLSearchParams;
|
|
5900
|
+
if (opts.namespace)
|
|
5901
|
+
params.set("namespace", opts.namespace);
|
|
5902
|
+
params.set("limit", "1");
|
|
5903
|
+
const result = await request("GET", `/v1/memories?${params}`);
|
|
5904
|
+
const total = result.total ?? "?";
|
|
5905
|
+
const walletAuth = await getWalletAuthHeader();
|
|
5906
|
+
const statusRes = await fetch(`${API_URL}/v1/free-tier/status`, {
|
|
5907
|
+
headers: { "x-wallet-auth": walletAuth }
|
|
5908
|
+
});
|
|
5909
|
+
let tierData = {};
|
|
5910
|
+
if (statusRes.ok) {
|
|
5911
|
+
tierData = await statusRes.json();
|
|
5912
|
+
}
|
|
5913
|
+
if (outputJson) {
|
|
5914
|
+
out({
|
|
5915
|
+
total_memories: total,
|
|
5916
|
+
api_url: API_URL,
|
|
5917
|
+
wallet: tierData.wallet || getAccount().address,
|
|
5918
|
+
free_tier_remaining: tierData.free_tier_remaining,
|
|
5919
|
+
free_tier_total: tierData.free_tier_total
|
|
5920
|
+
});
|
|
5921
|
+
} else {
|
|
5922
|
+
console.log(`${c.bold}MemoClaw Stats${c.reset}`);
|
|
5923
|
+
console.log(`${c.dim}${"─".repeat(40)}${c.reset}`);
|
|
5924
|
+
console.log(`Memories: ${c.cyan}${total}${c.reset}`);
|
|
5925
|
+
console.log(`API: ${c.dim}${API_URL}${c.reset}`);
|
|
5926
|
+
console.log(`Wallet: ${c.dim}${tierData.wallet || getAccount().address}${c.reset}`);
|
|
5927
|
+
if (tierData.free_tier_remaining !== undefined) {
|
|
5928
|
+
console.log(`Free calls left: ${c.cyan}${tierData.free_tier_remaining}${c.reset}/${tierData.free_tier_total}`);
|
|
5929
|
+
}
|
|
5930
|
+
if (opts.namespace) {
|
|
5931
|
+
console.log(`Namespace: ${c.cyan}${opts.namespace}${c.reset}`);
|
|
5932
|
+
}
|
|
5933
|
+
}
|
|
5934
|
+
}
|
|
5935
|
+
async function cmdCompletions(shell) {
|
|
5936
|
+
const commands = [
|
|
5937
|
+
"store",
|
|
5938
|
+
"recall",
|
|
5939
|
+
"list",
|
|
5940
|
+
"get",
|
|
5941
|
+
"update",
|
|
5942
|
+
"delete",
|
|
5943
|
+
"ingest",
|
|
5944
|
+
"extract",
|
|
5945
|
+
"consolidate",
|
|
5946
|
+
"relations",
|
|
5947
|
+
"suggested",
|
|
5948
|
+
"status",
|
|
5949
|
+
"export",
|
|
5950
|
+
"import",
|
|
5951
|
+
"stats",
|
|
5952
|
+
"browse",
|
|
5953
|
+
"completions",
|
|
5954
|
+
"config"
|
|
5955
|
+
];
|
|
5956
|
+
if (shell === "bash") {
|
|
5957
|
+
console.log(`# Add to ~/.bashrc:
|
|
5958
|
+
# eval "$(memoclaw completions bash)"
|
|
5959
|
+
_memoclaw() {
|
|
5960
|
+
local cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
5961
|
+
local cmds="${commands.join(" ")}"
|
|
5962
|
+
if [ "$COMP_CWORD" -eq 1 ]; then
|
|
5963
|
+
COMPREPLY=( $(compgen -W "$cmds" -- "$cur") )
|
|
5964
|
+
fi
|
|
5965
|
+
}
|
|
5966
|
+
complete -F _memoclaw memoclaw`);
|
|
5967
|
+
} else if (shell === "zsh") {
|
|
5968
|
+
console.log(`# Add to ~/.zshrc:
|
|
5969
|
+
# eval "$(memoclaw completions zsh)"
|
|
5970
|
+
_memoclaw() {
|
|
5971
|
+
local -a commands=(${commands.map((c2) => `'${c2}'`).join(" ")})
|
|
5972
|
+
_describe 'command' commands
|
|
5973
|
+
}
|
|
5974
|
+
compdef _memoclaw memoclaw`);
|
|
5975
|
+
} else if (shell === "fish") {
|
|
5976
|
+
console.log(`# Add to ~/.config/fish/completions/memoclaw.fish:
|
|
5977
|
+
${commands.map((cmd) => `complete -c memoclaw -n '__fish_use_subcommand' -a '${cmd}'`).join(`
|
|
5978
|
+
`)}`);
|
|
5979
|
+
} else {
|
|
5980
|
+
throw new Error(`Unknown shell: ${shell}. Supported: bash, zsh, fish`);
|
|
5981
|
+
}
|
|
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
|
+
}
|
|
6163
|
+
function printHelp(command) {
|
|
6164
|
+
if (command) {
|
|
6165
|
+
const subHelp = {
|
|
6166
|
+
store: `${c.bold}memoclaw store${c.reset} "content" [options]
|
|
6167
|
+
|
|
6168
|
+
Store a memory. Supports piping: ${c.dim}echo "content" | memoclaw store${c.reset}
|
|
6169
|
+
|
|
6170
|
+
Options:
|
|
6171
|
+
--importance <0-1> Importance score (default: 0.5)
|
|
6172
|
+
--tags <tag1,tag2> Comma-separated tags
|
|
6173
|
+
--namespace <name> Memory namespace`,
|
|
6174
|
+
recall: `${c.bold}memoclaw recall${c.reset} "query" [options]
|
|
6175
|
+
|
|
6176
|
+
Search memories by semantic similarity.
|
|
5569
6177
|
|
|
5570
6178
|
Options:
|
|
5571
|
-
--
|
|
5572
|
-
--
|
|
6179
|
+
--limit <n> Max results (default: 10)
|
|
6180
|
+
--min-similarity <0-1> Similarity threshold (default: 0.5)
|
|
6181
|
+
--namespace <name> Filter by namespace
|
|
6182
|
+
--tags <tag1,tag2> Filter by tags`,
|
|
6183
|
+
list: `${c.bold}memoclaw list${c.reset} [options]
|
|
6184
|
+
|
|
6185
|
+
List all memories in a table format.
|
|
5573
6186
|
|
|
5574
|
-
|
|
6187
|
+
Options:
|
|
6188
|
+
--limit <n> Max results (default: 20)
|
|
6189
|
+
--offset <n> Pagination offset
|
|
6190
|
+
--namespace <name> Filter by namespace`,
|
|
6191
|
+
export: `${c.bold}memoclaw export${c.reset} [options]
|
|
6192
|
+
|
|
6193
|
+
Export all memories as JSON. Useful for backups.
|
|
6194
|
+
|
|
6195
|
+
${c.dim}memoclaw export > backup.json${c.reset}
|
|
6196
|
+
${c.dim}memoclaw export --namespace project1 > project1.json${c.reset}
|
|
6197
|
+
|
|
6198
|
+
Options:
|
|
6199
|
+
--namespace <name> Filter by namespace
|
|
6200
|
+
--limit <n> Max per page (default: 1000)`,
|
|
6201
|
+
import: `${c.bold}memoclaw import${c.reset} [options]
|
|
6202
|
+
|
|
6203
|
+
Import memories from JSON file or stdin.
|
|
6204
|
+
|
|
6205
|
+
${c.dim}memoclaw import --file backup.json${c.reset}
|
|
6206
|
+
${c.dim}cat backup.json | memoclaw import${c.reset}
|
|
6207
|
+
|
|
6208
|
+
Options:
|
|
6209
|
+
--file <path> JSON file to import
|
|
6210
|
+
--namespace <name> Override namespace for all memories`,
|
|
6211
|
+
stats: `${c.bold}memoclaw stats${c.reset} [options]
|
|
6212
|
+
|
|
6213
|
+
Show memory statistics and account info.
|
|
6214
|
+
|
|
6215
|
+
Options:
|
|
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`,
|
|
6236
|
+
completions: `${c.bold}memoclaw completions${c.reset} <bash|zsh|fish>
|
|
6237
|
+
|
|
6238
|
+
Generate shell completion scripts.
|
|
6239
|
+
|
|
6240
|
+
${c.dim}eval "$(memoclaw completions bash)"${c.reset}
|
|
6241
|
+
${c.dim}eval "$(memoclaw completions zsh)"${c.reset}
|
|
6242
|
+
${c.dim}memoclaw completions fish > ~/.config/fish/completions/memoclaw.fish${c.reset}`
|
|
6243
|
+
};
|
|
6244
|
+
if (subHelp[command]) {
|
|
6245
|
+
console.log(subHelp[command]);
|
|
6246
|
+
} else {
|
|
6247
|
+
console.log(`No detailed help for "${command}". Run ${c.dim}memoclaw --help${c.reset} for overview.`);
|
|
6248
|
+
}
|
|
6249
|
+
return;
|
|
6250
|
+
}
|
|
6251
|
+
console.log(`${c.bold}MemoClaw CLI${c.reset} ${c.dim}v${VERSION}${c.reset} — Memory-as-a-Service for AI agents
|
|
6252
|
+
|
|
6253
|
+
${c.bold}Usage:${c.reset}
|
|
6254
|
+
memoclaw <command> [options]
|
|
6255
|
+
|
|
6256
|
+
${c.bold}Commands:${c.reset}
|
|
6257
|
+
${c.cyan}store${c.reset} "content" Store a memory (also accepts stdin)
|
|
6258
|
+
${c.cyan}recall${c.reset} "query" Search memories by similarity
|
|
6259
|
+
${c.cyan}list${c.reset} List memories in a table
|
|
6260
|
+
${c.cyan}get${c.reset} <id> Get a single memory by ID
|
|
6261
|
+
${c.cyan}update${c.reset} <id> Update a memory
|
|
6262
|
+
${c.cyan}delete${c.reset} <id> Delete a memory
|
|
6263
|
+
${c.cyan}ingest${c.reset} Ingest raw text into memories
|
|
6264
|
+
${c.cyan}extract${c.reset} "text" Extract memories from text
|
|
6265
|
+
${c.cyan}consolidate${c.reset} Merge similar memories
|
|
6266
|
+
${c.cyan}relations${c.reset} <sub> Manage memory relations
|
|
6267
|
+
${c.cyan}suggested${c.reset} Get suggested memories for review
|
|
6268
|
+
${c.cyan}status${c.reset} Check account & free tier info
|
|
6269
|
+
${c.cyan}stats${c.reset} Memory statistics
|
|
6270
|
+
${c.cyan}export${c.reset} Export all memories as JSON
|
|
6271
|
+
${c.cyan}import${c.reset} Import memories from JSON
|
|
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
|
|
6275
|
+
|
|
6276
|
+
${c.bold}Global Options:${c.reset}
|
|
6277
|
+
-h, --help Show help (use with command for details)
|
|
6278
|
+
-v, --version Show version
|
|
6279
|
+
-j, --json Output as JSON (machine-readable)
|
|
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)
|
|
6285
|
+
|
|
6286
|
+
${c.bold}Environment:${c.reset}
|
|
5575
6287
|
MEMOCLAW_PRIVATE_KEY Wallet private key for auth + payments
|
|
5576
6288
|
MEMOCLAW_URL API endpoint (default: https://api.memoclaw.com)
|
|
6289
|
+
NO_COLOR Disable colored output
|
|
6290
|
+
DEBUG Enable debug logging
|
|
5577
6291
|
|
|
5578
|
-
|
|
6292
|
+
${c.bold}Piping:${c.reset}
|
|
6293
|
+
echo "meeting notes" | memoclaw store
|
|
6294
|
+
echo "long text" | memoclaw ingest
|
|
6295
|
+
memoclaw export | jq '.memories | length'
|
|
6296
|
+
cat backup.json | memoclaw import
|
|
6297
|
+
|
|
6298
|
+
${c.bold}Free Tier:${c.reset}
|
|
5579
6299
|
Every wallet gets 1000 free API calls. After that, x402
|
|
5580
6300
|
micropayments kick in automatically ($0.001/call USDC on Base).
|
|
5581
6301
|
|
|
5582
|
-
API: https://api.memoclaw.com`);
|
|
6302
|
+
${c.dim}API: https://api.memoclaw.com${c.reset}`);
|
|
5583
6303
|
}
|
|
5584
6304
|
var args = parseArgs(process.argv.slice(2));
|
|
5585
6305
|
var [cmd, ...rest] = args._;
|
|
6306
|
+
outputJson = !!args.json;
|
|
6307
|
+
outputQuiet = !!args.quiet;
|
|
5586
6308
|
if (args.version) {
|
|
5587
|
-
console.log(
|
|
6309
|
+
console.log(`memoclaw ${VERSION}`);
|
|
5588
6310
|
process.exit(0);
|
|
5589
6311
|
}
|
|
5590
|
-
if (
|
|
6312
|
+
if (!cmd && args._.length === 0) {
|
|
5591
6313
|
printHelp();
|
|
5592
6314
|
process.exit(0);
|
|
5593
6315
|
}
|
|
6316
|
+
if (args.help) {
|
|
6317
|
+
printHelp(cmd);
|
|
6318
|
+
process.exit(0);
|
|
6319
|
+
}
|
|
5594
6320
|
try {
|
|
5595
6321
|
switch (cmd) {
|
|
5596
|
-
case "store":
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
6322
|
+
case "store": {
|
|
6323
|
+
let content = rest[0];
|
|
6324
|
+
if (!content) {
|
|
6325
|
+
const stdin = await readStdin();
|
|
6326
|
+
if (stdin)
|
|
6327
|
+
content = stdin;
|
|
6328
|
+
}
|
|
6329
|
+
if (!content)
|
|
6330
|
+
throw new Error("Content required. Provide as argument or pipe via stdin.");
|
|
6331
|
+
await cmdStore(content, args);
|
|
5600
6332
|
break;
|
|
6333
|
+
}
|
|
5601
6334
|
case "recall":
|
|
5602
6335
|
if (!rest[0])
|
|
5603
6336
|
throw new Error("Query required");
|
|
5604
|
-
await
|
|
6337
|
+
await cmdRecall(rest[0], args);
|
|
5605
6338
|
break;
|
|
5606
6339
|
case "list":
|
|
5607
|
-
await
|
|
6340
|
+
await cmdList(args);
|
|
6341
|
+
break;
|
|
6342
|
+
case "get":
|
|
6343
|
+
if (!rest[0])
|
|
6344
|
+
throw new Error("Memory ID required");
|
|
6345
|
+
await cmdGet(rest[0]);
|
|
5608
6346
|
break;
|
|
5609
6347
|
case "update":
|
|
5610
6348
|
if (!rest[0])
|
|
5611
6349
|
throw new Error("Memory ID required");
|
|
5612
|
-
await
|
|
6350
|
+
await cmdUpdate(rest[0], args);
|
|
5613
6351
|
break;
|
|
5614
6352
|
case "delete":
|
|
5615
6353
|
if (!rest[0])
|
|
5616
6354
|
throw new Error("Memory ID required");
|
|
5617
|
-
await
|
|
6355
|
+
await cmdDelete(rest[0]);
|
|
5618
6356
|
break;
|
|
5619
6357
|
case "ingest":
|
|
5620
|
-
await
|
|
6358
|
+
await cmdIngest(args);
|
|
5621
6359
|
break;
|
|
5622
|
-
case "extract":
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
6360
|
+
case "extract": {
|
|
6361
|
+
let text = rest[0];
|
|
6362
|
+
if (!text) {
|
|
6363
|
+
const stdin = await readStdin();
|
|
6364
|
+
if (stdin)
|
|
6365
|
+
text = stdin;
|
|
6366
|
+
}
|
|
6367
|
+
if (!text)
|
|
6368
|
+
throw new Error("Text required. Provide as argument or pipe via stdin.");
|
|
6369
|
+
await cmdExtract(text, args);
|
|
5626
6370
|
break;
|
|
6371
|
+
}
|
|
5627
6372
|
case "consolidate":
|
|
5628
|
-
await
|
|
6373
|
+
await cmdConsolidate(args);
|
|
5629
6374
|
break;
|
|
5630
6375
|
case "relations": {
|
|
5631
6376
|
const subcmd = rest[0];
|
|
5632
|
-
if (subcmd
|
|
5633
|
-
if (!rest[1])
|
|
5634
|
-
throw new Error("Memory ID required");
|
|
5635
|
-
await listRelations(rest[1]);
|
|
5636
|
-
} else if (subcmd === "create") {
|
|
5637
|
-
if (!rest[1] || !rest[2] || !rest[3])
|
|
5638
|
-
throw new Error("Usage: relations create <memory-id> <target-id> <type>");
|
|
5639
|
-
await createRelation(rest[1], rest[2], rest[3], args);
|
|
5640
|
-
} else if (subcmd === "delete") {
|
|
5641
|
-
if (!rest[1] || !rest[2])
|
|
5642
|
-
throw new Error("Usage: relations delete <memory-id> <relation-id>");
|
|
5643
|
-
await deleteRelation(rest[1], rest[2]);
|
|
5644
|
-
} else {
|
|
6377
|
+
if (!subcmd)
|
|
5645
6378
|
throw new Error("Usage: relations [list|create|delete]");
|
|
5646
|
-
|
|
6379
|
+
await cmdRelations(subcmd, rest.slice(1), args);
|
|
5647
6380
|
break;
|
|
5648
6381
|
}
|
|
5649
6382
|
case "suggested":
|
|
5650
|
-
await
|
|
6383
|
+
await cmdSuggested(args);
|
|
5651
6384
|
break;
|
|
5652
6385
|
case "status":
|
|
5653
|
-
await
|
|
6386
|
+
await cmdStatus();
|
|
6387
|
+
break;
|
|
6388
|
+
case "export":
|
|
6389
|
+
await cmdExport(args);
|
|
6390
|
+
break;
|
|
6391
|
+
case "import":
|
|
6392
|
+
await cmdImport(args);
|
|
6393
|
+
break;
|
|
6394
|
+
case "stats":
|
|
6395
|
+
await cmdStats(args);
|
|
6396
|
+
break;
|
|
6397
|
+
case "completions":
|
|
6398
|
+
if (!rest[0])
|
|
6399
|
+
throw new Error("Shell required: bash, zsh, or fish");
|
|
6400
|
+
await cmdCompletions(rest[0]);
|
|
6401
|
+
break;
|
|
6402
|
+
case "browse":
|
|
6403
|
+
await cmdBrowse(args);
|
|
6404
|
+
break;
|
|
6405
|
+
case "config":
|
|
6406
|
+
await cmdConfig(rest[0], rest.slice(1));
|
|
6407
|
+
break;
|
|
6408
|
+
case "help":
|
|
6409
|
+
printHelp(rest[0]);
|
|
5654
6410
|
break;
|
|
5655
6411
|
default:
|
|
5656
|
-
console.error(
|
|
5657
|
-
console.error(
|
|
6412
|
+
console.error(`${c.red}Unknown command: ${cmd}${c.reset}`);
|
|
6413
|
+
console.error(`Run ${c.dim}memoclaw --help${c.reset} for usage.`);
|
|
5658
6414
|
process.exit(1);
|
|
5659
6415
|
}
|
|
5660
6416
|
} catch (err) {
|
|
5661
|
-
|
|
6417
|
+
if (outputJson) {
|
|
6418
|
+
console.error(JSON.stringify({ error: err.message }));
|
|
6419
|
+
} else {
|
|
6420
|
+
console.error(`${c.red}Error:${c.reset} ${err.message}`);
|
|
6421
|
+
}
|
|
5662
6422
|
process.exit(1);
|
|
5663
6423
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "memoclaw",
|
|
3
|
-
"version": "1.
|
|
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": [
|