superlocalmemory 3.4.17 → 3.4.19

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.
Files changed (80) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/package.json +1 -3
  3. package/pyproject.toml +10 -1
  4. package/src/superlocalmemory/cli/setup_wizard.py +30 -0
  5. package/src/superlocalmemory/core/embeddings.py +8 -2
  6. package/src/superlocalmemory/retrieval/reranker.py +4 -2
  7. package/src/superlocalmemory.egg-info/PKG-INFO +4 -1
  8. package/src/superlocalmemory.egg-info/requires.txt +3 -0
  9. package/docs/ARCHITECTURE.md +0 -149
  10. package/docs/api-reference.md +0 -284
  11. package/docs/auto-memory.md +0 -150
  12. package/docs/cli-reference.md +0 -327
  13. package/docs/cloud-backup.md +0 -174
  14. package/docs/compliance.md +0 -191
  15. package/docs/configuration.md +0 -182
  16. package/docs/getting-started.md +0 -102
  17. package/docs/ide-setup.md +0 -261
  18. package/docs/mcp-tools.md +0 -220
  19. package/docs/migration-from-v2.md +0 -170
  20. package/docs/profiles.md +0 -173
  21. package/docs/screenshots/01-dashboard-main.png +0 -0
  22. package/docs/screenshots/02-knowledge-graph.png +0 -0
  23. package/docs/screenshots/03-math-health.png +0 -0
  24. package/docs/screenshots/03-patterns-learning.png +0 -0
  25. package/docs/screenshots/04-learning-dashboard.png +0 -0
  26. package/docs/screenshots/04-recall-lab.png +0 -0
  27. package/docs/screenshots/05-behavioral-analysis.png +0 -0
  28. package/docs/screenshots/05-trust-dashboard.png +0 -0
  29. package/docs/screenshots/06-graph-communities.png +0 -0
  30. package/docs/screenshots/06-settings.png +0 -0
  31. package/docs/screenshots/07-memories-blurred.png +0 -0
  32. package/docs/skill-evolution.md +0 -256
  33. package/docs/troubleshooting.md +0 -310
  34. package/docs/v2-archive/ACCESSIBILITY.md +0 -291
  35. package/docs/v2-archive/ARCHITECTURE.md +0 -886
  36. package/docs/v2-archive/CLI-COMMANDS-REFERENCE.md +0 -425
  37. package/docs/v2-archive/COMPRESSION-README.md +0 -390
  38. package/docs/v2-archive/FRAMEWORK-INTEGRATIONS.md +0 -300
  39. package/docs/v2-archive/MCP-MANUAL-SETUP.md +0 -775
  40. package/docs/v2-archive/MCP-TROUBLESHOOTING.md +0 -787
  41. package/docs/v2-archive/PATTERN-LEARNING.md +0 -228
  42. package/docs/v2-archive/PROFILES-GUIDE.md +0 -453
  43. package/docs/v2-archive/RESET-GUIDE.md +0 -353
  44. package/docs/v2-archive/SEARCH-ENGINE-V2.2.0.md +0 -749
  45. package/docs/v2-archive/SEARCH-INTEGRATION-GUIDE.md +0 -502
  46. package/docs/v2-archive/UI-SERVER.md +0 -262
  47. package/docs/v2-archive/UNIVERSAL-INTEGRATION.md +0 -488
  48. package/docs/v2-archive/V2.2.0-OPTIONAL-SEARCH.md +0 -666
  49. package/docs/v2-archive/WINDOWS-INSTALL-README.txt +0 -34
  50. package/docs/v2-archive/WINDOWS-POST-INSTALL.txt +0 -45
  51. package/docs/v2-archive/example_graph_usage.py +0 -146
  52. package/ui/index.html +0 -1879
  53. package/ui/js/agents.js +0 -192
  54. package/ui/js/auto-settings.js +0 -399
  55. package/ui/js/behavioral.js +0 -276
  56. package/ui/js/clusters.js +0 -206
  57. package/ui/js/compliance.js +0 -252
  58. package/ui/js/core.js +0 -246
  59. package/ui/js/dashboard.js +0 -110
  60. package/ui/js/events.js +0 -178
  61. package/ui/js/fact-detail.js +0 -92
  62. package/ui/js/feedback.js +0 -333
  63. package/ui/js/graph-core.js +0 -447
  64. package/ui/js/graph-filters.js +0 -220
  65. package/ui/js/graph-interactions.js +0 -351
  66. package/ui/js/graph-ui.js +0 -214
  67. package/ui/js/ide-status.js +0 -102
  68. package/ui/js/init.js +0 -45
  69. package/ui/js/learning.js +0 -435
  70. package/ui/js/lifecycle.js +0 -298
  71. package/ui/js/math-health.js +0 -98
  72. package/ui/js/memories.js +0 -264
  73. package/ui/js/modal.js +0 -357
  74. package/ui/js/patterns.js +0 -93
  75. package/ui/js/profiles.js +0 -236
  76. package/ui/js/recall-lab.js +0 -292
  77. package/ui/js/search.js +0 -59
  78. package/ui/js/settings.js +0 -224
  79. package/ui/js/timeline.js +0 -32
  80. package/ui/js/trust-dashboard.js +0 -73
package/ui/js/modal.js DELETED
@@ -1,357 +0,0 @@
1
- // SuperLocalMemory V2 - Memory Detail Modal + Copy/Export
2
- // Depends on: core.js
3
- //
4
- // Security: All dynamic values escaped via escapeHtml(). Data from local DB only.
5
- // nosemgrep: innerHTML-xss — all dynamic values escaped
6
-
7
- var currentMemoryDetail = null;
8
-
9
- function openMemoryDetail(mem, source) {
10
- // source: 'graph', 'recall', 'memories', or undefined
11
- currentMemoryDetail = mem;
12
- var fromGraph = source === 'graph';
13
- var fromRecall = source === 'recall';
14
- var body = document.getElementById('memory-detail-body');
15
- if (!mem) {
16
- body.textContent = 'No memory data';
17
- return;
18
- }
19
-
20
- // Store last focused element (for keyboard nav return)
21
- if (!window.lastFocusedElement) {
22
- window.lastFocusedElement = document.activeElement;
23
- }
24
-
25
- var content = mem.content || mem.summary || '(no content)';
26
- var tags = mem.tags || '';
27
- var importance = mem.importance || 5;
28
- var importanceClass = importance >= 8 ? 'success' : importance >= 5 ? 'warning' : 'secondary';
29
-
30
- // Build detail using DOM nodes for safety
31
- body.textContent = '';
32
-
33
- var contentDiv = document.createElement('div');
34
- contentDiv.className = 'memory-detail-content';
35
- contentDiv.textContent = content;
36
- body.appendChild(contentDiv);
37
-
38
- body.appendChild(document.createElement('hr'));
39
-
40
- var dl = document.createElement('dl');
41
- dl.className = 'memory-detail-meta row';
42
-
43
- // Left column
44
- var col1 = document.createElement('div');
45
- col1.className = 'col-md-6';
46
- addDetailRow(col1, 'ID', String(mem.id || '-'));
47
- addDetailBadgeRow(col1, 'Category', mem.category || 'None', 'bg-primary');
48
- addDetailRow(col1, 'Project', mem.project_name || '-');
49
- addDetailTagsRow(col1, 'Tags', tags);
50
- dl.appendChild(col1);
51
-
52
- // Right column
53
- var col2 = document.createElement('div');
54
- col2.className = 'col-md-6';
55
- addDetailBadgeRow(col2, 'Importance', importance + '/10', 'bg-' + importanceClass);
56
- addDetailRow(col2, 'Cluster', String(mem.cluster_id || '-'));
57
- addDetailRow(col2, 'Created', formatDateFull(mem.created_at));
58
- if (mem.updated_at) addDetailRow(col2, 'Updated', formatDateFull(mem.updated_at));
59
-
60
- if (typeof mem.score === 'number') {
61
- var pct = Math.round(mem.score * 100);
62
- addDetailRow(col2, 'Relevance Score', pct + '%');
63
- }
64
- dl.appendChild(col2);
65
-
66
- body.appendChild(dl);
67
-
68
- // Context-aware action buttons
69
- if (mem.id) {
70
- body.appendChild(document.createElement('hr'));
71
-
72
- var actionsDiv = document.createElement('div');
73
- actionsDiv.className = 'memory-detail-graph-actions';
74
- actionsDiv.style.cssText = 'display:flex; gap:10px; flex-wrap:wrap;';
75
-
76
- // "View Original Memory" — shown on Recall Lab + Memories, hidden on Graph
77
- // (On Graph the node IS the memory; on Recall Lab we have a fact, not the original)
78
- if (!fromGraph) {
79
- var viewBtn = document.createElement('button');
80
- viewBtn.className = 'btn btn-primary btn-sm';
81
- viewBtn.innerHTML = '<i class="bi bi-journal-text"></i> View Original Memory';
82
- viewBtn.onclick = function() {
83
- var mid = mem.memory_id || mem.id;
84
- viewBtn.disabled = true;
85
- viewBtn.textContent = 'Loading...';
86
- fetch('/api/memories/' + encodeURIComponent(mid) + '/facts')
87
- .then(function(r) { return r.json(); })
88
- .then(function(data) {
89
- if (data.ok && data.original_content) {
90
- contentDiv.textContent = '';
91
- var origLabel = document.createElement('small');
92
- origLabel.className = 'text-muted d-block mb-1';
93
- origLabel.textContent = 'Original memory (' + (data.fact_count || 0) + ' atomic facts extracted):';
94
- contentDiv.appendChild(origLabel);
95
- var origText = document.createElement('div');
96
- origText.style.cssText = 'white-space:pre-wrap;background:#f8f9fa;padding:10px;border-radius:6px;margin-bottom:8px;';
97
- origText.textContent = data.original_content;
98
- contentDiv.appendChild(origText);
99
- if (data.facts && data.facts.length > 0) {
100
- var toggle = document.createElement('button');
101
- toggle.className = 'btn btn-sm btn-outline-secondary mb-2';
102
- toggle.textContent = 'Show atomic facts (' + data.facts.length + ')';
103
- var factsDiv = document.createElement('div');
104
- factsDiv.style.display = 'none';
105
- data.facts.forEach(function(f) {
106
- var fDiv = document.createElement('div');
107
- fDiv.className = 'small py-1 border-bottom';
108
- var badge = document.createElement('span');
109
- badge.className = 'badge bg-secondary me-1';
110
- badge.style.fontSize = '0.6rem';
111
- badge.textContent = f.fact_type;
112
- fDiv.appendChild(badge);
113
- fDiv.appendChild(document.createTextNode(f.content));
114
- factsDiv.appendChild(fDiv);
115
- });
116
- toggle.onclick = function() {
117
- var hidden = factsDiv.style.display === 'none';
118
- factsDiv.style.display = hidden ? 'block' : 'none';
119
- toggle.textContent = hidden ? 'Hide atomic facts' : 'Show atomic facts (' + data.facts.length + ')';
120
- };
121
- contentDiv.appendChild(toggle);
122
- contentDiv.appendChild(factsDiv);
123
- }
124
- viewBtn.textContent = 'Showing original';
125
- } else {
126
- viewBtn.textContent = 'Not available';
127
- }
128
- }).catch(function() {
129
- viewBtn.textContent = 'Failed to load';
130
- viewBtn.disabled = false;
131
- });
132
- };
133
- actionsDiv.appendChild(viewBtn);
134
- }
135
-
136
- // "Expand Neighbors" — shown on Graph, hidden elsewhere (no graph context)
137
- if (fromGraph) {
138
- var expandBtn = document.createElement('button');
139
- expandBtn.className = 'btn btn-outline-secondary btn-sm';
140
- expandBtn.innerHTML = '<i class="bi bi-diagram-3"></i> Expand Neighbors';
141
- expandBtn.onclick = function() {
142
- modal.hide();
143
- setTimeout(function() {
144
- if (typeof expandNeighbors === 'function') expandNeighbors(mem.id);
145
- }, 300);
146
- };
147
- actionsDiv.appendChild(expandBtn);
148
- }
149
-
150
- // "Filter to Cluster" — always available if cluster exists
151
- if (mem.cluster_id) {
152
- var filterBtn = document.createElement('button');
153
- filterBtn.className = 'btn btn-outline-info btn-sm';
154
- var filterIcon = document.createElement('i');
155
- filterIcon.className = 'bi bi-funnel';
156
- filterBtn.appendChild(filterIcon);
157
- filterBtn.appendChild(document.createTextNode(' Filter to Cluster ' + mem.cluster_id));
158
- filterBtn.onclick = function() {
159
- modal.hide();
160
- // Switch to Graph tab
161
- const graphTab = document.querySelector('a[href="#graph"]');
162
- if (graphTab) graphTab.click();
163
- // Apply cluster filter after a delay
164
- setTimeout(function() {
165
- if (typeof filterState !== 'undefined' && typeof filterByCluster === 'function' && typeof renderGraph === 'function') {
166
- filterState.cluster_id = mem.cluster_id;
167
- const filtered = filterByCluster(originalGraphData, mem.cluster_id);
168
- renderGraph(filtered);
169
- // Update URL
170
- const url = new URL(window.location);
171
- url.searchParams.set('cluster_id', mem.cluster_id);
172
- window.history.replaceState({}, '', url);
173
- }
174
- }, 500);
175
- };
176
- actionsDiv.appendChild(filterBtn);
177
- }
178
-
179
- // Edit button — always available
180
- var editBtn = document.createElement('button');
181
- editBtn.className = 'btn btn-outline-warning btn-sm';
182
- editBtn.innerHTML = '<i class="bi bi-pencil"></i> Edit';
183
- editBtn.onclick = function() {
184
- var currentText = contentDiv.textContent;
185
- var textarea = document.createElement('textarea');
186
- textarea.className = 'form-control mb-2';
187
- textarea.rows = 4;
188
- textarea.value = currentText;
189
- contentDiv.textContent = '';
190
- contentDiv.appendChild(textarea);
191
- var saveBtn = document.createElement('button');
192
- saveBtn.className = 'btn btn-sm btn-success me-1';
193
- saveBtn.textContent = 'Save';
194
- saveBtn.onclick = function() {
195
- var newContent = textarea.value.trim();
196
- if (!newContent) return;
197
- fetch('/api/memories/' + encodeURIComponent(mem.id), {
198
- method: 'PATCH',
199
- headers: {'Content-Type': 'application/json'},
200
- body: JSON.stringify({content: newContent})
201
- }).then(function(r) { return r.json(); }).then(function(d) {
202
- if (d.success) {
203
- contentDiv.textContent = newContent;
204
- mem.content = newContent;
205
- if (typeof showToast === 'function') showToast('Memory updated');
206
- }
207
- });
208
- };
209
- var cancelBtn = document.createElement('button');
210
- cancelBtn.className = 'btn btn-sm btn-secondary';
211
- cancelBtn.textContent = 'Cancel';
212
- cancelBtn.onclick = function() { contentDiv.textContent = currentText; };
213
- contentDiv.appendChild(saveBtn);
214
- contentDiv.appendChild(cancelBtn);
215
- };
216
- actionsDiv.appendChild(editBtn);
217
-
218
- // Delete button — always available
219
- var deleteBtn = document.createElement('button');
220
- deleteBtn.className = 'btn btn-outline-danger btn-sm';
221
- deleteBtn.innerHTML = '<i class="bi bi-trash"></i> Delete';
222
- deleteBtn.onclick = function() {
223
- if (!confirm('Delete this memory? This cannot be undone.')) return;
224
- fetch('/api/memories/' + encodeURIComponent(mem.id), {method: 'DELETE'})
225
- .then(function(r) { return r.json(); })
226
- .then(function(d) {
227
- if (d.success) {
228
- modal.hide();
229
- if (typeof showToast === 'function') showToast('Memory deleted');
230
- if (typeof loadMemories === 'function') setTimeout(loadMemories, 300);
231
- }
232
- });
233
- };
234
- actionsDiv.appendChild(deleteBtn);
235
-
236
- body.appendChild(actionsDiv);
237
- }
238
-
239
- // v2.7.4: Add feedback buttons to modal body
240
- if (typeof createFeedbackButtons === 'function' && mem && mem.id) {
241
- var feedbackDiv = document.createElement('div');
242
- feedbackDiv.className = 'mt-3 pt-2 border-top';
243
- var feedbackLabel = document.createElement('small');
244
- feedbackLabel.className = 'text-muted d-block mb-1';
245
- feedbackLabel.textContent = 'Was this memory useful?';
246
- feedbackDiv.appendChild(feedbackLabel);
247
- feedbackDiv.appendChild(createFeedbackButtons(mem.id));
248
- body.appendChild(feedbackDiv);
249
- }
250
-
251
- var modalEl = document.getElementById('memoryDetailModal');
252
- var modal = new bootstrap.Modal(modalEl);
253
-
254
- // v2.7.4: Start dwell time tracking
255
- if (typeof startDwellTracking === 'function' && mem && mem.id) {
256
- startDwellTracking(mem.id);
257
- }
258
-
259
- // Focus first interactive element when modal opens
260
- modalEl.addEventListener('shown.bs.modal', function() {
261
- const firstButton = modalEl.querySelector('button, a[href]');
262
- if (firstButton) {
263
- firstButton.focus();
264
- }
265
- }, { once: true });
266
-
267
- // Return focus when modal closes + stop dwell tracking
268
- modalEl.addEventListener('hidden.bs.modal', function() {
269
- // v2.7.4: Stop dwell time tracking
270
- if (typeof stopDwellTracking === 'function') {
271
- stopDwellTracking();
272
- }
273
- if (window.lastFocusedElement && typeof window.lastFocusedElement.focus === 'function') {
274
- window.lastFocusedElement.focus();
275
- window.lastFocusedElement = null;
276
- }
277
- }, { once: true });
278
-
279
- modal.show();
280
- }
281
-
282
- function addDetailRow(parent, label, value) {
283
- var dt = document.createElement('dt');
284
- dt.textContent = label;
285
- parent.appendChild(dt);
286
- var dd = document.createElement('dd');
287
- dd.textContent = value;
288
- parent.appendChild(dd);
289
- }
290
-
291
- function addDetailBadgeRow(parent, label, value, badgeClass) {
292
- var dt = document.createElement('dt');
293
- dt.textContent = label;
294
- parent.appendChild(dt);
295
- var dd = document.createElement('dd');
296
- var badge = document.createElement('span');
297
- badge.className = 'badge ' + badgeClass;
298
- badge.textContent = value;
299
- dd.appendChild(badge);
300
- parent.appendChild(dd);
301
- }
302
-
303
- function addDetailTagsRow(parent, label, tags) {
304
- var dt = document.createElement('dt');
305
- dt.textContent = label;
306
- parent.appendChild(dt);
307
- var dd = document.createElement('dd');
308
- var tagList = typeof tags === 'string' ? tags.split(',') : (tags || []);
309
- if (tagList.length === 0 || (tagList.length === 1 && !tagList[0].trim())) {
310
- dd.className = 'text-muted';
311
- dd.textContent = 'None';
312
- } else {
313
- tagList.forEach(function(t) {
314
- var tag = t.trim();
315
- if (tag) {
316
- var badge = document.createElement('span');
317
- badge.className = 'badge bg-secondary me-1';
318
- badge.textContent = tag;
319
- dd.appendChild(badge);
320
- }
321
- });
322
- }
323
- parent.appendChild(dd);
324
- }
325
-
326
- function copyMemoryToClipboard() {
327
- if (!currentMemoryDetail) return;
328
- var text = currentMemoryDetail.content || currentMemoryDetail.summary || '';
329
- navigator.clipboard.writeText(text).then(function() {
330
- showToast('Copied to clipboard');
331
- }).catch(function() {
332
- var ta = document.createElement('textarea');
333
- ta.value = text;
334
- document.body.appendChild(ta);
335
- ta.select();
336
- document.execCommand('copy');
337
- document.body.removeChild(ta);
338
- showToast('Copied to clipboard');
339
- });
340
- }
341
-
342
- function exportMemoryAsMarkdown() {
343
- if (!currentMemoryDetail) return;
344
- var mem = currentMemoryDetail;
345
- var md = '# Memory #' + (mem.id || 'unknown') + '\n\n';
346
- md += '**Category:** ' + (mem.category || 'None') + ' \n';
347
- md += '**Project:** ' + (mem.project_name || '-') + ' \n';
348
- md += '**Importance:** ' + (mem.importance || 5) + '/10 \n';
349
- md += '**Tags:** ' + (mem.tags || 'None') + ' \n';
350
- md += '**Created:** ' + (mem.created_at || '-') + ' \n';
351
- if (mem.cluster_id) md += '**Cluster:** ' + mem.cluster_id + ' \n';
352
- md += '\n---\n\n';
353
- md += mem.content || mem.summary || '(no content)';
354
- md += '\n\n---\n*Exported from SuperLocalMemory V2*\n';
355
-
356
- downloadFile('memory-' + (mem.id || 'export') + '.md', md, 'text/markdown');
357
- }
package/ui/js/patterns.js DELETED
@@ -1,93 +0,0 @@
1
- // SuperLocalMemory V2 - Patterns View (Layer 4)
2
- // Depends on: core.js
3
-
4
- async function loadPatterns() {
5
- showLoading('patterns-list', 'Loading patterns...');
6
- try {
7
- var response = await fetch('/api/patterns');
8
- var data = await response.json();
9
- renderPatterns(data.patterns);
10
- } catch (error) {
11
- console.error('Error loading patterns:', error);
12
- showEmpty('patterns-list', 'puzzle', 'Failed to load patterns');
13
- }
14
- }
15
-
16
- function renderPatterns(patterns) {
17
- var container = document.getElementById('patterns-list');
18
- if (!patterns || Object.keys(patterns).length === 0) {
19
- showEmpty('patterns-list', 'puzzle', 'No patterns learned yet. Use SuperLocalMemory for a while to build patterns.');
20
- return;
21
- }
22
-
23
- var typeIcons = { preference: 'heart', style: 'palette', terminology: 'code-slash' };
24
- var typeLabels = { preference: 'Preferences', style: 'Coding Style', terminology: 'Terminology' };
25
-
26
- container.textContent = '';
27
-
28
- for (var type in patterns) {
29
- if (!patterns.hasOwnProperty(type)) continue;
30
- var items = patterns[type];
31
-
32
- var header = document.createElement('h6');
33
- header.className = 'mt-3 mb-2';
34
- var icon = document.createElement('i');
35
- icon.className = 'bi bi-' + (typeIcons[type] || 'puzzle') + ' me-1';
36
- header.appendChild(icon);
37
- header.appendChild(document.createTextNode(typeLabels[type] || type));
38
- var countBadge = document.createElement('span');
39
- countBadge.className = 'badge bg-secondary ms-2';
40
- countBadge.textContent = items.length;
41
- header.appendChild(countBadge);
42
- container.appendChild(header);
43
-
44
- var group = document.createElement('div');
45
- group.className = 'list-group mb-3';
46
-
47
- items.forEach(function(pattern) {
48
- var pct = Math.round(pattern.confidence * 100);
49
- var barColor = pct >= 60 ? '#43e97b' : pct >= 40 ? '#f9c74f' : '#6c757d';
50
- var badgeClass = pct >= 60 ? 'bg-success' : pct >= 40 ? 'bg-warning text-dark' : 'bg-secondary';
51
-
52
- var item = document.createElement('div');
53
- item.className = 'list-group-item';
54
-
55
- var topRow = document.createElement('div');
56
- topRow.className = 'd-flex justify-content-between align-items-center';
57
- var keyEl = document.createElement('strong');
58
- keyEl.textContent = pattern.key;
59
- var badge = document.createElement('span');
60
- badge.className = 'badge ' + badgeClass;
61
- badge.textContent = pct + '%';
62
- topRow.appendChild(keyEl);
63
- topRow.appendChild(badge);
64
- item.appendChild(topRow);
65
-
66
- var barContainer = document.createElement('div');
67
- barContainer.className = 'confidence-bar';
68
- var barFill = document.createElement('div');
69
- barFill.className = 'confidence-fill';
70
- barFill.style.width = pct + '%';
71
- barFill.style.background = barColor;
72
- barContainer.appendChild(barFill);
73
- item.appendChild(barContainer);
74
-
75
- var valueEl = document.createElement('div');
76
- valueEl.className = 'mt-1';
77
- var valueSmall = document.createElement('small');
78
- valueSmall.className = 'text-muted';
79
- valueSmall.textContent = typeof pattern.value === 'string' ? pattern.value : JSON.stringify(pattern.value);
80
- valueEl.appendChild(valueSmall);
81
- item.appendChild(valueEl);
82
-
83
- var evidenceEl = document.createElement('small');
84
- evidenceEl.className = 'text-muted';
85
- evidenceEl.textContent = 'Evidence: ' + (pattern.evidence_count || '?') + ' memories';
86
- item.appendChild(evidenceEl);
87
-
88
- group.appendChild(item);
89
- });
90
-
91
- container.appendChild(group);
92
- }
93
- }
package/ui/js/profiles.js DELETED
@@ -1,236 +0,0 @@
1
- // SuperLocalMemory V2 - Profile Management
2
- // Depends on: core.js
3
-
4
- async function loadProfiles() {
5
- try {
6
- var response = await fetch('/api/profiles');
7
- var data = await response.json();
8
- var select = document.getElementById('profile-select');
9
- select.textContent = '';
10
- var profiles = data.profiles || [];
11
- var active = data.active_profile || 'default';
12
-
13
- if (profiles.length === 0) {
14
- // Fresh install fallback — show default profile
15
- var opt = document.createElement('option');
16
- opt.value = 'default';
17
- opt.textContent = 'default (0)';
18
- opt.selected = true;
19
- select.appendChild(opt);
20
- } else {
21
- profiles.forEach(function(p) {
22
- var opt = document.createElement('option');
23
- opt.value = p.name;
24
- opt.textContent = p.name + ' (' + (p.memory_count || 0) + ')';
25
- if (p.name === active) opt.selected = true;
26
- select.appendChild(opt);
27
- });
28
- }
29
- } catch (error) {
30
- console.error('Error loading profiles:', error);
31
- // On error, ensure dropdown shows at least 'default'
32
- var select = document.getElementById('profile-select');
33
- if (select && select.options.length === 0) {
34
- select.textContent = '';
35
- var opt = document.createElement('option');
36
- opt.value = 'default';
37
- opt.textContent = 'default';
38
- opt.selected = true;
39
- select.appendChild(opt);
40
- }
41
- }
42
- }
43
-
44
- async function createProfile(nameOverride) {
45
- var name = nameOverride || document.getElementById('new-profile-name').value.trim();
46
- if (!name) {
47
- name = prompt('Enter new profile name:');
48
- if (!name || !name.trim()) return;
49
- name = name.trim();
50
- }
51
-
52
- if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
53
- showToast('Invalid name. Use letters, numbers, dashes, underscores.');
54
- return;
55
- }
56
-
57
- try {
58
- var response = await fetch('/api/profiles/create', {
59
- method: 'POST',
60
- headers: { 'Content-Type': 'application/json' },
61
- body: JSON.stringify({ profile_name: name })
62
- });
63
- var data = await response.json();
64
- if (response.status === 409) {
65
- showToast('Profile "' + name + '" already exists');
66
- return;
67
- }
68
- if (!response.ok) {
69
- showToast(data.detail || 'Failed to create profile');
70
- return;
71
- }
72
- showToast('Profile "' + name + '" created');
73
- var input = document.getElementById('new-profile-name');
74
- if (input) input.value = '';
75
- // Force reload with small delay to ensure backend has persisted
76
- setTimeout(function() {
77
- loadProfiles();
78
- if (typeof loadProfilesTable === 'function') loadProfilesTable();
79
- }, 300);
80
- } catch (error) {
81
- console.error('Error creating profile:', error);
82
- showToast('Error creating profile');
83
- }
84
- }
85
-
86
- async function deleteProfile(name) {
87
- if (name === 'default') {
88
- showToast('Cannot delete the default profile');
89
- return;
90
- }
91
- if (!confirm('Delete profile "' + name + '"?\nIts memories will be moved to the default profile.')) {
92
- return;
93
- }
94
- try {
95
- var response = await fetch('/api/profiles/' + encodeURIComponent(name), {
96
- method: 'DELETE'
97
- });
98
- var data = await response.json();
99
- if (!response.ok) {
100
- showToast(data.detail || 'Failed to delete profile');
101
- return;
102
- }
103
- showToast(data.message || 'Profile deleted');
104
- loadProfiles();
105
- loadProfilesTable();
106
- loadStats();
107
- } catch (error) {
108
- console.error('Error deleting profile:', error);
109
- showToast('Error deleting profile');
110
- }
111
- }
112
-
113
- async function loadProfilesTable() {
114
- var container = document.getElementById('profiles-table');
115
- if (!container) return;
116
- try {
117
- var response = await fetch('/api/profiles');
118
- var data = await response.json();
119
- var profiles = data.profiles || [];
120
- var active = data.active_profile || 'default';
121
-
122
- if (profiles.length === 0) {
123
- showEmpty('profiles-table', 'people', 'No profiles found.');
124
- return;
125
- }
126
-
127
- var table = document.createElement('table');
128
- table.className = 'table table-sm mb-0';
129
- var thead = document.createElement('thead');
130
- var headRow = document.createElement('tr');
131
- ['Name', 'Memories', 'Status', 'Actions'].forEach(function(h) {
132
- var th = document.createElement('th');
133
- th.textContent = h;
134
- headRow.appendChild(th);
135
- });
136
- thead.appendChild(headRow);
137
- table.appendChild(thead);
138
-
139
- var tbody = document.createElement('tbody');
140
- profiles.forEach(function(p) {
141
- var row = document.createElement('tr');
142
-
143
- var nameCell = document.createElement('td');
144
- var nameIcon = document.createElement('i');
145
- nameIcon.className = 'bi bi-person me-1';
146
- nameCell.appendChild(nameIcon);
147
- nameCell.appendChild(document.createTextNode(p.name));
148
- row.appendChild(nameCell);
149
-
150
- var countCell = document.createElement('td');
151
- countCell.textContent = (p.memory_count || 0) + ' memories';
152
- row.appendChild(countCell);
153
-
154
- var statusCell = document.createElement('td');
155
- if (p.name === active) {
156
- var badge = document.createElement('span');
157
- badge.className = 'badge bg-success';
158
- badge.textContent = 'Active';
159
- statusCell.appendChild(badge);
160
- } else {
161
- var switchBtn = document.createElement('button');
162
- switchBtn.className = 'btn btn-sm btn-outline-primary';
163
- switchBtn.textContent = 'Switch';
164
- switchBtn.addEventListener('click', (function(n) {
165
- return function() { switchProfile(n); };
166
- })(p.name));
167
- statusCell.appendChild(switchBtn);
168
- }
169
- row.appendChild(statusCell);
170
-
171
- var actionsCell = document.createElement('td');
172
- if (p.name !== 'default') {
173
- var delBtn = document.createElement('button');
174
- delBtn.className = 'btn btn-sm btn-outline-danger btn-delete-profile';
175
- delBtn.title = 'Delete profile';
176
- var delIcon = document.createElement('i');
177
- delIcon.className = 'bi bi-trash';
178
- delBtn.appendChild(delIcon);
179
- delBtn.addEventListener('click', (function(n) {
180
- return function() { deleteProfile(n); };
181
- })(p.name));
182
- actionsCell.appendChild(delBtn);
183
- } else {
184
- var protectedBadge = document.createElement('span');
185
- protectedBadge.className = 'badge bg-secondary';
186
- protectedBadge.textContent = 'Protected';
187
- actionsCell.appendChild(protectedBadge);
188
- }
189
- row.appendChild(actionsCell);
190
-
191
- tbody.appendChild(row);
192
- });
193
- table.appendChild(tbody);
194
-
195
- container.textContent = '';
196
- container.appendChild(table);
197
- } catch (error) {
198
- console.error('Error loading profiles table:', error);
199
- showEmpty('profiles-table', 'exclamation-triangle', 'Failed to load profiles');
200
- }
201
- }
202
-
203
- async function switchProfile(profileName) {
204
- try {
205
- var response = await fetch('/api/profiles/' + encodeURIComponent(profileName) + '/switch', {
206
- method: 'POST'
207
- });
208
- var data = await response.json();
209
- if (data.success || data.active_profile) {
210
- showToast('Switched to profile: ' + profileName);
211
- loadProfiles();
212
- loadStats();
213
- loadGraph();
214
- loadProfilesTable();
215
- // v2.7.4: Reload ALL tabs for new profile
216
- if (typeof loadLearning === 'function') loadLearning();
217
- if (typeof refreshFeedbackStats === 'function') refreshFeedbackStats();
218
- if (typeof loadLearningDataStats === 'function') loadLearningDataStats();
219
- if (typeof loadAgents === 'function') loadAgents();
220
- if (typeof loadMemories === 'function') loadMemories();
221
- if (typeof loadTimeline === 'function') loadTimeline();
222
- if (typeof loadEvents === 'function') loadEvents();
223
- // v2.8 tabs
224
- if (typeof loadLifecycle === 'function') loadLifecycle();
225
- if (typeof loadBehavioral === 'function') loadBehavioral();
226
- if (typeof loadCompliance === 'function') loadCompliance();
227
- var activeTab = document.querySelector('#mainTabs .nav-link.active');
228
- if (activeTab) activeTab.click();
229
- } else {
230
- showToast('Failed to switch profile');
231
- }
232
- } catch (error) {
233
- console.error('Error switching profile:', error);
234
- showToast('Error switching profile');
235
- }
236
- }