@agentmemory/agentmemory 0.7.9 → 0.8.1
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 +131 -112
- package/dist/cli.mjs +57 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +149 -17
- package/dist/index.mjs.map +1 -1
- package/dist/{src-DNbB7fd7.mjs → src-Df36IFVL.mjs} +150 -18
- package/dist/src-Df36IFVL.mjs.map +1 -0
- package/dist/standalone.mjs +1 -1
- package/dist/standalone.mjs.map +1 -1
- package/dist/viewer/index.html +2888 -0
- package/package.json +2 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/src-DNbB7fd7.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -7,6 +7,13 @@
|
|
|
7
7
|
Persistent memory for Claude Code, Cursor, Gemini CLI, OpenCode, and any MCP client.
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://www.npmjs.com/package/@agentmemory/agentmemory"><img src="https://img.shields.io/npm/v/@agentmemory/agentmemory?color=CB3837&label=npm" alt="npm version" /></a>
|
|
12
|
+
<a href="https://github.com/rohitg00/agentmemory/actions"><img src="https://img.shields.io/github/actions/workflow/status/rohitg00/agentmemory/ci.yml?label=tests" alt="CI" /></a>
|
|
13
|
+
<a href="https://github.com/rohitg00/agentmemory/blob/main/LICENSE"><img src="https://img.shields.io/github/license/rohitg00/agentmemory?color=blue" alt="License" /></a>
|
|
14
|
+
<a href="https://github.com/rohitg00/agentmemory/stargazers"><img src="https://img.shields.io/github/stars/rohitg00/agentmemory?style=flat&color=yellow" alt="Stars" /></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
10
17
|
<p align="center">
|
|
11
18
|
<img src="assets/demo.gif" alt="agentmemory demo" width="720" />
|
|
12
19
|
</p>
|
|
@@ -14,23 +21,28 @@
|
|
|
14
21
|
<p align="center">
|
|
15
22
|
<a href="#quick-start">Quick Start</a> •
|
|
16
23
|
<a href="#why-agentmemory">Why</a> •
|
|
17
|
-
<a href="#
|
|
24
|
+
<a href="#benchmarks-measured-not-projected">Benchmarks</a> •
|
|
18
25
|
<a href="#how-it-works">How It Works</a> •
|
|
19
26
|
<a href="#search">Search</a> •
|
|
20
|
-
<a href="#memory-evolution">Memory Evolution</a> •
|
|
21
27
|
<a href="#mcp-server">MCP</a> •
|
|
22
28
|
<a href="#real-time-viewer">Viewer</a> •
|
|
23
|
-
<a href="#configuration">
|
|
29
|
+
<a href="#configuration">Config</a> •
|
|
24
30
|
<a href="#api">API</a>
|
|
25
31
|
</p>
|
|
26
32
|
|
|
27
33
|
---
|
|
28
34
|
|
|
29
|
-
You explain the same architecture every session. You re-discover the same bugs. You re-teach the same preferences. Built-in memory (CLAUDE.md, .cursorrules) caps out at 200 lines and goes stale. agentmemory fixes this
|
|
35
|
+
You explain the same architecture every session. You re-discover the same bugs. You re-teach the same preferences. Built-in memory (CLAUDE.md, .cursorrules) caps out at 200 lines and goes stale. agentmemory fixes this. It silently captures what your agent does, compresses it into searchable memory, and injects the right context when the next session starts. One command. Works across agents.
|
|
30
36
|
|
|
31
|
-
**What changes:** Session 1 you set up JWT auth. Session 2 you ask for rate limiting
|
|
37
|
+
**What changes:** Session 1 you set up JWT auth. Session 2 you ask for rate limiting. The agent already knows your auth uses jose middleware in `src/middleware/auth.ts`, your tests cover token validation, and you chose jose over jsonwebtoken for Edge compatibility. No re-explaining. No copy-pasting. The agent just *knows*.
|
|
32
38
|
|
|
33
|
-
|
|
39
|
+
| | |
|
|
40
|
+
|---|---|
|
|
41
|
+
| **95.2% R@5** | [LongMemEval](https://arxiv.org/abs/2410.10813) (ICLR 2025) retrieval accuracy |
|
|
42
|
+
| **92% fewer tokens** | ~1,900 injected vs ~19,000 full context ($10/yr vs $500+/yr) |
|
|
43
|
+
| **43 MCP tools** | Search, remember, forget, actions, leases, signals, mesh sync |
|
|
44
|
+
| **12 hooks** | Captures every tool use automatically, zero manual effort |
|
|
45
|
+
| **0 external deps** | No Postgres, no Redis, no vector DB. Just iii-engine (auto-installed) |
|
|
34
46
|
|
|
35
47
|
```bash
|
|
36
48
|
npx @agentmemory/agentmemory # installs iii-engine if missing, starts everything
|
|
@@ -38,6 +50,39 @@ npx @agentmemory/agentmemory # installs iii-engine if missing, starts everythi
|
|
|
38
50
|
|
|
39
51
|
---
|
|
40
52
|
|
|
53
|
+
## Quick Start
|
|
54
|
+
|
|
55
|
+
### Claude Code (paste this, the agent does the rest)
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
Install agentmemory: run `npx @agentmemory/agentmemory` in a separate terminal to start the memory server. Then run `/plugin marketplace add rohitg00/agentmemory` and `/plugin install agentmemory` to register all 12 hooks, 4 skills, and 43 MCP tools. Verify with `curl http://localhost:3111/agentmemory/health`. The real-time viewer is at http://localhost:3113.
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
That's it. Paste the block above into Claude Code. The agent handles installation, engine startup, plugin registration, and verification.
|
|
62
|
+
|
|
63
|
+
### Other agents
|
|
64
|
+
|
|
65
|
+
Start the memory server first: `npx @agentmemory/agentmemory`
|
|
66
|
+
|
|
67
|
+
Then add the MCP config for your agent. All agents use the same server, so memories are shared across them.
|
|
68
|
+
|
|
69
|
+
| Agent | Setup |
|
|
70
|
+
|---|---|
|
|
71
|
+
| **OpenClaw** | Add to MCP config: `{"mcpServers": {"agentmemory": {"command": "npx", "args": ["agentmemory-mcp"]}}}` |
|
|
72
|
+
| **Cursor** | Add to `~/.cursor/mcp.json`: `{"mcpServers": {"agentmemory": {"command": "npx", "args": ["agentmemory-mcp"]}}}` |
|
|
73
|
+
| **OpenCode** | Add to `.opencode/config.json`: `{"mcpServers": {"agentmemory": {"command": "npx", "args": ["agentmemory-mcp"]}}}` |
|
|
74
|
+
| **Codex CLI** | Add to `.codex/config.yaml`: `mcp_servers: {agentmemory: {command: npx, args: ["agentmemory-mcp"]}}` |
|
|
75
|
+
| **Gemini CLI** | `gemini mcp add agentmemory -- npx agentmemory-mcp` |
|
|
76
|
+
| **Hermes Agent** | Add to `~/.hermes/config.yaml`: `mcp_servers: {agentmemory: {command: npx, args: ["agentmemory-mcp"]}}` or use the [memory provider plugin](integrations/hermes/) |
|
|
77
|
+
| **Cline** | Add MCP server in Cline settings |
|
|
78
|
+
| **Goose** | Add to `~/.config/goose/config.yaml`: `mcp_servers: {agentmemory: {command: npx, args: ["agentmemory-mcp"]}}` |
|
|
79
|
+
| **Kilo Code** | Add MCP server in Kilo Code settings |
|
|
80
|
+
| **Aider** | Use REST API: `curl -X POST http://localhost:3111/agentmemory/smart-search -d '{"query": "auth"}'` |
|
|
81
|
+
| **Claude Desktop** | Add to `claude_desktop_config.json`: `{"mcpServers": {"agentmemory": {"command": "npx", "args": ["agentmemory-mcp"]}}}` |
|
|
82
|
+
| **Any agent (32+)** | `npx skillkit install agentmemory` |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
41
86
|
## Why agentmemory
|
|
42
87
|
|
|
43
88
|
Every coding agent forgets everything when the session ends. You waste the first 5 minutes of every session re-explaining your stack, your conventions, your recent decisions. agentmemory runs in the background and eliminates that entirely.
|
|
@@ -82,7 +127,7 @@ Session 2: "Now add rate limiting"
|
|
|
82
127
|
|
|
83
128
|
### How it compares to built-in agent memory
|
|
84
129
|
|
|
85
|
-
Every AI coding agent now ships with built-in memory
|
|
130
|
+
Every AI coding agent now ships with built-in memory. Claude Code has `MEMORY.md`, Cursor has notepads, Cline has memory bank. These work like sticky notes: fast, always-on, but fundamentally limited.
|
|
86
131
|
|
|
87
132
|
agentmemory is the searchable database behind the sticky notes.
|
|
88
133
|
|
|
@@ -103,6 +148,33 @@ agentmemory is the searchable database behind the sticky notes.
|
|
|
103
148
|
| Knowledge graph | No | Entity extraction + temporal versioning |
|
|
104
149
|
| Observability | Read files manually | Real-time viewer on :3113 |
|
|
105
150
|
|
|
151
|
+
### What it costs (spoiler: almost nothing)
|
|
152
|
+
|
|
153
|
+
| Approach | Tokens/year | Annual cost | Notes |
|
|
154
|
+
|---|---|---|---|
|
|
155
|
+
| Paste full history into context | 19.5M+ | Impossible | Exceeds context window after ~200 observations |
|
|
156
|
+
| LLM-summarized memory (extraction-based) | ~650K | ~$500/yr | Loses context, summarization is lossy |
|
|
157
|
+
| **agentmemory context injection** | **~170K** | **~$10/yr** | Token-budgeted, only relevant memories injected |
|
|
158
|
+
| agentmemory with local embeddings | ~170K | **$0** | all-MiniLM-L6-v2 runs locally, no API calls |
|
|
159
|
+
|
|
160
|
+
### How memory flows
|
|
161
|
+
|
|
162
|
+
```text
|
|
163
|
+
PostToolUse hook fires
|
|
164
|
+
-> SHA-256 dedup (5min window)
|
|
165
|
+
-> Privacy filter (strip secrets, API keys)
|
|
166
|
+
-> Store raw observation
|
|
167
|
+
-> LLM compress -> structured facts + concepts + narrative
|
|
168
|
+
-> Generate vector embedding
|
|
169
|
+
-> Index in BM25 + vector + knowledge graph
|
|
170
|
+
|
|
171
|
+
SessionStart hook fires
|
|
172
|
+
-> Load project profile (top concepts, files, patterns)
|
|
173
|
+
-> Hybrid search (BM25 + vector + graph) for recent context
|
|
174
|
+
-> Apply token budget (default: 2000 tokens)
|
|
175
|
+
-> Inject into conversation via stdout
|
|
176
|
+
```
|
|
177
|
+
|
|
106
178
|
### Benchmarks (measured, not projected)
|
|
107
179
|
|
|
108
180
|
#### LongMemEval-S (ICLR 2025, 500 questions)
|
|
@@ -124,7 +196,9 @@ These are retrieval recall scores (not end-to-end QA accuracy). Embedding model:
|
|
|
124
196
|
| agentmemory BM25 (stemmed + synonyms) | 55.9% | 82.7% | 95.5% | 1,571 |
|
|
125
197
|
| agentmemory + Xenova embeddings | **64.1%** | **94.9%** | **100.0%** | **1,571** |
|
|
126
198
|
|
|
127
|
-
agentmemory finds "N+1 query fix" when you search "database performance optimization"
|
|
199
|
+
agentmemory finds "N+1 query fix" when you search "database performance optimization". Keyword matching can't do this.
|
|
200
|
+
|
|
201
|
+
> **Methodology note:** All LongMemEval numbers are retrieval recall (`recall_any@K`), not end-to-end QA accuracy. We clearly distinguish these because the LongMemEval leaderboard measures QA accuracy (retrieve + generate + judge). No hyperparameters were tuned on the test set. Full scripts and results are committed and reproducible.
|
|
128
202
|
|
|
129
203
|
Full benchmark reports: [`benchmark/LONGMEMEVAL.md`](benchmark/LONGMEMEVAL.md), [`benchmark/QUALITY.md`](benchmark/QUALITY.md), [`benchmark/SCALE.md`](benchmark/SCALE.md), [`benchmark/REAL-EMBEDDINGS.md`](benchmark/REAL-EMBEDDINGS.md)
|
|
130
204
|
|
|
@@ -147,11 +221,17 @@ Any agent that connects to MCP servers can use agentmemory's 43 tools, 6 resourc
|
|
|
147
221
|
|
|
148
222
|
| Agent | How to connect |
|
|
149
223
|
|---|---|
|
|
150
|
-
| **
|
|
224
|
+
| **OpenClaw** (345K stars) | Add MCP server in settings |
|
|
225
|
+
| **OpenCode** (100K stars) | Add to `.opencode/config.json` MCP servers |
|
|
226
|
+
| **Gemini CLI** (98K stars) | `gemini mcp add agentmemory -- npx agentmemory-mcp` |
|
|
227
|
+
| **Codex CLI** (62K stars) | Add to `.codex/config.yaml` MCP servers |
|
|
228
|
+
| **Cline** (59K stars) | Add MCP server in Cline settings |
|
|
229
|
+
| **Cursor** (1M+ users) | Add MCP server in settings or `~/.cursor/mcp.json` |
|
|
230
|
+
| **Hermes Agent** (33K stars) | MCP config or [memory provider plugin](integrations/hermes/) |
|
|
231
|
+
| **Goose** (33K stars) | Add to `~/.config/goose/config.yaml` MCP servers |
|
|
232
|
+
| **Kilo Code** (1.5M users) | Add MCP server in Kilo Code settings |
|
|
233
|
+
| **Aider** (42K stars) | Use REST API (no MCP) |
|
|
151
234
|
| **Claude Desktop** | Add to `claude_desktop_config.json` MCP servers |
|
|
152
|
-
| **Gemini CLI** | `gemini mcp add agentmemory -- npx agentmemory-mcp` |
|
|
153
|
-
| **OpenCode** | Add to `.opencode/config.json` MCP servers |
|
|
154
|
-
| **Cline / Continue** | MCP server configuration |
|
|
155
235
|
| **Any MCP client** | Point to `http://localhost:3111/agentmemory/mcp/*` |
|
|
156
236
|
|
|
157
237
|
### REST API (any agent, any language)
|
|
@@ -173,130 +253,65 @@ GET /agentmemory/profile # Get project intelligence
|
|
|
173
253
|
|---|---|
|
|
174
254
|
| Claude Code user | Plugin install (hooks + MCP + skills) |
|
|
175
255
|
| Building a custom agent with Claude SDK | AgentSDKProvider (zero config) |
|
|
176
|
-
|
|
|
256
|
+
| OpenClaw, Cursor, Codex, OpenCode, Gemini CLI, Cline, Goose, Kilo Code | MCP server (43 tools + 6 resources + 3 prompts) |
|
|
257
|
+
| Hermes Agent user | [Memory provider plugin](integrations/hermes/) (deeper) or MCP |
|
|
177
258
|
| Building your own agent framework | REST API (103 endpoints) |
|
|
178
|
-
| Sharing memory across multiple agents | All agents point to the same
|
|
259
|
+
| Sharing memory across multiple agents | All agents point to the same agentmemory instance |
|
|
179
260
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
### 1. Start agentmemory
|
|
183
|
-
|
|
184
|
-
```bash
|
|
185
|
-
npx @agentmemory/agentmemory
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
This auto-installs iii-engine if missing, starts it, and runs the worker. One command.
|
|
189
|
-
|
|
190
|
-
Or from source:
|
|
261
|
+
### From source
|
|
191
262
|
|
|
192
263
|
```bash
|
|
193
264
|
git clone https://github.com/rohitg00/agentmemory.git && cd agentmemory
|
|
194
265
|
npm install && npm run build && npm start
|
|
195
266
|
```
|
|
196
267
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
**Claude Code (plugin — hooks + MCP + skills):**
|
|
200
|
-
|
|
201
|
-
```bash
|
|
202
|
-
/plugin marketplace add rohitg00/agentmemory
|
|
203
|
-
/plugin install agentmemory
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
All 12 hooks, 4 skills, and MCP server are registered automatically.
|
|
207
|
-
|
|
208
|
-
**Cursor / Claude Desktop / Cline / any MCP client:**
|
|
268
|
+
## First Steps After Install
|
|
209
269
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
```json
|
|
213
|
-
{
|
|
214
|
-
"mcpServers": {
|
|
215
|
-
"agentmemory": {
|
|
216
|
-
"command": "npx",
|
|
217
|
-
"args": ["agentmemory-mcp"]
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
```
|
|
270
|
+
Once hooks are installed, memory builds silently. No action needed. Just use your agent normally.
|
|
222
271
|
|
|
223
|
-
|
|
272
|
+
### Session 1: Your agent works as usual
|
|
224
273
|
|
|
225
|
-
```
|
|
226
|
-
|
|
274
|
+
```text
|
|
275
|
+
You: "Add JWT auth to the Express API"
|
|
276
|
+
Agent: reads files, writes code, runs tests, fixes errors
|
|
227
277
|
```
|
|
228
278
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
Add to `.opencode/config.json`:
|
|
279
|
+
agentmemory captures every tool use via PostToolUse hooks. At session end, 47 raw observations compress into structured memory:
|
|
232
280
|
|
|
233
281
|
```json
|
|
234
282
|
{
|
|
235
|
-
"
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
283
|
+
"type": "file_edit",
|
|
284
|
+
"title": "Implement JWT middleware with jose",
|
|
285
|
+
"facts": ["Using jose library for Edge compatibility", "JWT tokens expire after 30 days", "Middleware in src/middleware/auth.ts"],
|
|
286
|
+
"concepts": ["jwt", "authentication", "jose", "middleware"],
|
|
287
|
+
"files": ["src/middleware/auth.ts", "src/app/api/auth/route.ts"],
|
|
288
|
+
"importance": 9
|
|
241
289
|
}
|
|
242
290
|
```
|
|
243
291
|
|
|
244
|
-
|
|
292
|
+
### Session 2: The payoff
|
|
245
293
|
|
|
246
|
-
|
|
247
|
-
curl -X POST http://localhost:3111/agentmemory/remember \
|
|
248
|
-
-H "Content-Type: application/json" \
|
|
249
|
-
-d '{"content": "Always use jose for JWT on Edge", "type": "preference"}'
|
|
294
|
+
You start a new session. Before the agent responds, the SessionStart hook fires and injects context (~1,900 tokens):
|
|
250
295
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
-
|
|
296
|
+
```text
|
|
297
|
+
Agent already knows:
|
|
298
|
+
- Auth uses jose JWT middleware in src/middleware/auth.ts
|
|
299
|
+
- Tests in test/auth.test.ts cover token validation
|
|
300
|
+
- You chose jose over jsonwebtoken for Edge compatibility
|
|
301
|
+
- Rate limiting discussion from last week's debugging session
|
|
254
302
|
```
|
|
255
303
|
|
|
256
|
-
|
|
304
|
+
No re-explaining. The agent starts working immediately.
|
|
305
|
+
|
|
306
|
+
### How to verify it's working
|
|
257
307
|
|
|
258
308
|
```bash
|
|
309
|
+
npx @agentmemory/agentmemory status # quick terminal check
|
|
259
310
|
curl http://localhost:3111/agentmemory/health
|
|
260
|
-
open http://localhost:3113
|
|
311
|
+
open http://localhost:3113 # real-time viewer
|
|
261
312
|
```
|
|
262
313
|
|
|
263
|
-
|
|
264
|
-
{
|
|
265
|
-
"status": "healthy",
|
|
266
|
-
"service": "agentmemory",
|
|
267
|
-
"version": "0.7.7",
|
|
268
|
-
"health": {
|
|
269
|
-
"memory": { "heapUsed": 42000000, "heapTotal": 67000000 },
|
|
270
|
-
"cpu": { "percent": 2.1 },
|
|
271
|
-
"eventLoopLagMs": 1.2,
|
|
272
|
-
"status": "healthy"
|
|
273
|
-
},
|
|
274
|
-
"circuitBreaker": { "state": "closed", "failures": 0 }
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### Manual Hook Setup (alternative)
|
|
279
|
-
|
|
280
|
-
If you prefer not to use the plugin, add hooks directly to `~/.claude/settings.json`:
|
|
281
|
-
|
|
282
|
-
```json
|
|
283
|
-
{
|
|
284
|
-
"hooks": {
|
|
285
|
-
"SessionStart": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/session-start.mjs" }],
|
|
286
|
-
"UserPromptSubmit": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/prompt-submit.mjs" }],
|
|
287
|
-
"PreToolUse": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/pre-tool-use.mjs" }],
|
|
288
|
-
"PostToolUse": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/post-tool-use.mjs" }],
|
|
289
|
-
"PostToolUseFailure": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/post-tool-failure.mjs" }],
|
|
290
|
-
"PreCompact": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/pre-compact.mjs" }],
|
|
291
|
-
"SubagentStart": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/subagent-start.mjs" }],
|
|
292
|
-
"SubagentStop": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/subagent-stop.mjs" }],
|
|
293
|
-
"Notification": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/notification.mjs" }],
|
|
294
|
-
"TaskCompleted": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/task-completed.mjs" }],
|
|
295
|
-
"Stop": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/stop.mjs" }],
|
|
296
|
-
"SessionEnd": [{ "type": "command", "command": "node ~/agentmemory/dist/hooks/session-end.mjs" }]
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
```
|
|
314
|
+
After 1 session: check the Timeline tab in the viewer. After 2+ sessions: check Dashboard for memory count > 0 and the Token Savings card.
|
|
300
315
|
|
|
301
316
|
## How It Works
|
|
302
317
|
|
|
@@ -416,7 +431,7 @@ agentmemory automatically cleans itself:
|
|
|
416
431
|
| Mechanism | What it does |
|
|
417
432
|
|---|---|
|
|
418
433
|
| **TTL expiry** | Memories with `forgetAfter` date are deleted when expired |
|
|
419
|
-
| **Contradiction detection** | Near-duplicate memories (Jaccard > 0.9)
|
|
434
|
+
| **Contradiction detection** | Near-duplicate memories (Jaccard > 0.9), older one is demoted |
|
|
420
435
|
| **Low-value eviction** | Observations older than 90 days with importance < 3 are removed |
|
|
421
436
|
| **Per-project cap** | Projects are capped at 10,000 observations (lowest importance evicted first) |
|
|
422
437
|
|
|
@@ -613,7 +628,8 @@ agentmemory needs an LLM for compressing observations and generating summaries.
|
|
|
613
628
|
| Provider | Config | Notes |
|
|
614
629
|
|----------|--------|-------|
|
|
615
630
|
| **Claude subscription** (default) | No config needed | Uses `@anthropic-ai/claude-agent-sdk`. Zero cost beyond your Max/Pro plan |
|
|
616
|
-
| **Anthropic API** | `ANTHROPIC_API_KEY` | Direct API access, per-token billing |
|
|
631
|
+
| **Anthropic API** | `ANTHROPIC_API_KEY` | Direct API access, per-token billing. Supports `ANTHROPIC_BASE_URL` for custom endpoints |
|
|
632
|
+
| **MiniMax** | `MINIMAX_API_KEY` | Anthropic-compatible API. Default model: `MiniMax-M2.7` |
|
|
617
633
|
| **Gemini** | `GEMINI_API_KEY` | Also enables Gemini embeddings (free tier) |
|
|
618
634
|
| **OpenRouter** | `OPENROUTER_API_KEY` | Access any model through one API |
|
|
619
635
|
|
|
@@ -626,6 +642,9 @@ Create `~/.agentmemory/.env`:
|
|
|
626
642
|
```env
|
|
627
643
|
# LLM provider (pick one, or leave empty for Claude subscription)
|
|
628
644
|
ANTHROPIC_API_KEY=sk-ant-...
|
|
645
|
+
# ANTHROPIC_BASE_URL=https://custom-endpoint.example.com
|
|
646
|
+
# MINIMAX_API_KEY=...
|
|
647
|
+
# MINIMAX_MODEL=MiniMax-M2.7
|
|
629
648
|
# GEMINI_API_KEY=...
|
|
630
649
|
# OPENROUTER_API_KEY=...
|
|
631
650
|
|
|
@@ -640,7 +659,7 @@ ANTHROPIC_API_KEY=sk-ant-...
|
|
|
640
659
|
# VECTOR_WEIGHT=0.6
|
|
641
660
|
|
|
642
661
|
# Provider fallback chain (comma-separated, tried in order)
|
|
643
|
-
# FALLBACK_PROVIDERS=anthropic,gemini,openrouter
|
|
662
|
+
# FALLBACK_PROVIDERS=anthropic,minimax,gemini,openrouter
|
|
644
663
|
|
|
645
664
|
# Bearer token for API auth
|
|
646
665
|
# AGENTMEMORY_SECRET=your-secret-here
|
|
@@ -703,7 +722,7 @@ ANTHROPIC_API_KEY=sk-ant-...
|
|
|
703
722
|
| `POST` | `/agentmemory/session/end` | Mark session complete |
|
|
704
723
|
| `POST` | `/agentmemory/observe` | Capture observation |
|
|
705
724
|
| `POST` | `/agentmemory/context` | Generate context |
|
|
706
|
-
| `POST` | `/agentmemory/search` | Search observations (BM25) |
|
|
725
|
+
| `POST` | `/agentmemory/search` | Search observations (BM25). Optional `project`/`cwd` filters |
|
|
707
726
|
| `POST` | `/agentmemory/smart-search` | Hybrid search with progressive disclosure |
|
|
708
727
|
| `POST` | `/agentmemory/summarize` | Generate session summary |
|
|
709
728
|
| `POST` | `/agentmemory/remember` | Save to long-term memory |
|
package/dist/cli.mjs
CHANGED
|
@@ -12,7 +12,11 @@ if (args.includes("--help") || args.includes("-h")) {
|
|
|
12
12
|
console.log(`
|
|
13
13
|
agentmemory — persistent memory for AI coding agents
|
|
14
14
|
|
|
15
|
-
Usage: agentmemory [options]
|
|
15
|
+
Usage: agentmemory [command] [options]
|
|
16
|
+
|
|
17
|
+
Commands:
|
|
18
|
+
(default) Start agentmemory worker
|
|
19
|
+
status Show connection status, memory count, and health
|
|
16
20
|
|
|
17
21
|
Options:
|
|
18
22
|
--help, -h Show this help
|
|
@@ -20,15 +24,10 @@ Options:
|
|
|
20
24
|
--no-engine Skip auto-starting iii-engine
|
|
21
25
|
--port <N> Override REST port (default: 3111)
|
|
22
26
|
|
|
23
|
-
Environment:
|
|
24
|
-
AGENTMEMORY_TOOLS=all Expose all 41 MCP tools
|
|
25
|
-
AGENTMEMORY_SECRET=xxx Auth secret for REST/MCP
|
|
26
|
-
CONSOLIDATION_ENABLED=true Enable auto-consolidation (off by default)
|
|
27
|
-
OBSIDIAN_AUTO_EXPORT=true Auto-export on consolidation
|
|
28
|
-
|
|
29
27
|
Quick start:
|
|
30
|
-
npx @agentmemory/agentmemory
|
|
31
|
-
npx agentmemory
|
|
28
|
+
npx @agentmemory/agentmemory # start everything
|
|
29
|
+
npx @agentmemory/agentmemory status # check health
|
|
30
|
+
npx agentmemory-mcp # standalone MCP (no engine)
|
|
32
31
|
`);
|
|
33
32
|
process.exit(0);
|
|
34
33
|
}
|
|
@@ -160,12 +159,12 @@ async function main() {
|
|
|
160
159
|
p.intro("agentmemory");
|
|
161
160
|
if (skipEngine) {
|
|
162
161
|
p.log.info("Skipping engine check (--no-engine)");
|
|
163
|
-
await import("./src-
|
|
162
|
+
await import("./src-Df36IFVL.mjs");
|
|
164
163
|
return;
|
|
165
164
|
}
|
|
166
165
|
if (await isEngineRunning()) {
|
|
167
166
|
p.log.success("iii-engine is running");
|
|
168
|
-
await import("./src-
|
|
167
|
+
await import("./src-Df36IFVL.mjs");
|
|
169
168
|
return;
|
|
170
169
|
}
|
|
171
170
|
if (!await startEngine()) {
|
|
@@ -193,9 +192,54 @@ async function main() {
|
|
|
193
192
|
process.exit(1);
|
|
194
193
|
}
|
|
195
194
|
s.stop("iii-engine is ready");
|
|
196
|
-
await import("./src-
|
|
195
|
+
await import("./src-Df36IFVL.mjs");
|
|
197
196
|
}
|
|
198
|
-
|
|
197
|
+
async function runStatus() {
|
|
198
|
+
const port = getRestPort();
|
|
199
|
+
const base = `http://localhost:${port}`;
|
|
200
|
+
p.intro("agentmemory status");
|
|
201
|
+
if (!await isEngineRunning()) {
|
|
202
|
+
p.log.error(`Not running — no response on port ${port}`);
|
|
203
|
+
p.log.info("Start with: npx @agentmemory/agentmemory");
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
try {
|
|
207
|
+
const [healthRes, sessionsRes, graphRes] = await Promise.all([
|
|
208
|
+
fetch(`${base}/agentmemory/health`, { signal: AbortSignal.timeout(5e3) }).then((r) => r.json()).catch(() => null),
|
|
209
|
+
fetch(`${base}/agentmemory/sessions`, { signal: AbortSignal.timeout(5e3) }).then((r) => r.json()).catch(() => null),
|
|
210
|
+
fetch(`${base}/agentmemory/graph/stats`, { signal: AbortSignal.timeout(5e3) }).then((r) => r.json()).catch(() => null)
|
|
211
|
+
]);
|
|
212
|
+
const h = healthRes?.health;
|
|
213
|
+
const status = healthRes?.status || "unknown";
|
|
214
|
+
const version = healthRes?.version || "?";
|
|
215
|
+
const sessions = Array.isArray(sessionsRes?.sessions) ? sessionsRes.sessions.length : 0;
|
|
216
|
+
h?.workers?.[0]?.function_count;
|
|
217
|
+
const nodes = graphRes?.nodes || 0;
|
|
218
|
+
const edges = graphRes?.edges || 0;
|
|
219
|
+
const cb = healthRes?.circuitBreaker?.state || "closed";
|
|
220
|
+
const heapMB = h?.memory ? Math.round(h.memory.heapUsed / 1048576) : 0;
|
|
221
|
+
const uptime = h?.uptimeSeconds ? Math.round(h.uptimeSeconds) : 0;
|
|
222
|
+
p.log.success(`Connected — v${version} on port ${port}`);
|
|
223
|
+
const lines = [
|
|
224
|
+
`Health: ${status === "healthy" ? "healthy" : status}`,
|
|
225
|
+
`Sessions: ${sessions}`,
|
|
226
|
+
`Graph: ${nodes} nodes, ${edges} edges`,
|
|
227
|
+
`Circuit: ${cb}`,
|
|
228
|
+
`Heap: ${heapMB} MB`,
|
|
229
|
+
`Uptime: ${uptime}s`,
|
|
230
|
+
`Viewer: http://localhost:${port + 2}`
|
|
231
|
+
];
|
|
232
|
+
p.note(lines.join("\n"), "agentmemory");
|
|
233
|
+
} catch (err) {
|
|
234
|
+
p.log.error(err instanceof Error ? err.message : String(err));
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (args[0] === "status") runStatus().catch((err) => {
|
|
239
|
+
p.log.error(err instanceof Error ? err.message : String(err));
|
|
240
|
+
process.exit(1);
|
|
241
|
+
});
|
|
242
|
+
else main().catch((err) => {
|
|
199
243
|
p.log.error(err instanceof Error ? err.message : String(err));
|
|
200
244
|
process.exit(1);
|
|
201
245
|
});
|
package/dist/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { spawn, execFileSync, execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as p from \"@clack/prompts\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst args = process.argv.slice(2);\n\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n console.log(`\nagentmemory — persistent memory for AI coding agents\n\nUsage: agentmemory [options]\n\nOptions:\n --help, -h Show this help\n --tools all|core Tool visibility (default: core = 7 tools)\n --no-engine Skip auto-starting iii-engine\n --port <N> Override REST port (default: 3111)\n\nEnvironment:\n AGENTMEMORY_TOOLS=all Expose all 41 MCP tools\n AGENTMEMORY_SECRET=xxx Auth secret for REST/MCP\n CONSOLIDATION_ENABLED=true Enable auto-consolidation (off by default)\n OBSIDIAN_AUTO_EXPORT=true Auto-export on consolidation\n\nQuick start:\n npx @agentmemory/agentmemory # installs iii if missing, starts everything\n npx agentmemory-mcp # standalone MCP server (no engine needed)\n`);\n process.exit(0);\n}\n\nconst toolsIdx = args.indexOf(\"--tools\");\nif (toolsIdx !== -1 && args[toolsIdx + 1]) {\n process.env[\"AGENTMEMORY_TOOLS\"] = args[toolsIdx + 1];\n}\n\nconst portIdx = args.indexOf(\"--port\");\nif (portIdx !== -1 && args[portIdx + 1]) {\n process.env[\"III_REST_PORT\"] = args[portIdx + 1];\n}\n\nconst skipEngine = args.includes(\"--no-engine\");\n\nfunction getRestPort(): number {\n return parseInt(process.env[\"III_REST_PORT\"] || \"3111\", 10) || 3111;\n}\n\nasync function isEngineRunning(): Promise<boolean> {\n try {\n await fetch(`http://localhost:${getRestPort()}/`, {\n signal: AbortSignal.timeout(2000),\n });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction findIiiConfig(): string {\n const candidates = [\n join(__dirname, \"iii-config.yaml\"),\n join(__dirname, \"..\", \"iii-config.yaml\"),\n join(process.cwd(), \"iii-config.yaml\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) return c;\n }\n return \"\";\n}\n\nfunction whichBinary(name: string): string | null {\n const cmd = process.platform === \"win32\" ? \"where\" : \"which\";\n try {\n return execFileSync(cmd, [name], { encoding: \"utf-8\" }).trim().split(\"\\n\")[0];\n } catch {\n return null;\n }\n}\n\nasync function installIii(): Promise<boolean> {\n if (process.platform === \"win32\") {\n p.log.warn(\"Automatic iii-engine install is not supported on Windows.\");\n p.log.info(\"Install manually: https://iii.dev/docs\");\n return false;\n }\n\n const curlBin = whichBinary(\"curl\");\n if (!curlBin) {\n p.log.warn(\"curl not found — cannot auto-install iii-engine.\");\n return false;\n }\n\n const shouldInstall = await p.confirm({\n message: \"iii-engine is not installed. Install it now?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldInstall) || !shouldInstall) {\n return false;\n }\n\n const s = p.spinner();\n s.start(\"Installing iii-engine...\");\n\n try {\n execSync(\"curl -fsSL https://install.iii.dev/iii/main/install.sh | sh\", {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 120000,\n });\n\n const installed = whichBinary(\"iii\");\n if (installed) {\n s.stop(\"iii-engine installed successfully\");\n return true;\n }\n\n s.stop(\"Installation completed but iii not found in PATH\");\n p.log.warn(\"You may need to restart your shell or add iii to your PATH.\");\n\n const iiiPaths = [\n join(process.env[\"HOME\"] || \"\", \".local\", \"bin\", \"iii\"),\n \"/usr/local/bin/iii\",\n ];\n for (const iiiPath of iiiPaths) {\n if (existsSync(iiiPath)) {\n p.log.info(`Found iii at: ${iiiPath}`);\n process.env[\"PATH\"] = `${dirname(iiiPath)}:${process.env[\"PATH\"]}`;\n return true;\n }\n }\n\n return false;\n } catch (err) {\n s.stop(\"Failed to install iii-engine\");\n p.log.error(err instanceof Error ? err.message : String(err));\n return false;\n }\n}\n\nasync function startEngine(): Promise<boolean> {\n const configPath = findIiiConfig();\n let iiiBin = whichBinary(\"iii\");\n\n if (!iiiBin) {\n const installed = await installIii();\n if (installed) {\n iiiBin = whichBinary(\"iii\");\n }\n }\n\n if (iiiBin && configPath) {\n const s = p.spinner();\n s.start(`Starting iii-engine: ${iiiBin}`);\n const child = spawn(iiiBin, [\"--config\", configPath], {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n s.stop(\"iii-engine process started\");\n return true;\n }\n\n const dockerBin = whichBinary(\"docker\");\n const dockerCompose = join(__dirname, \"..\", \"docker-compose.yml\");\n const dcExists = existsSync(dockerCompose) || existsSync(join(process.cwd(), \"docker-compose.yml\"));\n\n if (dockerBin && dcExists) {\n const composeFile = existsSync(dockerCompose) ? dockerCompose : join(process.cwd(), \"docker-compose.yml\");\n const s = p.spinner();\n s.start(\"Starting iii-engine via Docker...\");\n const child = spawn(dockerBin, [\"compose\", \"-f\", composeFile, \"up\", \"-d\"], {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n s.stop(\"Docker compose started\");\n return true;\n }\n\n return false;\n}\n\nasync function waitForEngine(timeoutMs: number): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n if (await isEngineRunning()) return true;\n await new Promise((r) => setTimeout(r, 500));\n }\n return false;\n}\n\nasync function main() {\n p.intro(\"agentmemory\");\n\n if (skipEngine) {\n p.log.info(\"Skipping engine check (--no-engine)\");\n await import(\"./index.js\");\n return;\n }\n\n if (await isEngineRunning()) {\n p.log.success(\"iii-engine is running\");\n await import(\"./index.js\");\n return;\n }\n\n const started = await startEngine();\n if (!started) {\n p.log.error(\"Could not start iii-engine.\");\n p.note(\n [\n \"Install iii-engine (pick one):\",\n \" curl -fsSL https://install.iii.dev/iii/main/install.sh | sh\",\n \" cargo install iii-engine\",\n \"\",\n \"Or use Docker:\",\n \" docker pull iiidev/iii:latest\",\n \"\",\n \"Docs: https://iii.dev/docs\",\n \"\",\n \"Or skip with: agentmemory --no-engine\",\n ].join(\"\\n\"),\n \"Setup required\",\n );\n process.exit(1);\n }\n\n const s = p.spinner();\n s.start(\"Waiting for iii-engine to be ready...\");\n\n const ready = await waitForEngine(15000);\n if (!ready) {\n const port = getRestPort();\n s.stop(\"iii-engine did not become ready within 15s\");\n p.log.error(`Check that ports ${port}, ${port + 1}, 49134 are available.`);\n process.exit(1);\n }\n\n s.stop(\"iii-engine is ready\");\n await import(\"./index.js\");\n}\n\nmain().catch((err) => {\n p.log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { spawn, execFileSync, execSync } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as p from \"@clack/prompts\";\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\nconst args = process.argv.slice(2);\n\nif (args.includes(\"--help\") || args.includes(\"-h\")) {\n console.log(`\nagentmemory — persistent memory for AI coding agents\n\nUsage: agentmemory [command] [options]\n\nCommands:\n (default) Start agentmemory worker\n status Show connection status, memory count, and health\n\nOptions:\n --help, -h Show this help\n --tools all|core Tool visibility (default: core = 7 tools)\n --no-engine Skip auto-starting iii-engine\n --port <N> Override REST port (default: 3111)\n\nQuick start:\n npx @agentmemory/agentmemory # start everything\n npx @agentmemory/agentmemory status # check health\n npx agentmemory-mcp # standalone MCP (no engine)\n`);\n process.exit(0);\n}\n\nconst toolsIdx = args.indexOf(\"--tools\");\nif (toolsIdx !== -1 && args[toolsIdx + 1]) {\n process.env[\"AGENTMEMORY_TOOLS\"] = args[toolsIdx + 1];\n}\n\nconst portIdx = args.indexOf(\"--port\");\nif (portIdx !== -1 && args[portIdx + 1]) {\n process.env[\"III_REST_PORT\"] = args[portIdx + 1];\n}\n\nconst skipEngine = args.includes(\"--no-engine\");\n\nfunction getRestPort(): number {\n return parseInt(process.env[\"III_REST_PORT\"] || \"3111\", 10) || 3111;\n}\n\nasync function isEngineRunning(): Promise<boolean> {\n try {\n await fetch(`http://localhost:${getRestPort()}/`, {\n signal: AbortSignal.timeout(2000),\n });\n return true;\n } catch {\n return false;\n }\n}\n\nfunction findIiiConfig(): string {\n const candidates = [\n join(__dirname, \"iii-config.yaml\"),\n join(__dirname, \"..\", \"iii-config.yaml\"),\n join(process.cwd(), \"iii-config.yaml\"),\n ];\n for (const c of candidates) {\n if (existsSync(c)) return c;\n }\n return \"\";\n}\n\nfunction whichBinary(name: string): string | null {\n const cmd = process.platform === \"win32\" ? \"where\" : \"which\";\n try {\n return execFileSync(cmd, [name], { encoding: \"utf-8\" }).trim().split(\"\\n\")[0];\n } catch {\n return null;\n }\n}\n\nasync function installIii(): Promise<boolean> {\n if (process.platform === \"win32\") {\n p.log.warn(\"Automatic iii-engine install is not supported on Windows.\");\n p.log.info(\"Install manually: https://iii.dev/docs\");\n return false;\n }\n\n const curlBin = whichBinary(\"curl\");\n if (!curlBin) {\n p.log.warn(\"curl not found — cannot auto-install iii-engine.\");\n return false;\n }\n\n const shouldInstall = await p.confirm({\n message: \"iii-engine is not installed. Install it now?\",\n initialValue: true,\n });\n\n if (p.isCancel(shouldInstall) || !shouldInstall) {\n return false;\n }\n\n const s = p.spinner();\n s.start(\"Installing iii-engine...\");\n\n try {\n execSync(\"curl -fsSL https://install.iii.dev/iii/main/install.sh | sh\", {\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 120000,\n });\n\n const installed = whichBinary(\"iii\");\n if (installed) {\n s.stop(\"iii-engine installed successfully\");\n return true;\n }\n\n s.stop(\"Installation completed but iii not found in PATH\");\n p.log.warn(\"You may need to restart your shell or add iii to your PATH.\");\n\n const iiiPaths = [\n join(process.env[\"HOME\"] || \"\", \".local\", \"bin\", \"iii\"),\n \"/usr/local/bin/iii\",\n ];\n for (const iiiPath of iiiPaths) {\n if (existsSync(iiiPath)) {\n p.log.info(`Found iii at: ${iiiPath}`);\n process.env[\"PATH\"] = `${dirname(iiiPath)}:${process.env[\"PATH\"]}`;\n return true;\n }\n }\n\n return false;\n } catch (err) {\n s.stop(\"Failed to install iii-engine\");\n p.log.error(err instanceof Error ? err.message : String(err));\n return false;\n }\n}\n\nasync function startEngine(): Promise<boolean> {\n const configPath = findIiiConfig();\n let iiiBin = whichBinary(\"iii\");\n\n if (!iiiBin) {\n const installed = await installIii();\n if (installed) {\n iiiBin = whichBinary(\"iii\");\n }\n }\n\n if (iiiBin && configPath) {\n const s = p.spinner();\n s.start(`Starting iii-engine: ${iiiBin}`);\n const child = spawn(iiiBin, [\"--config\", configPath], {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n s.stop(\"iii-engine process started\");\n return true;\n }\n\n const dockerBin = whichBinary(\"docker\");\n const dockerCompose = join(__dirname, \"..\", \"docker-compose.yml\");\n const dcExists = existsSync(dockerCompose) || existsSync(join(process.cwd(), \"docker-compose.yml\"));\n\n if (dockerBin && dcExists) {\n const composeFile = existsSync(dockerCompose) ? dockerCompose : join(process.cwd(), \"docker-compose.yml\");\n const s = p.spinner();\n s.start(\"Starting iii-engine via Docker...\");\n const child = spawn(dockerBin, [\"compose\", \"-f\", composeFile, \"up\", \"-d\"], {\n detached: true,\n stdio: \"ignore\",\n });\n child.unref();\n s.stop(\"Docker compose started\");\n return true;\n }\n\n return false;\n}\n\nasync function waitForEngine(timeoutMs: number): Promise<boolean> {\n const start = Date.now();\n while (Date.now() - start < timeoutMs) {\n if (await isEngineRunning()) return true;\n await new Promise((r) => setTimeout(r, 500));\n }\n return false;\n}\n\nasync function main() {\n p.intro(\"agentmemory\");\n\n if (skipEngine) {\n p.log.info(\"Skipping engine check (--no-engine)\");\n await import(\"./index.js\");\n return;\n }\n\n if (await isEngineRunning()) {\n p.log.success(\"iii-engine is running\");\n await import(\"./index.js\");\n return;\n }\n\n const started = await startEngine();\n if (!started) {\n p.log.error(\"Could not start iii-engine.\");\n p.note(\n [\n \"Install iii-engine (pick one):\",\n \" curl -fsSL https://install.iii.dev/iii/main/install.sh | sh\",\n \" cargo install iii-engine\",\n \"\",\n \"Or use Docker:\",\n \" docker pull iiidev/iii:latest\",\n \"\",\n \"Docs: https://iii.dev/docs\",\n \"\",\n \"Or skip with: agentmemory --no-engine\",\n ].join(\"\\n\"),\n \"Setup required\",\n );\n process.exit(1);\n }\n\n const s = p.spinner();\n s.start(\"Waiting for iii-engine to be ready...\");\n\n const ready = await waitForEngine(15000);\n if (!ready) {\n const port = getRestPort();\n s.stop(\"iii-engine did not become ready within 15s\");\n p.log.error(`Check that ports ${port}, ${port + 1}, 49134 are available.`);\n process.exit(1);\n }\n\n s.stop(\"iii-engine is ready\");\n await import(\"./index.js\");\n}\n\nasync function runStatus() {\n const port = getRestPort();\n const base = `http://localhost:${port}`;\n p.intro(\"agentmemory status\");\n\n const up = await isEngineRunning();\n if (!up) {\n p.log.error(`Not running — no response on port ${port}`);\n p.log.info(\"Start with: npx @agentmemory/agentmemory\");\n process.exit(1);\n }\n\n try {\n const [healthRes, sessionsRes, graphRes] = await Promise.all([\n fetch(`${base}/agentmemory/health`, { signal: AbortSignal.timeout(5000) }).then((r) => r.json()).catch(() => null),\n fetch(`${base}/agentmemory/sessions`, { signal: AbortSignal.timeout(5000) }).then((r) => r.json()).catch(() => null),\n fetch(`${base}/agentmemory/graph/stats`, { signal: AbortSignal.timeout(5000) }).then((r) => r.json()).catch(() => null),\n ]);\n\n const h = healthRes?.health;\n const status = healthRes?.status || \"unknown\";\n const version = healthRes?.version || \"?\";\n const sessions = Array.isArray(sessionsRes?.sessions) ? sessionsRes.sessions.length : 0;\n const memories = h?.workers?.[0]?.function_count || 0;\n const nodes = graphRes?.nodes || 0;\n const edges = graphRes?.edges || 0;\n const cb = healthRes?.circuitBreaker?.state || \"closed\";\n const heapMB = h?.memory ? Math.round(h.memory.heapUsed / 1048576) : 0;\n const uptime = h?.uptimeSeconds ? Math.round(h.uptimeSeconds) : 0;\n\n p.log.success(`Connected — v${version} on port ${port}`);\n\n const lines = [\n `Health: ${status === \"healthy\" ? \"healthy\" : status}`,\n `Sessions: ${sessions}`,\n `Graph: ${nodes} nodes, ${edges} edges`,\n `Circuit: ${cb}`,\n `Heap: ${heapMB} MB`,\n `Uptime: ${uptime}s`,\n `Viewer: http://localhost:${port + 2}`,\n ];\n p.note(lines.join(\"\\n\"), \"agentmemory\");\n } catch (err) {\n p.log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nif (args[0] === \"status\") {\n runStatus().catch((err) => {\n p.log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n });\n} else {\n main().catch((err) => {\n p.log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n });\n}\n"],"mappings":"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"}
|