superlocalmemory 3.3.29 → 3.4.1
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/ATTRIBUTION.md +1 -1
- package/CHANGELOG.md +3 -0
- package/LICENSE +633 -70
- package/README.md +14 -11
- package/docs/screenshots/01-dashboard-main.png +0 -0
- package/docs/screenshots/02-knowledge-graph.png +0 -0
- package/docs/screenshots/03-patterns-learning.png +0 -0
- package/docs/screenshots/04-learning-dashboard.png +0 -0
- package/docs/screenshots/05-behavioral-analysis.png +0 -0
- package/docs/screenshots/06-graph-communities.png +0 -0
- package/docs/v2-archive/ACCESSIBILITY.md +1 -1
- package/docs/v2-archive/FRAMEWORK-INTEGRATIONS.md +1 -1
- package/docs/v2-archive/MCP-MANUAL-SETUP.md +1 -1
- package/docs/v2-archive/SEARCH-ENGINE-V2.2.0.md +2 -2
- package/docs/v2-archive/SEARCH-INTEGRATION-GUIDE.md +1 -1
- package/docs/v2-archive/UNIVERSAL-INTEGRATION.md +1 -1
- package/docs/v2-archive/V2.2.0-OPTIONAL-SEARCH.md +1 -1
- package/docs/v2-archive/example_graph_usage.py +1 -1
- package/ide/configs/codex-mcp.toml +1 -1
- package/ide/integrations/langchain/README.md +1 -1
- package/ide/integrations/langchain/langchain_superlocalmemory/__init__.py +1 -1
- package/ide/integrations/langchain/langchain_superlocalmemory/chat_message_history.py +1 -1
- package/ide/integrations/langchain/pyproject.toml +2 -2
- package/ide/integrations/langchain/tests/__init__.py +1 -1
- package/ide/integrations/langchain/tests/test_chat_message_history.py +1 -1
- package/ide/integrations/langchain/tests/test_security.py +1 -1
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/__init__.py +1 -1
- package/ide/integrations/llamaindex/llama_index/storage/chat_store/superlocalmemory/base.py +1 -1
- package/ide/integrations/llamaindex/pyproject.toml +2 -2
- package/ide/integrations/llamaindex/tests/__init__.py +1 -1
- package/ide/integrations/llamaindex/tests/test_chat_store.py +1 -1
- package/ide/integrations/llamaindex/tests/test_security.py +1 -1
- package/ide/skills/slm-build-graph/SKILL.md +3 -3
- package/ide/skills/slm-list-recent/SKILL.md +3 -3
- package/ide/skills/slm-recall/SKILL.md +3 -3
- package/ide/skills/slm-remember/SKILL.md +3 -3
- package/ide/skills/slm-show-patterns/SKILL.md +3 -3
- package/ide/skills/slm-status/SKILL.md +3 -3
- package/ide/skills/slm-switch-profile/SKILL.md +3 -3
- package/package.json +3 -3
- package/pyproject.toml +3 -3
- package/src/superlocalmemory/core/engine_wiring.py +5 -1
- package/src/superlocalmemory/core/graph_analyzer.py +254 -12
- package/src/superlocalmemory/learning/consolidation_worker.py +240 -52
- package/src/superlocalmemory/retrieval/entity_channel.py +135 -4
- package/src/superlocalmemory/retrieval/spreading_activation.py +45 -0
- package/src/superlocalmemory/server/api.py +9 -1
- package/src/superlocalmemory/server/routes/behavioral.py +8 -4
- package/src/superlocalmemory/server/routes/chat.py +320 -0
- package/src/superlocalmemory/server/routes/insights.py +368 -0
- package/src/superlocalmemory/server/routes/learning.py +106 -6
- package/src/superlocalmemory/server/routes/memories.py +20 -9
- package/src/superlocalmemory/server/routes/stats.py +25 -3
- package/src/superlocalmemory/server/routes/timeline.py +252 -0
- package/src/superlocalmemory/server/routes/v3_api.py +161 -0
- package/src/superlocalmemory/server/ui.py +8 -0
- package/src/superlocalmemory/ui/index.html +168 -58
- package/src/superlocalmemory/ui/js/graph-event-bus.js +83 -0
- package/src/superlocalmemory/ui/js/graph-filters.js +1 -1
- package/src/superlocalmemory/ui/js/knowledge-graph.js +942 -0
- package/src/superlocalmemory/ui/js/memory-chat.js +344 -0
- package/src/superlocalmemory/ui/js/memory-timeline.js +265 -0
- package/src/superlocalmemory/ui/js/quick-actions.js +334 -0
- package/src/superlocalmemory.egg-info/PKG-INFO +597 -0
- package/src/superlocalmemory.egg-info/SOURCES.txt +287 -0
- package/src/superlocalmemory.egg-info/dependency_links.txt +1 -0
- package/src/superlocalmemory.egg-info/entry_points.txt +2 -0
- package/src/superlocalmemory.egg-info/requires.txt +47 -0
- package/src/superlocalmemory.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
// SuperLocalMemory v3.4.1 — Quick Insight Actions
|
|
2
|
+
// Copyright (c) 2026 Varun Pratap Bhardwaj — AGPL-3.0-or-later
|
|
3
|
+
// 5 one-click intelligence buttons. Safe DOM construction (HR-08).
|
|
4
|
+
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// INIT
|
|
7
|
+
// ============================================================================
|
|
8
|
+
|
|
9
|
+
function initQuickActions() {
|
|
10
|
+
var buttons = document.querySelectorAll('[data-insight-action]');
|
|
11
|
+
buttons.forEach(function(btn) {
|
|
12
|
+
btn.addEventListener('click', function() {
|
|
13
|
+
var action = btn.getAttribute('data-insight-action');
|
|
14
|
+
fetchInsight(action);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// FETCH + DISPATCH
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
function fetchInsight(actionName) {
|
|
24
|
+
var resultsDiv = document.getElementById('insight-results');
|
|
25
|
+
if (!resultsDiv) return;
|
|
26
|
+
|
|
27
|
+
// Show loading
|
|
28
|
+
resultsDiv.innerHTML = '';
|
|
29
|
+
var spinner = document.createElement('div');
|
|
30
|
+
spinner.className = 'text-center py-3';
|
|
31
|
+
spinner.innerHTML = '<div class="spinner-border spinner-border-sm text-primary"></div> Loading...';
|
|
32
|
+
resultsDiv.appendChild(spinner);
|
|
33
|
+
|
|
34
|
+
// Highlight active button
|
|
35
|
+
document.querySelectorAll('[data-insight-action]').forEach(function(b) {
|
|
36
|
+
b.classList.remove('active');
|
|
37
|
+
});
|
|
38
|
+
var activeBtn = document.querySelector('[data-insight-action="' + actionName + '"]');
|
|
39
|
+
if (activeBtn) activeBtn.classList.add('active');
|
|
40
|
+
|
|
41
|
+
fetch('/api/v3/insights/' + actionName)
|
|
42
|
+
.then(function(r) {
|
|
43
|
+
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
44
|
+
return r.json();
|
|
45
|
+
})
|
|
46
|
+
.then(function(data) {
|
|
47
|
+
resultsDiv.innerHTML = '';
|
|
48
|
+
renderInsightResult(actionName, data, resultsDiv);
|
|
49
|
+
})
|
|
50
|
+
.catch(function(e) {
|
|
51
|
+
resultsDiv.innerHTML = '';
|
|
52
|
+
var alert = document.createElement('div');
|
|
53
|
+
alert.className = 'alert alert-danger small';
|
|
54
|
+
alert.textContent = 'Failed to fetch insights: ' + e.message;
|
|
55
|
+
resultsDiv.appendChild(alert);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function renderInsightResult(action, data, container) {
|
|
60
|
+
if (data.count === 0 && action !== 'health') {
|
|
61
|
+
var empty = document.createElement('div');
|
|
62
|
+
empty.className = 'text-muted small py-2';
|
|
63
|
+
empty.textContent = 'No results for "' + action.replace(/_/g, ' ') + '".';
|
|
64
|
+
container.appendChild(empty);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Header with close button
|
|
69
|
+
var header = document.createElement('div');
|
|
70
|
+
header.className = 'd-flex justify-content-between align-items-center mb-2';
|
|
71
|
+
var title = document.createElement('strong');
|
|
72
|
+
title.className = 'small';
|
|
73
|
+
title.textContent = formatActionName(action) + ' (' + data.count + ')';
|
|
74
|
+
header.appendChild(title);
|
|
75
|
+
var closeBtn = document.createElement('button');
|
|
76
|
+
closeBtn.className = 'btn-close btn-close-sm';
|
|
77
|
+
closeBtn.setAttribute('aria-label', 'Close');
|
|
78
|
+
closeBtn.addEventListener('click', clearInsightResults);
|
|
79
|
+
header.appendChild(closeBtn);
|
|
80
|
+
container.appendChild(header);
|
|
81
|
+
|
|
82
|
+
var renderers = {
|
|
83
|
+
changed_this_week: renderChangedThisWeek,
|
|
84
|
+
opinions: renderOpinions,
|
|
85
|
+
contradictions: renderContradictions,
|
|
86
|
+
health: renderHealth,
|
|
87
|
+
cross_project: renderCrossProject,
|
|
88
|
+
};
|
|
89
|
+
var renderer = renderers[action];
|
|
90
|
+
if (renderer) renderer(data, container);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ============================================================================
|
|
94
|
+
// RENDERERS (safe DOM — createElement/textContent only, no innerHTML)
|
|
95
|
+
// ============================================================================
|
|
96
|
+
|
|
97
|
+
function renderChangedThisWeek(data, container) {
|
|
98
|
+
var nodeIds = [];
|
|
99
|
+
(data.items || []).forEach(function(item) {
|
|
100
|
+
var card = document.createElement('div');
|
|
101
|
+
card.className = 'border rounded p-2 mb-1';
|
|
102
|
+
card.style.fontSize = '0.78rem';
|
|
103
|
+
|
|
104
|
+
var badge = document.createElement('span');
|
|
105
|
+
badge.className = 'badge bg-info me-1';
|
|
106
|
+
badge.textContent = item.fact_type || 'fact';
|
|
107
|
+
card.appendChild(badge);
|
|
108
|
+
|
|
109
|
+
var content = document.createElement('span');
|
|
110
|
+
content.textContent = item.content;
|
|
111
|
+
card.appendChild(content);
|
|
112
|
+
|
|
113
|
+
var ts = document.createElement('div');
|
|
114
|
+
ts.className = 'text-muted mt-1';
|
|
115
|
+
ts.style.fontSize = '0.7rem';
|
|
116
|
+
ts.textContent = formatTimestamp(item.created_at);
|
|
117
|
+
card.appendChild(ts);
|
|
118
|
+
|
|
119
|
+
container.appendChild(card);
|
|
120
|
+
if (item.fact_id) nodeIds.push(item.fact_id);
|
|
121
|
+
});
|
|
122
|
+
highlightNodesInGraph(nodeIds);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function renderOpinions(data, container) {
|
|
126
|
+
var nodeIds = [];
|
|
127
|
+
(data.items || []).forEach(function(item) {
|
|
128
|
+
var card = document.createElement('div');
|
|
129
|
+
card.className = 'border-start border-3 border-warning p-2 mb-1';
|
|
130
|
+
card.style.fontSize = '0.78rem';
|
|
131
|
+
|
|
132
|
+
var conf = document.createElement('span');
|
|
133
|
+
conf.className = 'badge bg-warning text-dark me-1';
|
|
134
|
+
conf.textContent = (item.confidence * 100).toFixed(0) + '%';
|
|
135
|
+
card.appendChild(conf);
|
|
136
|
+
|
|
137
|
+
var content = document.createElement('span');
|
|
138
|
+
content.textContent = item.content;
|
|
139
|
+
card.appendChild(content);
|
|
140
|
+
|
|
141
|
+
var ts = document.createElement('div');
|
|
142
|
+
ts.className = 'text-muted mt-1';
|
|
143
|
+
ts.style.fontSize = '0.7rem';
|
|
144
|
+
ts.textContent = formatTimestamp(item.created_at);
|
|
145
|
+
card.appendChild(ts);
|
|
146
|
+
|
|
147
|
+
container.appendChild(card);
|
|
148
|
+
if (item.fact_id) nodeIds.push(item.fact_id);
|
|
149
|
+
});
|
|
150
|
+
highlightNodesInGraph(nodeIds);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function renderContradictions(data, container) {
|
|
154
|
+
var nodeIds = [];
|
|
155
|
+
(data.items || []).forEach(function(item) {
|
|
156
|
+
var card = document.createElement('div');
|
|
157
|
+
card.className = 'alert alert-warning d-flex align-items-start mb-2 py-2';
|
|
158
|
+
|
|
159
|
+
var badge = document.createElement('span');
|
|
160
|
+
badge.className = 'badge bg-danger me-2';
|
|
161
|
+
badge.textContent = (item.severity * 100).toFixed(0) + '%';
|
|
162
|
+
card.appendChild(badge);
|
|
163
|
+
|
|
164
|
+
var body = document.createElement('div');
|
|
165
|
+
body.style.fontSize = '0.78rem';
|
|
166
|
+
|
|
167
|
+
var src = document.createElement('div');
|
|
168
|
+
src.textContent = item.source_content;
|
|
169
|
+
body.appendChild(src);
|
|
170
|
+
|
|
171
|
+
var vs = document.createElement('strong');
|
|
172
|
+
vs.className = 'text-danger';
|
|
173
|
+
vs.textContent = ' vs ';
|
|
174
|
+
body.appendChild(vs);
|
|
175
|
+
|
|
176
|
+
var tgt = document.createElement('div');
|
|
177
|
+
tgt.textContent = item.target_content;
|
|
178
|
+
body.appendChild(tgt);
|
|
179
|
+
|
|
180
|
+
card.appendChild(body);
|
|
181
|
+
container.appendChild(card);
|
|
182
|
+
|
|
183
|
+
if (item.source_id) nodeIds.push(item.source_id);
|
|
184
|
+
if (item.target_id) nodeIds.push(item.target_id);
|
|
185
|
+
});
|
|
186
|
+
highlightNodesInGraph(nodeIds);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function renderHealth(data, container) {
|
|
190
|
+
var health = (data.items && data.items[0]) || {};
|
|
191
|
+
|
|
192
|
+
// Trust section
|
|
193
|
+
var trust = health.trust || {};
|
|
194
|
+
var trustCard = document.createElement('div');
|
|
195
|
+
trustCard.className = 'border rounded p-2 mb-2';
|
|
196
|
+
var trustTitle = document.createElement('strong');
|
|
197
|
+
trustTitle.className = 'small';
|
|
198
|
+
trustTitle.textContent = 'Trust Distribution';
|
|
199
|
+
trustCard.appendChild(trustTitle);
|
|
200
|
+
['high', 'medium', 'low'].forEach(function(level) {
|
|
201
|
+
var row = document.createElement('div');
|
|
202
|
+
row.className = 'd-flex justify-content-between small';
|
|
203
|
+
var label = document.createElement('span');
|
|
204
|
+
label.textContent = level.charAt(0).toUpperCase() + level.slice(1);
|
|
205
|
+
row.appendChild(label);
|
|
206
|
+
var val = document.createElement('span');
|
|
207
|
+
val.className = 'text-muted';
|
|
208
|
+
val.textContent = trust[level] || 0;
|
|
209
|
+
row.appendChild(val);
|
|
210
|
+
trustCard.appendChild(row);
|
|
211
|
+
});
|
|
212
|
+
container.appendChild(trustCard);
|
|
213
|
+
|
|
214
|
+
// Retention zones
|
|
215
|
+
var zones = health.retention_zones;
|
|
216
|
+
if (zones) {
|
|
217
|
+
var retCard = document.createElement('div');
|
|
218
|
+
retCard.className = 'border rounded p-2 mb-2';
|
|
219
|
+
var retTitle = document.createElement('strong');
|
|
220
|
+
retTitle.className = 'small';
|
|
221
|
+
retTitle.textContent = 'Retention Zones';
|
|
222
|
+
retCard.appendChild(retTitle);
|
|
223
|
+
Object.keys(zones).forEach(function(zone) {
|
|
224
|
+
var row = document.createElement('div');
|
|
225
|
+
row.className = 'd-flex justify-content-between small';
|
|
226
|
+
var label = document.createElement('span');
|
|
227
|
+
label.textContent = zone;
|
|
228
|
+
row.appendChild(label);
|
|
229
|
+
var val = document.createElement('span');
|
|
230
|
+
val.className = 'text-muted';
|
|
231
|
+
val.textContent = zones[zone].count + ' (' + (zones[zone].avg_retention * 100).toFixed(0) + '%)';
|
|
232
|
+
row.appendChild(val);
|
|
233
|
+
retCard.appendChild(row);
|
|
234
|
+
});
|
|
235
|
+
container.appendChild(retCard);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Totals
|
|
239
|
+
var totals = health.totals || {};
|
|
240
|
+
var totCard = document.createElement('div');
|
|
241
|
+
totCard.className = 'border rounded p-2 mb-2';
|
|
242
|
+
var totTitle = document.createElement('strong');
|
|
243
|
+
totTitle.className = 'small';
|
|
244
|
+
totTitle.textContent = 'Memory Totals';
|
|
245
|
+
totCard.appendChild(totTitle);
|
|
246
|
+
[['Facts', totals.facts], ['Entities', totals.entities], ['Edges', totals.edges], ['Communities', health.community_count || 0]].forEach(function(pair) {
|
|
247
|
+
var row = document.createElement('div');
|
|
248
|
+
row.className = 'd-flex justify-content-between small';
|
|
249
|
+
var label = document.createElement('span');
|
|
250
|
+
label.textContent = pair[0];
|
|
251
|
+
row.appendChild(label);
|
|
252
|
+
var val = document.createElement('span');
|
|
253
|
+
val.className = 'text-muted';
|
|
254
|
+
val.textContent = pair[1] || 0;
|
|
255
|
+
row.appendChild(val);
|
|
256
|
+
totCard.appendChild(row);
|
|
257
|
+
});
|
|
258
|
+
container.appendChild(totCard);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function renderCrossProject(data, container) {
|
|
262
|
+
(data.items || []).forEach(function(item) {
|
|
263
|
+
var card = document.createElement('div');
|
|
264
|
+
card.className = 'border rounded p-2 mb-1';
|
|
265
|
+
card.style.fontSize = '0.78rem';
|
|
266
|
+
|
|
267
|
+
var name = document.createElement('strong');
|
|
268
|
+
name.textContent = item.canonical_name;
|
|
269
|
+
card.appendChild(name);
|
|
270
|
+
|
|
271
|
+
var badge = document.createElement('span');
|
|
272
|
+
badge.className = 'badge bg-primary ms-1';
|
|
273
|
+
badge.textContent = item.session_count + ' sessions';
|
|
274
|
+
card.appendChild(badge);
|
|
275
|
+
|
|
276
|
+
var detail = document.createElement('div');
|
|
277
|
+
detail.className = 'text-muted mt-1';
|
|
278
|
+
detail.style.fontSize = '0.7rem';
|
|
279
|
+
detail.textContent = (item.entity_type || 'entity') + ' — ' + item.fact_count + ' facts';
|
|
280
|
+
card.appendChild(detail);
|
|
281
|
+
|
|
282
|
+
container.appendChild(card);
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ============================================================================
|
|
287
|
+
// EVENT BUS INTEGRATION (fire-and-forget — Phase 3 adds listener)
|
|
288
|
+
// ============================================================================
|
|
289
|
+
|
|
290
|
+
function highlightNodesInGraph(nodeIds) {
|
|
291
|
+
if (!nodeIds || nodeIds.length === 0) return;
|
|
292
|
+
window.dispatchEvent(new CustomEvent('slm:graph:highlight', {
|
|
293
|
+
detail: { nodeIds: nodeIds },
|
|
294
|
+
}));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function clearInsightResults() {
|
|
298
|
+
var resultsDiv = document.getElementById('insight-results');
|
|
299
|
+
if (resultsDiv) resultsDiv.innerHTML = '';
|
|
300
|
+
// Clear button active state
|
|
301
|
+
document.querySelectorAll('[data-insight-action]').forEach(function(b) {
|
|
302
|
+
b.classList.remove('active');
|
|
303
|
+
});
|
|
304
|
+
// Clear graph highlights
|
|
305
|
+
window.dispatchEvent(new CustomEvent('slm:graph:clearHighlight', { detail: {} }));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ============================================================================
|
|
309
|
+
// HELPERS
|
|
310
|
+
// ============================================================================
|
|
311
|
+
|
|
312
|
+
function formatActionName(action) {
|
|
313
|
+
return action.replace(/_/g, ' ').replace(/\b\w/g, function(c) { return c.toUpperCase(); });
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function formatTimestamp(ts) {
|
|
317
|
+
if (!ts) return '';
|
|
318
|
+
try {
|
|
319
|
+
var d = new Date(ts);
|
|
320
|
+
return d.toLocaleDateString() + ' ' + d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
321
|
+
} catch (_) {
|
|
322
|
+
return ts;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ============================================================================
|
|
327
|
+
// AUTO-INIT
|
|
328
|
+
// ============================================================================
|
|
329
|
+
|
|
330
|
+
if (document.readyState === 'loading') {
|
|
331
|
+
document.addEventListener('DOMContentLoaded', initQuickActions);
|
|
332
|
+
} else {
|
|
333
|
+
initQuickActions();
|
|
334
|
+
}
|