@mem0/cli 0.1.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/README.md +75 -0
- package/development.md +91 -0
- package/dist/chunk-EJ5AQPMT.js +120 -0
- package/dist/chunk-I7ABQZUR.js +111 -0
- package/dist/chunk-J7DYZDMM.js +187 -0
- package/dist/chunk-O3XZVUUX.js +252 -0
- package/dist/config-WKOCXNAS.js +86 -0
- package/dist/entities-XPRXH4X4.js +119 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +523 -0
- package/dist/init-N25QFHYP.js +161 -0
- package/dist/memory-JYJGE4VO.js +387 -0
- package/dist/utils-BAMFZ5H5.js +124 -0
- package/package.json +42 -0
- package/src/backend/base.ts +115 -0
- package/src/backend/index.ts +7 -0
- package/src/backend/platform.ts +303 -0
- package/src/branding.ts +145 -0
- package/src/commands/config.ts +90 -0
- package/src/commands/entities.ts +139 -0
- package/src/commands/init.ts +182 -0
- package/src/commands/memory.ts +487 -0
- package/src/commands/utils.ts +139 -0
- package/src/config.ts +159 -0
- package/src/help.ts +374 -0
- package/src/index.ts +501 -0
- package/src/output.ts +230 -0
- package/tests/branding.test.ts +98 -0
- package/tests/cli-integration.test.ts +156 -0
- package/tests/commands.test.ts +221 -0
- package/tests/config.test.ts +113 -0
- package/tests/output.test.ts +115 -0
- package/tests/setup.ts +75 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,487 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory CRUD commands: add, search, get, list, update, delete.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import { printError, printInfo, printScope, printSuccess, timedStatus } from "../branding.js";
|
|
7
|
+
import type { Backend } from "../backend/base.js";
|
|
8
|
+
import {
|
|
9
|
+
formatAddResult,
|
|
10
|
+
formatJson,
|
|
11
|
+
formatMemoriesTable,
|
|
12
|
+
formatMemoriesText,
|
|
13
|
+
formatSingleMemory,
|
|
14
|
+
printResultSummary,
|
|
15
|
+
} from "../output.js";
|
|
16
|
+
|
|
17
|
+
export async function cmdAdd(
|
|
18
|
+
backend: Backend,
|
|
19
|
+
text: string | undefined,
|
|
20
|
+
opts: {
|
|
21
|
+
userId?: string;
|
|
22
|
+
agentId?: string;
|
|
23
|
+
appId?: string;
|
|
24
|
+
runId?: string;
|
|
25
|
+
messages?: string;
|
|
26
|
+
file?: string;
|
|
27
|
+
metadata?: string;
|
|
28
|
+
immutable: boolean;
|
|
29
|
+
noInfer: boolean;
|
|
30
|
+
expires?: string;
|
|
31
|
+
categories?: string;
|
|
32
|
+
enableGraph: boolean;
|
|
33
|
+
output: string;
|
|
34
|
+
},
|
|
35
|
+
): Promise<void> {
|
|
36
|
+
let msgs: Record<string, unknown>[] | undefined;
|
|
37
|
+
let content = text;
|
|
38
|
+
|
|
39
|
+
// Read from file
|
|
40
|
+
if (opts.file) {
|
|
41
|
+
try {
|
|
42
|
+
const raw = fs.readFileSync(opts.file, "utf-8");
|
|
43
|
+
msgs = JSON.parse(raw);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
printError(`Failed to read file: ${e instanceof Error ? e.message : e}`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// Parse messages JSON
|
|
50
|
+
else if (opts.messages) {
|
|
51
|
+
try {
|
|
52
|
+
msgs = JSON.parse(opts.messages);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
printError(`Invalid JSON in --messages: ${e instanceof Error ? e.message : e}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Read from stdin if piped
|
|
59
|
+
else if (!content && !process.stdin.isTTY) {
|
|
60
|
+
content = fs.readFileSync(0, "utf-8").trim();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!content && !msgs) {
|
|
64
|
+
printError("No content provided. Pass text, --messages, --file, or pipe via stdin.");
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let meta: Record<string, unknown> | undefined;
|
|
69
|
+
if (opts.metadata) {
|
|
70
|
+
try {
|
|
71
|
+
meta = JSON.parse(opts.metadata);
|
|
72
|
+
} catch {
|
|
73
|
+
printError("Invalid JSON in --metadata.");
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let cats: string[] | undefined;
|
|
79
|
+
if (opts.categories) {
|
|
80
|
+
try {
|
|
81
|
+
cats = JSON.parse(opts.categories);
|
|
82
|
+
} catch {
|
|
83
|
+
cats = opts.categories.split(",").map((c) => c.trim());
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
let result: Record<string, unknown>;
|
|
88
|
+
try {
|
|
89
|
+
result = await timedStatus("Adding memory...", async () => {
|
|
90
|
+
return backend.add(content ?? undefined, msgs, {
|
|
91
|
+
userId: opts.userId,
|
|
92
|
+
agentId: opts.agentId,
|
|
93
|
+
appId: opts.appId,
|
|
94
|
+
runId: opts.runId,
|
|
95
|
+
metadata: meta,
|
|
96
|
+
immutable: opts.immutable,
|
|
97
|
+
infer: !opts.noInfer,
|
|
98
|
+
expires: opts.expires,
|
|
99
|
+
categories: cats,
|
|
100
|
+
enableGraph: opts.enableGraph,
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
} catch (e) {
|
|
104
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (opts.output === "quiet") return;
|
|
109
|
+
|
|
110
|
+
if (opts.output === "json") {
|
|
111
|
+
formatAddResult(result, opts.output);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.log();
|
|
116
|
+
printScope({ user_id: opts.userId, agent_id: opts.agentId, app_id: opts.appId, run_id: opts.runId });
|
|
117
|
+
const results = Array.isArray(result) ? result : ((result.results as unknown[]) ?? [result]);
|
|
118
|
+
const count = results.length;
|
|
119
|
+
printSuccess(`Memory processed — ${count} memor${count === 1 ? "y" : "ies"} extracted`);
|
|
120
|
+
formatAddResult(result, opts.output);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export async function cmdSearch(
|
|
124
|
+
backend: Backend,
|
|
125
|
+
query: string | undefined,
|
|
126
|
+
opts: {
|
|
127
|
+
userId?: string;
|
|
128
|
+
agentId?: string;
|
|
129
|
+
appId?: string;
|
|
130
|
+
runId?: string;
|
|
131
|
+
topK: number;
|
|
132
|
+
threshold: number;
|
|
133
|
+
rerank: boolean;
|
|
134
|
+
keyword: boolean;
|
|
135
|
+
filterJson?: string;
|
|
136
|
+
fields?: string;
|
|
137
|
+
enableGraph: boolean;
|
|
138
|
+
output: string;
|
|
139
|
+
},
|
|
140
|
+
): Promise<void> {
|
|
141
|
+
if (!query) {
|
|
142
|
+
printError("No query provided. Pass a query argument or pipe via stdin.");
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let filters: Record<string, unknown> | undefined;
|
|
147
|
+
if (opts.filterJson) {
|
|
148
|
+
try {
|
|
149
|
+
filters = JSON.parse(opts.filterJson);
|
|
150
|
+
} catch {
|
|
151
|
+
printError("Invalid JSON in --filter.");
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const fieldList = opts.fields ? opts.fields.split(",").map((f) => f.trim()) : undefined;
|
|
157
|
+
|
|
158
|
+
const start = performance.now();
|
|
159
|
+
let results: Record<string, unknown>[];
|
|
160
|
+
try {
|
|
161
|
+
results = await timedStatus("Searching memories...", async () => {
|
|
162
|
+
return backend.search(query!, {
|
|
163
|
+
userId: opts.userId,
|
|
164
|
+
agentId: opts.agentId,
|
|
165
|
+
appId: opts.appId,
|
|
166
|
+
runId: opts.runId,
|
|
167
|
+
topK: opts.topK,
|
|
168
|
+
threshold: opts.threshold,
|
|
169
|
+
rerank: opts.rerank,
|
|
170
|
+
keyword: opts.keyword,
|
|
171
|
+
filters,
|
|
172
|
+
fields: fieldList,
|
|
173
|
+
enableGraph: opts.enableGraph,
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
} catch (e) {
|
|
177
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
const elapsed = (performance.now() - start) / 1000;
|
|
181
|
+
|
|
182
|
+
if (opts.output === "json") {
|
|
183
|
+
formatJson(results);
|
|
184
|
+
} else if (opts.output === "table") {
|
|
185
|
+
if (results.length > 0) {
|
|
186
|
+
formatMemoriesTable(results);
|
|
187
|
+
printResultSummary({ count: results.length, durationSecs: elapsed, scopeIds: { user_id: opts.userId, agent_id: opts.agentId } });
|
|
188
|
+
} else {
|
|
189
|
+
console.log();
|
|
190
|
+
printInfo("No memories found matching your query.");
|
|
191
|
+
console.log();
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
if (results.length > 0) {
|
|
195
|
+
formatMemoriesText(results);
|
|
196
|
+
printResultSummary({ count: results.length, durationSecs: elapsed, scopeIds: { user_id: opts.userId, agent_id: opts.agentId } });
|
|
197
|
+
} else {
|
|
198
|
+
console.log();
|
|
199
|
+
printInfo("No memories found matching your query.");
|
|
200
|
+
console.log();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export async function cmdGet(
|
|
206
|
+
backend: Backend,
|
|
207
|
+
memoryId: string,
|
|
208
|
+
opts: { output: string },
|
|
209
|
+
): Promise<void> {
|
|
210
|
+
let result: Record<string, unknown>;
|
|
211
|
+
try {
|
|
212
|
+
result = await timedStatus("Fetching memory...", async () => {
|
|
213
|
+
return backend.get(memoryId);
|
|
214
|
+
});
|
|
215
|
+
} catch (e) {
|
|
216
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
formatSingleMemory(result, opts.output);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export async function cmdList(
|
|
224
|
+
backend: Backend,
|
|
225
|
+
opts: {
|
|
226
|
+
userId?: string;
|
|
227
|
+
agentId?: string;
|
|
228
|
+
appId?: string;
|
|
229
|
+
runId?: string;
|
|
230
|
+
page: number;
|
|
231
|
+
pageSize: number;
|
|
232
|
+
category?: string;
|
|
233
|
+
after?: string;
|
|
234
|
+
before?: string;
|
|
235
|
+
enableGraph: boolean;
|
|
236
|
+
output: string;
|
|
237
|
+
},
|
|
238
|
+
): Promise<void> {
|
|
239
|
+
const start = performance.now();
|
|
240
|
+
let results: Record<string, unknown>[];
|
|
241
|
+
try {
|
|
242
|
+
results = await timedStatus("Listing memories...", async () => {
|
|
243
|
+
return backend.listMemories({
|
|
244
|
+
userId: opts.userId,
|
|
245
|
+
agentId: opts.agentId,
|
|
246
|
+
appId: opts.appId,
|
|
247
|
+
runId: opts.runId,
|
|
248
|
+
page: opts.page,
|
|
249
|
+
pageSize: opts.pageSize,
|
|
250
|
+
category: opts.category,
|
|
251
|
+
after: opts.after,
|
|
252
|
+
before: opts.before,
|
|
253
|
+
enableGraph: opts.enableGraph,
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
} catch (e) {
|
|
257
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
const elapsed = (performance.now() - start) / 1000;
|
|
261
|
+
|
|
262
|
+
if (opts.output === "json") {
|
|
263
|
+
formatJson(results);
|
|
264
|
+
} else if (opts.output === "table") {
|
|
265
|
+
if (results.length > 0) {
|
|
266
|
+
formatMemoriesTable(results);
|
|
267
|
+
printResultSummary({ count: results.length, durationSecs: elapsed, page: opts.page, scopeIds: { user_id: opts.userId, agent_id: opts.agentId } });
|
|
268
|
+
} else {
|
|
269
|
+
console.log();
|
|
270
|
+
printInfo("No memories found.");
|
|
271
|
+
console.log();
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
if (results.length > 0) {
|
|
275
|
+
formatMemoriesText(results, "memories");
|
|
276
|
+
printResultSummary({ count: results.length, durationSecs: elapsed, page: opts.page, scopeIds: { user_id: opts.userId, agent_id: opts.agentId } });
|
|
277
|
+
} else {
|
|
278
|
+
console.log();
|
|
279
|
+
printInfo("No memories found.");
|
|
280
|
+
console.log();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export async function cmdUpdate(
|
|
286
|
+
backend: Backend,
|
|
287
|
+
memoryId: string,
|
|
288
|
+
text: string | undefined,
|
|
289
|
+
opts: { metadata?: string; output: string },
|
|
290
|
+
): Promise<void> {
|
|
291
|
+
let meta: Record<string, unknown> | undefined;
|
|
292
|
+
if (opts.metadata) {
|
|
293
|
+
try {
|
|
294
|
+
meta = JSON.parse(opts.metadata);
|
|
295
|
+
} catch {
|
|
296
|
+
printError("Invalid JSON in --metadata.");
|
|
297
|
+
process.exit(1);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const start = performance.now();
|
|
302
|
+
let result: Record<string, unknown>;
|
|
303
|
+
try {
|
|
304
|
+
result = await timedStatus("Updating memory...", async () => {
|
|
305
|
+
return backend.update(memoryId, text, meta);
|
|
306
|
+
});
|
|
307
|
+
} catch (e) {
|
|
308
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
309
|
+
process.exit(1);
|
|
310
|
+
}
|
|
311
|
+
const elapsed = (performance.now() - start) / 1000;
|
|
312
|
+
|
|
313
|
+
if (opts.output === "json") {
|
|
314
|
+
formatJson(result);
|
|
315
|
+
} else if (opts.output !== "quiet") {
|
|
316
|
+
printSuccess(`Memory ${memoryId.slice(0, 8)} updated (${elapsed.toFixed(2)}s)`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export async function cmdDelete(
|
|
321
|
+
backend: Backend,
|
|
322
|
+
memoryId: string,
|
|
323
|
+
opts: { output: string; dryRun?: boolean; force?: boolean },
|
|
324
|
+
): Promise<void> {
|
|
325
|
+
if (opts.dryRun) {
|
|
326
|
+
let mem: Record<string, unknown>;
|
|
327
|
+
try {
|
|
328
|
+
mem = await backend.get(memoryId);
|
|
329
|
+
} catch (e) {
|
|
330
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
331
|
+
process.exit(1);
|
|
332
|
+
}
|
|
333
|
+
const text = (mem.memory ?? mem.text ?? "") as string;
|
|
334
|
+
printInfo(`Would delete memory ${memoryId.slice(0, 8)}: ${text}`);
|
|
335
|
+
printInfo("No changes made.");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const start = performance.now();
|
|
340
|
+
let result: Record<string, unknown>;
|
|
341
|
+
try {
|
|
342
|
+
result = await timedStatus("Deleting...", async () => {
|
|
343
|
+
return backend.delete(memoryId);
|
|
344
|
+
});
|
|
345
|
+
} catch (e) {
|
|
346
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
347
|
+
process.exit(1);
|
|
348
|
+
}
|
|
349
|
+
const elapsed = (performance.now() - start) / 1000;
|
|
350
|
+
|
|
351
|
+
if (opts.output === "json") {
|
|
352
|
+
formatJson(result);
|
|
353
|
+
} else if (opts.output !== "quiet") {
|
|
354
|
+
printSuccess(`Memory ${memoryId.slice(0, 8)} deleted (${elapsed.toFixed(2)}s)`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export async function cmdDeleteAll(
|
|
359
|
+
backend: Backend,
|
|
360
|
+
opts: {
|
|
361
|
+
force: boolean;
|
|
362
|
+
dryRun?: boolean;
|
|
363
|
+
all?: boolean;
|
|
364
|
+
userId?: string;
|
|
365
|
+
agentId?: string;
|
|
366
|
+
appId?: string;
|
|
367
|
+
runId?: string;
|
|
368
|
+
output: string;
|
|
369
|
+
},
|
|
370
|
+
): Promise<void> {
|
|
371
|
+
if (opts.all) {
|
|
372
|
+
// Project-wide wipe using wildcard entity IDs
|
|
373
|
+
if (opts.dryRun) {
|
|
374
|
+
printInfo("Would delete ALL memories project-wide.");
|
|
375
|
+
printInfo("No changes made.");
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if (!opts.force) {
|
|
380
|
+
const readline = await import("node:readline");
|
|
381
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
382
|
+
const answer = await new Promise<string>((resolve) => {
|
|
383
|
+
rl.question(`\n \u26a0 Delete ALL memories across the ENTIRE project? This cannot be undone. [y/N] `, resolve);
|
|
384
|
+
});
|
|
385
|
+
rl.close();
|
|
386
|
+
if (answer.toLowerCase() !== "y") {
|
|
387
|
+
printInfo("Cancelled.");
|
|
388
|
+
process.exit(0);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const start = performance.now();
|
|
393
|
+
let result: Record<string, unknown>;
|
|
394
|
+
try {
|
|
395
|
+
result = await timedStatus("Deleting all memories project-wide...", async () => {
|
|
396
|
+
return backend.delete(undefined, {
|
|
397
|
+
all: true,
|
|
398
|
+
userId: "*",
|
|
399
|
+
agentId: "*",
|
|
400
|
+
appId: "*",
|
|
401
|
+
runId: "*",
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
} catch (e) {
|
|
405
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
406
|
+
process.exit(1);
|
|
407
|
+
}
|
|
408
|
+
const elapsed = (performance.now() - start) / 1000;
|
|
409
|
+
|
|
410
|
+
if (opts.output === "json") {
|
|
411
|
+
formatJson(result);
|
|
412
|
+
} else if (opts.output !== "quiet") {
|
|
413
|
+
if (result.message) {
|
|
414
|
+
printInfo("Deletion started. Memories will be removed in the background.");
|
|
415
|
+
} else {
|
|
416
|
+
printSuccess(`All project memories deleted (${elapsed.toFixed(2)}s)`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (opts.dryRun) {
|
|
423
|
+
let memories: Record<string, unknown>[];
|
|
424
|
+
try {
|
|
425
|
+
memories = await backend.listMemories({
|
|
426
|
+
userId: opts.userId,
|
|
427
|
+
agentId: opts.agentId,
|
|
428
|
+
appId: opts.appId,
|
|
429
|
+
runId: opts.runId,
|
|
430
|
+
});
|
|
431
|
+
} catch (e) {
|
|
432
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
printInfo(`Would delete ${memories.length} memories.`);
|
|
436
|
+
printInfo("No changes made.");
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (!opts.force) {
|
|
441
|
+
const scopeParts: string[] = [];
|
|
442
|
+
if (opts.userId) scopeParts.push(`user=${opts.userId}`);
|
|
443
|
+
if (opts.agentId) scopeParts.push(`agent=${opts.agentId}`);
|
|
444
|
+
if (opts.appId) scopeParts.push(`app=${opts.appId}`);
|
|
445
|
+
if (opts.runId) scopeParts.push(`run=${opts.runId}`);
|
|
446
|
+
const scope = scopeParts.length > 0 ? scopeParts.join(", ") : "ALL entities";
|
|
447
|
+
|
|
448
|
+
const readline = await import("node:readline");
|
|
449
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
450
|
+
const answer = await new Promise<string>((resolve) => {
|
|
451
|
+
rl.question(`\n \u26a0 Delete ALL memories for ${scope}? This cannot be undone. [y/N] `, resolve);
|
|
452
|
+
});
|
|
453
|
+
rl.close();
|
|
454
|
+
if (answer.toLowerCase() !== "y") {
|
|
455
|
+
printInfo("Cancelled.");
|
|
456
|
+
process.exit(0);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const start = performance.now();
|
|
461
|
+
let result: Record<string, unknown>;
|
|
462
|
+
try {
|
|
463
|
+
result = await timedStatus("Deleting all memories...", async () => {
|
|
464
|
+
return backend.delete(undefined, {
|
|
465
|
+
all: true,
|
|
466
|
+
userId: opts.userId,
|
|
467
|
+
agentId: opts.agentId,
|
|
468
|
+
appId: opts.appId,
|
|
469
|
+
runId: opts.runId,
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
} catch (e) {
|
|
473
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
474
|
+
process.exit(1);
|
|
475
|
+
}
|
|
476
|
+
const elapsed = (performance.now() - start) / 1000;
|
|
477
|
+
|
|
478
|
+
if (opts.output === "json") {
|
|
479
|
+
formatJson(result);
|
|
480
|
+
} else if (opts.output !== "quiet") {
|
|
481
|
+
if (result.message) {
|
|
482
|
+
printInfo("Deletion started. Memories will be removed in the background.");
|
|
483
|
+
} else {
|
|
484
|
+
printSuccess(`All matching memories deleted (${elapsed.toFixed(2)}s)`);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility commands: status, version, import.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
7
|
+
import { printError, printSuccess, timedStatus, colors } from "../branding.js";
|
|
8
|
+
import type { Backend } from "../backend/base.js";
|
|
9
|
+
import { formatJsonEnvelope } from "../output.js";
|
|
10
|
+
import boxen from "boxen";
|
|
11
|
+
|
|
12
|
+
const { brand, dim, success, error: errorColor } = colors;
|
|
13
|
+
|
|
14
|
+
const _require = createRequire(import.meta.url);
|
|
15
|
+
const VERSION: string = _require("../../package.json").version;
|
|
16
|
+
|
|
17
|
+
export async function cmdStatus(
|
|
18
|
+
backend: Backend,
|
|
19
|
+
opts: { userId?: string; agentId?: string; output?: string } = {},
|
|
20
|
+
): Promise<void> {
|
|
21
|
+
const start = performance.now();
|
|
22
|
+
let result: Record<string, unknown>;
|
|
23
|
+
try {
|
|
24
|
+
result = await timedStatus("Checking connection...", async () => {
|
|
25
|
+
return backend.status({ userId: opts.userId, agentId: opts.agentId });
|
|
26
|
+
});
|
|
27
|
+
} catch (e) {
|
|
28
|
+
result = { connected: false, error: e instanceof Error ? e.message : String(e) };
|
|
29
|
+
}
|
|
30
|
+
const elapsed = (performance.now() - start) / 1000;
|
|
31
|
+
|
|
32
|
+
if (opts.output === "json") {
|
|
33
|
+
formatJsonEnvelope({
|
|
34
|
+
command: "status",
|
|
35
|
+
data: {
|
|
36
|
+
connected: result.connected,
|
|
37
|
+
backend: result.backend ?? null,
|
|
38
|
+
base_url: result.base_url ?? null,
|
|
39
|
+
latency_ms: Math.round(elapsed * 1000),
|
|
40
|
+
},
|
|
41
|
+
durationMs: Math.round(elapsed * 1000),
|
|
42
|
+
});
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const lines: string[] = [];
|
|
47
|
+
if (result.connected) {
|
|
48
|
+
lines.push(` ${success("\u25cf")} Connected`);
|
|
49
|
+
} else {
|
|
50
|
+
lines.push(` ${errorColor("\u25cf")} Disconnected`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
lines.push(` ${dim("Backend:")} ${result.backend ?? "?"}`);
|
|
54
|
+
if (result.base_url) {
|
|
55
|
+
lines.push(` ${dim("API URL:")} ${result.base_url}`);
|
|
56
|
+
}
|
|
57
|
+
if (result.error) {
|
|
58
|
+
lines.push(` ${errorColor("Error:")} ${result.error}`);
|
|
59
|
+
}
|
|
60
|
+
lines.push(` ${dim("Latency:")} ${elapsed.toFixed(2)}s`);
|
|
61
|
+
|
|
62
|
+
const content = lines.join("\n");
|
|
63
|
+
console.log();
|
|
64
|
+
console.log(
|
|
65
|
+
boxen(content, {
|
|
66
|
+
title: brand("Connection Status"),
|
|
67
|
+
titleAlignment: "left",
|
|
68
|
+
borderColor: "magenta",
|
|
69
|
+
padding: 1,
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
console.log();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function cmdVersion(): void {
|
|
76
|
+
console.log(` ${brand("◆ Mem0")} CLI v${VERSION}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export async function cmdImport(
|
|
80
|
+
backend: Backend,
|
|
81
|
+
filePath: string,
|
|
82
|
+
opts: { userId?: string; agentId?: string; output?: string },
|
|
83
|
+
): Promise<void> {
|
|
84
|
+
let data: Record<string, unknown>[];
|
|
85
|
+
try {
|
|
86
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
87
|
+
const parsed = JSON.parse(raw);
|
|
88
|
+
data = Array.isArray(parsed) ? parsed : [parsed];
|
|
89
|
+
} catch (e) {
|
|
90
|
+
printError(`Failed to read file: ${e instanceof Error ? e.message : e}`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let added = 0;
|
|
95
|
+
let failed = 0;
|
|
96
|
+
const start = performance.now();
|
|
97
|
+
|
|
98
|
+
for (let i = 0; i < data.length; i++) {
|
|
99
|
+
const item = data[i];
|
|
100
|
+
const content = (item.memory ?? item.text ?? item.content ?? "") as string;
|
|
101
|
+
if (!content) {
|
|
102
|
+
failed++;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
await backend.add(content, undefined, {
|
|
108
|
+
userId: opts.userId ?? (item.user_id as string | undefined),
|
|
109
|
+
agentId: opts.agentId ?? (item.agent_id as string | undefined),
|
|
110
|
+
metadata: item.metadata as Record<string, unknown> | undefined,
|
|
111
|
+
});
|
|
112
|
+
added++;
|
|
113
|
+
} catch {
|
|
114
|
+
failed++;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Simple progress indicator
|
|
118
|
+
if ((i + 1) % 10 === 0 || i === data.length - 1) {
|
|
119
|
+
process.stdout.write(`\r ${dim(`Importing memories... ${i + 1}/${data.length}`)}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const elapsed = (performance.now() - start) / 1000;
|
|
124
|
+
console.log(); // Clear progress line
|
|
125
|
+
|
|
126
|
+
if (opts.output === "json") {
|
|
127
|
+
formatJsonEnvelope({
|
|
128
|
+
command: "import",
|
|
129
|
+
data: { added, failed, duration_s: parseFloat(elapsed.toFixed(2)) },
|
|
130
|
+
durationMs: Math.round(elapsed * 1000),
|
|
131
|
+
});
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
printSuccess(`Imported ${added} memories (${elapsed.toFixed(2)}s)`);
|
|
136
|
+
if (failed > 0) {
|
|
137
|
+
printError(`${failed} memories failed to import.`);
|
|
138
|
+
}
|
|
139
|
+
}
|