@cleocode/core 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 (62) hide show
  1. package/dist/hooks/handlers/task-hooks.d.ts.map +1 -1
  2. package/dist/hooks/handlers/task-hooks.js +11 -0
  3. package/dist/hooks/handlers/task-hooks.js.map +1 -1
  4. package/dist/index.js +647 -34
  5. package/dist/index.js.map +4 -4
  6. package/dist/internal.d.ts +3 -1
  7. package/dist/internal.d.ts.map +1 -1
  8. package/dist/internal.js +3 -1
  9. package/dist/internal.js.map +1 -1
  10. package/dist/memory/decisions.d.ts.map +1 -1
  11. package/dist/memory/decisions.js +18 -0
  12. package/dist/memory/decisions.js.map +1 -1
  13. package/dist/memory/engine-compat.d.ts +17 -0
  14. package/dist/memory/engine-compat.d.ts.map +1 -1
  15. package/dist/memory/engine-compat.js +36 -0
  16. package/dist/memory/engine-compat.js.map +1 -1
  17. package/dist/memory/graph-memory-bridge.d.ts +158 -0
  18. package/dist/memory/graph-memory-bridge.d.ts.map +1 -0
  19. package/dist/memory/graph-memory-bridge.js +519 -0
  20. package/dist/memory/graph-memory-bridge.js.map +1 -0
  21. package/dist/memory/index.d.ts +1 -0
  22. package/dist/memory/index.d.ts.map +1 -1
  23. package/dist/memory/index.js +2 -0
  24. package/dist/memory/index.js.map +1 -1
  25. package/dist/memory/learnings.d.ts.map +1 -1
  26. package/dist/memory/learnings.js +18 -0
  27. package/dist/memory/learnings.js.map +1 -1
  28. package/dist/memory/llm-extraction.d.ts.map +1 -1
  29. package/dist/memory/llm-extraction.js.map +1 -1
  30. package/dist/memory/patterns.d.ts.map +1 -1
  31. package/dist/memory/patterns.js +18 -0
  32. package/dist/memory/patterns.js.map +1 -1
  33. package/dist/memory/quality-feedback.d.ts +129 -0
  34. package/dist/memory/quality-feedback.d.ts.map +1 -0
  35. package/dist/memory/quality-feedback.js +449 -0
  36. package/dist/memory/quality-feedback.js.map +1 -0
  37. package/dist/memory/sleep-consolidation.d.ts +98 -0
  38. package/dist/memory/sleep-consolidation.d.ts.map +1 -0
  39. package/dist/memory/sleep-consolidation.js +706 -0
  40. package/dist/memory/sleep-consolidation.js.map +1 -0
  41. package/dist/memory/temporal-supersession.d.ts +155 -0
  42. package/dist/memory/temporal-supersession.d.ts.map +1 -0
  43. package/dist/memory/temporal-supersession.js +406 -0
  44. package/dist/memory/temporal-supersession.js.map +1 -0
  45. package/package.json +6 -6
  46. package/src/hooks/handlers/task-hooks.ts +11 -0
  47. package/src/internal.ts +12 -0
  48. package/src/memory/__tests__/graph-memory-bridge.test.ts +357 -0
  49. package/src/memory/__tests__/llm-extraction.test.ts +17 -0
  50. package/src/memory/__tests__/quality-feedback.test.ts +418 -0
  51. package/src/memory/__tests__/sleep-consolidation.test.ts +790 -0
  52. package/src/memory/__tests__/temporal-supersession.test.ts +534 -0
  53. package/src/memory/decisions.ts +24 -0
  54. package/src/memory/engine-compat.ts +37 -0
  55. package/src/memory/graph-memory-bridge.ts +751 -0
  56. package/src/memory/index.ts +2 -0
  57. package/src/memory/learnings.ts +24 -0
  58. package/src/memory/patterns.ts +24 -0
  59. package/src/memory/quality-feedback.ts +640 -0
  60. package/src/memory/sleep-consolidation.ts +932 -0
  61. package/src/memory/temporal-supersession.ts +568 -0
  62. package/src/store/__tests__/performance-safety.test.ts +4 -4
package/dist/index.js CHANGED
@@ -18648,6 +18648,210 @@ var init_quality_scoring = __esm({
18648
18648
  }
18649
18649
  });
18650
18650
 
18651
+ // packages/core/src/store/typed-query.ts
18652
+ function typedAll(stmt, ...params) {
18653
+ return stmt.all(...params);
18654
+ }
18655
+ function typedGet(stmt, ...params) {
18656
+ return stmt.get(...params);
18657
+ }
18658
+ var init_typed_query = __esm({
18659
+ "packages/core/src/store/typed-query.ts"() {
18660
+ "use strict";
18661
+ }
18662
+ });
18663
+
18664
+ // packages/core/src/memory/temporal-supersession.ts
18665
+ function extractKeywords(text3) {
18666
+ const words = text3.toLowerCase().replace(/[^a-z0-9\s\-_]/g, " ").split(/\s+/);
18667
+ const keywords = /* @__PURE__ */ new Set();
18668
+ for (const w of words) {
18669
+ if (w.length >= 4 && !STOP_WORDS.has(w)) {
18670
+ keywords.add(w);
18671
+ }
18672
+ }
18673
+ return keywords;
18674
+ }
18675
+ function keywordSimilarity(textA, textB) {
18676
+ const kwA = extractKeywords(textA);
18677
+ const kwB = extractKeywords(textB);
18678
+ if (kwA.size === 0 || kwB.size === 0) return { similarity: 0, shared: [] };
18679
+ const shared = [];
18680
+ for (const w of kwA) {
18681
+ if (kwB.has(w)) shared.push(w);
18682
+ }
18683
+ if (shared.length < MIN_SHARED_KEYWORDS) return { similarity: 0, shared: [] };
18684
+ const union3 = kwA.size + kwB.size - shared.length;
18685
+ const similarity = union3 > 0 ? shared.length / union3 : 0;
18686
+ return { similarity, shared };
18687
+ }
18688
+ function buildNodeId(type, entryId) {
18689
+ return `${type}:${entryId}`;
18690
+ }
18691
+ async function locateEntry(projectRoot, entryId) {
18692
+ await getBrainDb(projectRoot);
18693
+ const nativeDb = getBrainNativeDb();
18694
+ if (!nativeDb) return null;
18695
+ for (const tc of SUPERSEDABLE_TABLES) {
18696
+ const row = typedGet(
18697
+ nativeDb.prepare(`SELECT id FROM ${tc.table} WHERE id = ? LIMIT 1`),
18698
+ entryId
18699
+ );
18700
+ if (row) {
18701
+ return { tableConfig: tc, nodeId: buildNodeId(tc.type, entryId) };
18702
+ }
18703
+ }
18704
+ return null;
18705
+ }
18706
+ async function supersedeMemory(projectRoot, oldId, newId, reason) {
18707
+ if (!oldId?.trim()) throw new Error("oldId is required");
18708
+ if (!newId?.trim()) throw new Error("newId is required");
18709
+ if (!reason?.trim()) throw new Error("reason is required");
18710
+ if (oldId === newId) throw new Error("oldId and newId must be different entries");
18711
+ await getBrainDb(projectRoot);
18712
+ const nativeDb = getBrainNativeDb();
18713
+ if (!nativeDb) throw new Error("brain.db is unavailable");
18714
+ const now = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
18715
+ const oldLocation = await locateEntry(projectRoot, oldId);
18716
+ if (!oldLocation) throw new Error(`Entry not found: ${oldId}`);
18717
+ const newLocation = await locateEntry(projectRoot, newId);
18718
+ if (!newLocation) throw new Error(`Entry not found: ${newId}`);
18719
+ const { tableConfig: oldTc, nodeId: oldNodeId } = oldLocation;
18720
+ const { nodeId: newNodeId } = newLocation;
18721
+ try {
18722
+ nativeDb.prepare(
18723
+ `UPDATE ${oldTc.table} SET invalid_at = ?, updated_at = ? WHERE id = ? AND invalid_at IS NULL`
18724
+ ).run(now, now, oldId);
18725
+ } catch {
18726
+ }
18727
+ const provenanceText = reason.substring(0, 500);
18728
+ try {
18729
+ nativeDb.prepare(
18730
+ `INSERT OR IGNORE INTO brain_page_edges
18731
+ (from_id, to_id, edge_type, weight, provenance, created_at)
18732
+ VALUES (?, ?, 'supersedes', 1.0, ?, ?)`
18733
+ ).run(newNodeId, oldNodeId, provenanceText, now);
18734
+ } catch (err) {
18735
+ const message = err instanceof Error ? err.message : String(err);
18736
+ throw new Error(`Failed to create supersedes edge: ${message}`);
18737
+ }
18738
+ return {
18739
+ success: true,
18740
+ oldId,
18741
+ newId,
18742
+ edgeType: "supersedes"
18743
+ };
18744
+ }
18745
+ async function detectSupersession(projectRoot, newEntry) {
18746
+ try {
18747
+ await getBrainDb(projectRoot);
18748
+ const nativeDb = getBrainNativeDb();
18749
+ if (!nativeDb) return [];
18750
+ const newLocation = await locateEntry(projectRoot, newEntry.id);
18751
+ if (!newLocation) return [];
18752
+ const { tableConfig } = newLocation;
18753
+ const existing = typedAll(
18754
+ nativeDb.prepare(`
18755
+ SELECT id, COALESCE(${tableConfig.textCol}, '') AS text,
18756
+ created_at, quality_score
18757
+ FROM ${tableConfig.table}
18758
+ WHERE invalid_at IS NULL
18759
+ AND id != ?
18760
+ ORDER BY created_at DESC
18761
+ LIMIT 200
18762
+ `),
18763
+ newEntry.id
18764
+ );
18765
+ if (existing.length === 0) return [];
18766
+ const candidates = [];
18767
+ for (const row of existing) {
18768
+ if (row.created_at >= newEntry.createdAt) continue;
18769
+ const { similarity, shared } = keywordSimilarity(newEntry.text, row.text);
18770
+ if (similarity >= KEYWORD_OVERLAP_THRESHOLD) {
18771
+ candidates.push({
18772
+ existingId: row.id,
18773
+ similarity,
18774
+ table: tableConfig.table,
18775
+ sharedKeywords: shared.slice(0, 10)
18776
+ });
18777
+ }
18778
+ }
18779
+ candidates.sort((a, b) => b.similarity - a.similarity);
18780
+ return candidates;
18781
+ } catch (err) {
18782
+ console.warn("[temporal-supersession] detectSupersession failed:", err);
18783
+ return [];
18784
+ }
18785
+ }
18786
+ var KEYWORD_OVERLAP_THRESHOLD, MIN_SHARED_KEYWORDS, STOP_WORDS, SUPERSEDABLE_TABLES;
18787
+ var init_temporal_supersession = __esm({
18788
+ "packages/core/src/memory/temporal-supersession.ts"() {
18789
+ "use strict";
18790
+ init_brain_sqlite();
18791
+ init_typed_query();
18792
+ KEYWORD_OVERLAP_THRESHOLD = 0.8;
18793
+ MIN_SHARED_KEYWORDS = 3;
18794
+ STOP_WORDS = /* @__PURE__ */ new Set([
18795
+ "the",
18796
+ "a",
18797
+ "an",
18798
+ "is",
18799
+ "are",
18800
+ "was",
18801
+ "were",
18802
+ "be",
18803
+ "been",
18804
+ "being",
18805
+ "have",
18806
+ "has",
18807
+ "had",
18808
+ "do",
18809
+ "does",
18810
+ "did",
18811
+ "will",
18812
+ "would",
18813
+ "could",
18814
+ "should",
18815
+ "may",
18816
+ "might",
18817
+ "shall",
18818
+ "can",
18819
+ "to",
18820
+ "of",
18821
+ "in",
18822
+ "for",
18823
+ "on",
18824
+ "with",
18825
+ "at",
18826
+ "by",
18827
+ "from",
18828
+ "as",
18829
+ "into",
18830
+ "through",
18831
+ "and",
18832
+ "but",
18833
+ "or",
18834
+ "nor",
18835
+ "so",
18836
+ "yet",
18837
+ "this",
18838
+ "that",
18839
+ "these",
18840
+ "those",
18841
+ "it",
18842
+ "its",
18843
+ "not",
18844
+ "no"
18845
+ ]);
18846
+ SUPERSEDABLE_TABLES = [
18847
+ { table: "brain_decisions", textCol: "decision", type: "decision" },
18848
+ { table: "brain_learnings", textCol: "insight", type: "learning" },
18849
+ { table: "brain_patterns", textCol: "pattern", type: "pattern" },
18850
+ { table: "brain_observations", textCol: "narrative", type: "observation" }
18851
+ ];
18852
+ }
18853
+ });
18854
+
18651
18855
  // packages/core/src/memory/patterns.ts
18652
18856
  var patterns_exports = {};
18653
18857
  __export(patterns_exports, {
@@ -18745,6 +18949,22 @@ async function storePattern(projectRoot, params) {
18745
18949
  { type: saved.type, impact: saved.impact ?? void 0 }
18746
18950
  ).catch(() => {
18747
18951
  });
18952
+ detectSupersession(projectRoot, {
18953
+ id: saved.id,
18954
+ text: saved.pattern + " " + saved.context,
18955
+ createdAt: saved.extractedAt ?? (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
18956
+ }).then((candidates) => {
18957
+ for (const candidate of candidates) {
18958
+ supersedeMemory(
18959
+ projectRoot,
18960
+ candidate.existingId,
18961
+ saved.id,
18962
+ "auto:pattern-supersedes \u2014 high overlap detected at store time"
18963
+ ).catch(() => {
18964
+ });
18965
+ }
18966
+ }).catch(() => {
18967
+ });
18748
18968
  return {
18749
18969
  ...saved,
18750
18970
  examples: JSON.parse(saved.examplesJson || "[]")
@@ -18801,6 +19021,7 @@ var init_patterns = __esm({
18801
19021
  init_brain_accessor();
18802
19022
  init_graph_auto_populate();
18803
19023
  init_quality_scoring();
19024
+ init_temporal_supersession();
18804
19025
  }
18805
19026
  });
18806
19027
 
@@ -18892,6 +19113,22 @@ async function storeLearning(projectRoot, params) {
18892
19113
  { source: saved.source, confidence: saved.confidence, actionable: saved.actionable }
18893
19114
  ).catch(() => {
18894
19115
  });
19116
+ detectSupersession(projectRoot, {
19117
+ id: saved.id,
19118
+ text: saved.insight,
19119
+ createdAt: saved.createdAt ?? (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
19120
+ }).then((candidates) => {
19121
+ for (const candidate of candidates) {
19122
+ supersedeMemory(
19123
+ projectRoot,
19124
+ candidate.existingId,
19125
+ saved.id,
19126
+ "auto:learning-supersedes \u2014 high overlap detected at store time"
19127
+ ).catch(() => {
19128
+ });
19129
+ }
19130
+ }).catch(() => {
19131
+ });
18895
19132
  return {
18896
19133
  ...saved,
18897
19134
  applicableTypes: JSON.parse(saved.applicableTypesJson || "[]")
@@ -18952,6 +19189,7 @@ var init_learnings = __esm({
18952
19189
  init_brain_accessor();
18953
19190
  init_graph_auto_populate();
18954
19191
  init_quality_scoring();
19192
+ init_temporal_supersession();
18955
19193
  }
18956
19194
  });
18957
19195
 
@@ -18990,16 +19228,6 @@ var init_mvi_helpers = __esm({
18990
19228
  }
18991
19229
  });
18992
19230
 
18993
- // packages/core/src/store/typed-query.ts
18994
- function typedAll(stmt, ...params) {
18995
- return stmt.all(...params);
18996
- }
18997
- var init_typed_query = __esm({
18998
- "packages/core/src/store/typed-query.ts"() {
18999
- "use strict";
19000
- }
19001
- });
19002
-
19003
19231
  // packages/core/src/memory/brain-similarity.ts
19004
19232
  function parseIdPrefix(id) {
19005
19233
  if (id.startsWith("D-") || /^D\d/.test(id)) return "decision";
@@ -20784,6 +21012,22 @@ async function storeDecision(projectRoot, params) {
20784
21012
  }
20785
21013
  } catch {
20786
21014
  }
21015
+ detectSupersession(projectRoot, {
21016
+ id: saved.id,
21017
+ text: saved.decision + " " + saved.rationale,
21018
+ createdAt: saved.createdAt ?? (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19)
21019
+ }).then((candidates) => {
21020
+ for (const candidate of candidates) {
21021
+ supersedeMemory(
21022
+ projectRoot,
21023
+ candidate.existingId,
21024
+ saved.id,
21025
+ "auto:decision-supersedes \u2014 high overlap detected at store time"
21026
+ ).catch(() => {
21027
+ });
21028
+ }
21029
+ }).catch(() => {
21030
+ });
20787
21031
  return saved;
20788
21032
  }
20789
21033
  async function recallDecision(projectRoot, id) {
@@ -20836,6 +21080,7 @@ var init_decisions2 = __esm({
20836
21080
  init_sqlite2();
20837
21081
  init_graph_auto_populate();
20838
21082
  init_quality_scoring();
21083
+ init_temporal_supersession();
20839
21084
  }
20840
21085
  });
20841
21086
 
@@ -41744,7 +41989,9 @@ async function extractFromTranscript(options) {
41744
41989
  const maxTranscriptChars = llmCfg?.maxTranscriptChars ?? 6e4;
41745
41990
  const client = options.client ?? await buildAnthropicClient();
41746
41991
  if (!client) {
41747
- report.warnings.push("No Anthropic API key found (checked ANTHROPIC_API_KEY env and ~/.claude/.credentials.json) \u2014 extraction skipped");
41992
+ report.warnings.push(
41993
+ "No Anthropic API key found (checked ANTHROPIC_API_KEY env and ~/.claude/.credentials.json) \u2014 extraction skipped"
41994
+ );
41748
41995
  return report;
41749
41996
  }
41750
41997
  const clipped = clipTranscript(transcript, maxTranscriptChars);
@@ -41906,11 +42153,11 @@ var brain_consolidator_exports = {};
41906
42153
  __export(brain_consolidator_exports, {
41907
42154
  detectContradictions: () => detectContradictions
41908
42155
  });
41909
- function extractKeywords(text3) {
42156
+ function extractKeywords2(text3) {
41910
42157
  const words = text3.toLowerCase().replace(/[^a-z0-9\s\-_]/g, " ").split(/\s+/);
41911
42158
  const keywords = /* @__PURE__ */ new Set();
41912
42159
  for (const w of words) {
41913
- if (w.length >= 4 && !STOP_WORDS.has(w)) {
42160
+ if (w.length >= 4 && !STOP_WORDS2.has(w)) {
41914
42161
  keywords.add(w);
41915
42162
  }
41916
42163
  }
@@ -41959,7 +42206,7 @@ async function detectContradictions(projectRoot) {
41959
42206
  const keywordMap = /* @__PURE__ */ new Map();
41960
42207
  const negationMap = /* @__PURE__ */ new Map();
41961
42208
  for (const entry of entries) {
41962
- keywordMap.set(entry.id, extractKeywords(entry.text));
42209
+ keywordMap.set(entry.id, extractKeywords2(entry.text));
41963
42210
  negationMap.set(entry.id, findNegationMarkers(entry.text));
41964
42211
  }
41965
42212
  for (let i = 0; i < entries.length; i++) {
@@ -41973,7 +42220,7 @@ async function detectContradictions(projectRoot) {
41973
42220
  const keywordsB = keywordMap.get(entryB.id);
41974
42221
  const negationsB = negationMap.get(entryB.id);
41975
42222
  const shared = keywordIntersection(keywordsA, keywordsB);
41976
- if (shared.length < MIN_SHARED_KEYWORDS) continue;
42223
+ if (shared.length < MIN_SHARED_KEYWORDS2) continue;
41977
42224
  const negationsOnlyInA = negationsA.filter((m) => !negationsB.includes(m));
41978
42225
  const negationsOnlyInB = negationsB.filter((m) => !negationsA.includes(m));
41979
42226
  const negationFlip = negationsOnlyInA.length > 0 || negationsOnlyInB.length > 0;
@@ -41991,8 +42238,8 @@ async function detectContradictions(projectRoot) {
41991
42238
  sharedKeywords: shared.slice(0, 10),
41992
42239
  negationMarkers: negMarkers.slice(0, 5)
41993
42240
  });
41994
- const nodeA = buildNodeId(table, entryA.id);
41995
- const nodeB = buildNodeId(table, entryB.id);
42241
+ const nodeA = buildNodeId2(table, entryA.id);
42242
+ const nodeB = buildNodeId2(table, entryB.id);
41996
42243
  try {
41997
42244
  nativeDb.prepare(`
41998
42245
  INSERT OR IGNORE INTO brain_page_edges
@@ -42021,7 +42268,7 @@ async function detectContradictions(projectRoot) {
42021
42268
  }
42022
42269
  return results;
42023
42270
  }
42024
- function buildNodeId(table, entryId) {
42271
+ function buildNodeId2(table, entryId) {
42025
42272
  const typeMap = {
42026
42273
  brain_observations: "observation",
42027
42274
  brain_learnings: "learning",
@@ -42031,13 +42278,13 @@ function buildNodeId(table, entryId) {
42031
42278
  const type = typeMap[table] ?? "entry";
42032
42279
  return `${type}:${entryId}`;
42033
42280
  }
42034
- var MIN_SHARED_KEYWORDS, NEGATION_MARKERS, STOP_WORDS;
42281
+ var MIN_SHARED_KEYWORDS2, NEGATION_MARKERS, STOP_WORDS2;
42035
42282
  var init_brain_consolidator = __esm({
42036
42283
  "packages/core/src/memory/brain-consolidator.ts"() {
42037
42284
  "use strict";
42038
42285
  init_brain_sqlite();
42039
42286
  init_typed_query();
42040
- MIN_SHARED_KEYWORDS = 3;
42287
+ MIN_SHARED_KEYWORDS2 = 3;
42041
42288
  NEGATION_MARKERS = [
42042
42289
  "not",
42043
42290
  "never",
@@ -42058,7 +42305,7 @@ var init_brain_consolidator = __esm({
42058
42305
  "undone",
42059
42306
  "superseded"
42060
42307
  ];
42061
- STOP_WORDS = /* @__PURE__ */ new Set([
42308
+ STOP_WORDS2 = /* @__PURE__ */ new Set([
42062
42309
  "the",
42063
42310
  "a",
42064
42311
  "an",
@@ -42146,11 +42393,11 @@ async function applyTemporalDecay(projectRoot, options) {
42146
42393
  tablesProcessed: ["brain_learnings"]
42147
42394
  };
42148
42395
  }
42149
- function extractKeywords2(text3) {
42396
+ function extractKeywords3(text3) {
42150
42397
  const words = text3.toLowerCase().replace(/[^a-z0-9\s-]/g, "").split(/\s+/);
42151
42398
  const keywords = /* @__PURE__ */ new Set();
42152
42399
  for (const w of words) {
42153
- if (w.length >= 4 && !STOP_WORDS2.has(w)) {
42400
+ if (w.length >= 4 && !STOP_WORDS3.has(w)) {
42154
42401
  keywords.add(w);
42155
42402
  }
42156
42403
  }
@@ -42188,7 +42435,7 @@ async function consolidateMemories(projectRoot, options) {
42188
42435
  }
42189
42436
  const entries = oldObservations.map((obs) => ({
42190
42437
  ...obs,
42191
- keywords: extractKeywords2(`${obs.title} ${obs.narrative ?? ""}`),
42438
+ keywords: extractKeywords3(`${obs.title} ${obs.narrative ?? ""}`),
42192
42439
  clustered: false
42193
42440
  }));
42194
42441
  const clusters = [];
@@ -42590,13 +42837,13 @@ async function strengthenCoRetrievedEdges(projectRoot) {
42590
42837
  }
42591
42838
  return strengthened;
42592
42839
  }
42593
- var STOP_WORDS2;
42840
+ var STOP_WORDS3;
42594
42841
  var init_brain_lifecycle = __esm({
42595
42842
  "packages/core/src/memory/brain-lifecycle.ts"() {
42596
42843
  "use strict";
42597
42844
  init_brain_accessor();
42598
42845
  init_typed_query();
42599
- STOP_WORDS2 = /* @__PURE__ */ new Set([
42846
+ STOP_WORDS3 = /* @__PURE__ */ new Set([
42600
42847
  "the",
42601
42848
  "a",
42602
42849
  "an",
@@ -43201,6 +43448,358 @@ var init_session_hooks = __esm({
43201
43448
  }
43202
43449
  });
43203
43450
 
43451
+ // packages/core/src/memory/quality-feedback.ts
43452
+ var quality_feedback_exports = {};
43453
+ __export(quality_feedback_exports, {
43454
+ correlateOutcomes: () => correlateOutcomes,
43455
+ getMemoryQualityReport: () => getMemoryQualityReport,
43456
+ trackMemoryUsage: () => trackMemoryUsage
43457
+ });
43458
+ async function ensureUsageLogTable(projectRoot) {
43459
+ const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
43460
+ await getBrainDb2(projectRoot);
43461
+ const nativeDb = getBrainNativeDb2();
43462
+ if (!nativeDb) return;
43463
+ try {
43464
+ nativeDb.prepare(
43465
+ `CREATE TABLE IF NOT EXISTS brain_usage_log (
43466
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
43467
+ entry_id TEXT NOT NULL,
43468
+ task_id TEXT,
43469
+ used INTEGER NOT NULL DEFAULT 0,
43470
+ outcome TEXT NOT NULL DEFAULT 'unknown',
43471
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
43472
+ )`
43473
+ ).run();
43474
+ nativeDb.prepare(
43475
+ `CREATE INDEX IF NOT EXISTS idx_brain_usage_log_entry_id
43476
+ ON brain_usage_log(entry_id)`
43477
+ ).run();
43478
+ nativeDb.prepare(
43479
+ `CREATE INDEX IF NOT EXISTS idx_brain_usage_log_task_id
43480
+ ON brain_usage_log(task_id)`
43481
+ ).run();
43482
+ } catch {
43483
+ }
43484
+ }
43485
+ async function ensurePruneCandidateColumn(projectRoot) {
43486
+ const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
43487
+ await getBrainDb2(projectRoot);
43488
+ const nativeDb = getBrainNativeDb2();
43489
+ if (!nativeDb) return;
43490
+ const tables = [
43491
+ "brain_decisions",
43492
+ "brain_patterns",
43493
+ "brain_learnings",
43494
+ "brain_observations"
43495
+ ];
43496
+ for (const tbl of tables) {
43497
+ try {
43498
+ nativeDb.prepare(`ALTER TABLE ${tbl} ADD COLUMN prune_candidate INTEGER DEFAULT 0`).run();
43499
+ } catch {
43500
+ }
43501
+ }
43502
+ }
43503
+ async function trackMemoryUsage(projectRoot, memoryId, used, taskId, outcome = "unknown") {
43504
+ if (!memoryId?.trim()) return;
43505
+ await ensureUsageLogTable(projectRoot);
43506
+ const { getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
43507
+ const nativeDb = getBrainNativeDb2();
43508
+ if (!nativeDb) return;
43509
+ const now = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").slice(0, 19);
43510
+ try {
43511
+ nativeDb.prepare(
43512
+ `INSERT INTO brain_usage_log (entry_id, task_id, used, outcome, created_at)
43513
+ VALUES (?, ?, ?, ?, ?)`
43514
+ ).run(memoryId, taskId ?? null, used ? 1 : 0, outcome, now);
43515
+ } catch {
43516
+ }
43517
+ }
43518
+ function tableForId(id) {
43519
+ if (id.startsWith("D-") || /^D\d/.test(id)) return "brain_decisions";
43520
+ if (id.startsWith("P-") || /^P\d/.test(id)) return "brain_patterns";
43521
+ if (id.startsWith("L-") || /^L\d/.test(id)) return "brain_learnings";
43522
+ if (id.startsWith("O-") || id.startsWith("CM-") || /^O/.test(id)) return "brain_observations";
43523
+ return null;
43524
+ }
43525
+ function applyQualityDelta(nativeDb, table, id, delta, now) {
43526
+ if (!nativeDb) return;
43527
+ try {
43528
+ nativeDb.prepare(
43529
+ `UPDATE ${table}
43530
+ SET quality_score = MAX(0.0, MIN(1.0, COALESCE(quality_score, 0.5) + ?)),
43531
+ updated_at = ?
43532
+ WHERE id = ?`
43533
+ ).run(delta, now, id);
43534
+ } catch {
43535
+ }
43536
+ }
43537
+ async function correlateOutcomes(projectRoot) {
43538
+ await ensureUsageLogTable(projectRoot);
43539
+ await ensurePruneCandidateColumn(projectRoot);
43540
+ const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
43541
+ await getBrainDb2(projectRoot);
43542
+ const nativeDb = getBrainNativeDb2();
43543
+ const ranAt = (/* @__PURE__ */ new Date()).toISOString();
43544
+ if (!nativeDb) {
43545
+ return { boosted: 0, penalized: 0, flaggedForPruning: 0, ranAt };
43546
+ }
43547
+ const now = ranAt.replace("T", " ").slice(0, 19);
43548
+ let boosted = 0;
43549
+ let penalized = 0;
43550
+ let usageRows = [];
43551
+ try {
43552
+ usageRows = typedAll(
43553
+ nativeDb.prepare(
43554
+ `SELECT entry_id, outcome, SUM(used) AS used_count
43555
+ FROM brain_usage_log
43556
+ WHERE outcome IN ('success', 'failure')
43557
+ GROUP BY entry_id, outcome`
43558
+ )
43559
+ );
43560
+ } catch {
43561
+ usageRows = [];
43562
+ }
43563
+ for (const row of usageRows) {
43564
+ const table = tableForId(row.entry_id);
43565
+ if (!table) continue;
43566
+ if (row.outcome === "success" && row.used_count > 0) {
43567
+ applyQualityDelta(nativeDb, table, row.entry_id, 0.05, now);
43568
+ boosted++;
43569
+ } else if (row.outcome === "failure" && row.used_count > 0) {
43570
+ applyQualityDelta(nativeDb, table, row.entry_id, -0.05, now);
43571
+ penalized++;
43572
+ }
43573
+ }
43574
+ const cutoffDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1e3).toISOString().replace("T", " ").slice(0, 19);
43575
+ let flaggedForPruning = 0;
43576
+ const pruneTargetTables = [
43577
+ { table: "brain_decisions", dateCol: "created_at" },
43578
+ { table: "brain_patterns", dateCol: "extracted_at" },
43579
+ { table: "brain_learnings", dateCol: "created_at" },
43580
+ { table: "brain_observations", dateCol: "created_at" }
43581
+ ];
43582
+ for (const { table, dateCol } of pruneTargetTables) {
43583
+ try {
43584
+ const result = nativeDb.prepare(
43585
+ `UPDATE ${table}
43586
+ SET prune_candidate = 1
43587
+ WHERE COALESCE(citation_count, 0) = 0
43588
+ AND ${dateCol} < ?`
43589
+ ).run(cutoffDate);
43590
+ flaggedForPruning += result.changes ?? 0;
43591
+ } catch {
43592
+ }
43593
+ }
43594
+ return { boosted, penalized, flaggedForPruning, ranAt };
43595
+ }
43596
+ async function getMemoryQualityReport(projectRoot) {
43597
+ await ensureUsageLogTable(projectRoot);
43598
+ const { getBrainDb: getBrainDb2, getBrainNativeDb: getBrainNativeDb2 } = await Promise.resolve().then(() => (init_brain_sqlite(), brain_sqlite_exports));
43599
+ await getBrainDb2(projectRoot);
43600
+ const nativeDb = getBrainNativeDb2();
43601
+ const emptyReport = {
43602
+ totalRetrievals: 0,
43603
+ uniqueEntriesRetrieved: 0,
43604
+ usageRate: 0,
43605
+ topRetrieved: [],
43606
+ neverRetrieved: [],
43607
+ qualityDistribution: { low: 0, medium: 0, high: 0 },
43608
+ tierDistribution: { short: 0, medium: 0, long: 0, unknown: 0 },
43609
+ noiseRatio: 0
43610
+ };
43611
+ if (!nativeDb) return emptyReport;
43612
+ let totalRetrievals = 0;
43613
+ let uniqueEntriesRetrieved = 0;
43614
+ try {
43615
+ const logCount = typedAll(
43616
+ nativeDb.prepare("SELECT COUNT(*) AS cnt FROM brain_retrieval_log")
43617
+ );
43618
+ totalRetrievals = logCount[0]?.cnt ?? 0;
43619
+ const uniqueCount = typedAll(
43620
+ nativeDb.prepare(
43621
+ `SELECT COUNT(DISTINCT value) AS cnt
43622
+ FROM brain_retrieval_log,
43623
+ json_each('["' || replace(entry_ids, ',', '","') || '"]')`
43624
+ )
43625
+ );
43626
+ uniqueEntriesRetrieved = uniqueCount[0]?.cnt ?? 0;
43627
+ } catch {
43628
+ }
43629
+ let usageRate = 0;
43630
+ try {
43631
+ const totalUsage = typedAll(
43632
+ nativeDb.prepare("SELECT COUNT(*) AS cnt FROM brain_usage_log")
43633
+ );
43634
+ const usedCount = typedAll(
43635
+ nativeDb.prepare("SELECT COUNT(*) AS cnt FROM brain_usage_log WHERE used = 1")
43636
+ );
43637
+ const total = totalUsage[0]?.cnt ?? 0;
43638
+ const used = usedCount[0]?.cnt ?? 0;
43639
+ usageRate = total > 0 ? used / total : 0;
43640
+ } catch {
43641
+ }
43642
+ const topRetrieved = [];
43643
+ try {
43644
+ const rows = typedAll(
43645
+ nativeDb.prepare(
43646
+ `SELECT id,
43647
+ 'decision' AS type,
43648
+ decision AS title,
43649
+ COALESCE(citation_count, 0) AS citation_count
43650
+ FROM brain_decisions
43651
+ UNION ALL
43652
+ SELECT id,
43653
+ 'pattern' AS type,
43654
+ pattern AS title,
43655
+ COALESCE(citation_count, 0) AS citation_count
43656
+ FROM brain_patterns
43657
+ UNION ALL
43658
+ SELECT id,
43659
+ 'learning' AS type,
43660
+ insight AS title,
43661
+ COALESCE(citation_count, 0) AS citation_count
43662
+ FROM brain_learnings
43663
+ UNION ALL
43664
+ SELECT id,
43665
+ 'observation' AS type,
43666
+ title AS title,
43667
+ COALESCE(citation_count, 0) AS citation_count
43668
+ FROM brain_observations
43669
+ ORDER BY citation_count DESC
43670
+ LIMIT 10`
43671
+ )
43672
+ );
43673
+ for (const r of rows) {
43674
+ topRetrieved.push({
43675
+ id: r.id,
43676
+ type: r.type,
43677
+ title: String(r.title ?? "").slice(0, 120),
43678
+ citationCount: r.citation_count
43679
+ });
43680
+ }
43681
+ } catch {
43682
+ }
43683
+ const neverRetrieved = [];
43684
+ try {
43685
+ const rows = typedAll(
43686
+ nativeDb.prepare(
43687
+ `SELECT id,
43688
+ 'decision' AS type,
43689
+ decision AS title,
43690
+ COALESCE(quality_score, 0.5) AS quality_score
43691
+ FROM brain_decisions
43692
+ WHERE COALESCE(citation_count, 0) = 0
43693
+ UNION ALL
43694
+ SELECT id,
43695
+ 'pattern' AS type,
43696
+ pattern AS title,
43697
+ COALESCE(quality_score, 0.5) AS quality_score
43698
+ FROM brain_patterns
43699
+ WHERE COALESCE(citation_count, 0) = 0
43700
+ UNION ALL
43701
+ SELECT id,
43702
+ 'learning' AS type,
43703
+ insight AS title,
43704
+ COALESCE(quality_score, 0.5) AS quality_score
43705
+ FROM brain_learnings
43706
+ WHERE COALESCE(citation_count, 0) = 0
43707
+ UNION ALL
43708
+ SELECT id,
43709
+ 'observation' AS type,
43710
+ title AS title,
43711
+ COALESCE(quality_score, 0.5) AS quality_score
43712
+ FROM brain_observations
43713
+ WHERE COALESCE(citation_count, 0) = 0
43714
+ ORDER BY quality_score ASC
43715
+ LIMIT 10`
43716
+ )
43717
+ );
43718
+ for (const r of rows) {
43719
+ neverRetrieved.push({
43720
+ id: r.id,
43721
+ type: r.type,
43722
+ title: String(r.title ?? "").slice(0, 120),
43723
+ qualityScore: r.quality_score
43724
+ });
43725
+ }
43726
+ } catch {
43727
+ }
43728
+ let qualityDistribution = { low: 0, medium: 0, high: 0 };
43729
+ try {
43730
+ const rows = typedAll(
43731
+ nativeDb.prepare(
43732
+ `SELECT
43733
+ SUM(CASE WHEN qs < 0.3 THEN 1 ELSE 0 END) AS low,
43734
+ SUM(CASE WHEN qs >= 0.3 AND qs <= 0.6 THEN 1 ELSE 0 END) AS medium,
43735
+ SUM(CASE WHEN qs > 0.6 THEN 1 ELSE 0 END) AS high
43736
+ FROM (
43737
+ SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_decisions
43738
+ UNION ALL
43739
+ SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_patterns
43740
+ UNION ALL
43741
+ SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_learnings
43742
+ UNION ALL
43743
+ SELECT COALESCE(quality_score, 0.5) AS qs FROM brain_observations
43744
+ )`
43745
+ )
43746
+ );
43747
+ if (rows[0]) {
43748
+ qualityDistribution = {
43749
+ low: rows[0].low ?? 0,
43750
+ medium: rows[0].medium ?? 0,
43751
+ high: rows[0].high ?? 0
43752
+ };
43753
+ }
43754
+ } catch {
43755
+ }
43756
+ const tierDistribution = { short: 0, medium: 0, long: 0, unknown: 0 };
43757
+ try {
43758
+ const rows = typedAll(
43759
+ nativeDb.prepare(
43760
+ `SELECT memory_tier AS tier, COUNT(*) AS cnt
43761
+ FROM (
43762
+ SELECT memory_tier FROM brain_decisions
43763
+ UNION ALL
43764
+ SELECT memory_tier FROM brain_patterns
43765
+ UNION ALL
43766
+ SELECT memory_tier FROM brain_learnings
43767
+ UNION ALL
43768
+ SELECT memory_tier FROM brain_observations
43769
+ )
43770
+ GROUP BY memory_tier`
43771
+ )
43772
+ );
43773
+ for (const r of rows) {
43774
+ const tier = r.tier?.toLowerCase() ?? "unknown";
43775
+ if (tier === "short" || tier === "medium" || tier === "long") {
43776
+ tierDistribution[tier] += r.cnt;
43777
+ } else {
43778
+ tierDistribution.unknown += r.cnt;
43779
+ }
43780
+ }
43781
+ } catch {
43782
+ }
43783
+ const totalEntries = qualityDistribution.low + qualityDistribution.medium + qualityDistribution.high;
43784
+ const noiseRatio = totalEntries > 0 ? qualityDistribution.low / totalEntries : 0;
43785
+ return {
43786
+ totalRetrievals,
43787
+ uniqueEntriesRetrieved,
43788
+ usageRate,
43789
+ topRetrieved,
43790
+ neverRetrieved,
43791
+ qualityDistribution,
43792
+ tierDistribution,
43793
+ noiseRatio
43794
+ };
43795
+ }
43796
+ var init_quality_feedback = __esm({
43797
+ "packages/core/src/memory/quality-feedback.ts"() {
43798
+ "use strict";
43799
+ init_typed_query();
43800
+ }
43801
+ });
43802
+
43204
43803
  // packages/core/src/hooks/handlers/task-hooks.ts
43205
43804
  async function handleToolStart(projectRoot, payload) {
43206
43805
  const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
@@ -43234,6 +43833,13 @@ async function handleToolComplete(projectRoot, payload) {
43234
43833
  } catch {
43235
43834
  }
43236
43835
  });
43836
+ setImmediate(async () => {
43837
+ try {
43838
+ const { correlateOutcomes: correlateOutcomes2 } = await Promise.resolve().then(() => (init_quality_feedback(), quality_feedback_exports));
43839
+ await correlateOutcomes2(projectRoot);
43840
+ } catch {
43841
+ }
43842
+ });
43237
43843
  await maybeRefreshMemoryBridge(projectRoot);
43238
43844
  }
43239
43845
  var init_task_hooks = __esm({
@@ -57500,7 +58106,7 @@ function generateRecommendation2(changeType, affectedCount, cascadeDepth, taskId
57500
58106
  }
57501
58107
  }
57502
58108
  function scoreTaskMatch(change, task) {
57503
- const STOP_WORDS4 = /* @__PURE__ */ new Set([
58109
+ const STOP_WORDS5 = /* @__PURE__ */ new Set([
57504
58110
  "a",
57505
58111
  "an",
57506
58112
  "the",
@@ -57522,7 +58128,7 @@ function scoreTaskMatch(change, task) {
57522
58128
  "do",
57523
58129
  "not"
57524
58130
  ]);
57525
- const tokenise = (text3) => text3.toLowerCase().split(/\W+/).filter((t) => t.length > 2 && !STOP_WORDS4.has(t));
58131
+ const tokenise = (text3) => text3.toLowerCase().split(/\W+/).filter((t) => t.length > 2 && !STOP_WORDS5.has(t));
57526
58132
  const changeTokens = new Set(tokenise(change));
57527
58133
  if (changeTokens.size === 0) return 0;
57528
58134
  const taskText = `${task.title ?? ""} ${task.description ?? ""}`;
@@ -60488,6 +61094,7 @@ __export(memory_exports, {
60488
61094
  bulkLink: () => bulkLink,
60489
61095
  compactManifest: () => compactManifest,
60490
61096
  consolidateMemories: () => consolidateMemories,
61097
+ correlateOutcomes: () => correlateOutcomes,
60491
61098
  detectContradictions: () => detectContradictions,
60492
61099
  ensureFts5Tables: () => ensureFts5Tables,
60493
61100
  fetchBrainEntries: () => fetchBrainEntries,
@@ -60498,6 +61105,7 @@ __export(memory_exports, {
60498
61105
  getLinkedLearnings: () => getLinkedLearnings,
60499
61106
  getLinkedPatterns: () => getLinkedPatterns,
60500
61107
  getMemoryLinks: () => getMemoryLinks,
61108
+ getMemoryQualityReport: () => getMemoryQualityReport,
60501
61109
  getTaskLinks: () => getTaskLinks,
60502
61110
  hybridSearch: () => hybridSearch,
60503
61111
  learningStats: () => learningStats,
@@ -60539,6 +61147,7 @@ __export(memory_exports, {
60539
61147
  storePattern: () => storePattern,
60540
61148
  storeVerifiedCandidate: () => storeVerifiedCandidate,
60541
61149
  timelineBrain: () => timelineBrain,
61150
+ trackMemoryUsage: () => trackMemoryUsage,
60542
61151
  unlinkMemoryFromTask: () => unlinkMemoryFromTask,
60543
61152
  updateDecisionOutcome: () => updateDecisionOutcome,
60544
61153
  updateResearch: () => updateResearch,
@@ -60930,6 +61539,7 @@ async function verifyAndStoreBatch(projectRoot, candidates) {
60930
61539
  // packages/core/src/memory/index.ts
60931
61540
  init_learnings();
60932
61541
  init_patterns();
61542
+ init_quality_feedback();
60933
61543
  function getResearchPath(cwd) {
60934
61544
  return join49(getCleoDirAbsolute(cwd), "research.json");
60935
61545
  }
@@ -63846,7 +64456,7 @@ __export(nexus_exports, {
63846
64456
  criticalPath: () => criticalPath,
63847
64457
  discoverRelated: () => discoverRelated,
63848
64458
  executeTransfer: () => executeTransfer,
63849
- extractKeywords: () => extractKeywords3,
64459
+ extractKeywords: () => extractKeywords4,
63850
64460
  generateProjectHash: () => generateProjectHash,
63851
64461
  getCurrentProject: () => getCurrentProject,
63852
64462
  getNexusCacheDir: () => getNexusCacheDir,
@@ -64389,7 +64999,7 @@ async function orphanDetection() {
64389
64999
  // packages/core/src/nexus/discover.ts
64390
65000
  init_data_accessor();
64391
65001
  init_registry3();
64392
- var STOP_WORDS3 = /* @__PURE__ */ new Set([
65002
+ var STOP_WORDS4 = /* @__PURE__ */ new Set([
64393
65003
  "the",
64394
65004
  "a",
64395
65005
  "an",
@@ -64471,8 +65081,8 @@ var STOP_WORDS3 = /* @__PURE__ */ new Set([
64471
65081
  "it",
64472
65082
  "its"
64473
65083
  ]);
64474
- function extractKeywords3(text3) {
64475
- return text3.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOP_WORDS3.has(w));
65084
+ function extractKeywords4(text3) {
65085
+ return text3.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !STOP_WORDS4.has(w));
64476
65086
  }
64477
65087
  async function discoverRelated(taskQuery, method = "auto", limit = 10) {
64478
65088
  if (!validateSyntax(taskQuery)) {
@@ -64495,7 +65105,7 @@ async function discoverRelated(taskQuery, method = "auto", limit = 10) {
64495
65105
  const sourceLabels = new Set(sourceTask.labels ?? []);
64496
65106
  const sourceDesc = (sourceTask.description ?? "").toLowerCase();
64497
65107
  const sourceTitle = (sourceTask.title ?? "").toLowerCase();
64498
- const sourceWords = extractKeywords3(sourceTitle + " " + sourceDesc);
65108
+ const sourceWords = extractKeywords4(sourceTitle + " " + sourceDesc);
64499
65109
  const parsed = parseQuery(taskQuery);
64500
65110
  const registry2 = await readRegistry();
64501
65111
  if (!registry2) {
@@ -64530,7 +65140,7 @@ async function discoverRelated(taskQuery, method = "auto", limit = 10) {
64530
65140
  }
64531
65141
  if (method === "description" || method === "auto") {
64532
65142
  const taskDesc = ((task.description ?? "") + " " + (task.title ?? "")).toLowerCase();
64533
- const taskWords = extractKeywords3(taskDesc);
65143
+ const taskWords = extractKeywords4(taskDesc);
64534
65144
  const commonWords = sourceWords.filter((w) => taskWords.includes(w));
64535
65145
  if (commonWords.length > 0) {
64536
65146
  const descScore = commonWords.length / Math.max(sourceWords.length, taskWords.length, 1);
@@ -69572,6 +70182,7 @@ __export(research_exports, {
69572
70182
  bulkLink: () => bulkLink,
69573
70183
  compactManifest: () => compactManifest,
69574
70184
  consolidateMemories: () => consolidateMemories,
70185
+ correlateOutcomes: () => correlateOutcomes,
69575
70186
  detectContradictions: () => detectContradictions,
69576
70187
  ensureFts5Tables: () => ensureFts5Tables,
69577
70188
  fetchBrainEntries: () => fetchBrainEntries,
@@ -69582,6 +70193,7 @@ __export(research_exports, {
69582
70193
  getLinkedLearnings: () => getLinkedLearnings,
69583
70194
  getLinkedPatterns: () => getLinkedPatterns,
69584
70195
  getMemoryLinks: () => getMemoryLinks,
70196
+ getMemoryQualityReport: () => getMemoryQualityReport,
69585
70197
  getTaskLinks: () => getTaskLinks,
69586
70198
  hybridSearch: () => hybridSearch,
69587
70199
  learningStats: () => learningStats,
@@ -69623,6 +70235,7 @@ __export(research_exports, {
69623
70235
  storePattern: () => storePattern,
69624
70236
  storeVerifiedCandidate: () => storeVerifiedCandidate,
69625
70237
  timelineBrain: () => timelineBrain,
70238
+ trackMemoryUsage: () => trackMemoryUsage,
69626
70239
  unlinkMemoryFromTask: () => unlinkMemoryFromTask,
69627
70240
  updateDecisionOutcome: () => updateDecisionOutcome,
69628
70241
  updateResearch: () => updateResearch,