@memnexus-ai/cli 1.7.218 → 1.7.219

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.
@@ -1,4 +1,5 @@
1
1
  import { Command } from 'commander';
2
+ import { isRateLimitError, isServiceUnavailableError, isQuotaError, getRetryAfterMs, sleep } from '../lib/retry';
2
3
  /** Number of deletions within the window that triggers the guard. */
3
4
  export declare const BULK_DELETE_GUARD_THRESHOLD = 5;
4
5
  /** Rolling window in milliseconds (60 seconds). */
@@ -66,16 +67,7 @@ export declare function parseBatchIds(values: string[] | undefined): string[];
66
67
  export declare function isValidIsoDate(value: string): boolean;
67
68
  /** Split ids into pages of at most `size` (default 100). */
68
69
  export declare function chunkIds(ids: string[], size?: number): string[][];
69
- /** True when an error is an HTTP 429 (rate limited). */
70
- export declare function isRateLimitError(error: any): boolean;
71
- /**
72
- * Extract the server's Retry-After hint in milliseconds, or null if absent.
73
- * The API surfaces it as a body field (`retryAfter`, seconds) on 429s
74
- * (see lib/errors.ts) and may also send a Retry-After header; we honor both.
75
- */
76
- export declare function getRetryAfterMs(error: any): number | null;
77
- /** Promise-based sleep. Extracted so tests can inject a no-op/spy. */
78
- export declare function sleep(ms: number): Promise<void>;
70
+ export { isRateLimitError, isServiceUnavailableError, isQuotaError, getRetryAfterMs, sleep };
79
71
  export interface BulkDeleteDeps {
80
72
  /** Deletes one page (≤100 ids) and returns the server's counts. */
81
73
  deleteFn: (ids: string[]) => Promise<BulkDeleteResult>;
@@ -152,12 +144,8 @@ export declare const BATCH_CREATE_MAX_LINE_BYTES: number;
152
144
  * single-create, out of scope for the streaming path (noted in the PR).
153
145
  */
154
146
  export declare const BATCH_CREATE_ALLOWED_KEYS: Set<string>;
155
- /** True when an error is an HTTP 503 (service unavailable — transient). */
156
- export declare function isServiceUnavailableError(error: any): boolean;
157
147
  /** True when a create should be retried: 429 (rate limited) or 503 (transient). */
158
148
  export declare function isRetryableCreateError(error: any): boolean;
159
- /** True when an error is an HTTP 402 (quota / payment required). */
160
- export declare function isQuotaError(error: any): boolean;
161
149
  export interface BatchCreateItem {
162
150
  /** 1-based input line number (blank lines are skipped, so this is not dense). */
163
151
  line: number;
@@ -1 +1 @@
1
- {"version":3,"file":"memories.d.ts","sourceRoot":"","sources":["../../src/commands/memories.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memories.d.ts","sourceRoot":"","sources":["../../src/commands/memories.ts"],"names":[],"mappings":"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"}
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.StdinTooLargeError = exports.BATCH_CREATE_ALLOWED_KEYS = exports.BATCH_CREATE_MAX_LINE_BYTES = exports.BATCH_CREATE_MAX_STDIN_BYTES = exports.BATCH_CREATE_MAX_RETRIES = exports.BATCH_CREATE_CONCURRENCY_MAX = exports.BATCH_CREATE_CONCURRENCY_MIN = exports.BATCH_CREATE_DEFAULT_CONCURRENCY = exports.BULK_DELETE_LIST_PAGE_SIZE = exports.BULK_DELETE_MAX_RETRIES = exports.BULK_DELETE_PAGE_PAUSE_MS = exports.BULK_DELETE_MAX_IDS = exports.BULK_DELETE_GUARD_WINDOW_MS = exports.BULK_DELETE_GUARD_THRESHOLD = void 0;
39
+ exports.StdinTooLargeError = exports.BATCH_CREATE_ALLOWED_KEYS = exports.BATCH_CREATE_MAX_LINE_BYTES = exports.BATCH_CREATE_MAX_STDIN_BYTES = exports.BATCH_CREATE_MAX_RETRIES = exports.BATCH_CREATE_CONCURRENCY_MAX = exports.BATCH_CREATE_CONCURRENCY_MIN = exports.BATCH_CREATE_DEFAULT_CONCURRENCY = exports.sleep = exports.getRetryAfterMs = exports.isQuotaError = exports.isServiceUnavailableError = exports.isRateLimitError = exports.BULK_DELETE_LIST_PAGE_SIZE = exports.BULK_DELETE_MAX_RETRIES = exports.BULK_DELETE_PAGE_PAUSE_MS = exports.BULK_DELETE_MAX_IDS = exports.BULK_DELETE_GUARD_WINDOW_MS = exports.BULK_DELETE_GUARD_THRESHOLD = void 0;
40
40
  exports.getBulkDeleteGuardPath = getBulkDeleteGuardPath;
41
41
  exports.readDeleteGuardTimestamps = readDeleteGuardTimestamps;
42
42
  exports.recordDeletion = recordDeletion;
@@ -45,15 +45,10 @@ exports.parseCodeContextFlag = parseCodeContextFlag;
45
45
  exports.parseBatchIds = parseBatchIds;
46
46
  exports.isValidIsoDate = isValidIsoDate;
47
47
  exports.chunkIds = chunkIds;
48
- exports.isRateLimitError = isRateLimitError;
49
- exports.getRetryAfterMs = getRetryAfterMs;
50
- exports.sleep = sleep;
51
48
  exports.bulkDeleteWithRetry = bulkDeleteWithRetry;
52
49
  exports.runBulkDeletePaged = runBulkDeletePaged;
53
50
  exports.collectAllMemoryIds = collectAllMemoryIds;
54
- exports.isServiceUnavailableError = isServiceUnavailableError;
55
51
  exports.isRetryableCreateError = isRetryableCreateError;
56
- exports.isQuotaError = isQuotaError;
57
52
  exports.parseJsonlCreateLine = parseJsonlCreateLine;
58
53
  exports.resolveCreateConcurrency = resolveCreateConcurrency;
59
54
  exports.batchCreateWithRetry = batchCreateWithRetry;
@@ -74,6 +69,12 @@ const chalk_1 = __importDefault(require("chalk"));
74
69
  const api_client_1 = require("../lib/api-client");
75
70
  const config_1 = require("../lib/config");
76
71
  const errors_1 = require("../lib/errors");
72
+ const retry_1 = require("../lib/retry");
73
+ Object.defineProperty(exports, "isRateLimitError", { enumerable: true, get: function () { return retry_1.isRateLimitError; } });
74
+ Object.defineProperty(exports, "isServiceUnavailableError", { enumerable: true, get: function () { return retry_1.isServiceUnavailableError; } });
75
+ Object.defineProperty(exports, "isQuotaError", { enumerable: true, get: function () { return retry_1.isQuotaError; } });
76
+ Object.defineProperty(exports, "getRetryAfterMs", { enumerable: true, get: function () { return retry_1.getRetryAfterMs; } });
77
+ Object.defineProperty(exports, "sleep", { enumerable: true, get: function () { return retry_1.sleep; } });
77
78
  const formatters_1 = require("../lib/formatters");
78
79
  const js_yaml_1 = __importDefault(require("js-yaml"));
79
80
  const spinner_1 = require("../lib/spinner");
@@ -270,11 +271,11 @@ async function resolveShortIds(ids, opts = {}) {
270
271
  }
271
272
  else {
272
273
  // Resolve short ID
273
- const listResponse = await (0, api_client_1.getSdk)().memories.listMemories({
274
+ const listResponse = await retryRead(() => (0, api_client_1.getSdk)().memories.listMemories({
274
275
  limit: 10,
275
276
  offset: 0,
276
277
  idPrefix: id,
277
- });
278
+ }));
278
279
  const matches = listResponse.data?.data || [];
279
280
  if (matches.length === 0) {
280
281
  warn(`Warning: No memory found with prefix "${id}"`);
@@ -392,10 +393,10 @@ async function handleBatchMemoryGet(ids, options) {
392
393
  }
393
394
  spinner.text = `Fetching ${resolvedIds.length} memories...`;
394
395
  const batchDetail = options.detail || 'minimal';
395
- const response = await (0, api_client_1.getSdk)().memories.getMemoriesBatch({
396
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.getMemoriesBatch({
396
397
  ids: resolvedIds,
397
398
  detail: batchDetail,
398
- });
399
+ }));
399
400
  const result = response.data;
400
401
  if (result && result.meta && result.meta.missing && result.meta.missing.length > 0) {
401
402
  spinner.warn(`Found ${result.meta.found} of ${result.meta.requested} memories`);
@@ -506,42 +507,46 @@ function chunkIds(ids, size = exports.BULK_DELETE_MAX_IDS) {
506
507
  }
507
508
  return chunks;
508
509
  }
509
- /** True when an error is an HTTP 429 (rate limited). */
510
- function isRateLimitError(error) {
511
- const status = error?.status ?? error?.statusCode ?? error?.response?.status;
512
- return status === 429;
510
+ // ── Single-shot retry wiring (PO CLI-latency directive, item 3) ──────────────
511
+ // These thin wrappers apply the shared withSingleShotRetry helper at the plain
512
+ // single-request SDK call sites. The idempotency flag is passed PER CALL SITE —
513
+ // that is the crux of the retry matrix, and it cannot be inferred centrally
514
+ // because the same SDK method (createMemory) serves BOTH single create (retry)
515
+ // and the batch --stdin-jsonl path (already retries via batchCreateWithRetry).
516
+ // Wrapping per single-shot site is therefore the correct, non-double-wrapping
517
+ // chokepoint; the batch helpers are left untouched.
518
+ /** STDERR-only retry notice. Never touches stdout, so `--format json` stays pure. */
519
+ function emitRetryNotice(info) {
520
+ const reason = info.status === 429 ? 'rate limited' : `transient error ${info.status ?? ''}`.trim();
521
+ console.error(chalk_1.default.dim(`⏳ ${reason}; retry ${info.attempt}/${info.maxRetries} in ${(info.waitMs / 1000).toFixed(1)}s`));
513
522
  }
514
523
  /**
515
- * Extract the server's Retry-After hint in milliseconds, or null if absent.
516
- * The API surfaces it as a body field (`retryAfter`, seconds) on 429s
517
- * (see lib/errors.ts) and may also send a Retry-After header; we honor both.
524
+ * Wrap an idempotent single-shot read (GET search/get/list/recall) or a
525
+ * naturally idempotent write (DELETE — deleting an already-deleted id is a
526
+ * no-op). Retries 429 and transient 5xx (502/503/504/408). Do NOT use this for
527
+ * named-memory PUT: it is a version bump that is only idempotent when
528
+ * expectedHeadId is supplied, and the CLI/SDK never supply it — use retryWrite.
518
529
  */
519
- function getRetryAfterMs(error) {
520
- const data = error?.data ?? error?.response?.data ?? {};
521
- const secs = data?.retryAfter ?? data?.retry_after;
522
- if (typeof secs === 'number' && Number.isFinite(secs) && secs >= 0) {
523
- return Math.round(secs * 1000);
524
- }
525
- const headers = error?.headers;
526
- let headerVal;
527
- if (headers) {
528
- if (typeof headers.get === 'function') {
529
- headerVal = headers.get('retry-after') ?? headers.get('Retry-After');
530
- }
531
- else {
532
- headerVal = headers['retry-after'] ?? headers['Retry-After'];
533
- }
534
- }
535
- if (headerVal) {
536
- const n = parseInt(String(headerVal), 10);
537
- if (Number.isFinite(n) && n >= 0)
538
- return n * 1000;
539
- }
540
- return null;
530
+ function retryRead(fn) {
531
+ return (0, retry_1.withSingleShotRetry)(fn, {
532
+ idempotent: true,
533
+ sleep: retry_1.sleep,
534
+ maxRetries: retry_1.SINGLE_SHOT_MAX_RETRIES,
535
+ onRetry: emitRetryNotice,
536
+ });
541
537
  }
542
- /** Promise-based sleep. Extracted so tests can inject a no-op/spy. */
543
- function sleep(ms) {
544
- return new Promise((resolve) => setTimeout(resolve, ms));
538
+ /**
539
+ * Wrap a non-idempotent single-shot write (plain POST create, non-CAS update).
540
+ * Retries ONLY 429 (server rejected before processing — no duplicate risk);
541
+ * a transient 5xx is NOT auto-retried because the write may already have landed.
542
+ */
543
+ function retryWrite(fn) {
544
+ return (0, retry_1.withSingleShotRetry)(fn, {
545
+ idempotent: false,
546
+ sleep: retry_1.sleep,
547
+ maxRetries: retry_1.SINGLE_SHOT_MAX_RETRIES,
548
+ onRetry: emitRetryNotice,
549
+ });
545
550
  }
546
551
  /**
547
552
  * Delete a single page, retrying on 429 up to `maxRetries` times. Honors the
@@ -556,8 +561,8 @@ async function bulkDeleteWithRetry(ids, deps) {
556
561
  return await deps.deleteFn(ids);
557
562
  }
558
563
  catch (error) {
559
- if (isRateLimitError(error) && attempt < maxRetries) {
560
- const waitMs = getRetryAfterMs(error) ?? defaultRetryMs * (attempt + 1);
564
+ if ((0, retry_1.isRateLimitError)(error) && attempt < maxRetries) {
565
+ const waitMs = (0, retry_1.getRetryAfterMs)(error) ?? defaultRetryMs * (attempt + 1);
561
566
  deps.onRateLimited?.(waitMs);
562
567
  await deps.sleep(waitMs);
563
568
  attempt++;
@@ -737,7 +742,7 @@ async function handleBatchDelete(rawIds, options, mode) {
737
742
  try {
738
743
  const result = await runBulkDeletePaged(resolvedIds, {
739
744
  deleteFn: bulkDeleteViaSdk,
740
- sleep,
745
+ sleep: retry_1.sleep,
741
746
  onPage: (i, total) => {
742
747
  if (total > 1 && !jsonMode) {
743
748
  spinner.text = `Deleting page ${i + 1} of ${total}...`;
@@ -841,19 +846,9 @@ exports.BATCH_CREATE_ALLOWED_KEYS = new Set([
841
846
  'outcome',
842
847
  'distill',
843
848
  ]);
844
- /** True when an error is an HTTP 503 (service unavailable — transient). */
845
- function isServiceUnavailableError(error) {
846
- const status = error?.status ?? error?.statusCode ?? error?.response?.status;
847
- return status === 503;
848
- }
849
849
  /** True when a create should be retried: 429 (rate limited) or 503 (transient). */
850
850
  function isRetryableCreateError(error) {
851
- return isRateLimitError(error) || isServiceUnavailableError(error);
852
- }
853
- /** True when an error is an HTTP 402 (quota / payment required). */
854
- function isQuotaError(error) {
855
- const status = error?.status ?? error?.statusCode ?? error?.response?.status;
856
- return status === 402;
851
+ return (0, retry_1.isRateLimitError)(error) || (0, retry_1.isServiceUnavailableError)(error);
857
852
  }
858
853
  /**
859
854
  * Parse and validate one JSONL line into a createMemory body.
@@ -990,10 +985,10 @@ async function batchCreateWithRetry(data, deps) {
990
985
  return await deps.createFn(data);
991
986
  }
992
987
  catch (error) {
993
- if (isQuotaError(error))
988
+ if ((0, retry_1.isQuotaError)(error))
994
989
  throw error;
995
990
  if (isRetryableCreateError(error) && attempt < maxRetries) {
996
- const waitMs = getRetryAfterMs(error) ?? defaultRetryMs * (attempt + 1);
991
+ const waitMs = (0, retry_1.getRetryAfterMs)(error) ?? defaultRetryMs * (attempt + 1);
997
992
  deps.onRateLimited?.(waitMs);
998
993
  await deps.sleep(waitMs);
999
994
  attempt++;
@@ -1087,7 +1082,7 @@ async function runBatchCreate(items, deps) {
1087
1082
  }
1088
1083
  catch (error) {
1089
1084
  summary.failed++;
1090
- if (isQuotaError(error)) {
1085
+ if ((0, retry_1.isQuotaError)(error)) {
1091
1086
  // Quota exhausted — pointless to keep hammering. Stop pulling new
1092
1087
  // lines; in-flight workers finish, remaining lines are not-attempted.
1093
1088
  stopped = true;
@@ -1253,7 +1248,7 @@ async function handleStreamingCreate(maxStdinBytes = exports.BATCH_CREATE_MAX_ST
1253
1248
  const claudeSessionId = claudeSession?.sessionId || undefined;
1254
1249
  const summary = await runBatchCreate(items, {
1255
1250
  createFn: (data) => createOneViaSdk(claudeSessionId ? { ...data, claudeSessionId } : data),
1256
- sleep,
1251
+ sleep: retry_1.sleep,
1257
1252
  concurrency,
1258
1253
  onResult: (r) => {
1259
1254
  // Pure JSONL on stdout — the ONLY stdout write on this path. A broken pipe
@@ -1319,7 +1314,7 @@ function registerMemoriesCommands(program) {
1319
1314
  // Named memories filter — fetch and filter client-side
1320
1315
  if (options.named) {
1321
1316
  const spinner = (0, spinner_1.createSpinner)('Fetching named memories...', options.format).start();
1322
- const namedResponse = await (0, api_client_1.getSdk)().memories.listMemories({ limit: 100, offset: 0 });
1317
+ const namedResponse = await retryRead(() => (0, api_client_1.getSdk)().memories.listMemories({ limit: 100, offset: 0 }));
1323
1318
  const namedMemories = (namedResponse.data?.data || []).filter((m) => m.name);
1324
1319
  spinner.succeed(`Found ${namedMemories.length} named memories`);
1325
1320
  if (options.format === 'table' || !options.format) {
@@ -1420,7 +1415,7 @@ function registerMemoriesCommands(program) {
1420
1415
  .filter((t) => t.length > 0)
1421
1416
  .join(',');
1422
1417
  }
1423
- const response = await (0, api_client_1.getSdk)().memories.listMemories(listParams);
1418
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.listMemories(listParams));
1424
1419
  const result = response.data;
1425
1420
  spinner.succeed(`Found ${result?.data?.length || 0} memories`);
1426
1421
  // Format for table display
@@ -1479,9 +1474,9 @@ function registerMemoriesCommands(program) {
1479
1474
  // Named memory lookup — short-circuits the entire ID-based flow
1480
1475
  if (options.name) {
1481
1476
  const spinner = (0, spinner_1.createSpinner)('Fetching named memory...', options.format).start();
1482
- const response = await (0, api_client_1.getSdk)().memories.getMemoryByName(options.name, {
1477
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.getMemoryByName(options.name, {
1483
1478
  detail: options.detail || 'standard',
1484
- });
1479
+ }));
1485
1480
  const memory = response.data?.data;
1486
1481
  if (!memory) {
1487
1482
  spinner.fail(`No memory found with name '${options.name}'`);
@@ -1521,9 +1516,9 @@ function registerMemoriesCommands(program) {
1521
1516
  if (isNamedKey) {
1522
1517
  const spinner = (0, spinner_1.createSpinner)('Fetching named memory...', options.format).start();
1523
1518
  try {
1524
- const response = await (0, api_client_1.getSdk)().memories.getMemoryByName(singleId, {
1519
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.getMemoryByName(singleId, {
1525
1520
  detail: options.detail || 'standard',
1526
- });
1521
+ }));
1527
1522
  const memory = response.data?.data;
1528
1523
  if (!memory) {
1529
1524
  spinner.fail(`No memory found with name '${singleId}'`);
@@ -1552,11 +1547,11 @@ function registerMemoriesCommands(program) {
1552
1547
  let resolvedMemory = null;
1553
1548
  if (isShortId) {
1554
1549
  const spinner = (0, spinner_1.createSpinner)('Searching for matching memory...', options.format).start();
1555
- const listResponse = await (0, api_client_1.getSdk)().memories.listMemories({
1550
+ const listResponse = await retryRead(() => (0, api_client_1.getSdk)().memories.listMemories({
1556
1551
  limit: 10,
1557
1552
  offset: 0,
1558
1553
  idPrefix: singleId,
1559
- });
1554
+ }));
1560
1555
  const matches = listResponse.data?.data || [];
1561
1556
  if (matches.length === 0) {
1562
1557
  spinner.fail(`No memory found with ID prefix: ${singleId}`);
@@ -1597,9 +1592,9 @@ function registerMemoriesCommands(program) {
1597
1592
  });
1598
1593
  }
1599
1594
  else {
1600
- const response = await (0, api_client_1.getSdk)().memories.getMemoryById(memoryId, {
1595
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.getMemoryById(memoryId, {
1601
1596
  detail,
1602
- });
1597
+ }));
1603
1598
  const memory = response.data?.data;
1604
1599
  printMemoryWithDetail(memory, options.format, {
1605
1600
  includeVectors: !!options.includeVectors,
@@ -1789,7 +1784,12 @@ function registerMemoriesCommands(program) {
1789
1784
  let response;
1790
1785
  let upserted = false;
1791
1786
  try {
1792
- response = await (0, api_client_1.getSdk)().memories.createMemory(memoryData);
1787
+ // Single create is non-idempotent → retryWrite (429-only: a rejected
1788
+ // 429 never reached processing, so a retry cannot duplicate the create;
1789
+ // a transient 5xx is NOT retried here to avoid a duplicate). A 409
1790
+ // (named already exists) is not retryable and falls through to the
1791
+ // auto-upsert branch below unchanged.
1792
+ response = await retryWrite(() => (0, api_client_1.getSdk)().memories.createMemory(memoryData));
1793
1793
  }
1794
1794
  catch (createError) {
1795
1795
  // 409 = named memory already exists → auto-upsert via updateNamedMemory
@@ -1811,7 +1811,15 @@ function registerMemoriesCommands(program) {
1811
1811
  // intentionally NOT forwarded here: it is applied uniformly for both the
1812
1812
  // create and upsert paths by the createMemoryRelationship call below, so
1813
1813
  // forwarding it in the body too would create a duplicate SUPERSEDES edge.
1814
- response = await (0, api_client_1.getSdk)().memories.updateNamedMemory(memoryData.name, {
1814
+ // Named update is NOT idempotent on this path: the CLI/SDK never
1815
+ // supply expectedHeadId, so PUT /named/:name does an UNCONDITIONAL
1816
+ // version bump (buildNamedVersionBumpCypher). retryWrite → 429-only:
1817
+ // the named-write gate acquires the permit BEFORE this.write, so a
1818
+ // 429 is pre-write and safe to retry; a 5xx is ambiguous (the bump
1819
+ // may already have committed — e.g. Kong 504 after Neo4j commits)
1820
+ // and MUST NOT be retried, or it silently creates a second identical
1821
+ // version (memory-history corruption).
1822
+ response = await retryWrite(() => (0, api_client_1.getSdk)().memories.updateNamedMemory(memoryData.name, {
1815
1823
  content: memoryData.content,
1816
1824
  ...(options.memoryType && { memoryType: options.memoryType }),
1817
1825
  ...(memoryData.topics && { topics: memoryData.topics }),
@@ -1825,7 +1833,7 @@ function registerMemoriesCommands(program) {
1825
1833
  options.conversationId.toUpperCase() !== 'NEW' && {
1826
1834
  conversationId: options.conversationId,
1827
1835
  }),
1828
- });
1836
+ }));
1829
1837
  upserted = true;
1830
1838
  }
1831
1839
  else {
@@ -1858,12 +1866,12 @@ function registerMemoriesCommands(program) {
1858
1866
  if (options.supersedes && memory?.id) {
1859
1867
  const relSpinner = (0, spinner_1.createSpinner)('Creating SUPERSEDES relationship...', options.format).start();
1860
1868
  try {
1861
- await (0, api_client_1.getSdk)().memories.createMemoryRelationship(memory.id, {
1869
+ await retryWrite(() => (0, api_client_1.getSdk)().memories.createMemoryRelationship(memory.id, {
1862
1870
  targetMemoryId: options.supersedes,
1863
1871
  type: 'SUPERSEDES',
1864
1872
  confidence: 1.0,
1865
1873
  reason: 'Created via --supersedes flag',
1866
- });
1874
+ }));
1867
1875
  relSpinner.succeed(`Relationship created: ${memory.id.substring(0, 8)}... SUPERSEDES ${options.supersedes.substring(0, 8)}...`);
1868
1876
  }
1869
1877
  catch (relError) {
@@ -1928,7 +1936,7 @@ function registerMemoriesCommands(program) {
1928
1936
  }
1929
1937
  updates.name = options.assignName;
1930
1938
  const spinner = (0, spinner_1.createSpinner)('Assigning name...', options.format).start();
1931
- const response = await (0, api_client_1.getSdk)().memories.updateMemory(id, updates);
1939
+ const response = await retryWrite(() => (0, api_client_1.getSdk)().memories.updateMemory(id, updates));
1932
1940
  const memory = response.data?.data;
1933
1941
  spinner.succeed(`Memory ${id} named '${options.assignName}'`);
1934
1942
  (0, formatters_1.printOutput)(memory, options.format);
@@ -1939,15 +1947,15 @@ function registerMemoriesCommands(program) {
1939
1947
  if (options.name) {
1940
1948
  // Look up current memory by name, then update its name
1941
1949
  const spinner = (0, spinner_1.createSpinner)('Renaming...', options.format).start();
1942
- const getResponse = await (0, api_client_1.getSdk)().memories.getMemoryByName(options.name);
1950
+ const getResponse = await retryRead(() => (0, api_client_1.getSdk)().memories.getMemoryByName(options.name));
1943
1951
  const currentMemory = getResponse.data?.data;
1944
1952
  if (!currentMemory?.id) {
1945
1953
  spinner.fail(`Named memory '${options.name}' not found`);
1946
1954
  return;
1947
1955
  }
1948
- const response = await (0, api_client_1.getSdk)().memories.updateMemory(currentMemory.id, {
1956
+ const response = await retryWrite(() => (0, api_client_1.getSdk)().memories.updateMemory(currentMemory.id, {
1949
1957
  name: options.rename,
1950
- });
1958
+ }));
1951
1959
  const memory = response.data?.data;
1952
1960
  spinner.succeed(`Named memory '${options.name}' renamed to '${options.rename}'`);
1953
1961
  (0, formatters_1.printOutput)(memory, options.format);
@@ -1956,7 +1964,7 @@ function registerMemoriesCommands(program) {
1956
1964
  if (id) {
1957
1965
  updates.name = options.rename;
1958
1966
  const spinner = (0, spinner_1.createSpinner)('Renaming...', options.format).start();
1959
- const response = await (0, api_client_1.getSdk)().memories.updateMemory(id, updates);
1967
+ const response = await retryWrite(() => (0, api_client_1.getSdk)().memories.updateMemory(id, updates));
1960
1968
  const memory = response.data?.data;
1961
1969
  spinner.succeed(`Memory ${id} renamed to '${options.rename}'`);
1962
1970
  (0, formatters_1.printOutput)(memory, options.format);
@@ -1972,7 +1980,13 @@ function registerMemoriesCommands(program) {
1972
1980
  // Named memory update — creates new version
1973
1981
  if (options.name) {
1974
1982
  const spinner = (0, spinner_1.createSpinner)('Creating new version...', options.format).start();
1975
- const response = await (0, api_client_1.getSdk)().memories.updateNamedMemory(options.name, updates);
1983
+ // Named update is NOT idempotent without expectedHeadId (which the
1984
+ // CLI/SDK never supply): PUT /named/:name unconditionally bumps the
1985
+ // version. retryWrite → 429-only: the gate takes the permit before the
1986
+ // write, so a 429 is pre-write and safe to retry; a 5xx is ambiguous
1987
+ // (the bump may already have committed) and MUST NOT be retried, or it
1988
+ // creates a second identical version (silent history corruption).
1989
+ const response = await retryWrite(() => (0, api_client_1.getSdk)().memories.updateNamedMemory(options.name, updates));
1976
1990
  const memory = response.data?.data;
1977
1991
  const meta = response.data?.meta;
1978
1992
  spinner.succeed(`Named memory '${options.name}' updated to v${meta?.version}`);
@@ -1983,7 +1997,7 @@ function registerMemoriesCommands(program) {
1983
1997
  return;
1984
1998
  }
1985
1999
  const spinner = (0, spinner_1.createSpinner)('Updating memory...', options.format).start();
1986
- const response = await (0, api_client_1.getSdk)().memories.updateMemory(id, updates);
2000
+ const response = await retryWrite(() => (0, api_client_1.getSdk)().memories.updateMemory(id, updates));
1987
2001
  const memory = response.data?.data;
1988
2002
  spinner.succeed(`Memory ${id} updated successfully`);
1989
2003
  (0, formatters_1.printOutput)(memory, options.format);
@@ -2004,7 +2018,7 @@ function registerMemoriesCommands(program) {
2004
2018
  .action(async (name, options) => {
2005
2019
  try {
2006
2020
  const spinner = (0, spinner_1.createSpinner)('Fetching version history...', options.format).start();
2007
- const response = await (0, api_client_1.getSdk)().memories.getNamedMemoryHistory(name);
2021
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.getNamedMemoryHistory(name));
2008
2022
  const data = response.data;
2009
2023
  if (!data?.versions?.length) {
2010
2024
  spinner.fail(`No memory found with name '${name}'`);
@@ -2205,7 +2219,9 @@ function registerMemoriesCommands(program) {
2205
2219
  }
2206
2220
  }
2207
2221
  const spinner = (0, spinner_1.createSpinner)('Deleting memory...', 'table').start();
2208
- await (0, api_client_1.getSdk)().memories.deleteMemory(id);
2222
+ // DELETE is idempotent (deleting an already-deleted id is a no-op), so a
2223
+ // transient 5xx is retry-safe as well as a 429.
2224
+ await retryRead(() => (0, api_client_1.getSdk)().memories.deleteMemory(id));
2209
2225
  // Record this deletion in the cross-process guard file so the next
2210
2226
  // invocation's threshold check reflects it.
2211
2227
  if (isNonInteractive) {
@@ -2426,7 +2442,7 @@ function registerMemoriesCommands(program) {
2426
2442
  searchRequest.order = options.order;
2427
2443
  }
2428
2444
  // Use GET endpoint for better performance (Issue #79)
2429
- const response = await (0, api_client_1.getSdk)().memories.searchMemoriesGet(searchRequest);
2445
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.searchMemoriesGet(searchRequest));
2430
2446
  const searchData = response.data;
2431
2447
  // Normalize: API may return flat objects or {memory, score} wrappers.
2432
2448
  // Ensure consistent {memory, score, matchedVia} shape for display code.
@@ -2844,19 +2860,19 @@ async function handleMemoryDiscovery(memoryId, options) {
2844
2860
  const sdk = (0, api_client_1.getSdk)();
2845
2861
  if (options.similar) {
2846
2862
  discoveryType = 'similar';
2847
- const response = await sdk.memories.getSimilarMemories(memoryId, { limit: options.limit });
2863
+ const response = await retryRead(() => sdk.memories.getSimilarMemories(memoryId, { limit: options.limit }));
2848
2864
  result = response.data;
2849
2865
  }
2850
2866
  else if (options.conversation) {
2851
2867
  discoveryType = 'conversation';
2852
- const response = await sdk.memories.getConversationMemories(memoryId, {
2868
+ const response = await retryRead(() => sdk.memories.getConversationMemories(memoryId, {
2853
2869
  limit: options.limit,
2854
- });
2870
+ }));
2855
2871
  result = response.data;
2856
2872
  }
2857
2873
  else if (options.related) {
2858
2874
  discoveryType = 'related';
2859
- const response = await sdk.memories.getRelatedMemories(memoryId, { limit: options.limit });
2875
+ const response = await retryRead(() => sdk.memories.getRelatedMemories(memoryId, { limit: options.limit }));
2860
2876
  result = response.data;
2861
2877
  }
2862
2878
  else {
@@ -2957,9 +2973,9 @@ function registerMemoryRelationshipCommands(memories) {
2957
2973
  return;
2958
2974
  }
2959
2975
  const spinner = (0, spinner_1.createSpinner)('Fetching relationships...', options.format).start();
2960
- const response = await (0, api_client_1.getSdk)().memories.getMemoryRelationships(id, {
2976
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.getMemoryRelationships(id, {
2961
2977
  direction: options.direction,
2962
- });
2978
+ }));
2963
2979
  const result = response.data;
2964
2980
  spinner.succeed(`Found ${result?.data?.length || 0} relationships`);
2965
2981
  if (options.format === 'table' || !options.format) {
@@ -3065,7 +3081,7 @@ function registerMemoryRelationshipCommands(memories) {
3065
3081
  };
3066
3082
  }
3067
3083
  const spinner = (0, spinner_1.createSpinner)('Creating relationship...', options.format).start();
3068
- const response = await (0, api_client_1.getSdk)().memories.createMemoryRelationship(id, relationshipData);
3084
+ const response = await retryWrite(() => (0, api_client_1.getSdk)().memories.createMemoryRelationship(id, relationshipData));
3069
3085
  const relationship = response.data?.data;
3070
3086
  spinner.succeed(`Relationship created: ${id} ${relationship?.type} ${relationshipData.targetMemoryId}`);
3071
3087
  (0, formatters_1.printOutput)(relationship, options.format);
@@ -3108,7 +3124,7 @@ function registerMemoryRelationshipCommands(memories) {
3108
3124
  }
3109
3125
  // Non-interactive without --force: auto-confirm single delete
3110
3126
  const spinner = (0, spinner_1.createSpinner)('Deleting relationship...', 'table').start();
3111
- await (0, api_client_1.getSdk)().memories.deleteMemoryRelationship(id, relationshipId);
3127
+ await retryRead(() => (0, api_client_1.getSdk)().memories.deleteMemoryRelationship(id, relationshipId));
3112
3128
  spinner.succeed(`Relationship ${relationshipId} deleted successfully`);
3113
3129
  }
3114
3130
  catch (error) {
@@ -3136,7 +3152,7 @@ function registerMemoryTimelineCommand(memories) {
3136
3152
  const before = parseInt(options.before, 10);
3137
3153
  const after = parseInt(options.after, 10);
3138
3154
  const spinner = (0, spinner_1.createSpinner)('Fetching timeline context...', options.format).start();
3139
- const response = await (0, api_client_1.getSdk)().memories.getMemoryTimeline(id, { before, after });
3155
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.getMemoryTimeline(id, { before, after }));
3140
3156
  const result = response.data;
3141
3157
  spinner.succeed('Timeline context retrieved');
3142
3158
  if (options.format === 'table' || !options.format) {
@@ -3199,12 +3215,14 @@ function registerDetectRelationshipsCommand(memories) {
3199
3215
  const spinner = (0, spinner_1.createSpinner)(options.autoCreate
3200
3216
  ? 'Detecting and creating relationships...'
3201
3217
  : 'Detecting relationships...', options.format).start();
3202
- const response = await (0, api_client_1.getSdk)().memories.detectMemoryRelationships(id, {
3218
+ // detect with --auto-create writes relationship edges, so it is
3219
+ // non-idempotent → retryWrite (429-only) to avoid duplicate edges on 5xx.
3220
+ const response = await retryWrite(() => (0, api_client_1.getSdk)().memories.detectMemoryRelationships(id, {
3203
3221
  body: {
3204
3222
  autoCreate: options.autoCreate || false,
3205
3223
  minConfidence,
3206
3224
  },
3207
- });
3225
+ }));
3208
3226
  const result = response.data;
3209
3227
  const suggestions = result?.data || [];
3210
3228
  spinner.succeed(`Found ${suggestions.length} potential relationships`);
@@ -3344,7 +3362,7 @@ function registerDigestCommand(memories) {
3344
3362
  sdk.config.timeoutMs = RECALL_MAX_MS;
3345
3363
  let response;
3346
3364
  try {
3347
- response = await sdk.memories.generateMemoryDigest(body);
3365
+ response = await retryRead(() => sdk.memories.generateMemoryDigest(body));
3348
3366
  }
3349
3367
  finally {
3350
3368
  if (sdk.config)
@@ -3433,7 +3451,7 @@ function registerStatusCommand(memories) {
3433
3451
  sdk.config.timeoutMs = 180000;
3434
3452
  let response;
3435
3453
  try {
3436
- response = await sdk.memories.generateMemoryDigest(body);
3454
+ response = await retryRead(() => sdk.memories.generateMemoryDigest(body));
3437
3455
  }
3438
3456
  finally {
3439
3457
  if (sdk.config)
@@ -3579,7 +3597,7 @@ function registerRecapCommand(memories) {
3579
3597
  };
3580
3598
  if (excludeTopicsParam)
3581
3599
  searchRequest.excludeTopics = excludeTopicsParam;
3582
- const response = await (0, api_client_1.getSdk)().memories.searchMemoriesGet(searchRequest);
3600
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.searchMemoriesGet(searchRequest));
3583
3601
  // Normalize: API may return flat objects or {memory, score} wrappers.
3584
3602
  results = (response.data?.data || []).map((r) => r.memory ? r : { memory: r, score: r.score, matchedVia: r.matchedVia });
3585
3603
  }
@@ -3595,7 +3613,7 @@ function registerRecapCommand(memories) {
3595
3613
  };
3596
3614
  if (excludeTopicsParam)
3597
3615
  listRequest.excludeTopics = excludeTopicsParam;
3598
- const response = await (0, api_client_1.getSdk)().memories.listMemories(listRequest);
3616
+ const response = await retryRead(() => (0, api_client_1.getSdk)().memories.listMemories(listRequest));
3599
3617
  // Wrap in search-result shape expected by groupByConversation / displayRecap
3600
3618
  results = (response.data?.data || []).map((m) => ({ memory: m }));
3601
3619
  }
@@ -3833,7 +3851,7 @@ function registerBuildContextCommand(memories) {
3833
3851
  body.files = options.files;
3834
3852
  }
3835
3853
  const sdk = (0, api_client_1.getSdk)();
3836
- const response = await sdk.memories.buildContext(body);
3854
+ const response = await retryRead(() => sdk.memories.buildContext(body));
3837
3855
  const data = response?.data || response;
3838
3856
  if (!data) {
3839
3857
  spinner.fail('No response data received');