@hasna/mementos 0.10.11 → 0.10.12

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.
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Remote sync — push/pull memories to/from a remote mementos-serve instance.
3
+ *
4
+ * The remote must be running `mementos-serve`. Point at it via:
5
+ * MEMENTOS_REMOTE_URL=http://apple01:19428
6
+ * or pass the URL directly to push/pull functions.
7
+ */
8
+ declare const DEFAULT_PORT = 19428;
9
+ export interface RemoteSyncOptions {
10
+ remoteUrl?: string;
11
+ scope?: "global" | "shared" | "private";
12
+ agentId?: string;
13
+ projectId?: string;
14
+ since?: string;
15
+ limit?: number;
16
+ overwrite?: boolean;
17
+ }
18
+ export interface RemoteSyncResult {
19
+ pushed?: number;
20
+ pulled?: number;
21
+ errors: string[];
22
+ remote_url: string;
23
+ }
24
+ /**
25
+ * Push local memories to a remote mementos-serve instance.
26
+ * Uses POST /api/memories/import on the remote.
27
+ */
28
+ export declare function pushToRemote(opts?: RemoteSyncOptions): Promise<RemoteSyncResult>;
29
+ /**
30
+ * Pull memories from a remote mementos-serve instance into local DB.
31
+ * Uses POST /api/memories/export on the remote.
32
+ */
33
+ export declare function pullFromRemote(opts?: RemoteSyncOptions): Promise<RemoteSyncResult>;
34
+ /**
35
+ * Bidirectional sync: push local then pull remote.
36
+ * On key conflict, newer timestamp wins.
37
+ */
38
+ export declare function syncWithRemote(opts?: RemoteSyncOptions): Promise<RemoteSyncResult>;
39
+ /**
40
+ * Check if a remote mementos-serve is reachable.
41
+ */
42
+ export declare function pingRemote(url?: string): Promise<{
43
+ ok: boolean;
44
+ url: string;
45
+ status?: number;
46
+ error?: string;
47
+ }>;
48
+ export { DEFAULT_PORT };
49
+ //# sourceMappingURL=remote-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-sync.d.ts","sourceRoot":"","sources":["../../src/lib/remote-sync.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,QAAA,MAAM,YAAY,QAAQ,CAAC;AAE3B,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAqBD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA4B1F;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyB5F;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,IAAI,GAAE,iBAAsB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAU5F;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAUrH;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
package/dist/mcp/index.js CHANGED
@@ -3461,6 +3461,104 @@ var init_memory_broadcast = __esm(() => {
3461
3461
  CONVERSATIONS_API = process.env.CONVERSATIONS_API_URL || "http://localhost:7020";
3462
3462
  });
3463
3463
 
3464
+ // src/lib/remote-sync.ts
3465
+ var exports_remote_sync = {};
3466
+ __export(exports_remote_sync, {
3467
+ syncWithRemote: () => syncWithRemote,
3468
+ pushToRemote: () => pushToRemote,
3469
+ pullFromRemote: () => pullFromRemote,
3470
+ pingRemote: () => pingRemote,
3471
+ DEFAULT_PORT: () => DEFAULT_PORT
3472
+ });
3473
+ function resolveUrl(url) {
3474
+ const raw = url ?? process.env["MEMENTOS_REMOTE_URL"] ?? "";
3475
+ if (!raw)
3476
+ throw new Error("No remote URL. Set MEMENTOS_REMOTE_URL or pass url.");
3477
+ return raw.replace(/\/$/, "");
3478
+ }
3479
+ async function fetchJson(url, init) {
3480
+ const res = await fetch(url, {
3481
+ ...init,
3482
+ headers: { "Content-Type": "application/json", ...init?.headers },
3483
+ signal: AbortSignal.timeout(15000)
3484
+ });
3485
+ if (!res.ok) {
3486
+ const text = await res.text().catch(() => "");
3487
+ throw new Error(`Remote ${res.status}: ${text.slice(0, 200)}`);
3488
+ }
3489
+ return res.json();
3490
+ }
3491
+ async function pushToRemote(opts = {}) {
3492
+ const baseUrl = resolveUrl(opts.remoteUrl);
3493
+ const errors2 = [];
3494
+ const memories = listMemories({
3495
+ scope: opts.scope,
3496
+ agent_id: opts.agentId,
3497
+ project_id: opts.projectId,
3498
+ limit: opts.limit ?? 1e4
3499
+ });
3500
+ if (!memories.length) {
3501
+ return { pushed: 0, errors: [], remote_url: baseUrl };
3502
+ }
3503
+ const result = await fetchJson(`${baseUrl}/api/memories/import`, {
3504
+ method: "POST",
3505
+ body: JSON.stringify({ memories, overwrite: opts.overwrite ?? true })
3506
+ });
3507
+ return {
3508
+ pushed: result.imported,
3509
+ errors: [...errors2, ...result.errors],
3510
+ remote_url: baseUrl
3511
+ };
3512
+ }
3513
+ async function pullFromRemote(opts = {}) {
3514
+ const baseUrl = resolveUrl(opts.remoteUrl);
3515
+ const errors2 = [];
3516
+ const filter = { limit: opts.limit ?? 1e4 };
3517
+ if (opts.scope)
3518
+ filter.scope = opts.scope;
3519
+ if (opts.agentId)
3520
+ filter.agent_id = opts.agentId;
3521
+ if (opts.projectId)
3522
+ filter.project_id = opts.projectId;
3523
+ const result = await fetchJson(`${baseUrl}/api/memories/export`, { method: "POST", body: JSON.stringify(filter) });
3524
+ let pulled = 0;
3525
+ for (const mem of result.memories) {
3526
+ try {
3527
+ createMemory(mem, opts.overwrite !== false ? "merge" : "create");
3528
+ pulled++;
3529
+ } catch (e) {
3530
+ errors2.push(`Failed to import "${mem.key}": ${e instanceof Error ? e.message : String(e)}`);
3531
+ }
3532
+ }
3533
+ return { pulled, errors: errors2, remote_url: baseUrl };
3534
+ }
3535
+ async function syncWithRemote(opts = {}) {
3536
+ const baseUrl = resolveUrl(opts.remoteUrl);
3537
+ const pushResult = await pushToRemote({ ...opts, remoteUrl: baseUrl });
3538
+ const pullResult = await pullFromRemote({ ...opts, remoteUrl: baseUrl, overwrite: false });
3539
+ return {
3540
+ pushed: pushResult.pushed,
3541
+ pulled: pullResult.pulled,
3542
+ errors: [...pushResult.errors, ...pullResult.errors],
3543
+ remote_url: baseUrl
3544
+ };
3545
+ }
3546
+ async function pingRemote(url) {
3547
+ const baseUrl = resolveUrl(url);
3548
+ try {
3549
+ const res = await fetch(`${baseUrl}/api/health`, {
3550
+ signal: AbortSignal.timeout(5000)
3551
+ });
3552
+ return { ok: res.ok, url: baseUrl, status: res.status };
3553
+ } catch (e) {
3554
+ return { ok: false, url: baseUrl, error: e instanceof Error ? e.message : String(e) };
3555
+ }
3556
+ }
3557
+ var DEFAULT_PORT = 19428;
3558
+ var init_remote_sync = __esm(() => {
3559
+ init_memories();
3560
+ });
3561
+
3464
3562
  // src/mcp/index.ts
3465
3563
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3466
3564
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -9733,6 +9831,48 @@ ${lines.join(`
9733
9831
  return { content: [{ type: "text", text: formatError(e) }], isError: true };
9734
9832
  }
9735
9833
  });
9834
+ server.tool("memory_sync_push", "Push local memories to a remote mementos-serve instance. Set MEMENTOS_REMOTE_URL or pass url.", {
9835
+ url: exports_external.string().optional().describe("Remote URL (e.g. http://apple01:19428). Defaults to MEMENTOS_REMOTE_URL env var."),
9836
+ scope: exports_external.enum(["global", "shared", "private"]).optional(),
9837
+ agent_id: exports_external.string().optional(),
9838
+ project_id: exports_external.string().optional(),
9839
+ limit: exports_external.coerce.number().optional()
9840
+ }, async (args) => {
9841
+ try {
9842
+ const { pushToRemote: pushToRemote2 } = await Promise.resolve().then(() => (init_remote_sync(), exports_remote_sync));
9843
+ const result = await pushToRemote2({ remoteUrl: args.url, scope: args.scope, agentId: args.agent_id, projectId: args.project_id, limit: args.limit });
9844
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
9845
+ } catch (e) {
9846
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
9847
+ }
9848
+ });
9849
+ server.tool("memory_sync_pull", "Pull memories from a remote mementos-serve instance into local DB. Set MEMENTOS_REMOTE_URL or pass url.", {
9850
+ url: exports_external.string().optional().describe("Remote URL. Defaults to MEMENTOS_REMOTE_URL env var."),
9851
+ scope: exports_external.enum(["global", "shared", "private"]).optional(),
9852
+ agent_id: exports_external.string().optional(),
9853
+ project_id: exports_external.string().optional(),
9854
+ limit: exports_external.coerce.number().optional(),
9855
+ overwrite: exports_external.coerce.boolean().optional().describe("Overwrite existing memories with same key (default: false = keep newer)")
9856
+ }, async (args) => {
9857
+ try {
9858
+ const { pullFromRemote: pullFromRemote2 } = await Promise.resolve().then(() => (init_remote_sync(), exports_remote_sync));
9859
+ const result = await pullFromRemote2({ remoteUrl: args.url, scope: args.scope, agentId: args.agent_id, projectId: args.project_id, limit: args.limit, overwrite: args.overwrite });
9860
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
9861
+ } catch (e) {
9862
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
9863
+ }
9864
+ });
9865
+ server.tool("memory_sync_status", "Check if a remote mementos-serve is reachable. Set MEMENTOS_REMOTE_URL or pass url.", {
9866
+ url: exports_external.string().optional().describe("Remote URL. Defaults to MEMENTOS_REMOTE_URL env var.")
9867
+ }, async (args) => {
9868
+ try {
9869
+ const { pingRemote: pingRemote2 } = await Promise.resolve().then(() => (init_remote_sync(), exports_remote_sync));
9870
+ const result = await pingRemote2(args.url);
9871
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
9872
+ } catch (e) {
9873
+ return { content: [{ type: "text", text: formatError(e) }], isError: true };
9874
+ }
9875
+ });
9736
9876
  server.tool("memory_stats", "Get aggregate statistics about stored memories", {}, async () => {
9737
9877
  try {
9738
9878
  const db = getDatabase();
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AA6gDH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAkI9C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAihDH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAkI9C"}
@@ -5296,6 +5296,9 @@ function matchRoute(method, pathname) {
5296
5296
  }
5297
5297
  return null;
5298
5298
  }
5299
+ addRoute("GET", "/api/health", () => {
5300
+ return json({ ok: true, version: "1", db: getDbPath2() });
5301
+ });
5299
5302
  addRoute("GET", "/api/memories", (_req, url) => {
5300
5303
  const q = getSearchParams(url);
5301
5304
  const filter = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/mementos",
3
- "version": "0.10.11",
3
+ "version": "0.10.12",
4
4
  "description": "Universal memory system for AI agents - CLI + MCP server + library API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",