@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,161 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PlatformBackend
|
|
3
|
+
} from "./chunk-O3XZVUUX.js";
|
|
4
|
+
import {
|
|
5
|
+
createDefaultConfig,
|
|
6
|
+
saveConfig
|
|
7
|
+
} from "./chunk-EJ5AQPMT.js";
|
|
8
|
+
import {
|
|
9
|
+
colors,
|
|
10
|
+
printBanner,
|
|
11
|
+
printError,
|
|
12
|
+
printInfo,
|
|
13
|
+
printSuccess
|
|
14
|
+
} from "./chunk-I7ABQZUR.js";
|
|
15
|
+
|
|
16
|
+
// src/commands/init.ts
|
|
17
|
+
import readline from "readline";
|
|
18
|
+
var { brand, dim } = colors;
|
|
19
|
+
function promptSecret(label) {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
process.stdout.write(label);
|
|
22
|
+
if (process.stdin.isTTY) {
|
|
23
|
+
process.stdin.setRawMode(true);
|
|
24
|
+
}
|
|
25
|
+
process.stdin.resume();
|
|
26
|
+
process.stdin.setEncoding("utf-8");
|
|
27
|
+
const chars = [];
|
|
28
|
+
const onData = (key) => {
|
|
29
|
+
for (const ch of key) {
|
|
30
|
+
if (ch === "\r" || ch === "\n") {
|
|
31
|
+
cleanup();
|
|
32
|
+
process.stdout.write("\n");
|
|
33
|
+
resolve(chars.join(""));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (ch === "") {
|
|
37
|
+
cleanup();
|
|
38
|
+
reject(new Error("Interrupted"));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (ch === "\x7F" || ch === "\b") {
|
|
42
|
+
if (chars.length > 0) {
|
|
43
|
+
chars.pop();
|
|
44
|
+
process.stdout.write("\b \b");
|
|
45
|
+
}
|
|
46
|
+
} else if (ch === "") {
|
|
47
|
+
process.stdout.write("\b \b".repeat(chars.length));
|
|
48
|
+
chars.length = 0;
|
|
49
|
+
} else if (ch >= " ") {
|
|
50
|
+
chars.push(ch);
|
|
51
|
+
process.stdout.write("*");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const cleanup = () => {
|
|
56
|
+
process.stdin.removeListener("data", onData);
|
|
57
|
+
if (process.stdin.isTTY) {
|
|
58
|
+
process.stdin.setRawMode(false);
|
|
59
|
+
}
|
|
60
|
+
process.stdin.pause();
|
|
61
|
+
};
|
|
62
|
+
process.stdin.on("data", onData);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function promptLine(label, defaultValue) {
|
|
66
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
67
|
+
const prompt = defaultValue ? `${label} [${defaultValue}]: ` : `${label}: `;
|
|
68
|
+
return new Promise((resolve) => {
|
|
69
|
+
rl.question(prompt, (answer) => {
|
|
70
|
+
rl.close();
|
|
71
|
+
resolve(answer.trim() || defaultValue || "");
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
async function setupPlatform(config) {
|
|
76
|
+
console.log();
|
|
77
|
+
console.log(` ${dim("Get your API key at https://app.mem0.ai/dashboard/api-keys")}`);
|
|
78
|
+
console.log();
|
|
79
|
+
process.stdout.write(` ${brand("API Key")}: `);
|
|
80
|
+
const apiKey = await promptSecret("");
|
|
81
|
+
if (!apiKey) {
|
|
82
|
+
printError("API key is required.");
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
config.platform.apiKey = apiKey;
|
|
86
|
+
}
|
|
87
|
+
async function setupDefaults(config) {
|
|
88
|
+
console.log();
|
|
89
|
+
printInfo("Set default entity IDs (press Enter to skip).\n");
|
|
90
|
+
const userId = await promptLine(` ${brand("Default User ID")} ${dim("(recommended)")}`, "mem0-cli");
|
|
91
|
+
if (userId) config.defaults.userId = userId;
|
|
92
|
+
}
|
|
93
|
+
async function validatePlatform(config) {
|
|
94
|
+
console.log();
|
|
95
|
+
printInfo("Validating connection...");
|
|
96
|
+
try {
|
|
97
|
+
const backend = new PlatformBackend(config.platform);
|
|
98
|
+
const status = await backend.status({
|
|
99
|
+
userId: config.defaults.userId || void 0,
|
|
100
|
+
agentId: config.defaults.agentId || void 0
|
|
101
|
+
});
|
|
102
|
+
if (status.connected) {
|
|
103
|
+
printSuccess("Connected to mem0 Platform!");
|
|
104
|
+
} else {
|
|
105
|
+
printError(
|
|
106
|
+
`Could not connect: ${status.error ?? "Unknown error"}`,
|
|
107
|
+
"Check your API key and try again."
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
} catch (e) {
|
|
111
|
+
printError(`Connection test failed: ${e instanceof Error ? e.message : e}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function runInit(opts = {}) {
|
|
115
|
+
const config = createDefaultConfig();
|
|
116
|
+
if (opts.apiKey && opts.userId) {
|
|
117
|
+
config.platform.apiKey = opts.apiKey;
|
|
118
|
+
config.defaults.userId = opts.userId;
|
|
119
|
+
await validatePlatform(config);
|
|
120
|
+
saveConfig(config);
|
|
121
|
+
printSuccess("Configuration saved to ~/.mem0/config.json");
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (!process.stdin.isTTY && (!opts.apiKey || !opts.userId)) {
|
|
125
|
+
printError(
|
|
126
|
+
"Non-interactive terminal detected and missing required flags.",
|
|
127
|
+
"Usage: mem0 init --api-key <key> --user-id <id>"
|
|
128
|
+
);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
printBanner();
|
|
132
|
+
console.log();
|
|
133
|
+
printInfo("Welcome! Let's set up your mem0 CLI.\n");
|
|
134
|
+
if (opts.apiKey) {
|
|
135
|
+
config.platform.apiKey = opts.apiKey;
|
|
136
|
+
} else {
|
|
137
|
+
await setupPlatform(config);
|
|
138
|
+
}
|
|
139
|
+
if (opts.userId) {
|
|
140
|
+
config.defaults.userId = opts.userId;
|
|
141
|
+
} else {
|
|
142
|
+
await setupDefaults(config);
|
|
143
|
+
}
|
|
144
|
+
await validatePlatform(config);
|
|
145
|
+
saveConfig(config);
|
|
146
|
+
console.log();
|
|
147
|
+
printSuccess("Configuration saved to ~/.mem0/config.json");
|
|
148
|
+
console.log();
|
|
149
|
+
console.log(` ${dim("Get started:")}`);
|
|
150
|
+
if (config.defaults.userId) {
|
|
151
|
+
console.log(` ${dim(' mem0 add "I prefer dark mode"')}`);
|
|
152
|
+
console.log(` ${dim(' mem0 search "preferences"')}`);
|
|
153
|
+
} else {
|
|
154
|
+
console.log(` ${dim(' mem0 add "I prefer dark mode" --user-id alice')}`);
|
|
155
|
+
console.log(` ${dim(' mem0 search "preferences" --user-id alice')}`);
|
|
156
|
+
}
|
|
157
|
+
console.log();
|
|
158
|
+
}
|
|
159
|
+
export {
|
|
160
|
+
runInit
|
|
161
|
+
};
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatAddResult,
|
|
3
|
+
formatJson,
|
|
4
|
+
formatMemoriesTable,
|
|
5
|
+
formatMemoriesText,
|
|
6
|
+
formatSingleMemory,
|
|
7
|
+
printResultSummary
|
|
8
|
+
} from "./chunk-J7DYZDMM.js";
|
|
9
|
+
import {
|
|
10
|
+
printError,
|
|
11
|
+
printInfo,
|
|
12
|
+
printScope,
|
|
13
|
+
printSuccess,
|
|
14
|
+
timedStatus
|
|
15
|
+
} from "./chunk-I7ABQZUR.js";
|
|
16
|
+
|
|
17
|
+
// src/commands/memory.ts
|
|
18
|
+
import fs from "fs";
|
|
19
|
+
async function cmdAdd(backend, text, opts) {
|
|
20
|
+
let msgs;
|
|
21
|
+
let content = text;
|
|
22
|
+
if (opts.file) {
|
|
23
|
+
try {
|
|
24
|
+
const raw = fs.readFileSync(opts.file, "utf-8");
|
|
25
|
+
msgs = JSON.parse(raw);
|
|
26
|
+
} catch (e) {
|
|
27
|
+
printError(`Failed to read file: ${e instanceof Error ? e.message : e}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
} else if (opts.messages) {
|
|
31
|
+
try {
|
|
32
|
+
msgs = JSON.parse(opts.messages);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
printError(`Invalid JSON in --messages: ${e instanceof Error ? e.message : e}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
} else if (!content && !process.stdin.isTTY) {
|
|
38
|
+
content = fs.readFileSync(0, "utf-8").trim();
|
|
39
|
+
}
|
|
40
|
+
if (!content && !msgs) {
|
|
41
|
+
printError("No content provided. Pass text, --messages, --file, or pipe via stdin.");
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
let meta;
|
|
45
|
+
if (opts.metadata) {
|
|
46
|
+
try {
|
|
47
|
+
meta = JSON.parse(opts.metadata);
|
|
48
|
+
} catch {
|
|
49
|
+
printError("Invalid JSON in --metadata.");
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
let cats;
|
|
54
|
+
if (opts.categories) {
|
|
55
|
+
try {
|
|
56
|
+
cats = JSON.parse(opts.categories);
|
|
57
|
+
} catch {
|
|
58
|
+
cats = opts.categories.split(",").map((c) => c.trim());
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
let result;
|
|
62
|
+
try {
|
|
63
|
+
result = await timedStatus("Adding memory...", async () => {
|
|
64
|
+
return backend.add(content ?? void 0, msgs, {
|
|
65
|
+
userId: opts.userId,
|
|
66
|
+
agentId: opts.agentId,
|
|
67
|
+
appId: opts.appId,
|
|
68
|
+
runId: opts.runId,
|
|
69
|
+
metadata: meta,
|
|
70
|
+
immutable: opts.immutable,
|
|
71
|
+
infer: !opts.noInfer,
|
|
72
|
+
expires: opts.expires,
|
|
73
|
+
categories: cats,
|
|
74
|
+
enableGraph: opts.enableGraph
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
} catch (e) {
|
|
78
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
if (opts.output === "quiet") return;
|
|
82
|
+
if (opts.output === "json") {
|
|
83
|
+
formatAddResult(result, opts.output);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
console.log();
|
|
87
|
+
printScope({ user_id: opts.userId, agent_id: opts.agentId, app_id: opts.appId, run_id: opts.runId });
|
|
88
|
+
const results = Array.isArray(result) ? result : result.results ?? [result];
|
|
89
|
+
const count = results.length;
|
|
90
|
+
printSuccess(`Memory processed \u2014 ${count} memor${count === 1 ? "y" : "ies"} extracted`);
|
|
91
|
+
formatAddResult(result, opts.output);
|
|
92
|
+
}
|
|
93
|
+
async function cmdSearch(backend, query, opts) {
|
|
94
|
+
if (!query) {
|
|
95
|
+
printError("No query provided. Pass a query argument or pipe via stdin.");
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
let filters;
|
|
99
|
+
if (opts.filterJson) {
|
|
100
|
+
try {
|
|
101
|
+
filters = JSON.parse(opts.filterJson);
|
|
102
|
+
} catch {
|
|
103
|
+
printError("Invalid JSON in --filter.");
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const fieldList = opts.fields ? opts.fields.split(",").map((f) => f.trim()) : void 0;
|
|
108
|
+
const start = performance.now();
|
|
109
|
+
let results;
|
|
110
|
+
try {
|
|
111
|
+
results = await timedStatus("Searching memories...", async () => {
|
|
112
|
+
return backend.search(query, {
|
|
113
|
+
userId: opts.userId,
|
|
114
|
+
agentId: opts.agentId,
|
|
115
|
+
appId: opts.appId,
|
|
116
|
+
runId: opts.runId,
|
|
117
|
+
topK: opts.topK,
|
|
118
|
+
threshold: opts.threshold,
|
|
119
|
+
rerank: opts.rerank,
|
|
120
|
+
keyword: opts.keyword,
|
|
121
|
+
filters,
|
|
122
|
+
fields: fieldList,
|
|
123
|
+
enableGraph: opts.enableGraph
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
} catch (e) {
|
|
127
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
const elapsed = (performance.now() - start) / 1e3;
|
|
131
|
+
if (opts.output === "json") {
|
|
132
|
+
formatJson(results);
|
|
133
|
+
} else if (opts.output === "table") {
|
|
134
|
+
if (results.length > 0) {
|
|
135
|
+
formatMemoriesTable(results);
|
|
136
|
+
printResultSummary({ count: results.length, durationSecs: elapsed, scopeIds: { user_id: opts.userId, agent_id: opts.agentId } });
|
|
137
|
+
} else {
|
|
138
|
+
console.log();
|
|
139
|
+
printInfo("No memories found matching your query.");
|
|
140
|
+
console.log();
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
if (results.length > 0) {
|
|
144
|
+
formatMemoriesText(results);
|
|
145
|
+
printResultSummary({ count: results.length, durationSecs: elapsed, scopeIds: { user_id: opts.userId, agent_id: opts.agentId } });
|
|
146
|
+
} else {
|
|
147
|
+
console.log();
|
|
148
|
+
printInfo("No memories found matching your query.");
|
|
149
|
+
console.log();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async function cmdGet(backend, memoryId, opts) {
|
|
154
|
+
let result;
|
|
155
|
+
try {
|
|
156
|
+
result = await timedStatus("Fetching memory...", async () => {
|
|
157
|
+
return backend.get(memoryId);
|
|
158
|
+
});
|
|
159
|
+
} catch (e) {
|
|
160
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
163
|
+
formatSingleMemory(result, opts.output);
|
|
164
|
+
}
|
|
165
|
+
async function cmdList(backend, opts) {
|
|
166
|
+
const start = performance.now();
|
|
167
|
+
let results;
|
|
168
|
+
try {
|
|
169
|
+
results = await timedStatus("Listing memories...", async () => {
|
|
170
|
+
return backend.listMemories({
|
|
171
|
+
userId: opts.userId,
|
|
172
|
+
agentId: opts.agentId,
|
|
173
|
+
appId: opts.appId,
|
|
174
|
+
runId: opts.runId,
|
|
175
|
+
page: opts.page,
|
|
176
|
+
pageSize: opts.pageSize,
|
|
177
|
+
category: opts.category,
|
|
178
|
+
after: opts.after,
|
|
179
|
+
before: opts.before,
|
|
180
|
+
enableGraph: opts.enableGraph
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
} catch (e) {
|
|
184
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
const elapsed = (performance.now() - start) / 1e3;
|
|
188
|
+
if (opts.output === "json") {
|
|
189
|
+
formatJson(results);
|
|
190
|
+
} else if (opts.output === "table") {
|
|
191
|
+
if (results.length > 0) {
|
|
192
|
+
formatMemoriesTable(results);
|
|
193
|
+
printResultSummary({ count: results.length, durationSecs: elapsed, page: opts.page, scopeIds: { user_id: opts.userId, agent_id: opts.agentId } });
|
|
194
|
+
} else {
|
|
195
|
+
console.log();
|
|
196
|
+
printInfo("No memories found.");
|
|
197
|
+
console.log();
|
|
198
|
+
}
|
|
199
|
+
} else {
|
|
200
|
+
if (results.length > 0) {
|
|
201
|
+
formatMemoriesText(results, "memories");
|
|
202
|
+
printResultSummary({ count: results.length, durationSecs: elapsed, page: opts.page, scopeIds: { user_id: opts.userId, agent_id: opts.agentId } });
|
|
203
|
+
} else {
|
|
204
|
+
console.log();
|
|
205
|
+
printInfo("No memories found.");
|
|
206
|
+
console.log();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
async function cmdUpdate(backend, memoryId, text, opts) {
|
|
211
|
+
let meta;
|
|
212
|
+
if (opts.metadata) {
|
|
213
|
+
try {
|
|
214
|
+
meta = JSON.parse(opts.metadata);
|
|
215
|
+
} catch {
|
|
216
|
+
printError("Invalid JSON in --metadata.");
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const start = performance.now();
|
|
221
|
+
let result;
|
|
222
|
+
try {
|
|
223
|
+
result = await timedStatus("Updating memory...", async () => {
|
|
224
|
+
return backend.update(memoryId, text, meta);
|
|
225
|
+
});
|
|
226
|
+
} catch (e) {
|
|
227
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
const elapsed = (performance.now() - start) / 1e3;
|
|
231
|
+
if (opts.output === "json") {
|
|
232
|
+
formatJson(result);
|
|
233
|
+
} else if (opts.output !== "quiet") {
|
|
234
|
+
printSuccess(`Memory ${memoryId.slice(0, 8)} updated (${elapsed.toFixed(2)}s)`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
async function cmdDelete(backend, memoryId, opts) {
|
|
238
|
+
if (opts.dryRun) {
|
|
239
|
+
let mem;
|
|
240
|
+
try {
|
|
241
|
+
mem = await backend.get(memoryId);
|
|
242
|
+
} catch (e) {
|
|
243
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
244
|
+
process.exit(1);
|
|
245
|
+
}
|
|
246
|
+
const text = mem.memory ?? mem.text ?? "";
|
|
247
|
+
printInfo(`Would delete memory ${memoryId.slice(0, 8)}: ${text}`);
|
|
248
|
+
printInfo("No changes made.");
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const start = performance.now();
|
|
252
|
+
let result;
|
|
253
|
+
try {
|
|
254
|
+
result = await timedStatus("Deleting...", async () => {
|
|
255
|
+
return backend.delete(memoryId);
|
|
256
|
+
});
|
|
257
|
+
} catch (e) {
|
|
258
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
const elapsed = (performance.now() - start) / 1e3;
|
|
262
|
+
if (opts.output === "json") {
|
|
263
|
+
formatJson(result);
|
|
264
|
+
} else if (opts.output !== "quiet") {
|
|
265
|
+
printSuccess(`Memory ${memoryId.slice(0, 8)} deleted (${elapsed.toFixed(2)}s)`);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async function cmdDeleteAll(backend, opts) {
|
|
269
|
+
if (opts.all) {
|
|
270
|
+
if (opts.dryRun) {
|
|
271
|
+
printInfo("Would delete ALL memories project-wide.");
|
|
272
|
+
printInfo("No changes made.");
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
if (!opts.force) {
|
|
276
|
+
const readline = await import("readline");
|
|
277
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
278
|
+
const answer = await new Promise((resolve) => {
|
|
279
|
+
rl.question(`
|
|
280
|
+
\u26A0 Delete ALL memories across the ENTIRE project? This cannot be undone. [y/N] `, resolve);
|
|
281
|
+
});
|
|
282
|
+
rl.close();
|
|
283
|
+
if (answer.toLowerCase() !== "y") {
|
|
284
|
+
printInfo("Cancelled.");
|
|
285
|
+
process.exit(0);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const start2 = performance.now();
|
|
289
|
+
let result2;
|
|
290
|
+
try {
|
|
291
|
+
result2 = await timedStatus("Deleting all memories project-wide...", async () => {
|
|
292
|
+
return backend.delete(void 0, {
|
|
293
|
+
all: true,
|
|
294
|
+
userId: "*",
|
|
295
|
+
agentId: "*",
|
|
296
|
+
appId: "*",
|
|
297
|
+
runId: "*"
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
} catch (e) {
|
|
301
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
302
|
+
process.exit(1);
|
|
303
|
+
}
|
|
304
|
+
const elapsed2 = (performance.now() - start2) / 1e3;
|
|
305
|
+
if (opts.output === "json") {
|
|
306
|
+
formatJson(result2);
|
|
307
|
+
} else if (opts.output !== "quiet") {
|
|
308
|
+
if (result2.message) {
|
|
309
|
+
printInfo("Deletion started. Memories will be removed in the background.");
|
|
310
|
+
} else {
|
|
311
|
+
printSuccess(`All project memories deleted (${elapsed2.toFixed(2)}s)`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (opts.dryRun) {
|
|
317
|
+
let memories;
|
|
318
|
+
try {
|
|
319
|
+
memories = await backend.listMemories({
|
|
320
|
+
userId: opts.userId,
|
|
321
|
+
agentId: opts.agentId,
|
|
322
|
+
appId: opts.appId,
|
|
323
|
+
runId: opts.runId
|
|
324
|
+
});
|
|
325
|
+
} catch (e) {
|
|
326
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|
|
329
|
+
printInfo(`Would delete ${memories.length} memories.`);
|
|
330
|
+
printInfo("No changes made.");
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (!opts.force) {
|
|
334
|
+
const scopeParts = [];
|
|
335
|
+
if (opts.userId) scopeParts.push(`user=${opts.userId}`);
|
|
336
|
+
if (opts.agentId) scopeParts.push(`agent=${opts.agentId}`);
|
|
337
|
+
if (opts.appId) scopeParts.push(`app=${opts.appId}`);
|
|
338
|
+
if (opts.runId) scopeParts.push(`run=${opts.runId}`);
|
|
339
|
+
const scope = scopeParts.length > 0 ? scopeParts.join(", ") : "ALL entities";
|
|
340
|
+
const readline = await import("readline");
|
|
341
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
342
|
+
const answer = await new Promise((resolve) => {
|
|
343
|
+
rl.question(`
|
|
344
|
+
\u26A0 Delete ALL memories for ${scope}? This cannot be undone. [y/N] `, resolve);
|
|
345
|
+
});
|
|
346
|
+
rl.close();
|
|
347
|
+
if (answer.toLowerCase() !== "y") {
|
|
348
|
+
printInfo("Cancelled.");
|
|
349
|
+
process.exit(0);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const start = performance.now();
|
|
353
|
+
let result;
|
|
354
|
+
try {
|
|
355
|
+
result = await timedStatus("Deleting all memories...", async () => {
|
|
356
|
+
return backend.delete(void 0, {
|
|
357
|
+
all: true,
|
|
358
|
+
userId: opts.userId,
|
|
359
|
+
agentId: opts.agentId,
|
|
360
|
+
appId: opts.appId,
|
|
361
|
+
runId: opts.runId
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
} catch (e) {
|
|
365
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
366
|
+
process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
const elapsed = (performance.now() - start) / 1e3;
|
|
369
|
+
if (opts.output === "json") {
|
|
370
|
+
formatJson(result);
|
|
371
|
+
} else if (opts.output !== "quiet") {
|
|
372
|
+
if (result.message) {
|
|
373
|
+
printInfo("Deletion started. Memories will be removed in the background.");
|
|
374
|
+
} else {
|
|
375
|
+
printSuccess(`All matching memories deleted (${elapsed.toFixed(2)}s)`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
export {
|
|
380
|
+
cmdAdd,
|
|
381
|
+
cmdDelete,
|
|
382
|
+
cmdDeleteAll,
|
|
383
|
+
cmdGet,
|
|
384
|
+
cmdList,
|
|
385
|
+
cmdSearch,
|
|
386
|
+
cmdUpdate
|
|
387
|
+
};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
formatJsonEnvelope
|
|
3
|
+
} from "./chunk-J7DYZDMM.js";
|
|
4
|
+
import {
|
|
5
|
+
colors,
|
|
6
|
+
printError,
|
|
7
|
+
printSuccess,
|
|
8
|
+
timedStatus
|
|
9
|
+
} from "./chunk-I7ABQZUR.js";
|
|
10
|
+
|
|
11
|
+
// src/commands/utils.ts
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import { createRequire } from "module";
|
|
14
|
+
import boxen from "boxen";
|
|
15
|
+
var { brand, dim, success, error: errorColor } = colors;
|
|
16
|
+
var _require = createRequire(import.meta.url);
|
|
17
|
+
var VERSION = _require("../../package.json").version;
|
|
18
|
+
async function cmdStatus(backend, opts = {}) {
|
|
19
|
+
const start = performance.now();
|
|
20
|
+
let result;
|
|
21
|
+
try {
|
|
22
|
+
result = await timedStatus("Checking connection...", async () => {
|
|
23
|
+
return backend.status({ userId: opts.userId, agentId: opts.agentId });
|
|
24
|
+
});
|
|
25
|
+
} catch (e) {
|
|
26
|
+
result = { connected: false, error: e instanceof Error ? e.message : String(e) };
|
|
27
|
+
}
|
|
28
|
+
const elapsed = (performance.now() - start) / 1e3;
|
|
29
|
+
if (opts.output === "json") {
|
|
30
|
+
formatJsonEnvelope({
|
|
31
|
+
command: "status",
|
|
32
|
+
data: {
|
|
33
|
+
connected: result.connected,
|
|
34
|
+
backend: result.backend ?? null,
|
|
35
|
+
base_url: result.base_url ?? null,
|
|
36
|
+
latency_ms: Math.round(elapsed * 1e3)
|
|
37
|
+
},
|
|
38
|
+
durationMs: Math.round(elapsed * 1e3)
|
|
39
|
+
});
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const lines = [];
|
|
43
|
+
if (result.connected) {
|
|
44
|
+
lines.push(` ${success("\u25CF")} Connected`);
|
|
45
|
+
} else {
|
|
46
|
+
lines.push(` ${errorColor("\u25CF")} Disconnected`);
|
|
47
|
+
}
|
|
48
|
+
lines.push(` ${dim("Backend:")} ${result.backend ?? "?"}`);
|
|
49
|
+
if (result.base_url) {
|
|
50
|
+
lines.push(` ${dim("API URL:")} ${result.base_url}`);
|
|
51
|
+
}
|
|
52
|
+
if (result.error) {
|
|
53
|
+
lines.push(` ${errorColor("Error:")} ${result.error}`);
|
|
54
|
+
}
|
|
55
|
+
lines.push(` ${dim("Latency:")} ${elapsed.toFixed(2)}s`);
|
|
56
|
+
const content = lines.join("\n");
|
|
57
|
+
console.log();
|
|
58
|
+
console.log(
|
|
59
|
+
boxen(content, {
|
|
60
|
+
title: brand("Connection Status"),
|
|
61
|
+
titleAlignment: "left",
|
|
62
|
+
borderColor: "magenta",
|
|
63
|
+
padding: 1
|
|
64
|
+
})
|
|
65
|
+
);
|
|
66
|
+
console.log();
|
|
67
|
+
}
|
|
68
|
+
function cmdVersion() {
|
|
69
|
+
console.log(` ${brand("\u25C6 Mem0")} CLI v${VERSION}`);
|
|
70
|
+
}
|
|
71
|
+
async function cmdImport(backend, filePath, opts) {
|
|
72
|
+
let data;
|
|
73
|
+
try {
|
|
74
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
75
|
+
const parsed = JSON.parse(raw);
|
|
76
|
+
data = Array.isArray(parsed) ? parsed : [parsed];
|
|
77
|
+
} catch (e) {
|
|
78
|
+
printError(`Failed to read file: ${e instanceof Error ? e.message : e}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
let added = 0;
|
|
82
|
+
let failed = 0;
|
|
83
|
+
const start = performance.now();
|
|
84
|
+
for (let i = 0; i < data.length; i++) {
|
|
85
|
+
const item = data[i];
|
|
86
|
+
const content = item.memory ?? item.text ?? item.content ?? "";
|
|
87
|
+
if (!content) {
|
|
88
|
+
failed++;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
await backend.add(content, void 0, {
|
|
93
|
+
userId: opts.userId ?? item.user_id,
|
|
94
|
+
agentId: opts.agentId ?? item.agent_id,
|
|
95
|
+
metadata: item.metadata
|
|
96
|
+
});
|
|
97
|
+
added++;
|
|
98
|
+
} catch {
|
|
99
|
+
failed++;
|
|
100
|
+
}
|
|
101
|
+
if ((i + 1) % 10 === 0 || i === data.length - 1) {
|
|
102
|
+
process.stdout.write(`\r ${dim(`Importing memories... ${i + 1}/${data.length}`)}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const elapsed = (performance.now() - start) / 1e3;
|
|
106
|
+
console.log();
|
|
107
|
+
if (opts.output === "json") {
|
|
108
|
+
formatJsonEnvelope({
|
|
109
|
+
command: "import",
|
|
110
|
+
data: { added, failed, duration_s: parseFloat(elapsed.toFixed(2)) },
|
|
111
|
+
durationMs: Math.round(elapsed * 1e3)
|
|
112
|
+
});
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
printSuccess(`Imported ${added} memories (${elapsed.toFixed(2)}s)`);
|
|
116
|
+
if (failed > 0) {
|
|
117
|
+
printError(`${failed} memories failed to import.`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export {
|
|
121
|
+
cmdImport,
|
|
122
|
+
cmdStatus,
|
|
123
|
+
cmdVersion
|
|
124
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mem0/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The official CLI for mem0 — the memory layer for AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"mem0": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
11
|
+
"dev": "tsx src/index.ts",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"test:watch": "vitest",
|
|
14
|
+
"lint": "biome check src/",
|
|
15
|
+
"lint:fix": "biome check --write src/",
|
|
16
|
+
"typecheck": "tsc --noEmit"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18.0.0"
|
|
20
|
+
},
|
|
21
|
+
"license": "Apache-2.0",
|
|
22
|
+
"author": "mem0.ai <founders@mem0.ai>",
|
|
23
|
+
"keywords": ["mem0", "memory", "ai", "agents", "cli"],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"commander": "^12.0.0",
|
|
29
|
+
"chalk": "^5.3.0",
|
|
30
|
+
"cli-table3": "^0.6.4",
|
|
31
|
+
"ora": "^8.0.0",
|
|
32
|
+
"boxen": "^7.1.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"typescript": "^5.4.0",
|
|
36
|
+
"tsup": "^8.0.0",
|
|
37
|
+
"tsx": "^4.7.0",
|
|
38
|
+
"vitest": "^1.5.0",
|
|
39
|
+
"@biomejs/biome": "^1.7.0",
|
|
40
|
+
"@types/node": "^20.0.0"
|
|
41
|
+
}
|
|
42
|
+
}
|