@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/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 payload = hasBody ? JSON.stringify(body) : "";
777
- const script = [
778
- "curl -sS --fail-with-body",
779
- `-m "$MEM_API_TIMEOUT"`,
780
- `-X "$MEM_API_METHOD"`,
781
- `-H "Authorization: Bearer $MEM_API_KEY"`,
782
- `-H "x-api-key: $MEM_API_KEY"`,
783
- `-H "Content-Type: application/json"`,
784
- `-H "Accept: application/json"`,
785
- hasBody ? "--data-binary @-" : "",
786
- `-w '\\n%{http_code}'`,
787
- `"$MEM_API_URL"`
788
- ].filter(Boolean).join(" ");
789
- const proc = Bun.spawnSync(["bash", "-c", script], {
790
- stdin: hasBody ? Buffer.from(payload) : undefined,
791
- env: {
792
- ...process.env,
793
- MEM_API_KEY: cfg.apiKey,
794
- MEM_API_URL: url,
795
- MEM_API_METHOD: method,
796
- MEM_API_TIMEOUT: process.env["HASNA_MEMENTOS_API_TIMEOUT"] || DEFAULT_TIMEOUT_S
797
- },
798
- stdout: "pipe",
799
- stderr: "pipe"
800
- });
801
- const out = proc.stdout ? new TextDecoder().decode(proc.stdout) : "";
802
- const err = proc.stderr ? new TextDecoder().decode(proc.stderr) : "";
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 join2, resolve } from "path";
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 = join2(dir, ".mementos", "mementos.db");
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(join2(dir, ".git")))
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 = join2(home, ".hasna", "mementos");
1815
- const oldDir = join2(home, ".mementos");
1845
+ const newDir = join3(home, ".hasna", "mementos");
1846
+ const oldDir = join3(home, ".mementos");
1816
1847
  if (!existsSync2(newDir) && existsSync2(oldDir)) {
1817
- mkdirSync2(join2(home, ".hasna"), { recursive: true });
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 join2(gitRoot, ".mementos", "mementos.db");
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 join2(home, ".hasna", "mementos", "mementos.db");
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 writeFileSync2, unlinkSync, cpSync as cpSync2 } from "fs";
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 join6, resolve as resolve3 } from "path";
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 = join6(homeDir(), ".hasna", "mementos", "config.json");
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 = join6(dir, filename);
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(join6(dir, ".git"))) {
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 join6(homeDir(), ".hasna", "mementos", "profiles");
10524
+ return join7(homeDir(), ".hasna", "mementos", "profiles");
10510
10525
  }
10511
10526
  function globalConfigPath() {
10512
- return join6(homeDir(), ".hasna", "mementos", "config.json");
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 = join6(_home, ".hasna", "mementos");
10534
- const _oldDir = join6(_home, ".mementos");
10548
+ const _newDir = join7(_home, ".hasna", "mementos");
10549
+ const _oldDir = join7(_home, ".mementos");
10535
10550
  if (!existsSync6(_newDir) && existsSync6(_oldDir)) {
10536
- mkdirSync4(join6(_home, ".hasna"), { recursive: true });
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 = join6(profilesDir(), `${profile}.db`);
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 = join6(gitRoot, ".mementos", "mementos.db");
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(join6(".mementos", "mementos.db"));
10578
+ const found = findFileWalkingUp(join7(".mementos", "mementos.db"));
10564
10579
  if (found) {
10565
10580
  return found;
10566
10581
  }
10567
- const fallback = join6(homeDir(), ".hasna", "mementos", "mementos.db");
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 join3, resolve as resolve2 } from "path";
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(join3(dir, ".git")))
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 join4 } from "path";
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 join4(home, ".claude", "projects");
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: join4(projectDir, f),
55429
- mtime: statSync(join4(projectDir, f)).mtimeMs
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 = join4(getProjectsDir(), encodeCwd(cwd));
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 join5 } from "path";
55708
- var DB_PATH = join5(process.env["HOME"] || process.env["USERPROFILE"] || "~", ".open-sessions-registry.db");
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 asmrRecall(db, args.query, {
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 asmrRecall(db, args.query, {
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
- const db = getDatabase();
58869
- const id = resolvePartialId(db, "entities", nameOrId);
58870
- if (id)
58871
- return getEntity(id);
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 join7, resolve as resolve4, relative, dirname as dirname5, extname, basename as basename3 } from "path";
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 = join7(base, `index${ext}`);
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 = join7(current, entry);
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, db);
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 scopeClause = args.scope ? `AND scope = ?` : "";
62995
- const projectClause = args.project_id ? `AND project_id = ?` : "";
62996
- const machineClause = visibleMachineId === null ? "AND machine_id IS NULL" : "AND (machine_id IS NULL OR machine_id = ?)";
62997
- const extraParams = [
62998
- ...args.scope ? [args.scope] : [],
62999
- ...args.project_id ? [args.project_id] : [],
63000
- ...visibleMachineId === null ? [] : [visibleMachineId]
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
- function registerSystemMemoryAdminTools({ server, z, createMemory: createMemory2, getMemory: getMemory2, getDatabase: getDatabase2, formatError: formatError10, resolveId: resolveId2, ensureAutoProject: ensureAutoProject2 }) {
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 conditions = ["trust_score < ?", "status = 'active'"];
63237
- const params = [threshold];
63238
- if (args.project_id) {
63239
- const { resolvePartialId: resolvePartialId2 } = await Promise.resolve().then(() => (init_database(), exports_database));
63240
- const resolved = resolvePartialId2(db, "projects", args.project_id);
63241
- conditions.push("project_id = ?");
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 = (hasMore ? rows.slice(0, limit) : rows).map(parseMemoryRow3);
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
- const db = getDatabase();
63780
- db.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", message, email || null, category || "general", "mementos");
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);