@cleocode/cleo 2026.4.36 → 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 +884 -41
  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
 
@@ -45205,7 +45450,9 @@ async function extractFromTranscript(options) {
45205
45450
  const maxTranscriptChars = llmCfg?.maxTranscriptChars ?? 6e4;
45206
45451
  const client = options.client ?? await buildAnthropicClient();
45207
45452
  if (!client) {
45208
- report.warnings.push("No Anthropic API key found (checked ANTHROPIC_API_KEY env and ~/.claude/.credentials.json) \u2014 extraction skipped");
45453
+ report.warnings.push(
45454
+ "No Anthropic API key found (checked ANTHROPIC_API_KEY env and ~/.claude/.credentials.json) \u2014 extraction skipped"
45455
+ );
45209
45456
  return report;
45210
45457
  }
45211
45458
  const clipped = clipTranscript(transcript, maxTranscriptChars);
@@ -45367,11 +45614,11 @@ var brain_consolidator_exports = {};
45367
45614
  __export(brain_consolidator_exports, {
45368
45615
  detectContradictions: () => detectContradictions
45369
45616
  });
45370
- function extractKeywords(text3) {
45617
+ function extractKeywords2(text3) {
45371
45618
  const words = text3.toLowerCase().replace(/[^a-z0-9\s\-_]/g, " ").split(/\s+/);
45372
45619
  const keywords = /* @__PURE__ */ new Set();
45373
45620
  for (const w2 of words) {
45374
- if (w2.length >= 4 && !STOP_WORDS.has(w2)) {
45621
+ if (w2.length >= 4 && !STOP_WORDS2.has(w2)) {
45375
45622
  keywords.add(w2);
45376
45623
  }
45377
45624
  }
@@ -45420,7 +45667,7 @@ async function detectContradictions(projectRoot) {
45420
45667
  const keywordMap = /* @__PURE__ */ new Map();
45421
45668
  const negationMap = /* @__PURE__ */ new Map();
45422
45669
  for (const entry of entries) {
45423
- keywordMap.set(entry.id, extractKeywords(entry.text));
45670
+ keywordMap.set(entry.id, extractKeywords2(entry.text));
45424
45671
  negationMap.set(entry.id, findNegationMarkers(entry.text));
45425
45672
  }
45426
45673
  for (let i = 0; i < entries.length; i++) {
@@ -45434,7 +45681,7 @@ async function detectContradictions(projectRoot) {
45434
45681
  const keywordsB = keywordMap.get(entryB.id);
45435
45682
  const negationsB = negationMap.get(entryB.id);
45436
45683
  const shared = keywordIntersection(keywordsA, keywordsB);
45437
- if (shared.length < MIN_SHARED_KEYWORDS) continue;
45684
+ if (shared.length < MIN_SHARED_KEYWORDS2) continue;
45438
45685
  const negationsOnlyInA = negationsA.filter((m2) => !negationsB.includes(m2));
45439
45686
  const negationsOnlyInB = negationsB.filter((m2) => !negationsA.includes(m2));
45440
45687
  const negationFlip = negationsOnlyInA.length > 0 || negationsOnlyInB.length > 0;
@@ -45452,8 +45699,8 @@ async function detectContradictions(projectRoot) {
45452
45699
  sharedKeywords: shared.slice(0, 10),
45453
45700
  negationMarkers: negMarkers.slice(0, 5)
45454
45701
  });
45455
- const nodeA = buildNodeId(table, entryA.id);
45456
- const nodeB = buildNodeId(table, entryB.id);
45702
+ const nodeA = buildNodeId2(table, entryA.id);
45703
+ const nodeB = buildNodeId2(table, entryB.id);
45457
45704
  try {
45458
45705
  nativeDb.prepare(`
45459
45706
  INSERT OR IGNORE INTO brain_page_edges
@@ -45482,7 +45729,7 @@ async function detectContradictions(projectRoot) {
45482
45729
  }
45483
45730
  return results;
45484
45731
  }
45485
- function buildNodeId(table, entryId) {
45732
+ function buildNodeId2(table, entryId) {
45486
45733
  const typeMap = {
45487
45734
  brain_observations: "observation",
45488
45735
  brain_learnings: "learning",
@@ -45492,13 +45739,13 @@ function buildNodeId(table, entryId) {
45492
45739
  const type = typeMap[table] ?? "entry";
45493
45740
  return `${type}:${entryId}`;
45494
45741
  }
45495
- var MIN_SHARED_KEYWORDS, NEGATION_MARKERS, STOP_WORDS;
45742
+ var MIN_SHARED_KEYWORDS2, NEGATION_MARKERS, STOP_WORDS2;
45496
45743
  var init_brain_consolidator = __esm({
45497
45744
  "packages/core/src/memory/brain-consolidator.ts"() {
45498
45745
  "use strict";
45499
45746
  init_brain_sqlite();
45500
45747
  init_typed_query();
45501
- MIN_SHARED_KEYWORDS = 3;
45748
+ MIN_SHARED_KEYWORDS2 = 3;
45502
45749
  NEGATION_MARKERS = [
45503
45750
  "not",
45504
45751
  "never",
@@ -45519,7 +45766,7 @@ var init_brain_consolidator = __esm({
45519
45766
  "undone",
45520
45767
  "superseded"
45521
45768
  ];
45522
- STOP_WORDS = /* @__PURE__ */ new Set([
45769
+ STOP_WORDS2 = /* @__PURE__ */ new Set([
45523
45770
  "the",
45524
45771
  "a",
45525
45772
  "an",
@@ -45607,11 +45854,11 @@ async function applyTemporalDecay(projectRoot, options) {
45607
45854
  tablesProcessed: ["brain_learnings"]
45608
45855
  };
45609
45856
  }
45610
- function extractKeywords2(text3) {
45857
+ function extractKeywords3(text3) {
45611
45858
  const words = text3.toLowerCase().replace(/[^a-z0-9\s-]/g, "").split(/\s+/);
45612
45859
  const keywords = /* @__PURE__ */ new Set();
45613
45860
  for (const w2 of words) {
45614
- if (w2.length >= 4 && !STOP_WORDS2.has(w2)) {
45861
+ if (w2.length >= 4 && !STOP_WORDS3.has(w2)) {
45615
45862
  keywords.add(w2);
45616
45863
  }
45617
45864
  }
@@ -45649,7 +45896,7 @@ async function consolidateMemories(projectRoot, options) {
45649
45896
  }
45650
45897
  const entries = oldObservations.map((obs) => ({
45651
45898
  ...obs,
45652
- keywords: extractKeywords2(`${obs.title} ${obs.narrative ?? ""}`),
45899
+ keywords: extractKeywords3(`${obs.title} ${obs.narrative ?? ""}`),
45653
45900
  clustered: false
45654
45901
  }));
45655
45902
  const clusters = [];
@@ -46051,13 +46298,13 @@ async function strengthenCoRetrievedEdges(projectRoot) {
46051
46298
  }
46052
46299
  return strengthened;
46053
46300
  }
46054
- var STOP_WORDS2;
46301
+ var STOP_WORDS3;
46055
46302
  var init_brain_lifecycle = __esm({
46056
46303
  "packages/core/src/memory/brain-lifecycle.ts"() {
46057
46304
  "use strict";
46058
46305
  init_brain_accessor();
46059
46306
  init_typed_query();
46060
- STOP_WORDS2 = /* @__PURE__ */ new Set([
46307
+ STOP_WORDS3 = /* @__PURE__ */ new Set([
46061
46308
  "the",
46062
46309
  "a",
46063
46310
  "an",
@@ -46662,6 +46909,358 @@ var init_session_hooks = __esm({
46662
46909
  }
46663
46910
  });
46664
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
+
46665
47264
  // packages/core/src/hooks/handlers/task-hooks.ts
46666
47265
  async function handleToolStart(projectRoot, payload) {
46667
47266
  const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
@@ -46695,6 +47294,13 @@ async function handleToolComplete(projectRoot, payload) {
46695
47294
  } catch {
46696
47295
  }
46697
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
+ });
46698
47304
  await maybeRefreshMemoryBridge(projectRoot);
46699
47305
  }
46700
47306
  var init_task_hooks = __esm({
@@ -53192,7 +53798,7 @@ function generateRecommendation2(changeType, affectedCount, cascadeDepth, taskId
53192
53798
  }
53193
53799
  }
53194
53800
  function scoreTaskMatch(change, task) {
53195
- const STOP_WORDS4 = /* @__PURE__ */ new Set([
53801
+ const STOP_WORDS5 = /* @__PURE__ */ new Set([
53196
53802
  "a",
53197
53803
  "an",
53198
53804
  "the",
@@ -53214,7 +53820,7 @@ function scoreTaskMatch(change, task) {
53214
53820
  "do",
53215
53821
  "not"
53216
53822
  ]);
53217
- 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));
53218
53824
  const changeTokens = new Set(tokenise(change));
53219
53825
  if (changeTokens.size === 0) return 0;
53220
53826
  const taskText = `${task.title ?? ""} ${task.description ?? ""}`;
@@ -59664,6 +60270,7 @@ __export(memory_exports, {
59664
60270
  bulkLink: () => bulkLink,
59665
60271
  compactManifest: () => compactManifest,
59666
60272
  consolidateMemories: () => consolidateMemories,
60273
+ correlateOutcomes: () => correlateOutcomes,
59667
60274
  detectContradictions: () => detectContradictions,
59668
60275
  ensureFts5Tables: () => ensureFts5Tables,
59669
60276
  fetchBrainEntries: () => fetchBrainEntries,
@@ -59674,6 +60281,7 @@ __export(memory_exports, {
59674
60281
  getLinkedLearnings: () => getLinkedLearnings,
59675
60282
  getLinkedPatterns: () => getLinkedPatterns,
59676
60283
  getMemoryLinks: () => getMemoryLinks,
60284
+ getMemoryQualityReport: () => getMemoryQualityReport,
59677
60285
  getTaskLinks: () => getTaskLinks,
59678
60286
  hybridSearch: () => hybridSearch,
59679
60287
  learningStats: () => learningStats,
@@ -59715,6 +60323,7 @@ __export(memory_exports, {
59715
60323
  storePattern: () => storePattern,
59716
60324
  storeVerifiedCandidate: () => storeVerifiedCandidate,
59717
60325
  timelineBrain: () => timelineBrain,
60326
+ trackMemoryUsage: () => trackMemoryUsage,
59718
60327
  unlinkMemoryFromTask: () => unlinkMemoryFromTask,
59719
60328
  updateDecisionOutcome: () => updateDecisionOutcome,
59720
60329
  updateResearch: () => updateResearch,
@@ -60337,6 +60946,7 @@ var init_memory = __esm({
60337
60946
  init_extraction_gate();
60338
60947
  init_learnings();
60339
60948
  init_patterns();
60949
+ init_quality_feedback();
60340
60950
  }
60341
60951
  });
60342
60952
 
@@ -64051,8 +64661,8 @@ var init_deps = __esm({
64051
64661
  });
64052
64662
 
64053
64663
  // packages/core/src/nexus/discover.ts
64054
- function extractKeywords3(text3) {
64055
- 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));
64056
64666
  }
64057
64667
  async function discoverRelated(taskQuery, method = "auto", limit = 10) {
64058
64668
  if (!validateSyntax(taskQuery)) {
@@ -64075,7 +64685,7 @@ async function discoverRelated(taskQuery, method = "auto", limit = 10) {
64075
64685
  const sourceLabels = new Set(sourceTask.labels ?? []);
64076
64686
  const sourceDesc = (sourceTask.description ?? "").toLowerCase();
64077
64687
  const sourceTitle = (sourceTask.title ?? "").toLowerCase();
64078
- const sourceWords = extractKeywords3(sourceTitle + " " + sourceDesc);
64688
+ const sourceWords = extractKeywords4(sourceTitle + " " + sourceDesc);
64079
64689
  const parsed = parseQuery(taskQuery);
64080
64690
  const registry2 = await readRegistry();
64081
64691
  if (!registry2) {
@@ -64110,7 +64720,7 @@ async function discoverRelated(taskQuery, method = "auto", limit = 10) {
64110
64720
  }
64111
64721
  if (method === "description" || method === "auto") {
64112
64722
  const taskDesc = ((task.description ?? "") + " " + (task.title ?? "")).toLowerCase();
64113
- const taskWords = extractKeywords3(taskDesc);
64723
+ const taskWords = extractKeywords4(taskDesc);
64114
64724
  const commonWords = sourceWords.filter((w2) => taskWords.includes(w2));
64115
64725
  if (commonWords.length > 0) {
64116
64726
  const descScore = commonWords.length / Math.max(sourceWords.length, taskWords.length, 1);
@@ -64209,14 +64819,14 @@ async function searchAcrossProjects(pattern, projectFilter, limit = 20) {
64209
64819
  const sliced = results.slice(0, limit);
64210
64820
  return { pattern, results: sliced, resultCount: sliced.length };
64211
64821
  }
64212
- var STOP_WORDS3;
64822
+ var STOP_WORDS4;
64213
64823
  var init_discover = __esm({
64214
64824
  "packages/core/src/nexus/discover.ts"() {
64215
64825
  "use strict";
64216
64826
  init_data_accessor();
64217
64827
  init_query4();
64218
64828
  init_registry3();
64219
- STOP_WORDS3 = /* @__PURE__ */ new Set([
64829
+ STOP_WORDS4 = /* @__PURE__ */ new Set([
64220
64830
  "the",
64221
64831
  "a",
64222
64832
  "an",
@@ -66036,7 +66646,7 @@ __export(nexus_exports, {
66036
66646
  criticalPath: () => criticalPath,
66037
66647
  discoverRelated: () => discoverRelated,
66038
66648
  executeTransfer: () => executeTransfer,
66039
- extractKeywords: () => extractKeywords3,
66649
+ extractKeywords: () => extractKeywords4,
66040
66650
  generateProjectHash: () => generateProjectHash,
66041
66651
  getCurrentProject: () => getCurrentProject,
66042
66652
  getNexusCacheDir: () => getNexusCacheDir,
@@ -70462,6 +71072,7 @@ __export(research_exports, {
70462
71072
  bulkLink: () => bulkLink,
70463
71073
  compactManifest: () => compactManifest,
70464
71074
  consolidateMemories: () => consolidateMemories,
71075
+ correlateOutcomes: () => correlateOutcomes,
70465
71076
  detectContradictions: () => detectContradictions,
70466
71077
  ensureFts5Tables: () => ensureFts5Tables,
70467
71078
  fetchBrainEntries: () => fetchBrainEntries,
@@ -70472,6 +71083,7 @@ __export(research_exports, {
70472
71083
  getLinkedLearnings: () => getLinkedLearnings,
70473
71084
  getLinkedPatterns: () => getLinkedPatterns,
70474
71085
  getMemoryLinks: () => getMemoryLinks,
71086
+ getMemoryQualityReport: () => getMemoryQualityReport,
70475
71087
  getTaskLinks: () => getTaskLinks,
70476
71088
  hybridSearch: () => hybridSearch,
70477
71089
  learningStats: () => learningStats,
@@ -70513,6 +71125,7 @@ __export(research_exports, {
70513
71125
  storePattern: () => storePattern,
70514
71126
  storeVerifiedCandidate: () => storeVerifiedCandidate,
70515
71127
  timelineBrain: () => timelineBrain,
71128
+ trackMemoryUsage: () => trackMemoryUsage,
70516
71129
  unlinkMemoryFromTask: () => unlinkMemoryFromTask,
70517
71130
  updateDecisionOutcome: () => updateDecisionOutcome,
70518
71131
  updateResearch: () => updateResearch,
@@ -90882,6 +91495,22 @@ async function memoryGraphRemove(params, projectRoot) {
90882
91495
  };
90883
91496
  }
90884
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
+ }
90885
91514
  var init_engine_compat = __esm({
90886
91515
  "packages/core/src/memory/engine-compat.ts"() {
90887
91516
  "use strict";
@@ -109520,12 +110149,12 @@ import { join as join119 } from "node:path";
109520
110149
  function typedAll4(db, sql14, ...params) {
109521
110150
  return db.prepare(sql14).all(...params);
109522
110151
  }
109523
- function typedGet(db, sql14, ...params) {
110152
+ function typedGet2(db, sql14, ...params) {
109524
110153
  return db.prepare(sql14).get(...params);
109525
110154
  }
109526
110155
  function queryIndexMeta(db, projectId) {
109527
110156
  try {
109528
- const nodeMeta = typedGet(
110157
+ const nodeMeta = typedGet2(
109529
110158
  db,
109530
110159
  `SELECT COUNT(*) as total_nodes,
109531
110160
  COUNT(CASE WHEN kind = 'file' THEN 1 END) as file_count,
@@ -109534,7 +110163,7 @@ function queryIndexMeta(db, projectId) {
109534
110163
  WHERE project_id = ?`,
109535
110164
  projectId
109536
110165
  );
109537
- const relMeta = typedGet(
110166
+ const relMeta = typedGet2(
109538
110167
  db,
109539
110168
  `SELECT COUNT(*) as total_relations
109540
110169
  FROM nexus_relations
@@ -109629,7 +110258,7 @@ function queryCommunities(db, projectId, limit = 6) {
109629
110258
  }
109630
110259
  function queryProcessCount(db, projectId) {
109631
110260
  try {
109632
- const row = typedGet(
110261
+ const row = typedGet2(
109633
110262
  db,
109634
110263
  `SELECT COUNT(*) as count
109635
110264
  FROM nexus_nodes
@@ -111230,6 +111859,7 @@ __export(internal_exports, {
111230
111859
  coreValidateProtocol: () => coreValidateProtocol,
111231
111860
  coreValidateSchema: () => coreValidateSchema,
111232
111861
  coreValidateTask: () => coreValidateTask,
111862
+ correlateOutcomes: () => correlateOutcomes,
111233
111863
  createBackup: () => createBackup,
111234
111864
  createConduit: () => createConduit,
111235
111865
  createDataAccessor: () => createDataAccessor,
@@ -111382,6 +112012,7 @@ __export(internal_exports, {
111382
112012
  getLinksByTaskId: () => getLinksByTaskId,
111383
112013
  getLogDir: () => getLogDir,
111384
112014
  getLogger: () => getLogger,
112015
+ getMemoryQualityReport: () => getMemoryQualityReport,
111385
112016
  getMigrationStatus: () => getMigrationStatus2,
111386
112017
  getNativeDb: () => getNativeDb,
111387
112018
  getNativeOperations: () => getNativeOperations,
@@ -111552,6 +112183,7 @@ __export(internal_exports, {
111552
112183
  memoryPatternFind: () => memoryPatternFind,
111553
112184
  memoryPatternStats: () => memoryPatternStats,
111554
112185
  memoryPatternStore: () => memoryPatternStore,
112186
+ memoryQualityReport: () => memoryQualityReport,
111555
112187
  memoryReasonSimilar: () => memoryReasonSimilar,
111556
112188
  memoryReasonWhy: () => memoryReasonWhy,
111557
112189
  memorySearchHybrid: () => memorySearchHybrid,
@@ -111764,6 +112396,7 @@ __export(internal_exports, {
111764
112396
  tokenUsageMethodSchema: () => tokenUsageMethodSchema,
111765
112397
  tokenUsageTransportSchema: () => tokenUsageTransportSchema,
111766
112398
  touchLink: () => touchLink,
112399
+ trackMemoryUsage: () => trackMemoryUsage,
111767
112400
  ui: () => ui_exports,
111768
112401
  uncancelTask: () => uncancelTask,
111769
112402
  unpackBundle: () => unpackBundle,
@@ -111851,6 +112484,7 @@ var init_internal = __esm({
111851
112484
  init_claude_mem_migration();
111852
112485
  init_engine_compat();
111853
112486
  init_pipeline_manifest_sqlite();
112487
+ init_quality_feedback();
111854
112488
  init_token_service();
111855
112489
  init_deps();
111856
112490
  init_discover();
@@ -115016,6 +115650,66 @@ var init_registry5 = __esm({
115016
115650
  sessionRequired: false,
115017
115651
  requiredParams: []
115018
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
+ },
115019
115713
  {
115020
115714
  gateway: "mutate",
115021
115715
  domain: "pipeline",
@@ -123519,6 +124213,33 @@ var init_memory2 = __esm({
123519
124213
  );
123520
124214
  return wrapResult(result, "query", "memory", operation, startTime);
123521
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
+ }
123522
124243
  default:
123523
124244
  return unsupportedOp("query", "memory", operation, startTime);
123524
124245
  }
@@ -123689,6 +124410,21 @@ var init_memory2 = __esm({
123689
124410
  );
123690
124411
  return wrapResult(result, "mutate", "memory", operation, startTime);
123691
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
+ }
123692
124428
  default:
123693
124429
  return unsupportedOp("mutate", "memory", operation, startTime);
123694
124430
  }
@@ -123721,7 +124457,11 @@ var init_memory2 = __esm({
123721
124457
  "graph.stats",
123722
124458
  "reason.why",
123723
124459
  "reason.similar",
123724
- "search.hybrid"
124460
+ "search.hybrid",
124461
+ "quality",
124462
+ "code.links",
124463
+ "code.memories-for-code",
124464
+ "code.for-memory"
123725
124465
  ],
123726
124466
  mutate: [
123727
124467
  "observe",
@@ -123730,7 +124470,9 @@ var init_memory2 = __esm({
123730
124470
  "learning.store",
123731
124471
  "link",
123732
124472
  "graph.add",
123733
- "graph.remove"
124473
+ "graph.remove",
124474
+ "code.link",
124475
+ "code.auto-link"
123734
124476
  ]
123735
124477
  };
123736
124478
  }
@@ -133448,6 +134190,66 @@ function registerBrainCommand(program) {
133448
134190
  process.exit(1);
133449
134191
  }
133450
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
+ });
133451
134253
  }
133452
134254
 
133453
134255
  // packages/cleo/src/cli/commands/briefing.ts
@@ -136517,6 +137319,47 @@ function registerMemoryBrainCommand(program) {
136517
137319
  { command: "memory", operation: "memory.search.hybrid" }
136518
137320
  );
136519
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
+ });
136520
137363
  }
136521
137364
 
136522
137365
  // packages/cleo/src/cli/commands/migrate-claude-mem.ts