claude-memory-layer 1.0.36 → 1.0.37

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.
@@ -1128,6 +1128,10 @@ var MemoryQueryService = class {
1128
1128
  await this.initialize();
1129
1129
  return this.getMaintenanceStore("getOutboxStats").getOutboxStats();
1130
1130
  }
1131
+ async recoverStuckOutboxItems(options) {
1132
+ await this.initialize();
1133
+ return this.getMaintenanceStore("recoverStuckOutboxItems").recoverStuckOutboxItems(options);
1134
+ }
1131
1135
  async getStats() {
1132
1136
  await this.initialize();
1133
1137
  const deps = this.getStatsDeps();
@@ -2046,6 +2050,14 @@ function normalizeQueryRewriteKind(value) {
2046
2050
  return "none";
2047
2051
  }
2048
2052
  var REWRITTEN_QUERY_REWRITE_KIND_SQL = `LOWER(TRIM(COALESCE(query_rewrite_kind, 'none'))) IN ('follow-up-context', 'intent-rewrite')`;
2053
+ var DEFAULT_OUTBOX_STUCK_THRESHOLD_MS = 5 * 60 * 1e3;
2054
+ var DEFAULT_OUTBOX_MAX_RETRIES = 3;
2055
+ function emptyOutboxRecoveryResult() {
2056
+ return {
2057
+ embedding: { recoveredProcessing: 0, retriedFailed: 0 },
2058
+ vector: { recoveredProcessing: 0, retriedFailed: 0 }
2059
+ };
2060
+ }
2049
2061
  var SQLiteEventStore = class {
2050
2062
  db;
2051
2063
  initialized = false;
@@ -2796,7 +2808,9 @@ var SQLiteEventStore = class {
2796
2808
  const placeholders = ids.map(() => "?").join(",");
2797
2809
  sqliteRun(
2798
2810
  this.db,
2799
- `UPDATE embedding_outbox SET status = 'processing' WHERE id IN (${placeholders})`,
2811
+ `UPDATE embedding_outbox
2812
+ SET status = 'processing', processed_at = datetime('now'), error_message = NULL
2813
+ WHERE id IN (${placeholders})`,
2800
2814
  ids
2801
2815
  );
2802
2816
  return pending.map((row) => ({
@@ -2866,6 +2880,58 @@ var SQLiteEventStore = class {
2866
2880
  [error, ...ids]
2867
2881
  );
2868
2882
  }
2883
+ /**
2884
+ * Recover abandoned outbox work after a worker/process crash.
2885
+ *
2886
+ * Rows in `processing` are claimed work. If the process exits before marking
2887
+ * them done/failed, they otherwise remain invisible to future processing.
2888
+ * Recovery is deliberately age-gated so an active worker is not disturbed.
2889
+ */
2890
+ async recoverStuckOutboxItems(options = {}) {
2891
+ await this.initialize();
2892
+ const thresholdMs = Number.isFinite(options.stuckThresholdMs) && (options.stuckThresholdMs ?? 0) >= 0 ? options.stuckThresholdMs : DEFAULT_OUTBOX_STUCK_THRESHOLD_MS;
2893
+ const maxRetries = Number.isFinite(options.maxRetries) && (options.maxRetries ?? 0) > 0 ? options.maxRetries : DEFAULT_OUTBOX_MAX_RETRIES;
2894
+ const now = options.now ?? /* @__PURE__ */ new Date();
2895
+ const threshold = new Date(now.getTime() - thresholdMs).toISOString();
2896
+ const result = emptyOutboxRecoveryResult();
2897
+ const embeddingRecovered = sqliteRun(
2898
+ this.db,
2899
+ `UPDATE embedding_outbox
2900
+ SET status = 'pending', processed_at = NULL, error_message = NULL
2901
+ WHERE status = 'processing'
2902
+ AND datetime(COALESCE(processed_at, created_at)) < datetime(?)`,
2903
+ [threshold]
2904
+ );
2905
+ result.embedding.recoveredProcessing = Number(embeddingRecovered.changes ?? 0);
2906
+ const embeddingRetried = sqliteRun(
2907
+ this.db,
2908
+ `UPDATE embedding_outbox
2909
+ SET status = 'pending', error_message = NULL
2910
+ WHERE status = 'failed'
2911
+ AND retry_count < ?`,
2912
+ [maxRetries]
2913
+ );
2914
+ result.embedding.retriedFailed = Number(embeddingRetried.changes ?? 0);
2915
+ const vectorRecovered = sqliteRun(
2916
+ this.db,
2917
+ `UPDATE vector_outbox
2918
+ SET status = 'pending', updated_at = ?, error = NULL
2919
+ WHERE status = 'processing'
2920
+ AND datetime(updated_at) < datetime(?)`,
2921
+ [now.toISOString(), threshold]
2922
+ );
2923
+ result.vector.recoveredProcessing = Number(vectorRecovered.changes ?? 0);
2924
+ const vectorRetried = sqliteRun(
2925
+ this.db,
2926
+ `UPDATE vector_outbox
2927
+ SET status = 'pending', updated_at = ?, error = NULL
2928
+ WHERE status = 'failed'
2929
+ AND retry_count < ?`,
2930
+ [now.toISOString(), maxRetries]
2931
+ );
2932
+ result.vector.retriedFailed = Number(vectorRetried.changes ?? 0);
2933
+ return result;
2934
+ }
2869
2935
  /**
2870
2936
  * Get embedding/vector outbox health statistics
2871
2937
  */
@@ -3737,6 +3803,7 @@ var VectorStore = class {
3737
3803
  * Get total count of vectors
3738
3804
  */
3739
3805
  async count() {
3806
+ await this.initialize();
3740
3807
  if (!this.table)
3741
3808
  return 0;
3742
3809
  const result = await this.table.countRows();