@hasna/mementos 0.14.58 → 0.14.59
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/dist/cli/commands/info-report.d.ts.map +1 -1
- package/dist/cli/index.js +266 -113
- package/dist/db/api-mode.d.ts.map +1 -1
- package/dist/db/memories.d.ts +32 -0
- package/dist/db/memories.d.ts.map +1 -1
- package/dist/index.js +110 -65
- package/dist/lib/asmr/recall.d.ts +3 -0
- package/dist/lib/asmr/recall.d.ts.map +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +239 -267
- package/dist/mcp/tools/graph-utils.d.ts.map +1 -1
- package/dist/mcp/tools/memory-crud.d.ts.map +1 -1
- package/dist/mcp/tools/memory-search.d.ts.map +1 -1
- package/dist/mcp/tools/storage-tools.d.ts.map +1 -1
- package/dist/mcp/tools/system-tools-memory-admin.d.ts +1 -1
- package/dist/mcp/tools/system-tools-memory-admin.d.ts.map +1 -1
- package/dist/mcp/tools/system-tools-shared.d.ts.map +1 -1
- package/dist/mcp/tools/utility-tools.d.ts.map +1 -1
- package/dist/server/index.js +722 -53
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/lib/remote-sync.d.ts +0 -49
- package/dist/lib/remote-sync.d.ts.map +0 -1
- package/dist/mcp/tools/memory-sync.d.ts +0 -3
- package/dist/mcp/tools/memory-sync.d.ts.map +0 -1
package/dist/mcp/index.js
CHANGED
|
@@ -738,6 +738,10 @@ var init_storage = __esm(() => {
|
|
|
738
738
|
});
|
|
739
739
|
|
|
740
740
|
// src/db/api-mode.ts
|
|
741
|
+
import { tmpdir } from "os";
|
|
742
|
+
import { join as join2 } from "path";
|
|
743
|
+
import { writeFileSync as writeFileSync2, unlinkSync } from "fs";
|
|
744
|
+
import { randomUUID } from "crypto";
|
|
741
745
|
function firstEnv(...keys) {
|
|
742
746
|
for (const k of keys) {
|
|
743
747
|
const v = process.env[k]?.trim();
|
|
@@ -773,33 +777,60 @@ function apiRequestRaw(method, path, body) {
|
|
|
773
777
|
throw new Error("api-mode: not configured (HASNA_MEMENTOS_API_URL / HASNA_MEMENTOS_API_KEY)");
|
|
774
778
|
const url = `${cfg.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
775
779
|
const hasBody = body !== undefined && body !== null;
|
|
776
|
-
const
|
|
777
|
-
const
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
780
|
+
const timeout = process.env["HASNA_MEMENTOS_API_TIMEOUT"] || DEFAULT_TIMEOUT_S;
|
|
781
|
+
const headerLines = `Authorization: Bearer ${cfg.apiKey}
|
|
782
|
+
x-api-key: ${cfg.apiKey}
|
|
783
|
+
`;
|
|
784
|
+
const args = [
|
|
785
|
+
"curl",
|
|
786
|
+
"-sS",
|
|
787
|
+
"--fail-with-body",
|
|
788
|
+
"-m",
|
|
789
|
+
timeout,
|
|
790
|
+
"-X",
|
|
791
|
+
method,
|
|
792
|
+
"-H",
|
|
793
|
+
"@-",
|
|
794
|
+
"-H",
|
|
795
|
+
"Content-Type: application/json",
|
|
796
|
+
"-H",
|
|
797
|
+
"Accept: application/json",
|
|
798
|
+
"-w",
|
|
799
|
+
"\\n%{http_code}"
|
|
800
|
+
];
|
|
801
|
+
let bodyFile;
|
|
802
|
+
if (hasBody) {
|
|
803
|
+
bodyFile = join2(tmpdir(), `mem-req-${process.pid}-${randomUUID()}.json`);
|
|
804
|
+
writeFileSync2(bodyFile, JSON.stringify(body), { mode: 384 });
|
|
805
|
+
args.push("--data-binary", `@${bodyFile}`);
|
|
806
|
+
}
|
|
807
|
+
args.push(url);
|
|
808
|
+
const childEnv = {};
|
|
809
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
810
|
+
if (v === undefined)
|
|
811
|
+
continue;
|
|
812
|
+
if (k === "HASNA_MEMENTOS_API_KEY" || k === "MEMENTOS_API_KEY")
|
|
813
|
+
continue;
|
|
814
|
+
childEnv[k] = v;
|
|
815
|
+
}
|
|
816
|
+
let out = "";
|
|
817
|
+
let err = "";
|
|
818
|
+
try {
|
|
819
|
+
const proc = Bun.spawnSync(args, {
|
|
820
|
+
stdin: Buffer.from(headerLines),
|
|
821
|
+
stdout: "pipe",
|
|
822
|
+
stderr: "pipe",
|
|
823
|
+
env: childEnv
|
|
824
|
+
});
|
|
825
|
+
out = proc.stdout ? new TextDecoder().decode(proc.stdout) : "";
|
|
826
|
+
err = proc.stderr ? new TextDecoder().decode(proc.stderr) : "";
|
|
827
|
+
} finally {
|
|
828
|
+
if (bodyFile) {
|
|
829
|
+
try {
|
|
830
|
+
unlinkSync(bodyFile);
|
|
831
|
+
} catch {}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
803
834
|
const nl = out.lastIndexOf(`
|
|
804
835
|
`);
|
|
805
836
|
const codeStr = nl >= 0 ? out.slice(nl + 1).trim() : "";
|
|
@@ -1778,7 +1809,7 @@ __export(exports_database, {
|
|
|
1778
1809
|
closeDatabase: () => closeDatabase
|
|
1779
1810
|
});
|
|
1780
1811
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, cpSync } from "fs";
|
|
1781
|
-
import { dirname, join as
|
|
1812
|
+
import { dirname, join as join3, resolve } from "path";
|
|
1782
1813
|
function isInMemoryDb(path) {
|
|
1783
1814
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
1784
1815
|
}
|
|
@@ -1787,7 +1818,7 @@ function findNearestMementosDb(startDir) {
|
|
|
1787
1818
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
1788
1819
|
const legacyHomeDb = resolve(home, ".mementos", "mementos.db");
|
|
1789
1820
|
while (true) {
|
|
1790
|
-
const candidate =
|
|
1821
|
+
const candidate = join3(dir, ".mementos", "mementos.db");
|
|
1791
1822
|
if (existsSync2(candidate) && resolve(candidate) !== legacyHomeDb)
|
|
1792
1823
|
return candidate;
|
|
1793
1824
|
const parent = dirname(dir);
|
|
@@ -1800,7 +1831,7 @@ function findNearestMementosDb(startDir) {
|
|
|
1800
1831
|
function findGitRoot(startDir) {
|
|
1801
1832
|
let dir = resolve(startDir);
|
|
1802
1833
|
while (true) {
|
|
1803
|
-
if (existsSync2(
|
|
1834
|
+
if (existsSync2(join3(dir, ".git")))
|
|
1804
1835
|
return dir;
|
|
1805
1836
|
const parent = dirname(dir);
|
|
1806
1837
|
if (parent === dir)
|
|
@@ -1811,10 +1842,10 @@ function findGitRoot(startDir) {
|
|
|
1811
1842
|
}
|
|
1812
1843
|
function migrateGlobalDir() {
|
|
1813
1844
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
1814
|
-
const newDir =
|
|
1815
|
-
const oldDir =
|
|
1845
|
+
const newDir = join3(home, ".hasna", "mementos");
|
|
1846
|
+
const oldDir = join3(home, ".mementos");
|
|
1816
1847
|
if (!existsSync2(newDir) && existsSync2(oldDir)) {
|
|
1817
|
-
mkdirSync2(
|
|
1848
|
+
mkdirSync2(join3(home, ".hasna"), { recursive: true });
|
|
1818
1849
|
cpSync(oldDir, newDir, { recursive: true });
|
|
1819
1850
|
}
|
|
1820
1851
|
}
|
|
@@ -1830,12 +1861,12 @@ function getDbPath() {
|
|
|
1830
1861
|
if (process.env["MEMENTOS_DB_SCOPE"] === "project") {
|
|
1831
1862
|
const gitRoot = findGitRoot(cwd);
|
|
1832
1863
|
if (gitRoot) {
|
|
1833
|
-
return
|
|
1864
|
+
return join3(gitRoot, ".mementos", "mementos.db");
|
|
1834
1865
|
}
|
|
1835
1866
|
}
|
|
1836
1867
|
migrateGlobalDir();
|
|
1837
1868
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
1838
|
-
return
|
|
1869
|
+
return join3(home, ".hasna", "mementos", "mementos.db");
|
|
1839
1870
|
}
|
|
1840
1871
|
function ensureDir(filePath) {
|
|
1841
1872
|
if (isInMemoryDb(filePath))
|
|
@@ -2342,12 +2373,14 @@ __export(exports_memories, {
|
|
|
2342
2373
|
parseMemoryRow: () => parseMemoryRow,
|
|
2343
2374
|
listMemoryHistory: () => listMemoryHistory,
|
|
2344
2375
|
listMemories: () => listMemories,
|
|
2376
|
+
listLowTrustMemories: () => listLowTrustMemories,
|
|
2345
2377
|
indexMemoryEmbedding: () => indexMemoryEmbedding,
|
|
2346
2378
|
incrementRecallCount: () => incrementRecallCount,
|
|
2347
2379
|
getMemoryVersions: () => getMemoryVersions,
|
|
2348
2380
|
getMemoryEmbeddings: () => getMemoryEmbeddings,
|
|
2349
2381
|
getMemoryChain: () => getMemoryChain,
|
|
2350
2382
|
getMemoryByKey: () => getMemoryByKey,
|
|
2383
|
+
getMemoryBriefing: () => getMemoryBriefing,
|
|
2351
2384
|
getMemory: () => getMemory,
|
|
2352
2385
|
getMemoriesByKey: () => getMemoriesByKey,
|
|
2353
2386
|
deleteMemory: () => deleteMemory,
|
|
@@ -2357,6 +2390,14 @@ __export(exports_memories, {
|
|
|
2357
2390
|
bulkDeleteMemories: () => bulkDeleteMemories
|
|
2358
2391
|
});
|
|
2359
2392
|
function runEntityExtraction(_memory, _projectId, _d) {}
|
|
2393
|
+
function applyContentType(d, id, memory, contentType) {
|
|
2394
|
+
if (!contentType || contentType === "text")
|
|
2395
|
+
return;
|
|
2396
|
+
try {
|
|
2397
|
+
d.run("UPDATE memories SET content_type = ? WHERE id = ?", [contentType, id]);
|
|
2398
|
+
memory.content_type = contentType;
|
|
2399
|
+
} catch {}
|
|
2400
|
+
}
|
|
2360
2401
|
function parseMemoryRow(row) {
|
|
2361
2402
|
return {
|
|
2362
2403
|
id: row["id"],
|
|
@@ -2461,6 +2502,7 @@ function createMemory(input, dedupeMode = "merge", db) {
|
|
|
2461
2502
|
insertTag2.run(existing.id, tag);
|
|
2462
2503
|
}
|
|
2463
2504
|
const merged = getMemory(existing.id, d);
|
|
2505
|
+
applyContentType(d, existing.id, merged, input.content_type);
|
|
2464
2506
|
try {
|
|
2465
2507
|
const existingMemories = listMemoriesByKey(input.key, d);
|
|
2466
2508
|
const trustScore = computeTrustScore(safeValue, input.key, existingMemories, input.importance);
|
|
@@ -2510,6 +2552,7 @@ function createMemory(input, dedupeMode = "merge", db) {
|
|
|
2510
2552
|
insertTag.run(id, tag);
|
|
2511
2553
|
}
|
|
2512
2554
|
const memory = getMemory(id, d);
|
|
2555
|
+
applyContentType(d, id, memory, input.content_type);
|
|
2513
2556
|
try {
|
|
2514
2557
|
const existingMemories = listMemoriesByKey(input.key, d);
|
|
2515
2558
|
const trustScore = computeTrustScore(safeValue, input.key, existingMemories, input.importance);
|
|
@@ -2844,6 +2887,66 @@ function listMemories(filter, db) {
|
|
|
2844
2887
|
const rows = d.query(sql).all(...params);
|
|
2845
2888
|
return rows.map(parseMemoryRow);
|
|
2846
2889
|
}
|
|
2890
|
+
function getMemoryBriefing(opts, db) {
|
|
2891
|
+
const limit = opts.limit ?? 20;
|
|
2892
|
+
if (!db && isApiMode()) {
|
|
2893
|
+
const q = toQuery({
|
|
2894
|
+
since: opts.since,
|
|
2895
|
+
scope: opts.scope,
|
|
2896
|
+
project_id: opts.project_id,
|
|
2897
|
+
machine_agnostic: opts.visible_machine_id === null || opts.visible_machine_id === undefined ? true : undefined,
|
|
2898
|
+
visible_machine_id: typeof opts.visible_machine_id === "string" ? opts.visible_machine_id : undefined,
|
|
2899
|
+
limit
|
|
2900
|
+
});
|
|
2901
|
+
const { data } = apiJson("GET", `/memories/briefing${q}`);
|
|
2902
|
+
return data ?? { new: [], updated: [], expired: [] };
|
|
2903
|
+
}
|
|
2904
|
+
const d = db || getDatabase();
|
|
2905
|
+
const visibleMachineId = opts.visible_machine_id;
|
|
2906
|
+
const scopeClause = opts.scope ? "AND scope = ?" : "";
|
|
2907
|
+
const projectClause = opts.project_id ? "AND project_id = ?" : "";
|
|
2908
|
+
const machineClause = typeof visibleMachineId === "string" ? "AND (machine_id IS NULL OR machine_id = ?)" : "AND machine_id IS NULL";
|
|
2909
|
+
const extraParams = [
|
|
2910
|
+
...opts.scope ? [opts.scope] : [],
|
|
2911
|
+
...opts.project_id ? [opts.project_id] : [],
|
|
2912
|
+
...typeof visibleMachineId === "string" ? [visibleMachineId] : []
|
|
2913
|
+
];
|
|
2914
|
+
const newRows = d.prepare(`SELECT * FROM memories
|
|
2915
|
+
WHERE status = 'active' AND created_at > ? ${scopeClause} ${projectClause} ${machineClause}
|
|
2916
|
+
ORDER BY importance DESC, created_at DESC LIMIT ?`).all(opts.since, ...extraParams, limit);
|
|
2917
|
+
const updatedRows = d.prepare(`SELECT * FROM memories
|
|
2918
|
+
WHERE status = 'active' AND updated_at > ? AND created_at <= ? ${scopeClause} ${projectClause} ${machineClause}
|
|
2919
|
+
ORDER BY importance DESC, updated_at DESC LIMIT ?`).all(opts.since, opts.since, ...extraParams, limit);
|
|
2920
|
+
const expiredRows = d.prepare(`SELECT * FROM memories
|
|
2921
|
+
WHERE status != 'active' AND updated_at > ? ${scopeClause} ${projectClause} ${machineClause}
|
|
2922
|
+
ORDER BY updated_at DESC LIMIT ?`).all(opts.since, ...extraParams, Math.min(limit, 10));
|
|
2923
|
+
return {
|
|
2924
|
+
new: newRows.map(parseMemoryRow),
|
|
2925
|
+
updated: updatedRows.map(parseMemoryRow),
|
|
2926
|
+
expired: expiredRows.map(parseMemoryRow)
|
|
2927
|
+
};
|
|
2928
|
+
}
|
|
2929
|
+
function listLowTrustMemories(opts = {}, db) {
|
|
2930
|
+
const threshold = opts.threshold ?? 0.8;
|
|
2931
|
+
const limit = opts.limit ?? 20;
|
|
2932
|
+
const offset = opts.offset ?? 0;
|
|
2933
|
+
if (!db && isApiMode()) {
|
|
2934
|
+
const q = toQuery({ threshold, project_id: opts.project_id, limit, offset });
|
|
2935
|
+
const { data } = apiJson("GET", `/memories/audit${q}`);
|
|
2936
|
+
return data?.memories ?? [];
|
|
2937
|
+
}
|
|
2938
|
+
const d = db || getDatabase();
|
|
2939
|
+
const conditions = ["trust_score < ?", "status = 'active'"];
|
|
2940
|
+
const params = [threshold];
|
|
2941
|
+
if (opts.project_id) {
|
|
2942
|
+
const resolved = resolvePartialId(d, "projects", opts.project_id);
|
|
2943
|
+
conditions.push("project_id = ?");
|
|
2944
|
+
params.push(resolved ?? opts.project_id);
|
|
2945
|
+
}
|
|
2946
|
+
params.push(limit, offset);
|
|
2947
|
+
const rows = d.prepare(`SELECT * FROM memories WHERE ${conditions.join(" AND ")} ORDER BY trust_score ASC LIMIT ? OFFSET ?`).all(...params);
|
|
2948
|
+
return rows.map(parseMemoryRow);
|
|
2949
|
+
}
|
|
2847
2950
|
function listMemoryHistory(opts = {}, db) {
|
|
2848
2951
|
const limit = opts.limit ?? 20;
|
|
2849
2952
|
const offset = opts.offset ?? 0;
|
|
@@ -3055,6 +3158,10 @@ function incrementRecallCount(id, db) {
|
|
|
3055
3158
|
} catch {}
|
|
3056
3159
|
}
|
|
3057
3160
|
function cleanExpiredMemories(db) {
|
|
3161
|
+
if (!db && isApiMode()) {
|
|
3162
|
+
const { data } = apiJson("POST", "/memories/clean");
|
|
3163
|
+
return data?.cleaned ?? 0;
|
|
3164
|
+
}
|
|
3058
3165
|
const d = db || getDatabase();
|
|
3059
3166
|
const timestamp = now();
|
|
3060
3167
|
const countRow = d.query("SELECT COUNT(*) as c FROM memories WHERE expires_at IS NOT NULL AND expires_at < ?").get(timestamp);
|
|
@@ -3107,6 +3214,12 @@ async function semanticSearch(queryText, options = {}, db) {
|
|
|
3107
3214
|
}
|
|
3108
3215
|
const d = db || getDatabase();
|
|
3109
3216
|
const { threshold = 0.5, limit = 10, scope, agent_id, project_id } = options;
|
|
3217
|
+
if (options.index_missing) {
|
|
3218
|
+
const unindexed = d.prepare(`SELECT id, value, summary, when_to_use FROM memories
|
|
3219
|
+
WHERE status = 'active' AND id NOT IN (SELECT memory_id FROM memory_embeddings)
|
|
3220
|
+
LIMIT 100`).all();
|
|
3221
|
+
await Promise.all(unindexed.map((m) => indexMemoryEmbedding(m.id, m.when_to_use || [m.value, m.summary].filter(Boolean).join(" "), d)));
|
|
3222
|
+
}
|
|
3110
3223
|
const { embedding: queryEmbedding } = await generateEmbedding(queryText);
|
|
3111
3224
|
const conditions = ["m.status = 'active'", "e.embedding IS NOT NULL"];
|
|
3112
3225
|
const params = [];
|
|
@@ -10211,104 +10324,6 @@ var init_memory_broadcast = __esm(() => {
|
|
|
10211
10324
|
CONVERSATIONS_API = process.env.CONVERSATIONS_API_URL || "http://localhost:7020";
|
|
10212
10325
|
});
|
|
10213
10326
|
|
|
10214
|
-
// src/lib/remote-sync.ts
|
|
10215
|
-
var exports_remote_sync = {};
|
|
10216
|
-
__export(exports_remote_sync, {
|
|
10217
|
-
syncWithRemote: () => syncWithRemote,
|
|
10218
|
-
pushToRemote: () => pushToRemote,
|
|
10219
|
-
pullFromRemote: () => pullFromRemote,
|
|
10220
|
-
pingRemote: () => pingRemote,
|
|
10221
|
-
DEFAULT_PORT: () => DEFAULT_PORT
|
|
10222
|
-
});
|
|
10223
|
-
function resolveUrl(url) {
|
|
10224
|
-
const raw = url ?? process.env["MEMENTOS_REMOTE_URL"] ?? "";
|
|
10225
|
-
if (!raw)
|
|
10226
|
-
throw new Error("No remote URL. Set MEMENTOS_REMOTE_URL or pass url.");
|
|
10227
|
-
return raw.replace(/\/$/, "");
|
|
10228
|
-
}
|
|
10229
|
-
async function fetchJson(url, init) {
|
|
10230
|
-
const res = await fetch(url, {
|
|
10231
|
-
...init,
|
|
10232
|
-
headers: { "Content-Type": "application/json", ...init?.headers },
|
|
10233
|
-
signal: AbortSignal.timeout(15000)
|
|
10234
|
-
});
|
|
10235
|
-
if (!res.ok) {
|
|
10236
|
-
const text = await res.text().catch(() => "");
|
|
10237
|
-
throw new Error(`Remote ${res.status}: ${text.slice(0, 200)}`);
|
|
10238
|
-
}
|
|
10239
|
-
return res.json();
|
|
10240
|
-
}
|
|
10241
|
-
async function pushToRemote(opts = {}) {
|
|
10242
|
-
const baseUrl = resolveUrl(opts.remoteUrl);
|
|
10243
|
-
const errors2 = [];
|
|
10244
|
-
const memories = listMemories({
|
|
10245
|
-
scope: opts.scope,
|
|
10246
|
-
agent_id: opts.agentId,
|
|
10247
|
-
project_id: opts.projectId,
|
|
10248
|
-
limit: opts.limit ?? 1e4
|
|
10249
|
-
});
|
|
10250
|
-
if (!memories.length) {
|
|
10251
|
-
return { pushed: 0, errors: [], remote_url: baseUrl };
|
|
10252
|
-
}
|
|
10253
|
-
const result = await fetchJson(`${baseUrl}/api/memories/import`, {
|
|
10254
|
-
method: "POST",
|
|
10255
|
-
body: JSON.stringify({ memories, overwrite: opts.overwrite ?? true })
|
|
10256
|
-
});
|
|
10257
|
-
return {
|
|
10258
|
-
pushed: result.imported,
|
|
10259
|
-
errors: [...errors2, ...result.errors],
|
|
10260
|
-
remote_url: baseUrl
|
|
10261
|
-
};
|
|
10262
|
-
}
|
|
10263
|
-
async function pullFromRemote(opts = {}) {
|
|
10264
|
-
const baseUrl = resolveUrl(opts.remoteUrl);
|
|
10265
|
-
const errors2 = [];
|
|
10266
|
-
const filter = { limit: opts.limit ?? 1e4 };
|
|
10267
|
-
if (opts.scope)
|
|
10268
|
-
filter.scope = opts.scope;
|
|
10269
|
-
if (opts.agentId)
|
|
10270
|
-
filter.agent_id = opts.agentId;
|
|
10271
|
-
if (opts.projectId)
|
|
10272
|
-
filter.project_id = opts.projectId;
|
|
10273
|
-
const result = await fetchJson(`${baseUrl}/api/memories/export`, { method: "POST", body: JSON.stringify(filter) });
|
|
10274
|
-
let pulled = 0;
|
|
10275
|
-
for (const mem of result.memories) {
|
|
10276
|
-
try {
|
|
10277
|
-
createMemory(mem, opts.overwrite !== false ? "merge" : "create");
|
|
10278
|
-
pulled++;
|
|
10279
|
-
} catch (e) {
|
|
10280
|
-
errors2.push(`Failed to import "${mem.key}": ${e instanceof Error ? e.message : String(e)}`);
|
|
10281
|
-
}
|
|
10282
|
-
}
|
|
10283
|
-
return { pulled, errors: errors2, remote_url: baseUrl };
|
|
10284
|
-
}
|
|
10285
|
-
async function syncWithRemote(opts = {}) {
|
|
10286
|
-
const baseUrl = resolveUrl(opts.remoteUrl);
|
|
10287
|
-
const pushResult = await pushToRemote({ ...opts, remoteUrl: baseUrl });
|
|
10288
|
-
const pullResult = await pullFromRemote({ ...opts, remoteUrl: baseUrl, overwrite: false });
|
|
10289
|
-
return {
|
|
10290
|
-
pushed: pushResult.pushed,
|
|
10291
|
-
pulled: pullResult.pulled,
|
|
10292
|
-
errors: [...pushResult.errors, ...pullResult.errors],
|
|
10293
|
-
remote_url: baseUrl
|
|
10294
|
-
};
|
|
10295
|
-
}
|
|
10296
|
-
async function pingRemote(url) {
|
|
10297
|
-
const baseUrl = resolveUrl(url);
|
|
10298
|
-
try {
|
|
10299
|
-
const res = await fetch(`${baseUrl}/api/health`, {
|
|
10300
|
-
signal: AbortSignal.timeout(5000)
|
|
10301
|
-
});
|
|
10302
|
-
return { ok: res.ok, url: baseUrl, status: res.status };
|
|
10303
|
-
} catch (e) {
|
|
10304
|
-
return { ok: false, url: baseUrl, error: e instanceof Error ? e.message : String(e) };
|
|
10305
|
-
}
|
|
10306
|
-
}
|
|
10307
|
-
var DEFAULT_PORT = 19428;
|
|
10308
|
-
var init_remote_sync = __esm(() => {
|
|
10309
|
-
init_memories();
|
|
10310
|
-
});
|
|
10311
|
-
|
|
10312
10327
|
// src/db/audit.ts
|
|
10313
10328
|
var exports_audit = {};
|
|
10314
10329
|
__export(exports_audit, {
|
|
@@ -10422,9 +10437,9 @@ var init_export_v1 = __esm(() => {
|
|
|
10422
10437
|
});
|
|
10423
10438
|
|
|
10424
10439
|
// src/lib/config.ts
|
|
10425
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, writeFileSync as
|
|
10440
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, writeFileSync as writeFileSync3, unlinkSync as unlinkSync2, cpSync as cpSync2 } from "fs";
|
|
10426
10441
|
import { homedir as homedir2 } from "os";
|
|
10427
|
-
import { basename as basename2, dirname as dirname4, join as
|
|
10442
|
+
import { basename as basename2, dirname as dirname4, join as join7, resolve as resolve3 } from "path";
|
|
10428
10443
|
function isInMemoryDb2(path) {
|
|
10429
10444
|
return path === ":memory:" || path.startsWith("file::memory:");
|
|
10430
10445
|
}
|
|
@@ -10451,7 +10466,7 @@ function isValidCategory(value) {
|
|
|
10451
10466
|
return VALID_CATEGORIES.includes(value);
|
|
10452
10467
|
}
|
|
10453
10468
|
function loadConfig() {
|
|
10454
|
-
const configPath =
|
|
10469
|
+
const configPath = join7(homeDir(), ".hasna", "mementos", "config.json");
|
|
10455
10470
|
let fileConfig = {};
|
|
10456
10471
|
if (existsSync6(configPath)) {
|
|
10457
10472
|
try {
|
|
@@ -10481,7 +10496,7 @@ function findFileWalkingUp(filename) {
|
|
|
10481
10496
|
let dir = process.cwd();
|
|
10482
10497
|
const legacyHomeMementosDb = resolve3(homeDir(), ".mementos", "mementos.db");
|
|
10483
10498
|
while (true) {
|
|
10484
|
-
const candidate =
|
|
10499
|
+
const candidate = join7(dir, filename);
|
|
10485
10500
|
if (existsSync6(candidate) && resolve3(candidate) !== legacyHomeMementosDb) {
|
|
10486
10501
|
return candidate;
|
|
10487
10502
|
}
|
|
@@ -10495,7 +10510,7 @@ function findFileWalkingUp(filename) {
|
|
|
10495
10510
|
function findGitRoot3() {
|
|
10496
10511
|
let dir = process.cwd();
|
|
10497
10512
|
while (true) {
|
|
10498
|
-
if (existsSync6(
|
|
10513
|
+
if (existsSync6(join7(dir, ".git"))) {
|
|
10499
10514
|
return dir;
|
|
10500
10515
|
}
|
|
10501
10516
|
const parent = dirname4(dir);
|
|
@@ -10506,10 +10521,10 @@ function findGitRoot3() {
|
|
|
10506
10521
|
}
|
|
10507
10522
|
}
|
|
10508
10523
|
function profilesDir() {
|
|
10509
|
-
return
|
|
10524
|
+
return join7(homeDir(), ".hasna", "mementos", "profiles");
|
|
10510
10525
|
}
|
|
10511
10526
|
function globalConfigPath() {
|
|
10512
|
-
return
|
|
10527
|
+
return join7(homeDir(), ".hasna", "mementos", "config.json");
|
|
10513
10528
|
}
|
|
10514
10529
|
function readGlobalConfig() {
|
|
10515
10530
|
const p = globalConfigPath();
|
|
@@ -10530,10 +10545,10 @@ function getActiveProfile() {
|
|
|
10530
10545
|
}
|
|
10531
10546
|
function getDbPath2() {
|
|
10532
10547
|
const _home = homeDir();
|
|
10533
|
-
const _newDir =
|
|
10534
|
-
const _oldDir =
|
|
10548
|
+
const _newDir = join7(_home, ".hasna", "mementos");
|
|
10549
|
+
const _oldDir = join7(_home, ".mementos");
|
|
10535
10550
|
if (!existsSync6(_newDir) && existsSync6(_oldDir)) {
|
|
10536
|
-
mkdirSync4(
|
|
10551
|
+
mkdirSync4(join7(_home, ".hasna"), { recursive: true });
|
|
10537
10552
|
cpSync2(_oldDir, _newDir, { recursive: true });
|
|
10538
10553
|
}
|
|
10539
10554
|
const envDbPath = process.env["HASNA_MEMENTOS_DB_PATH"] ?? process.env["MEMENTOS_DB_PATH"];
|
|
@@ -10547,7 +10562,7 @@ function getDbPath2() {
|
|
|
10547
10562
|
}
|
|
10548
10563
|
const profile = getActiveProfile();
|
|
10549
10564
|
if (profile) {
|
|
10550
|
-
const profilePath =
|
|
10565
|
+
const profilePath = join7(profilesDir(), `${profile}.db`);
|
|
10551
10566
|
ensureDir2(dirname4(profilePath));
|
|
10552
10567
|
return profilePath;
|
|
10553
10568
|
}
|
|
@@ -10555,16 +10570,16 @@ function getDbPath2() {
|
|
|
10555
10570
|
if (dbScope === "project") {
|
|
10556
10571
|
const gitRoot = findGitRoot3();
|
|
10557
10572
|
if (gitRoot) {
|
|
10558
|
-
const dbPath =
|
|
10573
|
+
const dbPath = join7(gitRoot, ".mementos", "mementos.db");
|
|
10559
10574
|
ensureDir2(dirname4(dbPath));
|
|
10560
10575
|
return dbPath;
|
|
10561
10576
|
}
|
|
10562
10577
|
}
|
|
10563
|
-
const found = findFileWalkingUp(
|
|
10578
|
+
const found = findFileWalkingUp(join7(".mementos", "mementos.db"));
|
|
10564
10579
|
if (found) {
|
|
10565
10580
|
return found;
|
|
10566
10581
|
}
|
|
10567
|
-
const fallback =
|
|
10582
|
+
const fallback = join7(homeDir(), ".hasna", "mementos", "mementos.db");
|
|
10568
10583
|
ensureDir2(dirname4(fallback));
|
|
10569
10584
|
return fallback;
|
|
10570
10585
|
}
|
|
@@ -55370,11 +55385,11 @@ init_machines();
|
|
|
55370
55385
|
// src/lib/project-detect.ts
|
|
55371
55386
|
init_database();
|
|
55372
55387
|
import { existsSync as existsSync3 } from "fs";
|
|
55373
|
-
import { basename, dirname as dirname2, join as
|
|
55388
|
+
import { basename, dirname as dirname2, join as join4, resolve as resolve2 } from "path";
|
|
55374
55389
|
function findGitRoot2(startDir) {
|
|
55375
55390
|
let dir = resolve2(startDir);
|
|
55376
55391
|
while (true) {
|
|
55377
|
-
if (existsSync3(
|
|
55392
|
+
if (existsSync3(join4(dir, ".git")))
|
|
55378
55393
|
return dir;
|
|
55379
55394
|
const parent = dirname2(dir);
|
|
55380
55395
|
if (parent === dir)
|
|
@@ -55411,22 +55426,22 @@ init_built_in_hooks();
|
|
|
55411
55426
|
|
|
55412
55427
|
// src/lib/session-watcher.ts
|
|
55413
55428
|
import { watch, existsSync as existsSync4, statSync, readFileSync as readFileSync2 } from "fs";
|
|
55414
|
-
import { join as
|
|
55429
|
+
import { join as join5 } from "path";
|
|
55415
55430
|
import { readdirSync } from "fs";
|
|
55416
55431
|
function encodeCwd(cwd) {
|
|
55417
55432
|
return cwd.replace(/\//g, "-");
|
|
55418
55433
|
}
|
|
55419
55434
|
function getProjectsDir() {
|
|
55420
55435
|
const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
|
|
55421
|
-
return
|
|
55436
|
+
return join5(home, ".claude", "projects");
|
|
55422
55437
|
}
|
|
55423
55438
|
function findActiveSession(projectDir) {
|
|
55424
55439
|
if (!existsSync4(projectDir))
|
|
55425
55440
|
return null;
|
|
55426
55441
|
const files = readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).map((f) => ({
|
|
55427
55442
|
name: f,
|
|
55428
|
-
path:
|
|
55429
|
-
mtime: statSync(
|
|
55443
|
+
path: join5(projectDir, f),
|
|
55444
|
+
mtime: statSync(join5(projectDir, f)).mtimeMs
|
|
55430
55445
|
})).sort((a, b) => b.mtime - a.mtime);
|
|
55431
55446
|
return files[0]?.path || null;
|
|
55432
55447
|
}
|
|
@@ -55469,7 +55484,7 @@ function processNewLines(filePath, callback) {
|
|
|
55469
55484
|
}
|
|
55470
55485
|
function startSessionWatcher(cwd, callback) {
|
|
55471
55486
|
stopSessionWatcher();
|
|
55472
|
-
const projectDir =
|
|
55487
|
+
const projectDir = join5(getProjectsDir(), encodeCwd(cwd));
|
|
55473
55488
|
const sessionFile = findActiveSession(projectDir);
|
|
55474
55489
|
if (!sessionFile) {
|
|
55475
55490
|
return { sessionFile: null };
|
|
@@ -55704,8 +55719,8 @@ function getRecentlyPushedCount() {
|
|
|
55704
55719
|
// src/lib/session-registry.ts
|
|
55705
55720
|
init_storage();
|
|
55706
55721
|
import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
55707
|
-
import { dirname as dirname3, join as
|
|
55708
|
-
var DB_PATH =
|
|
55722
|
+
import { dirname as dirname3, join as join6 } from "path";
|
|
55723
|
+
var DB_PATH = join6(process.env["HOME"] || process.env["USERPROFILE"] || "~", ".open-sessions-registry.db");
|
|
55709
55724
|
var _db2 = null;
|
|
55710
55725
|
function getDb() {
|
|
55711
55726
|
if (_db2)
|
|
@@ -56216,6 +56231,7 @@ function resolveProjectId(agentId, explicitProjectId) {
|
|
|
56216
56231
|
|
|
56217
56232
|
// src/mcp/tools/memory-crud.ts
|
|
56218
56233
|
init_database();
|
|
56234
|
+
init_api_mode();
|
|
56219
56235
|
init_machines();
|
|
56220
56236
|
init_search();
|
|
56221
56237
|
|
|
@@ -56454,7 +56470,7 @@ function registerMemoryCrudTools(server) {
|
|
|
56454
56470
|
input.machine_id = getCurrentMachineId();
|
|
56455
56471
|
} catch {}
|
|
56456
56472
|
}
|
|
56457
|
-
if (conflictStrategy === "reject" && input.agent_id) {
|
|
56473
|
+
if (conflictStrategy === "reject" && input.agent_id && !isApiMode()) {
|
|
56458
56474
|
const db = getDatabase();
|
|
56459
56475
|
try {
|
|
56460
56476
|
const existing = db.query(`SELECT vector_clock FROM memories WHERE key = ? AND scope = ? AND COALESCE(agent_id, '') = ? AND COALESCE(project_id, '') = ? AND COALESCE(session_id, '') = ? AND status = 'active'`).get(input.key, input.scope || "private", input.agent_id || "", input.project_id || "", input.session_id || "");
|
|
@@ -56552,7 +56568,7 @@ Is the new memory already covered by these existing memories? Reply with JSON on
|
|
|
56552
56568
|
} catch {}
|
|
56553
56569
|
}
|
|
56554
56570
|
const memory = createMemory(input, dedupeMode);
|
|
56555
|
-
if (input.agent_id) {
|
|
56571
|
+
if (input.agent_id && !isApiMode()) {
|
|
56556
56572
|
try {
|
|
56557
56573
|
const db = getDatabase();
|
|
56558
56574
|
const row = db.query("SELECT vector_clock FROM memories WHERE id = ?").get(memory.id);
|
|
@@ -56599,7 +56615,7 @@ Is the new memory already covered by these existing memories? Reply with JSON on
|
|
|
56599
56615
|
if (args.agent_id)
|
|
56600
56616
|
touchAgent(args.agent_id);
|
|
56601
56617
|
let text = formatMemory(memory);
|
|
56602
|
-
if (memory.sequence_group) {
|
|
56618
|
+
if (memory.sequence_group && !isApiMode()) {
|
|
56603
56619
|
try {
|
|
56604
56620
|
const db = getDatabase();
|
|
56605
56621
|
const chainRows = db.prepare("SELECT * FROM memories WHERE sequence_group = ? AND status = 'active' ORDER BY sequence_order ASC").all(memory.sequence_group);
|
|
@@ -57197,7 +57213,6 @@ ID: ${mem?.id?.slice(0, 8)}` }] };
|
|
|
57197
57213
|
// src/mcp/tools/memory-search.ts
|
|
57198
57214
|
init_zod();
|
|
57199
57215
|
init_memories();
|
|
57200
|
-
init_database();
|
|
57201
57216
|
init_search();
|
|
57202
57217
|
|
|
57203
57218
|
// src/lib/asmr/fact-agent.ts
|
|
@@ -57690,6 +57705,25 @@ async function asmrRecall(db, query, opts) {
|
|
|
57690
57705
|
duration_ms: duration
|
|
57691
57706
|
};
|
|
57692
57707
|
}
|
|
57708
|
+
|
|
57709
|
+
// src/lib/asmr/recall.ts
|
|
57710
|
+
init_database();
|
|
57711
|
+
init_api_mode();
|
|
57712
|
+
async function deepRecall(query, opts = {}) {
|
|
57713
|
+
if (isApiMode()) {
|
|
57714
|
+
const { data } = apiJson("POST", "/memories/recall/deep", { query, ...opts });
|
|
57715
|
+
return data ?? {
|
|
57716
|
+
memories: [],
|
|
57717
|
+
facts: [],
|
|
57718
|
+
timeline: [],
|
|
57719
|
+
reasoning: "",
|
|
57720
|
+
agents_used: [],
|
|
57721
|
+
duration_ms: 0
|
|
57722
|
+
};
|
|
57723
|
+
}
|
|
57724
|
+
return asmrRecall(getDatabase(), query, opts);
|
|
57725
|
+
}
|
|
57726
|
+
|
|
57693
57727
|
// src/lib/asmr/ensemble.ts
|
|
57694
57728
|
var DEFAULT_MODEL = "gpt-4.1-mini";
|
|
57695
57729
|
var ESCALATION_MODEL = "gpt-4.1";
|
|
@@ -57857,6 +57891,7 @@ Produce the single most accurate answer based on the context. If there are genui
|
|
|
57857
57891
|
};
|
|
57858
57892
|
}
|
|
57859
57893
|
}
|
|
57894
|
+
|
|
57860
57895
|
// src/mcp/tools/memory-search.ts
|
|
57861
57896
|
function registerMemorySearchTools(server) {
|
|
57862
57897
|
server.tool("memory_search", "Search memories by keyword across key, value, summary, and tags", {
|
|
@@ -57926,13 +57961,6 @@ ${lines.join(`
|
|
|
57926
57961
|
}, async (args) => {
|
|
57927
57962
|
try {
|
|
57928
57963
|
ensureAutoProject();
|
|
57929
|
-
if (args.index_missing) {
|
|
57930
|
-
const db = getDatabase();
|
|
57931
|
-
const unindexed = db.prepare(`SELECT id, value, summary, when_to_use FROM memories
|
|
57932
|
-
WHERE status = 'active' AND id NOT IN (SELECT memory_id FROM memory_embeddings)
|
|
57933
|
-
LIMIT 100`).all();
|
|
57934
|
-
await Promise.all(unindexed.map((m) => indexMemoryEmbedding(m.id, m.when_to_use || [m.value, m.summary].filter(Boolean).join(" "))));
|
|
57935
|
-
}
|
|
57936
57964
|
let effectiveProjectId = args.project_id;
|
|
57937
57965
|
if (!args.project_id && args.agent_id) {
|
|
57938
57966
|
effectiveProjectId = resolveProjectId(args.agent_id, null) ?? undefined;
|
|
@@ -57943,7 +57971,8 @@ ${lines.join(`
|
|
|
57943
57971
|
limit,
|
|
57944
57972
|
scope: args.scope,
|
|
57945
57973
|
agent_id: args.agent_id,
|
|
57946
|
-
project_id: effectiveProjectId
|
|
57974
|
+
project_id: effectiveProjectId,
|
|
57975
|
+
index_missing: args.index_missing
|
|
57947
57976
|
});
|
|
57948
57977
|
if (results.length === 0) {
|
|
57949
57978
|
return { content: [{ type: "text", text: `No semantically similar memories found for: "${args.query}". Try a lower threshold or call with index_missing:true to generate embeddings first.` }] };
|
|
@@ -58047,7 +58076,6 @@ ${lines.join(`
|
|
|
58047
58076
|
}, async (args) => {
|
|
58048
58077
|
try {
|
|
58049
58078
|
ensureAutoProject();
|
|
58050
|
-
const db = getDatabase();
|
|
58051
58079
|
const FAST_SCORE_THRESHOLD = 0.6;
|
|
58052
58080
|
const maxResults = positiveLimit(args.max_results, 10);
|
|
58053
58081
|
if (args.mode === "fast") {
|
|
@@ -58064,7 +58092,7 @@ ${lines.join(`
|
|
|
58064
58092
|
`)}` }] };
|
|
58065
58093
|
}
|
|
58066
58094
|
if (args.mode === "deep") {
|
|
58067
|
-
const asmrResult2 = await
|
|
58095
|
+
const asmrResult2 = await deepRecall(args.query, {
|
|
58068
58096
|
max_results: maxResults,
|
|
58069
58097
|
project_id: args.project_id
|
|
58070
58098
|
});
|
|
@@ -58097,7 +58125,7 @@ Reasoning: ${compactText(answer.reasoning, 400)}`;
|
|
|
58097
58125
|
${lines.join(`
|
|
58098
58126
|
`)}` }] };
|
|
58099
58127
|
}
|
|
58100
|
-
const asmrResult = await
|
|
58128
|
+
const asmrResult = await deepRecall(args.query, {
|
|
58101
58129
|
max_results: maxResults,
|
|
58102
58130
|
project_id: args.project_id
|
|
58103
58131
|
});
|
|
@@ -58236,53 +58264,6 @@ ${lines.join(`
|
|
|
58236
58264
|
});
|
|
58237
58265
|
}
|
|
58238
58266
|
|
|
58239
|
-
// src/mcp/tools/memory-sync.ts
|
|
58240
|
-
init_zod();
|
|
58241
|
-
function registerMemorySyncTools(server) {
|
|
58242
|
-
server.tool("memory_sync_push", "Push local memories to a remote mementos-serve instance. Set MEMENTOS_REMOTE_URL or pass url.", {
|
|
58243
|
-
url: exports_external.string().optional().describe("Remote URL (e.g. http://apple01:19428). Defaults to MEMENTOS_REMOTE_URL env var."),
|
|
58244
|
-
scope: exports_external.enum(["global", "shared", "private", "working"]).optional(),
|
|
58245
|
-
agent_id: exports_external.string().optional(),
|
|
58246
|
-
project_id: exports_external.string().optional(),
|
|
58247
|
-
limit: exports_external.coerce.number().optional()
|
|
58248
|
-
}, async (args) => {
|
|
58249
|
-
try {
|
|
58250
|
-
const { pushToRemote: pushToRemote2 } = await Promise.resolve().then(() => (init_remote_sync(), exports_remote_sync));
|
|
58251
|
-
const result = await pushToRemote2({ remoteUrl: args.url, scope: args.scope, agentId: args.agent_id, projectId: args.project_id, limit: args.limit });
|
|
58252
|
-
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
58253
|
-
} catch (e) {
|
|
58254
|
-
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
58255
|
-
}
|
|
58256
|
-
});
|
|
58257
|
-
server.tool("memory_sync_pull", "Pull memories from a remote mementos-serve instance into local DB. Set MEMENTOS_REMOTE_URL or pass url.", {
|
|
58258
|
-
url: exports_external.string().optional().describe("Remote URL. Defaults to MEMENTOS_REMOTE_URL env var."),
|
|
58259
|
-
scope: exports_external.enum(["global", "shared", "private", "working"]).optional(),
|
|
58260
|
-
agent_id: exports_external.string().optional(),
|
|
58261
|
-
project_id: exports_external.string().optional(),
|
|
58262
|
-
limit: exports_external.coerce.number().optional(),
|
|
58263
|
-
overwrite: exports_external.coerce.boolean().optional().describe("Overwrite existing memories with same key (default: false = keep newer)")
|
|
58264
|
-
}, async (args) => {
|
|
58265
|
-
try {
|
|
58266
|
-
const { pullFromRemote: pullFromRemote2 } = await Promise.resolve().then(() => (init_remote_sync(), exports_remote_sync));
|
|
58267
|
-
const result = await pullFromRemote2({ remoteUrl: args.url, scope: args.scope, agentId: args.agent_id, projectId: args.project_id, limit: args.limit, overwrite: args.overwrite });
|
|
58268
|
-
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
58269
|
-
} catch (e) {
|
|
58270
|
-
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
58271
|
-
}
|
|
58272
|
-
});
|
|
58273
|
-
server.tool("memory_sync_status", "Check if a remote mementos-serve is reachable. Set MEMENTOS_REMOTE_URL or pass url.", {
|
|
58274
|
-
url: exports_external.string().optional().describe("Remote URL. Defaults to MEMENTOS_REMOTE_URL env var.")
|
|
58275
|
-
}, async (args) => {
|
|
58276
|
-
try {
|
|
58277
|
-
const { pingRemote: pingRemote2 } = await Promise.resolve().then(() => (init_remote_sync(), exports_remote_sync));
|
|
58278
|
-
const result = await pingRemote2(args.url);
|
|
58279
|
-
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
58280
|
-
} catch (e) {
|
|
58281
|
-
return { content: [{ type: "text", text: formatError(e) }], isError: true };
|
|
58282
|
-
}
|
|
58283
|
-
});
|
|
58284
|
-
}
|
|
58285
|
-
|
|
58286
58267
|
// src/mcp/tools/memory-stats.ts
|
|
58287
58268
|
init_zod();
|
|
58288
58269
|
function registerMemoryStatsTools(server) {
|
|
@@ -58845,6 +58826,7 @@ init_entity_memories();
|
|
|
58845
58826
|
|
|
58846
58827
|
// src/mcp/tools/graph-utils.ts
|
|
58847
58828
|
init_database();
|
|
58829
|
+
init_api_mode();
|
|
58848
58830
|
init_entities();
|
|
58849
58831
|
function formatGraphError(error) {
|
|
58850
58832
|
if (error instanceof Error)
|
|
@@ -58852,6 +58834,8 @@ function formatGraphError(error) {
|
|
|
58852
58834
|
return String(error);
|
|
58853
58835
|
}
|
|
58854
58836
|
function resolveGraphId(partialId, table = "memories") {
|
|
58837
|
+
if (isApiMode())
|
|
58838
|
+
return partialId;
|
|
58855
58839
|
const db = getDatabase();
|
|
58856
58840
|
const id = resolvePartialId(db, table, partialId);
|
|
58857
58841
|
if (!id)
|
|
@@ -58865,10 +58849,12 @@ function resolveEntityParam(nameOrId, type) {
|
|
|
58865
58849
|
try {
|
|
58866
58850
|
return getEntity(nameOrId);
|
|
58867
58851
|
} catch {}
|
|
58868
|
-
|
|
58869
|
-
|
|
58870
|
-
|
|
58871
|
-
|
|
58852
|
+
if (!isApiMode()) {
|
|
58853
|
+
const db = getDatabase();
|
|
58854
|
+
const id = resolvePartialId(db, "entities", nameOrId);
|
|
58855
|
+
if (id)
|
|
58856
|
+
return getEntity(id);
|
|
58857
|
+
}
|
|
58872
58858
|
throw new Error(`Entity not found: ${nameOrId}`);
|
|
58873
58859
|
}
|
|
58874
58860
|
|
|
@@ -59128,7 +59114,7 @@ init_database();
|
|
|
59128
59114
|
init_entities();
|
|
59129
59115
|
init_relations();
|
|
59130
59116
|
import { readdirSync as readdirSync3, readFileSync as readFileSync4, statSync as statSync2, existsSync as existsSync7 } from "fs";
|
|
59131
|
-
import { join as
|
|
59117
|
+
import { join as join8, resolve as resolve4, relative, dirname as dirname5, extname, basename as basename3 } from "path";
|
|
59132
59118
|
var DEFAULT_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".py", ".go", ".rs"];
|
|
59133
59119
|
var DEFAULT_EXCLUDES = ["node_modules", ".git", "dist", "build", ".next", "__pycache__", "target", "vendor"];
|
|
59134
59120
|
function parseImports(_filePath, content) {
|
|
@@ -59165,7 +59151,7 @@ function resolveImport(fromFile, importPath, allFiles) {
|
|
|
59165
59151
|
const withExt = base + ext;
|
|
59166
59152
|
if (allFiles.has(withExt))
|
|
59167
59153
|
return withExt;
|
|
59168
|
-
const index =
|
|
59154
|
+
const index = join8(base, `index${ext}`);
|
|
59169
59155
|
if (allFiles.has(index))
|
|
59170
59156
|
return index;
|
|
59171
59157
|
}
|
|
@@ -59183,7 +59169,7 @@ function collectFiles(dir, extensions, excludes) {
|
|
|
59183
59169
|
for (const entry of entries) {
|
|
59184
59170
|
if (excludes.some((e) => entry === e || current.includes(`/${e}/`)))
|
|
59185
59171
|
continue;
|
|
59186
|
-
const full =
|
|
59172
|
+
const full = join8(current, entry);
|
|
59187
59173
|
let stat;
|
|
59188
59174
|
try {
|
|
59189
59175
|
stat = statSync2(full);
|
|
@@ -62846,7 +62832,6 @@ ${created.join(`
|
|
|
62846
62832
|
// src/mcp/tools/utility-tools.ts
|
|
62847
62833
|
init_zod();
|
|
62848
62834
|
init_memories();
|
|
62849
|
-
init_database();
|
|
62850
62835
|
init_memories();
|
|
62851
62836
|
init_profile_synthesizer();
|
|
62852
62837
|
init_machine_visibility();
|
|
@@ -62979,9 +62964,8 @@ function registerUtilityTools(server) {
|
|
|
62979
62964
|
limit: exports_external.coerce.number().optional().describe("Max memories per category (default: 20)")
|
|
62980
62965
|
}, async (args) => {
|
|
62981
62966
|
try {
|
|
62982
|
-
const db = getDatabase();
|
|
62983
62967
|
const limit = args.limit || 20;
|
|
62984
|
-
const visibleMachineId = resolveVisibleMachineId(args.machine_id
|
|
62968
|
+
const visibleMachineId = resolveVisibleMachineId(args.machine_id);
|
|
62985
62969
|
let since = args.since;
|
|
62986
62970
|
if (!since && args.agent_id) {
|
|
62987
62971
|
const ag = getAgent(args.agent_id);
|
|
@@ -62991,23 +62975,13 @@ function registerUtilityTools(server) {
|
|
|
62991
62975
|
if (!since) {
|
|
62992
62976
|
since = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
|
62993
62977
|
}
|
|
62994
|
-
const
|
|
62995
|
-
|
|
62996
|
-
|
|
62997
|
-
|
|
62998
|
-
|
|
62999
|
-
|
|
63000
|
-
|
|
63001
|
-
];
|
|
63002
|
-
const newMems = db.prepare(`SELECT id, key, value, summary, importance, scope, category, agent_id, created_at
|
|
63003
|
-
FROM memories WHERE status = 'active' AND created_at > ? ${scopeClause} ${projectClause} ${machineClause}
|
|
63004
|
-
ORDER BY importance DESC, created_at DESC LIMIT ?`).all(since, ...extraParams, limit);
|
|
63005
|
-
const updatedMems = db.prepare(`SELECT id, key, value, summary, importance, scope, category, agent_id, updated_at
|
|
63006
|
-
FROM memories WHERE status = 'active' AND updated_at > ? AND created_at <= ? ${scopeClause} ${projectClause} ${machineClause}
|
|
63007
|
-
ORDER BY importance DESC, updated_at DESC LIMIT ?`).all(since, since, ...extraParams, limit);
|
|
63008
|
-
const expiredMems = db.prepare(`SELECT id, key, scope, category, updated_at, status
|
|
63009
|
-
FROM memories WHERE status != 'active' AND updated_at > ? ${scopeClause} ${projectClause} ${machineClause}
|
|
63010
|
-
ORDER BY updated_at DESC LIMIT ?`).all(since, ...extraParams, Math.min(limit, 10));
|
|
62978
|
+
const { new: newMems, updated: updatedMems, expired: expiredMems } = getMemoryBriefing({
|
|
62979
|
+
since,
|
|
62980
|
+
scope: args.scope,
|
|
62981
|
+
project_id: args.project_id,
|
|
62982
|
+
visible_machine_id: visibleMachineId,
|
|
62983
|
+
limit
|
|
62984
|
+
});
|
|
63011
62985
|
const parts = [`Memory briefing since ${since}`];
|
|
63012
62986
|
if (newMems.length > 0) {
|
|
63013
62987
|
parts.push(`
|
|
@@ -63221,7 +63195,8 @@ ${result.profile}` }] };
|
|
|
63221
63195
|
}
|
|
63222
63196
|
|
|
63223
63197
|
// src/mcp/tools/system-tools-memory-admin.ts
|
|
63224
|
-
|
|
63198
|
+
init_memories();
|
|
63199
|
+
function registerSystemMemoryAdminTools({ server, z, createMemory: createMemory2, getMemory: getMemory2, formatError: formatError10, resolveId: resolveId2, ensureAutoProject: ensureAutoProject2 }) {
|
|
63225
63200
|
server.tool("memory_audit", "Review low-trust memories (trust_score < threshold). Returns memories flagged by the poisoning detection heuristic for manual review.", {
|
|
63226
63201
|
threshold: z.coerce.number().optional().describe("Trust score threshold (default 0.8). Returns memories below this."),
|
|
63227
63202
|
project_id: z.string().optional(),
|
|
@@ -63229,27 +63204,20 @@ function registerSystemMemoryAdminTools({ server, z, createMemory: createMemory2
|
|
|
63229
63204
|
offset: z.coerce.number().optional().describe("Cursor offset for the next page")
|
|
63230
63205
|
}, async (args) => {
|
|
63231
63206
|
try {
|
|
63232
|
-
const db = getDatabase2();
|
|
63233
63207
|
const threshold = args.threshold ?? 0.8;
|
|
63234
63208
|
const limit = positiveLimit(args.limit, 20);
|
|
63235
63209
|
const offset = args.offset ?? 0;
|
|
63236
|
-
const
|
|
63237
|
-
|
|
63238
|
-
|
|
63239
|
-
|
|
63240
|
-
|
|
63241
|
-
|
|
63242
|
-
params.push(resolved ?? args.project_id);
|
|
63243
|
-
}
|
|
63244
|
-
params.push(limit + 1, offset);
|
|
63245
|
-
const sql = `SELECT * FROM memories WHERE ${conditions.join(" AND ")} ORDER BY trust_score ASC LIMIT ?`;
|
|
63246
|
-
const rows = db.query(`${sql} OFFSET ?`).all(...params);
|
|
63210
|
+
const rows = listLowTrustMemories({
|
|
63211
|
+
threshold,
|
|
63212
|
+
project_id: args.project_id,
|
|
63213
|
+
limit: limit + 1,
|
|
63214
|
+
offset
|
|
63215
|
+
});
|
|
63247
63216
|
if (rows.length === 0) {
|
|
63248
63217
|
return { content: [{ type: "text", text: `No low-trust memories found (threshold: ${threshold})` }] };
|
|
63249
63218
|
}
|
|
63250
|
-
const { parseMemoryRow: parseMemoryRow3 } = await Promise.resolve().then(() => (init_memories(), exports_memories));
|
|
63251
63219
|
const hasMore = rows.length > limit;
|
|
63252
|
-
const memories =
|
|
63220
|
+
const memories = hasMore ? rows.slice(0, limit) : rows;
|
|
63253
63221
|
const lines = memories.map((m) => `[trust=${(m.trust_score ?? 1).toFixed(2)}] ${m.id.slice(0, 8)} ${m.key}: ${compactText(m.value, 100)}`);
|
|
63254
63222
|
const hint = compactPageHint({
|
|
63255
63223
|
shown: memories.length,
|
|
@@ -63405,10 +63373,9 @@ ${lines.join(`
|
|
|
63405
63373
|
agent_id: args.agent_id,
|
|
63406
63374
|
project_id: args.project_id,
|
|
63407
63375
|
session_id: args.session_id,
|
|
63408
|
-
metadata
|
|
63376
|
+
metadata,
|
|
63377
|
+
content_type: "image"
|
|
63409
63378
|
});
|
|
63410
|
-
const db = getDatabase2();
|
|
63411
|
-
db.run("UPDATE memories SET content_type = 'image' WHERE id = ?", [memory.id]);
|
|
63412
63379
|
return { content: [{ type: "text", text: JSON.stringify({
|
|
63413
63380
|
saved: memory.key,
|
|
63414
63381
|
id: memory.id.slice(0, 8),
|
|
@@ -63663,6 +63630,7 @@ ${result.errors.join(`
|
|
|
63663
63630
|
init_zod();
|
|
63664
63631
|
init_memories();
|
|
63665
63632
|
init_database();
|
|
63633
|
+
init_api_mode();
|
|
63666
63634
|
init_tool_events();
|
|
63667
63635
|
function formatError10(error) {
|
|
63668
63636
|
if (error instanceof Error)
|
|
@@ -63670,6 +63638,8 @@ function formatError10(error) {
|
|
|
63670
63638
|
return String(error);
|
|
63671
63639
|
}
|
|
63672
63640
|
function resolveId2(partialId, table = "memories") {
|
|
63641
|
+
if (isApiMode())
|
|
63642
|
+
return partialId;
|
|
63673
63643
|
const db = getDatabase();
|
|
63674
63644
|
const id = resolvePartialId(db, table, partialId);
|
|
63675
63645
|
if (!id)
|
|
@@ -63709,7 +63679,6 @@ function registerSystemTools(server) {
|
|
|
63709
63679
|
// src/mcp/tools/storage-tools.ts
|
|
63710
63680
|
init_zod();
|
|
63711
63681
|
init_storage();
|
|
63712
|
-
init_database();
|
|
63713
63682
|
function parseTables(raw) {
|
|
63714
63683
|
if (!raw) {
|
|
63715
63684
|
return;
|
|
@@ -63776,8 +63745,12 @@ function registerMementosStorageTools(server) {
|
|
|
63776
63745
|
category: exports_external.enum(["bug", "feature", "general"]).optional()
|
|
63777
63746
|
}, async ({ message, email, category }) => {
|
|
63778
63747
|
try {
|
|
63779
|
-
|
|
63780
|
-
|
|
63748
|
+
saveFeedback({
|
|
63749
|
+
message,
|
|
63750
|
+
email: email || null,
|
|
63751
|
+
category: category || "general",
|
|
63752
|
+
version: "mementos"
|
|
63753
|
+
});
|
|
63781
63754
|
return text({ saved: true });
|
|
63782
63755
|
} catch (error) {
|
|
63783
63756
|
return errorText(error);
|
|
@@ -64922,7 +64895,6 @@ When running with --dangerously-load-development-channels, mementos will proacti
|
|
|
64922
64895
|
registerMemoryValidationTools(server);
|
|
64923
64896
|
registerMemorySearchTools(server);
|
|
64924
64897
|
registerMemoryLifecycleTools(server);
|
|
64925
|
-
registerMemorySyncTools(server);
|
|
64926
64898
|
registerMemoryStatsTools(server);
|
|
64927
64899
|
registerMemoryAuditTools(server);
|
|
64928
64900
|
registerMemoryIoTools(server);
|