@agentmemory/agentmemory 0.9.28 → 0.9.30
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/.env.example +98 -28
- package/AGENTS.md +19 -26
- package/README.md +619 -274
- package/dist/.env.example +98 -28
- package/dist/cli.d.mts.map +1 -1
- package/dist/cli.mjs +1328 -244
- package/dist/cli.mjs.map +1 -1
- package/dist/{connect-JnsJXc68.mjs → connect-B4_ca6BD.mjs} +619 -70
- package/dist/connect-B4_ca6BD.mjs.map +1 -0
- package/dist/docker-compose.yml +42 -16
- package/dist/hooks/_capture.d.mts +22 -0
- package/dist/hooks/_capture.d.mts.map +1 -0
- package/dist/hooks/_capture.mjs +908 -0
- package/dist/hooks/_capture.mjs.map +1 -0
- package/dist/hooks/antigravity-bridge.d.mts +8 -0
- package/dist/hooks/antigravity-bridge.d.mts.map +1 -0
- package/dist/hooks/antigravity-bridge.mjs +123 -0
- package/dist/hooks/antigravity-bridge.mjs.map +1 -0
- package/dist/hooks/notification.mjs +34 -27
- package/dist/hooks/notification.mjs.map +1 -1
- package/dist/hooks/post-commit.mjs +84 -2
- package/dist/hooks/post-commit.mjs.map +1 -1
- package/dist/hooks/post-tool-failure.mjs +71 -26
- package/dist/hooks/post-tool-failure.mjs.map +1 -1
- package/dist/hooks/post-tool-use.mjs +99 -36
- package/dist/hooks/post-tool-use.mjs.map +1 -1
- package/dist/hooks/pre-compact.mjs +95 -5
- package/dist/hooks/pre-compact.mjs.map +1 -1
- package/dist/hooks/pre-tool-use.mjs +72 -2
- package/dist/hooks/pre-tool-use.mjs.map +1 -1
- package/dist/hooks/prompt-submit.mjs +25 -22
- package/dist/hooks/prompt-submit.mjs.map +1 -1
- package/dist/hooks/session-end.mjs +93 -24
- package/dist/hooks/session-end.mjs.map +1 -1
- package/dist/hooks/session-start.mjs +101 -6
- package/dist/hooks/session-start.mjs.map +1 -1
- package/dist/hooks/stop.mjs +72 -8
- package/dist/hooks/stop.mjs.map +1 -1
- package/dist/hooks/subagent-start.mjs +28 -26
- package/dist/hooks/subagent-start.mjs.map +1 -1
- package/dist/hooks/subagent-stop.mjs +29 -26
- package/dist/hooks/subagent-stop.mjs.map +1 -1
- package/dist/hooks/task-completed.mjs +31 -28
- package/dist/hooks/task-completed.mjs.map +1 -1
- package/dist/iii-config.docker.yaml +10 -10
- package/dist/iii-config.yaml +3 -1
- package/dist/{image-refs-BKLmp_sD.mjs → image-refs-BaT-9oMU.mjs} +2 -2
- package/dist/image-refs-BaT-9oMU.mjs.map +1 -0
- package/dist/{image-refs-C2YU7BIm.mjs → image-refs-T_urbwHM.mjs} +3 -3
- package/dist/image-refs-T_urbwHM.mjs.map +1 -0
- package/dist/{keyed-mutex-DTHtcZrt.mjs → image-store-BsN4vyjr.mjs} +2 -14
- package/dist/image-store-BsN4vyjr.mjs.map +1 -0
- package/dist/index.mjs +14021 -6494
- package/dist/index.mjs.map +1 -1
- package/dist/keyed-mutex-DchXsyfP.mjs +221 -0
- package/dist/keyed-mutex-DchXsyfP.mjs.map +1 -0
- package/dist/secret-store-BnY3A50C.mjs +2348 -0
- package/dist/secret-store-BnY3A50C.mjs.map +1 -0
- package/dist/{src-CzgoepGU.mjs → src-Jsq9LCeH.mjs} +7349 -2940
- package/dist/src-Jsq9LCeH.mjs.map +1 -0
- package/dist/{standalone-YsZFFQBM.mjs → standalone-DKCdrf1d.mjs} +62 -24
- package/dist/standalone-DKCdrf1d.mjs.map +1 -0
- package/dist/standalone.d.mts.map +1 -1
- package/dist/standalone.mjs +298 -27
- package/dist/standalone.mjs.map +1 -1
- package/dist/status-IRz7ta8-.mjs +2344 -0
- package/dist/status-IRz7ta8-.mjs.map +1 -0
- package/dist/viewer/favicon.svg +35 -1
- package/dist/viewer/index.html +7428 -2608
- package/docker-compose.yml +42 -16
- package/iii-config.docker.yaml +10 -10
- package/iii-config.yaml +3 -1
- package/integrations/pi/README.md +77 -0
- package/integrations/pi/index.ts +402 -0
- package/integrations/pi/package.json +32 -0
- package/integrations/pi/security.ts +87 -0
- package/package.json +15 -7
- package/plugin/.claude-plugin/plugin.json +2 -2
- package/plugin/.codex-plugin/plugin.json +26 -4
- package/plugin/.devin-plugin/plugin.json +32 -0
- package/plugin/.mcp.codex.json +12 -0
- package/plugin/.mcp.copilot.json +2 -7
- package/plugin/.mcp.json +2 -7
- package/plugin/assets/icon.svg +35 -0
- package/plugin/cursor/hooks.json +41 -0
- package/plugin/cursor/mcp.json +12 -0
- package/plugin/hooks/hooks.antigravity.json +43 -0
- package/plugin/hooks/hooks.copilot.json +11 -11
- package/plugin/hooks/hooks.devin.json +67 -0
- package/plugin/hooks/hooks.droid.json +55 -0
- package/plugin/opencode/README.md +267 -31
- package/plugin/opencode/agentmemory-capture.ts +644 -15
- package/plugin/opencode/plugin.json +1 -1
- package/plugin/plugin.json +2 -2
- package/plugin/scripts/_capture.d.mts +22 -0
- package/plugin/scripts/_capture.d.mts.map +1 -0
- package/plugin/scripts/_capture.mjs +908 -0
- package/plugin/scripts/_capture.mjs.map +1 -0
- package/plugin/scripts/antigravity-bridge.d.mts +8 -0
- package/plugin/scripts/antigravity-bridge.d.mts.map +1 -0
- package/plugin/scripts/antigravity-bridge.mjs +123 -0
- package/plugin/scripts/antigravity-bridge.mjs.map +1 -0
- package/plugin/scripts/notification.mjs +34 -27
- package/plugin/scripts/notification.mjs.map +1 -1
- package/plugin/scripts/plugin-bridge.mjs +378 -0
- package/plugin/scripts/post-commit.mjs +84 -2
- package/plugin/scripts/post-commit.mjs.map +1 -1
- package/plugin/scripts/post-tool-failure.mjs +71 -26
- package/plugin/scripts/post-tool-failure.mjs.map +1 -1
- package/plugin/scripts/post-tool-use.mjs +99 -36
- package/plugin/scripts/post-tool-use.mjs.map +1 -1
- package/plugin/scripts/pre-compact.mjs +95 -5
- package/plugin/scripts/pre-compact.mjs.map +1 -1
- package/plugin/scripts/pre-tool-use.mjs +72 -2
- package/plugin/scripts/pre-tool-use.mjs.map +1 -1
- package/plugin/scripts/prompt-submit.mjs +25 -22
- package/plugin/scripts/prompt-submit.mjs.map +1 -1
- package/plugin/scripts/session-end.mjs +93 -24
- package/plugin/scripts/session-end.mjs.map +1 -1
- package/plugin/scripts/session-start.mjs +101 -6
- package/plugin/scripts/session-start.mjs.map +1 -1
- package/plugin/scripts/stop.mjs +72 -8
- package/plugin/scripts/stop.mjs.map +1 -1
- package/plugin/scripts/subagent-start.mjs +28 -26
- package/plugin/scripts/subagent-start.mjs.map +1 -1
- package/plugin/scripts/subagent-stop.mjs +29 -26
- package/plugin/scripts/subagent-stop.mjs.map +1 -1
- package/plugin/scripts/task-completed.mjs +31 -28
- package/plugin/scripts/task-completed.mjs.map +1 -1
- package/plugin/skills/_shared/TROUBLESHOOTING.md +22 -6
- package/plugin/skills/agentmemory-agents/REFERENCE.md +8 -5
- package/plugin/skills/agentmemory-config/REFERENCE.md +52 -1
- package/plugin/skills/agentmemory-config/SKILL.md +44 -7
- package/plugin/skills/agentmemory-mcp-tools/REFERENCE.md +4 -3
- package/plugin/skills/agentmemory-rest-api/REFERENCE.md +23 -2
- package/plugin/skills/forget/SKILL.md +4 -1
- package/plugin/skills/handoff/SKILL.md +4 -2
- package/plugin/skills/lesson/SKILL.md +64 -0
- package/plugin/skills/memory-discipline/SKILL.md +65 -0
- package/plugin/skills/recall/SKILL.md +4 -1
- package/plugin/skills/remember/SKILL.md +6 -1
- package/dist/config-ChC9EtgV.mjs +0 -259
- package/dist/config-ChC9EtgV.mjs.map +0 -1
- package/dist/connect-JnsJXc68.mjs.map +0 -1
- package/dist/image-refs-BKLmp_sD.mjs.map +0 -1
- package/dist/image-refs-C2YU7BIm.mjs.map +0 -1
- package/dist/keyed-mutex-DTHtcZrt.mjs.map +0 -1
- package/dist/logger-BEB7pCI9.mjs +0 -43
- package/dist/logger-BEB7pCI9.mjs.map +0 -1
- package/dist/schema-CNiCWzV9.mjs +0 -78
- package/dist/schema-CNiCWzV9.mjs.map +0 -1
- package/dist/src-CzgoepGU.mjs.map +0 -1
- package/dist/standalone-YsZFFQBM.mjs.map +0 -1
- package/dist/tools-registry-D3NEoe5m.mjs +0 -1115
- package/dist/tools-registry-D3NEoe5m.mjs.map +0 -1
- package/plugin/scripts/diagnostics.d.mts +0 -17
- package/plugin/scripts/diagnostics.d.mts.map +0 -1
- package/plugin/scripts/diagnostics.mjs.map +0 -1
package/dist/standalone.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
4
|
import { dirname, join } from "node:path";
|
|
4
5
|
import { homedir } from "node:os";
|
|
@@ -47,6 +48,13 @@ var InMemoryKV = class {
|
|
|
47
48
|
};
|
|
48
49
|
//#endregion
|
|
49
50
|
//#region src/mcp/transport.ts
|
|
51
|
+
var JsonRpcError = class extends Error {
|
|
52
|
+
constructor(code, message) {
|
|
53
|
+
super(message);
|
|
54
|
+
this.code = code;
|
|
55
|
+
this.name = "JsonRpcError";
|
|
56
|
+
}
|
|
57
|
+
};
|
|
50
58
|
function isNotification(req) {
|
|
51
59
|
return req.id === void 0 || req.id === null;
|
|
52
60
|
}
|
|
@@ -112,7 +120,7 @@ async function processLine(line, handler, writeOut, writeErr = (msg) => process.
|
|
|
112
120
|
jsonrpc: "2.0",
|
|
113
121
|
id: request.id,
|
|
114
122
|
error: {
|
|
115
|
-
code: -32603,
|
|
123
|
+
code: err instanceof JsonRpcError ? err.code : -32603,
|
|
116
124
|
message: err instanceof Error ? err.message : String(err)
|
|
117
125
|
}
|
|
118
126
|
});
|
|
@@ -283,6 +291,10 @@ const CORE_TOOLS = [
|
|
|
283
291
|
project: {
|
|
284
292
|
type: "string",
|
|
285
293
|
description: "Stable canonical project identifier this memory belongs to (e.g. a slug, UUID, or registry key). Must match the value used when the session was started. Do not use filesystem paths or ad-hoc display names — those change across machines and will silently break project scoping."
|
|
294
|
+
},
|
|
295
|
+
agentId: {
|
|
296
|
+
type: "string",
|
|
297
|
+
description: "Agent identity to scope this memory to. When set, agent-scoped recall and search only surface it for the same agentId. Omit for shared memory."
|
|
286
298
|
}
|
|
287
299
|
},
|
|
288
300
|
required: ["content"]
|
|
@@ -311,10 +323,16 @@ const CORE_TOOLS = [
|
|
|
311
323
|
description: "Detect recurring patterns across sessions.",
|
|
312
324
|
inputSchema: {
|
|
313
325
|
type: "object",
|
|
314
|
-
properties: {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
326
|
+
properties: {
|
|
327
|
+
project: {
|
|
328
|
+
type: "string",
|
|
329
|
+
description: "Project path to analyze"
|
|
330
|
+
},
|
|
331
|
+
limit: {
|
|
332
|
+
type: "integer",
|
|
333
|
+
description: "Most recent sessions to scan (default 50, max 500)"
|
|
334
|
+
}
|
|
335
|
+
}
|
|
318
336
|
}
|
|
319
337
|
},
|
|
320
338
|
{
|
|
@@ -1141,6 +1159,18 @@ const V070_TOOLS = [
|
|
|
1141
1159
|
required: ["query"]
|
|
1142
1160
|
}
|
|
1143
1161
|
},
|
|
1162
|
+
{
|
|
1163
|
+
name: "memory_lesson_delete",
|
|
1164
|
+
description: "Soft-delete a lesson by id. Deleted lessons are excluded from recall and list; re-saving the same content creates a fresh lesson.",
|
|
1165
|
+
inputSchema: {
|
|
1166
|
+
type: "object",
|
|
1167
|
+
properties: { lessonId: {
|
|
1168
|
+
type: "string",
|
|
1169
|
+
description: "The lesson id (lsn_...)"
|
|
1170
|
+
} },
|
|
1171
|
+
required: ["lessonId"]
|
|
1172
|
+
}
|
|
1173
|
+
},
|
|
1144
1174
|
{
|
|
1145
1175
|
name: "memory_obsidian_export",
|
|
1146
1176
|
description: "Export memories, lessons, and crystals as Obsidian-compatible Markdown files with YAML frontmatter and wikilinks for graph view.",
|
|
@@ -1313,8 +1343,13 @@ function getAllTools() {
|
|
|
1313
1343
|
];
|
|
1314
1344
|
}
|
|
1315
1345
|
const ENV_FILE = join(join(homedir(), ".agentmemory"), ".env");
|
|
1346
|
+
let envFileCache;
|
|
1316
1347
|
function loadEnvFile() {
|
|
1317
|
-
if (
|
|
1348
|
+
if (envFileCache) return envFileCache;
|
|
1349
|
+
if (!existsSync(ENV_FILE)) {
|
|
1350
|
+
envFileCache = {};
|
|
1351
|
+
return envFileCache;
|
|
1352
|
+
}
|
|
1318
1353
|
const content = readFileSync(ENV_FILE, "utf-8");
|
|
1319
1354
|
const vars = {};
|
|
1320
1355
|
for (const line of content.split("\n")) {
|
|
@@ -1334,7 +1369,8 @@ function loadEnvFile() {
|
|
|
1334
1369
|
}
|
|
1335
1370
|
vars[key] = val;
|
|
1336
1371
|
}
|
|
1337
|
-
|
|
1372
|
+
envFileCache = vars;
|
|
1373
|
+
return envFileCache;
|
|
1338
1374
|
}
|
|
1339
1375
|
function getMergedEnv(overrides) {
|
|
1340
1376
|
return {
|
|
@@ -1348,12 +1384,215 @@ function getStandalonePersistPath() {
|
|
|
1348
1384
|
}
|
|
1349
1385
|
//#endregion
|
|
1350
1386
|
//#region src/version.ts
|
|
1351
|
-
const VERSION = "0.9.
|
|
1387
|
+
const VERSION = "0.9.30";
|
|
1388
|
+
createRequire(import.meta.url);
|
|
1352
1389
|
//#endregion
|
|
1353
1390
|
//#region src/state/schema.ts
|
|
1391
|
+
const KV = {
|
|
1392
|
+
sessions: "mem:sessions",
|
|
1393
|
+
observations: (sessionId) => `mem:obs:${sessionId}`,
|
|
1394
|
+
memories: "mem:memories",
|
|
1395
|
+
summaries: "mem:summaries",
|
|
1396
|
+
config: "mem:config",
|
|
1397
|
+
metrics: "mem:metrics",
|
|
1398
|
+
health: "mem:health",
|
|
1399
|
+
embeddings: (obsId) => `mem:emb:${obsId}`,
|
|
1400
|
+
bm25Index: "mem:index:bm25",
|
|
1401
|
+
vectorPendingLog: "mem:index:vec-pending",
|
|
1402
|
+
relations: "mem:relations",
|
|
1403
|
+
profiles: "mem:profiles",
|
|
1404
|
+
claudeBridge: "mem:claude-bridge",
|
|
1405
|
+
graphNodes: "mem:graph:nodes",
|
|
1406
|
+
graphEdges: "mem:graph:edges",
|
|
1407
|
+
graphSnapshot: "mem:graph:snapshot",
|
|
1408
|
+
graphNameIndex: "mem:graph:name-index",
|
|
1409
|
+
graphEdgeKey: "mem:graph:edge-key",
|
|
1410
|
+
graphNodeDegree: "mem:graph:node-degree",
|
|
1411
|
+
semantic: "mem:semantic",
|
|
1412
|
+
procedural: "mem:procedural",
|
|
1413
|
+
teamShared: (teamId) => `mem:team:${teamId}:shared`,
|
|
1414
|
+
teamUsers: (teamId, userId) => `mem:team:${teamId}:users:${userId}`,
|
|
1415
|
+
teamProfile: (teamId) => `mem:team:${teamId}:profile`,
|
|
1416
|
+
audit: "mem:audit",
|
|
1417
|
+
auditMonth: (month) => `mem:audit:${month}`,
|
|
1418
|
+
auditMonths: "mem:audit:months",
|
|
1419
|
+
actions: "mem:actions",
|
|
1420
|
+
actionEdges: "mem:action-edges",
|
|
1421
|
+
leases: "mem:leases",
|
|
1422
|
+
routines: "mem:routines",
|
|
1423
|
+
routineRuns: "mem:routine-runs",
|
|
1424
|
+
signals: "mem:signals",
|
|
1425
|
+
checkpoints: "mem:checkpoints",
|
|
1426
|
+
mesh: "mem:mesh",
|
|
1427
|
+
sketches: "mem:sketches",
|
|
1428
|
+
facets: "mem:facets",
|
|
1429
|
+
sentinels: "mem:sentinels",
|
|
1430
|
+
crystals: "mem:crystals",
|
|
1431
|
+
lessons: "mem:lessons",
|
|
1432
|
+
insights: "mem:insights",
|
|
1433
|
+
graphEdgeHistory: "mem:graph:edge-history",
|
|
1434
|
+
enrichedChunks: (sessionId) => `mem:enriched:${sessionId}`,
|
|
1435
|
+
latentEmbeddings: (obsId) => `mem:latent:${obsId}`,
|
|
1436
|
+
retentionScores: "mem:retention",
|
|
1437
|
+
accessLog: "mem:access",
|
|
1438
|
+
imageRefs: "mem:image-refs",
|
|
1439
|
+
imageEmbeddings: "mem:image-embeddings",
|
|
1440
|
+
slots: "mem:slots",
|
|
1441
|
+
globalSlots: "mem:slots:global",
|
|
1442
|
+
state: "mem:state",
|
|
1443
|
+
commits: "mem:commits",
|
|
1444
|
+
recentSearches: "mem:recent-searches",
|
|
1445
|
+
projectSessionsIndex: "mem:idx:project-sessions",
|
|
1446
|
+
obsSessionIndex: (shard) => `mem:idx:obs:${shard}`,
|
|
1447
|
+
captureInbox: "mem:capture:inbox",
|
|
1448
|
+
captureEvents: (shard) => `mem:capture:events:${shard}`,
|
|
1449
|
+
capturePrompts: "mem:capture:prompts"
|
|
1450
|
+
};
|
|
1354
1451
|
function generateId(prefix) {
|
|
1355
1452
|
return `${prefix}_${Date.now().toString(36)}_${crypto.randomUUID().replace(/-/g, "").slice(0, 12)}`;
|
|
1356
1453
|
}
|
|
1454
|
+
process.env["AGENTMEMORY_VERBOSE"] === "1" || process.env["AGENTMEMORY_VERBOSE"];
|
|
1455
|
+
KV.auditMonths;
|
|
1456
|
+
const AUDIT_MIGRATION_STATE_KEY = "migration";
|
|
1457
|
+
async function readAuditMigrationState(kv) {
|
|
1458
|
+
return kv.get(KV.auditMonths, AUDIT_MIGRATION_STATE_KEY);
|
|
1459
|
+
}
|
|
1460
|
+
function monthStartMs(month) {
|
|
1461
|
+
const [year, mon] = month.split("-").map(Number);
|
|
1462
|
+
return Date.UTC(year, mon - 1, 1);
|
|
1463
|
+
}
|
|
1464
|
+
function monthEndMs(month) {
|
|
1465
|
+
const [year, mon] = month.split("-").map(Number);
|
|
1466
|
+
return Date.UTC(year, mon, 1) - 1;
|
|
1467
|
+
}
|
|
1468
|
+
async function readAuditMonthIndex(kv) {
|
|
1469
|
+
return (await kv.get(KV.auditMonths, "index"))?.months ?? [];
|
|
1470
|
+
}
|
|
1471
|
+
async function listAuditMonthsDesc(kv) {
|
|
1472
|
+
return [...await readAuditMonthIndex(kv)].sort().reverse();
|
|
1473
|
+
}
|
|
1474
|
+
async function queryAudit(kv, filter) {
|
|
1475
|
+
const limit = filter?.limit || 100;
|
|
1476
|
+
let fromMs;
|
|
1477
|
+
if (filter?.dateFrom) {
|
|
1478
|
+
fromMs = new Date(filter.dateFrom).getTime();
|
|
1479
|
+
if (Number.isNaN(fromMs)) throw new Error(`Invalid dateFrom: ${filter.dateFrom}`);
|
|
1480
|
+
}
|
|
1481
|
+
const query = filter?.query?.trim().toLowerCase();
|
|
1482
|
+
let toMs;
|
|
1483
|
+
if (filter?.dateTo) {
|
|
1484
|
+
toMs = new Date(filter.dateTo).getTime();
|
|
1485
|
+
if (Number.isNaN(toMs)) throw new Error(`Invalid dateTo: ${filter.dateTo}`);
|
|
1486
|
+
}
|
|
1487
|
+
const matches = (entry) => {
|
|
1488
|
+
if (filter?.operation && entry.operation !== filter.operation) return false;
|
|
1489
|
+
const t = new Date(entry.timestamp).getTime();
|
|
1490
|
+
if (fromMs !== void 0 && t < fromMs) return false;
|
|
1491
|
+
if (toMs !== void 0 && t > toMs) return false;
|
|
1492
|
+
if (query && ![entry.functionId, ...entry.targetIds || []].some((v) => String(v || "").toLowerCase().includes(query))) return false;
|
|
1493
|
+
return true;
|
|
1494
|
+
};
|
|
1495
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
1496
|
+
const collected = [];
|
|
1497
|
+
const addIfNew = (row) => {
|
|
1498
|
+
if (seenIds.has(row.id)) return;
|
|
1499
|
+
seenIds.add(row.id);
|
|
1500
|
+
if (matches(row)) collected.push(row);
|
|
1501
|
+
};
|
|
1502
|
+
const months = await listAuditMonthsDesc(kv);
|
|
1503
|
+
for (const month of months) {
|
|
1504
|
+
if (collected.length >= limit) break;
|
|
1505
|
+
if (toMs !== void 0 && monthStartMs(month) > toMs) continue;
|
|
1506
|
+
if (fromMs !== void 0 && monthEndMs(month) < fromMs) break;
|
|
1507
|
+
const rows = await kv.list(KV.auditMonth(month));
|
|
1508
|
+
for (const row of rows) addIfNew(row);
|
|
1509
|
+
}
|
|
1510
|
+
let legacyFrozen = false;
|
|
1511
|
+
let legacyFrozenBytes;
|
|
1512
|
+
if (collected.length < limit) {
|
|
1513
|
+
const migrationState = await readAuditMigrationState(kv);
|
|
1514
|
+
if (migrationState?.safeToListLegacy) {
|
|
1515
|
+
const legacyRows = await kv.list(KV.audit);
|
|
1516
|
+
for (const row of legacyRows) addIfNew(row);
|
|
1517
|
+
} else if (migrationState?.status === "too-large" || migrationState?.status === "unreadable") {
|
|
1518
|
+
legacyFrozen = true;
|
|
1519
|
+
legacyFrozenBytes = migrationState.legacySizeBytes;
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1522
|
+
collected.sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
|
|
1523
|
+
return {
|
|
1524
|
+
entries: collected.slice(0, limit),
|
|
1525
|
+
legacyFrozen,
|
|
1526
|
+
legacyFrozenBytes
|
|
1527
|
+
};
|
|
1528
|
+
}
|
|
1529
|
+
//#endregion
|
|
1530
|
+
//#region src/secret-store.ts
|
|
1531
|
+
const SECRET_KEY = "AGENTMEMORY_SECRET";
|
|
1532
|
+
function agentmemoryHomeDir() {
|
|
1533
|
+
return join(homedir(), ".agentmemory");
|
|
1534
|
+
}
|
|
1535
|
+
function secretFilePath() {
|
|
1536
|
+
return join(agentmemoryHomeDir(), "secret");
|
|
1537
|
+
}
|
|
1538
|
+
function usable(value) {
|
|
1539
|
+
if (typeof value !== "string") return "";
|
|
1540
|
+
const trimmed = value.trim();
|
|
1541
|
+
if (!trimmed) return "";
|
|
1542
|
+
if (trimmed.startsWith("${") && trimmed.endsWith("}")) return "";
|
|
1543
|
+
return trimmed;
|
|
1544
|
+
}
|
|
1545
|
+
function unquote(value) {
|
|
1546
|
+
const quote = value[0];
|
|
1547
|
+
if ((quote === "\"" || quote === "'") && value.length > 1) {
|
|
1548
|
+
const close = value.indexOf(quote, 1);
|
|
1549
|
+
if (close !== -1) return value.slice(1, close);
|
|
1550
|
+
}
|
|
1551
|
+
const hash = value.indexOf(" #");
|
|
1552
|
+
return hash === -1 ? value : value.slice(0, hash).trim();
|
|
1553
|
+
}
|
|
1554
|
+
function readEnvFileSecret() {
|
|
1555
|
+
let content;
|
|
1556
|
+
try {
|
|
1557
|
+
content = readFileSync(join(agentmemoryHomeDir(), ".env"), "utf-8");
|
|
1558
|
+
} catch {
|
|
1559
|
+
return "";
|
|
1560
|
+
}
|
|
1561
|
+
if (typeof content !== "string") return "";
|
|
1562
|
+
let found = "";
|
|
1563
|
+
for (const line of content.split("\n")) {
|
|
1564
|
+
const trimmed = line.trim();
|
|
1565
|
+
if (trimmed.startsWith("#")) continue;
|
|
1566
|
+
const eq = trimmed.indexOf("=");
|
|
1567
|
+
if (eq === -1) continue;
|
|
1568
|
+
if (trimmed.slice(0, eq).replace(/^export\s+/, "").trim() !== SECRET_KEY) continue;
|
|
1569
|
+
found = usable(unquote(trimmed.slice(eq + 1).trim()));
|
|
1570
|
+
}
|
|
1571
|
+
return found;
|
|
1572
|
+
}
|
|
1573
|
+
function readStoredSecret() {
|
|
1574
|
+
try {
|
|
1575
|
+
return usable(readFileSync(secretFilePath(), "utf-8"));
|
|
1576
|
+
} catch {
|
|
1577
|
+
return "";
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
function isLoopbackUrl(url) {
|
|
1581
|
+
let hostname;
|
|
1582
|
+
try {
|
|
1583
|
+
hostname = new URL(url).hostname.toLowerCase();
|
|
1584
|
+
} catch {
|
|
1585
|
+
return false;
|
|
1586
|
+
}
|
|
1587
|
+
const bare = hostname.replace(/^\[|\]$/g, "");
|
|
1588
|
+
return bare === "localhost" || bare === "::1" || /^127(?:\.\d{1,3}){3}$/.test(bare);
|
|
1589
|
+
}
|
|
1590
|
+
function resolveClientSecret(baseUrl, env = process.env) {
|
|
1591
|
+
const fromEnv = usable(env[SECRET_KEY]);
|
|
1592
|
+
if (fromEnv) return fromEnv;
|
|
1593
|
+
if (!isLoopbackUrl(baseUrl)) return "";
|
|
1594
|
+
return readEnvFileSecret() || readStoredSecret();
|
|
1595
|
+
}
|
|
1357
1596
|
//#endregion
|
|
1358
1597
|
//#region src/mcp/rest-proxy.ts
|
|
1359
1598
|
const DEFAULT_URL = "http://localhost:3111";
|
|
@@ -1370,6 +1609,16 @@ function forceProxy() {
|
|
|
1370
1609
|
const raw = process.env["AGENTMEMORY_FORCE_PROXY"];
|
|
1371
1610
|
return raw === "1" || raw === "true";
|
|
1372
1611
|
}
|
|
1612
|
+
var ProxyCallError = class extends Error {
|
|
1613
|
+
status;
|
|
1614
|
+
body;
|
|
1615
|
+
constructor(message, status, body) {
|
|
1616
|
+
super(message);
|
|
1617
|
+
this.name = "ProxyCallError";
|
|
1618
|
+
this.status = status;
|
|
1619
|
+
this.body = body;
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1373
1622
|
let cached = null;
|
|
1374
1623
|
let cachedAt = 0;
|
|
1375
1624
|
let probeInFlight = null;
|
|
@@ -1383,7 +1632,7 @@ function baseUrl() {
|
|
|
1383
1632
|
return (resolveEnvOrEmpty("AGENTMEMORY_URL") || DEFAULT_URL).replace(/\/+$/, "");
|
|
1384
1633
|
}
|
|
1385
1634
|
function authHeader() {
|
|
1386
|
-
const secret =
|
|
1635
|
+
const secret = resolveClientSecret(baseUrl());
|
|
1387
1636
|
return secret ? { authorization: `Bearer ${secret}` } : {};
|
|
1388
1637
|
}
|
|
1389
1638
|
const defaultLivezProbe = async (url, timeoutMs, headers) => {
|
|
@@ -1440,7 +1689,16 @@ async function resolveHandle() {
|
|
|
1440
1689
|
},
|
|
1441
1690
|
signal: AbortSignal.timeout(CALL_TIMEOUT_MS)
|
|
1442
1691
|
});
|
|
1443
|
-
if (!res.ok)
|
|
1692
|
+
if (!res.ok) {
|
|
1693
|
+
const errText = await res.text().catch(() => "");
|
|
1694
|
+
let errBody = void 0;
|
|
1695
|
+
if (errText) try {
|
|
1696
|
+
errBody = JSON.parse(errText);
|
|
1697
|
+
} catch {
|
|
1698
|
+
errBody = void 0;
|
|
1699
|
+
}
|
|
1700
|
+
throw new ProxyCallError(`${init?.method || "GET"} ${path} -> ${res.status} ${res.statusText}`, res.status, errBody);
|
|
1701
|
+
}
|
|
1444
1702
|
const text = await res.text();
|
|
1445
1703
|
return text ? JSON.parse(text) : null;
|
|
1446
1704
|
}
|
|
@@ -1471,10 +1729,15 @@ const IMPLEMENTED_TOOLS = new Set([
|
|
|
1471
1729
|
"memory_audit",
|
|
1472
1730
|
"memory_governance_delete"
|
|
1473
1731
|
]);
|
|
1732
|
+
const SUPPORTED_PROTOCOL_VERSIONS = [
|
|
1733
|
+
"2025-11-25",
|
|
1734
|
+
"2025-06-18",
|
|
1735
|
+
"2025-03-26",
|
|
1736
|
+
"2024-11-05"
|
|
1737
|
+
];
|
|
1474
1738
|
const SERVER_INFO = {
|
|
1475
1739
|
name: "agentmemory",
|
|
1476
|
-
version: VERSION
|
|
1477
|
-
protocolVersion: "2024-11-05"
|
|
1740
|
+
version: VERSION
|
|
1478
1741
|
};
|
|
1479
1742
|
const kv = new InMemoryKV(getStandalonePersistPath());
|
|
1480
1743
|
let modeAnnounced = false;
|
|
@@ -1523,6 +1786,8 @@ function validate(toolName, args) {
|
|
|
1523
1786
|
v.type = args["type"] || "fact";
|
|
1524
1787
|
v.concepts = normalizeList(args["concepts"]);
|
|
1525
1788
|
v.files = normalizeList(args["files"]);
|
|
1789
|
+
if (typeof args["project"] === "string" && args["project"].trim()) v.project = args["project"].trim();
|
|
1790
|
+
if (typeof args["agentId"] === "string" && args["agentId"].trim()) v.agentId = args["agentId"].trim();
|
|
1526
1791
|
return v;
|
|
1527
1792
|
}
|
|
1528
1793
|
case "memory_recall":
|
|
@@ -1566,7 +1831,9 @@ async function handleProxy(v, handle) {
|
|
|
1566
1831
|
content: v.content,
|
|
1567
1832
|
type: v.type,
|
|
1568
1833
|
concepts: v.concepts,
|
|
1569
|
-
files: v.files
|
|
1834
|
+
files: v.files,
|
|
1835
|
+
...v.project !== void 0 && { project: v.project },
|
|
1836
|
+
...v.agentId !== void 0 && { agentId: v.agentId }
|
|
1570
1837
|
})
|
|
1571
1838
|
}));
|
|
1572
1839
|
case "memory_recall": {
|
|
@@ -1601,7 +1868,12 @@ async function handleProxy(v, handle) {
|
|
|
1601
1868
|
reason: v.reason
|
|
1602
1869
|
})
|
|
1603
1870
|
}));
|
|
1604
|
-
case "memory_export":
|
|
1871
|
+
case "memory_export": try {
|
|
1872
|
+
return textResponse(await handle.call("/agentmemory/export", { method: "GET" }), true);
|
|
1873
|
+
} catch (err) {
|
|
1874
|
+
if (err instanceof ProxyCallError && err.body != null && typeof err.body === "object" && err.body.oversized === true) return textResponse(err.body, true);
|
|
1875
|
+
throw err;
|
|
1876
|
+
}
|
|
1605
1877
|
case "memory_audit": return textResponse(await handle.call(`/agentmemory/audit?limit=${v.limit}`, { method: "GET" }), true);
|
|
1606
1878
|
default: throw new Error(`Unknown tool: ${v.tool}`);
|
|
1607
1879
|
}
|
|
@@ -1670,11 +1942,7 @@ async function handleLocal(v, kvInstance) {
|
|
|
1670
1942
|
memories: await kvInstance.list("mem:memories"),
|
|
1671
1943
|
sessions: await kvInstance.list("mem:sessions")
|
|
1672
1944
|
}, true);
|
|
1673
|
-
case "memory_audit": {
|
|
1674
|
-
const entries = await kvInstance.list("mem:audit");
|
|
1675
|
-
const limit = v.limit ?? 50;
|
|
1676
|
-
return textResponse({ entries: entries.slice(0, limit) }, true);
|
|
1677
|
-
}
|
|
1945
|
+
case "memory_audit": return textResponse(await queryAudit(kvInstance, { limit: v.limit ?? 50 }), true);
|
|
1678
1946
|
default: throw new Error(`Unknown tool: ${v.tool}`);
|
|
1679
1947
|
}
|
|
1680
1948
|
}
|
|
@@ -1737,14 +2005,17 @@ async function handleToolsList() {
|
|
|
1737
2005
|
}
|
|
1738
2006
|
const transport = createStdioTransport(async (method, params) => {
|
|
1739
2007
|
switch (method) {
|
|
1740
|
-
case "initialize":
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
2008
|
+
case "initialize": {
|
|
2009
|
+
const requested = params?.protocolVersion;
|
|
2010
|
+
return {
|
|
2011
|
+
protocolVersion: typeof requested === "string" && SUPPORTED_PROTOCOL_VERSIONS.includes(requested) ? requested : SUPPORTED_PROTOCOL_VERSIONS[0],
|
|
2012
|
+
capabilities: { tools: { listChanged: false } },
|
|
2013
|
+
serverInfo: {
|
|
2014
|
+
name: SERVER_INFO.name,
|
|
2015
|
+
version: SERVER_INFO.version
|
|
2016
|
+
}
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
1748
2019
|
case "notifications/initialized": return {};
|
|
1749
2020
|
case "tools/list": return handleToolsList();
|
|
1750
2021
|
case "tools/call": {
|