@cleocode/core 2026.4.37 → 2026.4.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +644 -33
- 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.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
|
|
|
@@ -41908,11 +42153,11 @@ var brain_consolidator_exports = {};
|
|
|
41908
42153
|
__export(brain_consolidator_exports, {
|
|
41909
42154
|
detectContradictions: () => detectContradictions
|
|
41910
42155
|
});
|
|
41911
|
-
function
|
|
42156
|
+
function extractKeywords2(text3) {
|
|
41912
42157
|
const words = text3.toLowerCase().replace(/[^a-z0-9\s\-_]/g, " ").split(/\s+/);
|
|
41913
42158
|
const keywords = /* @__PURE__ */ new Set();
|
|
41914
42159
|
for (const w of words) {
|
|
41915
|
-
if (w.length >= 4 && !
|
|
42160
|
+
if (w.length >= 4 && !STOP_WORDS2.has(w)) {
|
|
41916
42161
|
keywords.add(w);
|
|
41917
42162
|
}
|
|
41918
42163
|
}
|
|
@@ -41961,7 +42206,7 @@ async function detectContradictions(projectRoot) {
|
|
|
41961
42206
|
const keywordMap = /* @__PURE__ */ new Map();
|
|
41962
42207
|
const negationMap = /* @__PURE__ */ new Map();
|
|
41963
42208
|
for (const entry of entries) {
|
|
41964
|
-
keywordMap.set(entry.id,
|
|
42209
|
+
keywordMap.set(entry.id, extractKeywords2(entry.text));
|
|
41965
42210
|
negationMap.set(entry.id, findNegationMarkers(entry.text));
|
|
41966
42211
|
}
|
|
41967
42212
|
for (let i = 0; i < entries.length; i++) {
|
|
@@ -41975,7 +42220,7 @@ async function detectContradictions(projectRoot) {
|
|
|
41975
42220
|
const keywordsB = keywordMap.get(entryB.id);
|
|
41976
42221
|
const negationsB = negationMap.get(entryB.id);
|
|
41977
42222
|
const shared = keywordIntersection(keywordsA, keywordsB);
|
|
41978
|
-
if (shared.length <
|
|
42223
|
+
if (shared.length < MIN_SHARED_KEYWORDS2) continue;
|
|
41979
42224
|
const negationsOnlyInA = negationsA.filter((m) => !negationsB.includes(m));
|
|
41980
42225
|
const negationsOnlyInB = negationsB.filter((m) => !negationsA.includes(m));
|
|
41981
42226
|
const negationFlip = negationsOnlyInA.length > 0 || negationsOnlyInB.length > 0;
|
|
@@ -41993,8 +42238,8 @@ async function detectContradictions(projectRoot) {
|
|
|
41993
42238
|
sharedKeywords: shared.slice(0, 10),
|
|
41994
42239
|
negationMarkers: negMarkers.slice(0, 5)
|
|
41995
42240
|
});
|
|
41996
|
-
const nodeA =
|
|
41997
|
-
const nodeB =
|
|
42241
|
+
const nodeA = buildNodeId2(table, entryA.id);
|
|
42242
|
+
const nodeB = buildNodeId2(table, entryB.id);
|
|
41998
42243
|
try {
|
|
41999
42244
|
nativeDb.prepare(`
|
|
42000
42245
|
INSERT OR IGNORE INTO brain_page_edges
|
|
@@ -42023,7 +42268,7 @@ async function detectContradictions(projectRoot) {
|
|
|
42023
42268
|
}
|
|
42024
42269
|
return results;
|
|
42025
42270
|
}
|
|
42026
|
-
function
|
|
42271
|
+
function buildNodeId2(table, entryId) {
|
|
42027
42272
|
const typeMap = {
|
|
42028
42273
|
brain_observations: "observation",
|
|
42029
42274
|
brain_learnings: "learning",
|
|
@@ -42033,13 +42278,13 @@ function buildNodeId(table, entryId) {
|
|
|
42033
42278
|
const type = typeMap[table] ?? "entry";
|
|
42034
42279
|
return `${type}:${entryId}`;
|
|
42035
42280
|
}
|
|
42036
|
-
var
|
|
42281
|
+
var MIN_SHARED_KEYWORDS2, NEGATION_MARKERS, STOP_WORDS2;
|
|
42037
42282
|
var init_brain_consolidator = __esm({
|
|
42038
42283
|
"packages/core/src/memory/brain-consolidator.ts"() {
|
|
42039
42284
|
"use strict";
|
|
42040
42285
|
init_brain_sqlite();
|
|
42041
42286
|
init_typed_query();
|
|
42042
|
-
|
|
42287
|
+
MIN_SHARED_KEYWORDS2 = 3;
|
|
42043
42288
|
NEGATION_MARKERS = [
|
|
42044
42289
|
"not",
|
|
42045
42290
|
"never",
|
|
@@ -42060,7 +42305,7 @@ var init_brain_consolidator = __esm({
|
|
|
42060
42305
|
"undone",
|
|
42061
42306
|
"superseded"
|
|
42062
42307
|
];
|
|
42063
|
-
|
|
42308
|
+
STOP_WORDS2 = /* @__PURE__ */ new Set([
|
|
42064
42309
|
"the",
|
|
42065
42310
|
"a",
|
|
42066
42311
|
"an",
|
|
@@ -42148,11 +42393,11 @@ async function applyTemporalDecay(projectRoot, options) {
|
|
|
42148
42393
|
tablesProcessed: ["brain_learnings"]
|
|
42149
42394
|
};
|
|
42150
42395
|
}
|
|
42151
|
-
function
|
|
42396
|
+
function extractKeywords3(text3) {
|
|
42152
42397
|
const words = text3.toLowerCase().replace(/[^a-z0-9\s-]/g, "").split(/\s+/);
|
|
42153
42398
|
const keywords = /* @__PURE__ */ new Set();
|
|
42154
42399
|
for (const w of words) {
|
|
42155
|
-
if (w.length >= 4 && !
|
|
42400
|
+
if (w.length >= 4 && !STOP_WORDS3.has(w)) {
|
|
42156
42401
|
keywords.add(w);
|
|
42157
42402
|
}
|
|
42158
42403
|
}
|
|
@@ -42190,7 +42435,7 @@ async function consolidateMemories(projectRoot, options) {
|
|
|
42190
42435
|
}
|
|
42191
42436
|
const entries = oldObservations.map((obs) => ({
|
|
42192
42437
|
...obs,
|
|
42193
|
-
keywords:
|
|
42438
|
+
keywords: extractKeywords3(`${obs.title} ${obs.narrative ?? ""}`),
|
|
42194
42439
|
clustered: false
|
|
42195
42440
|
}));
|
|
42196
42441
|
const clusters = [];
|
|
@@ -42592,13 +42837,13 @@ async function strengthenCoRetrievedEdges(projectRoot) {
|
|
|
42592
42837
|
}
|
|
42593
42838
|
return strengthened;
|
|
42594
42839
|
}
|
|
42595
|
-
var
|
|
42840
|
+
var STOP_WORDS3;
|
|
42596
42841
|
var init_brain_lifecycle = __esm({
|
|
42597
42842
|
"packages/core/src/memory/brain-lifecycle.ts"() {
|
|
42598
42843
|
"use strict";
|
|
42599
42844
|
init_brain_accessor();
|
|
42600
42845
|
init_typed_query();
|
|
42601
|
-
|
|
42846
|
+
STOP_WORDS3 = /* @__PURE__ */ new Set([
|
|
42602
42847
|
"the",
|
|
42603
42848
|
"a",
|
|
42604
42849
|
"an",
|
|
@@ -43203,6 +43448,358 @@ var init_session_hooks = __esm({
|
|
|
43203
43448
|
}
|
|
43204
43449
|
});
|
|
43205
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
|
+
|
|
43206
43803
|
// packages/core/src/hooks/handlers/task-hooks.ts
|
|
43207
43804
|
async function handleToolStart(projectRoot, payload) {
|
|
43208
43805
|
const { observeBrain: observeBrain2 } = await Promise.resolve().then(() => (init_brain_retrieval(), brain_retrieval_exports));
|
|
@@ -43236,6 +43833,13 @@ async function handleToolComplete(projectRoot, payload) {
|
|
|
43236
43833
|
} catch {
|
|
43237
43834
|
}
|
|
43238
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
|
+
});
|
|
43239
43843
|
await maybeRefreshMemoryBridge(projectRoot);
|
|
43240
43844
|
}
|
|
43241
43845
|
var init_task_hooks = __esm({
|
|
@@ -57502,7 +58106,7 @@ function generateRecommendation2(changeType, affectedCount, cascadeDepth, taskId
|
|
|
57502
58106
|
}
|
|
57503
58107
|
}
|
|
57504
58108
|
function scoreTaskMatch(change, task) {
|
|
57505
|
-
const
|
|
58109
|
+
const STOP_WORDS5 = /* @__PURE__ */ new Set([
|
|
57506
58110
|
"a",
|
|
57507
58111
|
"an",
|
|
57508
58112
|
"the",
|
|
@@ -57524,7 +58128,7 @@ function scoreTaskMatch(change, task) {
|
|
|
57524
58128
|
"do",
|
|
57525
58129
|
"not"
|
|
57526
58130
|
]);
|
|
57527
|
-
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));
|
|
57528
58132
|
const changeTokens = new Set(tokenise(change));
|
|
57529
58133
|
if (changeTokens.size === 0) return 0;
|
|
57530
58134
|
const taskText = `${task.title ?? ""} ${task.description ?? ""}`;
|
|
@@ -60490,6 +61094,7 @@ __export(memory_exports, {
|
|
|
60490
61094
|
bulkLink: () => bulkLink,
|
|
60491
61095
|
compactManifest: () => compactManifest,
|
|
60492
61096
|
consolidateMemories: () => consolidateMemories,
|
|
61097
|
+
correlateOutcomes: () => correlateOutcomes,
|
|
60493
61098
|
detectContradictions: () => detectContradictions,
|
|
60494
61099
|
ensureFts5Tables: () => ensureFts5Tables,
|
|
60495
61100
|
fetchBrainEntries: () => fetchBrainEntries,
|
|
@@ -60500,6 +61105,7 @@ __export(memory_exports, {
|
|
|
60500
61105
|
getLinkedLearnings: () => getLinkedLearnings,
|
|
60501
61106
|
getLinkedPatterns: () => getLinkedPatterns,
|
|
60502
61107
|
getMemoryLinks: () => getMemoryLinks,
|
|
61108
|
+
getMemoryQualityReport: () => getMemoryQualityReport,
|
|
60503
61109
|
getTaskLinks: () => getTaskLinks,
|
|
60504
61110
|
hybridSearch: () => hybridSearch,
|
|
60505
61111
|
learningStats: () => learningStats,
|
|
@@ -60541,6 +61147,7 @@ __export(memory_exports, {
|
|
|
60541
61147
|
storePattern: () => storePattern,
|
|
60542
61148
|
storeVerifiedCandidate: () => storeVerifiedCandidate,
|
|
60543
61149
|
timelineBrain: () => timelineBrain,
|
|
61150
|
+
trackMemoryUsage: () => trackMemoryUsage,
|
|
60544
61151
|
unlinkMemoryFromTask: () => unlinkMemoryFromTask,
|
|
60545
61152
|
updateDecisionOutcome: () => updateDecisionOutcome,
|
|
60546
61153
|
updateResearch: () => updateResearch,
|
|
@@ -60932,6 +61539,7 @@ async function verifyAndStoreBatch(projectRoot, candidates) {
|
|
|
60932
61539
|
// packages/core/src/memory/index.ts
|
|
60933
61540
|
init_learnings();
|
|
60934
61541
|
init_patterns();
|
|
61542
|
+
init_quality_feedback();
|
|
60935
61543
|
function getResearchPath(cwd) {
|
|
60936
61544
|
return join49(getCleoDirAbsolute(cwd), "research.json");
|
|
60937
61545
|
}
|
|
@@ -63848,7 +64456,7 @@ __export(nexus_exports, {
|
|
|
63848
64456
|
criticalPath: () => criticalPath,
|
|
63849
64457
|
discoverRelated: () => discoverRelated,
|
|
63850
64458
|
executeTransfer: () => executeTransfer,
|
|
63851
|
-
extractKeywords: () =>
|
|
64459
|
+
extractKeywords: () => extractKeywords4,
|
|
63852
64460
|
generateProjectHash: () => generateProjectHash,
|
|
63853
64461
|
getCurrentProject: () => getCurrentProject,
|
|
63854
64462
|
getNexusCacheDir: () => getNexusCacheDir,
|
|
@@ -64391,7 +64999,7 @@ async function orphanDetection() {
|
|
|
64391
64999
|
// packages/core/src/nexus/discover.ts
|
|
64392
65000
|
init_data_accessor();
|
|
64393
65001
|
init_registry3();
|
|
64394
|
-
var
|
|
65002
|
+
var STOP_WORDS4 = /* @__PURE__ */ new Set([
|
|
64395
65003
|
"the",
|
|
64396
65004
|
"a",
|
|
64397
65005
|
"an",
|
|
@@ -64473,8 +65081,8 @@ var STOP_WORDS3 = /* @__PURE__ */ new Set([
|
|
|
64473
65081
|
"it",
|
|
64474
65082
|
"its"
|
|
64475
65083
|
]);
|
|
64476
|
-
function
|
|
64477
|
-
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));
|
|
64478
65086
|
}
|
|
64479
65087
|
async function discoverRelated(taskQuery, method = "auto", limit = 10) {
|
|
64480
65088
|
if (!validateSyntax(taskQuery)) {
|
|
@@ -64497,7 +65105,7 @@ async function discoverRelated(taskQuery, method = "auto", limit = 10) {
|
|
|
64497
65105
|
const sourceLabels = new Set(sourceTask.labels ?? []);
|
|
64498
65106
|
const sourceDesc = (sourceTask.description ?? "").toLowerCase();
|
|
64499
65107
|
const sourceTitle = (sourceTask.title ?? "").toLowerCase();
|
|
64500
|
-
const sourceWords =
|
|
65108
|
+
const sourceWords = extractKeywords4(sourceTitle + " " + sourceDesc);
|
|
64501
65109
|
const parsed = parseQuery(taskQuery);
|
|
64502
65110
|
const registry2 = await readRegistry();
|
|
64503
65111
|
if (!registry2) {
|
|
@@ -64532,7 +65140,7 @@ async function discoverRelated(taskQuery, method = "auto", limit = 10) {
|
|
|
64532
65140
|
}
|
|
64533
65141
|
if (method === "description" || method === "auto") {
|
|
64534
65142
|
const taskDesc = ((task.description ?? "") + " " + (task.title ?? "")).toLowerCase();
|
|
64535
|
-
const taskWords =
|
|
65143
|
+
const taskWords = extractKeywords4(taskDesc);
|
|
64536
65144
|
const commonWords = sourceWords.filter((w) => taskWords.includes(w));
|
|
64537
65145
|
if (commonWords.length > 0) {
|
|
64538
65146
|
const descScore = commonWords.length / Math.max(sourceWords.length, taskWords.length, 1);
|
|
@@ -69574,6 +70182,7 @@ __export(research_exports, {
|
|
|
69574
70182
|
bulkLink: () => bulkLink,
|
|
69575
70183
|
compactManifest: () => compactManifest,
|
|
69576
70184
|
consolidateMemories: () => consolidateMemories,
|
|
70185
|
+
correlateOutcomes: () => correlateOutcomes,
|
|
69577
70186
|
detectContradictions: () => detectContradictions,
|
|
69578
70187
|
ensureFts5Tables: () => ensureFts5Tables,
|
|
69579
70188
|
fetchBrainEntries: () => fetchBrainEntries,
|
|
@@ -69584,6 +70193,7 @@ __export(research_exports, {
|
|
|
69584
70193
|
getLinkedLearnings: () => getLinkedLearnings,
|
|
69585
70194
|
getLinkedPatterns: () => getLinkedPatterns,
|
|
69586
70195
|
getMemoryLinks: () => getMemoryLinks,
|
|
70196
|
+
getMemoryQualityReport: () => getMemoryQualityReport,
|
|
69587
70197
|
getTaskLinks: () => getTaskLinks,
|
|
69588
70198
|
hybridSearch: () => hybridSearch,
|
|
69589
70199
|
learningStats: () => learningStats,
|
|
@@ -69625,6 +70235,7 @@ __export(research_exports, {
|
|
|
69625
70235
|
storePattern: () => storePattern,
|
|
69626
70236
|
storeVerifiedCandidate: () => storeVerifiedCandidate,
|
|
69627
70237
|
timelineBrain: () => timelineBrain,
|
|
70238
|
+
trackMemoryUsage: () => trackMemoryUsage,
|
|
69628
70239
|
unlinkMemoryFromTask: () => unlinkMemoryFromTask,
|
|
69629
70240
|
updateDecisionOutcome: () => updateDecisionOutcome,
|
|
69630
70241
|
updateResearch: () => updateResearch,
|