@monoes/monomindcli 2.9.3 → 2.9.4

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 (189) hide show
  1. package/.claude/helpers/intelligence.cjs +27 -6
  2. package/.claude/skills/agentic-jujutsu/SKILL.md +17 -15
  3. package/.claude/skills/hive-mind-advanced/SKILL.md +212 -559
  4. package/.claude/skills/hooks-automation/SKILL.md +1 -1
  5. package/.claude/skills/mastermind-createorg/SKILL.md +2 -1
  6. package/.claude/skills/pair-programming/SKILL.md +1 -1
  7. package/.claude/skills/performance-analysis/SKILL.md +228 -484
  8. package/.claude/skills/swarm-advanced/SKILL.md +2 -2
  9. package/.claude/skills/swarm-orchestration/SKILL.md +220 -150
  10. package/.claude/skills/verification-quality/SKILL.md +247 -571
  11. package/README.md +6 -2
  12. package/dist/src/autopilot-state.d.ts +16 -4
  13. package/dist/src/autopilot-state.d.ts.map +1 -1
  14. package/dist/src/autopilot-state.js +42 -19
  15. package/dist/src/autopilot-state.js.map +1 -1
  16. package/dist/src/commands/agent-lifecycle.js +3 -3
  17. package/dist/src/commands/agent-lifecycle.js.map +1 -1
  18. package/dist/src/commands/autopilot.d.ts.map +1 -1
  19. package/dist/src/commands/autopilot.js +113 -26
  20. package/dist/src/commands/autopilot.js.map +1 -1
  21. package/dist/src/commands/doc.d.ts.map +1 -1
  22. package/dist/src/commands/doc.js +14 -3
  23. package/dist/src/commands/doc.js.map +1 -1
  24. package/dist/src/commands/doctor-env-checks.d.ts +1 -1
  25. package/dist/src/commands/doctor-env-checks.d.ts.map +1 -1
  26. package/dist/src/commands/doctor.d.ts.map +1 -1
  27. package/dist/src/commands/doctor.js +30 -1
  28. package/dist/src/commands/doctor.js.map +1 -1
  29. package/dist/src/commands/hooks-routing-commands.d.ts.map +1 -1
  30. package/dist/src/commands/hooks-routing-commands.js +12 -26
  31. package/dist/src/commands/hooks-routing-commands.js.map +1 -1
  32. package/dist/src/commands/hooks-workers.js +8 -8
  33. package/dist/src/commands/hooks-workers.js.map +1 -1
  34. package/dist/src/commands/hooks.d.ts.map +1 -1
  35. package/dist/src/commands/hooks.js +96 -54
  36. package/dist/src/commands/hooks.js.map +1 -1
  37. package/dist/src/commands/init.d.ts.map +1 -1
  38. package/dist/src/commands/init.js +80 -7
  39. package/dist/src/commands/init.js.map +1 -1
  40. package/dist/src/commands/mcp.d.ts.map +1 -1
  41. package/dist/src/commands/mcp.js +78 -2
  42. package/dist/src/commands/mcp.js.map +1 -1
  43. package/dist/src/commands/memory-list.d.ts.map +1 -1
  44. package/dist/src/commands/memory-list.js +79 -36
  45. package/dist/src/commands/memory-list.js.map +1 -1
  46. package/dist/src/commands/org.d.ts.map +1 -1
  47. package/dist/src/commands/org.js +114 -1
  48. package/dist/src/commands/org.js.map +1 -1
  49. package/dist/src/commands/performance.js +1 -1
  50. package/dist/src/commands/performance.js.map +1 -1
  51. package/dist/src/commands/swarm.d.ts.map +1 -1
  52. package/dist/src/commands/swarm.js +144 -98
  53. package/dist/src/commands/swarm.js.map +1 -1
  54. package/dist/src/init/claudemd-generator.js +1 -1
  55. package/dist/src/init/executor.d.ts.map +1 -1
  56. package/dist/src/init/executor.js +13 -3
  57. package/dist/src/init/executor.js.map +1 -1
  58. package/dist/src/init/kimi-generator.d.ts +3 -2
  59. package/dist/src/init/kimi-generator.d.ts.map +1 -1
  60. package/dist/src/init/kimi-generator.js +45 -13
  61. package/dist/src/init/kimi-generator.js.map +1 -1
  62. package/dist/src/init/statusline-generator.d.ts +1 -1
  63. package/dist/src/init/statusline-generator.d.ts.map +1 -1
  64. package/dist/src/init/statusline-generator.js +48 -46
  65. package/dist/src/init/statusline-generator.js.map +1 -1
  66. package/dist/src/init/types.d.ts +1 -1
  67. package/dist/src/init/types.d.ts.map +1 -1
  68. package/dist/src/init/types.js +5 -1
  69. package/dist/src/init/types.js.map +1 -1
  70. package/dist/src/mcp-server.d.ts +6 -0
  71. package/dist/src/mcp-server.d.ts.map +1 -1
  72. package/dist/src/mcp-server.js +47 -22
  73. package/dist/src/mcp-server.js.map +1 -1
  74. package/dist/src/mcp-tools/hive-mind-tools.d.ts.map +1 -1
  75. package/dist/src/mcp-tools/hive-mind-tools.js +13 -11
  76. package/dist/src/mcp-tools/hive-mind-tools.js.map +1 -1
  77. package/dist/src/mcp-tools/hooks-intelligence.d.ts.map +1 -1
  78. package/dist/src/mcp-tools/hooks-intelligence.js +97 -40
  79. package/dist/src/mcp-tools/hooks-intelligence.js.map +1 -1
  80. package/dist/src/mcp-tools/hooks-routing.d.ts.map +1 -1
  81. package/dist/src/mcp-tools/hooks-routing.js +406 -205
  82. package/dist/src/mcp-tools/hooks-routing.js.map +1 -1
  83. package/dist/src/mcp-tools/monograph/impact-tools.d.ts.map +1 -1
  84. package/dist/src/mcp-tools/monograph/impact-tools.js +109 -44
  85. package/dist/src/mcp-tools/monograph/impact-tools.js.map +1 -1
  86. package/dist/src/mcp-tools/monograph/query-tools.d.ts.map +1 -1
  87. package/dist/src/mcp-tools/monograph/query-tools.js +48 -18
  88. package/dist/src/mcp-tools/monograph/query-tools.js.map +1 -1
  89. package/dist/src/mcp-tools/system-tools.d.ts.map +1 -1
  90. package/dist/src/mcp-tools/system-tools.js +100 -38
  91. package/dist/src/mcp-tools/system-tools.js.map +1 -1
  92. package/dist/src/memory/embedding-operations.d.ts +4 -0
  93. package/dist/src/memory/embedding-operations.d.ts.map +1 -1
  94. package/dist/src/memory/embedding-operations.js +125 -32
  95. package/dist/src/memory/embedding-operations.js.map +1 -1
  96. package/dist/src/memory/hnsw-operations.d.ts +1 -1
  97. package/dist/src/memory/hnsw-operations.js +1 -1
  98. package/dist/src/memory/memory-bridge.d.ts.map +1 -1
  99. package/dist/src/memory/memory-bridge.js +172 -69
  100. package/dist/src/memory/memory-bridge.js.map +1 -1
  101. package/dist/src/memory/memory-read.d.ts +1 -1
  102. package/dist/src/memory/memory-read.js +2 -2
  103. package/dist/src/memory/memory-read.js.map +1 -1
  104. package/dist/src/orgrt/checkpoint-ops.d.ts +11 -1
  105. package/dist/src/orgrt/checkpoint-ops.d.ts.map +1 -1
  106. package/dist/src/orgrt/checkpoint-ops.js +15 -1
  107. package/dist/src/orgrt/checkpoint-ops.js.map +1 -1
  108. package/dist/src/orgrt/checkpoint.js +1 -1
  109. package/dist/src/orgrt/checkpoint.js.map +1 -1
  110. package/dist/src/orgrt/daemon.d.ts +11 -3
  111. package/dist/src/orgrt/daemon.d.ts.map +1 -1
  112. package/dist/src/orgrt/daemon.js +317 -93
  113. package/dist/src/orgrt/daemon.js.map +1 -1
  114. package/dist/src/orgrt/decisions.d.ts +13 -0
  115. package/dist/src/orgrt/decisions.d.ts.map +1 -1
  116. package/dist/src/orgrt/decisions.js +95 -0
  117. package/dist/src/orgrt/decisions.js.map +1 -1
  118. package/dist/src/orgrt/remote.d.ts.map +1 -1
  119. package/dist/src/orgrt/remote.js +12 -6
  120. package/dist/src/orgrt/remote.js.map +1 -1
  121. package/dist/src/orgrt/server.d.ts.map +1 -1
  122. package/dist/src/orgrt/server.js +71 -14
  123. package/dist/src/orgrt/server.js.map +1 -1
  124. package/dist/src/orgrt/session.d.ts +27 -1
  125. package/dist/src/orgrt/session.d.ts.map +1 -1
  126. package/dist/src/orgrt/session.js +42 -3
  127. package/dist/src/orgrt/session.js.map +1 -1
  128. package/dist/src/orgrt/task-dag.d.ts +11 -1
  129. package/dist/src/orgrt/task-dag.d.ts.map +1 -1
  130. package/dist/src/orgrt/task-dag.js +93 -2
  131. package/dist/src/orgrt/task-dag.js.map +1 -1
  132. package/dist/src/orgrt/templates.d.ts.map +1 -1
  133. package/dist/src/orgrt/templates.js +24 -0
  134. package/dist/src/orgrt/templates.js.map +1 -1
  135. package/dist/src/orgrt/types.d.ts +70 -1
  136. package/dist/src/orgrt/types.d.ts.map +1 -1
  137. package/dist/src/orgrt/types.js +19 -0
  138. package/dist/src/orgrt/types.js.map +1 -1
  139. package/dist/src/orgrt/vercel-providers.d.ts.map +1 -1
  140. package/dist/src/orgrt/vercel-providers.js +9 -4
  141. package/dist/src/orgrt/vercel-providers.js.map +1 -1
  142. package/dist/src/orgrt/vercel-runner.d.ts +0 -23
  143. package/dist/src/orgrt/vercel-runner.d.ts.map +1 -1
  144. package/dist/src/orgrt/vercel-runner.js +26 -1
  145. package/dist/src/orgrt/vercel-runner.js.map +1 -1
  146. package/dist/src/types.d.ts +1 -1
  147. package/dist/src/types.d.ts.map +1 -1
  148. package/dist/src/ui/server.mjs +2647 -838
  149. package/dist/tsconfig.tsbuildinfo +1 -1
  150. package/package.json +7 -7
  151. package/.claude/commands/mastermind/approvev1.md +0 -94
  152. package/.claude/commands/mastermind/architect.md +0 -52
  153. package/.claude/commands/mastermind/autodev.md +0 -28
  154. package/.claude/commands/mastermind/build.md +0 -23
  155. package/.claude/commands/mastermind/finish.md +0 -17
  156. package/.claude/commands/mastermind/runorgv1.md +0 -159
  157. package/.claude/commands/mastermind/taskdev.md +0 -23
  158. package/.claude/commands/mastermind/tdd.md +0 -19
  159. package/.claude/commands/mastermind/verify.md +0 -19
  160. package/.claude/skills/mastermind-approvev1/SKILL.md +0 -191
  161. package/.claude/skills/mastermind-architect/SKILL.md +0 -862
  162. package/.claude/skills/mastermind-autodev/SKILL.md +0 -360
  163. package/.claude/skills/mastermind-build/SKILL.md +0 -169
  164. package/.claude/skills/mastermind-companies/SKILL.md +0 -256
  165. package/.claude/skills/mastermind-content/SKILL.md +0 -197
  166. package/.claude/skills/mastermind-costs/SKILL.md +0 -151
  167. package/.claude/skills/mastermind-finance/SKILL.md +0 -166
  168. package/.claude/skills/mastermind-finish/SKILL.md +0 -251
  169. package/.claude/skills/mastermind-heartbeatv1/SKILL.md +0 -167
  170. package/.claude/skills/mastermind-instance-settings/SKILL.md +0 -315
  171. package/.claude/skills/mastermind-marketing/SKILL.md +0 -228
  172. package/.claude/skills/mastermind-marketing/references/copywriting-frameworks.md +0 -181
  173. package/.claude/skills/mastermind-marketing/references/persuasion-psychology.md +0 -158
  174. package/.claude/skills/mastermind-ops/SKILL.md +0 -168
  175. package/.claude/skills/mastermind-org-chart/SKILL.md +0 -209
  176. package/.claude/skills/mastermind-project-detail/SKILL.md +0 -249
  177. package/.claude/skills/mastermind-project-workspace/SKILL.md +0 -244
  178. package/.claude/skills/mastermind-projects/SKILL.md +0 -167
  179. package/.claude/skills/mastermind-runorgv1/SKILL.md +0 -731
  180. package/.claude/skills/mastermind-sales/SKILL.md +0 -170
  181. package/.claude/skills/mastermind-taskdev/SKILL.md +0 -377
  182. package/.claude/skills/mastermind-taskdev/code-quality-reviewer-prompt.md +0 -60
  183. package/.claude/skills/mastermind-taskdev/final-reviewer-prompt.md +0 -144
  184. package/.claude/skills/mastermind-taskdev/implementer-prompt.md +0 -114
  185. package/.claude/skills/mastermind-taskdev/spec-reviewer-prompt.md +0 -80
  186. package/.claude/skills/mastermind-tdd/SKILL.md +0 -424
  187. package/.claude/skills/mastermind-verify/SKILL.md +0 -196
  188. package/.claude/skills/mastermind-wiki/SKILL.md +0 -314
  189. package/.claude/skills/monolean-review/SKILL.md +0 -57
@@ -39,7 +39,8 @@ export function safeParseEmbedding(raw) {
39
39
  try {
40
40
  parsed = JSON.parse(raw);
41
41
  }
42
- catch {
42
+ catch (e) {
43
+ logBridgeError('safeParseEmbedding', e);
43
44
  return null;
44
45
  }
45
46
  if (!Array.isArray(parsed))
@@ -65,7 +66,8 @@ const MAX_TAG_LEN = 64;
65
66
  const BRIDGE_RESULT_CONTENT_CAP = 500;
66
67
  function capResultContent(content) {
67
68
  return content.length > BRIDGE_RESULT_CONTENT_CAP
68
- ? content.slice(0, BRIDGE_RESULT_CONTENT_CAP) + '…' : content;
69
+ ? content.slice(0, BRIDGE_RESULT_CONTENT_CAP) + '…'
70
+ : content;
69
71
  }
70
72
  // ===== DB path resolution =====
71
73
  // LanceDB commits via atomic rename, which exFAT/SMB project volumes don't support
@@ -88,7 +90,9 @@ function walkToProjectRoot(start) {
88
90
  if (fs.existsSync(path.join(dir, '.monomind')) || fs.existsSync(path.join(dir, '.git')))
89
91
  return dir;
90
92
  }
91
- catch { /* unreadable dir — keep walking */ }
93
+ catch (e) {
94
+ logBridgeError('walkToProjectRoot', e); /* unreadable dir — keep walking */
95
+ }
92
96
  const parent = path.dirname(dir);
93
97
  if (parent === dir)
94
98
  break;
@@ -136,7 +140,10 @@ export function getProjectRoot(from = process.env.MONOMIND_CWD || process.cwd())
136
140
  function projectDataDir() {
137
141
  const resolved = path.resolve(getProjectRoot());
138
142
  const hash = crypto.createHash('sha256').update(resolved).digest('hex').slice(0, 16);
139
- const readable = path.basename(resolved).replace(/[^a-zA-Z0-9._-]+/g, '-').slice(0, 40) || 'project';
143
+ const readable = path
144
+ .basename(resolved)
145
+ .replace(/[^a-zA-Z0-9._-]+/g, '-')
146
+ .slice(0, 40) || 'project';
140
147
  return path.join(os.homedir(), '.monomind', 'projects', `${readable}-${hash}`);
141
148
  }
142
149
  /** Resolve symlinks so the traversal check below can't be bypassed by a link
@@ -145,7 +152,8 @@ function realOrResolved(p) {
145
152
  try {
146
153
  return fs.realpathSync(p);
147
154
  }
148
- catch {
155
+ catch (e) {
156
+ logBridgeError('realOrResolved', e);
149
157
  return p;
150
158
  }
151
159
  }
@@ -155,7 +163,7 @@ function realOrResolved(p) {
155
163
  * users who keep their brain on a synced/external location. Resolved lazily
156
164
  * so the override works regardless of import order. */
157
165
  export function getGlobalBrainDir() {
158
- return process.env.MONOMIND_GLOBAL_BRAIN_DIR || path.join(os.homedir(), '.monomind', 'global-brain');
166
+ return (process.env.MONOMIND_GLOBAL_BRAIN_DIR || path.join(os.homedir(), '.monomind', 'global-brain'));
159
167
  }
160
168
  /** Sentinel callers pass as dbPath to address the global brain. */
161
169
  export const GLOBAL_BRAIN = '@global';
@@ -198,10 +206,15 @@ function getAutomemConfig() {
198
206
  return defaults;
199
207
  const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
200
208
  return {
201
- dedupThreshold: typeof config?.scaffold?.dedupThreshold === 'number' ? config.scaffold.dedupThreshold : defaults.dedupThreshold,
202
- staleDays: typeof config?.scaffold?.staleDays === 'number' ? config.scaffold.staleDays : defaults.staleDays,
209
+ dedupThreshold: typeof config?.scaffold?.dedupThreshold === 'number'
210
+ ? config.scaffold.dedupThreshold
211
+ : defaults.dedupThreshold,
212
+ staleDays: typeof config?.scaffold?.staleDays === 'number'
213
+ ? config.scaffold.staleDays
214
+ : defaults.staleDays,
203
215
  feedbackInfluence: typeof config?.scaffold?.feedbackInfluence === 'number'
204
- ? Math.max(0, Math.min(1, config.scaffold.feedbackInfluence)) : defaults.feedbackInfluence,
216
+ ? Math.max(0, Math.min(1, config.scaffold.feedbackInfluence))
217
+ : defaults.feedbackInfluence,
205
218
  };
206
219
  }
207
220
  catch (e) {
@@ -223,9 +236,11 @@ const FREQUENCY_NORM_CAP = 10;
223
236
  function entryWeights(metadata) {
224
237
  const md = (metadata ?? {});
225
238
  const fw = typeof md.feedback_weight === 'number' && Number.isFinite(md.feedback_weight)
226
- ? Math.max(0, Math.min(1, md.feedback_weight)) : DEFAULT_FEEDBACK_WEIGHT;
239
+ ? Math.max(0, Math.min(1, md.feedback_weight))
240
+ : DEFAULT_FEEDBACK_WEIGHT;
227
241
  const freq = typeof md.frequency_weight === 'number' && Number.isFinite(md.frequency_weight)
228
- ? Math.max(0, md.frequency_weight) : 0;
242
+ ? Math.max(0, md.frequency_weight)
243
+ : 0;
229
244
  return { feedback: fw, frequency: freq };
230
245
  }
231
246
  /** Blend learned usefulness into a GENUINE embedding-similarity score.
@@ -289,7 +304,11 @@ export async function loadReranker() {
289
304
  const tokenizer = await hf.AutoTokenizer.from_pretrained(modelId, opts);
290
305
  const model = await hf.AutoModelForSequenceClassification.from_pretrained(modelId, opts);
291
306
  _reranker = async (query, passage) => {
292
- const inputs = await tokenizer(query, { text_pair: passage, padding: true, truncation: true });
307
+ const inputs = await tokenizer(query, {
308
+ text_pair: passage,
309
+ padding: true,
310
+ truncation: true,
311
+ });
293
312
  const output = await model(inputs);
294
313
  const logits = output.logits.data;
295
314
  // num_labels=1 → [1,1] regression score, apply sigmoid
@@ -335,7 +354,9 @@ async function flushBackend(backend) {
335
354
  try {
336
355
  await backend?.persist?.();
337
356
  }
338
- catch { /* best effort */ }
357
+ catch (e) {
358
+ logBridgeError('flushBackend', e); /* best effort */
359
+ }
339
360
  }
340
361
  /** Loads the local embedding model.
341
362
  *
@@ -360,7 +381,11 @@ async function loadEmbedder() {
360
381
  // silently killed embeddings (every search degraded to keyword matching)
361
382
  // dtype pinned explicitly: transformers.js logs a "dtype not specified"
362
383
  // warning to the console on every load otherwise (leaks into CLI output).
363
- const extractor = await hf.pipeline('feature-extraction', BRIDGE_EMBEDDING_MODEL, { revision: 'main', dtype: 'q8', local_files_only: true });
384
+ const extractor = await hf.pipeline('feature-extraction', BRIDGE_EMBEDDING_MODEL, {
385
+ revision: 'main',
386
+ dtype: 'q8',
387
+ local_files_only: true,
388
+ });
364
389
  _embedder = async (text) => {
365
390
  const output = await extractor(text, { pooling: 'cls', normalize: true });
366
391
  return new Float32Array(output.data);
@@ -390,7 +415,9 @@ async function getBackend(dbPath) {
390
415
  try {
391
416
  await evicted?.instance?.shutdown?.();
392
417
  }
393
- catch { /* best effort */ }
418
+ catch (e) {
419
+ logBridgeError('getBackend.evictedShutdown', e); /* best effort */
420
+ }
394
421
  backendSlots.delete(oldest);
395
422
  }
396
423
  slot = { promise: null, instance: null, available: null, attempts: 0 };
@@ -426,9 +453,12 @@ async function getBackend(dbPath) {
426
453
  // would make `cleanup --data` prune the WHOLE project's brain as
427
454
  // orphaned.
428
455
  const originFile = path.join(projectDataDir(), 'origin.json');
429
- fs.writeFileSync(originFile, JSON.stringify({ path: getProjectRoot(), updatedAt: new Date().toISOString() }) + '\n', 'utf-8');
456
+ fs.writeFileSync(originFile, JSON.stringify({ path: getProjectRoot(), updatedAt: new Date().toISOString() }) +
457
+ '\n', 'utf-8');
458
+ }
459
+ catch (e) {
460
+ logBridgeError('getBackend.originWrite', e); /* non-fatal */
430
461
  }
431
- catch { /* non-fatal */ }
432
462
  }
433
463
  const cfg = {
434
464
  databasePath: path.join(dir, 'memory.db'),
@@ -489,7 +519,8 @@ export async function bridgeStoreEntry(options) {
489
519
  return null;
490
520
  try {
491
521
  const key = typeof options.key === 'string' && options.key.length > BRIDGE_MAX_KEY_LEN
492
- ? options.key.slice(0, BRIDGE_MAX_KEY_LEN) : options.key;
522
+ ? options.key.slice(0, BRIDGE_MAX_KEY_LEN)
523
+ : options.key;
493
524
  if (typeof options.value === 'string' && options.value.length > BRIDGE_MAX_VALUE_LEN) {
494
525
  return {
495
526
  success: false,
@@ -500,9 +531,13 @@ export async function bridgeStoreEntry(options) {
500
531
  const value = options.value;
501
532
  const namespace = options.namespace ?? 'default';
502
533
  const tags = Array.isArray(options.tags)
503
- // src: tags carry the ingest source path for excerpt provenance — paths
504
- // routinely exceed the general 64-char tag cap, so they get 512.
505
- ? options.tags.filter(t => typeof t === 'string' && t.length > 0 && t.length <= (t.startsWith('src:') ? 512 : MAX_TAG_LEN)).slice(0, MAX_TAGS)
534
+ ? // src: tags carry the ingest source path for excerpt provenance — paths
535
+ // routinely exceed the general 64-char tag cap, so they get 512.
536
+ options.tags
537
+ .filter((t) => typeof t === 'string' &&
538
+ t.length > 0 &&
539
+ t.length <= (t.startsWith('src:') ? 512 : MAX_TAG_LEN))
540
+ .slice(0, MAX_TAGS)
506
541
  : [];
507
542
  const now = Date.now();
508
543
  const id = generateId('entry');
@@ -540,7 +575,9 @@ export async function bridgeStoreEntry(options) {
540
575
  try {
541
576
  upsertVictim = await backend.getByKey(namespace, key);
542
577
  }
543
- catch { /* treat as no existing entry */ }
578
+ catch (e) {
579
+ logBridgeError('bridgeStoreEntry.upsertLookup', e); /* treat as no existing entry */
580
+ }
544
581
  }
545
582
  // Dedup gate: skip if a near-duplicate already exists IN THIS NAMESPACE —
546
583
  // an unscoped search let a similar entry in some other namespace swallow
@@ -549,17 +586,22 @@ export async function bridgeStoreEntry(options) {
549
586
  if (embedding && !options.upsert) {
550
587
  try {
551
588
  const similar = await backend.search(embedding, {
552
- k: 1, threshold: automemCfg.dedupThreshold,
589
+ k: 1,
590
+ threshold: automemCfg.dedupThreshold,
553
591
  filters: { type: 'exact', namespace },
554
592
  });
555
593
  if (similar.length > 0 && similar[0].score >= automemCfg.dedupThreshold) {
556
594
  // Re-storing near-identical content is a usage signal: the fact keeps
557
595
  // being worth remembering. Reinforce the surviving entry.
558
- await recordUsageOnBackend(backend, [similar[0].entry.id]).catch(() => { });
596
+ await recordUsageOnBackend(backend, [similar[0].entry.id]).catch(() => {
597
+ /* best effort */
598
+ });
559
599
  return { success: true, id: similar[0].entry.id, duplicate: true };
560
600
  }
561
601
  }
562
- catch { /* non-fatal — store anyway */ }
602
+ catch (e) {
603
+ logBridgeError('bridgeStoreEntry.dedupSearch', e); /* non-fatal — store anyway */
604
+ }
563
605
  }
564
606
  await backend.store(entry);
565
607
  if (upsertVictim && upsertVictim.id !== id) {
@@ -575,7 +617,9 @@ export async function bridgeStoreEntry(options) {
575
617
  return { success: true, id, embedding: embeddingInfo };
576
618
  }
577
619
  catch (err) {
578
- return { success: false, id: '', error: String(err?.message ?? err) };
620
+ logBridgeError('bridgeStoreEntry', err);
621
+ const message = err instanceof Error ? err.message : String(err);
622
+ return { success: false, id: '', error: message };
579
623
  }
580
624
  }
581
625
  export async function bridgeSearchEntries(options) {
@@ -601,29 +645,35 @@ export async function bridgeSearchEntries(options) {
601
645
  if (knowledgeFilterActive) {
602
646
  try {
603
647
  const dp = await import('../knowledge/document-pipeline.js');
604
- const rootDir = options.dbPath === GLOBAL_BRAIN
605
- ? getGlobalBrainDir() : getProjectRoot();
648
+ const rootDir = options.dbPath === GLOBAL_BRAIN ? getGlobalBrainDir() : getProjectRoot();
606
649
  _knowledgeLive = dp.liveContentHashes(rootDir);
607
650
  _knowledgeHasMeta = dp.hasKnowledgeMetadata(rootDir);
608
651
  _isSupersededKey = dp.isSupersededKey;
609
652
  }
610
- catch { /* non-fatal: skip filtering when pipeline is unavailable */ }
653
+ catch (e) {
654
+ logBridgeError('bridgeSearchEntries.knowledgeFilter', e); /* non-fatal: skip filtering when pipeline is unavailable */
655
+ }
611
656
  }
612
657
  // Over-retrieve when the reranker is available: fetch more candidates so the
613
658
  // cross-encoder can reshuffle them. The reranker trims back to `limit`.
614
659
  // For knowledge namespaces, also over-fetch to compensate for superseded
615
660
  // document versions that will be filtered out below.
616
661
  const rerankerActive = !options.skipRerank && _reranker !== null && process.env.MONOMIND_RERANKER !== '0';
617
- const knowledgeLimit = (_knowledgeLive && _knowledgeLive.size > 0)
618
- ? Math.min(Math.max(limit * 20, limit), 300) : limit;
619
- const retrieveK = rerankerActive ? Math.min(knowledgeLimit * 3, Math.max(20, knowledgeLimit)) : knowledgeLimit;
662
+ const knowledgeLimit = _knowledgeLive && _knowledgeLive.size > 0
663
+ ? Math.min(Math.max(limit * 20, limit), 300)
664
+ : limit;
665
+ const retrieveK = rerankerActive
666
+ ? Math.min(knowledgeLimit * 3, Math.max(20, knowledgeLimit))
667
+ : knowledgeLimit;
620
668
  let results = [];
621
669
  let searchMethod = 'keyword';
622
670
  // Reported to callers so "(semantic)" can never be printed over keyword hits.
623
671
  // The two reasons for skipping the vector path are distinct and must not be
624
672
  // conflated: a healthy model given an empty query is not a missing model.
625
- let fallbackReason = !_embedder ? 'no-embedding-model'
626
- : queryStr.length === 0 ? 'empty-query'
673
+ let fallbackReason = !_embedder
674
+ ? 'no-embedding-model'
675
+ : queryStr.length === 0
676
+ ? 'empty-query'
627
677
  : undefined;
628
678
  let semanticAttempted = false;
629
679
  if (_embedder && queryStr.length > 0) {
@@ -636,7 +686,8 @@ export async function bridgeSearchEntries(options) {
636
686
  filters: namespace ? { type: 'exact', namespace } : undefined,
637
687
  });
638
688
  const { feedbackInfluence } = getAutomemConfig();
639
- results = searchResults.map((r) => {
689
+ results = searchResults
690
+ .map((r) => {
640
691
  const weights = entryWeights(r.entry.metadata);
641
692
  // Blend only here (semantic path): r.score is a genuine cosine similarity.
642
693
  const blended = blendScore(r.score, weights, feedbackInfluence);
@@ -650,7 +701,8 @@ export async function bridgeSearchEntries(options) {
650
701
  tags: r.entry.tags ?? [],
651
702
  _createdAt: r.entry.createdAt || 0,
652
703
  };
653
- }).sort((a, b) => b.score - a.score);
704
+ })
705
+ .sort((a, b) => b.score - a.score);
654
706
  searchMethod = 'semantic';
655
707
  fallbackReason = undefined;
656
708
  }
@@ -672,7 +724,10 @@ export async function bridgeSearchEntries(options) {
672
724
  // loaded up to 50k rows and scanned them in JS. The JS fallback is
673
725
  // kept for sql.js WASM builds that lack the FTS5 extension.
674
726
  {
675
- const tokens = queryStr.toLowerCase().split(/[^a-z0-9]+/).filter(t => t.length > 1);
727
+ const tokens = queryStr
728
+ .toLowerCase()
729
+ .split(/[^a-z0-9]+/)
730
+ .filter((t) => t.length > 1);
676
731
  let keywordHits = [];
677
732
  if (tokens.length) {
678
733
  // ── FTS5 fast path ──────────────────────────────────────────
@@ -723,7 +778,10 @@ export async function bridgeSearchEntries(options) {
723
778
  // sharing that key string resolved to whichever entry happened
724
779
  // to be inserted last into the lookup map, silently returning
725
780
  // the wrong entry's id/content/namespace.
726
- const chunks = entries.map((e, i) => ({ key: String(i), text: `${e.key || ''} ${e.content || ''}` }));
781
+ const chunks = entries.map((e, i) => ({
782
+ key: String(i),
783
+ text: `${e.key || ''} ${e.content || ''}`,
784
+ }));
727
785
  const idx = Bm25Index.build(chunks, () => false); // no superseded concept at this generic KV level — filtered later by callers that care
728
786
  const hits = idx.search(queryStr, limit);
729
787
  // #126-review: Math.max(..., 1) as a divide-by-zero guard also
@@ -732,7 +790,7 @@ export async function bridgeSearchEntries(options) {
732
790
  // regime this capped fallback runs in), so the top hit stopped
733
791
  // normalizing to 1.0 as the comment below claims. Only fall
734
792
  // back to 1 when there is no positive score to divide by.
735
- const rawMax = hits.length ? Math.max(...hits.map(h => h.score)) : 0;
793
+ const rawMax = hits.length ? Math.max(...hits.map((h) => h.score)) : 0;
736
794
  const maxScore = rawMax > 0 ? rawMax : 1;
737
795
  keywordHits = hits.map((h) => {
738
796
  const e = entries[Number(h.key)];
@@ -765,7 +823,7 @@ export async function bridgeSearchEntries(options) {
765
823
  keywordHits = entries
766
824
  .map((e) => {
767
825
  const haystack = `${e.key || ''} ${e.content || ''}`.toLowerCase();
768
- const hits = tokens.filter(t => haystack.includes(t)).length;
826
+ const hits = tokens.filter((t) => haystack.includes(t)).length;
769
827
  return { e, score: hits / tokens.length };
770
828
  })
771
829
  .filter((x) => x.score > 0)
@@ -817,13 +875,16 @@ export async function bridgeSearchEntries(options) {
817
875
  // stale cutoff.
818
876
  // org:* (cross-run org memory) and rules are durable learned state like
819
877
  // documents — the stale cliff silently erased org recall after a week.
820
- const durableNs = (ns) => ns.startsWith('knowledge:') || ns.startsWith('org:') || ns.startsWith('agent:') || ns.startsWith('kg:') || ns === 'rules';
878
+ const durableNs = (ns) => ns.startsWith('knowledge:') ||
879
+ ns.startsWith('org:') ||
880
+ ns.startsWith('agent:') ||
881
+ ns.startsWith('kg:') ||
882
+ ns === 'rules';
821
883
  const isKnowledgeNs = namespace ? durableNs(namespace) : false;
822
884
  if (!isKnowledgeNs) {
823
885
  const { staleDays } = getAutomemConfig();
824
886
  const staleCutoff = Date.now() - staleDays * 86400000;
825
- results = results.filter((r) => durableNs(String(r.namespace ?? ''))
826
- || !r._createdAt || r._createdAt > staleCutoff);
887
+ results = results.filter((r) => durableNs(String(r.namespace ?? '')) || !r._createdAt || r._createdAt > staleCutoff);
827
888
  }
828
889
  results.forEach((r) => delete r._createdAt);
829
890
  // ── Knowledge superseded filtering (issue #106) ─────────────────
@@ -846,7 +907,9 @@ export async function bridgeSearchEntries(options) {
846
907
  if (!_reranker && !_rerankerPromise) {
847
908
  // First qualifying search — kick off the lazy load. This search
848
909
  // proceeds without reranking; the NEXT search will use it.
849
- loadReranker().catch(() => { });
910
+ loadReranker().catch(() => {
911
+ /* swallowed — retry next time */
912
+ });
850
913
  }
851
914
  if (_reranker) {
852
915
  const rr = await rerankResults(queryStr, results, limit);
@@ -1008,7 +1071,8 @@ export async function bridgeGetBackendStats(dbPath) {
1008
1071
  memoryUsage: stats?.memoryUsage ?? 0,
1009
1072
  };
1010
1073
  }
1011
- catch {
1074
+ catch (e) {
1075
+ logBridgeError('bridgeGetBackendStats', e);
1012
1076
  return null;
1013
1077
  }
1014
1078
  }
@@ -1021,7 +1085,8 @@ export async function bridgeGetHNSWStatus(dbPath) {
1021
1085
  const stats = await backend.getStats();
1022
1086
  return { built: true, size: stats?.totalEntries ?? 0, dimensions: BRIDGE_EMBEDDING_DIMS };
1023
1087
  }
1024
- catch {
1088
+ catch (e) {
1089
+ logBridgeError('bridgeGetHNSWStatus', e);
1025
1090
  return { built: false, size: 0, dimensions: BRIDGE_EMBEDDING_DIMS };
1026
1091
  }
1027
1092
  }
@@ -1038,7 +1103,12 @@ export async function bridgeSearchHNSW(options) {
1038
1103
  return null;
1039
1104
  return {
1040
1105
  success: result.success,
1041
- results: result.results.map(r => ({ id: r.id, key: r.key, score: r.score, namespace: r.namespace })),
1106
+ results: result.results.map((r) => ({
1107
+ id: r.id,
1108
+ key: r.key,
1109
+ score: r.score,
1110
+ namespace: r.namespace,
1111
+ })),
1042
1112
  searchTime: result.searchTime,
1043
1113
  };
1044
1114
  }
@@ -1051,7 +1121,8 @@ export async function bridgeAddToHNSW(options) {
1051
1121
  const stats = await backend.getStats();
1052
1122
  return { success: true, indexSize: stats?.totalEntries ?? 0 };
1053
1123
  }
1054
- catch {
1124
+ catch (e) {
1125
+ logBridgeError('bridgeAddToHNSW', e);
1055
1126
  return { success: true };
1056
1127
  }
1057
1128
  }
@@ -1083,7 +1154,9 @@ export async function shutdownBridge() {
1083
1154
  try {
1084
1155
  await slot.instance.shutdown();
1085
1156
  }
1086
- catch { /* ignore */ }
1157
+ catch (e) {
1158
+ logBridgeError('bridgeShutdown.slotShutdown', e); /* ignore */
1159
+ }
1087
1160
  }
1088
1161
  }
1089
1162
  backendSlots.clear();
@@ -1119,12 +1192,14 @@ export async function bridgeSearchPatterns(options) {
1119
1192
  return null;
1120
1193
  return {
1121
1194
  success: result.success,
1122
- patterns: result.results.map(r => {
1195
+ patterns: result.results.map((r) => {
1123
1196
  let parsed = {};
1124
1197
  try {
1125
1198
  parsed = JSON.parse(r.content);
1126
1199
  }
1127
- catch { /* use raw */ }
1200
+ catch (e) {
1201
+ logBridgeError('bridgeSearchPatterns.parseContent', e); /* use raw */
1202
+ }
1128
1203
  return {
1129
1204
  id: r.id,
1130
1205
  pattern: parsed.pattern ?? r.content,
@@ -1152,7 +1227,9 @@ async function recordUsageOnBackend(backend, entryIds) {
1152
1227
  });
1153
1228
  updated++;
1154
1229
  }
1155
- catch { /* skip unreadable entries */ }
1230
+ catch (e) {
1231
+ logBridgeError('recordUsageOnBackend.entryUpdate', e); /* skip unreadable entries */
1232
+ }
1156
1233
  }
1157
1234
  return updated;
1158
1235
  }
@@ -1168,7 +1245,8 @@ export async function bridgeRecordUsage(options) {
1168
1245
  await flushBackend(backend);
1169
1246
  return { success: true, updated };
1170
1247
  }
1171
- catch {
1248
+ catch (e) {
1249
+ logBridgeError('bridgeRecordUsage', e);
1172
1250
  return { success: false, updated: 0 };
1173
1251
  }
1174
1252
  }
@@ -1182,7 +1260,9 @@ export async function bridgeApplyFeedback(options) {
1182
1260
  return null;
1183
1261
  try {
1184
1262
  const score = Math.max(0, Math.min(1, options.score));
1185
- const alpha = typeof options.alpha === 'number' ? Math.max(0, Math.min(1, options.alpha)) : FEEDBACK_EWMA_ALPHA;
1263
+ const alpha = typeof options.alpha === 'number'
1264
+ ? Math.max(0, Math.min(1, options.alpha))
1265
+ : FEEDBACK_EWMA_ALPHA;
1186
1266
  const ledgerEntryKey = options.ledgerKey ? `applied_${options.ledgerKey.slice(0, 500)}` : null;
1187
1267
  if (ledgerEntryKey) {
1188
1268
  const existing = await backend.getByKey('feedback', ledgerEntryKey).catch(() => null);
@@ -1202,12 +1282,19 @@ export async function bridgeApplyFeedback(options) {
1202
1282
  await backend.update(id, { metadata: { feedback_weight: next } });
1203
1283
  applied++;
1204
1284
  }
1205
- catch { /* skip unreadable entries */ }
1285
+ catch (e) {
1286
+ logBridgeError('bridgeApplyFeedback.entryUpdate', e); /* skip unreadable entries */
1287
+ }
1206
1288
  }
1207
1289
  if (ledgerEntryKey) {
1208
1290
  await bridgeStoreEntry({
1209
1291
  key: ledgerEntryKey,
1210
- value: JSON.stringify({ score, entryIds: options.entryIds.slice(0, 100), appliedAt: Date.now(), applied }),
1292
+ value: JSON.stringify({
1293
+ score,
1294
+ entryIds: options.entryIds.slice(0, 100),
1295
+ appliedAt: Date.now(),
1296
+ applied,
1297
+ }),
1211
1298
  namespace: 'feedback',
1212
1299
  generateEmbeddingFlag: false,
1213
1300
  dbPath: options.dbPath,
@@ -1219,7 +1306,9 @@ export async function bridgeApplyFeedback(options) {
1219
1306
  return { success: true, applied };
1220
1307
  }
1221
1308
  catch (err) {
1222
- return { success: false, applied: 0, error: String(err?.message ?? err) };
1309
+ logBridgeError('bridgeApplyFeedback', err);
1310
+ const message = err instanceof Error ? err.message : String(err);
1311
+ return { success: false, applied: 0, error: message };
1223
1312
  }
1224
1313
  }
1225
1314
  // ===== Feedback =====
@@ -1304,7 +1393,8 @@ export async function bridgeSessionEnd(options) {
1304
1393
  }
1305
1394
  return { success: true };
1306
1395
  }
1307
- catch {
1396
+ catch (e) {
1397
+ logBridgeError('bridgeSessionEnd', e);
1308
1398
  return { success: false };
1309
1399
  }
1310
1400
  }
@@ -1320,12 +1410,14 @@ export async function bridgeRouteTask(options) {
1320
1410
  return null;
1321
1411
  return {
1322
1412
  success: result.success,
1323
- routes: result.results.map(r => {
1413
+ routes: result.results.map((r) => {
1324
1414
  let parsed = {};
1325
1415
  try {
1326
1416
  parsed = JSON.parse(r.content);
1327
1417
  }
1328
- catch { /* use raw */ }
1418
+ catch (e) {
1419
+ logBridgeError('bridgeRouteTask.parseContent', e); /* use raw */
1420
+ }
1329
1421
  return {
1330
1422
  agentType: parsed.taskType ?? 'coder',
1331
1423
  confidence: r.score,
@@ -1345,13 +1437,16 @@ export async function bridgeHealthCheck(dbPath) {
1345
1437
  return {
1346
1438
  healthy: health?.healthy ?? true,
1347
1439
  backend: 'sqlite',
1348
- stats: stats ? {
1349
- totalEntries: stats.totalEntries ?? 0,
1350
- namespaces: Object.keys(stats.entriesByNamespace ?? {}),
1351
- } : undefined,
1440
+ stats: stats
1441
+ ? {
1442
+ totalEntries: stats.totalEntries ?? 0,
1443
+ namespaces: Object.keys(stats.entriesByNamespace ?? {}),
1444
+ }
1445
+ : undefined,
1352
1446
  };
1353
1447
  }
1354
- catch {
1448
+ catch (e) {
1449
+ logBridgeError('bridgeHealthCheck', e);
1355
1450
  return { healthy: false, backend: 'sqlite' };
1356
1451
  }
1357
1452
  }
@@ -1404,7 +1499,9 @@ export async function bridgeConsolidate(params) {
1404
1499
  continue;
1405
1500
  }
1406
1501
  if ((e.accessCount ?? 0) === 0) {
1407
- await backend.delete(e.id).catch(() => { });
1502
+ await backend.delete(e.id).catch(() => {
1503
+ /* non-fatal */
1504
+ });
1408
1505
  deleted++;
1409
1506
  }
1410
1507
  }
@@ -1412,7 +1509,8 @@ export async function bridgeConsolidate(params) {
1412
1509
  await flushBackend(backend);
1413
1510
  return { success: true, consolidated: deleted, preserved: kept };
1414
1511
  }
1415
- catch {
1512
+ catch (e) {
1513
+ logBridgeError('bridgeConsolidate', e);
1416
1514
  return { success: false, consolidated: 0 };
1417
1515
  }
1418
1516
  }
@@ -1425,7 +1523,11 @@ export async function bridgeBatchOperation(params) {
1425
1523
  let processed = 0;
1426
1524
  if (params.operation === 'store') {
1427
1525
  for (const e of params.entries) {
1428
- const result = await bridgeStoreEntry({ key: e.key, value: e.value, namespace: e.namespace });
1526
+ const result = await bridgeStoreEntry({
1527
+ key: e.key,
1528
+ value: e.value,
1529
+ namespace: e.namespace,
1530
+ });
1429
1531
  if (result?.success)
1430
1532
  processed++;
1431
1533
  }
@@ -1439,7 +1541,8 @@ export async function bridgeBatchOperation(params) {
1439
1541
  }
1440
1542
  return { success: true, processed };
1441
1543
  }
1442
- catch {
1544
+ catch (e) {
1545
+ logBridgeError('bridgeBatchOperation', e);
1443
1546
  return { success: false, processed: 0 };
1444
1547
  }
1445
1548
  }