@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 ADDED
@@ -0,0 +1,75 @@
1
+ # mem0 CLI (Node.js)
2
+
3
+ The official command-line interface for [mem0](https://mem0.ai) — the memory layer for AI agents. TypeScript implementation.
4
+
5
+ ## Prerequisites
6
+
7
+ - Node.js **18+**
8
+ - pnpm (`npm install -g pnpm`)
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install -g @mem0/cli
14
+ ```
15
+
16
+ Or from source:
17
+
18
+ ```bash
19
+ cd node
20
+ pnpm install
21
+ pnpm build
22
+ pnpm link --global
23
+
24
+ # Now use it like a normal CLI
25
+ mem0 --help
26
+ ```
27
+
28
+ ## Running during development
29
+
30
+ ```bash
31
+ cd node
32
+ pnpm install
33
+
34
+ # Development mode (runs TypeScript directly, no build needed)
35
+ pnpm dev --help
36
+ pnpm dev add "test memory" --user-id alice
37
+ pnpm dev search "test" --user-id alice
38
+
39
+ # Or build first, then run the compiled JS
40
+ pnpm build
41
+ node dist/index.js --help
42
+ node dist/index.js add "test memory" --user-id alice
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```bash
48
+ # Set up your configuration
49
+ mem0 init
50
+
51
+ # Add a memory
52
+ mem0 add "I prefer dark mode and use vim keybindings" --user-id alice
53
+
54
+ # Search memories
55
+ mem0 search "What are Alice's preferences?" --user-id alice
56
+
57
+ # List all memories
58
+ mem0 list --user-id alice
59
+ ```
60
+
61
+ ## Environment Variables
62
+
63
+ | Variable | Description |
64
+ |----------|-------------|
65
+ | `MEM0_API_KEY` | API key (overrides config file) |
66
+ | `MEM0_BASE_URL` | API base URL |
67
+ | `MEM0_USER_ID` | Default user ID |
68
+ | `MEM0_AGENT_ID` | Default agent ID |
69
+ | `MEM0_APP_ID` | Default app ID |
70
+ | `MEM0_RUN_ID` | Default run ID |
71
+ | `MEM0_ENABLE_GRAPH` | Enable graph memory (true/false) |
72
+
73
+ ## License
74
+
75
+ Apache-2.0
package/development.md ADDED
@@ -0,0 +1,91 @@
1
+ # Development
2
+
3
+ ## Prerequisites
4
+
5
+ - Node.js **18+**
6
+ - pnpm (`npm install -g pnpm`)
7
+
8
+ ## Setup
9
+
10
+ From the `node/` directory:
11
+
12
+ ```bash
13
+ pnpm install
14
+ ```
15
+
16
+ ## Running the CLI
17
+
18
+ There are two ways to run the CLI during development:
19
+
20
+ ### Option 1: Development mode (no build needed)
21
+
22
+ Uses `tsx` to run TypeScript directly. Pass CLI arguments after `pnpm dev`:
23
+
24
+ ```bash
25
+ pnpm dev --help
26
+ pnpm dev version
27
+ pnpm dev add "test memory" --user-id alice
28
+ pnpm dev search "test" --user-id alice
29
+ pnpm dev config show
30
+ ```
31
+
32
+ > **Note:** Do NOT use `pnpm dev -- --help`. With pnpm, arguments pass through directly — adding `--` inserts a literal `--` that breaks the CLI parser.
33
+
34
+ ### Option 2: Build and run compiled JS
35
+
36
+ ```bash
37
+ # Build first
38
+ pnpm build
39
+
40
+ # Run the compiled CLI
41
+ node dist/index.js --help
42
+ node dist/index.js version
43
+ node dist/index.js add "test memory" --user-id alice
44
+ ```
45
+
46
+ ### Option 3: Link globally (makes `mem0` available system-wide)
47
+
48
+ ```bash
49
+ pnpm build
50
+ pnpm link --global
51
+
52
+ # Now use it like a normal CLI
53
+ mem0 --help
54
+ mem0 version
55
+ ```
56
+
57
+ > **Warning:** If you also have the Python CLI installed, both register the `mem0` command. The last one linked/installed wins. Unlink with `pnpm unlink --global`.
58
+
59
+ ## Build
60
+
61
+ ```bash
62
+ pnpm build
63
+ ```
64
+
65
+ The compiled output is in `dist/`.
66
+
67
+ ## Run tests
68
+
69
+ ```bash
70
+ # Run all tests
71
+ pnpm test
72
+
73
+ # Watch mode
74
+ pnpm test:watch
75
+ ```
76
+
77
+ ## Lint
78
+
79
+ ```bash
80
+ # Check
81
+ pnpm lint
82
+
83
+ # Auto-fix
84
+ pnpm lint:fix
85
+ ```
86
+
87
+ ## Type checking
88
+
89
+ ```bash
90
+ pnpm typecheck
91
+ ```
@@ -0,0 +1,120 @@
1
+ // src/config.ts
2
+ import fs from "fs";
3
+ import os from "os";
4
+ import path from "path";
5
+ var CONFIG_DIR = path.join(os.homedir(), ".mem0");
6
+ var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
7
+ var DEFAULT_BASE_URL = "https://api.mem0.ai";
8
+ var CONFIG_VERSION = 1;
9
+ function createDefaultConfig() {
10
+ return {
11
+ version: CONFIG_VERSION,
12
+ defaults: {
13
+ userId: "",
14
+ agentId: "",
15
+ appId: "",
16
+ runId: "",
17
+ enableGraph: false
18
+ },
19
+ platform: {
20
+ apiKey: "",
21
+ baseUrl: DEFAULT_BASE_URL
22
+ }
23
+ };
24
+ }
25
+ function ensureConfigDir() {
26
+ fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
27
+ return CONFIG_DIR;
28
+ }
29
+ function loadConfig() {
30
+ const config = createDefaultConfig();
31
+ if (fs.existsSync(CONFIG_FILE)) {
32
+ const raw = fs.readFileSync(CONFIG_FILE, "utf-8");
33
+ const data = JSON.parse(raw);
34
+ config.version = data.version ?? CONFIG_VERSION;
35
+ const plat = data.platform ?? {};
36
+ config.platform.apiKey = plat.api_key ?? "";
37
+ config.platform.baseUrl = plat.base_url ?? DEFAULT_BASE_URL;
38
+ const defaults = data.defaults ?? {};
39
+ config.defaults.userId = defaults.user_id ?? "";
40
+ config.defaults.agentId = defaults.agent_id ?? "";
41
+ config.defaults.appId = defaults.app_id ?? "";
42
+ config.defaults.runId = defaults.run_id ?? "";
43
+ config.defaults.enableGraph = defaults.enable_graph ?? false;
44
+ }
45
+ if (process.env.MEM0_API_KEY) config.platform.apiKey = process.env.MEM0_API_KEY;
46
+ if (process.env.MEM0_BASE_URL) config.platform.baseUrl = process.env.MEM0_BASE_URL;
47
+ if (process.env.MEM0_USER_ID) config.defaults.userId = process.env.MEM0_USER_ID;
48
+ if (process.env.MEM0_AGENT_ID) config.defaults.agentId = process.env.MEM0_AGENT_ID;
49
+ if (process.env.MEM0_APP_ID) config.defaults.appId = process.env.MEM0_APP_ID;
50
+ if (process.env.MEM0_RUN_ID) config.defaults.runId = process.env.MEM0_RUN_ID;
51
+ if (process.env.MEM0_ENABLE_GRAPH) {
52
+ config.defaults.enableGraph = ["true", "1", "yes"].includes(
53
+ process.env.MEM0_ENABLE_GRAPH.toLowerCase()
54
+ );
55
+ }
56
+ return config;
57
+ }
58
+ function saveConfig(config) {
59
+ ensureConfigDir();
60
+ const data = {
61
+ version: config.version,
62
+ defaults: {
63
+ user_id: config.defaults.userId,
64
+ agent_id: config.defaults.agentId,
65
+ app_id: config.defaults.appId,
66
+ run_id: config.defaults.runId,
67
+ enable_graph: config.defaults.enableGraph
68
+ },
69
+ platform: {
70
+ api_key: config.platform.apiKey,
71
+ base_url: config.platform.baseUrl
72
+ }
73
+ };
74
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2));
75
+ fs.chmodSync(CONFIG_FILE, 384);
76
+ }
77
+ function redactKey(key) {
78
+ if (!key) return "(not set)";
79
+ if (key.length <= 8) return key.slice(0, 2) + "***";
80
+ return key.slice(0, 4) + "..." + key.slice(-4);
81
+ }
82
+ var KEY_MAP = {
83
+ "platform.api_key": ["platform", "apiKey"],
84
+ "platform.base_url": ["platform", "baseUrl"],
85
+ "defaults.user_id": ["defaults", "userId"],
86
+ "defaults.agent_id": ["defaults", "agentId"],
87
+ "defaults.app_id": ["defaults", "appId"],
88
+ "defaults.run_id": ["defaults", "runId"],
89
+ "defaults.enable_graph": ["defaults", "enableGraph"]
90
+ };
91
+ function getNestedValue(config, dottedKey) {
92
+ const mapping = KEY_MAP[dottedKey];
93
+ if (!mapping) return void 0;
94
+ const [section, field] = mapping;
95
+ return config[section][field];
96
+ }
97
+ function setNestedValue(config, dottedKey, value) {
98
+ const mapping = KEY_MAP[dottedKey];
99
+ if (!mapping) return false;
100
+ const [section, field] = mapping;
101
+ const obj = config[section];
102
+ const current = obj[field];
103
+ if (typeof current === "boolean") {
104
+ obj[field] = ["true", "1", "yes"].includes(value.toLowerCase());
105
+ } else if (typeof current === "number") {
106
+ obj[field] = parseInt(value, 10);
107
+ } else {
108
+ obj[field] = value;
109
+ }
110
+ return true;
111
+ }
112
+
113
+ export {
114
+ createDefaultConfig,
115
+ loadConfig,
116
+ saveConfig,
117
+ redactKey,
118
+ getNestedValue,
119
+ setNestedValue
120
+ };
@@ -0,0 +1,111 @@
1
+ // src/branding.ts
2
+ import chalk from "chalk";
3
+ import ora from "ora";
4
+ import { createRequire } from "module";
5
+ var _require = createRequire(import.meta.url);
6
+ var PKG_VERSION = _require("../package.json").version;
7
+ var LOGO = `
8
+ \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557
9
+ \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2551 \u2588\u2588\u2551
10
+ \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
11
+ \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551
12
+ \u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551
13
+ \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D
14
+ `;
15
+ var TAGLINE = "The Memory Layer for AI Agents";
16
+ var BRAND_COLOR = "#8b5cf6";
17
+ var ACCENT_COLOR = "#a78bfa";
18
+ var SUCCESS_COLOR = "#22c55e";
19
+ var ERROR_COLOR = "#ef4444";
20
+ var WARNING_COLOR = "#f59e0b";
21
+ var DIM_COLOR = "#6b7280";
22
+ var brand = chalk.hex(BRAND_COLOR);
23
+ var accent = chalk.hex(ACCENT_COLOR);
24
+ var success = chalk.hex(SUCCESS_COLOR);
25
+ var error = chalk.hex(ERROR_COLOR);
26
+ var warning = chalk.hex(WARNING_COLOR);
27
+ var dim = chalk.hex(DIM_COLOR);
28
+ function sym(fancy, plain) {
29
+ if (!process.stdout.isTTY || process.env.NO_COLOR) return plain;
30
+ return fancy;
31
+ }
32
+ function printBanner() {
33
+ const pad = 3;
34
+ const logoLines = LOGO.trimEnd().split("\n");
35
+ const tagline = ` ${TAGLINE}`;
36
+ const subtitle = `Node.js SDK \xB7 v${PKG_VERSION}`;
37
+ const contentLines = ["", ...logoLines, "", tagline, ""];
38
+ const maxContent = Math.max(...contentLines.map((l) => l.length));
39
+ const innerWidth = maxContent + pad * 2;
40
+ const totalWidth = innerWidth + 2;
41
+ const topBorder = brand(`\u256D${"\u2500".repeat(totalWidth - 2)}\u256E`);
42
+ const subtitleFill = totalWidth - 2 - subtitle.length - 3;
43
+ const bottomBorder = brand(`\u2570${"\u2500".repeat(subtitleFill)} ${dim(subtitle)} ${"\u2500"}\u256F`);
44
+ const body = contentLines.map((line) => {
45
+ const rightPad = innerWidth - pad - line.length;
46
+ return `${brand("\u2502")}${" ".repeat(pad)}${brand.bold(line)}${" ".repeat(Math.max(rightPad, 0))}${brand("\u2502")}`;
47
+ });
48
+ const taglineIdx = body.length - 2;
49
+ const taglineRightPad = innerWidth - pad - tagline.length;
50
+ body[taglineIdx] = `${brand("\u2502")}${" ".repeat(pad)}${accent(tagline)}${" ".repeat(Math.max(taglineRightPad, 0))}${brand("\u2502")}`;
51
+ console.log(topBorder);
52
+ for (const line of body) console.log(line);
53
+ console.log(bottomBorder);
54
+ }
55
+ function printSuccess(message) {
56
+ console.log(`${success(sym("\u2713", "[ok]"))} ${message}`);
57
+ }
58
+ function printError(message, hint) {
59
+ console.error(`${error(sym("\u2717", "[error]") + " Error:")} ${message}`);
60
+ if (hint) {
61
+ console.error(` ${dim(hint)}`);
62
+ }
63
+ }
64
+ function printInfo(message) {
65
+ console.log(`${brand(sym("\u25C6", "*"))} ${message}`);
66
+ }
67
+ function printScope(ids) {
68
+ const parts = [];
69
+ for (const [key, val] of Object.entries(ids)) {
70
+ if (val) {
71
+ const label = key.replace(/_/g, " ").replace("id", "ID").trim();
72
+ parts.push(`${label}=${val}`);
73
+ }
74
+ }
75
+ if (parts.length > 0) {
76
+ console.log(` ${dim(`Scope: ${parts.join(", ")}`)}`);
77
+ }
78
+ }
79
+ async function timedStatus(message, fn) {
80
+ const ctx = { successMsg: "", errorMsg: "" };
81
+ const spinner = ora({ text: dim(message), color: "magenta", stream: process.stderr }).start();
82
+ const start = performance.now();
83
+ try {
84
+ const result = await fn(ctx);
85
+ const elapsed = ((performance.now() - start) / 1e3).toFixed(2);
86
+ spinner.stop();
87
+ if (ctx.successMsg) {
88
+ console.error(`${success("\u2713")} ${ctx.successMsg} (${elapsed}s)`);
89
+ }
90
+ return result;
91
+ } catch (err) {
92
+ const elapsed = ((performance.now() - start) / 1e3).toFixed(2);
93
+ spinner.stop();
94
+ if (ctx.errorMsg) {
95
+ console.error(`${error("\u2717 Error:")} ${ctx.errorMsg} (${elapsed}s)`);
96
+ }
97
+ throw err;
98
+ }
99
+ }
100
+ var colors = { brand, accent, success, error, warning, dim };
101
+
102
+ export {
103
+ sym,
104
+ printBanner,
105
+ printSuccess,
106
+ printError,
107
+ printInfo,
108
+ printScope,
109
+ timedStatus,
110
+ colors
111
+ };
@@ -0,0 +1,187 @@
1
+ import {
2
+ colors,
3
+ sym
4
+ } from "./chunk-I7ABQZUR.js";
5
+
6
+ // src/output.ts
7
+ import Table from "cli-table3";
8
+ import boxen from "boxen";
9
+ var { brand, accent, success, error: errorColor, dim } = colors;
10
+ function formatDate(dtStr) {
11
+ if (!dtStr) return void 0;
12
+ try {
13
+ const dt = new Date(dtStr.replace("Z", "+00:00"));
14
+ return dt.toISOString().slice(0, 10);
15
+ } catch {
16
+ return dtStr?.slice(0, 10);
17
+ }
18
+ }
19
+ function formatMemoriesText(memories, title = "memories") {
20
+ const count = memories.length;
21
+ console.log(`
22
+ ${brand(`Found ${count} ${title}:`)}
23
+ `);
24
+ for (let i = 0; i < memories.length; i++) {
25
+ const mem = memories[i];
26
+ const memoryText = mem.memory ?? mem.text ?? "";
27
+ const memId = (mem.id ?? "").slice(0, 8);
28
+ const score = mem.score;
29
+ const created = formatDate(mem.created_at);
30
+ let category;
31
+ const cats = mem.categories;
32
+ if (Array.isArray(cats)) {
33
+ category = cats[0];
34
+ }
35
+ console.log(` ${i + 1}. ${memoryText}`);
36
+ const details = [];
37
+ if (score !== void 0) details.push(`Score: ${score.toFixed(2)}`);
38
+ if (memId) details.push(`ID: ${memId}`);
39
+ if (created) details.push(`Created: ${created}`);
40
+ if (category) details.push(`Category: ${category}`);
41
+ if (details.length > 0) {
42
+ console.log(` ${dim(details.join(" \xB7 "))}`);
43
+ }
44
+ console.log();
45
+ }
46
+ }
47
+ function formatMemoriesTable(memories) {
48
+ const table = new Table({
49
+ head: [accent("ID"), accent("Memory"), accent("Category"), accent("Created")],
50
+ colWidths: [12, 52, 16, 14],
51
+ wordWrap: true,
52
+ style: { head: [], border: [] }
53
+ });
54
+ for (const mem of memories) {
55
+ const memId = (mem.id ?? "").slice(0, 8);
56
+ let memoryText = mem.memory ?? mem.text ?? "";
57
+ if (memoryText.length > 60) {
58
+ memoryText = memoryText.slice(0, 57) + "...";
59
+ }
60
+ const categories = mem.categories;
61
+ const cat = Array.isArray(categories) && categories.length > 0 ? categories[0] : "\u2014";
62
+ const created = formatDate(mem.created_at) ?? "\u2014";
63
+ table.push([dim(memId), memoryText, cat, created]);
64
+ }
65
+ console.log();
66
+ console.log(table.toString());
67
+ console.log();
68
+ }
69
+ function formatJson(data) {
70
+ console.log(JSON.stringify(data, null, 2));
71
+ }
72
+ function formatSingleMemory(mem, output = "text") {
73
+ if (output === "json") {
74
+ formatJson(mem);
75
+ return;
76
+ }
77
+ const memoryText = mem.memory ?? mem.text ?? "";
78
+ const memId = mem.id ?? "";
79
+ const lines = [];
80
+ lines.push(` ${memoryText}`);
81
+ lines.push("");
82
+ if (memId) lines.push(` ${dim("ID:")} ${memId}`);
83
+ const created = formatDate(mem.created_at);
84
+ if (created) lines.push(` ${dim("Created:")} ${created}`);
85
+ const updated = formatDate(mem.updated_at);
86
+ if (updated) lines.push(` ${dim("Updated:")} ${updated}`);
87
+ const meta = mem.metadata;
88
+ if (meta) lines.push(` ${dim("Metadata:")} ${JSON.stringify(meta)}`);
89
+ const categories = mem.categories;
90
+ if (categories) {
91
+ const catStr = Array.isArray(categories) ? categories.join(", ") : String(categories);
92
+ lines.push(` ${dim("Categories:")} ${catStr}`);
93
+ }
94
+ const content = lines.join("\n");
95
+ console.log();
96
+ console.log(
97
+ boxen(content, {
98
+ title: brand("Memory"),
99
+ titleAlignment: "left",
100
+ borderColor: "magenta",
101
+ padding: 1
102
+ })
103
+ );
104
+ console.log();
105
+ }
106
+ function formatAddResult(result, output = "text") {
107
+ if (output === "json") {
108
+ formatJson(result);
109
+ return;
110
+ }
111
+ if (output === "quiet") return;
112
+ const results = Array.isArray(result) ? result : result.results ?? [result];
113
+ if (!results.length) {
114
+ console.log(` ${dim("No memories extracted.")}`);
115
+ return;
116
+ }
117
+ console.log();
118
+ for (const r of results) {
119
+ if (r.status === "PENDING") {
120
+ const eventId = (r.event_id ?? "").slice(0, 8);
121
+ const icon2 = accent(sym("\u29D7", "..."));
122
+ const parts2 = [` ${icon2} ${dim("Queued".padEnd(10))}`, "Processing in background"];
123
+ if (eventId) parts2.push(dim(`(event ${eventId})`));
124
+ console.log(parts2.join(" "));
125
+ continue;
126
+ }
127
+ const event = r.event ?? "ADD";
128
+ const memory = r.memory ?? r.text ?? r.content ?? r.data ?? "";
129
+ const memId = (r.id ?? r.memory_id ?? "").slice(0, 8);
130
+ let icon;
131
+ let label;
132
+ if (event === "ADD") {
133
+ icon = success("+");
134
+ label = "Added";
135
+ } else if (event === "UPDATE") {
136
+ icon = accent("~");
137
+ label = "Updated";
138
+ } else if (event === "DELETE") {
139
+ icon = errorColor("-");
140
+ label = "Deleted";
141
+ } else if (event === "NOOP") {
142
+ icon = dim("\xB7");
143
+ label = "No change";
144
+ } else {
145
+ icon = dim("?");
146
+ label = event;
147
+ }
148
+ const parts = [` ${icon} ${dim(label.padEnd(10))}`];
149
+ if (memory) parts.push(memory);
150
+ if (memId) parts.push(dim(`(${memId})`));
151
+ console.log(parts.join(" "));
152
+ }
153
+ console.log();
154
+ }
155
+ function formatJsonEnvelope(opts) {
156
+ const envelope = {
157
+ status: opts.status ?? "success",
158
+ command: opts.command
159
+ };
160
+ if (opts.durationMs !== void 0) envelope.duration_ms = opts.durationMs;
161
+ if (opts.scope !== void 0) envelope.scope = opts.scope;
162
+ if (opts.count !== void 0) envelope.count = opts.count;
163
+ if (opts.error) envelope.error = opts.error;
164
+ envelope.data = opts.data;
165
+ console.log(JSON.stringify(envelope, null, 2));
166
+ }
167
+ function printResultSummary(opts) {
168
+ const parts = [`${opts.count} result${opts.count !== 1 ? "s" : ""}`];
169
+ if (opts.page !== void 0) parts.push(`page ${opts.page}`);
170
+ if (opts.scopeIds) {
171
+ const scopeParts = Object.entries(opts.scopeIds).filter(([, v]) => v).map(([k, v]) => `${k.replace(/_/g, " ")}=${v}`);
172
+ if (scopeParts.length > 0) parts.push(scopeParts.join(", "));
173
+ }
174
+ if (opts.durationSecs !== void 0) parts.push(`${opts.durationSecs.toFixed(2)}s`);
175
+ console.log(` ${dim(parts.join(" \xB7 "))}`);
176
+ console.log();
177
+ }
178
+
179
+ export {
180
+ formatMemoriesText,
181
+ formatMemoriesTable,
182
+ formatJson,
183
+ formatSingleMemory,
184
+ formatAddResult,
185
+ formatJsonEnvelope,
186
+ printResultSummary
187
+ };