@hasna/mementos 0.14.84 → 0.14.85

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.
Files changed (37) hide show
  1. package/dist/cli/commands/info-history.d.ts.map +1 -1
  2. package/dist/cli/commands/info-stale.d.ts.map +1 -1
  3. package/dist/cli/commands/io-export.d.ts.map +1 -1
  4. package/dist/cli/commands/memory-cmd-list.d.ts.map +1 -1
  5. package/dist/cli/helpers.d.ts +31 -0
  6. package/dist/cli/helpers.d.ts.map +1 -1
  7. package/dist/cli/index.js +350 -73
  8. package/dist/db/analytics.d.ts +13 -0
  9. package/dist/db/analytics.d.ts.map +1 -1
  10. package/dist/db/api-mode.d.ts.map +1 -1
  11. package/dist/db/memories.d.ts +59 -3
  12. package/dist/db/memories.d.ts.map +1 -1
  13. package/dist/diagnostics/historical-project-registration-receipt.d.ts +39 -0
  14. package/dist/diagnostics/historical-project-registration-receipt.d.ts.map +1 -0
  15. package/dist/diagnostics/historical-project-registration-receipt.js +1656 -0
  16. package/dist/index.js +204 -35
  17. package/dist/lib/gatherer.d.ts.map +1 -1
  18. package/dist/mcp/index.js +238 -39
  19. package/dist/mcp/tools/memory-io.d.ts.map +1 -1
  20. package/dist/project-registration/authority.d.ts.map +1 -1
  21. package/dist/project-registration/historical-receipt.d.ts +38 -0
  22. package/dist/project-registration/historical-receipt.d.ts.map +1 -0
  23. package/dist/project-registration/identity.d.ts.map +1 -1
  24. package/dist/project-registration/index.d.ts +1 -1
  25. package/dist/project-registration/index.d.ts.map +1 -1
  26. package/dist/project-registration/types.d.ts +26 -0
  27. package/dist/project-registration/types.d.ts.map +1 -1
  28. package/dist/project-registration.js +201 -32
  29. package/dist/sdk/index.d.ts +7 -0
  30. package/dist/sdk/index.d.ts.map +1 -1
  31. package/dist/sdk/index.js +122 -30
  32. package/dist/server/index.js +312 -56
  33. package/dist/test-support/memories-page-stub-server.d.ts +2 -0
  34. package/dist/test-support/memories-page-stub-server.d.ts.map +1 -0
  35. package/dist/test-support/memories-page-stub.d.ts +28 -0
  36. package/dist/test-support/memories-page-stub.d.ts.map +1 -0
  37. package/package.json +3 -2
@@ -780,7 +780,16 @@ x-api-key: ${cfg.apiKey}
780
780
  function apiJson(method, path, body, options) {
781
781
  const raw = apiRequestRaw(method, path, body);
782
782
  if (raw.status >= 200 && raw.status < 300) {
783
- const data = raw.body.trim() ? JSON.parse(raw.body) : undefined;
783
+ let data;
784
+ if (raw.body.trim()) {
785
+ try {
786
+ data = JSON.parse(raw.body);
787
+ } catch (e) {
788
+ throw new ApiRequestError(`mementos cloud ${method} ${path} returned status ${raw.status} with a body that is not valid JSON (${e instanceof Error ? e.message : String(e)}) \u2014 the response is truncated or the server is unhealthy`, raw.status, raw.body.slice(0, 500));
789
+ }
790
+ } else {
791
+ data = undefined;
792
+ }
784
793
  return { status: raw.status, data };
785
794
  }
786
795
  if (raw.status === 404 && options?.allow404) {
@@ -2696,7 +2705,10 @@ __export(exports_memories, {
2696
2705
  touchMemory: () => touchMemory,
2697
2706
  semanticSearch: () => semanticSearch,
2698
2707
  parseMemoryRow: () => parseMemoryRow,
2708
+ listMemoryHistoryPage: () => listMemoryHistoryPage,
2699
2709
  listMemoryHistory: () => listMemoryHistory,
2710
+ listMemoriesPage: () => listMemoriesPage,
2711
+ listMemoriesBounded: () => listMemoriesBounded,
2700
2712
  listMemories: () => listMemories,
2701
2713
  listLowTrustMemories: () => listLowTrustMemories,
2702
2714
  indexMemoryEmbedding: () => indexMemoryEmbedding,
@@ -2710,6 +2722,8 @@ __export(exports_memories, {
2710
2722
  getMemoriesByKey: () => getMemoriesByKey,
2711
2723
  deleteMemory: () => deleteMemory,
2712
2724
  createMemory: () => createMemory,
2725
+ countMemoryHistory: () => countMemoryHistory,
2726
+ countMemories: () => countMemories,
2713
2727
  cleanExpiredMemories: () => cleanExpiredMemories,
2714
2728
  bulkUpsertMemories: () => bulkUpsertMemories,
2715
2729
  bulkDeleteMemories: () => bulkDeleteMemories
@@ -3076,29 +3090,7 @@ function getMemoriesByKey(key, scope, agentId, projectId, db) {
3076
3090
  const rows = d.query(sql).all(...params);
3077
3091
  return rows.map(parseMemoryRow);
3078
3092
  }
3079
- function listMemories(filter, db) {
3080
- if (!db && isApiMode()) {
3081
- const f = filter || {};
3082
- const q = toQuery({
3083
- key: f.key,
3084
- scope: f.scope,
3085
- category: f.category,
3086
- status: f.status,
3087
- tags: f.tags,
3088
- min_importance: f.min_importance,
3089
- pinned: f.pinned,
3090
- agent_id: f.agent_id,
3091
- project_id: f.project_id,
3092
- session_id: f.session_id,
3093
- namespace: f.namespace,
3094
- as_of: f.as_of,
3095
- limit: f.limit,
3096
- offset: f.offset
3097
- });
3098
- const { data } = apiJson("GET", `/memories${q}`);
3099
- return data?.memories ?? [];
3100
- }
3101
- const d = db || getDatabase();
3093
+ function buildMemoryListConditions(filter) {
3102
3094
  const conditions = [];
3103
3095
  const params = [];
3104
3096
  if (filter) {
@@ -3210,21 +3202,109 @@ function listMemories(filter, db) {
3210
3202
  } else {
3211
3203
  conditions.push("status = 'active'");
3212
3204
  }
3205
+ return { conditions, params };
3206
+ }
3207
+ function listMemoriesPage(filter, db) {
3208
+ const f = filter || {};
3209
+ if (!db && isApiMode()) {
3210
+ const q = toQuery({
3211
+ key: f.key,
3212
+ scope: f.scope,
3213
+ category: f.category,
3214
+ status: f.status,
3215
+ tags: f.tags,
3216
+ min_importance: f.min_importance,
3217
+ pinned: f.pinned,
3218
+ agent_id: f.agent_id,
3219
+ project_id: f.project_id,
3220
+ session_id: f.session_id,
3221
+ namespace: f.namespace,
3222
+ as_of: f.as_of,
3223
+ limit: f.limit,
3224
+ offset: f.offset
3225
+ });
3226
+ const { data } = apiJson("GET", `/memories${q}`);
3227
+ return {
3228
+ rows: data?.memories ?? [],
3229
+ has_more: data?.has_more,
3230
+ next_cursor: data?.next_cursor ?? null
3231
+ };
3232
+ }
3233
+ const d = db || getDatabase();
3234
+ const { conditions, params } = buildMemoryListConditions(f);
3213
3235
  let sql = "SELECT * FROM memories";
3214
3236
  if (conditions.length > 0) {
3215
3237
  sql += ` WHERE ${conditions.join(" AND ")}`;
3216
3238
  }
3217
3239
  sql += " ORDER BY importance DESC, created_at DESC";
3218
- if (filter?.limit) {
3240
+ if (f.limit) {
3219
3241
  sql += " LIMIT ?";
3220
- params.push(filter.limit);
3242
+ params.push(f.limit);
3221
3243
  }
3222
- if (filter?.offset) {
3244
+ if (f.offset) {
3223
3245
  sql += " OFFSET ?";
3224
- params.push(filter.offset);
3246
+ params.push(f.offset);
3225
3247
  }
3226
3248
  const rows = d.query(sql).all(...params);
3227
- return rows.map(parseMemoryRow);
3249
+ const parsed = rows.map(parseMemoryRow);
3250
+ const hasMore = f.limit !== undefined && parsed.length === f.limit;
3251
+ return {
3252
+ rows: parsed,
3253
+ has_more: hasMore,
3254
+ next_cursor: hasMore ? (f.offset ?? 0) + parsed.length : null
3255
+ };
3256
+ }
3257
+ function listMemories(filter, db) {
3258
+ return listMemoriesPage(filter, db).rows;
3259
+ }
3260
+ function listMemoriesBounded(filter = {}, target, db) {
3261
+ const pageSize = 1000;
3262
+ const maxPages = 1000;
3263
+ const want = target === undefined ? undefined : target + 1;
3264
+ const rows = [];
3265
+ const seenCursors = new Set;
3266
+ let cursor = filter.offset ?? 0;
3267
+ let pages = 0;
3268
+ for (;; ) {
3269
+ if (want !== undefined && rows.length >= want)
3270
+ break;
3271
+ if (++pages > maxPages) {
3272
+ throw new Error(`memories list traversal exceeded ${maxPages} pages while collecting rows \u2014 aborting (cursor cycle?)`);
3273
+ }
3274
+ const limit = Math.min(want === undefined ? pageSize : want - rows.length, pageSize);
3275
+ const page = listMemoriesPage({ ...filter, limit, offset: cursor }, db);
3276
+ rows.push(...page.rows);
3277
+ if (page.has_more === false)
3278
+ break;
3279
+ if (page.has_more === undefined && page.rows.length < limit)
3280
+ break;
3281
+ if (page.has_more === true && (page.next_cursor === null || page.next_cursor === undefined)) {
3282
+ throw new Error("memories list page claimed more results without a next cursor \u2014 aborting");
3283
+ }
3284
+ const next = page.next_cursor ?? cursor + page.rows.length;
3285
+ if (seenCursors.has(next)) {
3286
+ throw new Error("memories list traversal repeated a cursor \u2014 aborting");
3287
+ }
3288
+ seenCursors.add(next);
3289
+ cursor = next;
3290
+ }
3291
+ const hasMore = target !== undefined && rows.length > target;
3292
+ const trimmed = hasMore ? rows.slice(0, target) : rows;
3293
+ return {
3294
+ rows: trimmed,
3295
+ has_more: hasMore,
3296
+ next_cursor: hasMore ? (filter.offset ?? 0) + trimmed.length : null
3297
+ };
3298
+ }
3299
+ function countMemories(filter, db) {
3300
+ const d = db || getDatabase();
3301
+ const { conditions, params } = buildMemoryListConditions(filter);
3302
+ let sql = "SELECT COUNT(*) AS c FROM memories";
3303
+ if (conditions.length > 0) {
3304
+ sql += ` WHERE ${conditions.join(" AND ")}`;
3305
+ }
3306
+ const row = d.query(sql).get(...params);
3307
+ return row?.c ?? 0;
3228
3308
  }
3229
3309
  function getMemoryBriefing(opts, db) {
3230
3310
  const limit = opts.limit ?? 20;
@@ -3286,13 +3366,17 @@ function listLowTrustMemories(opts = {}, db) {
3286
3366
  const rows = d.prepare(`SELECT * FROM memories WHERE ${conditions.join(" AND ")} ORDER BY trust_score ASC LIMIT ? OFFSET ?`).all(...params);
3287
3367
  return rows.map(parseMemoryRow);
3288
3368
  }
3289
- function listMemoryHistory(opts = {}, db) {
3369
+ function listMemoryHistoryPage(opts = {}, db) {
3290
3370
  const limit = opts.limit ?? 20;
3291
3371
  const offset = opts.offset ?? 0;
3292
3372
  if (!db && isApiMode()) {
3293
3373
  const q = toQuery({ limit, offset });
3294
3374
  const { data } = apiJson("GET", `/memories/history${q}`);
3295
- return data?.memories ?? [];
3375
+ return {
3376
+ rows: data?.memories ?? [],
3377
+ has_more: data?.has_more,
3378
+ next_cursor: data?.next_cursor ?? null
3379
+ };
3296
3380
  }
3297
3381
  const d = db || getDatabase();
3298
3382
  const params = [limit];
@@ -3302,7 +3386,21 @@ function listMemoryHistory(opts = {}, db) {
3302
3386
  params.push(offset);
3303
3387
  }
3304
3388
  const rows = d.query(sql).all(...params);
3305
- return rows.map(parseMemoryRow);
3389
+ const parsed = rows.map(parseMemoryRow);
3390
+ const hasMore = parsed.length === limit;
3391
+ return {
3392
+ rows: parsed,
3393
+ has_more: hasMore,
3394
+ next_cursor: hasMore ? offset + parsed.length : null
3395
+ };
3396
+ }
3397
+ function listMemoryHistory(opts = {}, db) {
3398
+ return listMemoryHistoryPage(opts, db).rows;
3399
+ }
3400
+ function countMemoryHistory(db) {
3401
+ const d = db || getDatabase();
3402
+ const row = d.query("SELECT COUNT(*) AS c FROM memories WHERE status = 'active' AND accessed_at IS NOT NULL").get();
3403
+ return row?.c ?? 0;
3306
3404
  }
3307
3405
  function getMemoryChain(sequenceGroup, projectId, db) {
3308
3406
  if (!db && isApiMode()) {
@@ -19888,7 +19986,7 @@ class JSONSchemaGenerator {
19888
19986
  if (val === undefined) {
19889
19987
  if (this.unrepresentable === "throw") {
19890
19988
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
19891
- } else {}
19989
+ }
19892
19990
  } else if (typeof val === "bigint") {
19893
19991
  if (this.unrepresentable === "throw") {
19894
19992
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -41538,7 +41636,7 @@ var require_tracestate_impl = __commonJS((exports) => {
41538
41636
  const value = listMember.slice(i + 1, part.length);
41539
41637
  if ((0, tracestate_validators_1.validateKey)(key) && (0, tracestate_validators_1.validateValue)(value)) {
41540
41638
  agg.set(key, value);
41541
- } else {}
41639
+ }
41542
41640
  }
41543
41641
  return agg;
41544
41642
  }, new Map);
@@ -57102,6 +57200,7 @@ var FORMAT_UNITS = [
57102
57200
 
57103
57201
  // src/server/routes/memories-crud.ts
57104
57202
  init_router();
57203
+ init_database();
57105
57204
  init_enum_validation();
57106
57205
  init_types();
57107
57206
  addRoute("GET", "/api/memories", (_req, url) => {
@@ -57131,17 +57230,35 @@ addRoute("GET", "/api/memories", (_req, url) => {
57131
57230
  filter.namespace = q["namespace"];
57132
57231
  if (q["status"])
57133
57232
  filter.status = q["status"];
57134
- if (q["limit"])
57135
- filter.limit = parseInt(q["limit"], 10);
57136
- if (q["offset"])
57137
- filter.offset = parseInt(q["offset"], 10);
57233
+ const parsedLimit = Number(q["limit"]);
57234
+ const limit = Number.isInteger(parsedLimit) && parsedLimit > 0 ? Math.min(parsedLimit, 1000) : 1000;
57235
+ const parsedOffset = Number(q["offset"]);
57236
+ filter.limit = limit;
57237
+ filter.offset = Number.isInteger(parsedOffset) && parsedOffset >= 0 ? parsedOffset : 0;
57138
57238
  const memories = listMemories(filter);
57239
+ const total = countMemories(filter, getDatabase());
57240
+ const hasMore = memories.length === limit;
57241
+ const nextCursor = hasMore ? (filter.offset ?? 0) + memories.length : null;
57139
57242
  if (q["fields"]) {
57140
57243
  const fields = q["fields"].split(",").map((f) => f.trim());
57141
57244
  const filtered = memories.map((m) => Object.fromEntries(fields.map((f) => [f, m[f]]).filter(([, v]) => v !== undefined)));
57142
- return json({ memories: filtered, count: filtered.length });
57245
+ return json({
57246
+ memories: filtered,
57247
+ count: filtered.length,
57248
+ total,
57249
+ limit,
57250
+ has_more: hasMore,
57251
+ next_cursor: nextCursor
57252
+ });
57143
57253
  }
57144
- return json({ memories, count: memories.length });
57254
+ return json({
57255
+ memories,
57256
+ count: memories.length,
57257
+ total,
57258
+ limit,
57259
+ has_more: hasMore,
57260
+ next_cursor: nextCursor
57261
+ });
57145
57262
  });
57146
57263
  addRoute("POST", "/api/memories", async (req) => {
57147
57264
  const body = await readJson(req);
@@ -57389,14 +57506,20 @@ function getMemoryReport(filter = {}, db) {
57389
57506
  top_agents: topAgents
57390
57507
  };
57391
57508
  }
57392
- function getStaleMemories(filter = {}, db) {
57509
+ function getStaleMemoriesPage(filter = {}, db) {
57393
57510
  const days = Math.min(filter.days || 30, 365);
57394
57511
  const limit = filter.limit ?? 20;
57395
57512
  const offset = filter.offset ?? 0;
57396
57513
  if (!db && isApiMode()) {
57397
57514
  const q = toQuery({ days, project_id: filter.project_id, agent_id: filter.agent_id, limit, offset });
57398
57515
  const { data } = apiJson("GET", `/memories/stale${q}`);
57399
- return data?.memories ?? [];
57516
+ const rows2 = data?.memories ?? [];
57517
+ return {
57518
+ rows: rows2,
57519
+ total: data?.total ?? rows2.length,
57520
+ has_more: data?.has_more,
57521
+ next_cursor: data?.next_cursor ?? null
57522
+ };
57400
57523
  }
57401
57524
  const d = db || getDatabase();
57402
57525
  const cutoffDate = new Date(Date.now() - days * 86400000).toISOString();
@@ -57410,13 +57533,22 @@ function getStaleMemories(filter = {}, db) {
57410
57533
  conds.push("agent_id = ?");
57411
57534
  params.push(filter.agent_id);
57412
57535
  }
57413
- let sql = `SELECT id, key, value, importance, scope, category, accessed_at, access_count, created_at FROM memories WHERE ${conds.join(" AND ")} ORDER BY COALESCE(accessed_at, created_at) ASC LIMIT ?`;
57536
+ const where = conds.join(" AND ");
57537
+ const countRow = d.query(`SELECT COUNT(*) AS c FROM memories WHERE ${where}`).get(...params);
57538
+ let sql = `SELECT id, key, value, importance, scope, category, accessed_at, access_count, created_at FROM memories WHERE ${where} ORDER BY COALESCE(accessed_at, created_at) ASC LIMIT ?`;
57414
57539
  params.push(limit);
57415
57540
  if (offset) {
57416
57541
  sql += " OFFSET ?";
57417
57542
  params.push(offset);
57418
57543
  }
57419
- return d.query(sql).all(...params);
57544
+ const rows = d.query(sql).all(...params);
57545
+ const hasMore = rows.length === limit;
57546
+ return {
57547
+ rows,
57548
+ total: countRow?.c ?? 0,
57549
+ has_more: hasMore,
57550
+ next_cursor: hasMore ? offset + rows.length : null
57551
+ };
57420
57552
  }
57421
57553
  function getMemoryHealth(filter = {}, db) {
57422
57554
  const staleDays = filter.stale_days ?? 30;
@@ -57499,23 +57631,43 @@ addRoute("GET", "/api/activity", (_req, url) => {
57499
57631
  addRoute("GET", "/api/memories/stale", (_req, url) => {
57500
57632
  const q = getSearchParams(url);
57501
57633
  const days = q["days"] ? parseInt(q["days"], 10) : undefined;
57502
- const limit = Math.min(q["limit"] ? parseInt(q["limit"], 10) : 20, 100);
57503
- const memories = getStaleMemories({
57634
+ const parsedLimit = Number(q["limit"]);
57635
+ const limit = Number.isInteger(parsedLimit) && parsedLimit > 0 ? Math.min(parsedLimit, 1000) : 20;
57636
+ const parsedOffset = Number(q["offset"]);
57637
+ const offset = Number.isInteger(parsedOffset) && parsedOffset >= 0 ? parsedOffset : 0;
57638
+ const page = getStaleMemoriesPage({
57504
57639
  days,
57505
57640
  project_id: q["project_id"],
57506
57641
  agent_id: q["agent_id"],
57507
57642
  limit,
57508
- offset: q["offset"] ? parseInt(q["offset"], 10) : undefined
57643
+ offset
57509
57644
  }, getDatabase());
57510
- return json({ memories, count: memories.length, days: Math.min(days || 30, 365) });
57645
+ return json({
57646
+ memories: page.rows,
57647
+ count: page.rows.length,
57648
+ total: page.total,
57649
+ days: Math.min(days || 30, 365),
57650
+ limit,
57651
+ has_more: page.has_more,
57652
+ next_cursor: page.next_cursor
57653
+ });
57511
57654
  });
57512
57655
  addRoute("GET", "/api/memories/history", (_req, url) => {
57513
57656
  const q = getSearchParams(url);
57514
- const memories = listMemoryHistory({
57515
- limit: Math.min(q["limit"] ? parseInt(q["limit"], 10) : 20, 200),
57516
- offset: q["offset"] ? parseInt(q["offset"], 10) : undefined
57517
- }, getDatabase());
57518
- return json({ memories, count: memories.length });
57657
+ const parsedLimit = Number(q["limit"]);
57658
+ const limit = Number.isInteger(parsedLimit) && parsedLimit > 0 ? Math.min(parsedLimit, 200) : 20;
57659
+ const parsedOffset = Number(q["offset"]);
57660
+ const offset = Number.isInteger(parsedOffset) && parsedOffset >= 0 ? parsedOffset : 0;
57661
+ const page = listMemoryHistoryPage({ limit, offset }, getDatabase());
57662
+ const total = countMemoryHistory(getDatabase());
57663
+ return json({
57664
+ memories: page.rows,
57665
+ count: page.rows.length,
57666
+ total,
57667
+ limit,
57668
+ has_more: page.has_more,
57669
+ next_cursor: page.next_cursor
57670
+ });
57519
57671
  });
57520
57672
  addRoute("GET", "/api/memories/health", (_req, url) => {
57521
57673
  const q = getSearchParams(url);
@@ -58594,6 +58746,90 @@ class MementosProjectRegistrationError extends Error {
58594
58746
  }
58595
58747
  }
58596
58748
 
58749
+ // src/project-registration/historical-receipt.ts
58750
+ var ROOT_TENANT_ID = "adfd95c7-ee8b-52cb-ae47-4ae65dae3313";
58751
+ var FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION = {
58752
+ authority: "mementos",
58753
+ authority_route: "mementos.project-registration.v1",
58754
+ package_version: "1.0.0-rc.3",
58755
+ authority_id: "mementos",
58756
+ tenant_id: "default",
58757
+ corpus_id: "default",
58758
+ operation_id: "op-cli-register-full",
58759
+ step_id: "mementos_project",
58760
+ resource_kind: "project",
58761
+ direction: "forward",
58762
+ target_selector: "wks_005285827590a93b70e5",
58763
+ target_id: "mm_project_f75606ef14e51fb577a15882ba0ab8ed333b2c29",
58764
+ idempotency_key: "prk_786cdc6babddeae1be8d5078d0f75322d1ea1010ac5d8a50",
58765
+ receipt_id: "mmpr_a647f9908a33bb64bf137f584202590f91b72a33",
58766
+ request_digest: "8eb0e3fee26fdb7edb8a444aeddaaedb79a84a5a36e742ae03616f62b19f5c22",
58767
+ precondition_digest: "0b6c22fcf75d835f9f27308b1a9d40e8902e48a97da370fd56df5acacfcd968e",
58768
+ result_revision: "2026-08-09T13:37:43.068Z",
58769
+ result_digest: "26fb0dd5c5e20909d3653ab0ddd8fa45e5142728e4e66d595e2419f7ed40b036",
58770
+ created_at: "2026-08-09T13:37:43.068Z",
58771
+ identity_digest: "1108dd972c90e4989036fb6ecec7dde10f54641a697bd53cfcd64017f589ace7",
58772
+ target_digest: "72789fcd60668eeb66ee068936d3afa96deadcb007228830c64b6de783b6dcef",
58773
+ operation_digest: "d7e37bfb2c0d28f8c4086c53224cd855d14694f32807b74c102b61a99963f3c0",
58774
+ idempotency_digest: "b56d8ec37efb818759cdd2ee3b58bc1401ac13384c8d64c1813bb5c198b1e376",
58775
+ receipt_digest: "52ce90c5de6817989f107d9d27e06156962a2b9c365e34e16a57aa37886501a2",
58776
+ response_digest: "2fa3ed508f5f192c18753b1205ced996340fdf02f735420d32db897fc239805c"
58777
+ };
58778
+ var FLEET_RESOURCES_HISTORICAL_RECEIPT = {
58779
+ receipt_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.receipt_id,
58780
+ authority: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority,
58781
+ route: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_route,
58782
+ package_version: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.package_version,
58783
+ authority_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_id,
58784
+ tenant_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.tenant_id,
58785
+ corpus_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.corpus_id,
58786
+ operation_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.operation_id,
58787
+ step_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.step_id,
58788
+ resource_kind: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.resource_kind,
58789
+ direction: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.direction,
58790
+ idempotency_key: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.idempotency_key,
58791
+ request_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.request_digest,
58792
+ precondition_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.precondition_digest,
58793
+ outcome: "accepted",
58794
+ reason: null,
58795
+ target_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_id,
58796
+ result_revision: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.result_revision,
58797
+ result_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.result_digest,
58798
+ duplicate_of_receipt_id: null,
58799
+ accepted_receipt_id: null,
58800
+ created_by_operation: true,
58801
+ created_at: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.created_at
58802
+ };
58803
+ var FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY = {
58804
+ authority_id: "mementos",
58805
+ tenant_id: ROOT_TENANT_ID,
58806
+ corpus_id: "mementos:postgresql"
58807
+ };
58808
+ var FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY = {
58809
+ source: {
58810
+ authority: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority,
58811
+ authority_route: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_route,
58812
+ package_version: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.package_version,
58813
+ authority_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_id,
58814
+ tenant_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.tenant_id,
58815
+ corpus_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.corpus_id,
58816
+ operation_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.operation_id,
58817
+ step_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.step_id,
58818
+ resource_kind: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.resource_kind,
58819
+ direction: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.direction,
58820
+ target_selector: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_selector,
58821
+ target_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_id,
58822
+ idempotency_key: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.idempotency_key,
58823
+ receipt_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.receipt_id
58824
+ },
58825
+ destination: FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY,
58826
+ lookup_only: true,
58827
+ immutable_receipt: true
58828
+ };
58829
+ function supportsFleetResourcesHistoricalReceiptLookup(capability) {
58830
+ return capability.authority_id === FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY.authority_id && capability.tenant_id === FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY.tenant_id && capability.corpus_id === FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY.corpus_id;
58831
+ }
58832
+
58597
58833
  // src/project-registration/identity.ts
58598
58834
  var MEMENTOS_PROJECT_AUTHORITY_ENV = {
58599
58835
  authorityId: "MEMENTOS_PROJECT_AUTHORITY_ID",
@@ -58635,12 +58871,13 @@ function resolveMementosProjectAuthorityIdentity(options = {}) {
58635
58871
  }
58636
58872
  function buildMementosProjectRegistrationCapability(options = {}) {
58637
58873
  const identity = resolveMementosProjectAuthorityIdentity(options);
58638
- return {
58874
+ const capability = {
58639
58875
  authority: "mementos",
58640
58876
  route: MEMENTOS_PROJECT_REGISTRATION_ROUTE,
58641
58877
  package_version: options.packageVersion ?? getMementosPackageVersion(),
58642
58878
  ...identity,
58643
58879
  supported_resources: ["project"],
58880
+ supported_historical_lookup_identities: [],
58644
58881
  conditional_create: true,
58645
58882
  immutable_receipts: true,
58646
58883
  exact_terminal_lookup: true,
@@ -58659,6 +58896,12 @@ function buildMementosProjectRegistrationCapability(options = {}) {
58659
58896
  stable_keyset_pagination: true,
58660
58897
  explicit_membership_only: true
58661
58898
  };
58899
+ if (supportsFleetResourcesHistoricalReceiptLookup(capability)) {
58900
+ capability.supported_historical_lookup_identities = [
58901
+ FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY
58902
+ ];
58903
+ }
58904
+ return capability;
58662
58905
  }
58663
58906
 
58664
58907
  // src/db/memory-project-link.ts
@@ -60822,12 +61065,21 @@ function assertInverseRequest(request, capability) {
60822
61065
  }
60823
61066
  return accepted;
60824
61067
  }
61068
+ function matchesCurrentLookupIdentity(request, capability) {
61069
+ return request.authority_route === capability.route && request.package_version === capability.package_version && request.authority_id === capability.authority_id && request.tenant_id === capability.tenant_id && request.corpus_id === capability.corpus_id;
61070
+ }
61071
+ function matchesFleetResourcesHistoricalLookup(request, capability) {
61072
+ if (!supportsFleetResourcesHistoricalReceiptLookup(capability))
61073
+ return false;
61074
+ const source = FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY.source;
61075
+ return request.authority === source.authority && request.authority_route === source.authority_route && request.package_version === source.package_version && request.authority_id === source.authority_id && request.tenant_id === source.tenant_id && request.corpus_id === source.corpus_id && request.operation_id === source.operation_id && request.step_id === source.step_id && request.resource_kind === source.resource_kind && request.direction === source.direction && request.target_selector === source.target_selector && request.target_id === source.target_id && request.idempotency_key === source.idempotency_key;
61076
+ }
60825
61077
  function assertLookup(request, capability) {
60826
61078
  assertBounds(request);
60827
61079
  if (request.max_items !== 1) {
60828
61080
  throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_INVALID_BOUNDS", "terminal receipt lookup requires max_items exactly 1");
60829
61081
  }
60830
- if (request.authority !== "mementos" || request.resource_kind !== "project" || request.authority_route !== capability.route || request.package_version !== capability.package_version || request.authority_id !== capability.authority_id || request.tenant_id !== capability.tenant_id || request.corpus_id !== capability.corpus_id) {
61082
+ if (request.authority !== "mementos" || request.resource_kind !== "project" || !matchesCurrentLookupIdentity(request, capability) && !matchesFleetResourcesHistoricalLookup(request, capability)) {
60831
61083
  throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_CAPABILITY_MISMATCH", "receipt lookup does not match this authority capability identity");
60832
61084
  }
60833
61085
  requireString(request.operation_id, "operation_id", { pattern: OPERATION_PATTERN });
@@ -60845,6 +61097,7 @@ function assertLookup(request, capability) {
60845
61097
  pattern: PROJECT_ID_PATTERN
60846
61098
  });
60847
61099
  }
61100
+ return matchesCurrentLookupIdentity(request, capability) ? "current" : "fleet_resources_historical";
60848
61101
  }
60849
61102
 
60850
61103
  class PackageOwnedMementosProjectRegistrationAuthority {
@@ -61109,11 +61362,14 @@ class PackageOwnedMementosProjectRegistrationAuthority {
61109
61362
  }
61110
61363
  async lookupReceipt(request) {
61111
61364
  const startedAt = Date.now();
61112
- assertLookup(request, this.capabilityValue);
61365
+ const lookupIdentity = assertLookup(request, this.capabilityValue);
61113
61366
  const receipt = getReceiptForLookup(this.db, request);
61114
61367
  if (!receipt || request.target_id !== undefined && receipt.target_id !== request.target_id) {
61115
61368
  throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_RECEIPT_NOT_FOUND", "exact immutable terminal receipt was not found");
61116
61369
  }
61370
+ if (lookupIdentity === "fleet_resources_historical" && (receipt.receipt_id !== FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY.source.receipt_id || canonicalMementosProjectRegistrationJson(publicReceipt(receipt)) !== canonicalMementosProjectRegistrationJson(FLEET_RESOURCES_HISTORICAL_RECEIPT))) {
61371
+ throw new MementosProjectRegistrationError("MEMENTOS_PROJECT_REGISTRATION_RECEIPT_NOT_FOUND", "exact immutable historical terminal receipt was not found");
61372
+ }
61117
61373
  return withResponseControl(publicReceipt(receipt), request, startedAt);
61118
61374
  }
61119
61375
  async compensate(request) {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=memories-page-stub-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memories-page-stub-server.d.ts","sourceRoot":"","sources":["../../src/test-support/memories-page-stub-server.ts"],"names":[],"mappings":"AA8CA,OAAO,EAAE,CAAC"}
@@ -0,0 +1,28 @@
1
+ export interface MemoriesPageStub {
2
+ server: ReturnType<typeof Bun.serve>;
3
+ baseUrl: string;
4
+ stop(): void;
5
+ }
6
+ /** Start a stub GET /v1/memories serving `rowCount` rows on capped pages. */
7
+ export declare function startMemoriesPageStub(rowCount: number): MemoriesPageStub;
8
+ /**
9
+ * A process env for API mode pointed at a loopback stub. All store selectors
10
+ * are stripped first (the ambient environment on fleet machines carries the
11
+ * production API selectors), then the stub URL + a dummy key are set.
12
+ */
13
+ export declare function apiModeTestEnv(baseUrl: string): Record<string, string>;
14
+ export interface MemoriesPageStubProcess {
15
+ port: number;
16
+ baseUrl: string;
17
+ stop(): void;
18
+ }
19
+ /**
20
+ * Start the stub as a SEPARATE process. Required whenever the caller under
21
+ * test runs in the same process that would host the stub: the CLI's cloud
22
+ * reads are SYNCHRONOUS curl children (Bun.spawnSync), which deadlock against
23
+ * an in-process server whose event loop the spawn blocks.
24
+ */
25
+ export declare function startMemoriesPageStubProcess(rowCount: number): MemoriesPageStubProcess;
26
+ /** Poll the stub until it serves a page, or throw after ~5s. */
27
+ export declare function waitForMemoriesPageStub(baseUrl: string): Promise<void>;
28
+ //# sourceMappingURL=memories-page-stub.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memories-page-stub.d.ts","sourceRoot":"","sources":["../../src/test-support/memories-page-stub.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,UAAU,CAAC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;CACd;AAED,6EAA6E;AAC7E,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAqCxE;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CActE;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,MAAM,GACf,uBAAuB,CAuBzB;AAED,gEAAgE;AAChE,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAW5E"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/mementos",
3
- "version": "0.14.84",
3
+ "version": "0.14.85",
4
4
  "description": "Universal memory system for AI agents - CLI + MCP server + library API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -40,7 +40,7 @@
40
40
  ],
41
41
  "scripts": {
42
42
  "clean": "rm -rf dist",
43
- "build": "bun run clean && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/server/index.ts --outdir dist/server --target bun --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/index.ts src/storage.ts src/pg-sync-worker.ts src/project-registration.ts --outdir dist --target bun --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/sdk/index.ts --outdir dist/sdk --target bun && tsc --emitDeclarationOnly --outDir dist",
43
+ "build": "bun run clean && bun build src/cli/index.tsx --outdir dist/cli --target bun --external ink --external react --external chalk --external @modelcontextprotocol/sdk --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/mcp/index.ts --outdir dist/mcp --target bun --external @modelcontextprotocol/sdk --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/server/index.ts --outdir dist/server --target bun --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/index.ts src/storage.ts src/pg-sync-worker.ts src/project-registration.ts --outdir dist --target bun --external @hasna/contracts --external @hasna/contracts/schemas --external @hasna/contracts/auth --external pg && bun build src/diagnostics/historical-project-registration-receipt.ts --outdir dist/diagnostics --target bun --external pg && bun build src/sdk/index.ts --outdir dist/sdk --target bun && tsc --emitDeclarationOnly --outDir dist",
44
44
  "prepare": "bun run build",
45
45
  "prepack": "bun run build && bun run scan-artifact",
46
46
  "prepublishOnly": "bun run typecheck && bun run test && bun run contracts:conformance && contracts no-cloud-scan .",
@@ -49,6 +49,7 @@
49
49
  "contracts:conformance": "contracts conformance fixtures",
50
50
  "typecheck": "tsc --noEmit",
51
51
  "test": "bun test --isolate --timeout=10000",
52
+ "diagnose:historical-project-registration-receipt": "bun run src/diagnostics/historical-project-registration-receipt.ts",
52
53
  "test:pg": "bun scripts/pg-test-gate.ts",
53
54
  "dev:cli": "bun run src/cli/index.tsx",
54
55
  "dev:mcp": "bun run src/mcp/index.ts",