@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
package/dist/cli/index.js CHANGED
@@ -1011,7 +1011,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1011
1011
  this._exitCallback = (err) => {
1012
1012
  if (err.code !== "commander.executeSubCommandAsync") {
1013
1013
  throw err;
1014
- } else {}
1014
+ }
1015
1015
  };
1016
1016
  }
1017
1017
  return this;
@@ -3171,7 +3171,16 @@ x-api-key: ${cfg.apiKey}
3171
3171
  function apiJson(method, path, body, options) {
3172
3172
  const raw = apiRequestRaw(method, path, body);
3173
3173
  if (raw.status >= 200 && raw.status < 300) {
3174
- const data = raw.body.trim() ? JSON.parse(raw.body) : undefined;
3174
+ let data;
3175
+ if (raw.body.trim()) {
3176
+ try {
3177
+ data = JSON.parse(raw.body);
3178
+ } catch (e) {
3179
+ 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));
3180
+ }
3181
+ } else {
3182
+ data = undefined;
3183
+ }
3175
3184
  return { status: raw.status, data };
3176
3185
  }
3177
3186
  if (raw.status === 404 && options?.allow404) {
@@ -5259,7 +5268,10 @@ __export(exports_memories, {
5259
5268
  touchMemory: () => touchMemory,
5260
5269
  semanticSearch: () => semanticSearch,
5261
5270
  parseMemoryRow: () => parseMemoryRow,
5271
+ listMemoryHistoryPage: () => listMemoryHistoryPage,
5262
5272
  listMemoryHistory: () => listMemoryHistory,
5273
+ listMemoriesPage: () => listMemoriesPage,
5274
+ listMemoriesBounded: () => listMemoriesBounded,
5263
5275
  listMemories: () => listMemories,
5264
5276
  listLowTrustMemories: () => listLowTrustMemories,
5265
5277
  indexMemoryEmbedding: () => indexMemoryEmbedding,
@@ -5273,6 +5285,8 @@ __export(exports_memories, {
5273
5285
  getMemoriesByKey: () => getMemoriesByKey,
5274
5286
  deleteMemory: () => deleteMemory,
5275
5287
  createMemory: () => createMemory,
5288
+ countMemoryHistory: () => countMemoryHistory,
5289
+ countMemories: () => countMemories,
5276
5290
  cleanExpiredMemories: () => cleanExpiredMemories,
5277
5291
  bulkUpsertMemories: () => bulkUpsertMemories,
5278
5292
  bulkDeleteMemories: () => bulkDeleteMemories
@@ -5639,29 +5653,7 @@ function getMemoriesByKey(key, scope, agentId, projectId, db) {
5639
5653
  const rows = d.query(sql).all(...params);
5640
5654
  return rows.map(parseMemoryRow);
5641
5655
  }
5642
- function listMemories(filter, db) {
5643
- if (!db && isApiMode()) {
5644
- const f = filter || {};
5645
- const q = toQuery({
5646
- key: f.key,
5647
- scope: f.scope,
5648
- category: f.category,
5649
- status: f.status,
5650
- tags: f.tags,
5651
- min_importance: f.min_importance,
5652
- pinned: f.pinned,
5653
- agent_id: f.agent_id,
5654
- project_id: f.project_id,
5655
- session_id: f.session_id,
5656
- namespace: f.namespace,
5657
- as_of: f.as_of,
5658
- limit: f.limit,
5659
- offset: f.offset
5660
- });
5661
- const { data } = apiJson("GET", `/memories${q}`);
5662
- return data?.memories ?? [];
5663
- }
5664
- const d = db || getDatabase();
5656
+ function buildMemoryListConditions(filter) {
5665
5657
  const conditions = [];
5666
5658
  const params = [];
5667
5659
  if (filter) {
@@ -5773,21 +5765,109 @@ function listMemories(filter, db) {
5773
5765
  } else {
5774
5766
  conditions.push("status = 'active'");
5775
5767
  }
5768
+ return { conditions, params };
5769
+ }
5770
+ function listMemoriesPage(filter, db) {
5771
+ const f = filter || {};
5772
+ if (!db && isApiMode()) {
5773
+ const q = toQuery({
5774
+ key: f.key,
5775
+ scope: f.scope,
5776
+ category: f.category,
5777
+ status: f.status,
5778
+ tags: f.tags,
5779
+ min_importance: f.min_importance,
5780
+ pinned: f.pinned,
5781
+ agent_id: f.agent_id,
5782
+ project_id: f.project_id,
5783
+ session_id: f.session_id,
5784
+ namespace: f.namespace,
5785
+ as_of: f.as_of,
5786
+ limit: f.limit,
5787
+ offset: f.offset
5788
+ });
5789
+ const { data } = apiJson("GET", `/memories${q}`);
5790
+ return {
5791
+ rows: data?.memories ?? [],
5792
+ has_more: data?.has_more,
5793
+ next_cursor: data?.next_cursor ?? null
5794
+ };
5795
+ }
5796
+ const d = db || getDatabase();
5797
+ const { conditions, params } = buildMemoryListConditions(f);
5776
5798
  let sql = "SELECT * FROM memories";
5777
5799
  if (conditions.length > 0) {
5778
5800
  sql += ` WHERE ${conditions.join(" AND ")}`;
5779
5801
  }
5780
5802
  sql += " ORDER BY importance DESC, created_at DESC";
5781
- if (filter?.limit) {
5803
+ if (f.limit) {
5782
5804
  sql += " LIMIT ?";
5783
- params.push(filter.limit);
5805
+ params.push(f.limit);
5784
5806
  }
5785
- if (filter?.offset) {
5807
+ if (f.offset) {
5786
5808
  sql += " OFFSET ?";
5787
- params.push(filter.offset);
5809
+ params.push(f.offset);
5788
5810
  }
5789
5811
  const rows = d.query(sql).all(...params);
5790
- return rows.map(parseMemoryRow);
5812
+ const parsed = rows.map(parseMemoryRow);
5813
+ const hasMore = f.limit !== undefined && parsed.length === f.limit;
5814
+ return {
5815
+ rows: parsed,
5816
+ has_more: hasMore,
5817
+ next_cursor: hasMore ? (f.offset ?? 0) + parsed.length : null
5818
+ };
5819
+ }
5820
+ function listMemories(filter, db) {
5821
+ return listMemoriesPage(filter, db).rows;
5822
+ }
5823
+ function listMemoriesBounded(filter = {}, target, db) {
5824
+ const pageSize = 1000;
5825
+ const maxPages = 1000;
5826
+ const want = target === undefined ? undefined : target + 1;
5827
+ const rows = [];
5828
+ const seenCursors = new Set;
5829
+ let cursor = filter.offset ?? 0;
5830
+ let pages = 0;
5831
+ for (;; ) {
5832
+ if (want !== undefined && rows.length >= want)
5833
+ break;
5834
+ if (++pages > maxPages) {
5835
+ throw new Error(`memories list traversal exceeded ${maxPages} pages while collecting rows \u2014 aborting (cursor cycle?)`);
5836
+ }
5837
+ const limit = Math.min(want === undefined ? pageSize : want - rows.length, pageSize);
5838
+ const page = listMemoriesPage({ ...filter, limit, offset: cursor }, db);
5839
+ rows.push(...page.rows);
5840
+ if (page.has_more === false)
5841
+ break;
5842
+ if (page.has_more === undefined && page.rows.length < limit)
5843
+ break;
5844
+ if (page.has_more === true && (page.next_cursor === null || page.next_cursor === undefined)) {
5845
+ throw new Error("memories list page claimed more results without a next cursor \u2014 aborting");
5846
+ }
5847
+ const next = page.next_cursor ?? cursor + page.rows.length;
5848
+ if (seenCursors.has(next)) {
5849
+ throw new Error("memories list traversal repeated a cursor \u2014 aborting");
5850
+ }
5851
+ seenCursors.add(next);
5852
+ cursor = next;
5853
+ }
5854
+ const hasMore = target !== undefined && rows.length > target;
5855
+ const trimmed = hasMore ? rows.slice(0, target) : rows;
5856
+ return {
5857
+ rows: trimmed,
5858
+ has_more: hasMore,
5859
+ next_cursor: hasMore ? (filter.offset ?? 0) + trimmed.length : null
5860
+ };
5861
+ }
5862
+ function countMemories(filter, db) {
5863
+ const d = db || getDatabase();
5864
+ const { conditions, params } = buildMemoryListConditions(filter);
5865
+ let sql = "SELECT COUNT(*) AS c FROM memories";
5866
+ if (conditions.length > 0) {
5867
+ sql += ` WHERE ${conditions.join(" AND ")}`;
5868
+ }
5869
+ const row = d.query(sql).get(...params);
5870
+ return row?.c ?? 0;
5791
5871
  }
5792
5872
  function getMemoryBriefing(opts, db) {
5793
5873
  const limit = opts.limit ?? 20;
@@ -5849,13 +5929,17 @@ function listLowTrustMemories(opts = {}, db) {
5849
5929
  const rows = d.prepare(`SELECT * FROM memories WHERE ${conditions.join(" AND ")} ORDER BY trust_score ASC LIMIT ? OFFSET ?`).all(...params);
5850
5930
  return rows.map(parseMemoryRow);
5851
5931
  }
5852
- function listMemoryHistory(opts = {}, db) {
5932
+ function listMemoryHistoryPage(opts = {}, db) {
5853
5933
  const limit = opts.limit ?? 20;
5854
5934
  const offset = opts.offset ?? 0;
5855
5935
  if (!db && isApiMode()) {
5856
5936
  const q = toQuery({ limit, offset });
5857
5937
  const { data } = apiJson("GET", `/memories/history${q}`);
5858
- return data?.memories ?? [];
5938
+ return {
5939
+ rows: data?.memories ?? [],
5940
+ has_more: data?.has_more,
5941
+ next_cursor: data?.next_cursor ?? null
5942
+ };
5859
5943
  }
5860
5944
  const d = db || getDatabase();
5861
5945
  const params = [limit];
@@ -5865,7 +5949,21 @@ function listMemoryHistory(opts = {}, db) {
5865
5949
  params.push(offset);
5866
5950
  }
5867
5951
  const rows = d.query(sql).all(...params);
5868
- return rows.map(parseMemoryRow);
5952
+ const parsed = rows.map(parseMemoryRow);
5953
+ const hasMore = parsed.length === limit;
5954
+ return {
5955
+ rows: parsed,
5956
+ has_more: hasMore,
5957
+ next_cursor: hasMore ? offset + parsed.length : null
5958
+ };
5959
+ }
5960
+ function listMemoryHistory(opts = {}, db) {
5961
+ return listMemoryHistoryPage(opts, db).rows;
5962
+ }
5963
+ function countMemoryHistory(db) {
5964
+ const d = db || getDatabase();
5965
+ const row = d.query("SELECT COUNT(*) AS c FROM memories WHERE status = 'active' AND accessed_at IS NOT NULL").get();
5966
+ return row?.c ?? 0;
5869
5967
  }
5870
5968
  function getMemoryChain(sequenceGroup, projectId, db) {
5871
5969
  if (!db && isApiMode()) {
@@ -6391,6 +6489,92 @@ var init_types2 = __esm(() => {
6391
6489
  ];
6392
6490
  });
6393
6491
 
6492
+ // src/project-registration/historical-receipt.ts
6493
+ function supportsFleetResourcesHistoricalReceiptLookup(capability) {
6494
+ 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;
6495
+ }
6496
+ var ROOT_TENANT_ID = "adfd95c7-ee8b-52cb-ae47-4ae65dae3313", FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION, FLEET_RESOURCES_HISTORICAL_RECEIPT, FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY, FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY;
6497
+ var init_historical_receipt = __esm(() => {
6498
+ FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION = {
6499
+ authority: "mementos",
6500
+ authority_route: "mementos.project-registration.v1",
6501
+ package_version: "1.0.0-rc.3",
6502
+ authority_id: "mementos",
6503
+ tenant_id: "default",
6504
+ corpus_id: "default",
6505
+ operation_id: "op-cli-register-full",
6506
+ step_id: "mementos_project",
6507
+ resource_kind: "project",
6508
+ direction: "forward",
6509
+ target_selector: "wks_005285827590a93b70e5",
6510
+ target_id: "mm_project_f75606ef14e51fb577a15882ba0ab8ed333b2c29",
6511
+ idempotency_key: "prk_786cdc6babddeae1be8d5078d0f75322d1ea1010ac5d8a50",
6512
+ receipt_id: "mmpr_a647f9908a33bb64bf137f584202590f91b72a33",
6513
+ request_digest: "8eb0e3fee26fdb7edb8a444aeddaaedb79a84a5a36e742ae03616f62b19f5c22",
6514
+ precondition_digest: "0b6c22fcf75d835f9f27308b1a9d40e8902e48a97da370fd56df5acacfcd968e",
6515
+ result_revision: "2026-08-09T13:37:43.068Z",
6516
+ result_digest: "26fb0dd5c5e20909d3653ab0ddd8fa45e5142728e4e66d595e2419f7ed40b036",
6517
+ created_at: "2026-08-09T13:37:43.068Z",
6518
+ identity_digest: "1108dd972c90e4989036fb6ecec7dde10f54641a697bd53cfcd64017f589ace7",
6519
+ target_digest: "72789fcd60668eeb66ee068936d3afa96deadcb007228830c64b6de783b6dcef",
6520
+ operation_digest: "d7e37bfb2c0d28f8c4086c53224cd855d14694f32807b74c102b61a99963f3c0",
6521
+ idempotency_digest: "b56d8ec37efb818759cdd2ee3b58bc1401ac13384c8d64c1813bb5c198b1e376",
6522
+ receipt_digest: "52ce90c5de6817989f107d9d27e06156962a2b9c365e34e16a57aa37886501a2",
6523
+ response_digest: "2fa3ed508f5f192c18753b1205ced996340fdf02f735420d32db897fc239805c"
6524
+ };
6525
+ FLEET_RESOURCES_HISTORICAL_RECEIPT = {
6526
+ receipt_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.receipt_id,
6527
+ authority: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority,
6528
+ route: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_route,
6529
+ package_version: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.package_version,
6530
+ authority_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_id,
6531
+ tenant_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.tenant_id,
6532
+ corpus_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.corpus_id,
6533
+ operation_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.operation_id,
6534
+ step_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.step_id,
6535
+ resource_kind: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.resource_kind,
6536
+ direction: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.direction,
6537
+ idempotency_key: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.idempotency_key,
6538
+ request_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.request_digest,
6539
+ precondition_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.precondition_digest,
6540
+ outcome: "accepted",
6541
+ reason: null,
6542
+ target_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_id,
6543
+ result_revision: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.result_revision,
6544
+ result_digest: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.result_digest,
6545
+ duplicate_of_receipt_id: null,
6546
+ accepted_receipt_id: null,
6547
+ created_by_operation: true,
6548
+ created_at: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.created_at
6549
+ };
6550
+ FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY = {
6551
+ authority_id: "mementos",
6552
+ tenant_id: ROOT_TENANT_ID,
6553
+ corpus_id: "mementos:postgresql"
6554
+ };
6555
+ FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY = {
6556
+ source: {
6557
+ authority: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority,
6558
+ authority_route: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_route,
6559
+ package_version: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.package_version,
6560
+ authority_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.authority_id,
6561
+ tenant_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.tenant_id,
6562
+ corpus_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.corpus_id,
6563
+ operation_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.operation_id,
6564
+ step_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.step_id,
6565
+ resource_kind: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.resource_kind,
6566
+ direction: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.direction,
6567
+ target_selector: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_selector,
6568
+ target_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.target_id,
6569
+ idempotency_key: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.idempotency_key,
6570
+ receipt_id: FLEET_RESOURCES_HISTORICAL_PROJECT_REGISTRATION.receipt_id
6571
+ },
6572
+ destination: FLEET_RESOURCES_CURRENT_PROJECT_REGISTRATION_IDENTITY,
6573
+ lookup_only: true,
6574
+ immutable_receipt: true
6575
+ };
6576
+ });
6577
+
6394
6578
  // src/project-registration/identity.ts
6395
6579
  function configuredValue(override, envKey) {
6396
6580
  return override?.trim() || process.env[envKey]?.trim() || null;
@@ -6417,12 +6601,13 @@ function resolveMementosProjectAuthorityIdentity(options = {}) {
6417
6601
  }
6418
6602
  function buildMementosProjectRegistrationCapability(options = {}) {
6419
6603
  const identity = resolveMementosProjectAuthorityIdentity(options);
6420
- return {
6604
+ const capability = {
6421
6605
  authority: "mementos",
6422
6606
  route: MEMENTOS_PROJECT_REGISTRATION_ROUTE,
6423
6607
  package_version: options.packageVersion ?? getMementosPackageVersion(),
6424
6608
  ...identity,
6425
6609
  supported_resources: ["project"],
6610
+ supported_historical_lookup_identities: [],
6426
6611
  conditional_create: true,
6427
6612
  immutable_receipts: true,
6428
6613
  exact_terminal_lookup: true,
@@ -6441,11 +6626,18 @@ function buildMementosProjectRegistrationCapability(options = {}) {
6441
6626
  stable_keyset_pagination: true,
6442
6627
  explicit_membership_only: true
6443
6628
  };
6629
+ if (supportsFleetResourcesHistoricalReceiptLookup(capability)) {
6630
+ capability.supported_historical_lookup_identities = [
6631
+ FLEET_RESOURCES_HISTORICAL_LOOKUP_IDENTITY
6632
+ ];
6633
+ }
6634
+ return capability;
6444
6635
  }
6445
6636
  var MEMENTOS_PROJECT_AUTHORITY_ENV, MementosProjectAuthorityIdentityError;
6446
6637
  var init_identity = __esm(() => {
6447
6638
  init_package_version();
6448
6639
  init_types2();
6640
+ init_historical_receipt();
6449
6641
  MEMENTOS_PROJECT_AUTHORITY_ENV = {
6450
6642
  authorityId: "MEMENTOS_PROJECT_AUTHORITY_ID",
6451
6643
  tenantId: "MEMENTOS_PROJECT_TENANT_ID",
@@ -7272,6 +7464,7 @@ __export(exports_helpers, {
7272
7464
  colorImportance: () => colorImportance,
7273
7465
  colorEntityType: () => colorEntityType,
7274
7466
  colorCategory: () => colorCategory,
7467
+ collectPagedRows: () => collectPagedRows,
7275
7468
  VALID_SCOPES: () => VALID_SCOPES,
7276
7469
  VALID_CATEGORIES: () => VALID_CATEGORIES,
7277
7470
  DEFAULT_SNIPPET_LENGTH: () => DEFAULT_SNIPPET_LENGTH,
@@ -7358,6 +7551,39 @@ function truncateText(value, max = DEFAULT_SNIPPET_LENGTH) {
7358
7551
  return normalized.slice(0, max);
7359
7552
  return `${normalized.slice(0, max - 3)}...`;
7360
7553
  }
7554
+ function collectPagedRows(fetchPage, target, offset, opts = {}) {
7555
+ const pageSize = opts.pageSize ?? 1000;
7556
+ const maxPages = opts.maxPages ?? 1000;
7557
+ const want = target === undefined ? undefined : target + 1;
7558
+ const rows = [];
7559
+ const seenCursors = new Set;
7560
+ let cursor = offset;
7561
+ let pages = 0;
7562
+ for (;; ) {
7563
+ if (want !== undefined && rows.length >= want)
7564
+ break;
7565
+ if (++pages > maxPages) {
7566
+ throw new Error(`pagination exceeded ${maxPages} pages while collecting rows \u2014 aborting (cursor cycle?)`);
7567
+ }
7568
+ const limit = Math.min(want === undefined ? pageSize : want - rows.length, pageSize);
7569
+ const page = fetchPage(cursor, limit);
7570
+ rows.push(...page.rows);
7571
+ if (page.has_more === false)
7572
+ break;
7573
+ if (page.has_more === undefined && page.rows.length < limit)
7574
+ break;
7575
+ if (page.has_more === true && (page.next_cursor === null || page.next_cursor === undefined)) {
7576
+ throw new Error("pagination claimed more results without a next cursor \u2014 aborting");
7577
+ }
7578
+ const next = page.next_cursor ?? cursor + page.rows.length;
7579
+ if (seenCursors.has(next)) {
7580
+ throw new Error("pagination repeated a cursor \u2014 aborting");
7581
+ }
7582
+ seenCursors.add(next);
7583
+ cursor = next;
7584
+ }
7585
+ return { rows, hasMore: target !== undefined && rows.length > target };
7586
+ }
7361
7587
  function printPageHint(opts) {
7362
7588
  const hints = [];
7363
7589
  const offset = opts.offset ?? 0;
@@ -27040,7 +27266,7 @@ class JSONSchemaGenerator {
27040
27266
  if (val === undefined) {
27041
27267
  if (this.unrepresentable === "throw") {
27042
27268
  throw new Error("Literal `undefined` cannot be represented in JSON Schema");
27043
- } else {}
27269
+ }
27044
27270
  } else if (typeof val === "bigint") {
27045
27271
  if (this.unrepresentable === "throw") {
27046
27272
  throw new Error("BigInt literals cannot be represented in JSON Schema");
@@ -48690,7 +48916,7 @@ var require_tracestate_impl = __commonJS((exports) => {
48690
48916
  const value = listMember.slice(i + 1, part.length);
48691
48917
  if ((0, tracestate_validators_1.validateKey)(key) && (0, tracestate_validators_1.validateValue)(value)) {
48692
48918
  agg.set(key, value);
48693
- } else {}
48919
+ }
48694
48920
  }
48695
48921
  return agg;
48696
48922
  }, new Map);
@@ -63487,6 +63713,7 @@ import { createHash as createHash3 } from "crypto";
63487
63713
  init_projects();
63488
63714
  init_types2();
63489
63715
  init_identity();
63716
+ init_historical_receipt();
63490
63717
  function canonicalMementosProjectRegistrationJson(value) {
63491
63718
  return JSON.stringify(canonicalize2(value));
63492
63719
  }
@@ -64878,15 +65105,17 @@ function registerListCommand(program2) {
64878
65105
  const fmt = getOutputFormat(program2, opts.format);
64879
65106
  const isStructured = fmt === "json" || fmt === "csv" || fmt === "yaml";
64880
65107
  const requestedLimit = opts.limit;
64881
- const limit = positiveIntOrDefault(requestedLimit, isStructured ? 50 : DEFAULT_COMPACT_LIMIT);
64882
- const offset = cursorOrOffset(opts.cursor, opts.offset);
65108
+ const limit = requestedLimit === undefined ? isStructured ? undefined : DEFAULT_COMPACT_LIMIT : positiveIntOrDefault(requestedLimit, isStructured ? 50 : DEFAULT_COMPACT_LIMIT);
65109
+ const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
64883
65110
  const agentId = resolveAgentFilter(opts.agent || globalOpts.agent);
64884
65111
  const projectPath = opts.project || globalOpts.project;
64885
65112
  let projectId;
64886
65113
  if (projectPath) {
64887
65114
  const project = getProject(resolve7(projectPath));
64888
- if (project)
64889
- projectId = project.id;
65115
+ if (!project) {
65116
+ throw new Error(`Project not found: ${projectPath}`);
65117
+ }
65118
+ projectId = project.id;
64890
65119
  }
64891
65120
  const filter = {
64892
65121
  scope: opts.scope,
@@ -64896,16 +65125,24 @@ function registerListCommand(program2) {
64896
65125
  pinned: opts.pinned ? true : undefined,
64897
65126
  agent_id: agentId,
64898
65127
  project_id: projectId,
64899
- limit: isStructured ? limit : limit + 1,
64900
- offset,
64901
65128
  status: opts.status,
64902
65129
  session_id: opts.session || globalOpts.session
64903
65130
  };
64904
- const fetched = listMemories(filter);
64905
- const hasMore = !isStructured && fetched.length > limit;
64906
- const memories = hasMore ? fetched.slice(0, limit) : fetched;
65131
+ const { rows: collected, hasMore } = collectPagedRows((cursor, pageLimit) => {
65132
+ const page = listMemoriesPage({
65133
+ ...filter,
65134
+ limit: pageLimit,
65135
+ offset: cursor
65136
+ });
65137
+ return {
65138
+ rows: page.rows,
65139
+ has_more: page.has_more,
65140
+ next_cursor: page.next_cursor
65141
+ };
65142
+ }, limit, offset);
65143
+ const memories = hasMore && limit !== undefined ? collected.slice(0, limit) : collected;
64907
65144
  if (fmt === "json") {
64908
- outputJson(fetched);
65145
+ outputJson(memories);
64909
65146
  return;
64910
65147
  }
64911
65148
  if (fmt === "csv") {
@@ -64933,7 +65170,7 @@ function registerListCommand(program2) {
64933
65170
  }
64934
65171
  printPageHint({
64935
65172
  shown: memories.length,
64936
- limit,
65173
+ limit: limit ?? memories.length,
64937
65174
  offset,
64938
65175
  hasMore,
64939
65176
  command: "mementos list",
@@ -65068,14 +65305,20 @@ function getMemoryReport(filter = {}, db) {
65068
65305
  top_agents: topAgents
65069
65306
  };
65070
65307
  }
65071
- function getStaleMemories(filter = {}, db) {
65308
+ function getStaleMemoriesPage(filter = {}, db) {
65072
65309
  const days = Math.min(filter.days || 30, 365);
65073
65310
  const limit = filter.limit ?? 20;
65074
65311
  const offset = filter.offset ?? 0;
65075
65312
  if (!db && isApiMode()) {
65076
65313
  const q = toQuery({ days, project_id: filter.project_id, agent_id: filter.agent_id, limit, offset });
65077
65314
  const { data } = apiJson("GET", `/memories/stale${q}`);
65078
- return data?.memories ?? [];
65315
+ const rows2 = data?.memories ?? [];
65316
+ return {
65317
+ rows: rows2,
65318
+ total: data?.total ?? rows2.length,
65319
+ has_more: data?.has_more,
65320
+ next_cursor: data?.next_cursor ?? null
65321
+ };
65079
65322
  }
65080
65323
  const d = db || getDatabase();
65081
65324
  const cutoffDate = new Date(Date.now() - days * 86400000).toISOString();
@@ -65089,13 +65332,22 @@ function getStaleMemories(filter = {}, db) {
65089
65332
  conds.push("agent_id = ?");
65090
65333
  params.push(filter.agent_id);
65091
65334
  }
65092
- 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 ?`;
65335
+ const where = conds.join(" AND ");
65336
+ const countRow = d.query(`SELECT COUNT(*) AS c FROM memories WHERE ${where}`).get(...params);
65337
+ 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 ?`;
65093
65338
  params.push(limit);
65094
65339
  if (offset) {
65095
65340
  sql += " OFFSET ?";
65096
65341
  params.push(offset);
65097
65342
  }
65098
- return d.query(sql).all(...params);
65343
+ const rows = d.query(sql).all(...params);
65344
+ const hasMore = rows.length === limit;
65345
+ return {
65346
+ rows,
65347
+ total: countRow?.c ?? 0,
65348
+ has_more: hasMore,
65349
+ next_cursor: hasMore ? offset + rows.length : null
65350
+ };
65099
65351
  }
65100
65352
 
65101
65353
  // src/cli/commands/info-stats.ts
@@ -65255,7 +65507,7 @@ function registerStaleCommand(program2) {
65255
65507
  const fmt = getOutputFormat(program2, opts.format);
65256
65508
  const isJson = fmt === "json";
65257
65509
  const limit = positiveIntOrDefault(opts.limit, isJson ? 20 : DEFAULT_COMPACT_LIMIT);
65258
- const offset = cursorOrOffset(opts.cursor, opts.offset);
65510
+ const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
65259
65511
  const projectPath = opts.project || globalOpts.project;
65260
65512
  let projectId;
65261
65513
  if (projectPath) {
@@ -65264,17 +65516,36 @@ function registerStaleCommand(program2) {
65264
65516
  projectId = project.id;
65265
65517
  }
65266
65518
  const agentId = resolveAgentFilter(opts.agent || globalOpts.agent);
65267
- const rows = getStaleMemories({
65268
- days,
65269
- project_id: projectId,
65270
- agent_id: agentId,
65271
- limit: isJson ? limit : limit + 1,
65272
- offset
65273
- });
65274
- const hasMore = !isJson && rows.length > limit;
65275
- const displayRows = hasMore ? rows.slice(0, limit) : rows;
65519
+ let staleTotal = 0;
65520
+ let firstPage = true;
65521
+ const { rows: collected, hasMore } = collectPagedRows((cursor, pageLimit) => {
65522
+ const page = getStaleMemoriesPage({
65523
+ days,
65524
+ project_id: projectId,
65525
+ agent_id: agentId,
65526
+ limit: pageLimit,
65527
+ offset: cursor
65528
+ });
65529
+ if (firstPage) {
65530
+ staleTotal = page.total;
65531
+ firstPage = false;
65532
+ }
65533
+ return {
65534
+ rows: page.rows,
65535
+ has_more: page.has_more,
65536
+ next_cursor: page.next_cursor
65537
+ };
65538
+ }, limit, offset);
65539
+ const displayRows = hasMore ? collected.slice(0, limit) : collected;
65276
65540
  if (fmt === "json") {
65277
- outputJson({ stale_count: rows.length, threshold_days: days, memories: rows });
65541
+ outputJson({
65542
+ stale_count: staleTotal,
65543
+ returned: displayRows.length,
65544
+ threshold_days: days,
65545
+ has_more: hasMore,
65546
+ next_cursor: hasMore ? offset + displayRows.length : null,
65547
+ memories: displayRows
65548
+ });
65278
65549
  return;
65279
65550
  }
65280
65551
  if (displayRows.length === 0) {
@@ -65313,13 +65584,20 @@ function registerHistoryCommand(program2) {
65313
65584
  try {
65314
65585
  const globalOpts = program2.opts();
65315
65586
  const isJson = Boolean(globalOpts.json);
65316
- const limit = positiveIntOrDefault(opts.limit, isJson ? 20 : DEFAULT_SEARCH_LIMIT);
65317
- const offset = cursorOrOffset(opts.cursor, opts.offset);
65318
- const fetched = listMemoryHistory({ limit: isJson ? limit : limit + 1, offset });
65319
- const hasMore = !isJson && fetched.length > limit;
65320
- const memories = hasMore ? fetched.slice(0, limit) : fetched;
65587
+ const requestedLimit = opts.limit;
65588
+ const limit = requestedLimit === undefined ? isJson ? undefined : DEFAULT_SEARCH_LIMIT : positiveIntOrDefault(requestedLimit, isJson ? 20 : DEFAULT_SEARCH_LIMIT);
65589
+ const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
65590
+ const { rows: collected, hasMore } = collectPagedRows((cursor, pageLimit) => {
65591
+ const page = listMemoryHistoryPage({ limit: pageLimit, offset: cursor });
65592
+ return {
65593
+ rows: page.rows,
65594
+ has_more: page.has_more,
65595
+ next_cursor: page.next_cursor
65596
+ };
65597
+ }, limit, offset);
65598
+ const memories = hasMore && limit !== undefined ? collected.slice(0, limit) : collected;
65321
65599
  if (globalOpts.json) {
65322
- outputJson(fetched);
65600
+ outputJson(memories);
65323
65601
  return;
65324
65602
  }
65325
65603
  if (memories.length === 0) {
@@ -65337,7 +65615,7 @@ function registerHistoryCommand(program2) {
65337
65615
  }
65338
65616
  printPageHint({
65339
65617
  shown: memories.length,
65340
- limit,
65618
+ limit: limit ?? memories.length,
65341
65619
  offset,
65342
65620
  hasMore,
65343
65621
  command: "mementos history",
@@ -65529,10 +65807,9 @@ function registerExportCommand(program2) {
65529
65807
  scope: opts.scope,
65530
65808
  category: opts.category,
65531
65809
  agent_id: agentId,
65532
- project_id: projectId,
65533
- limit: 1e4
65810
+ project_id: projectId
65534
65811
  };
65535
- const memories = listMemories(filter);
65812
+ const memories = listMemoriesBounded(filter, 1e4).rows;
65536
65813
  outputJson(memories);
65537
65814
  } catch (e) {
65538
65815
  handleError(e);
@@ -71008,7 +71285,7 @@ ${matched.map((m) => `- ${m.key}: ${m.value.slice(0, 120)}${m.value.length > 120
71008
71285
  };
71009
71286
  }
71010
71287
  var gatherTrainingData = async (options = {}) => {
71011
- const allMemories = listMemories({ status: "active" });
71288
+ const allMemories = listMemoriesBounded({ status: "active" }, undefined).rows;
71012
71289
  const filtered = options.since ? allMemories.filter((m) => new Date(m.created_at) >= options.since) : allMemories;
71013
71290
  const sorted = filtered.slice().sort((a, b) => b.importance - a.importance);
71014
71291
  const fetchSet = options.limit ? sorted.slice(0, options.limit * 3) : sorted;
@@ -71,6 +71,19 @@ export interface StaleMemory {
71
71
  access_count: number;
72
72
  created_at?: string;
73
73
  }
74
+ export interface StalePage {
75
+ rows: StaleMemory[];
76
+ /** True total of stale memories matching the filter — never the page length. */
77
+ total: number;
78
+ has_more: boolean | undefined;
79
+ next_cursor: number | null;
80
+ }
81
+ /**
82
+ * One bounded page of the stale surface, with the TRUE total and an explicit
83
+ * pagination signal. The server caps single responses and answers with
84
+ * `total` / `has_more` / `next_cursor`, so a page never silently truncates.
85
+ */
86
+ export declare function getStaleMemoriesPage(filter?: StaleFilter, db?: Database): StalePage;
74
87
  export declare function getStaleMemories(filter?: StaleFilter, db?: Database): StaleMemory[];
75
88
  export interface HealthFilter {
76
89
  stale_days?: number;