@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,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Entity management commands.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import readline from "node:readline";
|
|
6
|
+
import Table from "cli-table3";
|
|
7
|
+
import { printError, printInfo, printSuccess, timedStatus, colors } from "../branding.js";
|
|
8
|
+
import type { Backend } from "../backend/base.js";
|
|
9
|
+
import { formatJson } from "../output.js";
|
|
10
|
+
|
|
11
|
+
const { brand, accent, dim } = colors;
|
|
12
|
+
|
|
13
|
+
const VALID_TYPES = new Set(["users", "agents", "apps", "runs"]);
|
|
14
|
+
|
|
15
|
+
export async function cmdEntitiesList(
|
|
16
|
+
backend: Backend,
|
|
17
|
+
entityType: string,
|
|
18
|
+
opts: { output: string },
|
|
19
|
+
): Promise<void> {
|
|
20
|
+
if (!VALID_TYPES.has(entityType)) {
|
|
21
|
+
printError(`Invalid entity type: ${entityType}. Use: ${[...VALID_TYPES].join(", ")}`);
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const start = performance.now();
|
|
26
|
+
let results: Record<string, unknown>[];
|
|
27
|
+
try {
|
|
28
|
+
results = await timedStatus(`Fetching ${entityType}...`, async () => {
|
|
29
|
+
return backend.entities(entityType);
|
|
30
|
+
});
|
|
31
|
+
} catch (e) {
|
|
32
|
+
printError(
|
|
33
|
+
e instanceof Error ? e.message : String(e),
|
|
34
|
+
"This feature may require the mem0 Platform.",
|
|
35
|
+
);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
const elapsed = (performance.now() - start) / 1000;
|
|
39
|
+
|
|
40
|
+
if (opts.output === "json") {
|
|
41
|
+
formatJson(results);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!results.length) {
|
|
46
|
+
printInfo(`No ${entityType} found.`);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const table = new Table({
|
|
51
|
+
head: [accent("Name / ID"), accent("Created")],
|
|
52
|
+
style: { head: [], border: [] },
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
for (const entity of results) {
|
|
56
|
+
const name = String(entity.name ?? entity.id ?? "—");
|
|
57
|
+
const created = String(entity.created_at ?? "—").slice(0, 10);
|
|
58
|
+
table.push([name, created]);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log();
|
|
62
|
+
console.log(table.toString());
|
|
63
|
+
console.log(` ${dim(`${results.length} ${entityType} (${elapsed.toFixed(2)}s)`)}`);
|
|
64
|
+
console.log();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function cmdEntitiesDelete(
|
|
68
|
+
backend: Backend,
|
|
69
|
+
opts: {
|
|
70
|
+
userId?: string;
|
|
71
|
+
agentId?: string;
|
|
72
|
+
appId?: string;
|
|
73
|
+
runId?: string;
|
|
74
|
+
dryRun?: boolean;
|
|
75
|
+
force: boolean;
|
|
76
|
+
output: string;
|
|
77
|
+
},
|
|
78
|
+
): Promise<void> {
|
|
79
|
+
if (!opts.userId && !opts.agentId && !opts.appId && !opts.runId) {
|
|
80
|
+
printError("Provide at least one of --user-id, --agent-id, --app-id, --run-id.");
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (opts.dryRun) {
|
|
85
|
+
const scopeParts: string[] = [];
|
|
86
|
+
if (opts.userId) scopeParts.push(`user=${opts.userId}`);
|
|
87
|
+
if (opts.agentId) scopeParts.push(`agent=${opts.agentId}`);
|
|
88
|
+
if (opts.appId) scopeParts.push(`app=${opts.appId}`);
|
|
89
|
+
if (opts.runId) scopeParts.push(`run=${opts.runId}`);
|
|
90
|
+
printInfo(`Would delete entity ${scopeParts.join(", ")} and all its memories.`);
|
|
91
|
+
printInfo("No changes made.");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!opts.force) {
|
|
96
|
+
const scopeParts: string[] = [];
|
|
97
|
+
if (opts.userId) scopeParts.push(`user=${opts.userId}`);
|
|
98
|
+
if (opts.agentId) scopeParts.push(`agent=${opts.agentId}`);
|
|
99
|
+
if (opts.appId) scopeParts.push(`app=${opts.appId}`);
|
|
100
|
+
if (opts.runId) scopeParts.push(`run=${opts.runId}`);
|
|
101
|
+
const scope = scopeParts.join(", ");
|
|
102
|
+
|
|
103
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
104
|
+
const answer = await new Promise<string>((resolve) => {
|
|
105
|
+
rl.question(
|
|
106
|
+
`\n \u26a0 Delete entity ${scope} AND all its memories? This cannot be undone. [y/N] `,
|
|
107
|
+
resolve,
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
rl.close();
|
|
111
|
+
if (answer.toLowerCase() !== "y") {
|
|
112
|
+
printInfo("Cancelled.");
|
|
113
|
+
process.exit(0);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const start = performance.now();
|
|
118
|
+
let result: Record<string, unknown>;
|
|
119
|
+
try {
|
|
120
|
+
result = await timedStatus("Deleting entity...", async () => {
|
|
121
|
+
return backend.deleteEntities({
|
|
122
|
+
userId: opts.userId,
|
|
123
|
+
agentId: opts.agentId,
|
|
124
|
+
appId: opts.appId,
|
|
125
|
+
runId: opts.runId,
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
} catch (e) {
|
|
129
|
+
printError(e instanceof Error ? e.message : String(e));
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
const elapsed = (performance.now() - start) / 1000;
|
|
133
|
+
|
|
134
|
+
if (opts.output === "json") {
|
|
135
|
+
formatJson(result);
|
|
136
|
+
} else if (opts.output !== "quiet") {
|
|
137
|
+
printSuccess(`Entity deleted with all memories (${elapsed.toFixed(2)}s)`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mem0 init — interactive setup wizard.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import readline from "node:readline";
|
|
6
|
+
import {
|
|
7
|
+
printBanner,
|
|
8
|
+
printError,
|
|
9
|
+
printInfo,
|
|
10
|
+
printSuccess,
|
|
11
|
+
colors,
|
|
12
|
+
} from "../branding.js";
|
|
13
|
+
import { type Mem0Config, createDefaultConfig, saveConfig } from "../config.js";
|
|
14
|
+
import { PlatformBackend } from "../backend/platform.js";
|
|
15
|
+
|
|
16
|
+
const { brand, dim } = colors;
|
|
17
|
+
|
|
18
|
+
function promptSecret(label: string): Promise<string> {
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
process.stdout.write(label);
|
|
21
|
+
|
|
22
|
+
if (process.stdin.isTTY) {
|
|
23
|
+
process.stdin.setRawMode(true);
|
|
24
|
+
}
|
|
25
|
+
process.stdin.resume();
|
|
26
|
+
process.stdin.setEncoding("utf-8");
|
|
27
|
+
|
|
28
|
+
const chars: string[] = [];
|
|
29
|
+
|
|
30
|
+
const onData = (key: string) => {
|
|
31
|
+
for (const ch of key) {
|
|
32
|
+
if (ch === "\r" || ch === "\n") {
|
|
33
|
+
cleanup();
|
|
34
|
+
process.stdout.write("\n");
|
|
35
|
+
resolve(chars.join(""));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (ch === "\x03") {
|
|
39
|
+
cleanup();
|
|
40
|
+
reject(new Error("Interrupted"));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (ch === "\x7f" || ch === "\x08") {
|
|
44
|
+
// backspace
|
|
45
|
+
if (chars.length > 0) {
|
|
46
|
+
chars.pop();
|
|
47
|
+
process.stdout.write("\b \b");
|
|
48
|
+
}
|
|
49
|
+
} else if (ch === "\x15") {
|
|
50
|
+
// Ctrl+U — clear line
|
|
51
|
+
process.stdout.write("\b \b".repeat(chars.length));
|
|
52
|
+
chars.length = 0;
|
|
53
|
+
} else if (ch >= " ") {
|
|
54
|
+
chars.push(ch);
|
|
55
|
+
process.stdout.write("*");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const cleanup = () => {
|
|
61
|
+
process.stdin.removeListener("data", onData);
|
|
62
|
+
if (process.stdin.isTTY) {
|
|
63
|
+
process.stdin.setRawMode(false);
|
|
64
|
+
}
|
|
65
|
+
process.stdin.pause();
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
process.stdin.on("data", onData);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function promptLine(label: string, defaultValue?: string): Promise<string> {
|
|
73
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
74
|
+
const prompt = defaultValue ? `${label} [${defaultValue}]: ` : `${label}: `;
|
|
75
|
+
return new Promise((resolve) => {
|
|
76
|
+
rl.question(prompt, (answer) => {
|
|
77
|
+
rl.close();
|
|
78
|
+
resolve(answer.trim() || defaultValue || "");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function setupPlatform(config: Mem0Config): Promise<void> {
|
|
84
|
+
console.log();
|
|
85
|
+
console.log(` ${dim("Get your API key at https://app.mem0.ai/dashboard/api-keys")}`);
|
|
86
|
+
console.log();
|
|
87
|
+
|
|
88
|
+
process.stdout.write(` ${brand("API Key")}: `);
|
|
89
|
+
const apiKey = await promptSecret("");
|
|
90
|
+
if (!apiKey) {
|
|
91
|
+
printError("API key is required.");
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
config.platform.apiKey = apiKey;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function setupDefaults(config: Mem0Config): Promise<void> {
|
|
98
|
+
console.log();
|
|
99
|
+
printInfo("Set default entity IDs (press Enter to skip).\n");
|
|
100
|
+
|
|
101
|
+
const userId = await promptLine(` ${brand("Default User ID")} ${dim("(recommended)")}`, "mem0-cli");
|
|
102
|
+
if (userId) config.defaults.userId = userId;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async function validatePlatform(config: Mem0Config): Promise<void> {
|
|
106
|
+
console.log();
|
|
107
|
+
printInfo("Validating connection...");
|
|
108
|
+
try {
|
|
109
|
+
const backend = new PlatformBackend(config.platform);
|
|
110
|
+
const status = await backend.status({
|
|
111
|
+
userId: config.defaults.userId || undefined,
|
|
112
|
+
agentId: config.defaults.agentId || undefined,
|
|
113
|
+
});
|
|
114
|
+
if (status.connected) {
|
|
115
|
+
printSuccess("Connected to mem0 Platform!");
|
|
116
|
+
} else {
|
|
117
|
+
printError(
|
|
118
|
+
`Could not connect: ${status.error ?? "Unknown error"}`,
|
|
119
|
+
"Check your API key and try again.",
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
} catch (e) {
|
|
123
|
+
printError(`Connection test failed: ${e instanceof Error ? e.message : e}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function runInit(opts: { apiKey?: string; userId?: string } = {}): Promise<void> {
|
|
128
|
+
const config = createDefaultConfig();
|
|
129
|
+
|
|
130
|
+
// Non-interactive: both flags provided
|
|
131
|
+
if (opts.apiKey && opts.userId) {
|
|
132
|
+
config.platform.apiKey = opts.apiKey;
|
|
133
|
+
config.defaults.userId = opts.userId;
|
|
134
|
+
await validatePlatform(config);
|
|
135
|
+
saveConfig(config);
|
|
136
|
+
printSuccess("Configuration saved to ~/.mem0/config.json");
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Non-TTY without full flags: error with usage hint
|
|
141
|
+
if (!process.stdin.isTTY && (!opts.apiKey || !opts.userId)) {
|
|
142
|
+
printError(
|
|
143
|
+
"Non-interactive terminal detected and missing required flags.",
|
|
144
|
+
"Usage: mem0 init --api-key <key> --user-id <id>",
|
|
145
|
+
);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
printBanner();
|
|
150
|
+
console.log();
|
|
151
|
+
printInfo("Welcome! Let's set up your mem0 CLI.\n");
|
|
152
|
+
|
|
153
|
+
// Use provided API key or prompt
|
|
154
|
+
if (opts.apiKey) {
|
|
155
|
+
config.platform.apiKey = opts.apiKey;
|
|
156
|
+
} else {
|
|
157
|
+
await setupPlatform(config);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Use provided user ID or prompt
|
|
161
|
+
if (opts.userId) {
|
|
162
|
+
config.defaults.userId = opts.userId;
|
|
163
|
+
} else {
|
|
164
|
+
await setupDefaults(config);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
await validatePlatform(config);
|
|
168
|
+
|
|
169
|
+
saveConfig(config);
|
|
170
|
+
console.log();
|
|
171
|
+
printSuccess("Configuration saved to ~/.mem0/config.json");
|
|
172
|
+
console.log();
|
|
173
|
+
console.log(` ${dim("Get started:")}`);
|
|
174
|
+
if (config.defaults.userId) {
|
|
175
|
+
console.log(` ${dim(' mem0 add "I prefer dark mode"')}`);
|
|
176
|
+
console.log(` ${dim(' mem0 search "preferences"')}`);
|
|
177
|
+
} else {
|
|
178
|
+
console.log(` ${dim(' mem0 add "I prefer dark mode" --user-id alice')}`);
|
|
179
|
+
console.log(` ${dim(' mem0 search "preferences" --user-id alice')}`);
|
|
180
|
+
}
|
|
181
|
+
console.log();
|
|
182
|
+
}
|