@hasna/mementos 0.16.0 → 0.17.0

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/README.md +21 -14
  2. package/dist/cli/commands/agent.d.ts.map +1 -1
  3. package/dist/cli/commands/consolidation.d.ts.map +1 -1
  4. package/dist/cli/commands/io-export.d.ts.map +1 -1
  5. package/dist/cli/commands/io-restore.d.ts.map +1 -1
  6. package/dist/cli/commands/memory-cmd-crud.d.ts.map +1 -1
  7. package/dist/cli/commands/memory-cmd-list.d.ts +1 -1
  8. package/dist/cli/commands/memory-cmd-list.d.ts.map +1 -1
  9. package/dist/cli/commands/memory-cmd-recall.d.ts.map +1 -1
  10. package/dist/cli/commands/memory-cmd-remove.d.ts.map +1 -1
  11. package/dist/cli/commands/memory-cmd-search.d.ts.map +1 -1
  12. package/dist/cli/commands/memory-cmd-view.d.ts.map +1 -1
  13. package/dist/cli/commands/memory-cmd-when-to-use.d.ts.map +1 -1
  14. package/dist/cli/commands/project.d.ts.map +1 -1
  15. package/dist/cli/commands/system-status.d.ts.map +1 -1
  16. package/dist/cli/helpers.d.ts +3 -1
  17. package/dist/cli/helpers.d.ts.map +1 -1
  18. package/dist/cli/index.js +415 -109
  19. package/dist/cli/structured-json.d.ts +54 -0
  20. package/dist/cli/structured-json.d.ts.map +1 -0
  21. package/dist/lib/conversations-transport.d.ts +21 -0
  22. package/dist/lib/conversations-transport.d.ts.map +1 -0
  23. package/dist/lib/export-v1.d.ts +2 -0
  24. package/dist/lib/export-v1.d.ts.map +1 -1
  25. package/dist/mcp/index.js +275 -70
  26. package/dist/mcp/memory-broadcast.d.ts +6 -8
  27. package/dist/mcp/memory-broadcast.d.ts.map +1 -1
  28. package/dist/mcp/tools/bounded-output.d.ts +27 -0
  29. package/dist/mcp/tools/bounded-output.d.ts.map +1 -0
  30. package/dist/mcp/tools/lock-tools.d.ts.map +1 -1
  31. package/dist/mcp/tools/memory-inject.d.ts.map +1 -1
  32. package/dist/mcp/tools/memory-io.d.ts.map +1 -1
  33. package/dist/mcp/tools/utility-tools.d.ts.map +1 -1
  34. package/dist/sdk/index.d.ts +1 -1
  35. package/dist/sdk/index.d.ts.map +1 -1
  36. package/dist/sdk/index.js +6 -3
  37. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -8218,6 +8218,7 @@ __export(exports_helpers, {
8218
8218
  positiveIntOrDefault: () => positiveIntOrDefault,
8219
8219
  parseConfigValue: () => parseConfigValue,
8220
8220
  outputYaml: () => outputYaml,
8221
+ outputJsonAndExit: () => outputJsonAndExit,
8221
8222
  outputJson: () => outputJson,
8222
8223
  makeHandleError: () => makeHandleError,
8223
8224
  importanceColor: () => importanceColor,
@@ -8298,7 +8299,30 @@ function resolveEntityArg(nameOrId, type) {
8298
8299
  process.exit(1);
8299
8300
  }
8300
8301
  function outputJson(data) {
8301
- console.log(JSON.stringify(data, null, 2));
8302
+ process.stdout.write(`${JSON.stringify(data, null, 2)}
8303
+ `);
8304
+ }
8305
+ function outputJsonAndExit(data, code) {
8306
+ const payload = `${JSON.stringify(data, null, 2)}
8307
+ `;
8308
+ return new Promise((resolve4) => {
8309
+ let settled = false;
8310
+ const finish = (exitCode) => {
8311
+ if (settled)
8312
+ return;
8313
+ settled = true;
8314
+ process.stdout.off("error", onError);
8315
+ process.exit(exitCode);
8316
+ resolve4(undefined);
8317
+ };
8318
+ const onError = () => finish(1);
8319
+ process.stdout.once("error", onError);
8320
+ try {
8321
+ process.stdout.write(payload, () => finish(code));
8322
+ } catch {
8323
+ finish(1);
8324
+ }
8325
+ });
8302
8326
  }
8303
8327
  function positiveIntOrDefault(value, fallback) {
8304
8328
  const parsed = typeof value === "number" ? value : Number(value);
@@ -8493,9 +8517,9 @@ function makeHandleError(program2) {
8493
8517
  return function handleError(e) {
8494
8518
  const globalOpts = program2.opts();
8495
8519
  if (globalOpts.json || globalOpts.format === "json") {
8496
- outputJson({
8520
+ return outputJsonAndExit({
8497
8521
  error: e instanceof Error ? e.message : String(e)
8498
- });
8522
+ }, 1);
8499
8523
  } else {
8500
8524
  console.error(chalk.red(e instanceof Error ? e.message : String(e)));
8501
8525
  }
@@ -67748,18 +67772,20 @@ function registerCrudCommands(program2) {
67748
67772
  handleError(e);
67749
67773
  }
67750
67774
  });
67751
- program2.command("update <id>").description("Update a memory by ID").option("--value <text>", "New value").option("--importance <n>", "New importance 1-10", parseInt).option("--tags <tags>", "New comma-separated tags").option("--summary <text>", "New summary").option("--pin", "Pin the memory").option("--unpin", "Unpin the memory").option("-c, --category <cat>", "New category").option("--scope <scope>", "New scope").option("--status <status>", "New status: active, archived, expired").action((id, opts) => {
67775
+ program2.command("update <id>").description("Update a memory by ID").option("--value <text>", "New value").option("--importance <n>", "New importance 1-10", parseInt).option("--tags <tags>", "New comma-separated tags").option("--summary <text>", "New summary").option("--pin", "Pin the memory").option("--unpin", "Unpin the memory").option("-c, --category <cat>", "New category").option("--scope <scope>", "New scope").option("--status <status>", "New status: active, archived, expired").action(async (id, opts) => {
67752
67776
  try {
67753
67777
  const globalOpts = program2.opts();
67754
67778
  const resolvedId = resolveMemoryId(id);
67755
67779
  const existing = getMemory(resolvedId);
67756
67780
  if (!existing) {
67757
67781
  if (globalOpts.json) {
67758
- outputJson({ error: `Memory not found: ${id}` });
67782
+ await outputJsonAndExit({ error: `Memory not found: ${id}` }, 1);
67759
67783
  } else {
67760
67784
  console.error(chalk2.red(`Memory not found: ${id}`));
67761
67785
  }
67762
- process.exit(1);
67786
+ if (!globalOpts.json)
67787
+ process.exit(1);
67788
+ return;
67763
67789
  }
67764
67790
  const updateInput = {
67765
67791
  version: existing.version
@@ -67811,7 +67837,7 @@ function registerCrudCommands(program2) {
67811
67837
  handleError(e);
67812
67838
  }
67813
67839
  });
67814
- program2.command("forget <keyOrId>").description("Delete a memory by key or ID").option("--scope <scope>", "Filter by scope (global, shared, private)").option("--agent <agent>", "Filter by agent ID").option("--project <project>", "Filter by project ID").option("--all", "Delete ALL matching memories (no disambiguation needed)").action((keyOrId, opts) => {
67840
+ program2.command("forget <keyOrId>").description("Delete a memory by key or ID").option("--scope <scope>", "Filter by scope (global, shared, private)").option("--agent <agent>", "Filter by agent ID").option("--project <project>", "Filter by project ID").option("--all", "Delete ALL matching memories (no disambiguation needed)").action(async (keyOrId, opts) => {
67815
67841
  try {
67816
67842
  const globalOpts = program2.opts();
67817
67843
  const idMatch = isApiMode() ? null : resolvePartialId(getDatabase(), "memories", keyOrId);
@@ -67835,11 +67861,13 @@ function registerCrudCommands(program2) {
67835
67861
  return;
67836
67862
  }
67837
67863
  if (globalOpts.json) {
67838
- outputJson({ error: `No memory found: ${keyOrId}` });
67864
+ await outputJsonAndExit({ error: `No memory found: ${keyOrId}` }, 1);
67839
67865
  } else {
67840
67866
  console.error(chalk2.red(`No memory found: ${keyOrId}`));
67841
67867
  }
67842
- process.exit(1);
67868
+ if (!globalOpts.json)
67869
+ process.exit(1);
67870
+ return;
67843
67871
  }
67844
67872
  if (matches.length === 1) {
67845
67873
  deleteMemory(matches[0].id);
@@ -67862,10 +67890,10 @@ function registerCrudCommands(program2) {
67862
67890
  return;
67863
67891
  }
67864
67892
  if (globalOpts.json) {
67865
- outputJson({
67893
+ await outputJsonAndExit({
67866
67894
  error: `Ambiguous key "${keyOrId}" \u2014 ${matches.length} memories found. Use --all to delete all, or specify an ID.`,
67867
67895
  matches: matches.map((m) => ({ id: m.id, key: redactCredentialKey(m.key), scope: m.scope, category: m.category, agent_id: m.agent_id }))
67868
- });
67896
+ }, 1);
67869
67897
  } else {
67870
67898
  console.log(chalk2.yellow(`Ambiguous key "${keyOrId}" \u2014 ${matches.length} memories found:`));
67871
67899
  for (const m of matches) {
@@ -67874,7 +67902,8 @@ function registerCrudCommands(program2) {
67874
67902
  console.log(chalk2.dim(`
67875
67903
  Use --all to delete all, or specify an ID.`));
67876
67904
  }
67877
- process.exit(1);
67905
+ if (!globalOpts.json)
67906
+ process.exit(1);
67878
67907
  } catch (e) {
67879
67908
  handleError(e);
67880
67909
  }
@@ -67888,18 +67917,20 @@ init_redact();
67888
67917
  import chalk3 from "chalk";
67889
67918
  function registerViewCommands(program2) {
67890
67919
  const handleError = makeHandleError(program2);
67891
- program2.command("show <id>").description("Show full detail of a memory by ID (supports partial IDs)").action((id) => {
67920
+ program2.command("show <id>").description("Show full detail of a memory by ID (supports partial IDs)").action(async (id) => {
67892
67921
  try {
67893
67922
  const globalOpts = program2.opts();
67894
67923
  const resolvedId = resolveMemoryId(id);
67895
67924
  const memory = getMemory(resolvedId);
67896
67925
  if (!memory) {
67897
67926
  if (globalOpts.json) {
67898
- outputJson({ error: `Memory not found: ${id}` });
67927
+ await outputJsonAndExit({ error: `Memory not found: ${id}` }, 1);
67899
67928
  } else {
67900
67929
  console.error(chalk3.red(`Memory not found: ${id}`));
67901
67930
  }
67902
- process.exit(1);
67931
+ if (!globalOpts.json)
67932
+ process.exit(1);
67933
+ return;
67903
67934
  }
67904
67935
  touchMemory(memory.id);
67905
67936
  const safe = redactMemoryForOutput(memory);
@@ -67912,17 +67943,19 @@ function registerViewCommands(program2) {
67912
67943
  handleError(e);
67913
67944
  }
67914
67945
  });
67915
- program2.command("pin <keyOrId>").description("Pin a memory by key or partial ID").option("--scope <scope>", "Scope filter for key lookup").option("--agent <name>", "Agent filter for key lookup").option("--project <path>", "Project filter for key lookup").action((keyOrId, opts) => {
67946
+ program2.command("pin <keyOrId>").description("Pin a memory by key or partial ID").option("--scope <scope>", "Scope filter for key lookup").option("--agent <name>", "Agent filter for key lookup").option("--project <path>", "Project filter for key lookup").action(async (keyOrId, opts) => {
67916
67947
  try {
67917
67948
  const globalOpts = program2.opts();
67918
67949
  const memory = resolveKeyOrId(keyOrId, opts, globalOpts);
67919
67950
  if (!memory) {
67920
67951
  if (globalOpts.json) {
67921
- outputJson({ error: `No memory found: ${keyOrId}` });
67952
+ await outputJsonAndExit({ error: `No memory found: ${keyOrId}` }, 1);
67922
67953
  } else {
67923
67954
  console.error(chalk3.red(`No memory found: ${keyOrId}`));
67924
67955
  }
67925
- process.exit(1);
67956
+ if (!globalOpts.json)
67957
+ process.exit(1);
67958
+ return;
67926
67959
  }
67927
67960
  const updated = updateMemory(memory.id, {
67928
67961
  version: memory.version,
@@ -67937,17 +67970,19 @@ function registerViewCommands(program2) {
67937
67970
  handleError(e);
67938
67971
  }
67939
67972
  });
67940
- program2.command("unpin <keyOrId>").description("Unpin a memory by key or partial ID").option("--scope <scope>", "Scope filter for key lookup").option("--agent <name>", "Agent filter for key lookup").option("--project <path>", "Project filter for key lookup").action((keyOrId, opts) => {
67973
+ program2.command("unpin <keyOrId>").description("Unpin a memory by key or partial ID").option("--scope <scope>", "Scope filter for key lookup").option("--agent <name>", "Agent filter for key lookup").option("--project <path>", "Project filter for key lookup").action(async (keyOrId, opts) => {
67941
67974
  try {
67942
67975
  const globalOpts = program2.opts();
67943
67976
  const memory = resolveKeyOrId(keyOrId, opts, globalOpts);
67944
67977
  if (!memory) {
67945
67978
  if (globalOpts.json) {
67946
- outputJson({ error: `No memory found: ${keyOrId}` });
67979
+ await outputJsonAndExit({ error: `No memory found: ${keyOrId}` }, 1);
67947
67980
  } else {
67948
67981
  console.error(chalk3.red(`No memory found: ${keyOrId}`));
67949
67982
  }
67950
- process.exit(1);
67983
+ if (!globalOpts.json)
67984
+ process.exit(1);
67985
+ return;
67951
67986
  }
67952
67987
  const updated = updateMemory(memory.id, {
67953
67988
  version: memory.version,
@@ -68140,14 +68175,167 @@ init_helpers();
68140
68175
  init_redact();
68141
68176
  import chalk6 from "chalk";
68142
68177
  import { resolve as resolve6 } from "path";
68178
+
68179
+ // src/cli/structured-json.ts
68180
+ init_helpers();
68181
+ var STRUCTURED_PAGE_MAX_ROWS = 1000;
68182
+ var STRUCTURED_ALL_MAX_ROWS = 1e5;
68183
+ var STRUCTURED_DEFAULT_MAX_BYTES = 32 * 1024;
68184
+ var STRUCTURED_FULL_MAX_BYTES = 64 * 1024;
68185
+ var STRUCTURED_ALL_MAX_BYTES = 64 * 1024 * 1024;
68186
+ var STRUCTURED_MIN_MAX_BYTES = 1024;
68187
+ function structuredMaxBytes(value, opts) {
68188
+ const fallback = opts.all ? STRUCTURED_ALL_MAX_BYTES : opts.detail === "full" ? STRUCTURED_FULL_MAX_BYTES : STRUCTURED_DEFAULT_MAX_BYTES;
68189
+ if (value === undefined)
68190
+ return fallback;
68191
+ const parsed = typeof value === "number" ? value : Number(value);
68192
+ if (!Number.isInteger(parsed) || parsed < STRUCTURED_MIN_MAX_BYTES || parsed > STRUCTURED_ALL_MAX_BYTES) {
68193
+ throw new Error(`--max-bytes must be an integer from ${STRUCTURED_MIN_MAX_BYTES} to ${STRUCTURED_ALL_MAX_BYTES}`);
68194
+ }
68195
+ return parsed;
68196
+ }
68197
+ function structuredPageLimit(value, fallback) {
68198
+ const parsed = value === undefined ? fallback : Number(value);
68199
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > STRUCTURED_PAGE_MAX_ROWS) {
68200
+ throw new Error(`--limit must be an integer from 1 to ${STRUCTURED_PAGE_MAX_ROWS}`);
68201
+ }
68202
+ return parsed;
68203
+ }
68204
+ function compactMemory(memory, opts = {}) {
68205
+ const value = truncateText(memory.summary || memory.value, 240);
68206
+ return {
68207
+ id: memory.id,
68208
+ key: memory.key,
68209
+ value,
68210
+ scope: memory.scope,
68211
+ category: memory.category,
68212
+ importance: memory.importance,
68213
+ status: memory.status,
68214
+ pinned: memory.pinned,
68215
+ ...Array.isArray(memory.tags) && memory.tags.length ? { tags: memory.tags.slice(0, 10) } : {},
68216
+ ...memory.agent_id ? { agent_id: memory.agent_id } : {},
68217
+ ...memory.project_id ? { project_id: memory.project_id } : {},
68218
+ ...memory.session_id ? { session_id: memory.session_id } : {},
68219
+ ...opts.history && memory.accessed_at ? { accessed_at: memory.accessed_at } : {},
68220
+ updated_at: memory.updated_at
68221
+ };
68222
+ }
68223
+ function compactProject(project) {
68224
+ return {
68225
+ id: project.id,
68226
+ name: project.name,
68227
+ path: truncateText(project.path, 240),
68228
+ ...project.description ? { description: truncateText(project.description, 240) } : {},
68229
+ ...project.memory_prefix ? { memory_prefix: project.memory_prefix } : {},
68230
+ updated_at: project.updated_at
68231
+ };
68232
+ }
68233
+ function compactAgent(agent) {
68234
+ return {
68235
+ id: agent.id,
68236
+ name: agent.name,
68237
+ role: agent.role || "agent",
68238
+ ...agent.description ? { description: truncateText(agent.description, 240) } : {},
68239
+ ...agent.active_project_id ? { active_project_id: agent.active_project_id } : {},
68240
+ last_seen_at: agent.last_seen_at
68241
+ };
68242
+ }
68243
+ function compactSearchResult(result) {
68244
+ return {
68245
+ memory: compactMemory(result.memory),
68246
+ score: result.score,
68247
+ match_type: result.match_type,
68248
+ ...result.confidence !== undefined ? { confidence: result.confidence } : {},
68249
+ ...result.highlights?.length ? { highlights: result.highlights.slice(0, 3).map((highlight) => ({
68250
+ field: highlight.field,
68251
+ snippet: truncateText(highlight.snippet, 240)
68252
+ })) } : {}
68253
+ };
68254
+ }
68255
+ function makeEnvelope(args, items, byteTruncated, omittedFromPage) {
68256
+ const hasMore = byteTruncated || args.sourceHasMore;
68257
+ const complete = args.offset === 0 && !hasMore;
68258
+ const nextCursor = hasMore ? args.offset + items.length : null;
68259
+ const envelope = {
68260
+ [args.collection]: items,
68261
+ _meta: {
68262
+ receipt: args.receipt,
68263
+ count: items.length,
68264
+ limit: args.all ? null : args.limit,
68265
+ offset: args.offset,
68266
+ next_cursor: nextCursor,
68267
+ has_more: hasMore,
68268
+ complete,
68269
+ all: args.all,
68270
+ detail: args.detail,
68271
+ max_rows: args.all ? STRUCTURED_ALL_MAX_ROWS : STRUCTURED_PAGE_MAX_ROWS,
68272
+ max_bytes: args.maxBytes,
68273
+ response_bytes: 0,
68274
+ truncated: hasMore,
68275
+ truncation_reason: byteTruncated ? "max_bytes" : args.sourceHasMore ? "limit" : null,
68276
+ omitted_from_page: omittedFromPage,
68277
+ next_arguments: nextCursor === null ? null : {
68278
+ cursor: nextCursor,
68279
+ limit: args.limit,
68280
+ ...args.includeDetailInNextArguments !== false && args.detail === "full" ? { full: true } : {},
68281
+ max_bytes: args.maxBytes,
68282
+ ...args.nextArguments
68283
+ },
68284
+ continuation_scope: "unchanged_snapshot"
68285
+ }
68286
+ };
68287
+ for (let attempt = 0;attempt < 8; attempt += 1) {
68288
+ const bytes = Buffer.byteLength(`${JSON.stringify(envelope)}
68289
+ `);
68290
+ const meta = envelope["_meta"];
68291
+ if (bytes === meta.response_bytes)
68292
+ break;
68293
+ meta.response_bytes = bytes;
68294
+ }
68295
+ return envelope;
68296
+ }
68297
+ function structuredCollectionOutput(args) {
68298
+ const complete = makeEnvelope(args, args.items, false, 0);
68299
+ const completeText = `${JSON.stringify(complete)}
68300
+ `;
68301
+ if (Buffer.byteLength(completeText) <= args.maxBytes)
68302
+ return completeText;
68303
+ if (args.all) {
68304
+ throw new Error(`Exhaustive structured output exceeds the hard safety limit of ${args.maxBytes} bytes; use paginated JSON output or raise --max-bytes explicitly`);
68305
+ }
68306
+ for (let count = args.items.length - 1;count >= 0; count -= 1) {
68307
+ const envelope = makeEnvelope({ ...args, sourceHasMore: true }, args.items.slice(0, count), true, args.items.length - count);
68308
+ const text = `${JSON.stringify(envelope)}
68309
+ `;
68310
+ if (Buffer.byteLength(text) > args.maxBytes)
68311
+ continue;
68312
+ if (count === 0 && args.items.length > 0) {
68313
+ throw new Error(`One structured row exceeds --max-bytes=${args.maxBytes}; use compact detail or raise --max-bytes`);
68314
+ }
68315
+ return text;
68316
+ }
68317
+ throw new Error(`Structured output metadata exceeds --max-bytes=${args.maxBytes}`);
68318
+ }
68319
+
68320
+ // src/cli/commands/memory-cmd-search.ts
68143
68321
  function registerSearchCommand(program2) {
68144
68322
  const handleError = makeHandleError(program2);
68145
- program2.command("search <query>").description("Full-text search across memories").option("--scope <scope>", "Scope filter").option("-c, --category <cat>", "Category filter").option("--tags <tags>", "Comma-separated tags filter").option("--project <path>", "Project filter (path or name)").option("--agent <name>", "Agent filter").option("--session <id>", "Session ID filter").option("--limit <n>", "Max results", parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--format <fmt>", "Output format: compact (default), json, csv, yaml").option("--verbose", "Show match highlights and wider snippets").option("--history", "Show recent search queries instead of searching").option("--popular", "Show most popular search queries").action((query, opts) => {
68323
+ program2.command("search <query>").description("Full-text search across memories").option("--scope <scope>", "Scope filter").option("-c, --category <cat>", "Category filter").option("--tags <tags>", "Comma-separated tags filter").option("--project <path>", "Project filter (path or name)").option("--agent <name>", "Agent filter").option("--session <id>", "Session ID filter").option("--limit <n>", "Max results", parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--format <fmt>", "Output format: compact (default), json, csv, yaml").option("--verbose", "Show match highlights and wider snippets").option("--all", `Exhaust matching results in one explicit JSON receipt (hard max: ${STRUCTURED_ALL_MAX_ROWS})`).option("--full", "Return full legacy search-result objects in the bounded JSON receipt").option("--max-bytes <n>", "JSON response byte ceiling", parseInt).option("--history", "Show recent search queries instead of searching").option("--popular", "Show most popular search queries").action((query, opts) => {
68146
68324
  try {
68147
68325
  const fmt = getOutputFormat(program2, opts.format);
68148
68326
  const isStructured = fmt === "json" || fmt === "csv" || fmt === "yaml";
68149
- const limit = positiveIntOrDefault(opts.limit, isStructured ? 20 : DEFAULT_SEARCH_LIMIT);
68150
- const offset = cursorOrOffset(opts.cursor, opts.offset);
68327
+ const jsonMode = fmt === "json";
68328
+ const all = Boolean(opts.all);
68329
+ const detail = opts.full ? "full" : "compact";
68330
+ if (!jsonMode && (all || opts.full || opts.maxBytes !== undefined)) {
68331
+ throw new Error("--all, --full, and --max-bytes require JSON output");
68332
+ }
68333
+ if (all && opts.limit !== undefined)
68334
+ throw new Error("--all cannot be combined with --limit");
68335
+ const limit = jsonMode ? structuredPageLimit(opts.limit, 20) : positiveIntOrDefault(opts.limit, isStructured ? 20 : DEFAULT_SEARCH_LIMIT);
68336
+ const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
68337
+ if (all && offset !== 0)
68338
+ throw new Error("--all requires --cursor/--offset 0");
68151
68339
  if (opts.history) {
68152
68340
  const history = getSearchHistory(limit);
68153
68341
  if (fmt === "json") {
@@ -68195,16 +68383,36 @@ function registerSearchCommand(program2) {
68195
68383
  tags: opts.tags ? opts.tags.split(",").map((t) => t.trim()) : undefined,
68196
68384
  project_id: projectId,
68197
68385
  agent_id: agentId,
68198
- session_id: opts.session || globalOpts.session,
68199
- limit: isStructured ? limit : limit + 1,
68200
- offset
68386
+ session_id: opts.session || globalOpts.session
68201
68387
  };
68202
- const fetched = searchMemories(query, filter);
68388
+ const target = all ? STRUCTURED_ALL_MAX_ROWS : limit;
68389
+ const { rows: fetched, hasMore } = collectPagedRows((cursor, pageLimit) => {
68390
+ const rows = searchMemories(query, { ...filter, limit: pageLimit, offset: cursor });
68391
+ return {
68392
+ rows,
68393
+ has_more: rows.length < pageLimit ? false : undefined,
68394
+ next_cursor: cursor + rows.length
68395
+ };
68396
+ }, target, offset);
68397
+ if (all && hasMore) {
68398
+ throw new Error(`Exhaustive search output exceeds the hard safety limit of ${STRUCTURED_ALL_MAX_ROWS} rows; use paginated JSON output`);
68399
+ }
68203
68400
  const sanitized = fetched.map(redactSearchResultForOutput);
68204
- const hasMore = !isStructured && sanitized.length > limit;
68205
68401
  const results = hasMore ? sanitized.slice(0, limit) : sanitized;
68206
- if (fmt === "json") {
68207
- outputJson(sanitized);
68402
+ if (jsonMode) {
68403
+ const items = detail === "full" ? results.map((result) => ({ ...result })) : results.map(compactSearchResult);
68404
+ process.stdout.write(structuredCollectionOutput({
68405
+ collection: "results",
68406
+ receipt: "mementos.search.page.v1",
68407
+ items,
68408
+ offset,
68409
+ limit,
68410
+ sourceHasMore: hasMore,
68411
+ all,
68412
+ detail,
68413
+ maxBytes: structuredMaxBytes(opts.maxBytes, { all, detail }),
68414
+ nextArguments: { query }
68415
+ }));
68208
68416
  return;
68209
68417
  }
68210
68418
  if (fmt === "csv") {
@@ -68257,18 +68465,20 @@ init_redact();
68257
68465
  import chalk7 from "chalk";
68258
68466
  function registerWhenToUseCommand(program2) {
68259
68467
  const handleError = makeHandleError(program2);
68260
- program2.command("when-to-use <memory_id>").description("Show the when_to_use guidance for a memory").action((memoryId) => {
68468
+ program2.command("when-to-use <memory_id>").description("Show the when_to_use guidance for a memory").action(async (memoryId) => {
68261
68469
  try {
68262
68470
  const globalOpts = program2.opts();
68263
68471
  const resolvedId = resolveMemoryId(memoryId);
68264
68472
  const memory = getMemory(resolvedId);
68265
68473
  if (!memory) {
68266
68474
  if (globalOpts.json) {
68267
- outputJson({ error: `Memory not found: ${memoryId}` });
68475
+ await outputJsonAndExit({ error: `Memory not found: ${memoryId}` }, 1);
68268
68476
  } else {
68269
68477
  console.error(chalk7.red(`Memory not found: ${memoryId}`));
68270
68478
  }
68271
- process.exit(1);
68479
+ if (!globalOpts.json)
68480
+ process.exit(1);
68481
+ return;
68272
68482
  }
68273
68483
  const safe = redactMemoryForOutput(memory);
68274
68484
  const whenToUse = safe.when_to_use ?? null;
@@ -68401,7 +68611,7 @@ init_memories();
68401
68611
  init_helpers();
68402
68612
  import chalk10 from "chalk";
68403
68613
  function registerRemoveCommand(program2) {
68404
- program2.command("remove <nameOrId>").description("Remove/delete a memory by name or ID (alias for memory forget)").option("--agent <id>", "Agent ID").option("--scope <scope>", "Filter by scope (when looking up by key)").action((nameOrId, opts) => {
68614
+ program2.command("remove <nameOrId>").description("Remove/delete a memory by name or ID (alias for memory forget)").option("--agent <id>", "Agent ID").option("--scope <scope>", "Filter by scope (when looking up by key)").action(async (nameOrId, opts) => {
68405
68615
  const globalOpts = program2.opts();
68406
68616
  const agentId = opts.agent || globalOpts.agent;
68407
68617
  let id = isApiMode() ? null : resolvePartialId(getDatabase(), "memories", nameOrId);
@@ -68415,11 +68625,13 @@ function registerRemoveCommand(program2) {
68415
68625
  }
68416
68626
  if (!id) {
68417
68627
  if (globalOpts.json) {
68418
- outputJson({ error: `Memory not found: ${nameOrId}` });
68628
+ await outputJsonAndExit({ error: `Memory not found: ${nameOrId}` }, 1);
68419
68629
  } else {
68420
68630
  console.error(chalk10.red(`Memory not found: ${nameOrId}`));
68421
68631
  }
68422
- process.exit(1);
68632
+ if (!globalOpts.json)
68633
+ process.exit(1);
68634
+ return;
68423
68635
  }
68424
68636
  const deleted = deleteMemory(id);
68425
68637
  if (deleted) {
@@ -68430,11 +68642,13 @@ function registerRemoveCommand(program2) {
68430
68642
  }
68431
68643
  } else {
68432
68644
  if (globalOpts.json) {
68433
- outputJson({ error: `Memory not found: ${nameOrId}` });
68645
+ await outputJsonAndExit({ error: `Memory not found: ${nameOrId}` }, 1);
68434
68646
  } else {
68435
68647
  console.error(chalk10.red(`Memory not found: ${nameOrId}`));
68436
68648
  }
68437
- process.exit(1);
68649
+ if (!globalOpts.json)
68650
+ process.exit(1);
68651
+ return;
68438
68652
  }
68439
68653
  });
68440
68654
  }
@@ -68465,7 +68679,7 @@ var RECALL_EXIT_FUZZY = 2;
68465
68679
  // src/cli/commands/memory-cmd-recall.ts
68466
68680
  function registerRecallCommand(program2) {
68467
68681
  const handleError = makeHandleError(program2);
68468
- program2.command("recall <key>").alias("get").description("Recall a memory by exact key (use --fuzzy to fall back to the nearest match)").option("--scope <scope>", "Scope filter").option("--agent <name>", "Agent filter").option("--project <path>", "Project filter").option("--fuzzy", "If the exact key is absent, return the nearest match instead (exits 2)").action((key, opts) => {
68682
+ program2.command("recall <key>").alias("get").description("Recall a memory by exact key (use --fuzzy to fall back to the nearest match)").option("--scope <scope>", "Scope filter").option("--agent <name>", "Agent filter").option("--project <path>", "Project filter").option("--fuzzy", "If the exact key is absent, return the nearest match instead (exits 2)").action(async (key, opts) => {
68469
68683
  try {
68470
68684
  const globalOpts = program2.opts();
68471
68685
  const agentId = resolveAgentFilter(opts.agent || globalOpts.agent);
@@ -68498,28 +68712,32 @@ function registerRecallCommand(program2) {
68498
68712
  const safeBest = redactSearchResultForOutput(results[0]);
68499
68713
  touchMemory(safeBest.memory.id);
68500
68714
  if (globalOpts.json) {
68501
- outputJson({
68715
+ await outputJsonAndExit({
68502
68716
  fuzzy_match: true,
68503
68717
  requested_key: key,
68504
68718
  returned_key: safeBest.memory.key,
68505
68719
  score: safeBest.score,
68506
68720
  match_type: safeBest.match_type,
68507
68721
  memory: safeBest.memory
68508
- });
68722
+ }, RECALL_EXIT_FUZZY);
68509
68723
  } else {
68510
68724
  console.error(chalk11.yellow(`No memory with key "${key}". Showing the nearest match "${safeBest.memory.key}" ` + `(score: ${safeBest.score.toFixed(2)}, match: ${safeBest.match_type}) \u2014 this is a DIFFERENT record.`));
68511
68725
  console.log(formatMemoryDetail(safeBest.memory));
68512
68726
  }
68513
- process.exit(RECALL_EXIT_FUZZY);
68727
+ if (!globalOpts.json)
68728
+ process.exit(RECALL_EXIT_FUZZY);
68729
+ return;
68514
68730
  }
68515
68731
  }
68516
68732
  const message = opts.fuzzy ? `No memory found for key: ${key}` : `No memory found for key: ${key} (exact match; pass --fuzzy to return the nearest record instead)`;
68517
68733
  if (globalOpts.json) {
68518
- outputJson({ error: message, requested_key: key });
68734
+ await outputJsonAndExit({ error: message, requested_key: key }, RECALL_EXIT_NOT_FOUND);
68519
68735
  } else {
68520
68736
  console.error(chalk11.yellow(message));
68521
68737
  }
68522
- process.exit(RECALL_EXIT_NOT_FOUND);
68738
+ if (!globalOpts.json)
68739
+ process.exit(RECALL_EXIT_NOT_FOUND);
68740
+ return;
68523
68741
  } catch (e) {
68524
68742
  handleError(e);
68525
68743
  }
@@ -68533,19 +68751,19 @@ init_redact();
68533
68751
  init_helpers();
68534
68752
  import chalk12 from "chalk";
68535
68753
  import { resolve as resolve8 } from "path";
68536
- var STRUCTURED_PAGE_MAX_ROWS = 1000;
68537
- var STRUCTURED_ALL_MAX_ROWS = 5000;
68538
- var STRUCTURED_DEFAULT_MAX_BYTES = 32 * 1024;
68539
- var STRUCTURED_FULL_MAX_BYTES = 64 * 1024;
68540
- var STRUCTURED_ALL_MAX_BYTES = 1024 * 1024;
68541
- var STRUCTURED_MIN_MAX_BYTES = 1024;
68542
- function structuredMaxBytes(value, opts) {
68543
- const fallback = opts.all ? STRUCTURED_ALL_MAX_BYTES : opts.detail === "full" ? STRUCTURED_FULL_MAX_BYTES : STRUCTURED_DEFAULT_MAX_BYTES;
68754
+ var STRUCTURED_PAGE_MAX_ROWS2 = 1000;
68755
+ var STRUCTURED_ALL_MAX_ROWS2 = 1e5;
68756
+ var STRUCTURED_DEFAULT_MAX_BYTES2 = 32 * 1024;
68757
+ var STRUCTURED_FULL_MAX_BYTES2 = 64 * 1024;
68758
+ var STRUCTURED_ALL_MAX_BYTES2 = 64 * 1024 * 1024;
68759
+ var STRUCTURED_MIN_MAX_BYTES2 = 1024;
68760
+ function structuredMaxBytes2(value, opts) {
68761
+ const fallback = opts.all ? STRUCTURED_ALL_MAX_BYTES2 : opts.detail === "full" ? STRUCTURED_FULL_MAX_BYTES2 : STRUCTURED_DEFAULT_MAX_BYTES2;
68544
68762
  if (value === undefined)
68545
68763
  return fallback;
68546
68764
  const parsed = typeof value === "number" ? value : Number(value);
68547
- if (!Number.isInteger(parsed) || parsed < STRUCTURED_MIN_MAX_BYTES || parsed > STRUCTURED_ALL_MAX_BYTES) {
68548
- throw new Error(`--max-bytes must be an integer from ${STRUCTURED_MIN_MAX_BYTES} to ${STRUCTURED_ALL_MAX_BYTES}`);
68765
+ if (!Number.isInteger(parsed) || parsed < STRUCTURED_MIN_MAX_BYTES2 || parsed > STRUCTURED_ALL_MAX_BYTES2) {
68766
+ throw new Error(`--max-bytes must be an integer from ${STRUCTURED_MIN_MAX_BYTES2} to ${STRUCTURED_ALL_MAX_BYTES2}`);
68549
68767
  }
68550
68768
  return parsed;
68551
68769
  }
@@ -68597,7 +68815,7 @@ function makeStructuredEnvelope(args) {
68597
68815
  complete,
68598
68816
  all: args.all,
68599
68817
  detail: args.detail,
68600
- max_rows: args.all ? STRUCTURED_ALL_MAX_ROWS : STRUCTURED_PAGE_MAX_ROWS,
68818
+ max_rows: args.all ? STRUCTURED_ALL_MAX_ROWS2 : STRUCTURED_PAGE_MAX_ROWS2,
68601
68819
  max_bytes: args.maxBytes,
68602
68820
  response_bytes: 0,
68603
68821
  truncated: !complete,
@@ -68661,7 +68879,7 @@ function structuredMemoryOutput(args) {
68661
68879
  }
68662
68880
  function assertReceiptFlags(opts, receiptMode, requestedFormat) {
68663
68881
  if (!receiptMode && (opts.all || opts.full || opts.maxBytes !== undefined)) {
68664
- throw new Error("--all, --full, and --max-bytes require --agent-json receipt mode");
68882
+ throw new Error("--all, --full, and --max-bytes require JSON receipt mode (--json, --format json, or --agent-json)");
68665
68883
  }
68666
68884
  if (receiptMode && requestedFormat !== undefined && requestedFormat !== "json") {
68667
68885
  throw new Error("--agent-json cannot be combined with a non-JSON --format");
@@ -68672,20 +68890,20 @@ function assertReceiptFlags(opts, receiptMode, requestedFormat) {
68672
68890
  }
68673
68891
  function registerListCommand(program2) {
68674
68892
  const handleError = makeHandleError(program2);
68675
- program2.command("list").description("List memories with optional filters").option("--scope <scope>", "Scope filter").option("-c, --category <cat>", "Category filter").option("--tags <tags>", "Comma-separated tags filter").option("--importance-min <n>", "Minimum importance", parseInt).option("--pinned", "Show only pinned").option("--agent <name>", "Agent filter").option("--project <path>", "Project filter").option("--session <id>", "Session ID filter").option("--limit <n>", `Max results (agent JSON page max: ${STRUCTURED_PAGE_MAX_ROWS})`, parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--status <status>", "Status filter: active, archived, expired").option("--format <fmt>", "Output format: compact (default), json, csv, yaml").option("--verbose", "Show wider memory snippets in human output").option("--agent-json", "Output a bounded, receipt-bearing JSON page").option("--all", `Exhaust agent JSON results from offset zero (hard max: ${STRUCTURED_ALL_MAX_ROWS} rows)`).option("--full", "Emit full memory objects in agent JSON instead of compact projections").option("--max-bytes <n>", `Agent JSON response byte ceiling (hard max: ${STRUCTURED_ALL_MAX_BYTES})`, parseInt).action((opts) => {
68893
+ program2.command("list").description("List memories with optional filters").option("--scope <scope>", "Scope filter").option("-c, --category <cat>", "Category filter").option("--tags <tags>", "Comma-separated tags filter").option("--importance-min <n>", "Minimum importance", parseInt).option("--pinned", "Show only pinned").option("--agent <name>", "Agent filter").option("--project <path>", "Project filter").option("--session <id>", "Session ID filter").option("--limit <n>", `Max results (agent JSON page max: ${STRUCTURED_PAGE_MAX_ROWS2})`, parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--status <status>", "Status filter: active, archived, expired").option("--format <fmt>", "Output format: compact (default), json, csv, yaml").option("--verbose", "Show wider memory snippets in human output").option("--agent-json", "Output a bounded, receipt-bearing JSON page").option("--all", `Exhaust agent JSON results from offset zero (hard max: ${STRUCTURED_ALL_MAX_ROWS2} rows)`).option("--full", "Emit full memory objects in agent JSON instead of compact projections").option("--max-bytes <n>", `Agent JSON response byte ceiling (hard max: ${STRUCTURED_ALL_MAX_BYTES2})`, parseInt).action((opts) => {
68676
68894
  try {
68677
68895
  const globalOpts = program2.opts();
68678
68896
  const requestedFormat = opts.format ?? globalOpts.format;
68679
68897
  const fmt = getOutputFormat(program2, opts.format);
68680
- const receiptMode = Boolean(opts.agentJson);
68898
+ const receiptMode = Boolean(opts.agentJson || fmt === "json");
68681
68899
  const isStructured = fmt === "json" || fmt === "csv" || fmt === "yaml";
68682
68900
  assertReceiptFlags(opts, receiptMode, requestedFormat);
68683
68901
  const requestedLimit = opts.limit;
68684
68902
  const all = Boolean(opts.all);
68685
68903
  const detail = opts.full ? "full" : "compact";
68686
68904
  const limit = requestedLimit === undefined ? receiptMode ? DEFAULT_COMPACT_LIMIT : isStructured ? undefined : DEFAULT_COMPACT_LIMIT : positiveIntOrDefault(requestedLimit, receiptMode ? DEFAULT_COMPACT_LIMIT : isStructured ? 50 : DEFAULT_COMPACT_LIMIT);
68687
- if (receiptMode && limit !== undefined && limit > STRUCTURED_PAGE_MAX_ROWS) {
68688
- throw new Error(`--limit cannot exceed the agent JSON page ceiling of ${STRUCTURED_PAGE_MAX_ROWS}; use --all for a bounded exhaustive read`);
68905
+ if (receiptMode && limit !== undefined && limit > STRUCTURED_PAGE_MAX_ROWS2) {
68906
+ throw new Error(`--limit cannot exceed the agent JSON page ceiling of ${STRUCTURED_PAGE_MAX_ROWS2}; use --all for a bounded exhaustive read`);
68689
68907
  }
68690
68908
  const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
68691
68909
  if (all && offset !== 0) {
@@ -68712,7 +68930,7 @@ function registerListCommand(program2) {
68712
68930
  status: opts.status,
68713
68931
  session_id: opts.session || globalOpts.session
68714
68932
  };
68715
- const target = all ? STRUCTURED_ALL_MAX_ROWS : limit;
68933
+ const target = all ? STRUCTURED_ALL_MAX_ROWS2 : limit;
68716
68934
  const { rows: collected, hasMore } = collectPagedRows((cursor, pageLimit) => {
68717
68935
  const page = listMemoriesPage({
68718
68936
  ...filter,
@@ -68726,7 +68944,7 @@ function registerListCommand(program2) {
68726
68944
  };
68727
68945
  }, target, offset);
68728
68946
  if (all && hasMore) {
68729
- throw new Error(`Exhaustive structured output exceeds the hard safety limit of ${STRUCTURED_ALL_MAX_ROWS} rows; use paginated JSON output instead`);
68947
+ throw new Error(`Exhaustive structured output exceeds the hard safety limit of ${STRUCTURED_ALL_MAX_ROWS2} rows; use paginated JSON output instead`);
68730
68948
  }
68731
68949
  const memories = target === undefined ? collected : collected.slice(0, target);
68732
68950
  const sanitized = memories.map(redactMemoryForOutput);
@@ -68739,7 +68957,7 @@ function registerListCommand(program2) {
68739
68957
  sourceHasMore: hasMore,
68740
68958
  all,
68741
68959
  detail,
68742
- maxBytes: structuredMaxBytes(opts.maxBytes, { all, detail })
68960
+ maxBytes: structuredMaxBytes2(opts.maxBytes, { all, detail })
68743
68961
  }));
68744
68962
  return;
68745
68963
  }
@@ -68776,7 +68994,7 @@ function registerListCommand(program2) {
68776
68994
  offset,
68777
68995
  hasMore,
68778
68996
  command: "mementos list",
68779
- detailHint: "use mementos show <id> for full details, --json for the compatible full array, or --agent-json for a bounded receipt"
68997
+ detailHint: "use mementos show <id> for full details; JSON output is a bounded receipt, with --full/--all as explicit compatibility escapes"
68780
68998
  });
68781
68999
  } catch (e) {
68782
69000
  handleError(e);
@@ -69203,7 +69421,7 @@ init_helpers();
69203
69421
  import chalk16 from "chalk";
69204
69422
  function registerHistoryCommand(program2) {
69205
69423
  const handleError = makeHandleError(program2);
69206
- program2.command("history").description("List memories sorted by most recently accessed").option("--limit <n>", `Max results (agent JSON page max: ${STRUCTURED_PAGE_MAX_ROWS})`, parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--verbose", "Show wider memory snippets").option("--agent-json", "Output a bounded, receipt-bearing JSON page").option("--all", `Exhaust agent JSON results from offset zero (hard max: ${STRUCTURED_ALL_MAX_ROWS} rows)`).option("--full", "Emit full memory objects in agent JSON instead of compact projections").option("--max-bytes <n>", `Agent JSON response byte ceiling (hard max: ${STRUCTURED_ALL_MAX_BYTES})`, parseInt).action((opts) => {
69424
+ program2.command("history").description("List memories sorted by most recently accessed").option("--limit <n>", `Max results (agent JSON page max: ${STRUCTURED_PAGE_MAX_ROWS2})`, parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--verbose", "Show wider memory snippets").option("--agent-json", "Output a bounded, receipt-bearing JSON page").option("--all", `Exhaust agent JSON results from offset zero (hard max: ${STRUCTURED_ALL_MAX_ROWS2} rows)`).option("--full", "Emit full memory objects in agent JSON instead of compact projections").option("--max-bytes <n>", `Agent JSON response byte ceiling (hard max: ${STRUCTURED_ALL_MAX_BYTES2})`, parseInt).action((opts) => {
69207
69425
  try {
69208
69426
  const globalOpts = program2.opts();
69209
69427
  const format = getOutputFormat(program2);
@@ -69222,14 +69440,14 @@ function registerHistoryCommand(program2) {
69222
69440
  const all = Boolean(opts.all);
69223
69441
  const detail = opts.full ? "full" : "compact";
69224
69442
  const limit = requestedLimit === undefined ? receiptMode ? DEFAULT_SEARCH_LIMIT : isJson ? undefined : DEFAULT_SEARCH_LIMIT : positiveIntOrDefault(requestedLimit, receiptMode ? DEFAULT_SEARCH_LIMIT : isJson ? 20 : DEFAULT_SEARCH_LIMIT);
69225
- if (receiptMode && limit !== undefined && limit > STRUCTURED_PAGE_MAX_ROWS) {
69226
- throw new Error(`--limit cannot exceed the agent JSON page ceiling of ${STRUCTURED_PAGE_MAX_ROWS}; use --all for a bounded exhaustive read`);
69443
+ if (receiptMode && limit !== undefined && limit > STRUCTURED_PAGE_MAX_ROWS2) {
69444
+ throw new Error(`--limit cannot exceed the agent JSON page ceiling of ${STRUCTURED_PAGE_MAX_ROWS2}; use --all for a bounded exhaustive read`);
69227
69445
  }
69228
69446
  const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
69229
69447
  if (all && offset !== 0) {
69230
69448
  throw new Error("--all requires --cursor/--offset 0");
69231
69449
  }
69232
- const target = all ? STRUCTURED_ALL_MAX_ROWS : limit;
69450
+ const target = all ? STRUCTURED_ALL_MAX_ROWS2 : limit;
69233
69451
  const { rows: collected, hasMore } = collectPagedRows((cursor, pageLimit) => {
69234
69452
  const page = listMemoryHistoryPage({ limit: pageLimit, offset: cursor });
69235
69453
  return {
@@ -69239,7 +69457,7 @@ function registerHistoryCommand(program2) {
69239
69457
  };
69240
69458
  }, target, offset);
69241
69459
  if (all && hasMore) {
69242
- throw new Error(`Exhaustive structured output exceeds the hard safety limit of ${STRUCTURED_ALL_MAX_ROWS} rows; use paginated JSON output instead`);
69460
+ throw new Error(`Exhaustive structured output exceeds the hard safety limit of ${STRUCTURED_ALL_MAX_ROWS2} rows; use paginated JSON output instead`);
69243
69461
  }
69244
69462
  const memories = target === undefined ? collected : collected.slice(0, target);
69245
69463
  const sanitized = memories.map(redactMemoryForOutput);
@@ -69252,7 +69470,7 @@ function registerHistoryCommand(program2) {
69252
69470
  sourceHasMore: hasMore,
69253
69471
  all,
69254
69472
  detail,
69255
- maxBytes: structuredMaxBytes(opts.maxBytes, { all, detail }),
69473
+ maxBytes: structuredMaxBytes2(opts.maxBytes, { all, detail }),
69256
69474
  history: true
69257
69475
  }));
69258
69476
  return;
@@ -69461,7 +69679,7 @@ init_helpers();
69461
69679
  import { resolve as resolve12 } from "path";
69462
69680
  function registerExportCommand(program2) {
69463
69681
  const handleError = makeHandleError(program2);
69464
- program2.command("export").description("Export memories as JSON").option("--scope <scope>", "Scope filter").option("-c, --category <cat>", "Category filter").option("--agent <name>", "Agent filter").option("--project <path>", "Project filter").action((opts) => {
69682
+ program2.command("export").description("Export a truthful full-detail JSON page; use --all for the exhaustive legacy array").option("--scope <scope>", "Scope filter").option("-c, --category <cat>", "Category filter").option("--agent <name>", "Agent filter").option("--project <path>", "Project filter").option("--limit <n>", "Page size (default: 100, maximum: 1000)", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--max-bytes <n>", "Paginated response byte ceiling (default: 65536)", parseInt).option("--all", "Exhaust the complete query and emit the legacy full JSON array").action((opts) => {
69465
69683
  try {
69466
69684
  const globalOpts = program2.opts();
69467
69685
  const agentId = resolveAgentFilter(opts.agent || globalOpts.agent);
@@ -69478,9 +69696,43 @@ function registerExportCommand(program2) {
69478
69696
  agent_id: agentId,
69479
69697
  project_id: projectId
69480
69698
  };
69481
- const memories = listMemoriesBounded(filter, 1e4).rows;
69482
- const sanitized = memories.map(redactMemoryForOutput);
69483
- outputJson(sanitized);
69699
+ const exhaustive = Boolean(opts.all);
69700
+ const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
69701
+ if (exhaustive && opts.limit !== undefined) {
69702
+ throw new Error("--all cannot be combined with --limit");
69703
+ }
69704
+ if (exhaustive && offset !== 0) {
69705
+ throw new Error("--all requires --cursor/--offset 0");
69706
+ }
69707
+ if (exhaustive && opts.maxBytes !== undefined) {
69708
+ throw new Error("--max-bytes applies to paginated exports; exhaustive --all is an explicit unbounded compatibility escape");
69709
+ }
69710
+ if (exhaustive) {
69711
+ const complete = listMemoriesBounded(filter, undefined).rows.map(redactMemoryForOutput);
69712
+ outputJson(complete);
69713
+ return;
69714
+ }
69715
+ const limit = structuredPageLimit(opts.limit, 100);
69716
+ const page = listMemoriesBounded({ ...filter, offset }, limit);
69717
+ const sanitized = page.rows.map(redactMemoryForOutput);
69718
+ process.stdout.write(structuredCollectionOutput({
69719
+ collection: "memories",
69720
+ receipt: "mementos.export.page.v1",
69721
+ items: sanitized,
69722
+ offset,
69723
+ limit,
69724
+ sourceHasMore: page.has_more,
69725
+ all: false,
69726
+ detail: "full",
69727
+ maxBytes: structuredMaxBytes(opts.maxBytes, { all: false, detail: "full" }),
69728
+ nextArguments: {
69729
+ ...opts.scope ? { scope: opts.scope } : {},
69730
+ ...opts.category ? { category: opts.category } : {},
69731
+ ...agentId ? { agent: agentId } : {},
69732
+ ...projectPath ? { project: projectPath } : {}
69733
+ },
69734
+ includeDetailInNextArguments: false
69735
+ }));
69484
69736
  } catch (e) {
69485
69737
  handleError(e);
69486
69738
  }
@@ -69886,7 +70138,7 @@ function inspectLocalRestoreSource(source) {
69886
70138
  }
69887
70139
  function registerRestoreCommand(program2) {
69888
70140
  const handleError = makeHandleError(program2);
69889
- program2.command("restore [file]").description("Restore the database from a backup file").option("--latest", "Restore the most recent backup from the mementos backups dir").option("--force", "Skip confirmation and perform the restore").action((filePath, opts) => {
70141
+ program2.command("restore [file]").description("Restore the database from a backup file").option("--latest", "Restore the most recent backup from the mementos backups dir").option("--force", "Skip confirmation and perform the restore").action(async (filePath, opts) => {
69890
70142
  try {
69891
70143
  const globalOpts = program2.opts();
69892
70144
  const backupsDir = join11(getDataRoot(), "backups");
@@ -69947,7 +70199,7 @@ function registerRestoreCommand(program2) {
69947
70199
  if (result.rejected > 0) {
69948
70200
  const msg = `${result.rejected} of ${result.total} memories were rejected and did not persist. See errors.`;
69949
70201
  if (globalOpts.json) {
69950
- outputJson({
70202
+ await outputJsonAndExit({
69951
70203
  action: "restore",
69952
70204
  status: "failed",
69953
70205
  source,
@@ -69957,11 +70209,12 @@ function registerRestoreCommand(program2) {
69957
70209
  rejected: result.rejected,
69958
70210
  total: result.total,
69959
70211
  error: msg
69960
- });
70212
+ }, 1);
69961
70213
  } else {
69962
70214
  console.error(chalk21.red(msg));
69963
70215
  }
69964
- process.exit(1);
70216
+ if (!globalOpts.json)
70217
+ process.exit(1);
69965
70218
  }
69966
70219
  if (globalOpts.json) {
69967
70220
  outputJson({
@@ -70116,20 +70369,40 @@ function registerAgentCommands(program2) {
70116
70369
  handleError(e);
70117
70370
  }
70118
70371
  });
70119
- program2.command("agents").description("List all registered agents").option("--limit <n>", "Max results (compact default: 20)", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--offset <n>", "Offset for pagination", parseInt).action((opts) => {
70372
+ program2.command("agents").description("List all registered agents").option("--limit <n>", "Max results (compact default: 20)", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--all", `Exhaust all agents in one explicit JSON receipt (hard max: ${STRUCTURED_ALL_MAX_ROWS})`).option("--full", "Return full agent objects instead of compact projections").option("--max-bytes <n>", "JSON response byte ceiling", parseInt).action((opts) => {
70120
70373
  try {
70121
70374
  const globalOpts = program2.opts();
70122
- const limit = positiveIntOrDefault(opts.limit, DEFAULT_COMPACT_LIMIT);
70375
+ const jsonMode = Boolean(globalOpts.json);
70376
+ const all = Boolean(opts.all);
70377
+ const detail = opts.full ? "full" : "compact";
70378
+ if (!jsonMode && (all || opts.full || opts.maxBytes !== undefined)) {
70379
+ throw new Error("--all, --full, and --max-bytes require --json");
70380
+ }
70381
+ if (all && opts.limit !== undefined)
70382
+ throw new Error("--all cannot be combined with --limit");
70383
+ const limit = jsonMode ? structuredPageLimit(opts.limit, DEFAULT_COMPACT_LIMIT) : positiveIntOrDefault(opts.limit, DEFAULT_COMPACT_LIMIT);
70123
70384
  const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
70124
- const explicitPagination = opts.limit !== undefined || opts.cursor !== undefined || opts.offset !== undefined;
70125
- const agents = listAgents({
70126
- limit: globalOpts.json ? explicitPagination ? limit : undefined : limit + 1,
70127
- offset
70128
- });
70129
- const hasMore = !globalOpts.json && agents.length > limit;
70385
+ if (all && offset !== 0)
70386
+ throw new Error("--all requires --cursor/--offset 0");
70387
+ const agents = all ? listAgents() : listAgents({ limit: limit + 1, offset });
70388
+ if (all && agents.length > STRUCTURED_ALL_MAX_ROWS) {
70389
+ throw new Error(`Exhaustive agent output exceeds the hard safety limit of ${STRUCTURED_ALL_MAX_ROWS} rows; use paginated JSON output`);
70390
+ }
70391
+ const hasMore = !all && agents.length > limit;
70130
70392
  const displayAgents = hasMore ? agents.slice(0, limit) : agents;
70131
- if (globalOpts.json) {
70132
- outputJson(agents);
70393
+ if (jsonMode) {
70394
+ const items = detail === "full" ? displayAgents.map((agent) => ({ ...agent })) : displayAgents.map(compactAgent);
70395
+ process.stdout.write(structuredCollectionOutput({
70396
+ collection: "agents",
70397
+ receipt: "mementos.agents.page.v1",
70398
+ items,
70399
+ offset,
70400
+ limit,
70401
+ sourceHasMore: hasMore,
70402
+ all,
70403
+ detail,
70404
+ maxBytes: structuredMaxBytes(opts.maxBytes, { all, detail })
70405
+ }));
70133
70406
  return;
70134
70407
  }
70135
70408
  if (displayAgents.length === 0) {
@@ -70153,7 +70426,7 @@ function registerAgentCommands(program2) {
70153
70426
  handleError(e);
70154
70427
  }
70155
70428
  });
70156
- program2.command("agent-update <id>").description("Update an agent's name, description, or role").option("--name <name>", "New agent name").option("-d, --description <text>", "New description").option("-r, --role <role>", "New role").action((id, opts) => {
70429
+ program2.command("agent-update <id>").description("Update an agent's name, description, or role").option("--name <name>", "New agent name").option("-d, --description <text>", "New description").option("-r, --role <role>", "New role").action(async (id, opts) => {
70157
70430
  try {
70158
70431
  const globalOpts = program2.opts();
70159
70432
  const updates = {};
@@ -70165,20 +70438,24 @@ function registerAgentCommands(program2) {
70165
70438
  updates.role = opts.role;
70166
70439
  if (Object.keys(updates).length === 0) {
70167
70440
  if (globalOpts.json) {
70168
- outputJson({ error: "No updates provided. Use --name, --description, or --role." });
70441
+ await outputJsonAndExit({ error: "No updates provided. Use --name, --description, or --role." }, 1);
70169
70442
  } else {
70170
70443
  console.error(chalk22.red("No updates provided. Use --name, --description, or --role."));
70171
70444
  }
70172
- process.exit(1);
70445
+ if (!globalOpts.json)
70446
+ process.exit(1);
70447
+ return;
70173
70448
  }
70174
70449
  const agent = updateAgent(id, updates);
70175
70450
  if (!agent) {
70176
70451
  if (globalOpts.json) {
70177
- outputJson({ error: `Agent not found: ${id}` });
70452
+ await outputJsonAndExit({ error: `Agent not found: ${id}` }, 1);
70178
70453
  } else {
70179
70454
  console.error(chalk22.red(`Agent not found: ${id}`));
70180
70455
  }
70181
- process.exit(1);
70456
+ if (!globalOpts.json)
70457
+ process.exit(1);
70458
+ return;
70182
70459
  }
70183
70460
  if (globalOpts.json) {
70184
70461
  outputJson(agent);
@@ -70266,7 +70543,7 @@ import { resolve as resolve17 } from "path";
70266
70543
  init_helpers();
70267
70544
  function registerProjectCommands(program2) {
70268
70545
  const handleError = makeHandleError(program2);
70269
- program2.command("projects").description("Manage projects").option("--add", "Add a new project").option("--update <id>", "Update a project by its exact stable ID").option("--name <name>", "Project name").option("--path <path>", "Project path").option("--description <text>", "Project description").option("--memory-prefix <prefix>", "Project memory prefix").option("--expected-revision <revision>", "Exact updated_at revision required for compare-and-swap").option("--idempotency-key <key>", "Caller-owned key for one guarded mutation").option("--operation-id <id>", "Operation identifier (defaults to the idempotency key)").option("--step-id <id>", "Step identifier (defaults to mementos_project_update)").option("--dry-run", "Validate and preview the guarded update without writing").option("--rollback-receipt <id>", "Restore the exact before snapshot from an accepted update receipt").option("--limit <n>", "Max results (compact default: 20)", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--offset <n>", "Offset for pagination", parseInt).action((opts) => {
70546
+ program2.command("projects").description("Manage projects").option("--add", "Add a new project").option("--update <id>", "Update a project by its exact stable ID").option("--name <name>", "Project name").option("--path <path>", "Project path").option("--description <text>", "Project description").option("--memory-prefix <prefix>", "Project memory prefix").option("--expected-revision <revision>", "Exact updated_at revision required for compare-and-swap").option("--idempotency-key <key>", "Caller-owned key for one guarded mutation").option("--operation-id <id>", "Operation identifier (defaults to the idempotency key)").option("--step-id <id>", "Step identifier (defaults to mementos_project_update)").option("--dry-run", "Validate and preview the guarded update without writing").option("--rollback-receipt <id>", "Restore the exact before snapshot from an accepted update receipt").option("--limit <n>", "Max results (compact default: 20)", parseInt).option("--cursor <n>", "Cursor offset for the next page", parseInt).option("--offset <n>", "Offset for pagination", parseInt).option("--all", `Exhaust all projects in one explicit JSON receipt (hard max: ${STRUCTURED_ALL_MAX_ROWS})`).option("--full", "Return full project objects instead of compact projections").option("--max-bytes <n>", "JSON response byte ceiling", parseInt).action((opts) => {
70270
70547
  try {
70271
70548
  const globalOpts = program2.opts();
70272
70549
  if (opts.add && opts.update) {
@@ -70347,15 +70624,39 @@ function registerProjectCommands(program2) {
70347
70624
  }
70348
70625
  return;
70349
70626
  }
70350
- const allProjects = listProjects();
70351
- const limit = positiveIntOrDefault(opts.limit, DEFAULT_COMPACT_LIMIT);
70627
+ const jsonMode = Boolean(globalOpts.json);
70628
+ const all = Boolean(opts.all);
70629
+ const detail = opts.full ? "full" : "compact";
70630
+ if (!jsonMode && (all || opts.full || opts.maxBytes !== undefined)) {
70631
+ throw new Error("--all, --full, and --max-bytes require --json");
70632
+ }
70633
+ if (all && opts.limit !== undefined) {
70634
+ throw new Error("--all cannot be combined with --limit");
70635
+ }
70636
+ const limit = jsonMode ? structuredPageLimit(opts.limit, DEFAULT_COMPACT_LIMIT) : positiveIntOrDefault(opts.limit, DEFAULT_COMPACT_LIMIT);
70352
70637
  const offset = cursorOrOffset(opts.cursor, opts.offset) ?? 0;
70353
- const explicitPagination = opts.limit !== undefined || opts.cursor !== undefined || opts.offset !== undefined;
70354
- const projects = globalOpts.json ? explicitPagination ? allProjects.slice(offset, offset + limit) : allProjects : allProjects.slice(offset, offset + limit + 1);
70355
- const hasMore = !globalOpts.json && projects.length > limit;
70356
- const displayProjects = hasMore ? projects.slice(0, limit) : projects;
70357
- if (globalOpts.json) {
70358
- outputJson(projects);
70638
+ if (all && offset !== 0)
70639
+ throw new Error("--all requires --cursor/--offset 0");
70640
+ const allProjects = listProjects();
70641
+ if (all && allProjects.length > STRUCTURED_ALL_MAX_ROWS) {
70642
+ throw new Error(`Exhaustive project output exceeds the hard safety limit of ${STRUCTURED_ALL_MAX_ROWS} rows; use paginated JSON output`);
70643
+ }
70644
+ const page = all ? allProjects : allProjects.slice(offset, offset + limit + 1);
70645
+ const hasMore = !all && page.length > limit;
70646
+ const displayProjects = hasMore ? page.slice(0, limit) : page;
70647
+ if (jsonMode) {
70648
+ const items = detail === "full" ? displayProjects.map((project) => ({ ...project })) : displayProjects.map(compactProject);
70649
+ process.stdout.write(structuredCollectionOutput({
70650
+ collection: "projects",
70651
+ receipt: "mementos.projects.page.v1",
70652
+ items,
70653
+ offset,
70654
+ limit,
70655
+ sourceHasMore: hasMore,
70656
+ all,
70657
+ detail,
70658
+ maxBytes: structuredMaxBytes(opts.maxBytes, { all, detail })
70659
+ }));
70359
70660
  return;
70360
70661
  }
70361
70662
  if (displayProjects.length === 0) {
@@ -71629,7 +71930,8 @@ function resolveApiStatus(version = getPackageVersion()) {
71629
71930
  error = err instanceof Error ? err.message : String(err);
71630
71931
  }
71631
71932
  }
71632
- const validBase = error ? null : apiBase;
71933
+ const resolvedApiUrl = error ? null : apiUrl ?? resolved?.baseUrl ?? null;
71934
+ const validBase = error ? null : apiBase ?? resolved?.baseUrl.replace(/\/v1$/, "") ?? null;
71633
71935
  const apiKeyConfigured = configured?.apiKeyPresent ?? false;
71634
71936
  let transport;
71635
71937
  if (hasExplicitLocalDbPath()) {
@@ -71646,7 +71948,7 @@ function resolveApiStatus(version = getPackageVersion()) {
71646
71948
  app: "mementos",
71647
71949
  version,
71648
71950
  transport,
71649
- api_url: apiUrl,
71951
+ api_url: resolvedApiUrl,
71650
71952
  api_base: validBase,
71651
71953
  api_key_present: apiKeyConfigured || resolved !== null
71652
71954
  },
@@ -74934,11 +75236,13 @@ function registerConsolidationCommands(program2) {
74934
75236
  }
74935
75237
  } catch (error40) {
74936
75238
  if (program2.opts().json) {
74937
- outputJson({ error: error40 instanceof Error ? error40.message : String(error40) });
75239
+ await outputJsonAndExit({ error: error40 instanceof Error ? error40.message : String(error40) }, 1);
74938
75240
  } else {
74939
75241
  console.error(chalk42.red(error40 instanceof Error ? error40.message : String(error40)));
74940
75242
  }
74941
- process.exit(1);
75243
+ if (!program2.opts().json)
75244
+ process.exit(1);
75245
+ return;
74942
75246
  }
74943
75247
  });
74944
75248
  program2.command("reflect").description("Reflect on a session, task, or range and save structured lessons").requiredOption("--on <target>", "Trajectory target: session, task, range").option("--source <idOrRange>", "Session ID, task ID, or range as since..until").option("--dry-run", "Critique without writing lesson memories").option("--project <idOrPath>", "Project ID, name, or path").option("--agent <nameOrId>", "Agent name or ID").option("--since <iso>", "Range start timestamp").option("--until <iso>", "Range end timestamp").option("--provider <name>", "Critic provider: anthropic, openai, cerebras, grok").option("--model <name>", "Critic model").option("--max-tokens <n>", "Maximum critic output tokens", parseNumber2).option("--format <fmt>", "Output format: compact, json").action(async (opts) => {
@@ -74977,11 +75281,13 @@ function registerConsolidationCommands(program2) {
74977
75281
  }
74978
75282
  } catch (error40) {
74979
75283
  if (program2.opts().json) {
74980
- outputJson({ error: error40 instanceof Error ? error40.message : String(error40) });
75284
+ await outputJsonAndExit({ error: error40 instanceof Error ? error40.message : String(error40) }, 1);
74981
75285
  } else {
74982
75286
  console.error(chalk42.red(error40 instanceof Error ? error40.message : String(error40)));
74983
75287
  }
74984
- process.exit(1);
75288
+ if (!program2.opts().json)
75289
+ process.exit(1);
75290
+ return;
74985
75291
  }
74986
75292
  });
74987
75293
  }