@cleocode/cleo 2026.4.37 → 2026.4.38

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 (33) hide show
  1. package/dist/cli/commands/brain.d.ts.map +1 -1
  2. package/dist/cli/commands/brain.js +60 -1
  3. package/dist/cli/commands/brain.js.map +1 -1
  4. package/dist/cli/commands/memory-brain.d.ts.map +1 -1
  5. package/dist/cli/commands/memory-brain.js +38 -0
  6. package/dist/cli/commands/memory-brain.js.map +1 -1
  7. package/dist/cli/commands/nexus.d.ts.map +1 -1
  8. package/dist/cli/commands/nexus.js +75 -2
  9. package/dist/cli/commands/nexus.js.map +1 -1
  10. package/dist/cli/index.js +881 -40
  11. package/dist/cli/index.js.map +4 -4
  12. package/dist/dispatch/domains/memory.d.ts.map +1 -1
  13. package/dist/dispatch/domains/memory.js +6 -1
  14. package/dist/dispatch/domains/memory.js.map +1 -1
  15. package/dist/dispatch/engines/memory-engine.d.ts +1 -1
  16. package/dist/dispatch/engines/memory-engine.d.ts.map +1 -1
  17. package/dist/dispatch/engines/memory-engine.js +1 -1
  18. package/dist/dispatch/engines/memory-engine.js.map +1 -1
  19. package/dist/dispatch/engines/orchestrate-engine.d.ts.map +1 -1
  20. package/dist/dispatch/engines/orchestrate-engine.js +50 -0
  21. package/dist/dispatch/engines/orchestrate-engine.js.map +1 -1
  22. package/dist/dispatch/lib/engine.d.ts +1 -1
  23. package/dist/dispatch/lib/engine.d.ts.map +1 -1
  24. package/dist/dispatch/lib/engine.js +1 -1
  25. package/dist/dispatch/lib/engine.js.map +1 -1
  26. package/dist/dispatch/registry.d.ts.map +1 -1
  27. package/dist/dispatch/registry.js +89 -0
  28. package/dist/dispatch/registry.js.map +1 -1
  29. package/dist/dispatch/types.d.ts +1 -1
  30. package/dist/dispatch/types.d.ts.map +1 -1
  31. package/dist/dispatch/types.js +1 -0
  32. package/dist/dispatch/types.js.map +1 -1
  33. package/package.json +8 -8
package/dist/cli/index.js CHANGED
@@ -22109,6 +22109,210 @@ var init_quality_scoring = __esm({
22109
22109
  }
22110
22110
  });
22111
22111
 
22112
+ // packages/core/src/store/typed-query.ts
22113
+ function typedAll(stmt, ...params) {
22114
+ return stmt.all(...params);
22115
+ }
22116
+ function typedGet(stmt, ...params) {
22117
+ return stmt.get(...params);
22118
+ }
22119
+ var init_typed_query = __esm({
22120
+ "packages/core/src/store/typed-query.ts"() {
22121
+ "use strict";
22122
+ }
22123
+ });
22124
+
22125
+ // packages/core/src/memory/temporal-supersession.ts
22126
+ function extractKeywords(text3) {
22127
+ const words = text3.toLowerCase().replace(/[^a-z0-9\s\-_]/g, " ").split(/\s+/);
22128
+ const keywords = /* @__PURE__ */ new Set();
22129
+ for (const w2 of words) {
22130
+ if (w2.length >= 4 && !STOP_WORDS.has(w2)) {
22131
+ keywords.add(w2);
22132
+ }
22133
+ }
22134
+ return keywords;
22135
+ }
22136
+ function keywordSimilarity(textA, textB) {
22137
+ const kwA = extractKeywords(textA);
22138
+ const kwB = extractKeywords(textB);
22139
+ if (kwA.size === 0 || kwB.size === 0) return { similarity: 0, shared: [] };
22140
+ const shared = [];
22141
+ for (const w2 of kwA) {
22142
+ if (kwB.has(w2)) shared.push(w2);
22143
+ }
22144
+ if (shared.length < MIN_SHARED_KEYWORDS) return { similarity: 0, shared: [] };
22145
+ const union3 = kwA.size + kwB.size - shared.length;
22146
+ const similarity = union3 > 0 ? shared.length / union3 : 0;
22147
+ return { similarity, shared };
22148
+ }
22149
+ function buildNodeId(type, entryId) {
22150
+ return `${type}:${entryId}`;
22151
+ }
22152
+ async function locateEntry(projectRoot, entryId) {
22153
+ await getBrainDb(projectRoot);
22154
+ const nativeDb = getBrainNativeDb();
22155
+ if (!nativeDb) return null;
22156
+ for (const tc of SUPERSEDABLE_TABLES) {
22157
+ const row = typedGet(
22158
+ nativeDb.prepare(`SELECT id FROM ${tc.table} WHERE id = ? LIMIT 1`),
22159
+ entryId
22160
+ );
22161
+ if (row) {
22162
+ return { tableConfig: tc, nodeId: buildNodeId(tc.type, entryId) };
22163
+ }
22164
+ }
22165
+ return null;
22166
+ }
22167
+ async function supersedeMemory(projectRoot, oldId, newId, reason) {
22168
+ if (!oldId?.trim()) throw new Error("oldId is required");
22169
+ if (!newId?.trim()) throw new Error("newId is required");
22170
+ if (!reason?.trim()) throw new Error("reason is required");
22171
+ if (oldId === newId) throw new Error("oldId and newId must be different entries");
22172
+ await getBrainDb(projectRoot);
22173
+ const nativeDb = getBrainNativeDb();
22174
+ if (!nativeDb) throw new Error("brain.db is unavailable");
22175
+ const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
22176
+ const oldLocation = await locateEntry(projectRoot, oldId);
22177
+ if (!oldLocation) throw new Error(`Entry not found: ${oldId}`);
22178
+ const newLocation = await locateEntry(projectRoot, newId);
22179
+ if (!newLocation) throw new Error(`Entry not found: ${newId}`);
22180
+ const { tableConfig: oldTc, nodeId: oldNodeId } = oldLocation;
22181
+ const { nodeId: newNodeId } = newLocation;
22182
+ try {
22183
+ nativeDb.prepare(
22184
+ `UPDATE ${oldTc.table} SET invalid_at = ?, updated_at = ? WHERE id = ? AND invalid_at IS NULL`
22185
+ ).run(now2, now2, oldId);
22186
+ } catch {
22187
+ }
22188
+ const provenanceText = reason.substring(0, 500);
22189
+ try {
22190
+ nativeDb.prepare(
22191
+ `INSERT OR IGNORE INTO brain_page_edges
22192
+ (from_id, to_id, edge_type, weight, provenance, created_at)
22193
+ VALUES (?, ?, 'supersedes', 1.0, ?, ?)`
22194
+ ).run(newNodeId, oldNodeId, provenanceText, now2);
22195
+ } catch (err) {
22196
+ const message = err instanceof Error ? err.message : String(err);
22197
+ throw new Error(`Failed to create supersedes edge: ${message}`);
22198
+ }
22199
+ return {
22200
+ success: true,
22201
+ oldId,
22202
+ newId,
22203
+ edgeType: "supersedes"
22204
+ };
22205
+ }
22206
+ async function detectSupersession(projectRoot, newEntry) {
22207
+ try {
22208
+ await getBrainDb(projectRoot);
22209
+ const nativeDb = getBrainNativeDb();
22210
+ if (!nativeDb) return [];
22211
+ const newLocation = await locateEntry(projectRoot, newEntry.id);
22212
+ if (!newLocation) return [];
22213
+ const { tableConfig } = newLocation;
22214
+ const existing = typedAll(
22215
+ nativeDb.prepare(`
22216
+ SELECT id, COALESCE(${tableConfig.textCol}, '') AS text,
22217
+ created_at, quality_score
22218
+ FROM ${tableConfig.table}
22219
+ WHERE invalid_at IS NULL
22220
+ AND id != ?
22221
+ ORDER BY created_at DESC
22222
+ LIMIT 200
22223
+ `),
22224
+ newEntry.id
22225
+ );
22226
+ if (existing.length === 0) return [];
22227
+ const candidates = [];
22228
+ for (const row of existing) {
22229
+ if (row.created_at >= newEntry.createdAt) continue;
22230
+ const { similarity, shared } = keywordSimilarity(newEntry.text, row.text);
22231
+ if (similarity >= KEYWORD_OVERLAP_THRESHOLD) {
22232
+ candidates.push({
22233
+ existingId: row.id,
22234
+ similarity,
22235
+ table: tableConfig.table,
22236
+ sharedKeywords: shared.slice(0, 10)
22237
+ });
22238
+ }
22239
+ }
22240
+ candidates.sort((a, b2) => b2.similarity - a.similarity);
22241
+ return candidates;
22242
+ } catch (err) {
22243
+ console.warn("[temporal-supersession] detectSupersession failed:", err);
22244
+ return [];
22245
+ }
22246
+ }
22247
+ var KEYWORD_OVERLAP_THRESHOLD, MIN_SHARED_KEYWORDS, STOP_WORDS, SUPERSEDABLE_TABLES;
22248
+ var init_temporal_supersession = __esm({
22249
+ "packages/core/src/memory/temporal-supersession.ts"() {
22250
+ "use strict";
22251
+ init_brain_sqlite();
22252
+ init_typed_query();
22253
+ KEYWORD_OVERLAP_THRESHOLD = 0.8;
22254
+ MIN_SHARED_KEYWORDS = 3;
22255
+ STOP_WORDS = /* @__PURE__ */ new Set([
22256
+ "the",
22257
+ "a",
22258
+ "an",
22259
+ "is",
22260
+ "are",
22261
+ "was",
22262
+ "were",
22263
+ "be",
22264
+ "been",
22265
+ "being",
22266
+ "have",
22267
+ "has",
22268
+ "had",
22269
+ "do",
22270
+ "does",
22271
+ "did",
22272
+ "will",
22273
+ "would",
22274
+ "could",
22275
+ "should",
22276
+ "may",
22277
+ "might",
22278
+ "shall",
22279
+ "can",
22280
+ "to",
22281
+ "of",
22282
+ "in",
22283
+ "for",
22284
+ "on",
22285
+ "with",
22286
+ "at",
22287
+ "by",
22288
+ "from",
22289
+ "as",
22290
+ "into",
22291
+ "through",
22292
+ "and",
22293
+ "but",
22294
+ "or",
22295
+ "nor",
22296
+ "so",
22297
+ "yet",
22298
+ "this",
22299
+ "that",
22300
+ "these",
22301
+ "those",
22302
+ "it",
22303
+ "its",
22304
+ "not",
22305
+ "no"
22306
+ ]);
22307
+ SUPERSEDABLE_TABLES = [
22308
+ { table: "brain_decisions", textCol: "decision", type: "decision" },
22309
+ { table: "brain_learnings", textCol: "insight", type: "learning" },
22310
+ { table: "brain_patterns", textCol: "pattern", type: "pattern" },
22311
+ { table: "brain_observations", textCol: "narrative", type: "observation" }
22312
+ ];
22313
+ }
22314
+ });
22315
+
22112
22316
  // packages/core/src/memory/patterns.ts
22113
22317
  var patterns_exports = {};
22114
22318
  __export(patterns_exports, {
@@ -22206,6 +22410,22 @@ async function storePattern(projectRoot, params) {
22206
22410
  { type: saved.type, impact: saved.impact ?? void 0 }
22207
22411
  ).catch(() => {
22208
22412
  });
22413
+ detectSupersession(projectRoot, {
22414
+ id: saved.id,
22415
+ text: saved.pattern + " " + saved.context,
22416
+ createdAt: saved.extractedAt ?? (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
22417
+ }).then((candidates) => {
22418
+ for (const candidate of candidates) {
22419
+ supersedeMemory(
22420
+ projectRoot,
22421
+ candidate.existingId,
22422
+ saved.id,
22423
+ "auto:pattern-supersedes \u2014 high overlap detected at store time"
22424
+ ).catch(() => {
22425
+ });
22426
+ }
22427
+ }).catch(() => {
22428
+ });
22209
22429
  return {
22210
22430
  ...saved,
22211
22431
  examples: JSON.parse(saved.examplesJson || "[]")
@@ -22262,6 +22482,7 @@ var init_patterns = __esm({
22262
22482
  init_brain_accessor();
22263
22483
  init_graph_auto_populate();
22264
22484
  init_quality_scoring();
22485
+ init_temporal_supersession();
22265
22486
  }
22266
22487
  });
22267
22488
 
@@ -22353,6 +22574,22 @@ async function storeLearning(projectRoot, params) {
22353
22574
  { source: saved.source, confidence: saved.confidence, actionable: saved.actionable }
22354
22575
  ).catch(() => {
22355
22576
  });
22577
+ detectSupersession(projectRoot, {
22578
+ id: saved.id,
22579
+ text: saved.insight,
22580
+ createdAt: saved.createdAt ?? (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
22581
+ }).then((candidates) => {
22582
+ for (const candidate of candidates) {
22583
+ supersedeMemory(
22584
+ projectRoot,
22585
+ candidate.existingId,
22586
+ saved.id,
22587
+ "auto:learning-supersedes \u2014 high overlap detected at store time"
22588
+ ).catch(() => {
22589
+ });
22590
+ }
22591
+ }).catch(() => {
22592
+ });
22356
22593
  return {
22357
22594
  ...saved,
22358
22595
  applicableTypes: JSON.parse(saved.applicableTypesJson || "[]")
@@ -22413,6 +22650,7 @@ var init_learnings = __esm({
22413
22650
  init_brain_accessor();
22414
22651
  init_graph_auto_populate();
22415
22652
  init_quality_scoring();
22653
+ init_temporal_supersession();
22416
22654
  }
22417
22655
  });
22418
22656
 
@@ -22451,16 +22689,6 @@ var init_mvi_helpers = __esm({
22451
22689
  }
22452
22690
  });
22453
22691
 
22454
- // packages/core/src/store/typed-query.ts
22455
- function typedAll(stmt, ...params) {
22456
- return stmt.all(...params);
22457
- }
22458
- var init_typed_query = __esm({
22459
- "packages/core/src/store/typed-query.ts"() {
22460
- "use strict";
22461
- }
22462
- });
22463
-
22464
22692
  // packages/core/src/memory/brain-similarity.ts
22465
22693
  function parseIdPrefix(id) {
22466
22694
  if (id.startsWith("D-") || /^D\d/.test(id)) return "decision";
@@ -24245,6 +24473,22 @@ async function storeDecision(projectRoot, params) {
24245
24473
  }
24246
24474
  } catch {
24247
24475
  }
24476
+ detectSupersession(projectRoot, {
24477
+ id: saved.id,
24478
+ text: saved.decision + " " + saved.rationale,
24479
+ createdAt: saved.createdAt ?? (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
24480
+ }).then((candidates) => {
24481
+ for (const candidate of candidates) {
24482
+ supersedeMemory(
24483
+ projectRoot,
24484
+ candidate.existingId,
24485
+ saved.id,
24486
+ "auto:decision-supersedes \u2014 high overlap detected at store time"
24487
+ ).catch(() => {
24488
+ });
24489
+ }
24490
+ }).catch(() => {
24491
+ });
24248
24492
  return saved;
24249
24493
  }
24250
24494
  async function recallDecision(projectRoot, id) {
@@ -24297,6 +24541,7 @@ var init_decisions2 = __esm({
24297
24541
  init_sqlite2();
24298
24542
  init_graph_auto_populate();
24299
24543
  init_quality_scoring();
24544
+ init_temporal_supersession();
24300
24545
  }
24301
24546
  });
24302
24547
 
@@ -45369,11 +45614,11 @@ var brain_consolidator_exports = {};
45369
45614
  __export(brain_consolidator_exports, {
45370
45615
  detectContradictions: () => detectContradictions
45371
45616
  });
45372
- function extractKeywords(text3) {
45617
+ function extractKeywords2(text3) {
45373
45618
  const words = text3.toLowerCase().replace(/[^a-z0-9\s\-_]/g, " ").split(/\s+/);
45374
45619
  const keywords = /* @__PURE__ */ new Set();
45375
45620
  for (const w2 of words) {
45376
- if (w2.length >= 4 && !STOP_WORDS.has(w2)) {
45621
+ if (w2.length >= 4 && !STOP_WORDS2.has(w2)) {
45377
45622
  keywords.add(w2);
45378
45623
  }
45379
45624
  }
@@ -45422,7 +45667,7 @@ async function detectContradictions(projectRoot) {
45422
45667
  const keywordMap = /* @__PURE__ */ new Map();
45423
45668
  const negationMap = /* @__PURE__ */ new Map();
45424
45669
  for (const entry of entries) {
45425
- keywordMap.set(entry.id, extractKeywords(entry.text));
45670
+ keywordMap.set(entry.id, extractKeywords2(entry.text));
45426
45671
  negationMap.set(entry.id, findNegationMarkers(entry.text));
45427
45672
  }
45428
45673
  for (let i = 0; i < entries.length; i++) {
@@ -45436,7 +45681,7 @@ async function detectContradictions(projectRoot) {
45436
45681
  const keywordsB = keywordMap.get(entryB.id);
45437
45682
  const negationsB = negationMap.get(entryB.id);
45438
45683
  const shared = keywordIntersection(keywordsA, keywordsB);
45439
- if (shared.length < MIN_SHARED_KEYWORDS) continue;
45684
+ if (shared.length < MIN_SHARED_KEYWORDS2) continue;
45440
45685
  const negationsOnlyInA = negationsA.filter((m2) => !negationsB.includes(m2));
45441
45686
  const negationsOnlyInB = negationsB.filter((m2) => !negationsA.includes(m2));
45442
45687
  const negationFlip = negationsOnlyInA.length > 0 || negationsOnlyInB.length > 0;
@@ -45454,8 +45699,8 @@ async function detectContradictions(projectRoot) {
45454
45699
  sharedKeywords: shared.slice(0, 10),
45455
45700
  negationMarkers: negMarkers.slice(0, 5)
45456
45701
  });
45457
- const nodeA = buildNodeId(table, entryA.id);
45458
- const nodeB = buildNodeId(table, entryB.id);
45702
+ const nodeA = buildNodeId2(table, entryA.id);
45703
+ const nodeB = buildNodeId2(table, entryB.id);
45459
45704
  try {
45460
45705
  nativeDb.prepare(`
45461
45706
  INSERT OR IGNORE INTO brain_page_edges
@@ -45484,7 +45729,7 @@ async function detectContradictions(projectRoot) {
45484
45729
  }
45485
45730
  return results;
45486
45731
  }
45487
- function buildNodeId(table, entryId) {
45732
+ function buildNodeId2(table, entryId) {
45488
45733
  const typeMap = {
45489
45734
  brain_observations: "observation",
45490
45735
  brain_learnings: "learning",
@@ -45494,13 +45739,13 @@ function buildNodeId(table, entryId) {
45494
45739
  const type = typeMap[table] ?? "entry";
45495
45740
  return `${type}:${entryId}`;
45496
45741
  }
45497
- var MIN_SHARED_KEYWORDS, NEGATION_MARKERS, STOP_WORDS;
45742
+ var MIN_SHARED_KEYWORDS2, NEGATION_MARKERS, STOP_WORDS2;
45498
45743
  var init_brain_consolidator = __esm({
45499
45744
  "packages/core/src/memory/brain-consolidator.ts"() {
45500
45745
  "use strict";
45501
45746
  init_brain_sqlite();
45502
45747
  init_typed_query();
45503
- MIN_SHARED_KEYWORDS = 3;
45748
+ MIN_SHARED_KEYWORDS2 = 3;
45504
45749
  NEGATION_MARKERS = [
45505
45750
  "not",
45506
45751
  "never",
@@ -45521,7 +45766,7 @@ var init_brain_consolidator = __esm({
45521
45766
  "undone",
45522
45767
  "superseded"
45523
45768
  ];
45524
- STOP_WORDS = /* @__PURE__ */ new Set([
45769
+ STOP_WORDS2 = /* @__PURE__ */ new Set([
45525
45770
  "the",
45526
45771
  "a",
45527
45772
  "an",
@@ -45609,11 +45854,11 @@ async function applyTemporalDecay(projectRoot, options) {
45609
45854
  tablesProcessed: ["brain_learnings"]
45610
45855
  };
45611
45856
  }
45612
- function extractKeywords2(text3) {
45857
+ function extractKeywords3(text3) {
45613
45858
  const words = text3.toLowerCase().replace(/[^a-z0-9\s-]/g, "").split(/\s+/);
45614
45859
  const keywords = /* @__PURE__ */ new Set();
45615
45860
  for (const w2 of words) {
45616
- if (w2.length >= 4 && !STOP_WORDS2.has(w2)) {
45861
+ if (w2.length >= 4 && !STOP_WORDS3.has(w2)) {
45617
45862
  keywords.add(w2);
45618
45863
  }
45619
45864
  }
@@ -45651,7 +45896,7 @@ async function consolidateMemories(projectRoot, options) {
45651
45896
  }
45652
45897
  const entries = oldObservations.map((obs) => ({
45653
45898
  ...obs,
45654
- keywords: extractKeywords2(`${obs.title} ${obs.narrative ?? ""}`),
45899
+ keywords: extractKeywords3(`${obs.title} ${obs.narrative ?? ""}`),
45655
45900
  clustered: false
45656
45901
  }));
45657
45902
  const clusters = [];
@@ -46053,13 +46298,13 @@ async function strengthenCoRetrievedEdges(projectRoot) {
46053
46298
  }
46054
46299
  return strengthened;
46055
46300
  }
46056
- var STOP_WORDS2;
46301
+ var STOP_WORDS3;
46057
46302
  var init_brain_lifecycle = __esm({
46058
46303
  "packages/core/src/memory/brain-lifecycle.ts"() {
46059
46304
  "use strict";
46060
46305
  init_brain_accessor();
46061
46306
  init_typed_query();
46062
- STOP_WORDS2 = /* @__PURE__ */ new Set([
46307
+ STOP_WORDS3 = /* @__PURE__ */ new Set([
46063
46308
  "the",
46064
46309
  "a",
46065
46310
  "an",
@@ -46664,6 +46909,358 @@ var init_session_hooks = __esm({
46664
46909
  }
46665
46910
  });
46666
46911
 
46912
+ // packages/core/src/memory/quality-feedback.ts
46913
+ var quality_feedback_exports = {};
46914
+ __export(quality_feedback_exports, {
46915
+ correlateOutcomes: () => correlateOutcomes,
46916
+ getMemoryQualityReport: () => getMemoryQualityReport,
46917
+ trackMemoryUsage: () => trackMemoryUsage
46918
+ });
46919
+ async function ensureUsageLogTable(projectRoot) {
46920
+ const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
46921
+ await getBrainDb2(projectRoot);
46922
+ const nativeDb = getBrainNativeDb2();
46923
+ if (!nativeDb) return;
46924
+ try {
46925
+ nativeDb.prepare(
46926
+ `CREATE TABLE IF NOT EXISTS brain_usage_log (
46927
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
46928
+ entry_id TEXT NOT NULL,
46929
+ task_id TEXT,
46930
+ used INTEGER NOT NULL DEFAULT 0,
46931
+ outcome TEXT NOT NULL DEFAULT 'unknown',
46932
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
46933
+ )`
46934
+ ).run();
46935
+ nativeDb.prepare(
46936
+ `CREATE INDEX IF NOT EXISTS idx_brain_usage_log_entry_id
46937
+ ON brain_usage_log(entry_id)`
46938
+ ).run();
46939
+ nativeDb.prepare(
46940
+ `CREATE INDEX IF NOT EXISTS idx_brain_usage_log_task_id
46941
+ ON brain_usage_log(task_id)`
46942
+ ).run();
46943
+ } catch {
46944
+ }
46945
+ }
46946
+ async function ensurePruneCandidateColumn(projectRoot) {
46947
+ const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
46948
+ await getBrainDb2(projectRoot);
46949
+ const nativeDb = getBrainNativeDb2();
46950
+ if (!nativeDb) return;
46951
+ const tables = [
46952
+ "brain_decisions",
46953
+ "brain_patterns",
46954
+ "brain_learnings",
46955
+ "brain_observations"
46956
+ ];
46957
+ for (const tbl of tables) {
46958
+ try {
46959
+ nativeDb.prepare(`ALTER TABLE ${tbl} ADD COLUMN prune_candidate INTEGER DEFAULT 0`).run();
46960
+ } catch {
46961
+ }
46962
+ }
46963
+ }
46964
+ async function trackMemoryUsage(projectRoot, memoryId, used, taskId, outcome = "unknown") {
46965
+ if (!memoryId?.trim()) return;
46966
+ await ensureUsageLogTable(projectRoot);
46967
+ const { getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
46968
+ const nativeDb = getBrainNativeDb2();
46969
+ if (!nativeDb) return;
46970
+ const now2 = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
46971
+ try {
46972
+ nativeDb.prepare(
46973
+ `INSERT INTO brain_usage_log (entry_id, task_id, used, outcome, created_at)
46974
+ VALUES (?, ?, ?, ?, ?)`
46975
+ ).run(memoryId, taskId ?? null, used ? 1 : 0, outcome, now2);
46976
+ } catch {
46977
+ }
46978
+ }
46979
+ function tableForId(id) {
46980
+ if (id.startsWith("D-") || /^D\d/.test(id)) return "brain_decisions";
46981
+ if (id.startsWith("P-") || /^P\d/.test(id)) return "brain_patterns";
46982
+ if (id.startsWith("L-") || /^L\d/.test(id)) return "brain_learnings";
46983
+ if (id.startsWith("O-") || id.startsWith("CM-") || /^O/.test(id)) return "brain_observations";
46984
+ return null;
46985
+ }
46986
+ function applyQualityDelta(nativeDb, table, id, delta, now2) {
46987
+ if (!nativeDb) return;
46988
+ try {
46989
+ nativeDb.prepare(
46990
+ `UPDATE ${table}
46991
+ SET quality_score = MAX(0.0, MIN(1.0, COALESCE(quality_score, 0.5) + ?)),
46992
+ updated_at = ?
46993
+ WHERE id = ?`
46994
+ ).run(delta, now2, id);
46995
+ } catch {
46996
+ }
46997
+ }
46998
+ async function correlateOutcomes(projectRoot) {
46999
+ await ensureUsageLogTable(projectRoot);
47000
+ await ensurePruneCandidateColumn(projectRoot);
47001
+ const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
47002
+ await getBrainDb2(projectRoot);
47003
+ const nativeDb = getBrainNativeDb2();
47004
+ const ranAt = (/* @__PURE__ */ new Date()).toISOString();
47005
+ if (!nativeDb) {
47006
+ return { boosted: 0, penalized: 0, flaggedForPruning: 0, ranAt };
47007
+ }
47008
+ const now2 = ranAt.replace("T", " ").slice(0, 19);
47009
+ let boosted = 0;
47010
+ let penalized = 0;
47011
+ let usageRows = [];
47012
+ try {
47013
+ usageRows = typedAll(
47014
+ nativeDb.prepare(
47015
+ `SELECT entry_id, outcome, SUM(used) AS used_count
47016
+ FROM brain_usage_log
47017
+ WHERE outcome IN ('success', 'failure')
47018
+ GROUP BY entry_id, outcome`
47019
+ )
47020
+ );
47021
+ } catch {
47022
+ usageRows = [];
47023
+ }
47024
+ for (const row of usageRows) {
47025
+ const table = tableForId(row.entry_id);
47026
+ if (!table) continue;
47027
+ if (row.outcome === "success" && row.used_count > 0) {
47028
+ applyQualityDelta(nativeDb, table, row.entry_id, 0.05, now2);
47029
+ boosted++;
47030
+ } else if (row.outcome === "failure" && row.used_count > 0) {
47031
+ applyQualityDelta(nativeDb, table, row.entry_id, -0.05, now2);
47032
+ penalized++;
47033
+ }
47034
+ }
47035
+ const cutoffDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3).toISOString().replace("T", " ").slice(0, 19);
47036
+ let flaggedForPruning = 0;
47037
+ const pruneTargetTables = [
47038
+ { table: "brain_decisions", dateCol: "created_at" },
47039
+ { table: "brain_patterns", dateCol: "extracted_at" },
47040
+ { table: "brain_learnings", dateCol: "created_at" },
47041
+ { table: "brain_observations", dateCol: "created_at" }
47042
+ ];
47043
+ for (const { table, dateCol } of pruneTargetTables) {
47044
+ try {
47045
+ const result = nativeDb.prepare(
47046
+ `UPDATE ${table}
47047
+ SET prune_candidate = 1
47048
+ WHERE COALESCE(citation_count, 0) = 0
47049
+ AND ${dateCol} < ?`
47050
+ ).run(cutoffDate);
47051
+ flaggedForPruning += result.changes ?? 0;
47052
+ } catch {
47053
+ }
47054
+ }
47055
+ return { boosted, penalized, flaggedForPruning, ranAt };
47056
+ }
47057
+ async function getMemoryQualityReport(projectRoot) {
47058
+ await ensureUsageLogTable(projectRoot);
47059
+ const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
47060
+ await getBrainDb2(projectRoot);
47061
+ const nativeDb = getBrainNativeDb2();
47062
+ const emptyReport = {
47063
+ totalRetrievals: 0,
47064
+ uniqueEntriesRetrieved: 0,
47065
+ usageRate: 0,
47066
+ topRetrieved: [],
47067
+ neverRetrieved: [],
47068
+ qualityDistribution: { low: 0, medium: 0, high: 0 },
47069
+ tierDistribution: { short: 0, medium: 0, long: 0, unknown: 0 },
47070
+ noiseRatio: 0
47071
+ };
47072
+ if (!nativeDb) return emptyReport;
47073
+ let totalRetrievals = 0;
47074
+ let uniqueEntriesRetrieved = 0;
47075
+ try {
47076
+ const logCount = typedAll(
47077
+ nativeDb.prepare("SELECT COUNT(*) AS cnt FROM brain_retrieval_log")
47078
+ );
47079
+ totalRetrievals = logCount[0]?.cnt ?? 0;
47080
+ const uniqueCount = typedAll(
47081
+ nativeDb.prepare(
47082
+ `SELECT COUNT(DISTINCT value) AS cnt
47083
+ FROM brain_retrieval_log,
47084
+ json_each('["' || replace(entry_ids, ',', '","') || '"]')`
47085
+ )
47086
+ );
47087
+ uniqueEntriesRetrieved = uniqueCount[0]?.cnt ?? 0;
47088
+ } catch {
47089
+ }
47090
+ let usageRate = 0;
47091
+ try {
47092
+ const totalUsage = typedAll(
47093
+ nativeDb.prepare("SELECT COUNT(*) AS cnt FROM brain_usage_log")
47094
+ );
47095
+ const usedCount = typedAll(
47096
+ nativeDb.prepare("SELECT COUNT(*) AS cnt FROM brain_usage_log WHERE used = 1")
47097
+ );
47098
+ const total = totalUsage[0]?.cnt ?? 0;
47099
+ const used = usedCount[0]?.cnt ?? 0;
47100
+ usageRate = total > 0 ? used / total : 0;
47101
+ } catch {
47102
+ }
47103
+ const topRetrieved = [];
47104
+ try {
47105
+ const rows = typedAll(
47106
+ nativeDb.prepare(
47107
+ `SELECT id,
47108
+ 'decision' AS type,
47109
+ decision AS title,
47110
+ COALESCE(citation_count, 0) AS citation_count
47111
+ FROM brain_decisions
47112
+ UNION ALL
47113
+ SELECT id,
47114
+ 'pattern' AS type,
47115
+ pattern AS title,
47116
+ COALESCE(citation_count, 0) AS citation_count
47117
+ FROM brain_patterns
47118
+ UNION ALL
47119
+ SELECT id,
47120
+ 'learning' AS type,
47121
+ insight AS title,
47122
+ COALESCE(citation_count, 0) AS citation_count
47123
+ FROM brain_learnings
47124
+ UNION ALL
47125
+ SELECT id,
47126
+ 'observation' AS type,
47127
+ title AS title,
47128
+ COALESCE(citation_count, 0) AS citation_count
47129
+ FROM brain_observations
47130
+ ORDER BY citation_count DESC
47131
+ LIMIT 10`
47132
+ )
47133
+ );
47134
+ for (const r of rows) {
47135
+ topRetrieved.push({
47136
+ id: r.id,
47137
+ type: r.type,
47138
+ title: String(r.title ?? "").slice(0, 120),
47139
+ citationCount: r.citation_count
47140
+ });
47141
+ }
47142
+ } catch {
47143
+ }
47144
+ const neverRetrieved = [];
47145
+ try {
47146
+ const rows = typedAll(
47147
+ nativeDb.prepare(
47148
+ `SELECT id,
47149
+ 'decision' AS type,
47150
+ decision AS title,
47151
+ COALESCE(quality_score, 0.5) AS quality_score
47152
+ FROM brain_decisions
47153
+ WHERE COALESCE(citation_count, 0) = 0
47154
+ UNION ALL
47155
+ SELECT id,
47156
+ 'pattern' AS type,
47157
+ pattern AS title,
47158
+ COALESCE(quality_score, 0.5) AS quality_score
47159
+ FROM brain_patterns
47160
+ WHERE COALESCE(citation_count, 0) = 0
47161
+ UNION ALL
47162
+ SELECT id,
47163
+ 'learning' AS type,
47164
+ insight AS title,
47165
+ COALESCE(quality_score, 0.5) AS quality_score
47166
+ FROM brain_learnings
47167
+ WHERE COALESCE(citation_count, 0) = 0
47168
+ UNION ALL
47169
+ SELECT id,
47170
+ 'observation' AS type,
47171
+ title AS title,
47172
+ COALESCE(quality_score, 0.5) AS quality_score
47173
+ FROM brain_observations
47174
+ WHERE COALESCE(citation_count, 0) = 0
47175
+ ORDER BY quality_score ASC
47176
+ LIMIT 10`
47177
+ )
47178
+ );
47179
+ for (const r of rows) {
47180
+ neverRetrieved.push({
47181
+ id: r.id,
47182
+ type: r.type,
47183
+ title: String(r.title ?? "").slice(0, 120),
47184
+ qualityScore: r.quality_score
47185
+ });
47186
+ }
47187
+ } catch {
47188
+ }
47189
+ let qualityDistribution = { low: 0, medium: 0, high: 0 };
47190
+ try {
47191
+ const rows = typedAll(
47192
+ nativeDb.prepare(
47193
+ `SELECT
47194
+ SUM(CASE WHEN qs < 0.3 THEN 1 ELSE 0 END) AS low,
47195
+ SUM(CASE WHEN qs >= 0.3 AND qs <= 0.6 THEN 1 ELSE 0 END) AS medium,
47196
+ SUM(CASE WHEN qs > 0.6 THEN 1 ELSE 0 END) AS high
47197
+ FROM (
47198
+ SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_decisions
47199
+ UNION ALL
47200
+ SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_patterns
47201
+ UNION ALL
47202
+ SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_learnings
47203
+ UNION ALL
47204
+ SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_observations
47205
+ )`
47206
+ )
47207
+ );
47208
+ if (rows[0]) {
47209
+ qualityDistribution = {
47210
+ low: rows[0].low ?? 0,
47211
+ medium: rows[0].medium ?? 0,
47212
+ high: rows[0].high ?? 0
47213
+ };
47214
+ }
47215
+ } catch {
47216
+ }
47217
+ const tierDistribution = { short: 0, medium: 0, long: 0, unknown: 0 };
47218
+ try {
47219
+ const rows = typedAll(
47220
+ nativeDb.prepare(
47221
+ `SELECT memory_tier AS tier, COUNT(*) AS cnt
47222
+ FROM (
47223
+ SELECT memory_tier FROM brain_decisions
47224
+ UNION ALL
47225
+ SELECT memory_tier FROM brain_patterns
47226
+ UNION ALL
47227
+ SELECT memory_tier FROM brain_learnings
47228
+ UNION ALL
47229
+ SELECT memory_tier FROM brain_observations
47230
+ )
47231
+ GROUP BY memory_tier`
47232
+ )
47233
+ );
47234
+ for (const r of rows) {
47235
+ const tier = r.tier?.toLowerCase() ?? "unknown";
47236
+ if (tier === "short" || tier === "medium" || tier === "long") {
47237
+ tierDistribution[tier] += r.cnt;
47238
+ } else {
47239
+ tierDistribution.unknown += r.cnt;
47240
+ }
47241
+ }
47242
+ } catch {
47243
+ }
47244
+ const totalEntries = qualityDistribution.low + qualityDistribution.medium + qualityDistribution.high;
47245
+ const noiseRatio = totalEntries > 0 ? qualityDistribution.low / totalEntries : 0;
47246
+ return {
47247
+ totalRetrievals,
47248
+ uniqueEntriesRetrieved,
47249
+ usageRate,
47250
+ topRetrieved,
47251
+ neverRetrieved,
47252
+ qualityDistribution,
47253
+ tierDistribution,
47254
+ noiseRatio
47255
+ };
47256
+ }
47257
+ var init_quality_feedback = __esm({
47258
+ "packages/core/src/memory/quality-feedback.ts"() {
47259
+ "use strict";
47260
+ init_typed_query();
47261
+ }
47262
+ });
47263
+
46667
47264
  // packages/core/src/hooks/handlers/task-hooks.ts
46668
47265
  async function handleToolStart(projectRoot, payload) {
46669
47266
  const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
@@ -46697,6 +47294,13 @@ async function handleToolComplete(projectRoot, payload) {
46697
47294
  } catch {
46698
47295
  }
46699
47296
  });
47297
+ setImmediate(async () => {
47298
+ try {
47299
+ const { correlateOutcomes: correlateOutcomes2 } = await Promise.resolve().then(() => (init_quality_feedback(), quality_feedback_exports));
47300
+ await correlateOutcomes2(projectRoot);
47301
+ } catch {
47302
+ }
47303
+ });
46700
47304
  await maybeRefreshMemoryBridge(projectRoot);
46701
47305
  }
46702
47306
  var init_task_hooks = __esm({
@@ -53194,7 +53798,7 @@ function generateRecommendation2(changeType, affectedCount, cascadeDepth, taskId
53194
53798
  }
53195
53799
  }
53196
53800
  function scoreTaskMatch(change, task) {
53197
- const STOP_WORDS4 = /* @__PURE__ */ new Set([
53801
+ const STOP_WORDS5 = /* @__PURE__ */ new Set([
53198
53802
  "a",
53199
53803
  "an",
53200
53804
  "the",
@@ -53216,7 +53820,7 @@ function scoreTaskMatch(change, task) {
53216
53820
  "do",
53217
53821
  "not"
53218
53822
  ]);
53219
- const tokenise = (text3) => text3.toLowerCase().split(/\W+/).filter((t) => t.length > 2 && !STOP_WORDS4.has(t));
53823
+ const tokenise = (text3) => text3.toLowerCase().split(/\W+/).filter((t) => t.length > 2 && !STOP_WORDS5.has(t));
53220
53824
  const changeTokens = new Set(tokenise(change));
53221
53825
  if (changeTokens.size === 0) return 0;
53222
53826
  const taskText = `${task.title ?? ""} ${task.description ?? ""}`;
@@ -59666,6 +60270,7 @@ __export(memory_exports, {
59666
60270
  bulkLink: () => bulkLink,
59667
60271
  compactManifest: () => compactManifest,
59668
60272
  consolidateMemories: () => consolidateMemories,
60273
+ correlateOutcomes: () => correlateOutcomes,
59669
60274
  detectContradictions: () => detectContradictions,
59670
60275
  ensureFts5Tables: () => ensureFts5Tables,
59671
60276
  fetchBrainEntries: () => fetchBrainEntries,
@@ -59676,6 +60281,7 @@ __export(memory_exports, {
59676
60281
  getLinkedLearnings: () => getLinkedLearnings,
59677
60282
  getLinkedPatterns: () => getLinkedPatterns,
59678
60283
  getMemoryLinks: () => getMemoryLinks,
60284
+ getMemoryQualityReport: () => getMemoryQualityReport,
59679
60285
  getTaskLinks: () => getTaskLinks,
59680
60286
  hybridSearch: () => hybridSearch,
59681
60287
  learningStats: () => learningStats,
@@ -59717,6 +60323,7 @@ __export(memory_exports, {
59717
60323
  storePattern: () => storePattern,
59718
60324
  storeVerifiedCandidate: () => storeVerifiedCandidate,
59719
60325
  timelineBrain: () => timelineBrain,
60326
+ trackMemoryUsage: () => trackMemoryUsage,
59720
60327
  unlinkMemoryFromTask: () => unlinkMemoryFromTask,
59721
60328
  updateDecisionOutcome: () => updateDecisionOutcome,
59722
60329
  updateResearch: () => updateResearch,
@@ -60339,6 +60946,7 @@ var init_memory = __esm({
60339
60946
  init_extraction_gate();
60340
60947
  init_learnings();
60341
60948
  init_patterns();
60949
+ init_quality_feedback();
60342
60950
  }
60343
60951
  });
60344
60952
 
@@ -64053,8 +64661,8 @@ var init_deps = __esm({
64053
64661
  });
64054
64662
 
64055
64663
  // packages/core/src/nexus/discover.ts
64056
- function extractKeywords3(text3) {
64057
- return text3.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w2) => w2.length > 2 && !STOP_WORDS3.has(w2));
64664
+ function extractKeywords4(text3) {
64665
+ return text3.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w2) => w2.length > 2 && !STOP_WORDS4.has(w2));
64058
64666
  }
64059
64667
  async function discoverRelated(taskQuery, method = "auto", limit = 10) {
64060
64668
  if (!validateSyntax(taskQuery)) {
@@ -64077,7 +64685,7 @@ async function discoverRelated(taskQuery, method = "auto", limit = 10) {
64077
64685
  const sourceLabels = new Set(sourceTask.labels ?? []);
64078
64686
  const sourceDesc = (sourceTask.description ?? "").toLowerCase();
64079
64687
  const sourceTitle = (sourceTask.title ?? "").toLowerCase();
64080
- const sourceWords = extractKeywords3(sourceTitle + " " + sourceDesc);
64688
+ const sourceWords = extractKeywords4(sourceTitle + " " + sourceDesc);
64081
64689
  const parsed = parseQuery(taskQuery);
64082
64690
  const registry2 = await readRegistry();
64083
64691
  if (!registry2) {
@@ -64112,7 +64720,7 @@ async function discoverRelated(taskQuery, method = "auto", limit = 10) {
64112
64720
  }
64113
64721
  if (method === "description" || method === "auto") {
64114
64722
  const taskDesc = ((task.description ?? "") + " " + (task.title ?? "")).toLowerCase();
64115
- const taskWords = extractKeywords3(taskDesc);
64723
+ const taskWords = extractKeywords4(taskDesc);
64116
64724
  const commonWords = sourceWords.filter((w2) => taskWords.includes(w2));
64117
64725
  if (commonWords.length > 0) {
64118
64726
  const descScore = commonWords.length / Math.max(sourceWords.length, taskWords.length, 1);
@@ -64211,14 +64819,14 @@ async function searchAcrossProjects(pattern, projectFilter, limit = 20) {
64211
64819
  const sliced = results.slice(0, limit);
64212
64820
  return { pattern, results: sliced, resultCount: sliced.length };
64213
64821
  }
64214
- var STOP_WORDS3;
64822
+ var STOP_WORDS4;
64215
64823
  var init_discover = __esm({
64216
64824
  "packages/core/src/nexus/discover.ts"() {
64217
64825
  "use strict";
64218
64826
  init_data_accessor();
64219
64827
  init_query4();
64220
64828
  init_registry3();
64221
- STOP_WORDS3 = /* @__PURE__ */ new Set([
64829
+ STOP_WORDS4 = /* @__PURE__ */ new Set([
64222
64830
  "the",
64223
64831
  "a",
64224
64832
  "an",
@@ -66038,7 +66646,7 @@ __export(nexus_exports, {
66038
66646
  criticalPath: () => criticalPath,
66039
66647
  discoverRelated: () => discoverRelated,
66040
66648
  executeTransfer: () => executeTransfer,
66041
- extractKeywords: () => extractKeywords3,
66649
+ extractKeywords: () => extractKeywords4,
66042
66650
  generateProjectHash: () => generateProjectHash,
66043
66651
  getCurrentProject: () => getCurrentProject,
66044
66652
  getNexusCacheDir: () => getNexusCacheDir,
@@ -70464,6 +71072,7 @@ __export(research_exports, {
70464
71072
  bulkLink: () => bulkLink,
70465
71073
  compactManifest: () => compactManifest,
70466
71074
  consolidateMemories: () => consolidateMemories,
71075
+ correlateOutcomes: () => correlateOutcomes,
70467
71076
  detectContradictions: () => detectContradictions,
70468
71077
  ensureFts5Tables: () => ensureFts5Tables,
70469
71078
  fetchBrainEntries: () => fetchBrainEntries,
@@ -70474,6 +71083,7 @@ __export(research_exports, {
70474
71083
  getLinkedLearnings: () => getLinkedLearnings,
70475
71084
  getLinkedPatterns: () => getLinkedPatterns,
70476
71085
  getMemoryLinks: () => getMemoryLinks,
71086
+ getMemoryQualityReport: () => getMemoryQualityReport,
70477
71087
  getTaskLinks: () => getTaskLinks,
70478
71088
  hybridSearch: () => hybridSearch,
70479
71089
  learningStats: () => learningStats,
@@ -70515,6 +71125,7 @@ __export(research_exports, {
70515
71125
  storePattern: () => storePattern,
70516
71126
  storeVerifiedCandidate: () => storeVerifiedCandidate,
70517
71127
  timelineBrain: () => timelineBrain,
71128
+ trackMemoryUsage: () => trackMemoryUsage,
70518
71129
  unlinkMemoryFromTask: () => unlinkMemoryFromTask,
70519
71130
  updateDecisionOutcome: () => updateDecisionOutcome,
70520
71131
  updateResearch: () => updateResearch,
@@ -90884,6 +91495,22 @@ async function memoryGraphRemove(params, projectRoot) {
90884
91495
  };
90885
91496
  }
90886
91497
  }
91498
+ async function memoryQualityReport(projectRoot) {
91499
+ try {
91500
+ const root = resolveRoot(projectRoot);
91501
+ const { getMemoryQualityReport: getMemoryQualityReport2 } = await Promise.resolve().then(() => (init_quality_feedback(), quality_feedback_exports));
91502
+ const report = await getMemoryQualityReport2(root);
91503
+ return { success: true, data: report };
91504
+ } catch (error48) {
91505
+ return {
91506
+ success: false,
91507
+ error: {
91508
+ code: "E_QUALITY_REPORT",
91509
+ message: error48 instanceof Error ? error48.message : String(error48)
91510
+ }
91511
+ };
91512
+ }
91513
+ }
90887
91514
  var init_engine_compat = __esm({
90888
91515
  "packages/core/src/memory/engine-compat.ts"() {
90889
91516
  "use strict";
@@ -109522,12 +110149,12 @@ import { join as join119 } from "node:path";
109522
110149
  function typedAll4(db, sql14, ...params) {
109523
110150
  return db.prepare(sql14).all(...params);
109524
110151
  }
109525
- function typedGet(db, sql14, ...params) {
110152
+ function typedGet2(db, sql14, ...params) {
109526
110153
  return db.prepare(sql14).get(...params);
109527
110154
  }
109528
110155
  function queryIndexMeta(db, projectId) {
109529
110156
  try {
109530
- const nodeMeta = typedGet(
110157
+ const nodeMeta = typedGet2(
109531
110158
  db,
109532
110159
  `SELECT COUNT(*) as total_nodes,
109533
110160
  COUNT(CASE WHEN kind = 'file' THEN 1 END) as file_count,
@@ -109536,7 +110163,7 @@ function queryIndexMeta(db, projectId) {
109536
110163
  WHERE project_id = ?`,
109537
110164
  projectId
109538
110165
  );
109539
- const relMeta = typedGet(
110166
+ const relMeta = typedGet2(
109540
110167
  db,
109541
110168
  `SELECT COUNT(*) as total_relations
109542
110169
  FROM nexus_relations
@@ -109631,7 +110258,7 @@ function queryCommunities(db, projectId, limit = 6) {
109631
110258
  }
109632
110259
  function queryProcessCount(db, projectId) {
109633
110260
  try {
109634
- const row = typedGet(
110261
+ const row = typedGet2(
109635
110262
  db,
109636
110263
  `SELECT COUNT(*) as count
109637
110264
  FROM nexus_nodes
@@ -111232,6 +111859,7 @@ __export(internal_exports, {
111232
111859
  coreValidateProtocol: () => coreValidateProtocol,
111233
111860
  coreValidateSchema: () => coreValidateSchema,
111234
111861
  coreValidateTask: () => coreValidateTask,
111862
+ correlateOutcomes: () => correlateOutcomes,
111235
111863
  createBackup: () => createBackup,
111236
111864
  createConduit: () => createConduit,
111237
111865
  createDataAccessor: () => createDataAccessor,
@@ -111384,6 +112012,7 @@ __export(internal_exports, {
111384
112012
  getLinksByTaskId: () => getLinksByTaskId,
111385
112013
  getLogDir: () => getLogDir,
111386
112014
  getLogger: () => getLogger,
112015
+ getMemoryQualityReport: () => getMemoryQualityReport,
111387
112016
  getMigrationStatus: () => getMigrationStatus2,
111388
112017
  getNativeDb: () => getNativeDb,
111389
112018
  getNativeOperations: () => getNativeOperations,
@@ -111554,6 +112183,7 @@ __export(internal_exports, {
111554
112183
  memoryPatternFind: () => memoryPatternFind,
111555
112184
  memoryPatternStats: () => memoryPatternStats,
111556
112185
  memoryPatternStore: () => memoryPatternStore,
112186
+ memoryQualityReport: () => memoryQualityReport,
111557
112187
  memoryReasonSimilar: () => memoryReasonSimilar,
111558
112188
  memoryReasonWhy: () => memoryReasonWhy,
111559
112189
  memorySearchHybrid: () => memorySearchHybrid,
@@ -111766,6 +112396,7 @@ __export(internal_exports, {
111766
112396
  tokenUsageMethodSchema: () => tokenUsageMethodSchema,
111767
112397
  tokenUsageTransportSchema: () => tokenUsageTransportSchema,
111768
112398
  touchLink: () => touchLink,
112399
+ trackMemoryUsage: () => trackMemoryUsage,
111769
112400
  ui: () => ui_exports,
111770
112401
  uncancelTask: () => uncancelTask,
111771
112402
  unpackBundle: () => unpackBundle,
@@ -111853,6 +112484,7 @@ var init_internal = __esm({
111853
112484
  init_claude_mem_migration();
111854
112485
  init_engine_compat();
111855
112486
  init_pipeline_manifest_sqlite();
112487
+ init_quality_feedback();
111856
112488
  init_token_service();
111857
112489
  init_deps();
111858
112490
  init_discover();
@@ -115018,6 +115650,66 @@ var init_registry5 = __esm({
115018
115650
  sessionRequired: false,
115019
115651
  requiredParams: []
115020
115652
  },
115653
+ {
115654
+ gateway: "query",
115655
+ domain: "memory",
115656
+ operation: "quality",
115657
+ description: "Memory quality report: retrieval stats, noise ratio, tier distribution",
115658
+ tier: 1,
115659
+ idempotent: true,
115660
+ sessionRequired: false,
115661
+ requiredParams: []
115662
+ },
115663
+ {
115664
+ gateway: "query",
115665
+ domain: "memory",
115666
+ operation: "code.links",
115667
+ description: "List code_reference edges connecting memories to nexus code symbols",
115668
+ tier: 1,
115669
+ idempotent: true,
115670
+ sessionRequired: false,
115671
+ requiredParams: []
115672
+ },
115673
+ {
115674
+ gateway: "query",
115675
+ domain: "memory",
115676
+ operation: "code.memories-for-code",
115677
+ description: "Find memories linked to a code symbol via code_reference edges",
115678
+ tier: 1,
115679
+ idempotent: true,
115680
+ sessionRequired: false,
115681
+ requiredParams: ["symbol"]
115682
+ },
115683
+ {
115684
+ gateway: "query",
115685
+ domain: "memory",
115686
+ operation: "code.for-memory",
115687
+ description: "Find code symbols linked to a memory entry via code_reference edges",
115688
+ tier: 1,
115689
+ idempotent: true,
115690
+ sessionRequired: false,
115691
+ requiredParams: ["memoryId"]
115692
+ },
115693
+ {
115694
+ gateway: "mutate",
115695
+ domain: "memory",
115696
+ operation: "code.link",
115697
+ description: "Create code_reference edge from memory to nexus symbol",
115698
+ tier: 1,
115699
+ idempotent: false,
115700
+ sessionRequired: false,
115701
+ requiredParams: ["memoryId", "codeSymbol"]
115702
+ },
115703
+ {
115704
+ gateway: "mutate",
115705
+ domain: "memory",
115706
+ operation: "code.auto-link",
115707
+ description: "Scan memories for entity references and auto-link to nexus nodes",
115708
+ tier: 1,
115709
+ idempotent: true,
115710
+ sessionRequired: false,
115711
+ requiredParams: []
115712
+ },
115021
115713
  {
115022
115714
  gateway: "mutate",
115023
115715
  domain: "pipeline",
@@ -123521,6 +124213,33 @@ var init_memory2 = __esm({
123521
124213
  );
123522
124214
  return wrapResult(result, "query", "memory", operation, startTime);
123523
124215
  }
124216
+ case "quality": {
124217
+ const result = await memoryQualityReport(projectRoot);
124218
+ return wrapResult(result, "query", "memory", operation, startTime);
124219
+ }
124220
+ case "code.links": {
124221
+ const { listCodeLinks } = await Promise.resolve().then(() => (init_internal(), internal_exports));
124222
+ const result = await listCodeLinks(projectRoot);
124223
+ return wrapResult(result, "query", "memory", operation, startTime);
124224
+ }
124225
+ case "code.memories-for-code": {
124226
+ const symbol2 = params?.symbol;
124227
+ if (!symbol2) {
124228
+ return errorResult("query", "memory", operation, "E_INVALID_INPUT", "symbol is required", startTime);
124229
+ }
124230
+ const { queryMemoriesForCode } = await Promise.resolve().then(() => (init_internal(), internal_exports));
124231
+ const result = await queryMemoriesForCode(projectRoot, symbol2);
124232
+ return wrapResult({ success: true, data: result }, "query", "memory", operation, startTime);
124233
+ }
124234
+ case "code.for-memory": {
124235
+ const memoryId = params?.memoryId;
124236
+ if (!memoryId) {
124237
+ return errorResult("query", "memory", operation, "E_INVALID_INPUT", "memoryId is required", startTime);
124238
+ }
124239
+ const { queryCodeForMemory } = await Promise.resolve().then(() => (init_internal(), internal_exports));
124240
+ const result = await queryCodeForMemory(projectRoot, memoryId);
124241
+ return wrapResult({ success: true, data: result }, "query", "memory", operation, startTime);
124242
+ }
123524
124243
  default:
123525
124244
  return unsupportedOp("query", "memory", operation, startTime);
123526
124245
  }
@@ -123691,6 +124410,21 @@ var init_memory2 = __esm({
123691
124410
  );
123692
124411
  return wrapResult(result, "mutate", "memory", operation, startTime);
123693
124412
  }
124413
+ case "code.link": {
124414
+ const memoryId = params?.memoryId;
124415
+ const codeSymbol = params?.codeSymbol;
124416
+ if (!memoryId || !codeSymbol) {
124417
+ return errorResult("mutate", "memory", operation, "E_INVALID_INPUT", "memoryId and codeSymbol are required", startTime);
124418
+ }
124419
+ const { linkMemoryToCode } = await Promise.resolve().then(() => (init_internal(), internal_exports));
124420
+ const linked = await linkMemoryToCode(projectRoot, memoryId, codeSymbol);
124421
+ return wrapResult({ success: true, data: { linked } }, "mutate", "memory", operation, startTime);
124422
+ }
124423
+ case "code.auto-link": {
124424
+ const { autoLinkMemories } = await Promise.resolve().then(() => (init_internal(), internal_exports));
124425
+ const result = await autoLinkMemories(projectRoot);
124426
+ return wrapResult({ success: true, data: result }, "mutate", "memory", operation, startTime);
124427
+ }
123694
124428
  default:
123695
124429
  return unsupportedOp("mutate", "memory", operation, startTime);
123696
124430
  }
@@ -123723,7 +124457,11 @@ var init_memory2 = __esm({
123723
124457
  "graph.stats",
123724
124458
  "reason.why",
123725
124459
  "reason.similar",
123726
- "search.hybrid"
124460
+ "search.hybrid",
124461
+ "quality",
124462
+ "code.links",
124463
+ "code.memories-for-code",
124464
+ "code.for-memory"
123727
124465
  ],
123728
124466
  mutate: [
123729
124467
  "observe",
@@ -123732,7 +124470,9 @@ var init_memory2 = __esm({
123732
124470
  "learning.store",
123733
124471
  "link",
123734
124472
  "graph.add",
123735
- "graph.remove"
124473
+ "graph.remove",
124474
+ "code.link",
124475
+ "code.auto-link"
123736
124476
  ]
123737
124477
  };
123738
124478
  }
@@ -133450,6 +134190,66 @@ function registerBrainCommand(program) {
133450
134190
  process.exit(1);
133451
134191
  }
133452
134192
  });
134193
+ brain.command("quality").description(
134194
+ "Show memory quality metrics: retrieval rates, top/never-retrieved entries, quality distribution, and noise ratio."
134195
+ ).option("--json", "Output results as JSON").action(async (opts) => {
134196
+ const root = getProjectRoot();
134197
+ const isJson = !!opts.json;
134198
+ try {
134199
+ const report = await getMemoryQualityReport(root);
134200
+ if (isJson) {
134201
+ console.log(
134202
+ JSON.stringify(
134203
+ {
134204
+ success: true,
134205
+ data: report,
134206
+ meta: { operation: "brain.quality", timestamp: (/* @__PURE__ */ new Date()).toISOString() }
134207
+ },
134208
+ null,
134209
+ 2
134210
+ )
134211
+ );
134212
+ return;
134213
+ }
134214
+ console.log("\nBrain Memory Quality Report");
134215
+ console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
134216
+ console.log(` Total retrievals: ${report.totalRetrievals}`);
134217
+ console.log(` Unique entries hit: ${report.uniqueEntriesRetrieved}`);
134218
+ console.log(` Usage rate: ${(report.usageRate * 100).toFixed(1)}%`);
134219
+ console.log(` Noise ratio: ${(report.noiseRatio * 100).toFixed(1)}%`);
134220
+ console.log("\nQuality Distribution");
134221
+ console.log(` Low (<0.3): ${report.qualityDistribution.low}`);
134222
+ console.log(` Med (0.3-0.6): ${report.qualityDistribution.medium}`);
134223
+ console.log(` High (>0.6): ${report.qualityDistribution.high}`);
134224
+ console.log("\nTier Distribution");
134225
+ console.log(` Short: ${report.tierDistribution.short}`);
134226
+ console.log(` Medium: ${report.tierDistribution.medium}`);
134227
+ console.log(` Long: ${report.tierDistribution.long}`);
134228
+ if (report.tierDistribution.unknown > 0) {
134229
+ console.log(` Unknown: ${report.tierDistribution.unknown}`);
134230
+ }
134231
+ if (report.topRetrieved.length > 0) {
134232
+ console.log("\nTop 10 Most Retrieved");
134233
+ for (const e of report.topRetrieved) {
134234
+ console.log(` [${e.citationCount}x] ${e.id} ${e.title.slice(0, 60)}`);
134235
+ }
134236
+ }
134237
+ if (report.neverRetrieved.length > 0) {
134238
+ console.log("\nNever Retrieved (pruning candidates)");
134239
+ for (const e of report.neverRetrieved) {
134240
+ console.log(` q=${e.qualityScore.toFixed(2)} ${e.id} ${e.title.slice(0, 60)}`);
134241
+ }
134242
+ }
134243
+ } catch (err) {
134244
+ const message = err instanceof Error ? err.message : String(err);
134245
+ if (isJson) {
134246
+ console.log(JSON.stringify({ success: false, error: message }));
134247
+ } else {
134248
+ console.error(`Brain quality report failed: ${message}`);
134249
+ }
134250
+ process.exit(1);
134251
+ }
134252
+ });
133453
134253
  }
133454
134254
 
133455
134255
  // packages/cleo/src/cli/commands/briefing.ts
@@ -136519,6 +137319,47 @@ function registerMemoryBrainCommand(program) {
136519
137319
  { command: "memory", operation: "memory.search.hybrid" }
136520
137320
  );
136521
137321
  });
137322
+ memory.command("code-links").description("Show code \u2194 memory connections (code_reference edges between brain and nexus)").option("--limit <n>", "Maximum entries to return (default 100)", parseInt).option("--json", "Output as JSON").action(async (opts) => {
137323
+ await dispatchFromCli(
137324
+ "query",
137325
+ "memory",
137326
+ "code.links",
137327
+ {
137328
+ ...opts["limit"] !== void 0 && { limit: opts["limit"] }
137329
+ },
137330
+ { command: "memory", operation: "memory.code.links" }
137331
+ );
137332
+ });
137333
+ memory.command("code-auto-link").description("Scan brain memory nodes for entity references and auto-link to nexus code nodes").option("--json", "Output as JSON").action(async () => {
137334
+ await dispatchFromCli(
137335
+ "mutate",
137336
+ "memory",
137337
+ "code.auto-link",
137338
+ {},
137339
+ {
137340
+ command: "memory",
137341
+ operation: "memory.code.auto-link"
137342
+ }
137343
+ );
137344
+ });
137345
+ memory.command("code-memories-for-code <symbol>").description("Find brain memory nodes that reference a given nexus code symbol").option("--json", "Output as JSON").action(async (symbol2) => {
137346
+ await dispatchFromCli(
137347
+ "query",
137348
+ "memory",
137349
+ "code.memories-for-code",
137350
+ { symbol: symbol2 },
137351
+ { command: "memory", operation: "memory.code.memories-for-code" }
137352
+ );
137353
+ });
137354
+ memory.command("code-for-memory <memoryId>").description("Find nexus code nodes referenced by a given brain memory entry").option("--json", "Output as JSON").action(async (memoryId) => {
137355
+ await dispatchFromCli(
137356
+ "query",
137357
+ "memory",
137358
+ "code.for-memory",
137359
+ { memoryId },
137360
+ { command: "memory", operation: "memory.code.for-memory" }
137361
+ );
137362
+ });
136522
137363
  }
136523
137364
 
136524
137365
  // packages/cleo/src/cli/commands/migrate-claude-mem.ts