@jungjaehoon/mama-os 0.62.0 → 0.64.0

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 (106) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +1 -1
  3. package/dist/api/attachment-actions.d.ts.map +1 -1
  4. package/dist/api/attachment-actions.js +6 -2
  5. package/dist/api/attachment-actions.js.map +1 -1
  6. package/dist/api/drive-actions.d.ts +2 -1
  7. package/dist/api/drive-actions.d.ts.map +1 -1
  8. package/dist/api/drive-actions.js +1 -0
  9. package/dist/api/drive-actions.js.map +1 -1
  10. package/dist/api/drive-delivery.d.ts +16 -0
  11. package/dist/api/drive-delivery.d.ts.map +1 -0
  12. package/dist/api/drive-delivery.js +190 -0
  13. package/dist/api/drive-delivery.js.map +1 -0
  14. package/dist/api/file-delivery.d.ts +2 -2
  15. package/dist/api/file-delivery.d.ts.map +1 -1
  16. package/dist/api/file-delivery.js +5 -5
  17. package/dist/api/file-delivery.js.map +1 -1
  18. package/dist/api/security-events.d.ts +5 -4
  19. package/dist/api/security-events.d.ts.map +1 -1
  20. package/dist/api/security-events.js +25 -3
  21. package/dist/api/security-events.js.map +1 -1
  22. package/dist/api/viewer-data.d.ts +82 -1
  23. package/dist/api/viewer-data.d.ts.map +1 -1
  24. package/dist/api/viewer-data.js +116 -0
  25. package/dist/api/viewer-data.js.map +1 -1
  26. package/dist/api/viewer-server.d.ts +2 -2
  27. package/dist/api/viewer-server.d.ts.map +1 -1
  28. package/dist/api/viewer-server.js +154 -5
  29. package/dist/api/viewer-server.js.map +1 -1
  30. package/dist/api/wiki-actions.d.ts.map +1 -1
  31. package/dist/api/wiki-actions.js +44 -0
  32. package/dist/api/wiki-actions.js.map +1 -1
  33. package/dist/api/work-actions.d.ts +2 -0
  34. package/dist/api/work-actions.d.ts.map +1 -1
  35. package/dist/api/work-actions.js +4 -5
  36. package/dist/api/work-actions.js.map +1 -1
  37. package/dist/cli/commands/daemon.d.ts.map +1 -1
  38. package/dist/cli/commands/daemon.js +14 -7
  39. package/dist/cli/commands/daemon.js.map +1 -1
  40. package/dist/gateways/discord.d.ts.map +1 -1
  41. package/dist/gateways/discord.js +1 -1
  42. package/dist/gateways/discord.js.map +1 -1
  43. package/dist/gateways/slack.d.ts.map +1 -1
  44. package/dist/gateways/slack.js +1 -1
  45. package/dist/gateways/slack.js.map +1 -1
  46. package/dist/gateways/telegram.d.ts.map +1 -1
  47. package/dist/gateways/telegram.js +1 -1
  48. package/dist/gateways/telegram.js.map +1 -1
  49. package/dist/replay/replay-source-catalog.js +1 -1
  50. package/dist/replay/replay-source-catalog.js.map +1 -1
  51. package/dist/runtime/action-surface.d.ts +4 -1
  52. package/dist/runtime/action-surface.d.ts.map +1 -1
  53. package/dist/runtime/action-surface.js +19 -1
  54. package/dist/runtime/action-surface.js.map +1 -1
  55. package/dist/runtime/config.d.ts +20 -0
  56. package/dist/runtime/config.d.ts.map +1 -1
  57. package/dist/runtime/config.js +48 -3
  58. package/dist/runtime/config.js.map +1 -1
  59. package/dist/runtime/outbound-attempts.d.ts +4 -2
  60. package/dist/runtime/outbound-attempts.d.ts.map +1 -1
  61. package/dist/runtime/outbound-attempts.js +17 -1
  62. package/dist/runtime/outbound-attempts.js.map +1 -1
  63. package/dist/runtime/owner-runtime.d.ts +6 -1
  64. package/dist/runtime/owner-runtime.d.ts.map +1 -1
  65. package/dist/runtime/owner-runtime.js +4 -1
  66. package/dist/runtime/owner-runtime.js.map +1 -1
  67. package/dist/runtime/owner-system-prompt.d.ts +1 -1
  68. package/dist/runtime/owner-system-prompt.d.ts.map +1 -1
  69. package/dist/runtime/owner-system-prompt.js +10 -4
  70. package/dist/runtime/owner-system-prompt.js.map +1 -1
  71. package/dist/runtime/report-scheduler.d.ts +2 -1
  72. package/dist/runtime/report-scheduler.d.ts.map +1 -1
  73. package/dist/runtime/report-scheduler.js +1 -1
  74. package/dist/runtime/report-scheduler.js.map +1 -1
  75. package/dist/runtime/stimulus-delivery.js +1 -1
  76. package/dist/runtime/stimulus-delivery.js.map +1 -1
  77. package/dist/runtime/turn-orders.d.ts.map +1 -1
  78. package/dist/runtime/turn-orders.js +7 -3
  79. package/dist/runtime/turn-orders.js.map +1 -1
  80. package/dist/wiki/obsidian-writer.d.ts +0 -3
  81. package/dist/wiki/obsidian-writer.d.ts.map +1 -1
  82. package/dist/wiki/obsidian-writer.js +8 -108
  83. package/dist/wiki/obsidian-writer.js.map +1 -1
  84. package/dist/wiki/path-safety.d.ts +1 -1
  85. package/dist/wiki/path-safety.d.ts.map +1 -1
  86. package/dist/wiki/path-safety.js +2 -2
  87. package/dist/wiki/path-safety.js.map +1 -1
  88. package/dist/wiki/wiki-move.d.ts +12 -0
  89. package/dist/wiki/wiki-move.d.ts.map +1 -0
  90. package/dist/wiki/wiki-move.js +95 -0
  91. package/dist/wiki/wiki-move.js.map +1 -0
  92. package/dist/wiki/wiki-read.d.ts +7 -0
  93. package/dist/wiki/wiki-read.d.ts.map +1 -1
  94. package/dist/wiki/wiki-read.js +38 -17
  95. package/dist/wiki/wiki-read.js.map +1 -1
  96. package/package.json +2 -2
  97. package/public/viewer/js/modules/graph.js +266 -992
  98. package/public/viewer/js/modules/memory-timeline.js +216 -0
  99. package/public/viewer/js/modules/wiki.js +4 -4
  100. package/public/viewer/js/utils/api.js +7 -26
  101. package/public/viewer/src/modules/graph.ts +307 -1185
  102. package/public/viewer/src/modules/memory-timeline.ts +280 -0
  103. package/public/viewer/src/modules/wiki.ts +4 -4
  104. package/public/viewer/src/utils/api.ts +48 -47
  105. package/public/viewer/viewer.css +257 -7
  106. package/public/viewer/viewer.html +68 -292
@@ -427,7 +427,7 @@
427
427
 
428
428
  <div class="tab-content" id="tab-memory">
429
429
  <div class="flex-1 flex flex-col min-h-0">
430
- <!-- Compact Filter Bar (full width, top) -->
430
+ <!-- Period, kinds and search: every control is a server read of the saved timeline -->
431
431
  <div
432
432
  class="memory-controls flex items-center gap-2 px-3 py-2 border-b border-gray-200 bg-white"
433
433
  >
@@ -436,7 +436,7 @@
436
436
  id="checkpoint-sidebar-toggle"
437
437
  class="w-7 h-7 bg-white border border-gray-200 rounded flex items-center justify-center text-gray-500 hover:bg-gray-100 hover:text-gray-700"
438
438
  onclick="toggleCheckpointSidebar()"
439
- title="Toggle Decision List"
439
+ title="Show or hide the saved list"
440
440
  aria-controls="checkpoint-sidebar"
441
441
  aria-expanded="true"
442
442
  >
@@ -456,129 +456,29 @@
456
456
  <line x1="9" y1="21" x2="9" y2="9" />
457
457
  </svg>
458
458
  </button>
459
- <!-- Stats (compact inline) -->
460
- <span
461
- id="memory-stats-total"
462
- style="
463
- font-family: Inter, 'Noto Sans KR', sans-serif;
464
- font-size: 13px;
465
- font-weight: 600;
466
- color: #1a1a1a;
467
- "
468
- >-</span
469
- >
470
- <span style="font-size: 11px; color: #9e9891">decisions</span>
471
- <span style="color: #ede9e1">|</span>
472
- <span id="memory-stats-week" style="font-size: 11px; color: #6b6560"
473
- >- this week</span
474
- >
475
- <!-- Spacer -->
476
- <div style="flex: 1"></div>
477
- <!-- Topic filter -->
478
- <input
479
- list="topic-filter-list"
480
- class="px-2 py-1 bg-white border border-gray-200 rounded text-xs focus:outline-none focus:ring-1 focus:ring-yellow-400"
481
- id="topic-filter"
482
- placeholder="Filter topics..."
483
- oninput="filterByTopic(this.value)"
484
- />
485
- <datalist id="topic-filter-list"></datalist>
486
- <select
487
- class="px-2 py-1 bg-white border border-gray-200 rounded text-xs focus:outline-none focus:ring-1 focus:ring-yellow-400"
488
- id="outcome-filter"
489
- onchange="filterByOutcome(this.value)"
490
- style="display: none"
491
- >
492
- <option value="">All Outcomes</option>
493
- <option value="success">Success</option>
494
- <option value="failed">Failed</option>
495
- <option value="partial">Partial</option>
496
- <option value="pending">Pending</option>
497
- </select>
498
- <!-- Search -->
459
+ <div class="memory-periods" role="group" aria-label="Period">
460
+ <button type="button" class="memory-chip" data-memory-period="today">
461
+ Today
462
+ </button>
463
+ <button type="button" class="memory-chip" data-memory-period="7d">7 days</button>
464
+ <button type="button" class="memory-chip" data-memory-period="30d">
465
+ 30 days
466
+ </button>
467
+ <input type="date" id="memory-day" class="memory-day" aria-label="One day" />
468
+ </div>
469
+ <div
470
+ id="memory-group-chips"
471
+ class="memory-groups"
472
+ role="group"
473
+ aria-label="Kinds"
474
+ ></div>
499
475
  <input
500
- type="text"
476
+ type="search"
477
+ id="memory-timeline-search"
501
478
  class="px-2 py-1 bg-white border border-gray-200 rounded text-xs placeholder-gray-400 focus:outline-none focus:ring-1 focus:ring-yellow-400"
502
- id="search-input"
503
- placeholder="Search content..."
504
- onkeyup="handleGraphSearch(event)"
479
+ placeholder="Search saved text..."
480
+ aria-label="Search saved text"
505
481
  />
506
- <button
507
- onclick="clearFilters()"
508
- class="px-2 py-1 text-[10px] text-gray-400 hover:text-gray-600"
509
- >
510
- Clear
511
- </button>
512
- <!-- Export (collapsed) -->
513
- <details style="position: relative">
514
- <summary
515
- style="
516
- font-size: 10px;
517
- color: #9e9891;
518
- cursor: pointer;
519
- padding: 4px 8px;
520
- border: 1px solid #ede9e1;
521
- border-radius: 4px;
522
- "
523
- >
524
- Export
525
- </summary>
526
- <div
527
- style="
528
- position: absolute;
529
- right: 0;
530
- top: 100%;
531
- background: #fff;
532
- border: 1px solid #ede9e1;
533
- border-radius: 4px;
534
- padding: 4px;
535
- z-index: 10;
536
- display: flex;
537
- gap: 4px;
538
- margin-top: 2px;
539
- "
540
- >
541
- <button
542
- onclick="exportDecisions('json')"
543
- style="
544
- font-size: 10px;
545
- padding: 2px 8px;
546
- background: #f5f2ed;
547
- border: none;
548
- border-radius: 2px;
549
- cursor: pointer;
550
- "
551
- >
552
- JSON
553
- </button>
554
- <button
555
- onclick="exportDecisions('markdown')"
556
- style="
557
- font-size: 10px;
558
- padding: 2px 8px;
559
- background: #f5f2ed;
560
- border: none;
561
- border-radius: 2px;
562
- cursor: pointer;
563
- "
564
- >
565
- MD
566
- </button>
567
- <button
568
- onclick="exportDecisions('csv')"
569
- style="
570
- font-size: 10px;
571
- padding: 2px 8px;
572
- background: #f5f2ed;
573
- border: none;
574
- border-radius: 2px;
575
- cursor: pointer;
576
- "
577
- >
578
- CSV
579
- </button>
580
- </div>
581
- </details>
582
482
  </div>
583
483
 
584
484
  <!-- Main content area: Sidebar + Graph -->
@@ -586,25 +486,15 @@
586
486
  <!-- Decision List Sidebar -->
587
487
  <aside
588
488
  id="checkpoint-sidebar"
589
- class="checkpoint-sidebar w-64 border-r border-gray-200 bg-white flex flex-col min-h-0 overflow-hidden"
590
- style="min-width: 180px; max-width: 400px"
489
+ class="checkpoint-sidebar w-96 border-r border-gray-200 bg-white flex flex-col min-h-0 overflow-hidden"
490
+ style="min-width: 240px; max-width: 640px"
591
491
  >
592
- <div class="p-2 border-b border-gray-200 flex items-center justify-between">
593
- <span
594
- style="
595
- font-family: Inter, 'Noto Sans KR', sans-serif;
596
- font-size: 12px;
597
- font-weight: 600;
598
- color: #1a1a1a;
599
- "
600
- >Decisions</span
601
- >
602
- <span id="decision-list-count" style="font-size: 10px; color: #9e9891">0</span>
492
+ <div class="mt-head">
493
+ <span id="memory-timeline-range" class="mt-range">Saved</span>
494
+ <span id="memory-timeline-count" class="mt-total"></span>
603
495
  </div>
604
- <div class="flex-1 overflow-y-auto" id="decision-list" style="padding: 4px">
605
- <div style="padding: 16px; text-align: center; color: #9e9891; font-size: 11px">
606
- Loading decisions...
607
- </div>
496
+ <div class="flex-1 overflow-y-auto" id="memory-timeline">
497
+ <div class="mt-empty">Reading what was saved...</div>
608
498
  </div>
609
499
  </aside>
610
500
 
@@ -629,18 +519,23 @@
629
519
  style="background: #fafafa"
630
520
  ></div>
631
521
 
522
+ <div class="absolute inset-0 flex items-center justify-center" id="graph-empty">
523
+ Reading what was saved...
524
+ </div>
525
+
632
526
  <div
633
527
  class="absolute inset-0 flex flex-col items-center justify-center bg-white/95"
634
528
  id="graph-loading"
529
+ style="display: none"
635
530
  >
636
531
  <div
637
532
  class="w-6 h-6 border-2 border-gray-400 border-t-transparent rounded-full animate-spin"
638
533
  ></div>
639
- <span class="mt-2 text-xs text-gray-500">Loading graph...</span>
534
+ <span class="mt-2 text-xs text-gray-500">Reading links...</span>
640
535
  </div>
641
536
 
642
537
  <div
643
- class="legend-panel absolute bottom-16 right-4 w-64 bg-white/95 backdrop-blur-sm border border-gray-200 rounded-lg shadow-lg p-3 z-10"
538
+ class="legend-panel absolute bottom-16 right-4 w-80 bg-white/95 backdrop-blur-sm border border-gray-200 rounded-lg shadow-lg p-3 z-10"
644
539
  id="legend-panel"
645
540
  >
646
541
  <button
@@ -662,9 +557,7 @@
662
557
  <line x1="6" y1="6" x2="18" y2="18" />
663
558
  </svg>
664
559
  </button>
665
- <h4
666
- class="text-xs font-semibold text-gray-700 text-gray-700 flex items-center gap-1.5 mb-3"
667
- >
560
+ <h4 class="text-sm font-semibold text-gray-700 flex items-center gap-1.5 mb-3">
668
561
  <svg
669
562
  xmlns="http://www.w3.org/2000/svg"
670
563
  width="14"
@@ -680,11 +573,11 @@
680
573
  <line x1="12" y1="16" x2="12" y2="12" />
681
574
  <line x1="12" y1="8" x2="12.01" y2="8" />
682
575
  </svg>
683
- Legend
576
+ What the dots and lines mean
684
577
  </h4>
685
578
  <div
686
579
  id="graph-legend-content"
687
- class="legend-content space-y-3 max-h-64 overflow-y-auto"
580
+ class="legend-content space-y-3 max-h-80 overflow-y-auto"
688
581
  ></div>
689
582
  </div>
690
583
  <button
@@ -725,7 +618,7 @@
725
618
  id="detail-modal-header"
726
619
  >
727
620
  <h3 class="text-sm font-semibold text-gray-900 truncate flex-1" id="detail-topic">
728
- Decision Detail
621
+ Record
729
622
  </h3>
730
623
  <button
731
624
  class="p-1 rounded hover:bg-gray-200 transition-colors text-gray-500 hover:text-gray-700 ml-2"
@@ -747,9 +640,12 @@
747
640
  </svg>
748
641
  </button>
749
642
  </div>
750
- <div class="flex-1 p-3 overflow-y-auto space-y-3 text-xs">
643
+ <div class="flex-1 p-3 overflow-y-auto space-y-3 text-sm">
644
+ <div class="flex gap-4 text-xs text-gray-500">
645
+ <span id="detail-kind"></span>
646
+ <span>Saved <span id="detail-created"></span></span>
647
+ </div>
751
648
  <div>
752
- <div class="font-semibold text-gray-500 uppercase tracking-wide mb-1">Decision</div>
753
649
  <div
754
650
  class="text-gray-900 leading-relaxed markdown-content"
755
651
  id="detail-decision"
@@ -757,55 +653,16 @@
757
653
  </div>
758
654
  <div>
759
655
  <div
760
- class="font-semibold text-gray-500 uppercase tracking-wide mb-1 cursor-pointer hover:text-gray-700"
656
+ class="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-1 cursor-pointer hover:text-gray-700"
761
657
  onclick="toggleReasoning()"
762
658
  >
763
- <span id="reasoning-arrow">▶</span> Reasoning
659
+ <span id="reasoning-arrow">▶</span> Reasoning and evidence
764
660
  </div>
765
661
  <div
766
662
  class="text-gray-900 leading-relaxed markdown-content hidden"
767
663
  id="detail-reasoning"
768
664
  ></div>
769
665
  </div>
770
- <div class="flex items-center gap-3">
771
- <div class="flex items-center gap-2">
772
- <span class="font-semibold text-gray-500 uppercase">Outcome:</span>
773
- <select
774
- class="px-1.5 py-0.5 bg-white border border-gray-200 rounded text-xs focus:outline-none focus:ring-1 focus:ring-yellow-400"
775
- id="detail-outcome-select"
776
- >
777
- <option value="PENDING">PENDING</option>
778
- <option value="SUCCESS">SUCCESS</option>
779
- <option value="FAILED">FAILED</option>
780
- <option value="PARTIAL">PARTIAL</option>
781
- </select>
782
- <button
783
- class="px-1.5 py-0.5 bg-gray-100 hover:bg-gray-200 rounded transition-colors"
784
- onclick="saveOutcome()"
785
- >
786
- Save
787
- </button>
788
- <span id="outcome-status"></span>
789
- </div>
790
- </div>
791
- <div class="flex gap-4">
792
- <div>
793
- <span class="font-semibold text-gray-500 uppercase">Confidence:</span>
794
- <span class="text-gray-900" id="detail-confidence"></span>
795
- </div>
796
- <div>
797
- <span class="font-semibold text-gray-500 uppercase">Created:</span>
798
- <span class="text-gray-900" id="detail-created"></span>
799
- </div>
800
- </div>
801
- <div>
802
- <div class="font-semibold text-gray-500 uppercase tracking-wide mb-1">
803
- Similar Decisions
804
- </div>
805
- <div class="text-gray-900" id="detail-similar">
806
- <span class="text-gray-400">Searching...</span>
807
- </div>
808
- </div>
809
666
  </div>
810
667
  <div
811
668
  id="decision-resize-handle"
@@ -1202,6 +1059,7 @@ export MAMA_AUTH_TOKEN="your-secure-token-here"</pre
1202
1059
 
1203
1060
  <script type="module">
1204
1061
  import { GraphModule } from '/viewer/js/modules/graph.js';
1062
+ import { MemoryTimelineModule } from '/viewer/js/modules/memory-timeline.js';
1205
1063
  import { MemoryModule } from '/viewer/js/modules/memory.js';
1206
1064
  import { WikiModule } from '/viewer/js/modules/wiki.js';
1207
1065
  import { renderRuntimeView, renderConnectorsView } from '/viewer/js/modules/system.js';
@@ -1209,6 +1067,18 @@ export MAMA_AUTH_TOKEN="your-secure-token-here"</pre
1209
1067
 
1210
1068
  const memory = new MemoryModule();
1211
1069
  const graph = new GraphModule();
1070
+ const timeline = new MemoryTimelineModule({
1071
+ onSelect: (id) => graph.focusRecord(id),
1072
+ onRender: (data) =>
1073
+ graph.showSelection(data).catch((error) => {
1074
+ console.error('[MAMA] Failed to draw the memory graph:', error);
1075
+ const empty = document.getElementById('graph-empty');
1076
+ if (empty) {
1077
+ empty.style.display = '';
1078
+ empty.textContent = `Could not read the links between records: ${error.message}`;
1079
+ }
1080
+ }),
1081
+ });
1212
1082
  const wiki = new WikiModule();
1213
1083
 
1214
1084
  // Exposed for inline handlers and debugging.
@@ -1368,7 +1238,6 @@ export MAMA_AUTH_TOKEN="your-secure-token-here"</pre
1368
1238
  route: DEFAULT_ROUTE,
1369
1239
  routeKey: null,
1370
1240
  theme: 'light',
1371
- graphLoaded: false,
1372
1241
  };
1373
1242
 
1374
1243
  async function applyRoute(route) {
@@ -1400,22 +1269,7 @@ export MAMA_AUTH_TOKEN="your-secure-token-here"</pre
1400
1269
 
1401
1270
  if (route.view === 'memory') {
1402
1271
  updateCheckpointSidebarForScreenSize();
1403
- updateMemoryStats();
1404
- if (!STATE.graphLoaded) {
1405
- try {
1406
- const data = await graph.fetchData();
1407
- graph.init(data);
1408
- STATE.graphLoaded = true;
1409
- const loadingEl = document.getElementById('graph-loading');
1410
- if (loadingEl) loadingEl.style.display = 'none';
1411
- } catch (error) {
1412
- console.error('[MAMA] Failed to load graph:', error);
1413
- const loadingEl = document.getElementById('graph-loading');
1414
- if (loadingEl) {
1415
- loadingEl.innerHTML = '<span class="text-red-500">Failed to load graph data</span>';
1416
- }
1417
- }
1418
- }
1272
+ await timeline.init();
1419
1273
  return;
1420
1274
  }
1421
1275
 
@@ -1668,9 +1522,9 @@ export MAMA_AUTH_TOKEN="your-secure-token-here"</pre
1668
1522
  const isExpanding = sidebar.classList.contains('collapsed');
1669
1523
  if (isExpanding) {
1670
1524
  sidebar.classList.remove('collapsed');
1671
- sidebar.style.width = '224px'; // w-56 = 14rem = 224px
1525
+ sidebar.style.width = '';
1672
1526
  if (toggleBtn) {
1673
- toggleBtn.title = 'Hide Checkpoints';
1527
+ toggleBtn.title = 'Hide the saved list';
1674
1528
  toggleBtn.setAttribute('aria-expanded', 'true');
1675
1529
  }
1676
1530
  if (handle) handle.style.display = '';
@@ -1678,7 +1532,7 @@ export MAMA_AUTH_TOKEN="your-secure-token-here"</pre
1678
1532
  sidebar.classList.add('collapsed');
1679
1533
  sidebar.style.width = '0';
1680
1534
  if (toggleBtn) {
1681
- toggleBtn.title = 'Show Checkpoints';
1535
+ toggleBtn.title = 'Show the saved list';
1682
1536
  toggleBtn.setAttribute('aria-expanded', 'false');
1683
1537
  }
1684
1538
  if (handle) handle.style.display = 'none';
@@ -1696,17 +1550,18 @@ export MAMA_AUTH_TOKEN="your-secure-token-here"</pre
1696
1550
  // Mobile: stack layout with resizable height
1697
1551
  sidebar.classList.remove('collapsed');
1698
1552
  sidebar.style.width = '100%';
1699
- sidebar.style.height = '30vh';
1553
+ sidebar.style.height = '55vh';
1700
1554
  if (handle) {
1701
1555
  handle.style.display = '';
1702
1556
  handle.classList.add('sidebar-resize-handle--row');
1703
1557
  }
1704
1558
  if (toggleBtn) toggleBtn.setAttribute('aria-expanded', 'true');
1705
1559
  } else {
1706
- // Desktop: expand if was collapsed due to mobile
1560
+ // Desktop: the stacked layout's full width and any collapse give way to the class width.
1561
+ if (sidebar.style.width === '100%') sidebar.style.width = '';
1707
1562
  if (sidebar.classList.contains('collapsed')) {
1708
1563
  sidebar.classList.remove('collapsed');
1709
- sidebar.style.width = '224px';
1564
+ sidebar.style.width = '';
1710
1565
  }
1711
1566
  sidebar.style.height = '';
1712
1567
  if (handle) {
@@ -1846,79 +1701,6 @@ export MAMA_AUTH_TOKEN="your-secure-token-here"</pre
1846
1701
  .catch(() => (result.innerHTML = '<span class="text-red-500">Connection failed</span>'));
1847
1702
  }
1848
1703
 
1849
- function filterByTopic(topic) {
1850
- graph.filterByTopic && graph.filterByTopic(topic);
1851
- }
1852
-
1853
- function filterByOutcome(outcome) {
1854
- graph.filterByOutcome && graph.filterByOutcome(outcome);
1855
- }
1856
-
1857
- // Clear is scoped to the Graph module instance that owns the filters. Each
1858
- // control is looked up defensively: the bar is markup that can be edited,
1859
- // and one missing input must not take the whole Clear action down.
1860
- function clearFilters() {
1861
- const topicFilter = document.getElementById('topic-filter');
1862
- const outcomeFilter = document.getElementById('outcome-filter');
1863
- const searchInput = document.getElementById('search-input');
1864
- if (topicFilter) topicFilter.value = '';
1865
- if (outcomeFilter) outcomeFilter.value = '';
1866
- if (searchInput) searchInput.value = '';
1867
- graph?.clearFilters?.();
1868
- }
1869
-
1870
- async function exportDecisions(format) {
1871
- try {
1872
- const response = await fetch(`/api/memory/export?format=${format}`);
1873
- if (!response.ok) throw new Error('Export failed');
1874
-
1875
- const blob = await response.blob();
1876
- const filename =
1877
- response.headers.get('Content-Disposition')?.match(/filename="(.+)"/)?.[1] ||
1878
- `mama-export.${format}`;
1879
-
1880
- const url = URL.createObjectURL(blob);
1881
- const a = document.createElement('a');
1882
- a.href = url;
1883
- a.download = filename;
1884
- document.body.appendChild(a);
1885
- a.click();
1886
- document.body.removeChild(a);
1887
- URL.revokeObjectURL(url);
1888
- } catch (error) {
1889
- console.error('[Export] Error:', error);
1890
- alert('Export failed: ' + error.message);
1891
- }
1892
- }
1893
-
1894
- async function updateMemoryStats() {
1895
- try {
1896
- const data = await API.get('/api/dashboard/status');
1897
- const memory = data.memory || {};
1898
- const totalEl = document.getElementById('memory-stats-total');
1899
- const weekEl = document.getElementById('memory-stats-week');
1900
- if (totalEl) totalEl.textContent = memory.total || 0;
1901
- if (weekEl) weekEl.textContent = `${memory.thisWeek || 0} this week`;
1902
- } catch (error) {
1903
- console.error('[MemoryStats] Error:', error);
1904
- }
1905
- }
1906
-
1907
- function handleGraphSearch(event) {
1908
- if (event.key === 'Enter') {
1909
- graph.search && graph.search();
1910
- }
1911
- }
1912
-
1913
- function saveOutcome() {
1914
- const select = document.getElementById('detail-outcome-select');
1915
- const outcome = select.value;
1916
- const nodeId = graph.currentNodeId;
1917
- if (nodeId && outcome) {
1918
- graph.updateOutcome && graph.updateOutcome(nodeId, outcome);
1919
- }
1920
- }
1921
-
1922
1704
  // Expose to window for onclick handlers
1923
1705
  window.switchTab = switchTab;
1924
1706
  window.toggleTheme = toggleTheme;
@@ -1931,12 +1713,6 @@ export MAMA_AUTH_TOKEN="your-secure-token-here"</pre
1931
1713
  window.hideSaveDecisionForm = hideSaveDecisionForm;
1932
1714
  window.submitSaveDecision = submitSaveDecision;
1933
1715
  window.testConnection = testConnection;
1934
- window.filterByOutcome = filterByOutcome;
1935
- window.clearFilters = clearFilters;
1936
- window.exportDecisions = exportDecisions;
1937
- window.filterByTopic = filterByTopic;
1938
- window.handleGraphSearch = handleGraphSearch;
1939
- window.saveOutcome = saveOutcome;
1940
1716
 
1941
1717
  document.addEventListener('DOMContentLoaded', () => {
1942
1718
  const userLang = navigator.language || navigator.userLanguage;