superlocalmemory 3.4.17 → 3.4.18
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/CHANGELOG.md +8 -0
- package/package.json +1 -3
- package/pyproject.toml +10 -1
- package/src/superlocalmemory/cli/setup_wizard.py +30 -0
- package/src/superlocalmemory.egg-info/PKG-INFO +4 -1
- package/src/superlocalmemory.egg-info/requires.txt +3 -0
- package/docs/ARCHITECTURE.md +0 -149
- package/docs/api-reference.md +0 -284
- package/docs/auto-memory.md +0 -150
- package/docs/cli-reference.md +0 -327
- package/docs/cloud-backup.md +0 -174
- package/docs/compliance.md +0 -191
- package/docs/configuration.md +0 -182
- package/docs/getting-started.md +0 -102
- package/docs/ide-setup.md +0 -261
- package/docs/mcp-tools.md +0 -220
- package/docs/migration-from-v2.md +0 -170
- package/docs/profiles.md +0 -173
- package/docs/screenshots/01-dashboard-main.png +0 -0
- package/docs/screenshots/02-knowledge-graph.png +0 -0
- package/docs/screenshots/03-math-health.png +0 -0
- package/docs/screenshots/03-patterns-learning.png +0 -0
- package/docs/screenshots/04-learning-dashboard.png +0 -0
- package/docs/screenshots/04-recall-lab.png +0 -0
- package/docs/screenshots/05-behavioral-analysis.png +0 -0
- package/docs/screenshots/05-trust-dashboard.png +0 -0
- package/docs/screenshots/06-graph-communities.png +0 -0
- package/docs/screenshots/06-settings.png +0 -0
- package/docs/screenshots/07-memories-blurred.png +0 -0
- package/docs/skill-evolution.md +0 -256
- package/docs/troubleshooting.md +0 -310
- package/docs/v2-archive/ACCESSIBILITY.md +0 -291
- package/docs/v2-archive/ARCHITECTURE.md +0 -886
- package/docs/v2-archive/CLI-COMMANDS-REFERENCE.md +0 -425
- package/docs/v2-archive/COMPRESSION-README.md +0 -390
- package/docs/v2-archive/FRAMEWORK-INTEGRATIONS.md +0 -300
- package/docs/v2-archive/MCP-MANUAL-SETUP.md +0 -775
- package/docs/v2-archive/MCP-TROUBLESHOOTING.md +0 -787
- package/docs/v2-archive/PATTERN-LEARNING.md +0 -228
- package/docs/v2-archive/PROFILES-GUIDE.md +0 -453
- package/docs/v2-archive/RESET-GUIDE.md +0 -353
- package/docs/v2-archive/SEARCH-ENGINE-V2.2.0.md +0 -749
- package/docs/v2-archive/SEARCH-INTEGRATION-GUIDE.md +0 -502
- package/docs/v2-archive/UI-SERVER.md +0 -262
- package/docs/v2-archive/UNIVERSAL-INTEGRATION.md +0 -488
- package/docs/v2-archive/V2.2.0-OPTIONAL-SEARCH.md +0 -666
- package/docs/v2-archive/WINDOWS-INSTALL-README.txt +0 -34
- package/docs/v2-archive/WINDOWS-POST-INSTALL.txt +0 -45
- package/docs/v2-archive/example_graph_usage.py +0 -146
- package/ui/index.html +0 -1879
- package/ui/js/agents.js +0 -192
- package/ui/js/auto-settings.js +0 -399
- package/ui/js/behavioral.js +0 -276
- package/ui/js/clusters.js +0 -206
- package/ui/js/compliance.js +0 -252
- package/ui/js/core.js +0 -246
- package/ui/js/dashboard.js +0 -110
- package/ui/js/events.js +0 -178
- package/ui/js/fact-detail.js +0 -92
- package/ui/js/feedback.js +0 -333
- package/ui/js/graph-core.js +0 -447
- package/ui/js/graph-filters.js +0 -220
- package/ui/js/graph-interactions.js +0 -351
- package/ui/js/graph-ui.js +0 -214
- package/ui/js/ide-status.js +0 -102
- package/ui/js/init.js +0 -45
- package/ui/js/learning.js +0 -435
- package/ui/js/lifecycle.js +0 -298
- package/ui/js/math-health.js +0 -98
- package/ui/js/memories.js +0 -264
- package/ui/js/modal.js +0 -357
- package/ui/js/patterns.js +0 -93
- package/ui/js/profiles.js +0 -236
- package/ui/js/recall-lab.js +0 -292
- package/ui/js/search.js +0 -59
- package/ui/js/settings.js +0 -224
- package/ui/js/timeline.js +0 -32
- package/ui/js/trust-dashboard.js +0 -73
package/ui/js/behavioral.js
DELETED
|
@@ -1,276 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: Elastic-2.0
|
|
2
|
-
// Copyright (c) 2026 SuperLocalMemory (superlocalmemory.com)
|
|
3
|
-
// Behavioral Learning tab — outcomes, patterns, cross-project transfers (v2.8)
|
|
4
|
-
// NOTE: All dynamic values use textContent or escapeHtml() from core.js before DOM insertion.
|
|
5
|
-
|
|
6
|
-
var _behavioralData = null;
|
|
7
|
-
|
|
8
|
-
async function loadBehavioral() {
|
|
9
|
-
try {
|
|
10
|
-
var response = await fetch('/api/behavioral/status');
|
|
11
|
-
var data = await response.json();
|
|
12
|
-
_behavioralData = data;
|
|
13
|
-
|
|
14
|
-
if (!data.available) {
|
|
15
|
-
showEmpty('behavioral-patterns-content', 'lightbulb', 'Behavioral learning not available. Upgrade to v2.8.');
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
renderBehavioralStats(data);
|
|
20
|
-
renderBehavioralPatterns(data);
|
|
21
|
-
renderBehavioralTransfers(data);
|
|
22
|
-
renderBehavioralOutcomes(data);
|
|
23
|
-
|
|
24
|
-
var badge = document.getElementById('behavioral-profile-badge');
|
|
25
|
-
if (badge) badge.textContent = data.active_profile || 'default';
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.error('Error loading behavioral:', error);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function renderBehavioralStats(data) {
|
|
32
|
-
var stats = data.stats || {};
|
|
33
|
-
animateCounter('bh-success-count', stats.success_count || 0);
|
|
34
|
-
animateCounter('bh-failure-count', stats.failure_count || 0);
|
|
35
|
-
animateCounter('bh-partial-count', stats.partial_count || 0);
|
|
36
|
-
animateCounter('bh-patterns-count', stats.patterns_count || 0);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function renderBehavioralPatterns(data) {
|
|
40
|
-
var container = document.getElementById('behavioral-patterns-content');
|
|
41
|
-
if (!container) return;
|
|
42
|
-
var patterns = data.patterns || [];
|
|
43
|
-
container.textContent = '';
|
|
44
|
-
|
|
45
|
-
if (patterns.length === 0) {
|
|
46
|
-
var empty = document.createElement('div');
|
|
47
|
-
empty.className = 'text-center text-muted py-3';
|
|
48
|
-
empty.textContent = 'No patterns learned yet. Report outcomes to start learning.';
|
|
49
|
-
container.appendChild(empty);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
for (var i = 0; i < patterns.length; i++) {
|
|
54
|
-
var p = patterns[i];
|
|
55
|
-
var successRate = Math.round((p.success_rate || 0) * 100);
|
|
56
|
-
var confPct = Math.round((p.confidence || 0) * 100);
|
|
57
|
-
var barColor = successRate >= 70 ? 'bg-success' : (successRate >= 40 ? 'bg-warning' : 'bg-danger');
|
|
58
|
-
|
|
59
|
-
var row = document.createElement('div');
|
|
60
|
-
row.className = 'd-flex align-items-center mb-2';
|
|
61
|
-
|
|
62
|
-
// Pattern key label
|
|
63
|
-
var label = document.createElement('div');
|
|
64
|
-
label.style.minWidth = '140px';
|
|
65
|
-
var labelCode = document.createElement('code');
|
|
66
|
-
labelCode.className = 'small';
|
|
67
|
-
labelCode.textContent = p.pattern_key || '';
|
|
68
|
-
label.appendChild(labelCode);
|
|
69
|
-
|
|
70
|
-
// Success rate progress bar
|
|
71
|
-
var barWrap = document.createElement('div');
|
|
72
|
-
barWrap.className = 'flex-grow-1 mx-2';
|
|
73
|
-
var progress = document.createElement('div');
|
|
74
|
-
progress.className = 'progress';
|
|
75
|
-
progress.style.height = '20px';
|
|
76
|
-
progress.style.borderRadius = '10px';
|
|
77
|
-
var barEl = document.createElement('div');
|
|
78
|
-
barEl.className = 'progress-bar ' + barColor;
|
|
79
|
-
barEl.style.width = successRate + '%';
|
|
80
|
-
barEl.style.borderRadius = '10px';
|
|
81
|
-
barEl.style.fontSize = '0.7rem';
|
|
82
|
-
barEl.textContent = successRate + '% success';
|
|
83
|
-
progress.appendChild(barEl);
|
|
84
|
-
barWrap.appendChild(progress);
|
|
85
|
-
|
|
86
|
-
// Evidence count
|
|
87
|
-
var evidence = document.createElement('small');
|
|
88
|
-
evidence.className = 'text-muted';
|
|
89
|
-
evidence.style.minWidth = '50px';
|
|
90
|
-
evidence.style.textAlign = 'right';
|
|
91
|
-
evidence.textContent = (p.evidence_count || 0) + ' ev.';
|
|
92
|
-
|
|
93
|
-
// Confidence badge
|
|
94
|
-
var confBadge = document.createElement('span');
|
|
95
|
-
confBadge.className = 'badge ms-2 ' + (confPct >= 70 ? 'bg-success' : (confPct >= 40 ? 'bg-warning' : 'bg-secondary'));
|
|
96
|
-
confBadge.style.minWidth = '50px';
|
|
97
|
-
confBadge.textContent = confPct + '%';
|
|
98
|
-
|
|
99
|
-
row.appendChild(label);
|
|
100
|
-
row.appendChild(barWrap);
|
|
101
|
-
row.appendChild(evidence);
|
|
102
|
-
row.appendChild(confBadge);
|
|
103
|
-
container.appendChild(row);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function renderBehavioralTransfers(data) {
|
|
108
|
-
var container = document.getElementById('behavioral-transfers-content');
|
|
109
|
-
if (!container) return;
|
|
110
|
-
var transfers = data.transfers || [];
|
|
111
|
-
container.textContent = '';
|
|
112
|
-
|
|
113
|
-
if (transfers.length === 0) {
|
|
114
|
-
var empty = document.createElement('div');
|
|
115
|
-
empty.className = 'text-center text-muted py-3';
|
|
116
|
-
empty.textContent = 'No cross-project transfers yet. Patterns transfer automatically when confidence is high.';
|
|
117
|
-
container.appendChild(empty);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
var table = document.createElement('table');
|
|
122
|
-
table.className = 'table table-sm table-hover mb-0';
|
|
123
|
-
var thead = document.createElement('thead');
|
|
124
|
-
var headRow = document.createElement('tr');
|
|
125
|
-
['Pattern', 'From Project', 'To Project', 'Confidence', 'Date'].forEach(function(h) {
|
|
126
|
-
var th = document.createElement('th');
|
|
127
|
-
th.textContent = h;
|
|
128
|
-
headRow.appendChild(th);
|
|
129
|
-
});
|
|
130
|
-
thead.appendChild(headRow);
|
|
131
|
-
table.appendChild(thead);
|
|
132
|
-
|
|
133
|
-
var tbody = document.createElement('tbody');
|
|
134
|
-
for (var i = 0; i < transfers.length; i++) {
|
|
135
|
-
var t = transfers[i];
|
|
136
|
-
var row = document.createElement('tr');
|
|
137
|
-
|
|
138
|
-
var patternCell = document.createElement('td');
|
|
139
|
-
var patternCode = document.createElement('code');
|
|
140
|
-
patternCode.className = 'small';
|
|
141
|
-
patternCode.textContent = t.pattern_key || '';
|
|
142
|
-
patternCell.appendChild(patternCode);
|
|
143
|
-
row.appendChild(patternCell);
|
|
144
|
-
|
|
145
|
-
var fromCell = document.createElement('td');
|
|
146
|
-
var fromBadge = document.createElement('span');
|
|
147
|
-
fromBadge.className = 'badge bg-secondary';
|
|
148
|
-
fromBadge.textContent = t.from_project || '';
|
|
149
|
-
fromCell.appendChild(fromBadge);
|
|
150
|
-
row.appendChild(fromCell);
|
|
151
|
-
|
|
152
|
-
var toCell = document.createElement('td');
|
|
153
|
-
var toBadge = document.createElement('span');
|
|
154
|
-
toBadge.className = 'badge bg-primary';
|
|
155
|
-
toBadge.textContent = t.to_project || '';
|
|
156
|
-
toCell.appendChild(toBadge);
|
|
157
|
-
row.appendChild(toCell);
|
|
158
|
-
|
|
159
|
-
var confCell = document.createElement('td');
|
|
160
|
-
confCell.textContent = Math.round((t.confidence || 0) * 100) + '%';
|
|
161
|
-
row.appendChild(confCell);
|
|
162
|
-
|
|
163
|
-
var dateCell = document.createElement('td');
|
|
164
|
-
dateCell.className = 'small text-muted';
|
|
165
|
-
dateCell.textContent = formatDate(t.transferred_at || '');
|
|
166
|
-
row.appendChild(dateCell);
|
|
167
|
-
|
|
168
|
-
tbody.appendChild(row);
|
|
169
|
-
}
|
|
170
|
-
table.appendChild(tbody);
|
|
171
|
-
container.appendChild(table);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function renderBehavioralOutcomes(data) {
|
|
175
|
-
var container = document.getElementById('behavioral-outcomes-content');
|
|
176
|
-
if (!container) return;
|
|
177
|
-
var outcomes = data.recent_outcomes || [];
|
|
178
|
-
container.textContent = '';
|
|
179
|
-
|
|
180
|
-
if (outcomes.length === 0) {
|
|
181
|
-
var empty = document.createElement('div');
|
|
182
|
-
empty.className = 'text-center text-muted py-3';
|
|
183
|
-
empty.textContent = 'No outcomes recorded yet. Use the form above or the report_outcome MCP tool.';
|
|
184
|
-
container.appendChild(empty);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
var table = document.createElement('table');
|
|
189
|
-
table.className = 'table table-sm table-hover mb-0';
|
|
190
|
-
var thead = document.createElement('thead');
|
|
191
|
-
var headRow = document.createElement('tr');
|
|
192
|
-
['Memory IDs', 'Outcome', 'Action Type', 'Date'].forEach(function(h) {
|
|
193
|
-
var th = document.createElement('th');
|
|
194
|
-
th.textContent = h;
|
|
195
|
-
headRow.appendChild(th);
|
|
196
|
-
});
|
|
197
|
-
thead.appendChild(headRow);
|
|
198
|
-
table.appendChild(thead);
|
|
199
|
-
|
|
200
|
-
var outcomeBadgeColors = {
|
|
201
|
-
success: 'bg-success',
|
|
202
|
-
failure: 'bg-danger',
|
|
203
|
-
partial: 'bg-warning'
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
var tbody = document.createElement('tbody');
|
|
207
|
-
for (var i = 0; i < outcomes.length; i++) {
|
|
208
|
-
var o = outcomes[i];
|
|
209
|
-
var row = document.createElement('tr');
|
|
210
|
-
|
|
211
|
-
var idsCell = document.createElement('td');
|
|
212
|
-
var memIds = o.memory_ids || [];
|
|
213
|
-
idsCell.textContent = memIds.join(', ');
|
|
214
|
-
row.appendChild(idsCell);
|
|
215
|
-
|
|
216
|
-
var outcomeCell = document.createElement('td');
|
|
217
|
-
var outBadge = document.createElement('span');
|
|
218
|
-
outBadge.className = 'badge ' + (outcomeBadgeColors[o.outcome] || 'bg-secondary');
|
|
219
|
-
outBadge.textContent = o.outcome || '';
|
|
220
|
-
outcomeCell.appendChild(outBadge);
|
|
221
|
-
row.appendChild(outcomeCell);
|
|
222
|
-
|
|
223
|
-
var actionCell = document.createElement('td');
|
|
224
|
-
actionCell.textContent = o.action_type || '';
|
|
225
|
-
row.appendChild(actionCell);
|
|
226
|
-
|
|
227
|
-
var dateCell = document.createElement('td');
|
|
228
|
-
dateCell.className = 'small text-muted';
|
|
229
|
-
dateCell.textContent = formatDate(o.created_at || '');
|
|
230
|
-
row.appendChild(dateCell);
|
|
231
|
-
|
|
232
|
-
tbody.appendChild(row);
|
|
233
|
-
}
|
|
234
|
-
table.appendChild(tbody);
|
|
235
|
-
container.appendChild(table);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
async function reportOutcome() {
|
|
239
|
-
var memIdsInput = document.getElementById('bh-memory-ids');
|
|
240
|
-
var outcomeSelect = document.getElementById('bh-outcome');
|
|
241
|
-
var actionSelect = document.getElementById('bh-action-type');
|
|
242
|
-
var contextInput = document.getElementById('bh-context');
|
|
243
|
-
|
|
244
|
-
var rawIds = (memIdsInput.value || '').trim();
|
|
245
|
-
if (!rawIds) {
|
|
246
|
-
showToast('Enter at least one memory ID.');
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
var memoryIds = rawIds.split(',').map(function(id) { return id.trim(); }).filter(function(id) { return id.length > 0; });
|
|
251
|
-
|
|
252
|
-
try {
|
|
253
|
-
var response = await fetch('/api/behavioral/report-outcome', {
|
|
254
|
-
method: 'POST',
|
|
255
|
-
headers: { 'Content-Type': 'application/json' },
|
|
256
|
-
body: JSON.stringify({
|
|
257
|
-
memory_ids: memoryIds,
|
|
258
|
-
outcome: outcomeSelect.value,
|
|
259
|
-
action_type: actionSelect.value,
|
|
260
|
-
context: contextInput.value.trim() || undefined
|
|
261
|
-
})
|
|
262
|
-
});
|
|
263
|
-
var data = await response.json();
|
|
264
|
-
if (response.ok) {
|
|
265
|
-
showToast('Outcome reported successfully.');
|
|
266
|
-
memIdsInput.value = '';
|
|
267
|
-
contextInput.value = '';
|
|
268
|
-
loadBehavioral(); // Refresh
|
|
269
|
-
} else {
|
|
270
|
-
showToast(data.detail || 'Failed to report outcome.');
|
|
271
|
-
}
|
|
272
|
-
} catch (error) {
|
|
273
|
-
console.error('Error reporting outcome:', error);
|
|
274
|
-
showToast('Error reporting outcome.');
|
|
275
|
-
}
|
|
276
|
-
}
|
package/ui/js/clusters.js
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
// SuperLocalMemory V3 - Clusters View
|
|
2
|
-
// Part of Qualixar | https://superlocalmemory.com
|
|
3
|
-
|
|
4
|
-
async function loadClusters() {
|
|
5
|
-
showLoading('clusters-list', 'Loading clusters...');
|
|
6
|
-
try {
|
|
7
|
-
var response = await fetch('/api/clusters');
|
|
8
|
-
var data = await response.json();
|
|
9
|
-
renderClusters(data.clusters);
|
|
10
|
-
} catch (error) {
|
|
11
|
-
console.error('Error loading clusters:', error);
|
|
12
|
-
showEmpty('clusters-list', 'collection', 'Failed to load clusters');
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function renderClusters(clusters) {
|
|
17
|
-
var container = document.getElementById('clusters-list');
|
|
18
|
-
if (!clusters || clusters.length === 0) {
|
|
19
|
-
showEmpty('clusters-list', 'collection', 'No clusters found yet. Clusters form automatically as you store related memories.');
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
var colors = ['#667eea', '#f093fb', '#4facfe', '#43e97b', '#fa709a', '#30cfd0', '#764ba2', '#f5576c'];
|
|
24
|
-
container.textContent = '';
|
|
25
|
-
|
|
26
|
-
clusters.forEach(function(cluster, idx) {
|
|
27
|
-
var color = colors[idx % colors.length];
|
|
28
|
-
|
|
29
|
-
var card = document.createElement('div');
|
|
30
|
-
card.className = 'card mb-2';
|
|
31
|
-
card.style.borderLeft = '4px solid ' + color;
|
|
32
|
-
|
|
33
|
-
var body = document.createElement('div');
|
|
34
|
-
body.className = 'card-body py-2 px-3';
|
|
35
|
-
body.style.cursor = 'pointer';
|
|
36
|
-
|
|
37
|
-
// Header row
|
|
38
|
-
var headerRow = document.createElement('div');
|
|
39
|
-
headerRow.className = 'd-flex justify-content-between align-items-center';
|
|
40
|
-
|
|
41
|
-
var title = document.createElement('h6');
|
|
42
|
-
title.className = 'mb-0';
|
|
43
|
-
title.textContent = 'Cluster ' + cluster.cluster_id;
|
|
44
|
-
|
|
45
|
-
var badges = document.createElement('div');
|
|
46
|
-
var countBadge = document.createElement('span');
|
|
47
|
-
countBadge.className = 'badge bg-secondary me-1';
|
|
48
|
-
countBadge.textContent = cluster.member_count + ' memories';
|
|
49
|
-
badges.appendChild(countBadge);
|
|
50
|
-
|
|
51
|
-
if (cluster.avg_importance) {
|
|
52
|
-
var impBadge = document.createElement('span');
|
|
53
|
-
impBadge.className = 'badge bg-outline-primary';
|
|
54
|
-
impBadge.style.cssText = 'border:1px solid #667eea; color:#667eea;';
|
|
55
|
-
impBadge.textContent = 'imp: ' + parseFloat(cluster.avg_importance).toFixed(1);
|
|
56
|
-
badges.appendChild(impBadge);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
var expandIcon = document.createElement('i');
|
|
60
|
-
expandIcon.className = 'bi bi-chevron-down ms-2';
|
|
61
|
-
expandIcon.style.transition = 'transform 0.2s';
|
|
62
|
-
badges.appendChild(expandIcon);
|
|
63
|
-
|
|
64
|
-
headerRow.appendChild(title);
|
|
65
|
-
headerRow.appendChild(badges);
|
|
66
|
-
body.appendChild(headerRow);
|
|
67
|
-
|
|
68
|
-
// Summary line (categories if available)
|
|
69
|
-
if (cluster.categories) {
|
|
70
|
-
var catLine = document.createElement('small');
|
|
71
|
-
catLine.className = 'text-muted';
|
|
72
|
-
catLine.textContent = cluster.categories;
|
|
73
|
-
body.appendChild(catLine);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Expandable member area (hidden by default)
|
|
77
|
-
var memberArea = document.createElement('div');
|
|
78
|
-
memberArea.className = 'mt-2';
|
|
79
|
-
memberArea.style.display = 'none';
|
|
80
|
-
memberArea.id = 'cluster-members-' + cluster.cluster_id;
|
|
81
|
-
|
|
82
|
-
var loadingText = document.createElement('div');
|
|
83
|
-
loadingText.className = 'text-center text-muted small py-2';
|
|
84
|
-
loadingText.textContent = 'Loading members...';
|
|
85
|
-
memberArea.appendChild(loadingText);
|
|
86
|
-
|
|
87
|
-
body.appendChild(memberArea);
|
|
88
|
-
card.appendChild(body);
|
|
89
|
-
container.appendChild(card);
|
|
90
|
-
|
|
91
|
-
// Click to expand/collapse
|
|
92
|
-
var expanded = false;
|
|
93
|
-
body.addEventListener('click', function(e) {
|
|
94
|
-
expanded = !expanded;
|
|
95
|
-
memberArea.style.display = expanded ? 'block' : 'none';
|
|
96
|
-
expandIcon.style.transform = expanded ? 'rotate(180deg)' : 'rotate(0)';
|
|
97
|
-
|
|
98
|
-
if (expanded && memberArea.children.length === 1 && memberArea.children[0] === loadingText) {
|
|
99
|
-
loadClusterMembers(cluster.cluster_id, memberArea);
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
async function loadClusterMembers(clusterId, container) {
|
|
106
|
-
try {
|
|
107
|
-
var response = await fetch('/api/clusters/' + clusterId + '?limit=10');
|
|
108
|
-
var data = await response.json();
|
|
109
|
-
container.textContent = '';
|
|
110
|
-
|
|
111
|
-
// Show cluster summary if available
|
|
112
|
-
if (data.summary) {
|
|
113
|
-
var summaryDiv = document.createElement('div');
|
|
114
|
-
summaryDiv.className = 'alert alert-light border-start border-3 border-primary py-2 px-3 mb-2 small';
|
|
115
|
-
var summaryLabel = document.createElement('strong');
|
|
116
|
-
summaryLabel.textContent = 'Summary: ';
|
|
117
|
-
summaryDiv.appendChild(summaryLabel);
|
|
118
|
-
summaryDiv.appendChild(document.createTextNode(data.summary));
|
|
119
|
-
container.appendChild(summaryDiv);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (!data.members || data.members.length === 0) {
|
|
123
|
-
var empty = document.createElement('div');
|
|
124
|
-
empty.className = 'text-muted small';
|
|
125
|
-
empty.textContent = 'No members found.';
|
|
126
|
-
container.appendChild(empty);
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
data.members.forEach(function(m, i) {
|
|
131
|
-
var row = document.createElement('div');
|
|
132
|
-
row.className = 'border-bottom py-1';
|
|
133
|
-
if (i === data.members.length - 1) row.className = 'py-1';
|
|
134
|
-
|
|
135
|
-
var content = document.createElement('div');
|
|
136
|
-
content.className = 'small';
|
|
137
|
-
var text = m.content || m.summary || '';
|
|
138
|
-
content.textContent = (i + 1) + '. ' + (text.length > 150 ? text.substring(0, 150) + '...' : text);
|
|
139
|
-
row.appendChild(content);
|
|
140
|
-
|
|
141
|
-
var meta = document.createElement('div');
|
|
142
|
-
meta.className = 'text-muted';
|
|
143
|
-
meta.style.fontSize = '0.7rem';
|
|
144
|
-
var parts = [];
|
|
145
|
-
if (m.category) parts.push(m.category);
|
|
146
|
-
if (m.importance) parts.push('imp: ' + m.importance);
|
|
147
|
-
if (m.created_at) parts.push(m.created_at.substring(0, 10));
|
|
148
|
-
meta.textContent = parts.join(' | ');
|
|
149
|
-
row.appendChild(meta);
|
|
150
|
-
|
|
151
|
-
container.appendChild(row);
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
// View in graph button
|
|
155
|
-
var graphBtn = document.createElement('button');
|
|
156
|
-
graphBtn.className = 'btn btn-sm btn-outline-primary mt-2';
|
|
157
|
-
graphBtn.textContent = 'View in Knowledge Graph';
|
|
158
|
-
graphBtn.addEventListener('click', function(e) {
|
|
159
|
-
e.stopPropagation();
|
|
160
|
-
filterGraphToCluster(clusterId);
|
|
161
|
-
});
|
|
162
|
-
container.appendChild(graphBtn);
|
|
163
|
-
|
|
164
|
-
} catch (error) {
|
|
165
|
-
container.textContent = '';
|
|
166
|
-
var errDiv = document.createElement('div');
|
|
167
|
-
errDiv.className = 'text-danger small';
|
|
168
|
-
errDiv.textContent = 'Failed to load: ' + error.message;
|
|
169
|
-
container.appendChild(errDiv);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function filterGraphToCluster(clusterId) {
|
|
174
|
-
var graphTab = document.querySelector('a[href="#graph"]');
|
|
175
|
-
if (graphTab) graphTab.click();
|
|
176
|
-
|
|
177
|
-
setTimeout(function() {
|
|
178
|
-
if (typeof filterState !== 'undefined' && typeof filterByCluster === 'function' && typeof renderGraph === 'function') {
|
|
179
|
-
filterState.cluster_id = clusterId;
|
|
180
|
-
var filtered = filterByCluster(originalGraphData, clusterId);
|
|
181
|
-
renderGraph(filtered);
|
|
182
|
-
var url = new URL(window.location);
|
|
183
|
-
url.searchParams.set('cluster_id', clusterId);
|
|
184
|
-
window.history.replaceState({}, '', url);
|
|
185
|
-
}
|
|
186
|
-
}, 300);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function filterGraphByEntity(entity) {
|
|
190
|
-
var graphTab = document.querySelector('a[href="#graph"]');
|
|
191
|
-
if (graphTab) graphTab.click();
|
|
192
|
-
|
|
193
|
-
setTimeout(function() {
|
|
194
|
-
if (typeof filterState !== 'undefined' && typeof filterByEntity === 'function' && typeof renderGraph === 'function') {
|
|
195
|
-
filterState.entity = entity;
|
|
196
|
-
var filtered = filterByEntity(originalGraphData, entity);
|
|
197
|
-
renderGraph(filtered);
|
|
198
|
-
}
|
|
199
|
-
}, 300);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function showClusterMemories(clusterId) {
|
|
203
|
-
var memoriesTab = document.querySelector('a[href="#memories"]');
|
|
204
|
-
if (memoriesTab) memoriesTab.click();
|
|
205
|
-
if (typeof showToast === 'function') showToast('Filtering memories for cluster ' + clusterId);
|
|
206
|
-
}
|