@massu/core 2.5.5 → 2.5.7

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.
@@ -2193,6 +2193,8 @@ __export(memory_db_exports, {
2193
2193
  MEMORY_FILE_TITLE_LIKE: () => MEMORY_FILE_TITLE_LIKE,
2194
2194
  MEMORY_FILE_TITLE_PREFIX: () => MEMORY_FILE_TITLE_PREFIX,
2195
2195
  MEMORY_SCHEMA_VERSION: () => MEMORY_SCHEMA_VERSION,
2196
+ PENDING_SYNC_MAX_AGE_DAYS: () => PENDING_SYNC_MAX_AGE_DAYS,
2197
+ PENDING_SYNC_MAX_ITEMS: () => PENDING_SYNC_MAX_ITEMS,
2196
2198
  TOOL_COST_EVENTS_RETENTION_DAYS: () => TOOL_COST_EVENTS_RETENTION_DAYS,
2197
2199
  USAGE_COUNTER_ARMED_KEY: () => USAGE_COUNTER_ARMED_KEY,
2198
2200
  addConversationTurn: () => addConversationTurn,
@@ -2201,6 +2203,7 @@ __export(memory_db_exports, {
2201
2203
  addSummary: () => addSummary,
2202
2204
  addToolCallDetail: () => addToolCallDetail,
2203
2205
  addUserPrompt: () => addUserPrompt,
2206
+ allPendingSync: () => allPendingSync,
2204
2207
  appendIncidentToFailureClass: () => appendIncidentToFailureClass,
2205
2208
  armUsageCounter: () => armUsageCounter,
2206
2209
  assignImportance: () => assignImportance,
@@ -2208,6 +2211,7 @@ __export(memory_db_exports, {
2208
2211
  createSession: () => createSession,
2209
2212
  deduplicateFailedAttempt: () => deduplicateFailedAttempt,
2210
2213
  dequeuePendingSync: () => dequeuePendingSync,
2214
+ discardPendingSync: () => discardPendingSync,
2211
2215
  embedMissingObservations: () => embedMissingObservations,
2212
2216
  endSession: () => endSession,
2213
2217
  enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
@@ -3190,6 +3194,35 @@ function initMemorySchema(db) {
3190
3194
  }
3191
3195
  function enqueueSyncPayload(db, payload) {
3192
3196
  db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
3197
+ const overflow = db.prepare(
3198
+ `SELECT id, retry_count, last_error, payload FROM pending_sync
3199
+ WHERE created_at < datetime('now', ?)
3200
+ OR id NOT IN (SELECT id FROM pending_sync ORDER BY created_at DESC, id DESC LIMIT ?)
3201
+ LIMIT 10000`
3202
+ ).all(`-${PENDING_SYNC_MAX_AGE_DAYS} days`, PENDING_SYNC_MAX_ITEMS);
3203
+ if (overflow.length > 0) {
3204
+ discardPendingSync(db, overflow, `over the queue limit (${PENDING_SYNC_MAX_ITEMS} items / ${PENDING_SYNC_MAX_AGE_DAYS} days)`);
3205
+ }
3206
+ }
3207
+ function discardPendingSync(db, rows, why) {
3208
+ if (rows.length === 0) return 0;
3209
+ const rescued = rescueLearningFromStalePayloads(db, rows);
3210
+ for (let i = 0; i < rows.length; i += 500) {
3211
+ const ids = rows.slice(i, i + 500).map((r) => r.id);
3212
+ db.prepare(`DELETE FROM pending_sync WHERE id IN (${ids.map(() => "?").join(",")})`).run(...ids);
3213
+ }
3214
+ if (rescued > 0) {
3215
+ process.stderr.write(
3216
+ `[massu] RESCUED ${rescued} learned rule(s) from ${rows.length} discarded payload(s) \u2014 they were re-queued for delivery, NOT discarded.
3217
+ `
3218
+ );
3219
+ }
3220
+ process.stderr.write(`[massu] cloud sync: discarded ${rows.length} queued upload(s): ${why}.
3221
+ `);
3222
+ return rows.length;
3223
+ }
3224
+ function allPendingSync(db) {
3225
+ return db.prepare("SELECT id, retry_count, last_error, payload FROM pending_sync").all();
3193
3226
  }
3194
3227
  function getMemoryMeta(db, key) {
3195
3228
  const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
@@ -3392,7 +3425,9 @@ function dequeuePendingSync(db, limit = 10) {
3392
3425
  }
3393
3426
  }
3394
3427
  return db.prepare(
3395
- "SELECT id, payload, retry_count FROM pending_sync ORDER BY created_at ASC LIMIT ?"
3428
+ // Least-retried first: oldest-first retried the same 10 items until they were discarded
3429
+ // while every newer item waited at retry 0 (2026-11-09: 43,492 never attempted).
3430
+ "SELECT id, payload, retry_count FROM pending_sync ORDER BY retry_count ASC, created_at ASC LIMIT ?"
3396
3431
  ).all(limit);
3397
3432
  }
3398
3433
  function removePendingSync(db, id) {
@@ -4065,7 +4100,7 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
4065
4100
  }
4066
4101
  return bestMatch;
4067
4102
  }
4068
- var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
4103
+ var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, PENDING_SYNC_MAX_ITEMS, PENDING_SYNC_MAX_AGE_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
4069
4104
  var init_memory_db = __esm({
4070
4105
  "src/memory-db.ts"() {
4071
4106
  "use strict";
@@ -4080,6 +4115,8 @@ var init_memory_db = __esm({
4080
4115
  init_memory_embed_sweep();
4081
4116
  MEMORY_SCHEMA_VERSION = 2;
4082
4117
  TOOL_COST_EVENTS_RETENTION_DAYS = 90;
4118
+ PENDING_SYNC_MAX_ITEMS = 500;
4119
+ PENDING_SYNC_MAX_AGE_DAYS = 30;
4083
4120
  MAX_DRAFT_TEXT_LEN = 16384;
4084
4121
  FUNNEL_EVENT_OUTBOX_CAP = 2e4;
4085
4122
  _temporalColCache = /* @__PURE__ */ new WeakMap();
@@ -4527,6 +4564,27 @@ init_config();
4527
4564
  init_memory_db();
4528
4565
 
4529
4566
  // src/lib/safe-write.ts
4567
+ import {
4568
+ writeFileSync as writeFileSync3,
4569
+ renameSync,
4570
+ openSync as openSync2,
4571
+ fsyncSync as fsyncSync2,
4572
+ closeSync as closeSync2,
4573
+ existsSync as existsSync9,
4574
+ realpathSync,
4575
+ unlinkSync as unlinkSync2,
4576
+ accessSync as accessSync2,
4577
+ statSync as statSync2,
4578
+ chmodSync as chmodSync3,
4579
+ constants
4580
+ } from "fs";
4581
+ function isSameRealPath(a, b) {
4582
+ try {
4583
+ return realpathSync(a) === realpathSync(b);
4584
+ } catch {
4585
+ return false;
4586
+ }
4587
+ }
4530
4588
  var SLUG_ALLOWED = /^[a-z0-9_]+$/;
4531
4589
  function deriveSlug(input) {
4532
4590
  const cleaned = input.toLowerCase().replace(/[^a-z0-9\s]+/g, " ").replace(/\s+/g, "_").replace(/^_+|_+$/g, "");
@@ -4639,15 +4697,20 @@ function writeHookContext(hookEventName, message) {
4639
4697
  // src/hooks/memory-recall.ts
4640
4698
  init_db_driver();
4641
4699
  init_hook_failure_signal();
4642
- import { existsSync as existsSync9 } from "fs";
4700
+ import { existsSync as existsSync10 } from "fs";
4643
4701
 
4644
4702
  // src/hooks/lib/is-direct-invocation.ts
4645
- import { pathToFileURL } from "url";
4703
+ import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
4646
4704
  function isDirectInvocation(moduleUrl) {
4647
4705
  const entry = process.argv[1];
4648
4706
  if (!entry) return false;
4649
4707
  try {
4650
- return moduleUrl === pathToFileURL(entry).href;
4708
+ if (moduleUrl === pathToFileURL(entry).href) return true;
4709
+ } catch {
4710
+ return false;
4711
+ }
4712
+ try {
4713
+ return isSameRealPath(fileURLToPath2(moduleUrl), entry);
4651
4714
  } catch {
4652
4715
  return false;
4653
4716
  }
@@ -4690,6 +4753,12 @@ function withTimeout(p, ms) {
4690
4753
  ]);
4691
4754
  }
4692
4755
  async function main() {
4756
+ if (process.argv.includes("--warm-cache")) {
4757
+ const r = await warmCache();
4758
+ process.stderr.write(`warm-cache: ${r}
4759
+ `);
4760
+ return void process.exit(0);
4761
+ }
4693
4762
  try {
4694
4763
  const input = await readStdin();
4695
4764
  if (!input.trim()) return void process.exit(0);
@@ -4724,7 +4793,7 @@ async function computeRecall(prompt, cfg, sessionId) {
4724
4793
  );
4725
4794
  memDb = getMemoryDb();
4726
4795
  const knowledgeDbPath = getResolvedPaths().knowledgeDbPath;
4727
- if (cfg.sources.includes("knowledge_chunk") && existsSync9(knowledgeDbPath)) {
4796
+ if (cfg.sources.includes("knowledge_chunk") && existsSync10(knowledgeDbPath)) {
4728
4797
  try {
4729
4798
  knowledgeDb = openDatabase2(knowledgeDbPath, { readonly: true, selfHeal: false });
4730
4799
  } catch {
@@ -4806,6 +4875,20 @@ function readStdin() {
4806
4875
  setTimeout(() => resolve5(data), 3e3);
4807
4876
  });
4808
4877
  }
4878
+ var WARM_CACHE_BUDGET_MS = 8e3;
4879
+ async function warmCache() {
4880
+ const timer = new Promise((resolve5) => setTimeout(() => resolve5(null), WARM_CACHE_BUDGET_MS).unref());
4881
+ try {
4882
+ const v = await Promise.race([embed("warm-up"), timer]);
4883
+ return v ? "ok" : "null";
4884
+ } catch {
4885
+ return "null";
4886
+ }
4887
+ }
4809
4888
  if (isDirectInvocation(import.meta.url)) {
4810
4889
  main();
4811
4890
  }
4891
+ export {
4892
+ WARM_CACHE_BUDGET_MS,
4893
+ warmCache
4894
+ };
@@ -2086,6 +2086,8 @@ __export(memory_db_exports, {
2086
2086
  MEMORY_FILE_TITLE_LIKE: () => MEMORY_FILE_TITLE_LIKE,
2087
2087
  MEMORY_FILE_TITLE_PREFIX: () => MEMORY_FILE_TITLE_PREFIX,
2088
2088
  MEMORY_SCHEMA_VERSION: () => MEMORY_SCHEMA_VERSION,
2089
+ PENDING_SYNC_MAX_AGE_DAYS: () => PENDING_SYNC_MAX_AGE_DAYS,
2090
+ PENDING_SYNC_MAX_ITEMS: () => PENDING_SYNC_MAX_ITEMS,
2089
2091
  TOOL_COST_EVENTS_RETENTION_DAYS: () => TOOL_COST_EVENTS_RETENTION_DAYS,
2090
2092
  USAGE_COUNTER_ARMED_KEY: () => USAGE_COUNTER_ARMED_KEY,
2091
2093
  addConversationTurn: () => addConversationTurn,
@@ -2094,6 +2096,7 @@ __export(memory_db_exports, {
2094
2096
  addSummary: () => addSummary,
2095
2097
  addToolCallDetail: () => addToolCallDetail,
2096
2098
  addUserPrompt: () => addUserPrompt,
2099
+ allPendingSync: () => allPendingSync,
2097
2100
  appendIncidentToFailureClass: () => appendIncidentToFailureClass,
2098
2101
  armUsageCounter: () => armUsageCounter,
2099
2102
  assignImportance: () => assignImportance,
@@ -2101,6 +2104,7 @@ __export(memory_db_exports, {
2101
2104
  createSession: () => createSession,
2102
2105
  deduplicateFailedAttempt: () => deduplicateFailedAttempt,
2103
2106
  dequeuePendingSync: () => dequeuePendingSync,
2107
+ discardPendingSync: () => discardPendingSync,
2104
2108
  embedMissingObservations: () => embedMissingObservations,
2105
2109
  endSession: () => endSession,
2106
2110
  enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
@@ -3083,6 +3087,35 @@ function initMemorySchema(db) {
3083
3087
  }
3084
3088
  function enqueueSyncPayload(db, payload) {
3085
3089
  db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
3090
+ const overflow = db.prepare(
3091
+ `SELECT id, retry_count, last_error, payload FROM pending_sync
3092
+ WHERE created_at < datetime('now', ?)
3093
+ OR id NOT IN (SELECT id FROM pending_sync ORDER BY created_at DESC, id DESC LIMIT ?)
3094
+ LIMIT 10000`
3095
+ ).all(`-${PENDING_SYNC_MAX_AGE_DAYS} days`, PENDING_SYNC_MAX_ITEMS);
3096
+ if (overflow.length > 0) {
3097
+ discardPendingSync(db, overflow, `over the queue limit (${PENDING_SYNC_MAX_ITEMS} items / ${PENDING_SYNC_MAX_AGE_DAYS} days)`);
3098
+ }
3099
+ }
3100
+ function discardPendingSync(db, rows, why) {
3101
+ if (rows.length === 0) return 0;
3102
+ const rescued = rescueLearningFromStalePayloads(db, rows);
3103
+ for (let i = 0; i < rows.length; i += 500) {
3104
+ const ids = rows.slice(i, i + 500).map((r) => r.id);
3105
+ db.prepare(`DELETE FROM pending_sync WHERE id IN (${ids.map(() => "?").join(",")})`).run(...ids);
3106
+ }
3107
+ if (rescued > 0) {
3108
+ process.stderr.write(
3109
+ `[massu] RESCUED ${rescued} learned rule(s) from ${rows.length} discarded payload(s) \u2014 they were re-queued for delivery, NOT discarded.
3110
+ `
3111
+ );
3112
+ }
3113
+ process.stderr.write(`[massu] cloud sync: discarded ${rows.length} queued upload(s): ${why}.
3114
+ `);
3115
+ return rows.length;
3116
+ }
3117
+ function allPendingSync(db) {
3118
+ return db.prepare("SELECT id, retry_count, last_error, payload FROM pending_sync").all();
3086
3119
  }
3087
3120
  function getMemoryMeta(db, key) {
3088
3121
  const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
@@ -3285,7 +3318,9 @@ function dequeuePendingSync(db, limit = 10) {
3285
3318
  }
3286
3319
  }
3287
3320
  return db.prepare(
3288
- "SELECT id, payload, retry_count FROM pending_sync ORDER BY created_at ASC LIMIT ?"
3321
+ // Least-retried first: oldest-first retried the same 10 items until they were discarded
3322
+ // while every newer item waited at retry 0 (2026-11-09: 43,492 never attempted).
3323
+ "SELECT id, payload, retry_count FROM pending_sync ORDER BY retry_count ASC, created_at ASC LIMIT ?"
3289
3324
  ).all(limit);
3290
3325
  }
3291
3326
  function removePendingSync(db, id) {
@@ -3958,7 +3993,7 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
3958
3993
  }
3959
3994
  return bestMatch;
3960
3995
  }
3961
- var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
3996
+ var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, PENDING_SYNC_MAX_ITEMS, PENDING_SYNC_MAX_AGE_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
3962
3997
  var init_memory_db = __esm({
3963
3998
  "src/memory-db.ts"() {
3964
3999
  "use strict";
@@ -3973,6 +4008,8 @@ var init_memory_db = __esm({
3973
4008
  init_memory_embed_sweep();
3974
4009
  MEMORY_SCHEMA_VERSION = 2;
3975
4010
  TOOL_COST_EVENTS_RETENTION_DAYS = 90;
4011
+ PENDING_SYNC_MAX_ITEMS = 500;
4012
+ PENDING_SYNC_MAX_AGE_DAYS = 30;
3976
4013
  MAX_DRAFT_TEXT_LEN = 16384;
3977
4014
  FUNNEL_EVENT_OUTBOX_CAP = 2e4;
3978
4015
  _temporalColCache = /* @__PURE__ */ new WeakMap();
@@ -4179,13 +4216,41 @@ function writeHookContext(hookEventName, message) {
4179
4216
  // src/hooks/post-edit-context.ts
4180
4217
  init_hook_failure_signal();
4181
4218
 
4219
+ // src/lib/safe-write.ts
4220
+ import {
4221
+ writeFileSync as writeFileSync3,
4222
+ renameSync,
4223
+ openSync as openSync2,
4224
+ fsyncSync as fsyncSync2,
4225
+ closeSync as closeSync2,
4226
+ existsSync as existsSync9,
4227
+ realpathSync,
4228
+ unlinkSync as unlinkSync2,
4229
+ accessSync as accessSync2,
4230
+ statSync as statSync2,
4231
+ chmodSync as chmodSync3,
4232
+ constants
4233
+ } from "fs";
4234
+ function isSameRealPath(a, b) {
4235
+ try {
4236
+ return realpathSync(a) === realpathSync(b);
4237
+ } catch {
4238
+ return false;
4239
+ }
4240
+ }
4241
+
4182
4242
  // src/hooks/lib/is-direct-invocation.ts
4183
- import { pathToFileURL } from "url";
4243
+ import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
4184
4244
  function isDirectInvocation(moduleUrl) {
4185
4245
  const entry = process.argv[1];
4186
4246
  if (!entry) return false;
4187
4247
  try {
4188
- return moduleUrl === pathToFileURL(entry).href;
4248
+ if (moduleUrl === pathToFileURL(entry).href) return true;
4249
+ } catch {
4250
+ return false;
4251
+ }
4252
+ try {
4253
+ return isSameRealPath(fileURLToPath2(moduleUrl), entry);
4189
4254
  } catch {
4190
4255
  return false;
4191
4256
  }
@@ -2163,6 +2163,8 @@ __export(memory_db_exports, {
2163
2163
  MEMORY_FILE_TITLE_LIKE: () => MEMORY_FILE_TITLE_LIKE,
2164
2164
  MEMORY_FILE_TITLE_PREFIX: () => MEMORY_FILE_TITLE_PREFIX,
2165
2165
  MEMORY_SCHEMA_VERSION: () => MEMORY_SCHEMA_VERSION,
2166
+ PENDING_SYNC_MAX_AGE_DAYS: () => PENDING_SYNC_MAX_AGE_DAYS,
2167
+ PENDING_SYNC_MAX_ITEMS: () => PENDING_SYNC_MAX_ITEMS,
2166
2168
  TOOL_COST_EVENTS_RETENTION_DAYS: () => TOOL_COST_EVENTS_RETENTION_DAYS,
2167
2169
  USAGE_COUNTER_ARMED_KEY: () => USAGE_COUNTER_ARMED_KEY,
2168
2170
  addConversationTurn: () => addConversationTurn,
@@ -2171,6 +2173,7 @@ __export(memory_db_exports, {
2171
2173
  addSummary: () => addSummary,
2172
2174
  addToolCallDetail: () => addToolCallDetail,
2173
2175
  addUserPrompt: () => addUserPrompt,
2176
+ allPendingSync: () => allPendingSync,
2174
2177
  appendIncidentToFailureClass: () => appendIncidentToFailureClass,
2175
2178
  armUsageCounter: () => armUsageCounter,
2176
2179
  assignImportance: () => assignImportance,
@@ -2178,6 +2181,7 @@ __export(memory_db_exports, {
2178
2181
  createSession: () => createSession,
2179
2182
  deduplicateFailedAttempt: () => deduplicateFailedAttempt,
2180
2183
  dequeuePendingSync: () => dequeuePendingSync,
2184
+ discardPendingSync: () => discardPendingSync,
2181
2185
  embedMissingObservations: () => embedMissingObservations,
2182
2186
  endSession: () => endSession,
2183
2187
  enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
@@ -3160,6 +3164,35 @@ function initMemorySchema(db) {
3160
3164
  }
3161
3165
  function enqueueSyncPayload(db, payload) {
3162
3166
  db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
3167
+ const overflow = db.prepare(
3168
+ `SELECT id, retry_count, last_error, payload FROM pending_sync
3169
+ WHERE created_at < datetime('now', ?)
3170
+ OR id NOT IN (SELECT id FROM pending_sync ORDER BY created_at DESC, id DESC LIMIT ?)
3171
+ LIMIT 10000`
3172
+ ).all(`-${PENDING_SYNC_MAX_AGE_DAYS} days`, PENDING_SYNC_MAX_ITEMS);
3173
+ if (overflow.length > 0) {
3174
+ discardPendingSync(db, overflow, `over the queue limit (${PENDING_SYNC_MAX_ITEMS} items / ${PENDING_SYNC_MAX_AGE_DAYS} days)`);
3175
+ }
3176
+ }
3177
+ function discardPendingSync(db, rows, why) {
3178
+ if (rows.length === 0) return 0;
3179
+ const rescued = rescueLearningFromStalePayloads(db, rows);
3180
+ for (let i = 0; i < rows.length; i += 500) {
3181
+ const ids = rows.slice(i, i + 500).map((r) => r.id);
3182
+ db.prepare(`DELETE FROM pending_sync WHERE id IN (${ids.map(() => "?").join(",")})`).run(...ids);
3183
+ }
3184
+ if (rescued > 0) {
3185
+ process.stderr.write(
3186
+ `[massu] RESCUED ${rescued} learned rule(s) from ${rows.length} discarded payload(s) \u2014 they were re-queued for delivery, NOT discarded.
3187
+ `
3188
+ );
3189
+ }
3190
+ process.stderr.write(`[massu] cloud sync: discarded ${rows.length} queued upload(s): ${why}.
3191
+ `);
3192
+ return rows.length;
3193
+ }
3194
+ function allPendingSync(db) {
3195
+ return db.prepare("SELECT id, retry_count, last_error, payload FROM pending_sync").all();
3163
3196
  }
3164
3197
  function getMemoryMeta(db, key) {
3165
3198
  const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
@@ -3362,7 +3395,9 @@ function dequeuePendingSync(db, limit = 10) {
3362
3395
  }
3363
3396
  }
3364
3397
  return db.prepare(
3365
- "SELECT id, payload, retry_count FROM pending_sync ORDER BY created_at ASC LIMIT ?"
3398
+ // Least-retried first: oldest-first retried the same 10 items until they were discarded
3399
+ // while every newer item waited at retry 0 (2026-11-09: 43,492 never attempted).
3400
+ "SELECT id, payload, retry_count FROM pending_sync ORDER BY retry_count ASC, created_at ASC LIMIT ?"
3366
3401
  ).all(limit);
3367
3402
  }
3368
3403
  function removePendingSync(db, id) {
@@ -4035,7 +4070,7 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
4035
4070
  }
4036
4071
  return bestMatch;
4037
4072
  }
4038
- var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
4073
+ var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, PENDING_SYNC_MAX_ITEMS, PENDING_SYNC_MAX_AGE_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
4039
4074
  var init_memory_db = __esm({
4040
4075
  "src/memory-db.ts"() {
4041
4076
  "use strict";
@@ -4050,6 +4085,8 @@ var init_memory_db = __esm({
4050
4085
  init_memory_embed_sweep();
4051
4086
  MEMORY_SCHEMA_VERSION = 2;
4052
4087
  TOOL_COST_EVENTS_RETENTION_DAYS = 90;
4088
+ PENDING_SYNC_MAX_ITEMS = 500;
4089
+ PENDING_SYNC_MAX_AGE_DAYS = 30;
4053
4090
  MAX_DRAFT_TEXT_LEN = 16384;
4054
4091
  FUNNEL_EVENT_OUTBOX_CAP = 2e4;
4055
4092
  _temporalColCache = /* @__PURE__ */ new WeakMap();
@@ -4864,7 +4901,7 @@ function storeSecurityScore(db, sessionId, filePath, riskScore, findings) {
4864
4901
 
4865
4902
  // src/hooks/post-tool-use.ts
4866
4903
  init_config();
4867
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync3, existsSync as existsSync13, mkdirSync as mkdirSync7, statSync as statSync3 } from "fs";
4904
+ import { readFileSync as readFileSync10, writeFileSync as writeFileSync4, existsSync as existsSync14, mkdirSync as mkdirSync7, statSync as statSync4 } from "fs";
4868
4905
  import { join as join7, basename as pathBasename2, dirname as pathDirname, resolve as pathResolve } from "path";
4869
4906
 
4870
4907
  // src/lib/recurrence-incrementer.ts
@@ -5121,13 +5158,41 @@ function mapMemoryTypeToObservationType(memoryType) {
5121
5158
  }
5122
5159
  }
5123
5160
 
5161
+ // src/lib/safe-write.ts
5162
+ import {
5163
+ writeFileSync as writeFileSync3,
5164
+ renameSync,
5165
+ openSync as openSync2,
5166
+ fsyncSync as fsyncSync2,
5167
+ closeSync as closeSync2,
5168
+ existsSync as existsSync13,
5169
+ realpathSync,
5170
+ unlinkSync as unlinkSync2,
5171
+ accessSync as accessSync2,
5172
+ statSync as statSync3,
5173
+ chmodSync as chmodSync3,
5174
+ constants
5175
+ } from "fs";
5176
+ function isSameRealPath(a, b) {
5177
+ try {
5178
+ return realpathSync(a) === realpathSync(b);
5179
+ } catch {
5180
+ return false;
5181
+ }
5182
+ }
5183
+
5124
5184
  // src/hooks/lib/is-direct-invocation.ts
5125
- import { pathToFileURL } from "url";
5185
+ import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
5126
5186
  function isDirectInvocation(moduleUrl) {
5127
5187
  const entry = process.argv[1];
5128
5188
  if (!entry) return false;
5129
5189
  try {
5130
- return moduleUrl === pathToFileURL(entry).href;
5190
+ if (moduleUrl === pathToFileURL(entry).href) return true;
5191
+ } catch {
5192
+ return false;
5193
+ }
5194
+ try {
5195
+ return isSameRealPath(fileURLToPath2(moduleUrl), entry);
5131
5196
  } catch {
5132
5197
  return false;
5133
5198
  }
@@ -5305,11 +5370,11 @@ async function main() {
5305
5370
  try {
5306
5371
  const projectRoot = process.cwd();
5307
5372
  const dir = join7(projectRoot, ".massu", "rule-candidates");
5308
- if (!existsSync13(dir)) mkdirSync7(dir, { recursive: true });
5373
+ if (!existsSync14(dir)) mkdirSync7(dir, { recursive: true });
5309
5374
  const logPath = join7(dir, ".cr53-increment-failures.jsonl");
5310
- const pre = existsSync13(logPath) ? readFileSync10(logPath, "utf-8") : "";
5375
+ const pre = existsSync14(logPath) ? readFileSync10(logPath, "utf-8") : "";
5311
5376
  const sep = pre && !pre.endsWith("\n") ? "\n" : "";
5312
- writeFileSync3(logPath, pre + sep + JSON.stringify({
5377
+ writeFileSync4(logPath, pre + sep + JSON.stringify({
5313
5378
  session_id,
5314
5379
  scanner_output_excerpt: (tool_response ?? "").slice(0, 200),
5315
5380
  error: err instanceof Error ? err.message : String(err),
@@ -5413,8 +5478,8 @@ function readConventions(cwd) {
5413
5478
  try {
5414
5479
  const projectRoot = cwd ?? process.cwd();
5415
5480
  const configPath = join7(projectRoot, "massu.config.yaml");
5416
- if (!existsSync13(configPath)) return _conventionDefaults;
5417
- const mtimeMs = statSync3(configPath).mtimeMs;
5481
+ if (!existsSync14(configPath)) return _conventionDefaults;
5482
+ const mtimeMs = statSync4(configPath).mtimeMs;
5418
5483
  if (_cachedConventions !== null && _cachedConventionsPath === configPath && _cachedConventionsMtimeMs === mtimeMs) {
5419
5484
  return _cachedConventions;
5420
5485
  }
@@ -5450,7 +5515,7 @@ function isKnowledgeSourceFile(filePath) {
5450
5515
  function checkMemoryFileIntegrity(filePath) {
5451
5516
  const issues = [];
5452
5517
  try {
5453
- if (!existsSync13(filePath)) {
5518
+ if (!existsSync14(filePath)) {
5454
5519
  issues.push("MEMORY.md file does not exist after write");
5455
5520
  return issues;
5456
5521
  }
@@ -2157,6 +2157,8 @@ __export(memory_db_exports, {
2157
2157
  MEMORY_FILE_TITLE_LIKE: () => MEMORY_FILE_TITLE_LIKE,
2158
2158
  MEMORY_FILE_TITLE_PREFIX: () => MEMORY_FILE_TITLE_PREFIX,
2159
2159
  MEMORY_SCHEMA_VERSION: () => MEMORY_SCHEMA_VERSION,
2160
+ PENDING_SYNC_MAX_AGE_DAYS: () => PENDING_SYNC_MAX_AGE_DAYS,
2161
+ PENDING_SYNC_MAX_ITEMS: () => PENDING_SYNC_MAX_ITEMS,
2160
2162
  TOOL_COST_EVENTS_RETENTION_DAYS: () => TOOL_COST_EVENTS_RETENTION_DAYS,
2161
2163
  USAGE_COUNTER_ARMED_KEY: () => USAGE_COUNTER_ARMED_KEY,
2162
2164
  addConversationTurn: () => addConversationTurn,
@@ -2165,6 +2167,7 @@ __export(memory_db_exports, {
2165
2167
  addSummary: () => addSummary,
2166
2168
  addToolCallDetail: () => addToolCallDetail,
2167
2169
  addUserPrompt: () => addUserPrompt,
2170
+ allPendingSync: () => allPendingSync,
2168
2171
  appendIncidentToFailureClass: () => appendIncidentToFailureClass,
2169
2172
  armUsageCounter: () => armUsageCounter,
2170
2173
  assignImportance: () => assignImportance,
@@ -2172,6 +2175,7 @@ __export(memory_db_exports, {
2172
2175
  createSession: () => createSession,
2173
2176
  deduplicateFailedAttempt: () => deduplicateFailedAttempt,
2174
2177
  dequeuePendingSync: () => dequeuePendingSync,
2178
+ discardPendingSync: () => discardPendingSync,
2175
2179
  embedMissingObservations: () => embedMissingObservations,
2176
2180
  endSession: () => endSession,
2177
2181
  enqueueRulePromotionEvent: () => enqueueRulePromotionEvent,
@@ -3154,6 +3158,35 @@ function initMemorySchema(db) {
3154
3158
  }
3155
3159
  function enqueueSyncPayload(db, payload) {
3156
3160
  db.prepare("INSERT INTO pending_sync (payload) VALUES (?)").run(payload);
3161
+ const overflow = db.prepare(
3162
+ `SELECT id, retry_count, last_error, payload FROM pending_sync
3163
+ WHERE created_at < datetime('now', ?)
3164
+ OR id NOT IN (SELECT id FROM pending_sync ORDER BY created_at DESC, id DESC LIMIT ?)
3165
+ LIMIT 10000`
3166
+ ).all(`-${PENDING_SYNC_MAX_AGE_DAYS} days`, PENDING_SYNC_MAX_ITEMS);
3167
+ if (overflow.length > 0) {
3168
+ discardPendingSync(db, overflow, `over the queue limit (${PENDING_SYNC_MAX_ITEMS} items / ${PENDING_SYNC_MAX_AGE_DAYS} days)`);
3169
+ }
3170
+ }
3171
+ function discardPendingSync(db, rows, why) {
3172
+ if (rows.length === 0) return 0;
3173
+ const rescued = rescueLearningFromStalePayloads(db, rows);
3174
+ for (let i = 0; i < rows.length; i += 500) {
3175
+ const ids = rows.slice(i, i + 500).map((r) => r.id);
3176
+ db.prepare(`DELETE FROM pending_sync WHERE id IN (${ids.map(() => "?").join(",")})`).run(...ids);
3177
+ }
3178
+ if (rescued > 0) {
3179
+ process.stderr.write(
3180
+ `[massu] RESCUED ${rescued} learned rule(s) from ${rows.length} discarded payload(s) \u2014 they were re-queued for delivery, NOT discarded.
3181
+ `
3182
+ );
3183
+ }
3184
+ process.stderr.write(`[massu] cloud sync: discarded ${rows.length} queued upload(s): ${why}.
3185
+ `);
3186
+ return rows.length;
3187
+ }
3188
+ function allPendingSync(db) {
3189
+ return db.prepare("SELECT id, retry_count, last_error, payload FROM pending_sync").all();
3157
3190
  }
3158
3191
  function getMemoryMeta(db, key) {
3159
3192
  const row = db.prepare("SELECT value FROM memory_meta WHERE key = ?").get(key);
@@ -3356,7 +3389,9 @@ function dequeuePendingSync(db, limit = 10) {
3356
3389
  }
3357
3390
  }
3358
3391
  return db.prepare(
3359
- "SELECT id, payload, retry_count FROM pending_sync ORDER BY created_at ASC LIMIT ?"
3392
+ // Least-retried first: oldest-first retried the same 10 items until they were discarded
3393
+ // while every newer item waited at retry 0 (2026-11-09: 43,492 never attempted).
3394
+ "SELECT id, payload, retry_count FROM pending_sync ORDER BY retry_count ASC, created_at ASC LIMIT ?"
3360
3395
  ).all(limit);
3361
3396
  }
3362
3397
  function removePendingSync(db, id) {
@@ -4029,7 +4064,7 @@ function scoreFailureClasses(db, matchText, filePath, promptContext, weights) {
4029
4064
  }
4030
4065
  return bestMatch;
4031
4066
  }
4032
- var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
4067
+ var MEMORY_SCHEMA_VERSION, TOOL_COST_EVENTS_RETENTION_DAYS, PENDING_SYNC_MAX_ITEMS, PENDING_SYNC_MAX_AGE_DAYS, MAX_DRAFT_TEXT_LEN, FUNNEL_EVENT_OUTBOX_CAP, _temporalColCache, CONSOLIDATION_LESSON_EVIDENCE, MEMORY_FILE_TITLE_PREFIX, MEMORY_FILE_TITLE_LIKE, USAGE_COUNTER_ARMED_KEY;
4033
4068
  var init_memory_db = __esm({
4034
4069
  "src/memory-db.ts"() {
4035
4070
  "use strict";
@@ -4044,6 +4079,8 @@ var init_memory_db = __esm({
4044
4079
  init_memory_embed_sweep();
4045
4080
  MEMORY_SCHEMA_VERSION = 2;
4046
4081
  TOOL_COST_EVENTS_RETENTION_DAYS = 90;
4082
+ PENDING_SYNC_MAX_ITEMS = 500;
4083
+ PENDING_SYNC_MAX_AGE_DAYS = 30;
4047
4084
  MAX_DRAFT_TEXT_LEN = 16384;
4048
4085
  FUNNEL_EVENT_OUTBOX_CAP = 2e4;
4049
4086
  _temporalColCache = /* @__PURE__ */ new WeakMap();
@@ -4080,13 +4117,41 @@ function logAuditEntry(db, entry) {
4080
4117
  // src/hooks/pre-compact.ts
4081
4118
  init_hook_failure_signal();
4082
4119
 
4120
+ // src/lib/safe-write.ts
4121
+ import {
4122
+ writeFileSync as writeFileSync3,
4123
+ renameSync,
4124
+ openSync as openSync2,
4125
+ fsyncSync as fsyncSync2,
4126
+ closeSync as closeSync2,
4127
+ existsSync as existsSync9,
4128
+ realpathSync,
4129
+ unlinkSync as unlinkSync2,
4130
+ accessSync as accessSync2,
4131
+ statSync as statSync2,
4132
+ chmodSync as chmodSync3,
4133
+ constants
4134
+ } from "fs";
4135
+ function isSameRealPath(a, b) {
4136
+ try {
4137
+ return realpathSync(a) === realpathSync(b);
4138
+ } catch {
4139
+ return false;
4140
+ }
4141
+ }
4142
+
4083
4143
  // src/hooks/lib/is-direct-invocation.ts
4084
- import { pathToFileURL } from "url";
4144
+ import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
4085
4145
  function isDirectInvocation(moduleUrl) {
4086
4146
  const entry = process.argv[1];
4087
4147
  if (!entry) return false;
4088
4148
  try {
4089
- return moduleUrl === pathToFileURL(entry).href;
4149
+ if (moduleUrl === pathToFileURL(entry).href) return true;
4150
+ } catch {
4151
+ return false;
4152
+ }
4153
+ try {
4154
+ return isSameRealPath(fileURLToPath2(moduleUrl), entry);
4090
4155
  } catch {
4091
4156
  return false;
4092
4157
  }