superlocalmemory 3.4.19 → 3.4.22

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 (177) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +42 -34
  3. package/bin/slm +11 -0
  4. package/bin/slm.bat +12 -0
  5. package/package.json +4 -3
  6. package/pyproject.toml +4 -3
  7. package/scripts/build-slm-hook.ps1 +40 -0
  8. package/scripts/build-slm-hook.sh +45 -0
  9. package/scripts/build_entry.py +452 -0
  10. package/scripts/ci/stage5b_gate.sh +50 -0
  11. package/scripts/postinstall/validation.js +187 -0
  12. package/scripts/postinstall-interactive.js +756 -0
  13. package/scripts/postinstall_binary.js +287 -0
  14. package/scripts/release_manifest.py +273 -0
  15. package/scripts/slm-hook.spec +56 -0
  16. package/skills/slm-build-graph/SKILL.md +423 -0
  17. package/skills/slm-list-recent/SKILL.md +348 -0
  18. package/skills/slm-recall/SKILL.md +343 -0
  19. package/skills/slm-remember/SKILL.md +194 -0
  20. package/skills/slm-show-patterns/SKILL.md +224 -0
  21. package/skills/slm-status/SKILL.md +363 -0
  22. package/skills/slm-switch-profile/SKILL.md +442 -0
  23. package/src/superlocalmemory/cli/commands.py +254 -79
  24. package/src/superlocalmemory/cli/context_commands.py +192 -0
  25. package/src/superlocalmemory/cli/daemon.py +15 -1
  26. package/src/superlocalmemory/cli/db_migrate.py +80 -0
  27. package/src/superlocalmemory/cli/escape_hatch.py +220 -0
  28. package/src/superlocalmemory/cli/main.py +72 -1
  29. package/src/superlocalmemory/core/context_cache.py +397 -0
  30. package/src/superlocalmemory/core/engine.py +38 -2
  31. package/src/superlocalmemory/core/engine_wiring.py +1 -1
  32. package/src/superlocalmemory/core/ram_lock.py +111 -0
  33. package/src/superlocalmemory/core/recall_pipeline.py +433 -3
  34. package/src/superlocalmemory/core/recall_worker.py +8 -3
  35. package/src/superlocalmemory/core/security_primitives.py +635 -0
  36. package/src/superlocalmemory/core/shadow_router.py +319 -0
  37. package/src/superlocalmemory/core/slm_disabled.py +87 -0
  38. package/src/superlocalmemory/core/slmignore.py +125 -0
  39. package/src/superlocalmemory/core/topic_signature.py +143 -0
  40. package/src/superlocalmemory/core/worker_pool.py +14 -3
  41. package/src/superlocalmemory/encoding/cognitive_consolidator.py +2 -2
  42. package/src/superlocalmemory/evolution/budget.py +321 -0
  43. package/src/superlocalmemory/evolution/llm_dispatch.py +508 -0
  44. package/src/superlocalmemory/evolution/skill_evolver.py +144 -94
  45. package/src/superlocalmemory/hooks/_outcome_common.py +506 -0
  46. package/src/superlocalmemory/hooks/adapter_base.py +317 -0
  47. package/src/superlocalmemory/hooks/antigravity_adapter.py +192 -0
  48. package/src/superlocalmemory/hooks/claude_code_hooks.py +33 -1
  49. package/src/superlocalmemory/hooks/context_payload.py +312 -0
  50. package/src/superlocalmemory/hooks/copilot_adapter.py +154 -0
  51. package/src/superlocalmemory/hooks/cross_platform_connector.py +90 -0
  52. package/src/superlocalmemory/hooks/cursor_adapter.py +195 -0
  53. package/src/superlocalmemory/hooks/hook_handlers.py +109 -8
  54. package/src/superlocalmemory/hooks/ide_connector.py +25 -2
  55. package/src/superlocalmemory/hooks/post_tool_async_hook.py +165 -0
  56. package/src/superlocalmemory/hooks/post_tool_outcome_hook.py +223 -0
  57. package/src/superlocalmemory/hooks/prewarm_auth.py +170 -0
  58. package/src/superlocalmemory/hooks/session_registry.py +186 -0
  59. package/src/superlocalmemory/hooks/stop_outcome_hook.py +134 -0
  60. package/src/superlocalmemory/hooks/sync_loop.py +114 -0
  61. package/src/superlocalmemory/hooks/user_prompt_hook.py +128 -0
  62. package/src/superlocalmemory/hooks/user_prompt_rehash_hook.py +202 -0
  63. package/src/superlocalmemory/infra/backup.py +3 -3
  64. package/src/superlocalmemory/infra/cloud_backup.py +2 -2
  65. package/src/superlocalmemory/infra/event_bus.py +2 -2
  66. package/src/superlocalmemory/infra/webhook_dispatcher.py +3 -3
  67. package/src/superlocalmemory/learning/arm_catalog.py +99 -0
  68. package/src/superlocalmemory/learning/bandit.py +526 -0
  69. package/src/superlocalmemory/learning/bandit_cache.py +133 -0
  70. package/src/superlocalmemory/learning/behavioral.py +53 -1
  71. package/src/superlocalmemory/learning/consolidation_cycle.py +381 -0
  72. package/src/superlocalmemory/learning/consolidation_worker.py +188 -520
  73. package/src/superlocalmemory/learning/database.py +256 -0
  74. package/src/superlocalmemory/learning/dedup_hnsw.py +413 -0
  75. package/src/superlocalmemory/learning/ensemble.py +300 -0
  76. package/src/superlocalmemory/learning/fact_outcome_joins.py +207 -0
  77. package/src/superlocalmemory/learning/forgetting_scheduler.py +55 -0
  78. package/src/superlocalmemory/learning/hnsw_dedup.py +69 -0
  79. package/src/superlocalmemory/learning/labeler.py +87 -0
  80. package/src/superlocalmemory/learning/legacy_migration.py +277 -0
  81. package/src/superlocalmemory/learning/memory_merge.py +160 -0
  82. package/src/superlocalmemory/learning/model_cache.py +269 -0
  83. package/src/superlocalmemory/learning/model_rollback.py +278 -0
  84. package/src/superlocalmemory/learning/outcome_queue.py +284 -0
  85. package/src/superlocalmemory/learning/pattern_miner.py +415 -0
  86. package/src/superlocalmemory/learning/pattern_miner_constants.py +47 -0
  87. package/src/superlocalmemory/learning/ranker.py +225 -81
  88. package/src/superlocalmemory/learning/ranker_common.py +163 -0
  89. package/src/superlocalmemory/learning/ranker_retrain_legacy.py +202 -0
  90. package/src/superlocalmemory/learning/ranker_retrain_online.py +411 -0
  91. package/src/superlocalmemory/learning/reward.py +777 -0
  92. package/src/superlocalmemory/learning/reward_archive.py +210 -0
  93. package/src/superlocalmemory/learning/reward_boost.py +201 -0
  94. package/src/superlocalmemory/learning/reward_proxy.py +326 -0
  95. package/src/superlocalmemory/learning/shadow_test.py +524 -0
  96. package/src/superlocalmemory/learning/signal_worker.py +270 -0
  97. package/src/superlocalmemory/learning/signals.py +314 -0
  98. package/src/superlocalmemory/learning/trigram_index.py +547 -0
  99. package/src/superlocalmemory/mcp/server.py +5 -5
  100. package/src/superlocalmemory/mcp/tools_context.py +183 -0
  101. package/src/superlocalmemory/mcp/tools_core.py +92 -27
  102. package/src/superlocalmemory/parameterization/soft_prompt_generator.py +13 -0
  103. package/src/superlocalmemory/retrieval/engine.py +52 -0
  104. package/src/superlocalmemory/server/api.py +2 -2
  105. package/src/superlocalmemory/server/bandit_loops.py +140 -0
  106. package/src/superlocalmemory/server/middleware/__init__.py +11 -0
  107. package/src/superlocalmemory/server/middleware/security_headers.py +144 -0
  108. package/src/superlocalmemory/server/routes/backup.py +36 -13
  109. package/src/superlocalmemory/server/routes/behavioral.py +50 -19
  110. package/src/superlocalmemory/server/routes/brain.py +1234 -0
  111. package/src/superlocalmemory/server/routes/data_io.py +4 -4
  112. package/src/superlocalmemory/server/routes/events.py +2 -2
  113. package/src/superlocalmemory/server/routes/helpers.py +1 -1
  114. package/src/superlocalmemory/server/routes/learning.py +192 -7
  115. package/src/superlocalmemory/server/routes/memories.py +189 -1
  116. package/src/superlocalmemory/server/routes/prewarm.py +171 -0
  117. package/src/superlocalmemory/server/routes/profiles.py +3 -3
  118. package/src/superlocalmemory/server/routes/token.py +88 -0
  119. package/src/superlocalmemory/server/routes/ws.py +5 -5
  120. package/src/superlocalmemory/server/security_middleware.py +13 -7
  121. package/src/superlocalmemory/server/ui.py +2 -2
  122. package/src/superlocalmemory/server/unified_daemon.py +335 -3
  123. package/src/superlocalmemory/skills/slm-build-graph/SKILL.md +423 -0
  124. package/src/superlocalmemory/skills/slm-list-recent/SKILL.md +348 -0
  125. package/src/superlocalmemory/skills/slm-recall/SKILL.md +343 -0
  126. package/src/superlocalmemory/skills/slm-remember/SKILL.md +194 -0
  127. package/src/superlocalmemory/skills/slm-show-patterns/SKILL.md +224 -0
  128. package/src/superlocalmemory/skills/slm-status/SKILL.md +363 -0
  129. package/src/superlocalmemory/skills/slm-switch-profile/SKILL.md +442 -0
  130. package/src/superlocalmemory/storage/migration_runner.py +545 -0
  131. package/src/superlocalmemory/storage/migrations/M001_add_signal_features_columns.py +67 -0
  132. package/src/superlocalmemory/storage/migrations/M002_model_state_history.py +132 -0
  133. package/src/superlocalmemory/storage/migrations/M003_migration_log.py +38 -0
  134. package/src/superlocalmemory/storage/migrations/M004_cross_platform_sync_log.py +46 -0
  135. package/src/superlocalmemory/storage/migrations/M005_bandit_tables.py +75 -0
  136. package/src/superlocalmemory/storage/migrations/M006_action_outcomes_reward.py +75 -0
  137. package/src/superlocalmemory/storage/migrations/M007_pending_outcomes.py +63 -0
  138. package/src/superlocalmemory/storage/migrations/M009_model_lineage.py +54 -0
  139. package/src/superlocalmemory/storage/migrations/M010_evolution_config.py +75 -0
  140. package/src/superlocalmemory/storage/migrations/M011_archive_and_merge.py +87 -0
  141. package/src/superlocalmemory/storage/migrations/M012_shadow_observations.py +72 -0
  142. package/src/superlocalmemory/storage/migrations/M013_bi_temporal_columns.py +55 -0
  143. package/src/superlocalmemory/storage/migrations/__init__.py +81 -0
  144. package/src/superlocalmemory/storage/models.py +4 -0
  145. package/src/superlocalmemory/ui/css/brain.css +409 -0
  146. package/src/superlocalmemory/ui/css/legacy-dashboard.css +645 -0
  147. package/src/superlocalmemory/ui/index.html +459 -1345
  148. package/src/superlocalmemory/ui/js/brain.js +1321 -0
  149. package/src/superlocalmemory/ui/js/clusters.js +123 -4
  150. package/src/superlocalmemory/ui/js/init.js +48 -39
  151. package/src/superlocalmemory/ui/js/memories.js +88 -2
  152. package/src/superlocalmemory/ui/js/modal.js +71 -1
  153. package/src/superlocalmemory/ui/js/ng-shell.js +101 -88
  154. package/src/superlocalmemory/ui/js/trust-dashboard.js +168 -25
  155. package/src/superlocalmemory/ui/vendor/bootstrap-icons/bootstrap-icons.css +2018 -0
  156. package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff +0 -0
  157. package/src/superlocalmemory/ui/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2 +0 -0
  158. package/src/superlocalmemory/ui/vendor/bootstrap.bundle.min.js +7 -0
  159. package/src/superlocalmemory/ui/vendor/bootstrap.min.css +6 -0
  160. package/src/superlocalmemory/ui/vendor/d3.v7.min.js +2 -0
  161. package/src/superlocalmemory/ui/vendor/graphology-library.min.js +2 -0
  162. package/src/superlocalmemory/ui/vendor/graphology.umd.min.js +2 -0
  163. package/src/superlocalmemory/ui/vendor/inter-ui/inter-variable.min.css +8 -0
  164. package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable-Italic.woff2 +0 -0
  165. package/src/superlocalmemory/ui/vendor/inter-ui/variable/InterVariable.woff2 +0 -0
  166. package/src/superlocalmemory/ui/vendor/sigma.min.js +1 -0
  167. package/src/superlocalmemory/ui/js/behavioral.js +0 -447
  168. package/src/superlocalmemory/ui/js/graph-core.js +0 -447
  169. package/src/superlocalmemory/ui/js/graph-interactions.js +0 -351
  170. package/src/superlocalmemory/ui/js/learning.js +0 -435
  171. package/src/superlocalmemory/ui/js/patterns.js +0 -93
  172. package/src/superlocalmemory.egg-info/PKG-INFO +0 -647
  173. package/src/superlocalmemory.egg-info/SOURCES.txt +0 -335
  174. package/src/superlocalmemory.egg-info/dependency_links.txt +0 -1
  175. package/src/superlocalmemory.egg-info/entry_points.txt +0 -2
  176. package/src/superlocalmemory.egg-info/requires.txt +0 -58
  177. package/src/superlocalmemory.egg-info/top_level.txt +0 -1
@@ -11,41 +11,19 @@
11
11
  label: 'Memory',
12
12
  items: [
13
13
  { id: 'dashboard-pane', icon: 'bi-speedometer2', text: 'Dashboard' },
14
+ { id: 'brain-pane', icon: 'bi-lightbulb', text: 'Brain' },
14
15
  { id: 'graph-pane', icon: 'bi-diagram-3', text: 'Knowledge Graph' },
15
- { id: 'memories-pane', icon: 'bi-list-ul', text: 'Memories' },
16
- { id: 'recall-lab-pane', icon: 'bi-search-heart', text: 'Recall Lab' },
17
- { id: 'timeline-pane', icon: 'bi-clock-history', text: 'Timeline' }
18
- ]
19
- },
20
- {
21
- label: 'Intelligence',
22
- items: [
23
- { id: 'clusters-pane', icon: 'bi-collection', text: 'Clusters' },
24
- { id: 'patterns-pane', icon: 'bi-puzzle', text: 'Patterns' },
25
- { id: 'learning-pane', icon: 'bi-mortarboard', text: 'Learning' },
26
- { id: 'behavioral-pane', icon: 'bi-lightbulb', text: 'Behavioral' }
16
+ { id: 'memories-pane', icon: 'bi-list-ul', text: 'Memories' }
27
17
  ]
28
18
  },
29
19
  {
30
20
  label: 'System',
31
21
  items: [
32
- { id: 'events-pane', icon: 'bi-broadcast', text: 'Live Events' },
33
- { id: 'agents-pane', icon: 'bi-robot', text: 'Agents' },
34
- { id: 'trust-pane', icon: 'bi-shield-check', text: 'Trust' },
35
- { id: 'lifecycle-pane', icon: 'bi-hourglass-split', text: 'Lifecycle' },
36
- { id: 'compliance-pane', icon: 'bi-shield-lock', text: 'Compliance' },
37
- { id: 'math-health-pane', icon: 'bi-calculator', text: 'Math Health' },
38
- { id: 'ide-pane', icon: 'bi-plug', text: 'IDEs' }
39
- ]
40
- },
41
- {
42
- label: 'v3.4.3',
43
- items: [
44
- { id: 'health-pane', icon: 'bi-heart-pulse', text: 'Health Monitor', badge: 'NEW' },
45
- { id: 'ingestion-pane', icon: 'bi-cloud-download', text: 'Ingestion', badge: 'NEW' },
46
- { id: 'entities-pane', icon: 'bi-person-badge', text: 'Entity Explorer', badge: 'NEW' },
47
- { id: 'skills-pane', icon: 'bi-lightning-charge', text: 'Skill Evolution', badge: 'NEW' },
48
- { id: 'mesh-pane', icon: 'bi-share', text: 'Mesh Peers', badge: 'NEW' }
22
+ { id: 'health-pane', icon: 'bi-heart-pulse', text: 'Health' },
23
+ { id: 'operations-pane', icon: 'bi-diagram-2', text: 'Operations' },
24
+ { id: 'entities-pane', icon: 'bi-person-badge', text: 'Entity Explorer' },
25
+ { id: 'skills-pane', icon: 'bi-lightning-charge', text: 'Skill Evolution' },
26
+ { id: 'mesh-pane', icon: 'bi-share', text: 'Mesh Peers' }
49
27
  ]
50
28
  },
51
29
  {
@@ -74,7 +52,7 @@
74
52
  '</div>' +
75
53
  '<div>' +
76
54
  '<div class="ng-sidebar-brand-text">SuperLocalMemory</div>' +
77
- '<div class="ng-sidebar-brand-version" id="ng-version">v3.4.4</div>' +
55
+ '<div class="ng-sidebar-brand-version" id="ng-version">\u2026</div>' +
78
56
  '</div>' +
79
57
  '</div>';
80
58
  sidebar.appendChild(header);
@@ -230,12 +208,17 @@
230
208
  // Replace container with shell
231
209
  container.parentNode.replaceChild(shell, container);
232
210
 
233
- // Move dashboard-only elements INTO the dashboard-pane so they scroll with it
211
+ // Move dashboard-only elements INTO the dashboard-pane so they scroll
212
+ // with it. stats-container starts ``display:none`` in the HTML to kill
213
+ // the pre-glass flash; reveal it once it's in its final home.
234
214
  var dashboardPane = document.getElementById('dashboard-pane');
235
215
  if (dashboardPane) {
236
216
  ['stats-container', 'privacy-notice', 'feedback-progress'].forEach(function(id) {
237
217
  var el = document.getElementById(id);
238
- if (el) dashboardPane.insertBefore(el, dashboardPane.firstChild);
218
+ if (el) {
219
+ dashboardPane.insertBefore(el, dashboardPane.firstChild);
220
+ if (id === 'stats-container') el.style.display = '';
221
+ }
239
222
  });
240
223
  }
241
224
 
@@ -260,14 +243,26 @@
260
243
  refreshBtn.addEventListener('click', refreshDashboard);
261
244
  }
262
245
 
263
- // Sync version from dashboard
264
- setTimeout(function() {
265
- var dashVer = document.getElementById('dashboard-version');
266
- var ngVer = document.getElementById('ng-version');
267
- if (dashVer && ngVer && dashVer.textContent !== '...') {
268
- ngVer.textContent = 'v' + dashVer.textContent;
269
- }
270
- }, 1500);
246
+ // Sidebar version: always the live daemon version from /health.
247
+ // Don't depend on dashboard.js timing — that used to leave "v3.4.4"
248
+ // hardcoded in the sidebar when dashboard.js hadn't run yet.
249
+ fetch('/health', { credentials: 'same-origin' })
250
+ .then(function (r) { return r.ok ? r.json() : null; })
251
+ .then(function (data) {
252
+ var ngVer = document.getElementById('ng-version');
253
+ if (ngVer && data && data.version) {
254
+ ngVer.textContent = 'v' + data.version;
255
+ }
256
+ })
257
+ .catch(function () {
258
+ // Fallback: if /health is unreachable, fall back to whatever
259
+ // dashboard.js populates into #dashboard-version.
260
+ var dashVer = document.getElementById('dashboard-version');
261
+ var ngVer = document.getElementById('ng-version');
262
+ if (dashVer && ngVer && dashVer.textContent && dashVer.textContent !== '...') {
263
+ ngVer.textContent = 'v' + dashVer.textContent;
264
+ }
265
+ });
271
266
  }
272
267
 
273
268
  // ── Tab Activation ─────────────────────────────────────────
@@ -296,16 +291,25 @@
296
291
  targetPane.classList.add('show', 'active');
297
292
  }
298
293
 
299
- // Dispatch Bootstrap tab event for backward compat
294
+ // Dispatch Bootstrap tab event for backward compat.
295
+ //
296
+ // Previous code assigned ``event.target = tabButton``; that property
297
+ // is readonly on DOM Event objects, so in strict mode the assignment
298
+ // throws TypeError, the surrounding try/catch silently swallowed it,
299
+ // and dispatchEvent() was NEVER reached. brain.js's
300
+ // ``shown.bs.tab`` listener never fired when navigating between tabs
301
+ // via the sidebar, so the Brain pane stayed stuck on "Loading Brain..."
302
+ // forever (and any other listener that relied on the event didn't
303
+ // get a chance). The DOM automatically sets ``event.target`` to the
304
+ // element on which ``dispatchEvent`` is called, so we don't need to
305
+ // assign it manually.
300
306
  var tabButton = document.getElementById(targetId.replace('-pane', '-tab'));
301
307
  if (tabButton) {
302
308
  try {
303
- var event = new Event('shown.bs.tab', { bubbles: true });
304
- event.target = tabButton;
305
- event.relatedTarget = null;
306
- tabButton.dispatchEvent(event);
309
+ var tabEvent = new Event('shown.bs.tab', { bubbles: true });
310
+ tabButton.dispatchEvent(tabEvent);
307
311
  } catch (e) {
308
- // Ignore if event dispatch fails
312
+ // Ignore if event dispatch fails (very old browsers)
309
313
  }
310
314
  }
311
315
 
@@ -339,55 +343,38 @@
339
343
  if (typeof initMemoryChat === 'function' && !document.getElementById('chat-panel')) {
340
344
  initMemoryChat();
341
345
  }
342
- break;
343
- case 'memories-pane':
344
- if (typeof loadMemories === 'function') loadMemories();
345
- break;
346
- case 'clusters-pane':
346
+ // Domain 3 (v3.4.21): Clusters still folded into graph. Entity
347
+ // Explorer has its own standalone sidebar entry now.
347
348
  if (typeof loadClusters === 'function') loadClusters();
348
349
  break;
349
- case 'patterns-pane':
350
- if (typeof loadPatterns === 'function') loadPatterns();
350
+ case 'entities-pane':
351
+ if (typeof loadEntityExplorer === 'function') loadEntityExplorer();
351
352
  break;
352
- case 'timeline-pane':
353
+ case 'memories-pane':
354
+ if (typeof loadMemories === 'function') loadMemories();
355
+ // Domain 4 (v3.4.21): Recall Lab + Timeline now live inside
356
+ // memories-pane. Fire the timeline loader alongside so users
357
+ // don't need a separate tab click to see the chart.
353
358
  if (typeof loadTimeline === 'function') loadTimeline();
354
359
  break;
355
- case 'events-pane':
360
+ case 'health-pane':
361
+ // v3.4.21 / v3.4.21 (taxonomy): Health = runtime health ONLY
362
+ // (Daemon, Events, Agents, IDEs, Math). Governance concerns live
363
+ // in operations-pane. IDEs folded in v3.4.21 per Varun — they're
364
+ // connected-client state, same category as Agents.
365
+ if (typeof loadHealthMonitor === 'function') loadHealthMonitor();
356
366
  if (typeof initEventStream === 'function') initEventStream();
357
367
  if (typeof loadEventStats === 'function') loadEventStats();
358
- break;
359
- case 'agents-pane':
360
368
  if (typeof loadAgents === 'function') loadAgents();
361
- break;
362
- case 'learning-pane':
363
- if (typeof loadLearning === 'function') loadLearning();
364
- break;
365
- case 'trust-pane':
366
- if (typeof loadTrustDashboard === 'function') loadTrustDashboard();
367
- break;
368
- case 'lifecycle-pane':
369
- if (typeof loadLifecycle === 'function') loadLifecycle();
370
- break;
371
- case 'behavioral-pane':
372
- if (typeof loadBehavioral === 'function') loadBehavioral();
373
- break;
374
- case 'compliance-pane':
375
- if (typeof loadCompliance === 'function') loadCompliance();
376
- break;
377
- case 'math-health-pane':
378
- if (typeof loadMathHealth === 'function') loadMathHealth();
379
- break;
380
- case 'ide-pane':
381
369
  if (typeof loadIDEStatus === 'function') loadIDEStatus();
370
+ if (typeof loadMathHealth === 'function') loadMathHealth();
382
371
  break;
383
- case 'health-pane':
384
- if (typeof loadHealthMonitor === 'function') loadHealthMonitor();
385
- break;
386
- case 'ingestion-pane':
372
+ case 'operations-pane':
373
+ // v3.4.21: data governance (Ingestion, Lifecycle, Trust, Compliance).
387
374
  if (typeof loadIngestionStatus === 'function') loadIngestionStatus();
388
- break;
389
- case 'entities-pane':
390
- if (typeof loadEntityExplorer === 'function') loadEntityExplorer();
375
+ if (typeof loadLifecycle === 'function') loadLifecycle();
376
+ if (typeof loadTrustDashboard === 'function') loadTrustDashboard();
377
+ if (typeof loadCompliance === 'function') loadCompliance();
391
378
  break;
392
379
  case 'skills-pane':
393
380
  if (typeof loadSkillEvolution === 'function') loadSkillEvolution();
@@ -407,8 +394,25 @@
407
394
  // ── Hash-based Routing ─────────────────────────────────────
408
395
  function handleHash() {
409
396
  var hash = window.location.hash.replace('#', '');
410
- if (hash && document.getElementById(hash)) {
397
+ if (!hash) return;
398
+ var el = document.getElementById(hash);
399
+ if (!el) return;
400
+ // Only activate real tab-panes. Previously this tried to activate
401
+ // ANY element whose id matched the hash, which broke when Domain 5
402
+ // sub-nav anchors like ``#health-section-events`` fired — it would
403
+ // strip ``show active`` off every real pane and leave the app blank.
404
+ if (el.classList && el.classList.contains('tab-pane')) {
411
405
  activateTab(hash);
406
+ return;
407
+ }
408
+ // Not a tab-pane — find the pane that contains this element (e.g.
409
+ // a section inside health-pane) and activate that first, then scroll.
410
+ var parent = el.closest && el.closest('.tab-pane');
411
+ if (parent && parent.id) activateTab(parent.id);
412
+ try {
413
+ el.scrollIntoView({ behavior: 'smooth', block: 'start' });
414
+ } catch (e) {
415
+ // pre-smooth-scroll browsers: no-op
412
416
  }
413
417
  }
414
418
 
@@ -470,12 +474,21 @@
470
474
  // Restructure DOM
471
475
  restructureDOM();
472
476
 
473
- // Handle initial hash run synchronously, no timeout race
477
+ // v3.4.21 fix: a browser-restored URL fragment (e.g. a stale
478
+ // ``#health-section-events`` from a previous session) used to yank
479
+ // the user off Dashboard on refresh. Refresh should always land on
480
+ // the pane that has ``show active`` in the HTML — Dashboard. Only
481
+ // respond to hash changes the user triggers explicitly AFTER load.
474
482
  if (window.location.hash) {
475
- handleHash();
483
+ try {
484
+ history.replaceState(null, '', window.location.pathname);
485
+ } catch (e) {
486
+ // Older browsers without replaceState: leave the hash alone
487
+ // rather than crashing init.
488
+ }
476
489
  }
477
490
 
478
- // Listen for hash changes
491
+ // Listen for subsequent (user-triggered) hash changes
479
492
  window.addEventListener('hashchange', handleHash);
480
493
 
481
494
  // toggleDarkMode already overridden above with theme toggle support
@@ -1,35 +1,78 @@
1
1
  // SuperLocalMemory V3 — Trust Dashboard
2
2
  // Loads and displays Bayesian trust scores per agent and per fact.
3
+ //
4
+ // v3.4.21 (Operations pane): /api/v3/trust/dashboard returns
5
+ // thousands of rows in one shot (3,900+ agents on Varun's live DB).
6
+ // Client-side pagination keeps the table bounded; the user chooses
7
+ // sort order + page size; all data stays real (no mock fallback).
3
8
 
4
- async function loadTrustDashboard() {
5
- try {
6
- var response = await fetch('/api/v3/trust/dashboard');
7
- if (!response.ok) return;
8
- var data = await response.json();
9
+ (function trustDashboard() {
10
+ 'use strict';
9
11
 
10
- var agents = data.agents || [];
11
- document.getElementById('trust-agent-count').textContent = agents.length;
12
+ var STATE = {
13
+ agents: [],
14
+ page: 0,
15
+ pageSize: 25,
16
+ sort: 'score-desc',
17
+ };
12
18
 
13
- var avg = agents.length > 0
14
- ? (agents.reduce(function(s, a) { return s + (a.trust_score || 0); }, 0) / agents.length).toFixed(3)
15
- : '\u2014';
16
- document.getElementById('trust-avg-score').textContent = avg;
17
- document.getElementById('trust-burst-count').textContent = (data.alerts || []).length;
19
+ function _sortedAgents() {
20
+ var arr = STATE.agents.slice();
21
+ switch (STATE.sort) {
22
+ case 'score-asc':
23
+ arr.sort(function (a, b) {
24
+ return (a.trust_score || 0) - (b.trust_score || 0);
25
+ });
26
+ break;
27
+ case 'evidence-desc':
28
+ arr.sort(function (a, b) {
29
+ return (b.evidence_count || 0) - (a.evidence_count || 0);
30
+ });
31
+ break;
32
+ case 'updated-desc':
33
+ arr.sort(function (a, b) {
34
+ return String(b.last_updated || '').localeCompare(
35
+ String(a.last_updated || '')
36
+ );
37
+ });
38
+ break;
39
+ case 'score-desc':
40
+ default:
41
+ arr.sort(function (a, b) {
42
+ return (b.trust_score || 0) - (a.trust_score || 0);
43
+ });
44
+ break;
45
+ }
46
+ return arr;
47
+ }
18
48
 
49
+ function _renderPage() {
19
50
  var tbody = document.getElementById('trust-agents-body');
51
+ if (!tbody) return;
52
+
53
+ var agents = _sortedAgents();
54
+ var total = agents.length;
55
+ var pageSize = Math.max(1, STATE.pageSize);
56
+ var maxPage = Math.max(0, Math.ceil(total / pageSize) - 1);
57
+ if (STATE.page > maxPage) STATE.page = maxPage;
58
+ if (STATE.page < 0) STATE.page = 0;
59
+ var start = STATE.page * pageSize;
60
+ var end = Math.min(total, start + pageSize);
61
+ var slice = agents.slice(start, end);
62
+
20
63
  tbody.textContent = '';
21
- agents.forEach(function(a) {
64
+ slice.forEach(function (a) {
22
65
  var tr = document.createElement('tr');
23
- var score = (a.trust_score || 0);
24
- var badge = score >= 0.7 ? 'success' : score >= 0.3 ? 'warning' : 'danger';
25
- var label = score >= 0.7 ? 'Trusted' : score >= 0.3 ? 'Neutral' : 'Low Trust';
66
+ var score = a.trust_score || 0;
67
+ var badge = score >= 0.7 ? 'success'
68
+ : score >= 0.3 ? 'warning' : 'danger';
69
+ var label = score >= 0.7 ? 'Trusted'
70
+ : score >= 0.3 ? 'Neutral' : 'Low trust';
26
71
 
27
- // Target ID cell
28
72
  var tdTarget = document.createElement('td');
29
73
  tdTarget.textContent = a.target_id || '';
30
74
  tr.appendChild(tdTarget);
31
75
 
32
- // Type cell
33
76
  var tdType = document.createElement('td');
34
77
  var spanType = document.createElement('span');
35
78
  spanType.className = 'badge bg-secondary';
@@ -37,7 +80,6 @@ async function loadTrustDashboard() {
37
80
  tdType.appendChild(spanType);
38
81
  tr.appendChild(tdType);
39
82
 
40
- // Trust score progress bar cell
41
83
  var tdScore = document.createElement('td');
42
84
  var progress = document.createElement('div');
43
85
  progress.className = 'progress';
@@ -50,12 +92,10 @@ async function loadTrustDashboard() {
50
92
  tdScore.appendChild(progress);
51
93
  tr.appendChild(tdScore);
52
94
 
53
- // Evidence count cell
54
95
  var tdEvidence = document.createElement('td');
55
96
  tdEvidence.textContent = a.evidence_count || 0;
56
97
  tr.appendChild(tdEvidence);
57
98
 
58
- // Status badge cell
59
99
  var tdStatus = document.createElement('td');
60
100
  var spanStatus = document.createElement('span');
61
101
  spanStatus.className = 'badge bg-' + badge;
@@ -65,9 +105,112 @@ async function loadTrustDashboard() {
65
105
 
66
106
  tbody.appendChild(tr);
67
107
  });
68
- } catch (e) {
69
- console.log('Trust dashboard error:', e);
108
+
109
+ // Pagination controls state
110
+ var info = document.getElementById('trust-page-info');
111
+ if (info) {
112
+ if (total === 0) {
113
+ info.textContent = 'No rows';
114
+ } else {
115
+ info.textContent = (start + 1) + '\u2013' + end
116
+ + ' of ' + total.toLocaleString();
117
+ }
118
+ }
119
+ var detail = document.getElementById('trust-page-detail');
120
+ if (detail) {
121
+ detail.textContent = 'Page ' + (STATE.page + 1)
122
+ + ' of ' + Math.max(1, maxPage + 1);
123
+ }
124
+ var prev = document.getElementById('trust-prev-btn');
125
+ var next = document.getElementById('trust-next-btn');
126
+ if (prev) prev.disabled = STATE.page <= 0;
127
+ if (next) next.disabled = STATE.page >= maxPage;
128
+ }
129
+
130
+ async function loadTrustDashboard() {
131
+ try {
132
+ var resp = await fetch('/api/v3/trust/dashboard');
133
+ if (!resp.ok) return;
134
+ var data = await resp.json();
135
+
136
+ var agents = data.agents || [];
137
+ STATE.agents = agents;
138
+ STATE.page = 0;
139
+
140
+ var el;
141
+ el = document.getElementById('trust-agent-count');
142
+ if (el) el.textContent = agents.length.toLocaleString();
143
+
144
+ var avg = agents.length > 0
145
+ ? (agents.reduce(function (s, a) {
146
+ return s + (a.trust_score || 0);
147
+ }, 0) / agents.length).toFixed(3)
148
+ : '\u2014';
149
+ el = document.getElementById('trust-avg-score');
150
+ if (el) el.textContent = avg;
151
+
152
+ el = document.getElementById('trust-burst-count');
153
+ if (el) el.textContent = (data.alerts || []).length;
154
+
155
+ _renderPage();
156
+ } catch (e) {
157
+ if (window.console && window.console.debug) {
158
+ window.console.debug('Trust dashboard error:', e);
159
+ }
160
+ }
161
+ }
162
+
163
+ function _wireControls() {
164
+ var sort = document.getElementById('trust-sort');
165
+ if (sort) {
166
+ sort.addEventListener('change', function () {
167
+ STATE.sort = sort.value;
168
+ STATE.page = 0;
169
+ _renderPage();
170
+ });
171
+ }
172
+ var pageSize = document.getElementById('trust-page-size');
173
+ if (pageSize) {
174
+ pageSize.addEventListener('change', function () {
175
+ STATE.pageSize = parseInt(pageSize.value, 10) || 25;
176
+ STATE.page = 0;
177
+ _renderPage();
178
+ });
179
+ }
180
+ var prev = document.getElementById('trust-prev-btn');
181
+ if (prev) {
182
+ prev.addEventListener('click', function () {
183
+ if (STATE.page > 0) {
184
+ STATE.page -= 1;
185
+ _renderPage();
186
+ }
187
+ });
188
+ }
189
+ var next = document.getElementById('trust-next-btn');
190
+ if (next) {
191
+ next.addEventListener('click', function () {
192
+ STATE.page += 1;
193
+ _renderPage();
194
+ });
195
+ }
196
+ }
197
+
198
+ function _boot() {
199
+ _wireControls();
200
+ // Re-load when the old Bootstrap trust-tab fires or when
201
+ // ng-shell activates operations-pane.
202
+ var trustTab = document.getElementById('trust-tab');
203
+ if (trustTab) {
204
+ trustTab.addEventListener('shown.bs.tab', loadTrustDashboard);
205
+ }
206
+ }
207
+
208
+ if (document.readyState === 'loading') {
209
+ document.addEventListener('DOMContentLoaded', _boot);
210
+ } else {
211
+ _boot();
70
212
  }
71
- }
72
213
 
73
- document.getElementById('trust-tab')?.addEventListener('shown.bs.tab', loadTrustDashboard);
214
+ // Public surface
215
+ window.loadTrustDashboard = loadTrustDashboard;
216
+ })();