cortex-mcp 2.5.0 → 2.6.0
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/memory/access-pattern-tracker.d.ts +51 -0
- package/dist/memory/access-pattern-tracker.d.ts.map +1 -0
- package/dist/memory/access-pattern-tracker.js +92 -0
- package/dist/memory/access-pattern-tracker.js.map +1 -0
- package/dist/memory/cross-memory-linker.d.ts +18 -0
- package/dist/memory/cross-memory-linker.d.ts.map +1 -0
- package/dist/memory/cross-memory-linker.js +115 -0
- package/dist/memory/cross-memory-linker.js.map +1 -0
- package/dist/memory/daily-diary.d.ts +30 -0
- package/dist/memory/daily-diary.d.ts.map +1 -0
- package/dist/memory/daily-diary.js +159 -0
- package/dist/memory/daily-diary.js.map +1 -0
- package/dist/memory/embedding-cache.d.ts +32 -0
- package/dist/memory/embedding-cache.d.ts.map +1 -0
- package/dist/memory/embedding-cache.js +76 -0
- package/dist/memory/embedding-cache.js.map +1 -0
- package/dist/memory/memory-decay.d.ts.map +1 -1
- package/dist/memory/memory-decay.js +10 -6
- package/dist/memory/memory-decay.js.map +1 -1
- package/dist/memory/memory-export-md.d.ts +12 -0
- package/dist/memory/memory-export-md.d.ts.map +1 -0
- package/dist/memory/memory-export-md.js +188 -0
- package/dist/memory/memory-export-md.js.map +1 -0
- package/dist/memory/memory-ranker.d.ts.map +1 -1
- package/dist/memory/memory-ranker.js +7 -2
- package/dist/memory/memory-ranker.js.map +1 -1
- package/dist/memory/mmr-reranker.d.ts +39 -0
- package/dist/memory/mmr-reranker.d.ts.map +1 -0
- package/dist/memory/mmr-reranker.js +115 -0
- package/dist/memory/mmr-reranker.js.map +1 -0
- package/dist/memory/query-expansion.d.ts +28 -0
- package/dist/memory/query-expansion.d.ts.map +1 -0
- package/dist/memory/query-expansion.js +140 -0
- package/dist/memory/query-expansion.js.map +1 -0
- package/dist/memory/soul-manager.d.ts +30 -0
- package/dist/memory/soul-manager.d.ts.map +1 -0
- package/dist/memory/soul-manager.js +171 -0
- package/dist/memory/soul-manager.js.map +1 -0
- package/dist/server/mcp-handler.d.ts.map +1 -1
- package/dist/server/mcp-handler.js +103 -48
- package/dist/server/mcp-handler.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access Pattern Tracker — Learns which memory types each user actually uses.
|
|
3
|
+
*
|
|
4
|
+
* Tracks recall/search patterns and builds a personal preference profile.
|
|
5
|
+
* The ranker uses this to boost memory types the user accesses most often.
|
|
6
|
+
*
|
|
7
|
+
* Example: If a user recalls CORRECTION memories 5x more than INSIGHT,
|
|
8
|
+
* future results boost CORRECTIONs so the brain feels personalized.
|
|
9
|
+
*/
|
|
10
|
+
import { MemoryStore } from '../db/memory-store';
|
|
11
|
+
export interface AccessProfile {
|
|
12
|
+
typeCounts: Record<string, number>;
|
|
13
|
+
totalAccesses: number;
|
|
14
|
+
lastUpdated: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Record that the user accessed a memory of a given type.
|
|
18
|
+
* Called whenever recall_memory, force_recall, or pre_check returns results.
|
|
19
|
+
*/
|
|
20
|
+
export declare function recordAccess(type: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Record accesses for a batch of recalled memories.
|
|
23
|
+
*/
|
|
24
|
+
export declare function recordBatchAccess(memories: Array<{
|
|
25
|
+
type: string;
|
|
26
|
+
}>): void;
|
|
27
|
+
/**
|
|
28
|
+
* Get a personalized boost multiplier for a memory type.
|
|
29
|
+
* Types the user accesses frequently get boosted (up to 1.8x).
|
|
30
|
+
* Types never accessed stay at 1.0x (neutral).
|
|
31
|
+
*
|
|
32
|
+
* Uses frequency ratio: (type_count / total) normalized to 1.0-1.8 range.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getPersonalBoost(type: string): number;
|
|
35
|
+
/**
|
|
36
|
+
* Get the full access profile (for dashboard/stats).
|
|
37
|
+
*/
|
|
38
|
+
export declare function getAccessProfile(): AccessProfile;
|
|
39
|
+
/**
|
|
40
|
+
* Try to load access profile from stored memories (persistence across restarts).
|
|
41
|
+
*/
|
|
42
|
+
export declare function loadAccessProfile(memoryStore: MemoryStore): void;
|
|
43
|
+
/**
|
|
44
|
+
* Get top accessed types (for diagnostics).
|
|
45
|
+
*/
|
|
46
|
+
export declare function getTopTypes(n?: number): Array<{
|
|
47
|
+
type: string;
|
|
48
|
+
count: number;
|
|
49
|
+
boost: number;
|
|
50
|
+
}>;
|
|
51
|
+
//# sourceMappingURL=access-pattern-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-pattern-tracker.d.ts","sourceRoot":"","sources":["../../src/memory/access-pattern-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC1B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACvB;AASD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAI/C;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,IAAI,CAIzE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYrD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAkBhE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAE,MAAU,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAShG"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.recordAccess = recordAccess;
|
|
4
|
+
exports.recordBatchAccess = recordBatchAccess;
|
|
5
|
+
exports.getPersonalBoost = getPersonalBoost;
|
|
6
|
+
exports.getAccessProfile = getAccessProfile;
|
|
7
|
+
exports.loadAccessProfile = loadAccessProfile;
|
|
8
|
+
exports.getTopTypes = getTopTypes;
|
|
9
|
+
// In-memory access profile (persisted via session tracker)
|
|
10
|
+
let accessProfile = {
|
|
11
|
+
typeCounts: {},
|
|
12
|
+
totalAccesses: 0,
|
|
13
|
+
lastUpdated: Date.now(),
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Record that the user accessed a memory of a given type.
|
|
17
|
+
* Called whenever recall_memory, force_recall, or pre_check returns results.
|
|
18
|
+
*/
|
|
19
|
+
function recordAccess(type) {
|
|
20
|
+
accessProfile.typeCounts[type] = (accessProfile.typeCounts[type] || 0) + 1;
|
|
21
|
+
accessProfile.totalAccesses++;
|
|
22
|
+
accessProfile.lastUpdated = Date.now();
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Record accesses for a batch of recalled memories.
|
|
26
|
+
*/
|
|
27
|
+
function recordBatchAccess(memories) {
|
|
28
|
+
for (const m of memories) {
|
|
29
|
+
recordAccess(m.type);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get a personalized boost multiplier for a memory type.
|
|
34
|
+
* Types the user accesses frequently get boosted (up to 1.8x).
|
|
35
|
+
* Types never accessed stay at 1.0x (neutral).
|
|
36
|
+
*
|
|
37
|
+
* Uses frequency ratio: (type_count / total) normalized to 1.0-1.8 range.
|
|
38
|
+
*/
|
|
39
|
+
function getPersonalBoost(type) {
|
|
40
|
+
if (accessProfile.totalAccesses < 10)
|
|
41
|
+
return 1.0; // Not enough data yet
|
|
42
|
+
const typeCount = accessProfile.typeCounts[type] || 0;
|
|
43
|
+
const frequency = typeCount / accessProfile.totalAccesses;
|
|
44
|
+
// Expected frequency if all types were equal (~20% with 5 types)
|
|
45
|
+
const expectedFreq = 0.2;
|
|
46
|
+
// Boost = 1.0 + (frequency - expected) * scale, clamped to [0.7, 1.8]
|
|
47
|
+
const boost = 1.0 + (frequency - expectedFreq) * 4.0;
|
|
48
|
+
return Math.max(0.7, Math.min(1.8, boost));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get the full access profile (for dashboard/stats).
|
|
52
|
+
*/
|
|
53
|
+
function getAccessProfile() {
|
|
54
|
+
return { ...accessProfile };
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Try to load access profile from stored memories (persistence across restarts).
|
|
58
|
+
*/
|
|
59
|
+
function loadAccessProfile(memoryStore) {
|
|
60
|
+
try {
|
|
61
|
+
const profileMemories = memoryStore.getByType('INSIGHT', 100);
|
|
62
|
+
// Reconstruct from access_count of each type
|
|
63
|
+
const all = memoryStore.getActive(500);
|
|
64
|
+
const typeCounts = {};
|
|
65
|
+
let total = 0;
|
|
66
|
+
for (const m of all) {
|
|
67
|
+
const count = m.accessCount || 0;
|
|
68
|
+
if (count > 0) {
|
|
69
|
+
typeCounts[m.type] = (typeCounts[m.type] || 0) + count;
|
|
70
|
+
total += count;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (total > 0) {
|
|
74
|
+
accessProfile = { typeCounts, totalAccesses: total, lastUpdated: Date.now() };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch { /* fresh install, no data yet */ }
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Get top accessed types (for diagnostics).
|
|
81
|
+
*/
|
|
82
|
+
function getTopTypes(n = 5) {
|
|
83
|
+
return Object.entries(accessProfile.typeCounts)
|
|
84
|
+
.sort(([, a], [, b]) => b - a)
|
|
85
|
+
.slice(0, n)
|
|
86
|
+
.map(([type, count]) => ({
|
|
87
|
+
type,
|
|
88
|
+
count,
|
|
89
|
+
boost: getPersonalBoost(type),
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=access-pattern-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-pattern-tracker.js","sourceRoot":"","sources":["../../src/memory/access-pattern-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-Memory Linker — Automatically creates edges between related memories.
|
|
3
|
+
*
|
|
4
|
+
* When a new memory is stored, this module finds existing memories that share
|
|
5
|
+
* topics, files, or keywords and creates graph edges between them.
|
|
6
|
+
*
|
|
7
|
+
* This transforms isolated memories into a connected knowledge graph.
|
|
8
|
+
* When the user asks "tell me about auth", they get a connected story
|
|
9
|
+
* instead of random fragments.
|
|
10
|
+
*/
|
|
11
|
+
import { MemoryStore } from '../db/memory-store';
|
|
12
|
+
import type { MemoryUnit } from '../types';
|
|
13
|
+
/**
|
|
14
|
+
* After storing a new memory, auto-link it to related existing memories.
|
|
15
|
+
* Uses 3 signals: shared files, shared tags, and word overlap.
|
|
16
|
+
*/
|
|
17
|
+
export declare function autoLinkMemory(memoryStore: MemoryStore, newMemory: MemoryUnit): number;
|
|
18
|
+
//# sourceMappingURL=cross-memory-linker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-memory-linker.d.ts","sourceRoot":"","sources":["../../src/memory/cross-memory-linker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,UAAU,CAAC;AAEtD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,GAAG,MAAM,CAyEtF"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.autoLinkMemory = autoLinkMemory;
|
|
4
|
+
/**
|
|
5
|
+
* After storing a new memory, auto-link it to related existing memories.
|
|
6
|
+
* Uses 3 signals: shared files, shared tags, and word overlap.
|
|
7
|
+
*/
|
|
8
|
+
function autoLinkMemory(memoryStore, newMemory) {
|
|
9
|
+
let linksCreated = 0;
|
|
10
|
+
try {
|
|
11
|
+
// 1. Find memories sharing the same files
|
|
12
|
+
const fileRelated = [];
|
|
13
|
+
if (newMemory.relatedFiles && newMemory.relatedFiles.length > 0) {
|
|
14
|
+
for (const file of newMemory.relatedFiles.slice(0, 3)) {
|
|
15
|
+
const basename = file.split(/[/\\]/).pop() || file;
|
|
16
|
+
const related = memoryStore.getByFile(basename, 10);
|
|
17
|
+
for (const m of related) {
|
|
18
|
+
if (m.id !== newMemory.id && m.isActive) {
|
|
19
|
+
fileRelated.push(m);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// 2. Find memories sharing tags
|
|
25
|
+
const tagRelated = [];
|
|
26
|
+
const newTags = parseTags(newMemory.tags);
|
|
27
|
+
if (newTags.length > 0) {
|
|
28
|
+
for (const tag of newTags.slice(0, 3)) {
|
|
29
|
+
try {
|
|
30
|
+
const tagged = memoryStore.findByTag(tag, 10);
|
|
31
|
+
for (const m of tagged) {
|
|
32
|
+
if (m.id !== newMemory.id && m.isActive) {
|
|
33
|
+
tagRelated.push(m);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch { /* tag search might fail */ }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// 3. Compute word overlap with recent memories
|
|
41
|
+
const newWords = extractKeywords(newMemory.intent);
|
|
42
|
+
const recentMemories = memoryStore.getActive(50);
|
|
43
|
+
const wordRelated = [];
|
|
44
|
+
for (const m of recentMemories) {
|
|
45
|
+
if (m.id === newMemory.id)
|
|
46
|
+
continue;
|
|
47
|
+
const mWords = extractKeywords(m.intent);
|
|
48
|
+
const overlap = wordOverlap(newWords, mWords);
|
|
49
|
+
if (overlap >= 0.3) { // 30%+ word overlap → related
|
|
50
|
+
wordRelated.push(m);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Deduplicate and create edges
|
|
54
|
+
const seen = new Set();
|
|
55
|
+
const candidates = [...fileRelated, ...tagRelated, ...wordRelated];
|
|
56
|
+
for (const related of candidates) {
|
|
57
|
+
if (seen.has(related.id))
|
|
58
|
+
continue;
|
|
59
|
+
seen.add(related.id);
|
|
60
|
+
if (linksCreated >= 5)
|
|
61
|
+
break; // Max 5 links per memory
|
|
62
|
+
const edgeType = fileRelated.includes(related) ? 'same_file' :
|
|
63
|
+
tagRelated.includes(related) ? 'same_topic' : 'similar';
|
|
64
|
+
try {
|
|
65
|
+
memoryStore.addEdge({
|
|
66
|
+
sourceId: newMemory.id,
|
|
67
|
+
targetId: related.id,
|
|
68
|
+
edgeType,
|
|
69
|
+
weight: edgeType === 'same_file' ? 0.9 :
|
|
70
|
+
edgeType === 'same_topic' ? 0.7 : 0.5,
|
|
71
|
+
});
|
|
72
|
+
linksCreated++;
|
|
73
|
+
}
|
|
74
|
+
catch { /* edge might already exist */ }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch { /* don't break memory storage if linking fails */ }
|
|
78
|
+
return linksCreated;
|
|
79
|
+
}
|
|
80
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
81
|
+
function parseTags(tags) {
|
|
82
|
+
if (!tags)
|
|
83
|
+
return [];
|
|
84
|
+
if (Array.isArray(tags))
|
|
85
|
+
return tags;
|
|
86
|
+
if (typeof tags === 'string') {
|
|
87
|
+
try {
|
|
88
|
+
return JSON.parse(tags);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
function extractKeywords(text) {
|
|
97
|
+
const STOP = new Set(['the', 'a', 'an', 'is', 'are', 'was', 'were', 'to', 'of', 'in',
|
|
98
|
+
'for', 'on', 'with', 'at', 'by', 'from', 'use', 'always', 'never', 'should',
|
|
99
|
+
'must', 'not', 'do', 'be', 'it', 'this', 'that', 'and', 'or', 'but', 'we', 'i']);
|
|
100
|
+
return new Set(text.toLowerCase()
|
|
101
|
+
.replace(/[^a-z0-9\s]/g, ' ')
|
|
102
|
+
.split(/\s+/)
|
|
103
|
+
.filter(w => w.length > 2 && !STOP.has(w)));
|
|
104
|
+
}
|
|
105
|
+
function wordOverlap(a, b) {
|
|
106
|
+
if (a.size === 0 || b.size === 0)
|
|
107
|
+
return 0;
|
|
108
|
+
let shared = 0;
|
|
109
|
+
for (const word of a) {
|
|
110
|
+
if (b.has(word))
|
|
111
|
+
shared++;
|
|
112
|
+
}
|
|
113
|
+
return shared / Math.min(a.size, b.size);
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=cross-memory-linker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cross-memory-linker.js","sourceRoot":"","sources":["../../src/memory/cross-memory-linker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface DiaryEntry {
|
|
2
|
+
type: 'decision' | 'correction' | 'bug_fix' | 'convention' | 'insight' | 'task' | 'file_change';
|
|
3
|
+
content: string;
|
|
4
|
+
file?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Append an entry to today's diary.
|
|
8
|
+
*/
|
|
9
|
+
export declare function appendDiaryEntry(entry: DiaryEntry): void;
|
|
10
|
+
/**
|
|
11
|
+
* Get diary content for a specific date.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getDiaryForDate(date: string): string | null;
|
|
14
|
+
/**
|
|
15
|
+
* Get the last N days of diary entries combined.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getRecentDiary(days?: number): string;
|
|
18
|
+
/**
|
|
19
|
+
* Format diary context for injection into force_recall.
|
|
20
|
+
* Returns last 2 days of diary, condensed.
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatDiaryContext(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Get diary stats for dashboard.
|
|
25
|
+
*/
|
|
26
|
+
export declare function getDiaryStats(): {
|
|
27
|
+
totalDays: number;
|
|
28
|
+
todayEntries: number;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=daily-diary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daily-diary.d.ts","sourceRoot":"","sources":["../../src/memory/daily-diary.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,MAAM,GAAG,aAAa,CAAC;IAChG,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACjB;AAID;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAoBxD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ3D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAU,GAAG,MAAM,CAevD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAU3C;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAY3E"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.appendDiaryEntry = appendDiaryEntry;
|
|
37
|
+
exports.getDiaryForDate = getDiaryForDate;
|
|
38
|
+
exports.getRecentDiary = getRecentDiary;
|
|
39
|
+
exports.formatDiaryContext = formatDiaryContext;
|
|
40
|
+
exports.getDiaryStats = getDiaryStats;
|
|
41
|
+
/**
|
|
42
|
+
* Daily Diary — OpenClaw-style daily Markdown logs.
|
|
43
|
+
*
|
|
44
|
+
* Writes append-only daily notes like OpenClaw's memory/YYYY-MM-DD.md.
|
|
45
|
+
* Each day gets its own file with timestamped entries:
|
|
46
|
+
* - What was learned
|
|
47
|
+
* - What files changed
|
|
48
|
+
* - What decisions were made
|
|
49
|
+
* - What bugs were fixed
|
|
50
|
+
*
|
|
51
|
+
* This gives the AI a "running journal" of recent work.
|
|
52
|
+
* Injected into force_recall as Layer 7.5 (recent context).
|
|
53
|
+
*
|
|
54
|
+
* Stored in: ~/.cortex-memory/diary/YYYY-MM-DD.md
|
|
55
|
+
*/
|
|
56
|
+
const fs = __importStar(require("fs"));
|
|
57
|
+
const path = __importStar(require("path"));
|
|
58
|
+
const os = __importStar(require("os"));
|
|
59
|
+
const DIARY_DIR = path.join(os.homedir(), '.cortex-memory', 'diary');
|
|
60
|
+
/**
|
|
61
|
+
* Append an entry to today's diary.
|
|
62
|
+
*/
|
|
63
|
+
function appendDiaryEntry(entry) {
|
|
64
|
+
try {
|
|
65
|
+
if (!fs.existsSync(DIARY_DIR))
|
|
66
|
+
fs.mkdirSync(DIARY_DIR, { recursive: true });
|
|
67
|
+
const today = getDateString();
|
|
68
|
+
const diaryPath = path.join(DIARY_DIR, `${today}.md`);
|
|
69
|
+
const time = new Date().toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit' });
|
|
70
|
+
const icon = ICONS[entry.type] || '📝';
|
|
71
|
+
const fileSuffix = entry.file ? ` _(${path.basename(entry.file)})_` : '';
|
|
72
|
+
const line = `- ${time} ${icon} **${entry.type.toUpperCase()}**: ${entry.content}${fileSuffix}\n`;
|
|
73
|
+
// Create header if new file
|
|
74
|
+
if (!fs.existsSync(diaryPath)) {
|
|
75
|
+
const header = `# 📔 Cortex Diary — ${today}\n\n`;
|
|
76
|
+
fs.writeFileSync(diaryPath, header, 'utf-8');
|
|
77
|
+
}
|
|
78
|
+
fs.appendFileSync(diaryPath, line, 'utf-8');
|
|
79
|
+
}
|
|
80
|
+
catch { /* diary is non-critical */ }
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get diary content for a specific date.
|
|
84
|
+
*/
|
|
85
|
+
function getDiaryForDate(date) {
|
|
86
|
+
try {
|
|
87
|
+
const diaryPath = path.join(DIARY_DIR, `${date}.md`);
|
|
88
|
+
if (fs.existsSync(diaryPath)) {
|
|
89
|
+
return fs.readFileSync(diaryPath, 'utf-8');
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch { /* */ }
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Get the last N days of diary entries combined.
|
|
97
|
+
*/
|
|
98
|
+
function getRecentDiary(days = 3) {
|
|
99
|
+
const entries = [];
|
|
100
|
+
const now = Date.now();
|
|
101
|
+
const DAY = 24 * 60 * 60 * 1000;
|
|
102
|
+
for (let i = 0; i < days; i++) {
|
|
103
|
+
const date = new Date(now - i * DAY);
|
|
104
|
+
const dateStr = formatDate(date);
|
|
105
|
+
const content = getDiaryForDate(dateStr);
|
|
106
|
+
if (content && content.trim().length > 50) {
|
|
107
|
+
entries.push(content.trim());
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return entries.join('\n\n---\n\n');
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Format diary context for injection into force_recall.
|
|
114
|
+
* Returns last 2 days of diary, condensed.
|
|
115
|
+
*/
|
|
116
|
+
function formatDiaryContext() {
|
|
117
|
+
const diary = getRecentDiary(2);
|
|
118
|
+
if (!diary || diary.length < 50)
|
|
119
|
+
return '';
|
|
120
|
+
// Truncate to last 20 entries to avoid flooding context
|
|
121
|
+
const lines = diary.split('\n').filter(l => l.startsWith('- '));
|
|
122
|
+
const recent = lines.slice(-20);
|
|
123
|
+
if (recent.length === 0)
|
|
124
|
+
return '';
|
|
125
|
+
return `\n## 📔 Recent Diary (last 2 days)\n${recent.join('\n')}`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get diary stats for dashboard.
|
|
129
|
+
*/
|
|
130
|
+
function getDiaryStats() {
|
|
131
|
+
try {
|
|
132
|
+
if (!fs.existsSync(DIARY_DIR))
|
|
133
|
+
return { totalDays: 0, todayEntries: 0 };
|
|
134
|
+
const files = fs.readdirSync(DIARY_DIR).filter(f => f.endsWith('.md'));
|
|
135
|
+
const today = getDiaryForDate(getDateString());
|
|
136
|
+
const todayEntries = today ? today.split('\n').filter(l => l.startsWith('- ')).length : 0;
|
|
137
|
+
return { totalDays: files.length, todayEntries };
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return { totalDays: 0, todayEntries: 0 };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
144
|
+
const ICONS = {
|
|
145
|
+
decision: '📌',
|
|
146
|
+
correction: '🔴',
|
|
147
|
+
bug_fix: '🐛',
|
|
148
|
+
convention: '📏',
|
|
149
|
+
insight: '💡',
|
|
150
|
+
task: '📋',
|
|
151
|
+
file_change: '📁',
|
|
152
|
+
};
|
|
153
|
+
function getDateString() {
|
|
154
|
+
return formatDate(new Date());
|
|
155
|
+
}
|
|
156
|
+
function formatDate(d) {
|
|
157
|
+
return d.toISOString().split('T')[0]; // YYYY-MM-DD
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=daily-diary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daily-diary.js","sourceRoot":"","sources":["../../src/memory/daily-diary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedding Cache — Avoids re-computing embeddings for identical text.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from OpenClaw's embedding_cache table architecture.
|
|
5
|
+
*
|
|
6
|
+
* Problem: Every recall re-embeds the query, even if it's the exact same text.
|
|
7
|
+
* With MiniLM this takes ~50ms per embedding — adds up fast.
|
|
8
|
+
*
|
|
9
|
+
* Solution: Cache embeddings in memory with an LRU eviction policy.
|
|
10
|
+
* Cache key = hash of the text content.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Get a cached embedding for text, or null if not cached.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getCachedEmbedding(text: string): number[] | null;
|
|
16
|
+
/**
|
|
17
|
+
* Store an embedding in the cache.
|
|
18
|
+
* Uses LRU eviction when cache is full.
|
|
19
|
+
*/
|
|
20
|
+
export declare function cacheEmbedding(text: string, embedding: number[]): void;
|
|
21
|
+
/**
|
|
22
|
+
* Clear the entire embedding cache.
|
|
23
|
+
*/
|
|
24
|
+
export declare function clearEmbeddingCache(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Get cache stats for debugging/dashboard.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getEmbeddingCacheStats(): {
|
|
29
|
+
size: number;
|
|
30
|
+
maxSize: number;
|
|
31
|
+
};
|
|
32
|
+
//# sourceMappingURL=embedding-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding-cache.d.ts","sourceRoot":"","sources":["../../src/memory/embedding-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAuBH;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,CAQhE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAiBtE;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAE1E"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Embedding Cache — Avoids re-computing embeddings for identical text.
|
|
4
|
+
*
|
|
5
|
+
* Extracted from OpenClaw's embedding_cache table architecture.
|
|
6
|
+
*
|
|
7
|
+
* Problem: Every recall re-embeds the query, even if it's the exact same text.
|
|
8
|
+
* With MiniLM this takes ~50ms per embedding — adds up fast.
|
|
9
|
+
*
|
|
10
|
+
* Solution: Cache embeddings in memory with an LRU eviction policy.
|
|
11
|
+
* Cache key = hash of the text content.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.getCachedEmbedding = getCachedEmbedding;
|
|
15
|
+
exports.cacheEmbedding = cacheEmbedding;
|
|
16
|
+
exports.clearEmbeddingCache = clearEmbeddingCache;
|
|
17
|
+
exports.getEmbeddingCacheStats = getEmbeddingCacheStats;
|
|
18
|
+
const CACHE_MAX = 256;
|
|
19
|
+
const cache = new Map();
|
|
20
|
+
/**
|
|
21
|
+
* Simple FNV-1a hash — fast and good enough for cache keys.
|
|
22
|
+
*/
|
|
23
|
+
function hashText(text) {
|
|
24
|
+
let hash = 0x811c9dc5;
|
|
25
|
+
for (let i = 0; i < text.length; i++) {
|
|
26
|
+
hash ^= text.charCodeAt(i);
|
|
27
|
+
hash = (hash * 0x01000193) >>> 0;
|
|
28
|
+
}
|
|
29
|
+
return hash.toString(36);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get a cached embedding for text, or null if not cached.
|
|
33
|
+
*/
|
|
34
|
+
function getCachedEmbedding(text) {
|
|
35
|
+
const key = hashText(text);
|
|
36
|
+
const entry = cache.get(key);
|
|
37
|
+
if (entry) {
|
|
38
|
+
entry.timestamp = Date.now(); // Touch for LRU
|
|
39
|
+
return entry.embedding;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Store an embedding in the cache.
|
|
45
|
+
* Uses LRU eviction when cache is full.
|
|
46
|
+
*/
|
|
47
|
+
function cacheEmbedding(text, embedding) {
|
|
48
|
+
const key = hashText(text);
|
|
49
|
+
// LRU eviction if full
|
|
50
|
+
if (cache.size >= CACHE_MAX && !cache.has(key)) {
|
|
51
|
+
let oldestKey = '';
|
|
52
|
+
let oldestTime = Infinity;
|
|
53
|
+
for (const [k, v] of cache) {
|
|
54
|
+
if (v.timestamp < oldestTime) {
|
|
55
|
+
oldestTime = v.timestamp;
|
|
56
|
+
oldestKey = k;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (oldestKey)
|
|
60
|
+
cache.delete(oldestKey);
|
|
61
|
+
}
|
|
62
|
+
cache.set(key, { embedding, timestamp: Date.now() });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Clear the entire embedding cache.
|
|
66
|
+
*/
|
|
67
|
+
function clearEmbeddingCache() {
|
|
68
|
+
cache.clear();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get cache stats for debugging/dashboard.
|
|
72
|
+
*/
|
|
73
|
+
function getEmbeddingCacheStats() {
|
|
74
|
+
return { size: cache.size, maxSize: CACHE_MAX };
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=embedding-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding-cache.js","sourceRoot":"","sources":["../../src/memory/embedding-cache.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AA0BH,gDAQC;AAMD,wCAiBC;AAKD,kDAEC;AAKD,wDAEC;AArED,MAAM,SAAS,GAAG,GAAG,CAAC;AAOtB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;AAE5C;;GAEG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC1B,IAAI,IAAI,GAAG,UAAU,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC3B,IAAI,GAAG,CAAC,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,SAAgB,kBAAkB,CAAC,IAAY;IAC3C,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC3B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,IAAI,KAAK,EAAE,CAAC;QACR,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,gBAAgB;QAC9C,OAAO,KAAK,CAAC,SAAS,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,SAAgB,cAAc,CAAC,IAAY,EAAE,SAAmB;IAC5D,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAE3B,uBAAuB;IACvB,IAAI,KAAK,CAAC,IAAI,IAAI,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,IAAI,UAAU,GAAG,QAAQ,CAAC;QAC1B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,CAAC,SAAS,GAAG,UAAU,EAAE,CAAC;gBAC3B,UAAU,GAAG,CAAC,CAAC,SAAS,CAAC;gBACzB,SAAS,GAAG,CAAC,CAAC;YAClB,CAAC;QACL,CAAC;QACD,IAAI,SAAS;YAAE,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,SAAgB,mBAAmB;IAC/B,KAAK,CAAC,KAAK,EAAE,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,SAAgB,sBAAsB;IAClC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AACpD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-decay.d.ts","sourceRoot":"","sources":["../../src/memory/memory-decay.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKjD,wBAAgB,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"memory-decay.d.ts","sourceRoot":"","sources":["../../src/memory/memory-decay.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAKjD,wBAAgB,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,CAgH9D"}
|