@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
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
|
+
};
|