@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.
- package/dist/hooks/handlers/task-hooks.d.ts.map +1 -1
- package/dist/hooks/handlers/task-hooks.js +11 -0
- package/dist/hooks/handlers/task-hooks.js.map +1 -1
- package/dist/index.js +647 -34
- package/dist/index.js.map +4 -4
- package/dist/internal.d.ts +3 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +3 -1
- package/dist/internal.js.map +1 -1
- package/dist/memory/decisions.d.ts.map +1 -1
- package/dist/memory/decisions.js +18 -0
- package/dist/memory/decisions.js.map +1 -1
- package/dist/memory/engine-compat.d.ts +17 -0
- package/dist/memory/engine-compat.d.ts.map +1 -1
- package/dist/memory/engine-compat.js +36 -0
- package/dist/memory/engine-compat.js.map +1 -1
- package/dist/memory/graph-memory-bridge.d.ts +158 -0
- package/dist/memory/graph-memory-bridge.d.ts.map +1 -0
- package/dist/memory/graph-memory-bridge.js +519 -0
- package/dist/memory/graph-memory-bridge.js.map +1 -0
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/memory/index.js +2 -0
- package/dist/memory/index.js.map +1 -1
- package/dist/memory/learnings.d.ts.map +1 -1
- package/dist/memory/learnings.js +18 -0
- package/dist/memory/learnings.js.map +1 -1
- package/dist/memory/llm-extraction.d.ts.map +1 -1
- package/dist/memory/llm-extraction.js.map +1 -1
- package/dist/memory/patterns.d.ts.map +1 -1
- package/dist/memory/patterns.js +18 -0
- package/dist/memory/patterns.js.map +1 -1
- package/dist/memory/quality-feedback.d.ts +129 -0
- package/dist/memory/quality-feedback.d.ts.map +1 -0
- package/dist/memory/quality-feedback.js +449 -0
- package/dist/memory/quality-feedback.js.map +1 -0
- package/dist/memory/sleep-consolidation.d.ts +98 -0
- package/dist/memory/sleep-consolidation.d.ts.map +1 -0
- package/dist/memory/sleep-consolidation.js +706 -0
- package/dist/memory/sleep-consolidation.js.map +1 -0
- package/dist/memory/temporal-supersession.d.ts +155 -0
- package/dist/memory/temporal-supersession.d.ts.map +1 -0
- package/dist/memory/temporal-supersession.js +406 -0
- package/dist/memory/temporal-supersession.js.map +1 -0
- package/package.json +6 -6
- package/src/hooks/handlers/task-hooks.ts +11 -0
- package/src/internal.ts +12 -0
- package/src/memory/__tests__/graph-memory-bridge.test.ts +357 -0
- package/src/memory/__tests__/llm-extraction.test.ts +17 -0
- package/src/memory/__tests__/quality-feedback.test.ts +418 -0
- package/src/memory/__tests__/sleep-consolidation.test.ts +790 -0
- package/src/memory/__tests__/temporal-supersession.test.ts +534 -0
- package/src/memory/decisions.ts +24 -0
- package/src/memory/engine-compat.ts +37 -0
- package/src/memory/graph-memory-bridge.ts +751 -0
- package/src/memory/index.ts +2 -0
- package/src/memory/learnings.ts +24 -0
- package/src/memory/patterns.ts +24 -0
- package/src/memory/quality-feedback.ts +640 -0
- package/src/memory/sleep-consolidation.ts +932 -0
- package/src/memory/temporal-supersession.ts +568 -0
- 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(
|
|
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
|
|
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 && !
|
|
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,
|
|
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 <
|
|
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 =
|
|
41995
|
-
const nodeB =
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 && !
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
|
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 && !
|
|
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: () =>
|
|
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
|
|
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
|
|
64475
|
-
return text3.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length > 2 && !
|
|
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 =
|
|
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 =
|
|
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,
|