superlocalmemory 3.4.18 → 3.4.21
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 +35 -0
- package/README.md +42 -34
- package/bin/slm +11 -0
- package/bin/slm.bat +12 -0
- package/package.json +4 -3
- package/pyproject.toml +3 -2
- package/scripts/build-slm-hook.ps1 +40 -0
- package/scripts/build-slm-hook.sh +45 -0
- package/scripts/build_entry.py +452 -0
- package/scripts/ci/stage5b_gate.sh +50 -0
- package/scripts/postinstall/validation.js +187 -0
- package/scripts/postinstall-interactive.js +756 -0
- package/scripts/postinstall_binary.js +287 -0
- package/scripts/release_manifest.py +273 -0
- package/scripts/slm-hook.spec +56 -0
- package/skills/slm-build-graph/SKILL.md +423 -0
- package/skills/slm-list-recent/SKILL.md +348 -0
- package/skills/slm-recall/SKILL.md +343 -0
- package/skills/slm-remember/SKILL.md +194 -0
- package/skills/slm-show-patterns/SKILL.md +224 -0
- package/skills/slm-status/SKILL.md +363 -0
- package/skills/slm-switch-profile/SKILL.md +442 -0
- package/src/superlocalmemory/cli/commands.py +219 -79
- package/src/superlocalmemory/cli/context_commands.py +192 -0
- package/src/superlocalmemory/cli/daemon.py +15 -1
- package/src/superlocalmemory/cli/db_migrate.py +80 -0
- package/src/superlocalmemory/cli/escape_hatch.py +220 -0
- package/src/superlocalmemory/cli/main.py +72 -1
- package/src/superlocalmemory/core/context_cache.py +397 -0
- package/src/superlocalmemory/core/embeddings.py +8 -2
- package/src/superlocalmemory/core/engine.py +38 -2
- package/src/superlocalmemory/core/engine_wiring.py +1 -1
- package/src/superlocalmemory/core/ram_lock.py +111 -0
- package/src/superlocalmemory/core/recall_pipeline.py +433 -3
- package/src/superlocalmemory/core/recall_worker.py +8 -3
- package/src/superlocalmemory/core/security_primitives.py +635 -0
- package/src/superlocalmemory/core/shadow_router.py +319 -0
- package/src/superlocalmemory/core/slm_disabled.py +87 -0
- package/src/superlocalmemory/core/slmignore.py +125 -0
- package/src/superlocalmemory/core/topic_signature.py +143 -0
- package/src/superlocalmemory/core/worker_pool.py +14 -3
- package/src/superlocalmemory/encoding/cognitive_consolidator.py +2 -2
- package/src/superlocalmemory/evolution/budget.py +321 -0
- package/src/superlocalmemory/evolution/llm_dispatch.py +508 -0
- package/src/superlocalmemory/evolution/skill_evolver.py +144 -94
- package/src/superlocalmemory/hooks/_outcome_common.py +506 -0
- package/src/superlocalmemory/hooks/adapter_base.py +317 -0
- package/src/superlocalmemory/hooks/antigravity_adapter.py +192 -0
- package/src/superlocalmemory/hooks/claude_code_hooks.py +33 -1
- package/src/superlocalmemory/hooks/context_payload.py +312 -0
- package/src/superlocalmemory/hooks/copilot_adapter.py +154 -0
- package/src/superlocalmemory/hooks/cross_platform_connector.py +90 -0
- package/src/superlocalmemory/hooks/cursor_adapter.py +195 -0
- package/src/superlocalmemory/hooks/hook_handlers.py +109 -8
- package/src/superlocalmemory/hooks/ide_connector.py +25 -2
- package/src/superlocalmemory/hooks/post_tool_async_hook.py +165 -0
- package/src/superlocalmemory/hooks/post_tool_outcome_hook.py +223 -0
- package/src/superlocalmemory/hooks/prewarm_auth.py +170 -0
- package/src/superlocalmemory/hooks/session_registry.py +186 -0
- package/src/superlocalmemory/hooks/stop_outcome_hook.py +134 -0
- package/src/superlocalmemory/hooks/sync_loop.py +114 -0
- package/src/superlocalmemory/hooks/user_prompt_hook.py +128 -0
- package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +202 -0
- package/src/superlocalmemory/infra/backup.py +3 -3
- package/src/superlocalmemory/infra/cloud_backup.py +2 -2
- package/src/superlocalmemory/infra/event_bus.py +2 -2
- package/src/superlocalmemory/infra/webhook_dispatcher.py +3 -3
- package/src/superlocalmemory/learning/arm_catalog.py +99 -0
- package/src/superlocalmemory/learning/bandit.py +526 -0
- package/src/superlocalmemory/learning/bandit_cache.py +133 -0
- package/src/superlocalmemory/learning/behavioral.py +53 -1
- package/src/superlocalmemory/learning/consolidation_cycle.py +381 -0
- package/src/superlocalmemory/learning/consolidation_worker.py +188 -520
- package/src/superlocalmemory/learning/database.py +256 -0
- package/src/superlocalmemory/learning/dedup_hnsw.py +413 -0
- package/src/superlocalmemory/learning/ensemble.py +300 -0
- package/src/superlocalmemory/learning/fact_outcome_joins.py +207 -0
- package/src/superlocalmemory/learning/forgetting_scheduler.py +55 -0
- package/src/superlocalmemory/learning/hnsw_dedup.py +69 -0
- package/src/superlocalmemory/learning/labeler.py +87 -0
- package/src/superlocalmemory/learning/legacy_migration.py +277 -0
- package/src/superlocalmemory/learning/memory_merge.py +160 -0
- package/src/superlocalmemory/learning/model_cache.py +269 -0
- package/src/superlocalmemory/learning/model_rollback.py +278 -0
- package/src/superlocalmemory/learning/outcome_queue.py +284 -0
- package/src/superlocalmemory/learning/pattern_miner.py +415 -0
- package/src/superlocalmemory/learning/pattern_miner_constants.py +47 -0
- package/src/superlocalmemory/learning/ranker.py +225 -81
- package/src/superlocalmemory/learning/ranker_common.py +163 -0
- package/src/superlocalmemory/learning/ranker_retrain_legacy.py +202 -0
- package/src/superlocalmemory/learning/ranker_retrain_online.py +411 -0
- package/src/superlocalmemory/learning/reward.py +777 -0
- package/src/superlocalmemory/learning/reward_archive.py +210 -0
- package/src/superlocalmemory/learning/reward_boost.py +201 -0
- package/src/superlocalmemory/learning/reward_proxy.py +326 -0
- package/src/superlocalmemory/learning/shadow_test.py +524 -0
- package/src/superlocalmemory/learning/signal_worker.py +270 -0
- package/src/superlocalmemory/learning/signals.py +314 -0
- package/src/superlocalmemory/learning/trigram_index.py +547 -0
- package/src/superlocalmemory/mcp/server.py +5 -5
- package/src/superlocalmemory/mcp/tools_context.py +183 -0
- package/src/superlocalmemory/mcp/tools_core.py +92 -27
- package/src/superlocalmemory/parameterization/soft_prompt_generator.py +13 -0
- package/src/superlocalmemory/retrieval/engine.py +52 -0
- package/src/superlocalmemory/retrieval/reranker.py +4 -2
- package/src/superlocalmemory/server/api.py +2 -2
- package/src/superlocalmemory/server/bandit_loops.py +140 -0
- package/src/superlocalmemory/server/middleware/__init__.py +11 -0
- package/src/superlocalmemory/server/middleware/security_headers.py +144 -0
- package/src/superlocalmemory/server/routes/backup.py +36 -13
- package/src/superlocalmemory/server/routes/behavioral.py +50 -19
- package/src/superlocalmemory/server/routes/brain.py +1234 -0
- package/src/superlocalmemory/server/routes/data_io.py +4 -4
- package/src/superlocalmemory/server/routes/events.py +2 -2
- package/src/superlocalmemory/server/routes/helpers.py +1 -1
- package/src/superlocalmemory/server/routes/learning.py +192 -7
- package/src/superlocalmemory/server/routes/memories.py +189 -1
- package/src/superlocalmemory/server/routes/prewarm.py +171 -0
- package/src/superlocalmemory/server/routes/profiles.py +3 -3
- package/src/superlocalmemory/server/routes/token.py +88 -0
- package/src/superlocalmemory/server/routes/ws.py +5 -5
- package/src/superlocalmemory/server/security_middleware.py +13 -7
- package/src/superlocalmemory/server/ui.py +2 -2
- package/src/superlocalmemory/server/unified_daemon.py +335 -3
- package/src/superlocalmemory/storage/migration_runner.py +545 -0
- package/src/superlocalmemory/storage/migrations/M001_add_signal_features_columns.py +67 -0
- package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +132 -0
- package/src/superlocalmemory/storage/migrations/M003_migration_log.py +38 -0
- package/src/superlocalmemory/storage/migrations/M004_cross_platform_sync_log.py +46 -0
- package/src/superlocalmemory/storage/migrations/M005_bandit_tables.py +75 -0
- package/src/superlocalmemory/storage/migrations/M006_action_outcomes_reward.py +75 -0
- package/src/superlocalmemory/storage/migrations/M007_pending_outcomes.py +63 -0
- package/src/superlocalmemory/storage/migrations/M009_model_lineage.py +54 -0
- package/src/superlocalmemory/storage/migrations/M010_evolution_config.py +75 -0
- package/src/superlocalmemory/storage/migrations/M011_archive_and_merge.py +87 -0
- package/src/superlocalmemory/storage/migrations/M012_shadow_observations.py +72 -0
- package/src/superlocalmemory/storage/migrations/M013_bi_temporal_columns.py +55 -0
- package/src/superlocalmemory/storage/migrations/__init__.py +81 -0
- package/src/superlocalmemory/storage/models.py +4 -0
- package/src/superlocalmemory/ui/css/brain.css +409 -0
- package/src/superlocalmemory/ui/css/legacy-dashboard.css +645 -0
- package/src/superlocalmemory/ui/index.html +459 -1345
- package/src/superlocalmemory/ui/js/brain.js +1321 -0
- package/src/superlocalmemory/ui/js/clusters.js +123 -4
- package/src/superlocalmemory/ui/js/init.js +48 -39
- package/src/superlocalmemory/ui/js/memories.js +88 -2
- package/src/superlocalmemory/ui/js/modal.js +71 -1
- package/src/superlocalmemory/ui/js/ng-shell.js +101 -88
- package/src/superlocalmemory/ui/js/trust-dashboard.js +168 -25
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/bootstrap-icons.css +2018 -0
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
- package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/bootstrap.bundle.min.js +7 -0
- package/src/superlocalmemory/ui/vendor/bootstrap.min.css +6 -0
- package/src/superlocalmemory/ui/vendor/d3.v7.min.js +2 -0
- package/src/superlocalmemory/ui/vendor/graphology-library.min.js +2 -0
- package/src/superlocalmemory/ui/vendor/graphology.umd.min.js +2 -0
- package/src/superlocalmemory/ui/vendor/inter-ui/inter-variable.min.css +8 -0
- package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable-Italic.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable.woff2 +0 -0
- package/src/superlocalmemory/ui/vendor/sigma.min.js +1 -0
- package/src/superlocalmemory/ui/js/behavioral.js +0 -447
- package/src/superlocalmemory/ui/js/graph-core.js +0 -447
- package/src/superlocalmemory/ui/js/graph-interactions.js +0 -351
- package/src/superlocalmemory/ui/js/learning.js +0 -435
- package/src/superlocalmemory/ui/js/patterns.js +0 -93
- package/src/superlocalmemory.egg-info/PKG-INFO +0 -647
- package/src/superlocalmemory.egg-info/SOURCES.txt +0 -335
- package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
- package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
- package/src/superlocalmemory.egg-info/requires.txt +0 -58
- package/src/superlocalmemory.egg-info/top_level.txt +0 -1
|
@@ -1,435 +0,0 @@
|
|
|
1
|
-
// SuperLocalMemory V2 - Learning System Dashboard (v2.7)
|
|
2
|
-
// Copyright (c) 2026 Varun Pratap Bhardwaj - Elastic License 2.0
|
|
3
|
-
// NOTE: All dynamic values pass through escapeHtml() from core.js before DOM insertion.
|
|
4
|
-
|
|
5
|
-
var _learningData = null;
|
|
6
|
-
|
|
7
|
-
async function loadLearning() {
|
|
8
|
-
try {
|
|
9
|
-
var response = await fetch('/api/learning/status');
|
|
10
|
-
var data = await response.json();
|
|
11
|
-
_learningData = data;
|
|
12
|
-
renderLearningStatus(data);
|
|
13
|
-
} catch (error) {
|
|
14
|
-
console.error('Error loading learning status:', error);
|
|
15
|
-
var el = document.getElementById('learning-phase');
|
|
16
|
-
if (el) el.textContent = 'Unavailable';
|
|
17
|
-
var detail = document.getElementById('learning-phase-detail');
|
|
18
|
-
if (detail) detail.textContent = 'Learning system not available';
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function renderLearningStatus(data) {
|
|
23
|
-
renderPhase(data);
|
|
24
|
-
renderFeedbackCount(data.stats);
|
|
25
|
-
renderEngagementHealth(data.engagement);
|
|
26
|
-
renderProgressBar(data.stats ? data.stats.feedback_count : 0);
|
|
27
|
-
renderWhatWeLearned(data);
|
|
28
|
-
renderTechPreferences(data.tech_preferences || []);
|
|
29
|
-
renderWorkflowPatterns(data.workflow_patterns || []);
|
|
30
|
-
renderSourceQuality(data.source_scores || {});
|
|
31
|
-
renderPrivacyStats(data.stats);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function renderWhatWeLearned(data) {
|
|
35
|
-
var container = document.getElementById('what-we-learned-content');
|
|
36
|
-
var profileBadge = document.getElementById('learned-profile-badge');
|
|
37
|
-
if (!container) return;
|
|
38
|
-
container.textContent = '';
|
|
39
|
-
|
|
40
|
-
// Show active profile
|
|
41
|
-
if (profileBadge && data.stats && data.stats.active_profile) {
|
|
42
|
-
profileBadge.textContent = data.stats.active_profile;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
var insights = [];
|
|
46
|
-
|
|
47
|
-
// Collect tech preference insights
|
|
48
|
-
var techPrefs = data.tech_preferences || [];
|
|
49
|
-
var highConfTech = techPrefs.filter(function(p) { return p.confidence >= 0.6; });
|
|
50
|
-
if (highConfTech.length > 0) {
|
|
51
|
-
var techNames = highConfTech.map(function(p) { return p.value; }).slice(0, 5);
|
|
52
|
-
insights.push({
|
|
53
|
-
icon: 'bi-cpu',
|
|
54
|
-
color: 'text-primary',
|
|
55
|
-
text: 'You prefer: ' + techNames.join(', '),
|
|
56
|
-
detail: highConfTech.length + ' tech preferences learned',
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Collect workflow insights
|
|
61
|
-
var workflows = data.workflow_patterns || [];
|
|
62
|
-
var sequences = workflows.filter(function(w) { return w.type === 'sequence'; });
|
|
63
|
-
var temporal = workflows.filter(function(w) { return w.type === 'temporal'; });
|
|
64
|
-
if (sequences.length > 0) {
|
|
65
|
-
insights.push({
|
|
66
|
-
icon: 'bi-diagram-3',
|
|
67
|
-
color: 'text-info',
|
|
68
|
-
text: sequences.length + ' workflow sequence' + (sequences.length > 1 ? 's' : '') + ' detected',
|
|
69
|
-
detail: 'Common patterns in how you work',
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
if (temporal.length > 0) {
|
|
73
|
-
insights.push({
|
|
74
|
-
icon: 'bi-clock',
|
|
75
|
-
color: 'text-warning',
|
|
76
|
-
text: temporal.length + ' time-based pattern' + (temporal.length > 1 ? 's' : '') + ' found',
|
|
77
|
-
detail: 'When you tend to work on what',
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Source quality insights
|
|
82
|
-
var sources = data.source_scores || {};
|
|
83
|
-
var sourceCount = Object.keys(sources).length;
|
|
84
|
-
if (sourceCount > 0) {
|
|
85
|
-
var bestSource = Object.entries(sources).sort(function(a, b) { return b[1] - a[1]; })[0];
|
|
86
|
-
insights.push({
|
|
87
|
-
icon: 'bi-trophy',
|
|
88
|
-
color: 'text-success',
|
|
89
|
-
text: 'Best source: ' + bestSource[0] + ' (' + Math.round(bestSource[1] * 100) + '% quality)',
|
|
90
|
-
detail: sourceCount + ' sources tracked',
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Feedback volume insight
|
|
95
|
-
var feedbackCount = (data.stats && data.stats.feedback_count) || 0;
|
|
96
|
-
if (feedbackCount > 0) {
|
|
97
|
-
var phase = data.ranking_phase || 'baseline';
|
|
98
|
-
var phaseLabel = {baseline: 'collecting data', rule_based: 'learning your preferences', ml_model: 'fully personalized'}[phase] || phase;
|
|
99
|
-
insights.push({
|
|
100
|
-
icon: 'bi-graph-up',
|
|
101
|
-
color: 'text-success',
|
|
102
|
-
text: feedbackCount + ' feedback signals collected',
|
|
103
|
-
detail: 'Currently ' + phaseLabel,
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Render insights
|
|
108
|
-
if (insights.length === 0) {
|
|
109
|
-
var empty = document.createElement('div');
|
|
110
|
-
empty.className = 'text-center text-muted py-3';
|
|
111
|
-
var emptyIcon = document.createElement('i');
|
|
112
|
-
emptyIcon.className = 'bi bi-lightbulb';
|
|
113
|
-
emptyIcon.style.fontSize = '2rem';
|
|
114
|
-
empty.appendChild(emptyIcon);
|
|
115
|
-
var emptyText = document.createElement('p');
|
|
116
|
-
emptyText.className = 'mt-2 mb-0 small';
|
|
117
|
-
emptyText.textContent = 'Start using recall and giving feedback. SuperLocalMemory will learn your preferences automatically.';
|
|
118
|
-
empty.appendChild(emptyText);
|
|
119
|
-
container.appendChild(empty);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
for (var i = 0; i < insights.length; i++) {
|
|
124
|
-
var insight = insights[i];
|
|
125
|
-
var row = document.createElement('div');
|
|
126
|
-
row.className = 'd-flex align-items-start mb-2 p-2 rounded';
|
|
127
|
-
row.style.backgroundColor = 'var(--bs-body-bg)';
|
|
128
|
-
|
|
129
|
-
var icon = document.createElement('i');
|
|
130
|
-
icon.className = 'bi ' + insight.icon + ' ' + insight.color + ' me-3';
|
|
131
|
-
icon.style.fontSize = '1.3rem';
|
|
132
|
-
icon.style.marginTop = '2px';
|
|
133
|
-
|
|
134
|
-
var textDiv = document.createElement('div');
|
|
135
|
-
var mainText = document.createElement('div');
|
|
136
|
-
mainText.className = 'fw-semibold';
|
|
137
|
-
mainText.textContent = insight.text;
|
|
138
|
-
var detailText = document.createElement('small');
|
|
139
|
-
detailText.className = 'text-muted';
|
|
140
|
-
detailText.textContent = insight.detail;
|
|
141
|
-
textDiv.appendChild(mainText);
|
|
142
|
-
textDiv.appendChild(detailText);
|
|
143
|
-
|
|
144
|
-
row.appendChild(icon);
|
|
145
|
-
row.appendChild(textDiv);
|
|
146
|
-
container.appendChild(row);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function renderPhase(data) {
|
|
151
|
-
var phaseEl = document.getElementById('learning-phase');
|
|
152
|
-
var phaseDetail = document.getElementById('learning-phase-detail');
|
|
153
|
-
if (!phaseEl) return;
|
|
154
|
-
|
|
155
|
-
if (!data.ranking_phase) {
|
|
156
|
-
phaseEl.textContent = 'Not Available';
|
|
157
|
-
phaseEl.style.color = 'var(--bs-secondary)';
|
|
158
|
-
if (phaseDetail) phaseDetail.textContent = 'Install: pip3 install lightgbm scipy';
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
var labels = { 'baseline': 'Baseline', 'rule_based': 'Rule-Based', 'ml_model': 'ML Model' };
|
|
163
|
-
var colors = { 'baseline': 'var(--bs-secondary)', 'rule_based': 'var(--bs-primary)', 'ml_model': 'var(--bs-warning)' };
|
|
164
|
-
phaseEl.textContent = labels[data.ranking_phase] || data.ranking_phase;
|
|
165
|
-
phaseEl.style.color = colors[data.ranking_phase] || 'var(--bs-primary)';
|
|
166
|
-
|
|
167
|
-
var fc = (data.stats && data.stats.feedback_count) || 0;
|
|
168
|
-
if (phaseDetail) {
|
|
169
|
-
if (data.ranking_phase === 'baseline') phaseDetail.textContent = 'Need 20+ signals. Currently: ' + fc;
|
|
170
|
-
else if (data.ranking_phase === 'rule_based') phaseDetail.textContent = 'Active! Need 200+ for ML. Currently: ' + fc;
|
|
171
|
-
else phaseDetail.textContent = 'Full ML ranking with ' + fc + ' signals';
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function renderFeedbackCount(stats) {
|
|
176
|
-
var el = document.getElementById('learning-feedback-count');
|
|
177
|
-
var detail = document.getElementById('learning-feedback-detail');
|
|
178
|
-
if (el && stats) el.textContent = stats.feedback_count || 0;
|
|
179
|
-
if (detail && stats) detail.textContent = (stats.unique_queries || 0) + ' unique queries';
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function renderEngagementHealth(engagement) {
|
|
183
|
-
var el = document.getElementById('learning-health');
|
|
184
|
-
var detail = document.getElementById('learning-health-detail');
|
|
185
|
-
if (!el) return;
|
|
186
|
-
if (!engagement) { el.textContent = '--'; return; }
|
|
187
|
-
|
|
188
|
-
var status = engagement.health_status || 'UNKNOWN';
|
|
189
|
-
var colors = { 'HEALTHY': 'var(--bs-success)', 'DECLINING': 'var(--bs-warning)', 'AT_RISK': 'var(--bs-danger)', 'INACTIVE': 'var(--bs-secondary)' };
|
|
190
|
-
el.textContent = status;
|
|
191
|
-
el.style.color = colors[status] || 'var(--bs-secondary)';
|
|
192
|
-
if (detail) {
|
|
193
|
-
var p = [];
|
|
194
|
-
if (engagement.days_active !== undefined) p.push(engagement.days_active + ' days active');
|
|
195
|
-
if (engagement.memories_per_day !== undefined) p.push(engagement.memories_per_day.toFixed(1) + ' mem/day');
|
|
196
|
-
detail.textContent = p.join(' | ') || 'No data';
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function renderProgressBar(count) {
|
|
201
|
-
var bar = document.getElementById('learning-progress');
|
|
202
|
-
if (!bar) return;
|
|
203
|
-
var pct = 0, cls = 'bg-secondary', lbl = '';
|
|
204
|
-
|
|
205
|
-
if (count >= 200) { pct = 100; cls = 'bg-warning'; lbl = 'ML Model Active'; }
|
|
206
|
-
else if (count >= 20) { pct = 10 + ((count - 20) / 180) * 60; cls = 'bg-primary'; lbl = 'Rule-Based (' + count + '/200)'; }
|
|
207
|
-
else if (count > 0) { pct = (count / 20) * 10; lbl = 'Baseline (' + count + '/20)'; }
|
|
208
|
-
else { lbl = 'No feedback yet'; }
|
|
209
|
-
|
|
210
|
-
bar.style.width = Math.min(pct, 100) + '%';
|
|
211
|
-
bar.className = 'progress-bar ' + cls;
|
|
212
|
-
bar.textContent = lbl;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
function renderTechPreferences(patterns) {
|
|
216
|
-
var container = document.getElementById('learning-tech-prefs');
|
|
217
|
-
if (!container) return;
|
|
218
|
-
container.textContent = '';
|
|
219
|
-
|
|
220
|
-
if (!patterns || patterns.length === 0) {
|
|
221
|
-
var empty = document.createElement('div');
|
|
222
|
-
empty.className = 'text-center text-muted py-3';
|
|
223
|
-
empty.textContent = 'No patterns yet. Use recall + feedback to start learning.';
|
|
224
|
-
container.appendChild(empty);
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
for (var i = 0; i < patterns.length; i++) {
|
|
229
|
-
var p = patterns[i];
|
|
230
|
-
var confPct = Math.round((p.confidence || 0) * 100);
|
|
231
|
-
var barColor = confPct >= 80 ? 'bg-success' : (confPct >= 60 ? 'bg-primary' : 'bg-secondary');
|
|
232
|
-
|
|
233
|
-
var row = document.createElement('div');
|
|
234
|
-
row.className = 'd-flex align-items-center mb-2';
|
|
235
|
-
|
|
236
|
-
var label = document.createElement('div');
|
|
237
|
-
label.style.minWidth = '120px';
|
|
238
|
-
var labelSpan = document.createElement('span');
|
|
239
|
-
labelSpan.className = 'text-muted small';
|
|
240
|
-
labelSpan.textContent = p.key || '';
|
|
241
|
-
label.appendChild(labelSpan);
|
|
242
|
-
|
|
243
|
-
var barWrap = document.createElement('div');
|
|
244
|
-
barWrap.className = 'flex-grow-1 mx-2';
|
|
245
|
-
var progress = document.createElement('div');
|
|
246
|
-
progress.className = 'progress';
|
|
247
|
-
progress.style.height = '18px';
|
|
248
|
-
progress.style.borderRadius = '9px';
|
|
249
|
-
var barEl = document.createElement('div');
|
|
250
|
-
barEl.className = 'progress-bar ' + barColor;
|
|
251
|
-
barEl.style.width = confPct + '%';
|
|
252
|
-
barEl.style.borderRadius = '9px';
|
|
253
|
-
barEl.style.fontSize = '0.7rem';
|
|
254
|
-
barEl.textContent = (p.value || '') + ' (' + confPct + '%)';
|
|
255
|
-
progress.appendChild(barEl);
|
|
256
|
-
barWrap.appendChild(progress);
|
|
257
|
-
|
|
258
|
-
var evidence = document.createElement('small');
|
|
259
|
-
evidence.className = 'text-muted';
|
|
260
|
-
evidence.style.minWidth = '60px';
|
|
261
|
-
evidence.style.textAlign = 'right';
|
|
262
|
-
evidence.textContent = (p.evidence || 0) + ' ev.';
|
|
263
|
-
|
|
264
|
-
row.appendChild(label);
|
|
265
|
-
row.appendChild(barWrap);
|
|
266
|
-
row.appendChild(evidence);
|
|
267
|
-
container.appendChild(row);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function renderWorkflowPatterns(workflows) {
|
|
272
|
-
var container = document.getElementById('learning-workflows');
|
|
273
|
-
if (!container) return;
|
|
274
|
-
container.textContent = '';
|
|
275
|
-
|
|
276
|
-
if (!workflows || workflows.length === 0) {
|
|
277
|
-
var empty = document.createElement('div');
|
|
278
|
-
empty.className = 'text-center text-muted py-3';
|
|
279
|
-
empty.textContent = 'Sequences detected after 30+ memories.';
|
|
280
|
-
container.appendChild(empty);
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
for (var i = 0; i < workflows.length; i++) {
|
|
285
|
-
var w = workflows[i];
|
|
286
|
-
var card = document.createElement('div');
|
|
287
|
-
card.className = 'mb-2 p-2 border rounded';
|
|
288
|
-
|
|
289
|
-
if (w.type === 'sequence') {
|
|
290
|
-
var seq = [];
|
|
291
|
-
try { seq = JSON.parse(w.value); } catch(e) { seq = [String(w.value)]; }
|
|
292
|
-
var flowDiv = document.createElement('div');
|
|
293
|
-
flowDiv.className = 'd-flex align-items-center flex-wrap gap-1';
|
|
294
|
-
for (var j = 0; j < seq.length; j++) {
|
|
295
|
-
if (j > 0) {
|
|
296
|
-
var arrow = document.createElement('i');
|
|
297
|
-
arrow.className = 'bi bi-arrow-right text-muted small';
|
|
298
|
-
flowDiv.appendChild(arrow);
|
|
299
|
-
}
|
|
300
|
-
var badge = document.createElement('span');
|
|
301
|
-
badge.className = 'badge bg-primary bg-opacity-75';
|
|
302
|
-
badge.textContent = seq[j];
|
|
303
|
-
flowDiv.appendChild(badge);
|
|
304
|
-
}
|
|
305
|
-
card.appendChild(flowDiv);
|
|
306
|
-
} else if (w.type === 'temporal') {
|
|
307
|
-
// Parse temporal pattern: show "Morning: code (26%)" format
|
|
308
|
-
var parsed = {};
|
|
309
|
-
try { parsed = JSON.parse(w.value); } catch(e) { parsed = {}; }
|
|
310
|
-
var timeBadge = document.createElement('span');
|
|
311
|
-
timeBadge.className = 'badge bg-info bg-opacity-75 me-2';
|
|
312
|
-
timeBadge.textContent = (w.key || '').charAt(0).toUpperCase() + (w.key || '').slice(1);
|
|
313
|
-
card.appendChild(timeBadge);
|
|
314
|
-
|
|
315
|
-
var activity = document.createElement('span');
|
|
316
|
-
activity.className = 'fw-bold';
|
|
317
|
-
activity.textContent = parsed.dominant_activity || w.value;
|
|
318
|
-
card.appendChild(activity);
|
|
319
|
-
|
|
320
|
-
var evCount = document.createElement('small');
|
|
321
|
-
evCount.className = 'text-muted ms-2';
|
|
322
|
-
evCount.textContent = '(' + (parsed.evidence_count || 0) + ' memories)';
|
|
323
|
-
card.appendChild(evCount);
|
|
324
|
-
|
|
325
|
-
// Show distribution as mini bar
|
|
326
|
-
if (parsed.distribution) {
|
|
327
|
-
var distDiv = document.createElement('div');
|
|
328
|
-
distDiv.className = 'd-flex flex-wrap gap-1 mt-1';
|
|
329
|
-
var sortedActivities = Object.entries(parsed.distribution).sort(function(a, b) { return b[1] - a[1]; });
|
|
330
|
-
var total = sortedActivities.reduce(function(s, e) { return s + e[1]; }, 0);
|
|
331
|
-
for (var k = 0; k < sortedActivities.length; k++) {
|
|
332
|
-
var actName = sortedActivities[k][0];
|
|
333
|
-
var actCount = sortedActivities[k][1];
|
|
334
|
-
var actPct = Math.round((actCount / total) * 100);
|
|
335
|
-
var actBadge = document.createElement('span');
|
|
336
|
-
actBadge.className = 'badge bg-light text-dark';
|
|
337
|
-
actBadge.style.fontSize = '0.65rem';
|
|
338
|
-
actBadge.textContent = actName + ' ' + actPct + '%';
|
|
339
|
-
distDiv.appendChild(actBadge);
|
|
340
|
-
}
|
|
341
|
-
card.appendChild(distDiv);
|
|
342
|
-
}
|
|
343
|
-
} else {
|
|
344
|
-
var typeBadge = document.createElement('span');
|
|
345
|
-
typeBadge.className = 'badge bg-info bg-opacity-75';
|
|
346
|
-
typeBadge.textContent = w.key || w.type;
|
|
347
|
-
card.appendChild(typeBadge);
|
|
348
|
-
var valSpan = document.createElement('span');
|
|
349
|
-
valSpan.className = 'small ms-1';
|
|
350
|
-
valSpan.textContent = w.value || '';
|
|
351
|
-
card.appendChild(valSpan);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
var confSmall = document.createElement('small');
|
|
355
|
-
confSmall.className = 'text-muted d-block';
|
|
356
|
-
confSmall.textContent = 'Confidence: ' + Math.round((w.confidence || 0) * 100) + '%';
|
|
357
|
-
card.appendChild(confSmall);
|
|
358
|
-
container.appendChild(card);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
function renderSourceQuality(scores) {
|
|
363
|
-
var container = document.getElementById('learning-sources');
|
|
364
|
-
if (!container) return;
|
|
365
|
-
container.textContent = '';
|
|
366
|
-
|
|
367
|
-
var sources = Object.keys(scores);
|
|
368
|
-
if (sources.length === 0) {
|
|
369
|
-
var empty = document.createElement('div');
|
|
370
|
-
empty.className = 'text-center text-muted py-3';
|
|
371
|
-
empty.textContent = 'Source quality computed after feedback signals.';
|
|
372
|
-
container.appendChild(empty);
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
sources.sort(function(a, b) { return scores[b] - scores[a]; });
|
|
377
|
-
|
|
378
|
-
for (var i = 0; i < sources.length; i++) {
|
|
379
|
-
var src = sources[i];
|
|
380
|
-
var pct = Math.round(scores[src] * 100);
|
|
381
|
-
var barColor = pct >= 60 ? 'bg-success' : (pct >= 40 ? 'bg-warning' : 'bg-danger');
|
|
382
|
-
|
|
383
|
-
var row = document.createElement('div');
|
|
384
|
-
row.className = 'd-flex align-items-center mb-2';
|
|
385
|
-
|
|
386
|
-
var label = document.createElement('div');
|
|
387
|
-
label.style.minWidth = '140px';
|
|
388
|
-
var code = document.createElement('code');
|
|
389
|
-
code.className = 'small';
|
|
390
|
-
code.textContent = src;
|
|
391
|
-
label.appendChild(code);
|
|
392
|
-
|
|
393
|
-
var barWrap = document.createElement('div');
|
|
394
|
-
barWrap.className = 'flex-grow-1 mx-2';
|
|
395
|
-
var progress = document.createElement('div');
|
|
396
|
-
progress.className = 'progress';
|
|
397
|
-
progress.style.height = '16px';
|
|
398
|
-
progress.style.borderRadius = '8px';
|
|
399
|
-
var barEl = document.createElement('div');
|
|
400
|
-
barEl.className = 'progress-bar ' + barColor;
|
|
401
|
-
barEl.style.width = pct + '%';
|
|
402
|
-
barEl.style.borderRadius = '8px';
|
|
403
|
-
barEl.style.fontSize = '0.65rem';
|
|
404
|
-
barEl.textContent = pct + '%';
|
|
405
|
-
progress.appendChild(barEl);
|
|
406
|
-
barWrap.appendChild(progress);
|
|
407
|
-
|
|
408
|
-
row.appendChild(label);
|
|
409
|
-
row.appendChild(barWrap);
|
|
410
|
-
container.appendChild(row);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
function renderPrivacyStats(stats) {
|
|
415
|
-
if (!stats) return;
|
|
416
|
-
var el;
|
|
417
|
-
el = document.getElementById('learning-db-size');
|
|
418
|
-
if (el) el.textContent = (stats.db_size_kb || 0) + ' KB';
|
|
419
|
-
el = document.getElementById('learning-pattern-count');
|
|
420
|
-
if (el) el.textContent = stats.transferable_patterns || 0;
|
|
421
|
-
el = document.getElementById('learning-model-count');
|
|
422
|
-
if (el) el.textContent = stats.models_trained || 0;
|
|
423
|
-
el = document.getElementById('learning-source-count');
|
|
424
|
-
if (el) el.textContent = stats.tracked_sources || 0;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
async function resetLearning() {
|
|
428
|
-
if (!confirm('Delete all learning data? Memories will be preserved.')) return;
|
|
429
|
-
try {
|
|
430
|
-
var response = await fetch('/api/learning/reset', { method: 'POST' });
|
|
431
|
-
var data = await response.json();
|
|
432
|
-
if (data.success) { alert('Learning data reset. Memories preserved.'); loadLearning(); }
|
|
433
|
-
else alert('Reset failed: ' + (data.error || 'Unknown error'));
|
|
434
|
-
} catch (error) { alert('Reset failed: ' + error.message); }
|
|
435
|
-
}
|
|
@@ -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
|
-
}
|