superlocalmemory 3.7.6 → 3.7.8

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 (34) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +2 -2
  3. package/package.json +2 -2
  4. package/plugin/.claude-plugin/plugin.json +1 -1
  5. package/plugin/requirements.txt +1 -1
  6. package/plugin-src/manifest.json +1 -1
  7. package/plugin-src/requirements.txt +1 -1
  8. package/pyproject.toml +6 -7
  9. package/src/superlocalmemory/__init__.py +1 -1
  10. package/src/superlocalmemory/cli/commands.py +171 -11
  11. package/src/superlocalmemory/cli/setup_wizard.py +18 -1
  12. package/src/superlocalmemory/infra/auth_middleware.py +33 -5
  13. package/src/superlocalmemory/mcp/_daemon_proxy.py +8 -10
  14. package/src/superlocalmemory/mcp/server.py +1 -0
  15. package/src/superlocalmemory/mcp/tools_core.py +216 -20
  16. package/src/superlocalmemory/optimize/cache/centroid_store.py +21 -3
  17. package/src/superlocalmemory/optimize/cache/manager.py +7 -0
  18. package/src/superlocalmemory/optimize/cache/semantic.py +27 -10
  19. package/src/superlocalmemory/server/api.py +17 -0
  20. package/src/superlocalmemory/server/profile_runtime.py +384 -0
  21. package/src/superlocalmemory/server/recall_health.py +12 -6
  22. package/src/superlocalmemory/server/routes/chat.py +63 -12
  23. package/src/superlocalmemory/server/routes/helpers.py +9 -16
  24. package/src/superlocalmemory/server/routes/memories.py +58 -11
  25. package/src/superlocalmemory/server/routes/profiles.py +24 -14
  26. package/src/superlocalmemory/server/routes/v3_api.py +128 -52
  27. package/src/superlocalmemory/server/ui.py +10 -0
  28. package/src/superlocalmemory/server/unified_daemon.py +290 -74
  29. package/src/superlocalmemory/storage/migration_runner.py +17 -3
  30. package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +32 -3
  31. package/src/superlocalmemory/storage/schema_v32.py +0 -9
  32. package/src/superlocalmemory/ui/index.html +32 -1
  33. package/src/superlocalmemory/ui/js/auto-settings.js +48 -0
  34. package/src/superlocalmemory/ui/js/profiles.js +11 -2
@@ -1058,11 +1058,42 @@
1058
1058
  </button>
1059
1059
  <span id="settings-emb-test-result" class="ms-2 small"></span>
1060
1060
  </div>
1061
- <div id="settings-emb-info" class="small text-muted mt-1">
1061
+ <div id="settings-emb-info" class="small text-muted mt-1">
1062
1062
  Using local <strong>nomic-embed-text-v1.5</strong> (768d)
1063
1063
  </div>
1064
1064
  </div>
1065
1065
 
1066
+ <!-- Step 4: Scope defaults (shared/global remain opt-in) -->
1067
+ <div class="mt-3 pt-3 border-top" id="settings-scope-panel">
1068
+ <h6 class="text-muted"><i class="bi bi-shield-lock"></i> Step 4: Memory Visibility</h6>
1069
+ <p class="small text-muted mb-2">
1070
+ Personal-only is the privacy-safe default. Enable broader visibility deliberately.
1071
+ </p>
1072
+ <div class="row g-2 align-items-end">
1073
+ <div class="col-md-4">
1074
+ <label class="form-label small" for="settings-default-scope">Default write scope</label>
1075
+ <select class="form-select form-select-sm" id="settings-default-scope">
1076
+ <option value="personal">Personal (recommended)</option>
1077
+ <option value="shared">Shared</option>
1078
+ <option value="global">Global</option>
1079
+ </select>
1080
+ </div>
1081
+ <div class="col-md-4">
1082
+ <div class="form-check form-switch">
1083
+ <input class="form-check-input" type="checkbox" id="settings-recall-shared">
1084
+ <label class="form-check-label small" for="settings-recall-shared">Include shared memories by default</label>
1085
+ </div>
1086
+ </div>
1087
+ <div class="col-md-4">
1088
+ <div class="form-check form-switch">
1089
+ <input class="form-check-input" type="checkbox" id="settings-recall-global">
1090
+ <label class="form-check-label small" for="settings-recall-global">Include global memories by default</label>
1091
+ </div>
1092
+ </div>
1093
+ </div>
1094
+ <div id="settings-scope-status" class="small text-muted mt-2"></div>
1095
+ </div>
1096
+
1066
1097
  <!-- Save button -->
1067
1098
  <div class="mt-3">
1068
1099
  <button class="btn btn-primary" id="settings-save-all">
@@ -27,6 +27,50 @@ async function loadAutoSettings() {
27
27
  }
28
28
  }
29
29
 
30
+ async function loadScopeSettings() {
31
+ try {
32
+ var response = await fetch('/api/v3/scope/config');
33
+ if (!response.ok) throw new Error('HTTP ' + response.status);
34
+ var data = await response.json();
35
+ var defaultScope = document.getElementById('settings-default-scope');
36
+ var shared = document.getElementById('settings-recall-shared');
37
+ var globalScope = document.getElementById('settings-recall-global');
38
+ if (defaultScope) defaultScope.value = data.default_scope || 'personal';
39
+ if (shared) shared.checked = data.recall_include_shared === true;
40
+ if (globalScope) globalScope.checked = data.recall_include_global === true;
41
+ } catch (error) {
42
+ var status = document.getElementById('settings-scope-status');
43
+ if (status) status.textContent = 'Could not load runtime visibility settings.';
44
+ }
45
+ }
46
+
47
+ async function saveScopeSettings() {
48
+ var status = document.getElementById('settings-scope-status');
49
+ var payload = {
50
+ default_scope: document.getElementById('settings-default-scope')?.value || 'personal',
51
+ recall_include_shared: document.getElementById('settings-recall-shared')?.checked === true,
52
+ recall_include_global: document.getElementById('settings-recall-global')?.checked === true,
53
+ };
54
+ if (status) status.textContent = 'Applying to daemon...';
55
+ try {
56
+ var response = await fetch('/api/v3/scope/config', {
57
+ method: 'PUT',
58
+ headers: {'Content-Type': 'application/json'},
59
+ body: JSON.stringify(payload),
60
+ });
61
+ var data = await response.json();
62
+ if (!response.ok || data.success !== true) {
63
+ throw new Error(data.error || 'daemon rejected visibility settings');
64
+ }
65
+ if (status) status.textContent = 'Applied to the resident daemon.';
66
+ return true;
67
+ } catch (error) {
68
+ if (status) status.textContent = 'Not applied: ' + error.message;
69
+ await loadScopeSettings();
70
+ return false;
71
+ }
72
+ }
73
+
30
74
  function saveAutoCaptureConfig() {
31
75
  var payload = {
32
76
  enabled: document.getElementById('auto-capture-toggle')?.checked,
@@ -533,6 +577,9 @@ document.getElementById('settings-save-all')?.addEventListener('click', saveAllS
533
577
  document.getElementById('settings-test-btn')?.addEventListener('click', testConnection);
534
578
  document.getElementById('settings-emb-provider')?.addEventListener('change', updateEmbeddingUI);
535
579
  document.getElementById('settings-emb-test-btn')?.addEventListener('click', testEmbeddingEndpoint);
580
+ ['settings-default-scope', 'settings-recall-shared', 'settings-recall-global'].forEach(function(id) {
581
+ document.getElementById(id)?.addEventListener('change', saveScopeSettings);
582
+ });
536
583
 
537
584
  // Mode radio buttons
538
585
  document.querySelectorAll('input[name="settings-mode-radio"]').forEach(function(radio) {
@@ -542,6 +589,7 @@ document.querySelectorAll('input[name="settings-mode-radio"]').forEach(function(
542
589
  // Load settings when the settings tab is shown
543
590
  document.getElementById('settings-tab')?.addEventListener('shown.bs.tab', function() {
544
591
  loadAutoSettings();
592
+ loadScopeSettings();
545
593
  loadModeSettings();
546
594
  loadEmbeddingSettings();
547
595
  updateModeUI();
@@ -206,7 +206,9 @@ async function switchProfile(profileName) {
206
206
  method: 'POST'
207
207
  });
208
208
  var data = await response.json();
209
- if (data.success || data.active_profile) {
209
+ var acknowledged = response.ok && data.success === true &&
210
+ data.active_profile === profileName && Number.isInteger(data.generation);
211
+ if (acknowledged) {
210
212
  showToast('Switched to profile: ' + profileName);
211
213
  loadProfiles();
212
214
  loadStats();
@@ -226,11 +228,18 @@ async function switchProfile(profileName) {
226
228
  if (typeof loadCompliance === 'function') loadCompliance();
227
229
  var activeTab = document.querySelector('#mainTabs .nav-link.active');
228
230
  if (activeTab) activeTab.click();
231
+ return true;
229
232
  } else {
230
- showToast('Failed to switch profile');
233
+ showToast(data.detail || 'Daemon did not acknowledge the requested profile');
234
+ // Restore the selector from daemon runtime truth after any failure
235
+ // or mismatched acknowledgement.
236
+ loadProfiles();
237
+ return false;
231
238
  }
232
239
  } catch (error) {
233
240
  console.error('Error switching profile:', error);
234
241
  showToast('Error switching profile');
242
+ loadProfiles();
243
+ return false;
235
244
  }
236
245
  }