claude-memory-layer 1.0.7 → 1.0.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 (38) hide show
  1. package/.claude/settings.local.json +4 -1
  2. package/.history/package_20260201192048.json +47 -0
  3. package/dist/cli/index.js +569 -39
  4. package/dist/cli/index.js.map +4 -4
  5. package/dist/core/index.js +192 -5
  6. package/dist/core/index.js.map +4 -4
  7. package/dist/hooks/session-end.js +262 -18
  8. package/dist/hooks/session-end.js.map +4 -4
  9. package/dist/hooks/session-start.js +262 -18
  10. package/dist/hooks/session-start.js.map +4 -4
  11. package/dist/hooks/stop.js +262 -18
  12. package/dist/hooks/stop.js.map +4 -4
  13. package/dist/hooks/user-prompt-submit.js +262 -18
  14. package/dist/hooks/user-prompt-submit.js.map +4 -4
  15. package/dist/server/api/index.js +404 -39
  16. package/dist/server/api/index.js.map +4 -4
  17. package/dist/server/index.js +413 -46
  18. package/dist/server/index.js.map +4 -4
  19. package/dist/services/memory-service.js +269 -18
  20. package/dist/services/memory-service.js.map +4 -4
  21. package/dist/ui/index.html +495 -15
  22. package/package.json +2 -1
  23. package/scripts/build.ts +3 -2
  24. package/src/cli/index.ts +226 -0
  25. package/src/core/db-wrapper.ts +8 -1
  26. package/src/core/event-store.ts +52 -3
  27. package/src/core/graduation-worker.ts +171 -0
  28. package/src/core/graduation.ts +15 -2
  29. package/src/core/index.ts +1 -0
  30. package/src/core/retriever.ts +18 -0
  31. package/src/server/api/citations.ts +7 -3
  32. package/src/server/api/events.ts +7 -3
  33. package/src/server/api/search.ts +7 -3
  34. package/src/server/api/sessions.ts +7 -3
  35. package/src/server/api/stats.ts +129 -12
  36. package/src/server/index.ts +18 -9
  37. package/src/services/memory-service.ts +107 -19
  38. package/src/ui/index.html +495 -15
package/src/ui/index.html CHANGED
@@ -358,6 +358,158 @@
358
358
  background: rgba(251, 191, 36, 0.2);
359
359
  color: var(--warning);
360
360
  }
361
+
362
+ /* Memory Level Navigation */
363
+ .level-nav {
364
+ display: flex;
365
+ gap: 8px;
366
+ margin-bottom: 20px;
367
+ flex-wrap: wrap;
368
+ }
369
+
370
+ .level-tab {
371
+ padding: 12px 20px;
372
+ background: var(--bg-card);
373
+ border: 1px solid var(--border);
374
+ border-radius: 8px;
375
+ cursor: pointer;
376
+ transition: all 0.2s;
377
+ display: flex;
378
+ flex-direction: column;
379
+ align-items: center;
380
+ min-width: 80px;
381
+ }
382
+
383
+ .level-tab:hover {
384
+ border-color: var(--accent);
385
+ }
386
+
387
+ .level-tab.active {
388
+ background: var(--accent);
389
+ border-color: var(--accent);
390
+ }
391
+
392
+ .level-tab .level-name {
393
+ font-weight: 600;
394
+ font-size: 1.1rem;
395
+ }
396
+
397
+ .level-tab .level-count {
398
+ font-size: 0.75rem;
399
+ color: var(--text-secondary);
400
+ margin-top: 4px;
401
+ }
402
+
403
+ .level-tab.active .level-count {
404
+ color: rgba(255, 255, 255, 0.8);
405
+ }
406
+
407
+ .level-description {
408
+ font-size: 0.85rem;
409
+ color: var(--text-secondary);
410
+ margin-bottom: 16px;
411
+ padding: 12px;
412
+ background: var(--bg-card);
413
+ border-radius: 8px;
414
+ }
415
+
416
+ .level-pipeline {
417
+ display: flex;
418
+ align-items: center;
419
+ justify-content: center;
420
+ gap: 8px;
421
+ margin-bottom: 20px;
422
+ flex-wrap: wrap;
423
+ }
424
+
425
+ .pipeline-step {
426
+ padding: 8px 16px;
427
+ background: var(--bg-card);
428
+ border-radius: 20px;
429
+ font-size: 0.8rem;
430
+ opacity: 0.5;
431
+ }
432
+
433
+ .pipeline-step.active {
434
+ opacity: 1;
435
+ background: var(--accent);
436
+ }
437
+
438
+ .pipeline-arrow {
439
+ color: var(--text-secondary);
440
+ }
441
+
442
+ .event-card {
443
+ padding: 16px;
444
+ background: var(--bg-card);
445
+ border-radius: 8px;
446
+ margin-bottom: 12px;
447
+ border: 1px solid transparent;
448
+ transition: all 0.2s;
449
+ }
450
+
451
+ .event-card:hover {
452
+ border-color: var(--accent);
453
+ }
454
+
455
+ .event-type {
456
+ display: inline-block;
457
+ padding: 2px 8px;
458
+ border-radius: 4px;
459
+ font-size: 0.75rem;
460
+ font-weight: 600;
461
+ margin-right: 8px;
462
+ }
463
+
464
+ .event-type.user_prompt {
465
+ background: rgba(59, 130, 246, 0.2);
466
+ color: #3b82f6;
467
+ }
468
+
469
+ .event-type.agent_response {
470
+ background: rgba(16, 185, 129, 0.2);
471
+ color: #10b981;
472
+ }
473
+
474
+ .event-type.tool_observation {
475
+ background: rgba(245, 158, 11, 0.2);
476
+ color: #f59e0b;
477
+ }
478
+
479
+ .event-type.session_summary {
480
+ background: rgba(139, 92, 246, 0.2);
481
+ color: #8b5cf6;
482
+ }
483
+
484
+ .event-content {
485
+ margin-top: 8px;
486
+ font-size: 0.9rem;
487
+ color: var(--text-secondary);
488
+ line-height: 1.5;
489
+ white-space: pre-wrap;
490
+ word-break: break-word;
491
+ }
492
+
493
+ .load-more-btn {
494
+ width: 100%;
495
+ padding: 12px;
496
+ background: var(--bg-card);
497
+ border: 1px solid var(--border);
498
+ color: var(--text-primary);
499
+ border-radius: 8px;
500
+ cursor: pointer;
501
+ transition: all 0.2s;
502
+ margin-top: 16px;
503
+ }
504
+
505
+ .load-more-btn:hover {
506
+ border-color: var(--accent);
507
+ }
508
+
509
+ .load-more-btn:disabled {
510
+ opacity: 0.5;
511
+ cursor: not-allowed;
512
+ }
361
513
  </style>
362
514
  </head>
363
515
  <body>
@@ -409,6 +561,108 @@
409
561
  </div>
410
562
  </div>
411
563
 
564
+ <!-- Memory Level Explorer -->
565
+ <div class="section" style="margin-bottom: 30px;">
566
+ <h2 class="section-title">🎯 Memory Level Explorer</h2>
567
+
568
+ <!-- Pipeline Visualization -->
569
+ <div class="level-pipeline" id="level-pipeline">
570
+ <span class="pipeline-step active" data-level="L0">L0 Raw</span>
571
+ <span class="pipeline-arrow">→</span>
572
+ <span class="pipeline-step" data-level="L1">L1 Structured</span>
573
+ <span class="pipeline-arrow">→</span>
574
+ <span class="pipeline-step" data-level="L2">L2 Validated</span>
575
+ <span class="pipeline-arrow">→</span>
576
+ <span class="pipeline-step" data-level="L3">L3 Verified</span>
577
+ <span class="pipeline-arrow">→</span>
578
+ <span class="pipeline-step" data-level="L4">L4 Active</span>
579
+ </div>
580
+
581
+ <!-- Level Tabs -->
582
+ <div class="level-nav" id="level-nav">
583
+ <div class="level-tab active" data-level="L0" onclick="selectLevel('L0')">
584
+ <span class="level-name">L0</span>
585
+ <span class="level-count" id="level-count-L0">0</span>
586
+ </div>
587
+ <div class="level-tab" data-level="L1" onclick="selectLevel('L1')">
588
+ <span class="level-name">L1</span>
589
+ <span class="level-count" id="level-count-L1">0</span>
590
+ </div>
591
+ <div class="level-tab" data-level="L2" onclick="selectLevel('L2')">
592
+ <span class="level-name">L2</span>
593
+ <span class="level-count" id="level-count-L2">0</span>
594
+ </div>
595
+ <div class="level-tab" data-level="L3" onclick="selectLevel('L3')">
596
+ <span class="level-name">L3</span>
597
+ <span class="level-count" id="level-count-L3">0</span>
598
+ </div>
599
+ <div class="level-tab" data-level="L4" onclick="selectLevel('L4')">
600
+ <span class="level-name">L4</span>
601
+ <span class="level-count" id="level-count-L4">0</span>
602
+ </div>
603
+ </div>
604
+
605
+ <!-- Level Description -->
606
+ <div class="level-description" id="level-description">
607
+ <strong>L0 - Raw Events:</strong> Unprocessed events from conversations. Includes user prompts, agent responses, and tool observations.
608
+ </div>
609
+
610
+ <!-- Events List -->
611
+ <div id="level-events-list">
612
+ <div class="loading-spinner">Loading...</div>
613
+ </div>
614
+
615
+ <!-- Load More Button -->
616
+ <button class="load-more-btn" id="load-more-btn" onclick="loadMoreEvents()" style="display: none;">
617
+ Load More Events
618
+ </button>
619
+
620
+ <!-- Graduation Controls -->
621
+ <div class="graduation-section" style="margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--border);">
622
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
623
+ <h3 style="font-size: 1rem; color: var(--text-secondary);">🎓 Graduation Pipeline</h3>
624
+ <button class="refresh-btn" id="run-graduation-btn" onclick="runGraduation()" style="padding: 8px 16px; font-size: 0.85rem;">
625
+ <span id="graduation-icon">⚡</span> Run Graduation
626
+ </button>
627
+ </div>
628
+ <div class="graduation-criteria" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px;">
629
+ <div class="criteria-card" style="background: var(--bg-card); padding: 12px; border-radius: 8px;">
630
+ <div style="color: var(--accent); font-weight: 600; margin-bottom: 8px;">L0 → L1</div>
631
+ <div style="font-size: 0.85rem; color: var(--text-secondary);">
632
+ • Access: ≥1<br>
633
+ • Confidence: ≥50%<br>
634
+ • Cross-session: 0
635
+ </div>
636
+ </div>
637
+ <div class="criteria-card" style="background: var(--bg-card); padding: 12px; border-radius: 8px;">
638
+ <div style="color: var(--accent); font-weight: 600; margin-bottom: 8px;">L1 → L2</div>
639
+ <div style="font-size: 0.85rem; color: var(--text-secondary);">
640
+ • Access: ≥3<br>
641
+ • Confidence: ≥70%<br>
642
+ • Cross-session: ≥1
643
+ </div>
644
+ </div>
645
+ <div class="criteria-card" style="background: var(--bg-card); padding: 12px; border-radius: 8px;">
646
+ <div style="color: var(--accent); font-weight: 600; margin-bottom: 8px;">L2 → L3</div>
647
+ <div style="font-size: 0.85rem; color: var(--text-secondary);">
648
+ • Access: ≥5<br>
649
+ • Confidence: ≥85%<br>
650
+ • Cross-session: ≥2
651
+ </div>
652
+ </div>
653
+ <div class="criteria-card" style="background: var(--bg-card); padding: 12px; border-radius: 8px;">
654
+ <div style="color: var(--accent); font-weight: 600; margin-bottom: 8px;">L3 → L4</div>
655
+ <div style="font-size: 0.85rem; color: var(--text-secondary);">
656
+ • Access: ≥10<br>
657
+ • Confidence: ≥92%<br>
658
+ • Cross-session: ≥3
659
+ </div>
660
+ </div>
661
+ </div>
662
+ <div id="graduation-result" style="margin-top: 12px; display: none;"></div>
663
+ </div>
664
+ </div>
665
+
412
666
  <div class="main-grid">
413
667
  <div class="section">
414
668
  <h2 class="section-title">📋 Recent Sessions</h2>
@@ -465,6 +719,13 @@
465
719
  </div>
466
720
  </div>
467
721
 
722
+ <div class="section" style="margin-top: 30px;">
723
+ <h2 class="section-title">🔥 Most Referenced Memories</h2>
724
+ <div id="most-accessed-list">
725
+ <div class="loading-spinner">Loading...</div>
726
+ </div>
727
+ </div>
728
+
468
729
  <div class="timeline-container section" style="margin-top: 30px;">
469
730
  <h2 class="section-title">📊 Activity Timeline (Last 7 Days)</h2>
470
731
  <div class="timeline-bar" id="timeline-bar">
@@ -480,6 +741,20 @@
480
741
  const API_BASE = '/api';
481
742
  let refreshInterval = null;
482
743
 
744
+ // Level Explorer State
745
+ let currentLevel = 'L0';
746
+ let currentOffset = 0;
747
+ const pageSize = 20;
748
+ let hasMoreEvents = false;
749
+
750
+ const LEVEL_DESCRIPTIONS = {
751
+ L0: '<strong>L0 - Raw Events:</strong> Unprocessed events from conversations. Includes user prompts, agent responses, and tool observations.',
752
+ L1: '<strong>L1 - Structured:</strong> Events that have been analyzed and structured. Contains session summaries and extracted patterns.',
753
+ L2: '<strong>L2 - Validated:</strong> Type candidates with validated schemas. Events that have been cross-referenced and verified.',
754
+ L3: '<strong>L3 - Verified:</strong> Cross-session validated knowledge. High-confidence information verified across multiple sessions.',
755
+ L4: '<strong>L4 - Active:</strong> Indexed and readily searchable memories. The most refined and accessible knowledge.'
756
+ };
757
+
483
758
  async function fetchStats() {
484
759
  try {
485
760
  const response = await fetch(`${API_BASE}/stats`);
@@ -535,6 +810,171 @@
535
810
  }
536
811
  }
537
812
 
813
+ async function fetchMostAccessed() {
814
+ try {
815
+ const response = await fetch(`${API_BASE}/stats/most-accessed?limit=10`);
816
+ if (!response.ok) throw new Error('Failed to fetch most accessed');
817
+ return await response.json();
818
+ } catch (error) {
819
+ console.error('Most accessed fetch error:', error);
820
+ return null;
821
+ }
822
+ }
823
+
824
+ async function fetchLevelEvents(level, offset = 0) {
825
+ try {
826
+ const response = await fetch(`${API_BASE}/stats/levels/${level}?limit=${pageSize}&offset=${offset}`);
827
+ if (!response.ok) throw new Error('Failed to fetch level events');
828
+ return await response.json();
829
+ } catch (error) {
830
+ console.error('Level events fetch error:', error);
831
+ return null;
832
+ }
833
+ }
834
+
835
+ function selectLevel(level) {
836
+ currentLevel = level;
837
+ currentOffset = 0;
838
+
839
+ // Update tab styles
840
+ document.querySelectorAll('.level-tab').forEach(tab => {
841
+ tab.classList.toggle('active', tab.dataset.level === level);
842
+ });
843
+
844
+ // Update pipeline visualization
845
+ document.querySelectorAll('.pipeline-step').forEach(step => {
846
+ step.classList.toggle('active', step.dataset.level === level);
847
+ });
848
+
849
+ // Update description
850
+ document.getElementById('level-description').innerHTML = LEVEL_DESCRIPTIONS[level];
851
+
852
+ // Load events for this level
853
+ loadLevelEvents(level, true);
854
+ }
855
+
856
+ async function loadLevelEvents(level, reset = false) {
857
+ const container = document.getElementById('level-events-list');
858
+ const loadMoreBtn = document.getElementById('load-more-btn');
859
+
860
+ if (reset) {
861
+ currentOffset = 0;
862
+ container.innerHTML = '<div class="loading-spinner">Loading...</div>';
863
+ }
864
+
865
+ const data = await fetchLevelEvents(level, currentOffset);
866
+
867
+ if (!data || !data.events) {
868
+ if (reset) {
869
+ container.innerHTML = '<div class="empty-state">Failed to load events</div>';
870
+ }
871
+ loadMoreBtn.style.display = 'none';
872
+ return;
873
+ }
874
+
875
+ if (data.events.length === 0 && reset) {
876
+ container.innerHTML = `<div class="empty-state">No events at level ${level} yet</div>`;
877
+ loadMoreBtn.style.display = 'none';
878
+ return;
879
+ }
880
+
881
+ const eventsHtml = data.events.map(event => {
882
+ const typeClass = event.eventType.replace('_', '-');
883
+ const time = formatTimeAgo(event.timestamp);
884
+ return `
885
+ <div class="event-card">
886
+ <div>
887
+ <span class="event-type ${event.eventType}">${event.eventType}</span>
888
+ <span style="color: var(--text-secondary); font-size: 0.85rem;">${time}</span>
889
+ <span style="color: var(--text-secondary); font-size: 0.75rem; margin-left: 8px;">
890
+ Session: ${event.sessionId.slice(0, 8)}...
891
+ </span>
892
+ </div>
893
+ <div class="event-content">${escapeHtml(event.content)}</div>
894
+ </div>
895
+ `;
896
+ }).join('');
897
+
898
+ if (reset) {
899
+ container.innerHTML = eventsHtml;
900
+ } else {
901
+ container.innerHTML += eventsHtml;
902
+ }
903
+
904
+ hasMoreEvents = data.hasMore;
905
+ loadMoreBtn.style.display = hasMoreEvents ? 'block' : 'none';
906
+ }
907
+
908
+ function loadMoreEvents() {
909
+ currentOffset += pageSize;
910
+ loadLevelEvents(currentLevel, false);
911
+ }
912
+
913
+ async function runGraduation() {
914
+ const btn = document.getElementById('run-graduation-btn');
915
+ const icon = document.getElementById('graduation-icon');
916
+ const resultDiv = document.getElementById('graduation-result');
917
+
918
+ btn.classList.add('loading');
919
+ icon.textContent = '⏳';
920
+ resultDiv.style.display = 'none';
921
+
922
+ try {
923
+ const response = await fetch('/api/stats/graduation/run', { method: 'POST' });
924
+ const data = await response.json();
925
+
926
+ if (data.success) {
927
+ let message = `✅ Evaluated ${data.evaluated} events, graduated ${data.graduated}`;
928
+ if (data.graduated > 0 && Object.keys(data.byLevel).length > 0) {
929
+ const levels = Object.entries(data.byLevel)
930
+ .map(([level, count]) => `${level}: ${count}`)
931
+ .join(', ');
932
+ message += ` (${levels})`;
933
+ }
934
+ resultDiv.innerHTML = `<div style="padding: 12px; background: rgba(74, 222, 128, 0.1); border-radius: 8px; color: var(--success);">${message}</div>`;
935
+ resultDiv.style.display = 'block';
936
+
937
+ // Refresh data to show updated counts
938
+ if (data.graduated > 0) {
939
+ setTimeout(() => {
940
+ refreshData();
941
+ }, 500);
942
+ }
943
+ } else {
944
+ resultDiv.innerHTML = `<div style="padding: 12px; background: rgba(233, 69, 96, 0.1); border-radius: 8px; color: var(--accent);">❌ ${data.error || 'Graduation failed'}</div>`;
945
+ resultDiv.style.display = 'block';
946
+ }
947
+ } catch (error) {
948
+ resultDiv.innerHTML = `<div style="padding: 12px; background: rgba(233, 69, 96, 0.1); border-radius: 8px; color: var(--accent);">❌ Error: ${error.message}</div>`;
949
+ resultDiv.style.display = 'block';
950
+ } finally {
951
+ btn.classList.remove('loading');
952
+ icon.textContent = '⚡';
953
+ }
954
+ }
955
+
956
+ function escapeHtml(text) {
957
+ const div = document.createElement('div');
958
+ div.textContent = text;
959
+ return div.innerHTML;
960
+ }
961
+
962
+ function updateLevelCounts(stats) {
963
+ if (!stats || !stats.levelStats) return;
964
+
965
+ // Reset all counts to 0
966
+ ['L0', 'L1', 'L2', 'L3', 'L4'].forEach(level => {
967
+ const el = document.getElementById(`level-count-${level}`);
968
+ if (el) el.textContent = '0';
969
+ });
970
+
971
+ // Update with actual counts
972
+ stats.levelStats.forEach(stat => {
973
+ const el = document.getElementById(`level-count-${stat.level}`);
974
+ if (el) el.textContent = formatNumber(stat.count);
975
+ });
976
+ }
977
+
538
978
  async function searchMemories(query) {
539
979
  try {
540
980
  const response = await fetch(`${API_BASE}/search?q=${encodeURIComponent(query)}&limit=10`);
@@ -622,19 +1062,24 @@
622
1062
  return;
623
1063
  }
624
1064
 
625
- container.innerHTML = sessions.map(session => `
626
- <li class="session-item">
627
- <div class="session-header">
628
- <span class="session-id">${session.sessionId.slice(0, 16)}...</span>
629
- <span class="session-time">${formatTimeAgo(session.lastActivity || session.startTime)}</span>
630
- </div>
631
- <div class="session-meta">
632
- <span>📝 ${session.eventCount || 0} events</span>
633
- <span>👤 ${session.promptCount || 0} prompts</span>
634
- <span>🤖 ${session.responseCount || 0} responses</span>
635
- </div>
636
- </li>
637
- `).join('');
1065
+ container.innerHTML = sessions.map(session => {
1066
+ // Handle both API formats: id/sessionId, lastEventAt/lastActivity
1067
+ const sessionId = session.id || session.sessionId || 'unknown';
1068
+ const lastTime = session.lastEventAt || session.lastActivity || session.startedAt || session.startTime;
1069
+ const eventCount = session.eventCount || 0;
1070
+
1071
+ return `
1072
+ <li class="session-item">
1073
+ <div class="session-header">
1074
+ <span class="session-id">${sessionId.slice(0, 16)}...</span>
1075
+ <span class="session-time">${formatTimeAgo(lastTime)}</span>
1076
+ </div>
1077
+ <div class="session-meta">
1078
+ <span>📝 ${eventCount} events</span>
1079
+ </div>
1080
+ </li>
1081
+ `;
1082
+ }).join('');
638
1083
  }
639
1084
 
640
1085
  function updateTimeline(timeline) {
@@ -666,6 +1111,37 @@
666
1111
  labels.innerHTML = `<span>${firstDate}</span><span>${lastDate}</span>`;
667
1112
  }
668
1113
 
1114
+ function updateMostAccessed(data) {
1115
+ const container = document.getElementById('most-accessed-list');
1116
+
1117
+ if (!data || !data.memories || data.memories.length === 0) {
1118
+ container.innerHTML = '<div class="empty-state">No memory access data yet. Memories will appear here as they are referenced.</div>';
1119
+ return;
1120
+ }
1121
+
1122
+ container.innerHTML = data.memories.map(memory => {
1123
+ const accessBars = '█'.repeat(Math.min(10, memory.accessCount));
1124
+ const accessEmpty = '░'.repeat(Math.max(0, 10 - memory.accessCount));
1125
+ const lastAccessed = memory.lastAccessed ? formatTimeAgo(memory.lastAccessed) : 'Never';
1126
+
1127
+ return `
1128
+ <div class="session-item">
1129
+ <div class="session-header">
1130
+ <span class="session-id">🧠 ${memory.topics?.slice(0, 2).join(', ') || 'Memory'}</span>
1131
+ <span class="session-time">${lastAccessed}</span>
1132
+ </div>
1133
+ <div style="margin: 8px 0;">
1134
+ <span style="color: var(--text-secondary); font-size: 0.85rem;">Access count:</span>
1135
+ <span style="font-family: monospace; color: var(--accent);">[${accessBars}${accessEmpty}] ${memory.accessCount}</span>
1136
+ </div>
1137
+ <p style="color: var(--text-secondary); font-size: 0.9rem; margin-top: 8px;">
1138
+ ${memory.summary?.slice(0, 150) || 'No summary'}${memory.summary?.length > 150 ? '...' : ''}
1139
+ </p>
1140
+ </div>
1141
+ `;
1142
+ }).join('');
1143
+ }
1144
+
669
1145
  function showSearchResults(results) {
670
1146
  const container = document.getElementById('search-results');
671
1147
  const content = document.getElementById('search-results-content');
@@ -714,12 +1190,13 @@
714
1190
  document.getElementById('refresh-icon').textContent = '⏳';
715
1191
 
716
1192
  try {
717
- const [stats, sharedStats, endlessStatus, sessions, timeline] = await Promise.all([
1193
+ const [stats, sharedStats, endlessStatus, sessions, timeline, mostAccessed] = await Promise.all([
718
1194
  fetchStats(),
719
1195
  fetchSharedStats(),
720
1196
  fetchEndlessStatus(),
721
1197
  fetchSessions(),
722
- fetchTimeline()
1198
+ fetchTimeline(),
1199
+ fetchMostAccessed()
723
1200
  ]);
724
1201
 
725
1202
  updateStats(stats);
@@ -727,6 +1204,9 @@
727
1204
  updateEndlessStatus(endlessStatus);
728
1205
  updateSessions(sessions?.sessions || sessions || []);
729
1206
  updateTimeline(timeline);
1207
+ updateMostAccessed(mostAccessed);
1208
+ updateLevelCounts(stats);
1209
+ loadLevelEvents(currentLevel, true);
730
1210
  } catch (error) {
731
1211
  console.error('Refresh error:', error);
732
1212
  } finally {