@jungjaehoon/mama-os 0.8.3 → 0.9.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 +10 -0
  2. package/dist/agent/agent-loop.d.ts +1 -8
  3. package/dist/agent/agent-loop.d.ts.map +1 -1
  4. package/dist/agent/agent-loop.js +44 -159
  5. package/dist/agent/agent-loop.js.map +1 -1
  6. package/dist/agent/claude-cli-wrapper.d.ts +6 -0
  7. package/dist/agent/claude-cli-wrapper.d.ts.map +1 -1
  8. package/dist/agent/claude-cli-wrapper.js +6 -0
  9. package/dist/agent/claude-cli-wrapper.js.map +1 -1
  10. package/dist/agent/codex-mcp-process.d.ts +85 -0
  11. package/dist/agent/codex-mcp-process.d.ts.map +1 -0
  12. package/dist/agent/codex-mcp-process.js +357 -0
  13. package/dist/agent/codex-mcp-process.js.map +1 -0
  14. package/dist/agent/session-pool.d.ts +17 -2
  15. package/dist/agent/session-pool.d.ts.map +1 -1
  16. package/dist/agent/session-pool.js +51 -26
  17. package/dist/agent/session-pool.js.map +1 -1
  18. package/dist/agent/types.d.ts +9 -24
  19. package/dist/agent/types.d.ts.map +1 -1
  20. package/dist/agent/types.js.map +1 -1
  21. package/dist/api/graph-api.d.ts.map +1 -1
  22. package/dist/api/graph-api.js +133 -45
  23. package/dist/api/graph-api.js.map +1 -1
  24. package/dist/cli/commands/init.d.ts +1 -1
  25. package/dist/cli/commands/init.d.ts.map +1 -1
  26. package/dist/cli/commands/init.js +14 -25
  27. package/dist/cli/commands/init.js.map +1 -1
  28. package/dist/cli/commands/run.d.ts.map +1 -1
  29. package/dist/cli/commands/run.js +3 -10
  30. package/dist/cli/commands/run.js.map +1 -1
  31. package/dist/cli/commands/start.d.ts.map +1 -1
  32. package/dist/cli/commands/start.js +143 -54
  33. package/dist/cli/commands/start.js.map +1 -1
  34. package/dist/cli/commands/status.d.ts.map +1 -1
  35. package/dist/cli/commands/status.js +2 -7
  36. package/dist/cli/commands/status.js.map +1 -1
  37. package/dist/cli/config/config-manager.d.ts.map +1 -1
  38. package/dist/cli/config/config-manager.js +9 -17
  39. package/dist/cli/config/config-manager.js.map +1 -1
  40. package/dist/cli/config/types.d.ts +19 -25
  41. package/dist/cli/config/types.d.ts.map +1 -1
  42. package/dist/cli/config/types.js.map +1 -1
  43. package/dist/cli/index.js +2 -2
  44. package/dist/cli/index.js.map +1 -1
  45. package/dist/gateways/context-injector.d.ts.map +1 -1
  46. package/dist/gateways/context-injector.js +6 -3
  47. package/dist/gateways/context-injector.js.map +1 -1
  48. package/dist/gateways/discord.d.ts +4 -0
  49. package/dist/gateways/discord.d.ts.map +1 -1
  50. package/dist/gateways/discord.js +39 -16
  51. package/dist/gateways/discord.js.map +1 -1
  52. package/dist/gateways/message-router.d.ts +6 -1
  53. package/dist/gateways/message-router.d.ts.map +1 -1
  54. package/dist/gateways/message-router.js +92 -7
  55. package/dist/gateways/message-router.js.map +1 -1
  56. package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
  57. package/dist/multi-agent/agent-process-manager.js +36 -9
  58. package/dist/multi-agent/agent-process-manager.js.map +1 -1
  59. package/dist/multi-agent/runtime-process.d.ts +4 -4
  60. package/dist/multi-agent/runtime-process.d.ts.map +1 -1
  61. package/dist/multi-agent/runtime-process.js +9 -20
  62. package/dist/multi-agent/runtime-process.js.map +1 -1
  63. package/dist/multi-agent/types.d.ts +13 -8
  64. package/dist/multi-agent/types.d.ts.map +1 -1
  65. package/dist/multi-agent/types.js.map +1 -1
  66. package/dist/setup/setup-prompt.d.ts +1 -1
  67. package/dist/setup/setup-prompt.d.ts.map +1 -1
  68. package/dist/setup/setup-prompt.js +19 -0
  69. package/dist/setup/setup-prompt.js.map +1 -1
  70. package/dist/setup/setup-server.d.ts.map +1 -1
  71. package/dist/setup/setup-server.js +39 -16
  72. package/dist/setup/setup-server.js.map +1 -1
  73. package/dist/skills/skill-registry.d.ts.map +1 -1
  74. package/dist/skills/skill-registry.js +5 -2
  75. package/dist/skills/skill-registry.js.map +1 -1
  76. package/package.json +5 -3
  77. package/public/setup.html +12 -1
  78. package/public/viewer/js/modules/chat.js +1760 -1976
  79. package/public/viewer/js/modules/dashboard.js +613 -695
  80. package/public/viewer/js/modules/graph.js +857 -970
  81. package/public/viewer/js/modules/memory.js +357 -312
  82. package/public/viewer/js/modules/settings.js +1009 -1026
  83. package/public/viewer/js/modules/skills.js +336 -355
  84. package/public/viewer/js/utils/api.js +255 -255
  85. package/public/viewer/js/utils/debug-logger.js +20 -26
  86. package/public/viewer/js/utils/dom.js +73 -60
  87. package/public/viewer/js/utils/format.js +182 -228
  88. package/public/viewer/js/utils/markdown.js +40 -0
  89. package/public/viewer/src/modules/chat.ts +2258 -0
  90. package/public/viewer/src/modules/dashboard.ts +1052 -0
  91. package/public/viewer/src/modules/graph.ts +1080 -0
  92. package/public/viewer/src/modules/memory.ts +453 -0
  93. package/public/viewer/src/modules/settings.ts +1398 -0
  94. package/public/viewer/src/modules/skills.ts +457 -0
  95. package/public/viewer/src/types/global.d.ts +168 -0
  96. package/public/viewer/src/utils/api.ts +650 -0
  97. package/public/viewer/src/utils/debug-logger.ts +36 -0
  98. package/public/viewer/src/utils/dom.ts +138 -0
  99. package/public/viewer/src/utils/format.ts +331 -0
  100. package/public/viewer/src/utils/markdown.ts +46 -0
  101. package/public/viewer/tsconfig.viewer.json +18 -0
  102. package/public/viewer/viewer.html +214 -311
  103. package/dist/agent/codex-cli-wrapper.d.ts +0 -85
  104. package/dist/agent/codex-cli-wrapper.d.ts.map +0 -1
  105. package/dist/agent/codex-cli-wrapper.js +0 -295
  106. package/dist/agent/codex-cli-wrapper.js.map +0 -1
@@ -28,6 +28,7 @@
28
28
  <script src="https://unpkg.com/vis-network@9/dist/vis-network.min.js"></script>
29
29
  <script src="https://unpkg.com/lucide@latest"></script>
30
30
  <script src="https://cdn.jsdelivr.net/npm/marked@11/marked.min.js"></script>
31
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.2.5/purify.min.js"></script>
31
32
  <script src="https://cdn.tailwindcss.com"></script>
32
33
  <script>
33
34
  tailwind.config = {
@@ -475,344 +476,245 @@
475
476
 
476
477
  <!-- Settings Tab -->
477
478
  <div class="tab-content" id="tab-settings">
478
- <div class="flex-1 flex flex-col min-h-0 overflow-y-auto p-3 md:p-4">
479
- <!-- Header -->
480
- <div class="mb-4">
481
- <h1 class="text-lg font-bold text-gray-900">Settings</h1>
482
- <p class="text-xs text-gray-500 mt-0.5">Configure MAMA gateways and agent settings</p>
479
+ <div class="flex-1 flex flex-col min-h-0 overflow-y-auto p-2 md:p-3">
480
+ <!-- Compact Header -->
481
+ <div class="flex items-center justify-between mb-3">
482
+ <h1 class="text-sm font-bold text-gray-900">⚙️ Settings</h1>
483
+ <span class="text-[10px] text-gray-400">MAMA OS Configuration</span>
483
484
  </div>
484
485
 
485
- <!-- Gateway Settings -->
486
- <section class="mb-4">
487
- <h2 class="text-sm font-semibold text-gray-900 mb-2">Gateway Connections</h2>
488
- <div class="grid gap-2">
489
- <!-- Discord -->
490
- <div class="bg-white border border-gray-200 rounded-lg p-2.5">
491
- <div class="flex items-center justify-between mb-2">
492
- <div class="flex items-center gap-2">
493
- <span class="text-xl">💬</span>
494
- <h3 class="font-semibold text-gray-900 text-mama-black">Discord</h3>
486
+ <!-- Main Grid: 2 columns on desktop -->
487
+ <div class="grid grid-cols-1 lg:grid-cols-2 gap-3">
488
+
489
+ <!-- Left Column -->
490
+ <div class="space-y-3">
491
+
492
+ <!-- Gateway Connections - 2x2 Grid -->
493
+ <section>
494
+ <h2 class="text-xs font-semibold text-gray-700 mb-1.5 flex items-center gap-1">🌐 Gateways</h2>
495
+ <div class="grid grid-cols-2 gap-1.5">
496
+ <!-- Discord -->
497
+ <div class="bg-white border border-gray-200 rounded-lg p-2 shadow-sm">
498
+ <div class="flex items-center justify-between mb-1.5">
499
+ <span class="text-xs font-medium">💬 Discord</span>
500
+ <label class="relative inline-flex items-center cursor-pointer">
501
+ <input type="checkbox" id="settings-discord-enabled" class="sr-only peer" aria-label="Enable Discord">
502
+ <div class="w-6 h-3.5 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full after:content-[''] after:absolute after:top-[1px] after:left-[1px] after:bg-white after:rounded-full after:h-2.5 after:w-2.5 after:transition-all peer-checked:bg-green-500"></div>
503
+ </label>
504
+ </div>
505
+ <input type="password" id="settings-discord-token" placeholder="Bot Token" aria-label="Discord bot token" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50 mb-1">
506
+ <input type="text" id="settings-discord-channel" placeholder="Channel ID" aria-label="Discord channel ID" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
495
507
  </div>
496
- <label class="relative inline-flex items-center cursor-pointer">
497
- <input type="checkbox" id="settings-discord-enabled" class="sr-only peer">
498
- <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-mama-yellow/50 rounded-full peer bg-mama-lavender-light peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all border-mama-lavender-dark peer-checked:bg-mama-yellow"></div>
499
- </label>
500
- </div>
501
- <div class="space-y-1.5">
502
- <div>
503
- <label class="block text-[10px] font-medium text-gray-500 mb-0.5">Bot Token</label>
504
- <input type="password" id="settings-discord-token" placeholder="Enter Discord bot token" class="w-full px-2 py-1 text-xs border border-gray-200 rounded bg-gray-50 text-gray-900 focus:ring-1 focus:ring-yellow-400 focus:border-transparent">
508
+ <!-- Slack -->
509
+ <div class="bg-white border border-gray-200 rounded-lg p-2 shadow-sm">
510
+ <div class="flex items-center justify-between mb-1.5">
511
+ <span class="text-xs font-medium">📱 Slack</span>
512
+ <label class="relative inline-flex items-center cursor-pointer">
513
+ <input type="checkbox" id="settings-slack-enabled" class="sr-only peer" aria-label="Enable Slack">
514
+ <div class="w-6 h-3.5 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full after:content-[''] after:absolute after:top-[1px] after:left-[1px] after:bg-white after:rounded-full after:h-2.5 after:w-2.5 after:transition-all peer-checked:bg-green-500"></div>
515
+ </label>
516
+ </div>
517
+ <input type="password" id="settings-slack-bot-token" placeholder="Bot Token (xoxb-)" aria-label="Slack bot token" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50 mb-1">
518
+ <input type="password" id="settings-slack-app-token" placeholder="App Token (xapp-)" aria-label="Slack app token" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
505
519
  </div>
506
- <div>
507
- <label class="block text-[10px] font-medium text-gray-500 mb-0.5">Default Channel ID</label>
508
- <input type="text" id="settings-discord-channel" placeholder="Channel ID for notifications" class="w-full px-2 py-1 text-xs border border-gray-200 rounded bg-gray-50 text-gray-900 focus:ring-1 focus:ring-yellow-400 focus:border-transparent">
520
+ <!-- Telegram -->
521
+ <div class="bg-white border border-gray-200 rounded-lg p-2 shadow-sm">
522
+ <div class="flex items-center justify-between mb-1.5">
523
+ <span class="text-xs font-medium">✈️ Telegram</span>
524
+ <label class="relative inline-flex items-center cursor-pointer">
525
+ <input type="checkbox" id="settings-telegram-enabled" class="sr-only peer" aria-label="Enable Telegram">
526
+ <div class="w-6 h-3.5 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full after:content-[''] after:absolute after:top-[1px] after:left-[1px] after:bg-white after:rounded-full after:h-2.5 after:w-2.5 after:transition-all peer-checked:bg-green-500"></div>
527
+ </label>
528
+ </div>
529
+ <input type="password" id="settings-telegram-token" placeholder="Bot Token" aria-label="Telegram bot token" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
509
530
  </div>
510
- </div>
511
- </div>
512
-
513
- <!-- Slack -->
514
- <div class="bg-white border border-gray-200 rounded-lg p-2.5">
515
- <div class="flex items-center justify-between mb-2">
516
- <div class="flex items-center gap-1.5">
517
- <span class="text-base">📱</span>
518
- <h3 class="font-semibold text-gray-900 text-sm">Slack</h3>
531
+ <!-- Chatwork -->
532
+ <div class="bg-white border border-gray-200 rounded-lg p-2 shadow-sm">
533
+ <div class="flex items-center justify-between mb-1.5">
534
+ <span class="text-xs font-medium">💼 Chatwork</span>
535
+ <label class="relative inline-flex items-center cursor-pointer">
536
+ <input type="checkbox" id="settings-chatwork-enabled" class="sr-only peer" aria-label="Enable Chatwork">
537
+ <div class="w-6 h-3.5 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full after:content-[''] after:absolute after:top-[1px] after:left-[1px] after:bg-white after:rounded-full after:h-2.5 after:w-2.5 after:transition-all peer-checked:bg-green-500"></div>
538
+ </label>
539
+ </div>
540
+ <input type="password" id="settings-chatwork-token" placeholder="API Token" aria-label="Chatwork API token" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
519
541
  </div>
520
- <label class="relative inline-flex items-center cursor-pointer">
521
- <input type="checkbox" id="settings-slack-enabled" class="sr-only peer">
522
- <div class="w-9 h-5 bg-gray-200 peer-focus:ring-2 peer-focus:ring-yellow-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-yellow-400"></div>
523
- </label>
524
542
  </div>
525
- <div class="space-y-1.5">
526
- <div>
527
- <label class="block text-[10px] font-medium text-gray-500 mb-0.5">Bot Token</label>
528
- <input type="password" id="settings-slack-bot-token" placeholder="xoxb-..." class="w-full px-2 py-1 text-xs border border-gray-200 rounded bg-gray-50 text-gray-900 focus:ring-1 focus:ring-yellow-400 focus:border-transparent">
529
- </div>
530
- <div>
531
- <label class="block text-[10px] font-medium text-gray-500 mb-0.5">App Token</label>
532
- <input type="password" id="settings-slack-app-token" placeholder="xapp-..." class="w-full px-2 py-1 text-xs border border-gray-200 rounded bg-gray-50 text-gray-900 focus:ring-1 focus:ring-yellow-400 focus:border-transparent">
543
+ </section>
544
+
545
+ <!-- Agent Config Card -->
546
+ <section>
547
+ <h2 class="text-xs font-semibold text-gray-700 mb-1.5 flex items-center gap-1">🤖 Default Agent</h2>
548
+ <div class="bg-white border border-gray-200 rounded-lg p-2 shadow-sm">
549
+ <div class="grid grid-cols-2 gap-1.5 mb-2">
550
+ <div>
551
+ <label class="block text-[9px] text-gray-500 mb-0.5">Backend</label>
552
+ <select id="settings-agent-backend" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
553
+ <option value="claude">Claude CLI</option>
554
+ <option value="codex-mcp">Codex MCP</option>
555
+ </select>
556
+ </div>
557
+ <div>
558
+ <label class="block text-[9px] text-gray-500 mb-0.5">Model</label>
559
+ <select id="settings-agent-model" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50"></select>
560
+ </div>
561
+ <div id="settings-effort-container" style="display: none;">
562
+ <label class="block text-[9px] text-gray-500 mb-0.5">Effort <span class="text-indigo-500">(4.6)</span></label>
563
+ <select id="settings-agent-effort" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
564
+ <option value="low">Low</option>
565
+ <option value="medium" selected>Medium</option>
566
+ <option value="high">High</option>
567
+ </select>
568
+ </div>
569
+ <div>
570
+ <label class="block text-[9px] text-gray-500 mb-0.5">Max Turns</label>
571
+ <input type="number" id="settings-agent-max-turns" value="10" min="1" max="100" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
572
+ </div>
573
+ <div>
574
+ <label class="block text-[9px] text-gray-500 mb-0.5">Timeout (s)</label>
575
+ <input type="number" id="settings-agent-timeout" value="300" min="30" max="600" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
576
+ </div>
533
577
  </div>
534
578
  </div>
535
- </div>
536
-
537
- <!-- Telegram -->
538
- <div class="bg-white border border-gray-200 rounded-lg p-2.5">
539
- <div class="flex items-center justify-between mb-2">
540
- <div class="flex items-center gap-2">
541
- <span class="text-xl">✈️</span>
542
- <h3 class="font-semibold text-gray-900 text-mama-black">Telegram</h3>
579
+ </section>
580
+
581
+ <!-- Heartbeat Card -->
582
+ <section>
583
+ <h2 class="text-xs font-semibold text-gray-700 mb-1.5 flex items-center gap-1">⏰ Heartbeat</h2>
584
+ <div class="bg-white border border-gray-200 rounded-lg p-2 shadow-sm">
585
+ <div class="flex items-center justify-between mb-2">
586
+ <span class="text-[10px] text-gray-600">Enable scheduler</span>
587
+ <label class="relative inline-flex items-center cursor-pointer">
588
+ <input type="checkbox" id="settings-heartbeat-enabled" class="sr-only peer" aria-label="Enable heartbeat scheduler">
589
+ <div class="w-6 h-3.5 bg-gray-200 rounded-full peer peer-checked:after:translate-x-full after:content-[''] after:absolute after:top-[1px] after:left-[1px] after:bg-white after:rounded-full after:h-2.5 after:w-2.5 after:transition-all peer-checked:bg-green-500"></div>
590
+ </label>
543
591
  </div>
544
- <label class="relative inline-flex items-center cursor-pointer">
545
- <input type="checkbox" id="settings-telegram-enabled" class="sr-only peer">
546
- <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-mama-yellow/50 rounded-full peer bg-mama-lavender-light peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all border-mama-lavender-dark peer-checked:bg-mama-yellow"></div>
547
- </label>
548
- </div>
549
- <div>
550
- <label class="block text-xs font-medium text-gray-500 text-gray-600 mb-1">Bot Token</label>
551
- <input type="password" id="settings-telegram-token" placeholder="123456:ABC-DEF..." class="w-full px-2 py-1.5 text-xs border border-gray-200 rounded-lg bg-gray-50 text-gray-900 text-mama-black focus:ring-2 focus:ring-mama-yellow focus:border-transparent">
552
- </div>
553
- </div>
554
-
555
- <!-- Chatwork -->
556
- <div class="bg-white border border-gray-200 rounded-lg p-2.5">
557
- <div class="flex items-center justify-between mb-2">
558
- <div class="flex items-center gap-2">
559
- <span class="text-xl">💼</span>
560
- <h3 class="font-semibold text-gray-900 text-mama-black">Chatwork</h3>
592
+ <div class="grid grid-cols-3 gap-1">
593
+ <div>
594
+ <label class="block text-[9px] text-gray-500 mb-0.5">Interval (min)</label>
595
+ <input type="number" id="settings-heartbeat-interval" value="30" min="5" max="1440" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
596
+ </div>
597
+ <div>
598
+ <label class="block text-[9px] text-gray-500 mb-0.5">Quiet Start</label>
599
+ <input type="number" id="settings-heartbeat-quiet-start" value="23" min="0" max="23" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
600
+ </div>
601
+ <div>
602
+ <label class="block text-[9px] text-gray-500 mb-0.5">Quiet End</label>
603
+ <input type="number" id="settings-heartbeat-quiet-end" value="8" min="0" max="23" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
604
+ </div>
561
605
  </div>
562
- <label class="relative inline-flex items-center cursor-pointer">
563
- <input type="checkbox" id="settings-chatwork-enabled" class="sr-only peer">
564
- <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-mama-yellow/50 rounded-full peer bg-mama-lavender-light peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all border-mama-lavender-dark peer-checked:bg-mama-yellow"></div>
565
- </label>
566
606
  </div>
567
- <div>
568
- <label class="block text-xs font-medium text-gray-500 text-gray-600 mb-1">API Token</label>
569
- <input type="password" id="settings-chatwork-token" placeholder="Enter Chatwork API token" class="w-full px-2 py-1.5 text-xs border border-gray-200 rounded-lg bg-gray-50 text-gray-900 text-mama-black focus:ring-2 focus:ring-mama-yellow focus:border-transparent">
607
+ </section>
608
+
609
+ <!-- Role Permissions -->
610
+ <section>
611
+ <h2 class="text-xs font-semibold text-gray-700 mb-1.5 flex items-center gap-1">🔐 Roles</h2>
612
+ <div id="settings-roles-container" class="grid grid-cols-2 gap-1.5">
613
+ <div class="animate-pulse bg-white rounded-lg h-12"></div>
614
+ <div class="animate-pulse bg-white rounded-lg h-12"></div>
570
615
  </div>
571
- </div>
572
- </div>
573
- </section>
616
+ </section>
574
617
 
575
- <!-- Role Permissions -->
576
- <section class="mb-4">
577
- <h2 class="text-sm font-semibold text-gray-900 mb-2">🔐 Role Permissions</h2>
578
- <div class="grid gap-2" id="settings-roles-container">
579
- <!-- Roles will be rendered dynamically from config -->
580
- <div class="animate-pulse bg-white rounded-lg h-20"></div>
581
- <div class="animate-pulse bg-white rounded-lg h-20"></div>
582
618
  </div>
583
- <p class="text-[10px] text-gray-400 mt-1.5">💡 OS Agent can manage roles using: <code>os_set_permissions</code> tool</p>
584
- </section>
585
619
 
586
- <!-- Heartbeat Settings -->
587
- <section class="mb-4">
588
- <h2 class="text-sm font-semibold text-gray-900 mb-2">Heartbeat Scheduler</h2>
589
- <div class="bg-white border border-gray-200 rounded-lg p-2.5">
590
- <div class="flex items-center justify-between mb-2">
591
- <span class="text-sm text-gray-700 text-gray-700">Enable Heartbeat</span>
592
- <label class="relative inline-flex items-center cursor-pointer">
593
- <input type="checkbox" id="settings-heartbeat-enabled" class="sr-only peer">
594
- <div class="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-mama-yellow/50 rounded-full peer bg-mama-lavender-light peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all border-mama-lavender-dark peer-checked:bg-mama-yellow"></div>
595
- </label>
596
- </div>
597
- <div class="grid grid-cols-1 md:grid-cols-3 gap-2">
598
- <div>
599
- <label class="block text-xs font-medium text-gray-500 text-gray-600 mb-1">Interval (minutes)</label>
600
- <input type="number" id="settings-heartbeat-interval" value="30" min="5" max="1440" class="w-full px-2 py-1.5 text-xs border border-gray-200 rounded-lg bg-gray-50 text-gray-900 text-mama-black focus:ring-2 focus:ring-mama-yellow focus:border-transparent">
601
- </div>
602
- <div>
603
- <label class="block text-xs font-medium text-gray-500 text-gray-600 mb-1">Quiet Start (hour)</label>
604
- <input type="number" id="settings-heartbeat-quiet-start" value="23" min="0" max="23" class="w-full px-2 py-1.5 text-xs border border-gray-200 rounded-lg bg-gray-50 text-gray-900 text-mama-black focus:ring-2 focus:ring-mama-yellow focus:border-transparent">
605
- </div>
606
- <div>
607
- <label class="block text-xs font-medium text-gray-500 text-gray-600 mb-1">Quiet End (hour)</label>
608
- <input type="number" id="settings-heartbeat-quiet-end" value="8" min="0" max="23" class="w-full px-2 py-1.5 text-xs border border-gray-200 rounded-lg bg-gray-50 text-gray-900 text-mama-black focus:ring-2 focus:ring-mama-yellow focus:border-transparent">
609
- </div>
610
- </div>
611
- </div>
612
- </section>
613
-
614
- <!-- Agent Settings -->
615
- <section class="mb-4">
616
- <h2 class="text-sm font-semibold text-gray-900 mb-2">Agent Configuration</h2>
617
- <div class="bg-white border border-gray-200 rounded-lg p-2.5">
618
- <div class="grid grid-cols-1 md:grid-cols-4 gap-2">
619
- <div>
620
- <label class="block text-xs font-medium text-gray-500 text-gray-600 mb-1">Backend</label>
621
- <select id="settings-agent-backend" class="w-full px-2 py-1.5 text-xs border border-gray-200 rounded-lg bg-gray-50 text-gray-900 text-mama-black focus:ring-2 focus:ring-mama-yellow focus:border-transparent">
622
- <option value="claude">Claude CLI</option>
623
- <option value="codex">Codex CLI</option>
624
- </select>
625
- </div>
626
- <div>
627
- <label class="block text-xs font-medium text-gray-500 text-gray-600 mb-1">Model</label>
628
- <input id="settings-agent-model" list="settings-agent-model-list" class="w-full px-2 py-1.5 text-xs border border-gray-200 rounded-lg bg-gray-50 text-gray-900 text-mama-black focus:ring-2 focus:ring-mama-yellow focus:border-transparent" placeholder="Select or type a model">
629
- <datalist id="settings-agent-model-list"></datalist>
630
- </div>
631
- <div>
632
- <label class="block text-xs font-medium text-gray-500 text-gray-600 mb-1">Max Turns</label>
633
- <input type="number" id="settings-agent-max-turns" value="10" min="1" max="50" class="w-full px-2 py-1.5 text-xs border border-gray-200 rounded-lg bg-gray-50 text-gray-900 text-mama-black focus:ring-2 focus:ring-mama-yellow focus:border-transparent">
634
- </div>
635
- <div>
636
- <label class="block text-xs font-medium text-gray-500 text-gray-600 mb-1">Timeout (seconds)</label>
637
- <input type="number" id="settings-agent-timeout" value="300" min="30" max="600" class="w-full px-2 py-1.5 text-xs border border-gray-200 rounded-lg bg-gray-50 text-gray-900 text-mama-black focus:ring-2 focus:ring-mama-yellow focus:border-transparent">
638
- </div>
639
- </div>
640
- <div class="flex items-center gap-3 mt-2 pt-2 border-t border-gray-100">
641
- <label class="relative inline-flex items-center cursor-pointer">
642
- <input type="checkbox" id="settings-agent-persistent-cli" class="sr-only peer">
643
- <div class="w-9 h-5 bg-gray-200 peer-focus:ring-2 peer-focus:ring-mama-yellow rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-green-500"></div>
644
- </label>
645
- <div>
646
- <span class="text-xs font-medium text-gray-700">Persistent CLI</span>
647
- <span class="text-[10px] text-gray-400 ml-1">~2-3s response (Claude only)</span>
648
- </div>
649
- </div>
650
- </div>
651
- </section>
652
-
653
- <!-- Multi-Agent Team Settings (F3) -->
654
- <section class="mb-4">
655
- <h2 class="text-sm font-semibold text-gray-900 mb-2">🤖 Multi-Agent Team</h2>
656
- <div id="settings-multi-agent-container" class="grid gap-2">
657
- <div class="animate-pulse bg-white rounded-lg h-20"></div>
658
- </div>
659
- </section>
620
+ <!-- Right Column -->
621
+ <div class="space-y-3">
660
622
 
661
- <!-- Tool Selection Settings -->
662
- <section class="mb-6">
663
- <h2 class="text-lg font-semibold text-gray-900 text-mama-black mb-3">Tool Selection</h2>
664
- <div class="bg-white bg-white border border-gray-200 border-mama-lavender-dark rounded-lg p-4">
665
- <p class="text-sm text-gray-600 mb-4">Select which tools to enable. Gateway tools run directly (self-contained), MCP tools use external servers.</p>
666
-
667
- <!-- Gateway Tools -->
668
- <div class="mb-4">
669
- <div class="flex items-center justify-between mb-2">
670
- <h3 class="text-sm font-semibold text-mama-black flex items-center gap-2">
671
- <span class="w-2 h-2 bg-green-500 rounded-full"></span>
672
- Gateway Tools (Self-contained)
673
- </h3>
674
- <label class="flex items-center gap-1 text-xs text-gray-500 cursor-pointer">
675
- <input type="checkbox" id="gateway-select-all" onchange="settingsModule.toggleAllGateway(this.checked)" checked>
676
- Select All
677
- </label>
623
+ <!-- Multi-Agent Team -->
624
+ <section>
625
+ <h2 class="text-xs font-semibold text-gray-700 mb-1.5 flex items-center gap-1">👥 Multi-Agent Team</h2>
626
+ <div id="settings-multi-agent-container">
627
+ <div class="animate-pulse bg-white rounded-lg h-20"></div>
678
628
  </div>
629
+ </section>
679
630
 
680
- <!-- MAMA Memory Category -->
681
- <div class="mb-3">
682
- <div class="text-xs font-medium text-gray-500 mb-1 flex items-center gap-1">
683
- <span>🧠</span> MAMA Memory
684
- </div>
685
- <div class="grid grid-cols-2 md:grid-cols-4 gap-2">
686
- <label class="flex items-center gap-2 p-2 border border-gray-200 rounded-lg text-xs cursor-pointer hover:bg-mama-lavender-light">
687
- <input type="checkbox" class="gateway-tool" value="mama_search" checked> mama_search
688
- </label>
689
- <label class="flex items-center gap-2 p-2 border border-gray-200 rounded-lg text-xs cursor-pointer hover:bg-mama-lavender-light">
690
- <input type="checkbox" class="gateway-tool" value="mama_save" checked> mama_save
691
- </label>
692
- <label class="flex items-center gap-2 p-2 border border-gray-200 rounded-lg text-xs cursor-pointer hover:bg-mama-lavender-light">
693
- <input type="checkbox" class="gateway-tool" value="mama_update" checked> mama_update
694
- </label>
695
- <label class="flex items-center gap-2 p-2 border border-gray-200 rounded-lg text-xs cursor-pointer hover:bg-mama-lavender-light">
696
- <input type="checkbox" class="gateway-tool" value="mama_load_checkpoint" checked> mama_load_checkpoint
697
- </label>
698
- </div>
631
+ <!-- Installed Skills -->
632
+ <section>
633
+ <h2 class="text-xs font-semibold text-gray-700 mb-1.5 flex items-center gap-1">📚 Skills</h2>
634
+ <div id="settings-skills-container" class="bg-white border border-gray-200 rounded-lg p-2 shadow-sm">
635
+ <p class="text-[10px] text-gray-500">Loading...</p>
699
636
  </div>
700
-
701
- <!-- Utility Category -->
702
- <div class="mb-3">
703
- <div class="text-xs font-medium text-gray-500 mb-1 flex items-center gap-1">
704
- <span>🛠️</span> Utility
705
- </div>
706
- <div class="grid grid-cols-2 md:grid-cols-4 gap-2">
707
- <label class="flex items-center gap-2 p-2 border border-gray-200 rounded-lg text-xs cursor-pointer hover:bg-mama-lavender-light">
708
- <input type="checkbox" class="gateway-tool" value="discord_send" checked> discord_send
709
- </label>
710
- <label class="flex items-center gap-2 p-2 border border-gray-200 rounded-lg text-xs cursor-pointer hover:bg-mama-lavender-light">
711
- <input type="checkbox" class="gateway-tool" value="Read" checked> Read
712
- </label>
713
- <label class="flex items-center gap-2 p-2 border border-gray-200 rounded-lg text-xs cursor-pointer hover:bg-mama-lavender-light">
714
- <input type="checkbox" class="gateway-tool" value="Write" checked> Write
715
- </label>
716
- <label class="flex items-center gap-2 p-2 border border-gray-200 rounded-lg text-xs cursor-pointer hover:bg-mama-lavender-light">
717
- <input type="checkbox" class="gateway-tool" value="Bash" checked> Bash
718
- </label>
637
+ </section>
638
+
639
+ <!-- Token Budget -->
640
+ <section>
641
+ <h2 class="text-xs font-semibold text-gray-700 mb-1.5 flex items-center gap-1">💰 Token Budget</h2>
642
+ <div class="bg-white border border-gray-200 rounded-lg p-2 shadow-sm">
643
+ <div class="grid grid-cols-2 gap-1.5">
644
+ <div>
645
+ <label class="block text-[9px] text-gray-500 mb-0.5">Daily Limit</label>
646
+ <input type="number" id="settings-token-daily-limit" placeholder="1000000" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
647
+ </div>
648
+ <div>
649
+ <label class="block text-[9px] text-gray-500 mb-0.5">Alert ($)</label>
650
+ <input type="number" id="settings-token-alert-threshold" step="0.01" placeholder="5.00" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
651
+ </div>
719
652
  </div>
720
653
  </div>
721
- </div>
654
+ </section>
722
655
 
723
- <!-- MCP Tools -->
724
- <div class="mb-4">
725
- <div class="flex items-center justify-between mb-2">
726
- <h3 class="text-sm font-semibold text-mama-black flex items-center gap-2">
727
- <span class="w-2 h-2 bg-blue-500 rounded-full"></span>
728
- MCP Tools (External Server)
729
- </h3>
730
- <label class="flex items-center gap-1 text-xs text-gray-500 cursor-pointer">
731
- <input type="checkbox" id="mcp-select-all" onchange="settingsModule.toggleAllMCP(this.checked)">
732
- Select All
733
- </label>
734
- </div>
735
- <div class="grid grid-cols-2 md:grid-cols-4 gap-2" id="mcp-tools-list">
736
- <!-- MCP servers loaded dynamically from /api/mcp-servers -->
737
- <p class="text-xs text-gray-400 col-span-full">Loading MCP servers...</p>
738
- </div>
739
- <p class="text-xs text-gray-500 mt-2">MCP config path: ~/.mama/mama-mcp-config.json</p>
740
- </div>
741
-
742
- <!-- Status Display -->
743
- <div class="mt-4 p-3 bg-mama-lavender-light rounded-lg" id="tool-mode-status">
744
- <div class="flex items-center gap-2">
745
- <span class="text-sm font-medium text-mama-black" id="tool-summary">Gateway: 18 tools | MCP: 0 tools</span>
656
+ <!-- Scheduled Jobs -->
657
+ <section>
658
+ <h2 class="text-xs font-semibold text-gray-700 mb-1.5 flex items-center gap-1">📅 Scheduled Jobs</h2>
659
+ <div id="settings-cron-container" class="bg-white border border-gray-200 rounded-lg p-2 shadow-sm mb-1.5">
660
+ <p class="text-[10px] text-gray-500">Loading...</p>
746
661
  </div>
747
- </div>
748
- </div>
749
- </section>
750
-
751
- <!-- Installed Skills -->
752
- <section class="mb-4">
753
- <h2 class="text-sm font-semibold text-gray-900 mb-2">Installed Skills</h2>
754
- <div id="settings-skills-container" class="bg-white border border-gray-200 rounded-lg p-2.5">
755
- <p class="text-xs text-gray-500">Loading skills...</p>
756
- </div>
757
- <p class="text-[10px] text-gray-400 mt-1">Skills directory: ~/.mama/skills/</p>
758
- </section>
662
+ <details class="bg-white border border-gray-200 rounded-lg shadow-sm">
663
+ <summary class="px-2 py-1.5 text-[10px] font-medium text-gray-600 cursor-pointer hover:bg-gray-50">+ Add New Job</summary>
664
+ <div class="p-2 border-t border-gray-100 space-y-1.5" id="settings-cron-form">
665
+ <div class="grid grid-cols-2 gap-1.5">
666
+ <input type="text" id="settings-cron-name" placeholder="Job Name" aria-label="Cron job name" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
667
+ <input type="text" id="settings-cron-expr" placeholder="0 * * * *" aria-label="Cron expression" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50">
668
+ </div>
669
+ <textarea id="settings-cron-prompt" rows="2" placeholder="Task prompt..." aria-label="Cron job task prompt" class="w-full px-1.5 py-0.5 text-[10px] border border-gray-200 rounded bg-gray-50 resize-none"></textarea>
670
+ <button onclick="settingsModule.addCronJob()" class="w-full px-2 py-1 text-[10px] font-medium bg-yellow-400 hover:bg-yellow-300 rounded">Add</button>
671
+ </div>
672
+ </details>
673
+ </section>
759
674
 
760
- <!-- Token Budget -->
761
- <section class="mb-4">
762
- <h2 class="text-sm font-semibold text-gray-900 mb-2">Token Budget</h2>
763
- <div class="bg-white border border-gray-200 rounded-lg p-2.5 space-y-2">
764
- <div>
765
- <label class="block text-[10px] font-medium text-gray-500 mb-0.5">Daily Token Limit</label>
766
- <input type="number" id="settings-token-daily-limit" placeholder="e.g. 1000000" class="w-full px-2 py-1 text-xs border border-gray-200 rounded bg-gray-50 text-gray-900 focus:ring-1 focus:ring-yellow-400">
767
- </div>
768
- <div>
769
- <label class="block text-[10px] font-medium text-gray-500 mb-0.5">Cost Alert Threshold (USD)</label>
770
- <input type="number" id="settings-token-alert-threshold" step="0.01" placeholder="e.g. 5.00" class="w-full px-2 py-1 text-xs border border-gray-200 rounded bg-gray-50 text-gray-900 focus:ring-1 focus:ring-yellow-400">
771
- </div>
772
675
  </div>
773
- </section>
676
+ </div>
774
677
 
775
- <!-- Scheduled Jobs (Cron) -->
776
- <section class="mb-4">
777
- <h2 class="text-sm font-semibold text-gray-900 mb-2">Scheduled Jobs</h2>
778
- <div id="settings-cron-container" class="bg-white border border-gray-200 rounded-lg p-2.5">
779
- <p class="text-xs text-gray-500">Loading scheduled jobs...</p>
780
- </div>
781
- <div class="mt-2 bg-white border border-gray-200 rounded-lg p-2.5 space-y-2" id="settings-cron-form">
782
- <h3 class="text-xs font-medium text-gray-700">Add New Job</h3>
783
- <div class="grid grid-cols-2 gap-2">
784
- <div>
785
- <label class="block text-[10px] font-medium text-gray-500 mb-0.5">Name</label>
786
- <input type="text" id="settings-cron-name" placeholder="e.g. Danggeun Monitor" class="w-full px-2 py-1 text-xs border border-gray-200 rounded bg-gray-50 text-gray-900 focus:ring-1 focus:ring-yellow-400">
678
+ <!-- Full Width: Tools Section (collapsible) -->
679
+ <details class="mt-3">
680
+ <summary class="text-xs font-semibold text-gray-700 cursor-pointer mb-1.5 flex items-center gap-1">🔧 Tool Selection <span class="text-[9px] text-gray-400 font-normal">(click to expand)</span></summary>
681
+ <div class="bg-white border border-gray-200 rounded-lg p-2 shadow-sm">
682
+ <div class="flex items-center justify-between mb-2">
683
+ <div class="flex items-center gap-2">
684
+ <span class="text-[10px] text-gray-500">Gateway</span>
685
+ <label class="flex items-center gap-1 text-[10px] cursor-pointer">
686
+ <input type="checkbox" id="gateway-select-all" onchange="settingsModule.toggleAllGateway(this.checked)" checked class="w-3 h-3" aria-label="Select all gateway tools">All
687
+ </label>
787
688
  </div>
788
- <div>
789
- <label class="block text-[10px] font-medium text-gray-500 mb-0.5">Schedule (cron)</label>
790
- <input type="text" id="settings-cron-expr" placeholder="0 * * * *" class="w-full px-2 py-1 text-xs border border-gray-200 rounded bg-gray-50 text-gray-900 focus:ring-1 focus:ring-yellow-400">
689
+ <div class="flex items-center gap-2">
690
+ <span class="text-[10px] text-gray-500">MCP</span>
691
+ <label class="flex items-center gap-1 text-[10px] cursor-pointer">
692
+ <input type="checkbox" id="mcp-select-all" onchange="settingsModule.toggleAllMCP(this.checked)" class="w-3 h-3" aria-label="Select all MCP tools">All
693
+ </label>
791
694
  </div>
792
695
  </div>
793
- <div>
794
- <label class="block text-[10px] font-medium text-gray-500 mb-0.5">Prompt</label>
795
- <textarea id="settings-cron-prompt" rows="2" placeholder="Task prompt for agent to execute each tick..." class="w-full px-2 py-1 text-xs border border-gray-200 rounded bg-gray-50 text-gray-900 focus:ring-1 focus:ring-yellow-400 resize-none"></textarea>
696
+ <div class="grid grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-1 mb-2">
697
+ <label class="flex items-center gap-1 text-[9px] cursor-pointer"><input type="checkbox" class="gateway-tool w-2.5 h-2.5" value="mama_search" checked>mama_search</label>
698
+ <label class="flex items-center gap-1 text-[9px] cursor-pointer"><input type="checkbox" class="gateway-tool w-2.5 h-2.5" value="mama_save" checked>mama_save</label>
699
+ <label class="flex items-center gap-1 text-[9px] cursor-pointer"><input type="checkbox" class="gateway-tool w-2.5 h-2.5" value="mama_update" checked>mama_update</label>
700
+ <label class="flex items-center gap-1 text-[9px] cursor-pointer"><input type="checkbox" class="gateway-tool w-2.5 h-2.5" value="mama_load_checkpoint" checked>checkpoint</label>
701
+ <label class="flex items-center gap-1 text-[9px] cursor-pointer"><input type="checkbox" class="gateway-tool w-2.5 h-2.5" value="discord_send" checked>discord_send</label>
702
+ <label class="flex items-center gap-1 text-[9px] cursor-pointer"><input type="checkbox" class="gateway-tool w-2.5 h-2.5" value="Read" checked>Read</label>
703
+ <label class="flex items-center gap-1 text-[9px] cursor-pointer"><input type="checkbox" class="gateway-tool w-2.5 h-2.5" value="Write" checked>Write</label>
704
+ <label class="flex items-center gap-1 text-[9px] cursor-pointer"><input type="checkbox" class="gateway-tool w-2.5 h-2.5" value="Bash" checked>Bash</label>
796
705
  </div>
797
- <button onclick="settingsModule.addCronJob()" class="px-3 py-1 text-xs font-medium text-mama-black bg-mama-yellow hover:bg-mama-yellow-hover rounded transition-colors">
798
- Add Job
799
- </button>
706
+ <div id="mcp-tools-list" class="grid grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-1 text-[9px] text-gray-400">Loading MCP...</div>
707
+ <div class="mt-2 pt-2 border-t border-gray-100 text-[10px] text-gray-500" id="tool-summary">Gateway: 8 | MCP: 0</div>
800
708
  </div>
801
- </section>
709
+ </details>
802
710
 
803
711
  <!-- Action Buttons -->
804
- <div class="flex items-center justify-between pt-4 border-t border-gray-200 border-mama-lavender-dark">
805
- <button onclick="settingsModule.resetForm()" class="px-4 py-2 text-sm font-medium text-gray-700 text-gray-700 bg-gray-100 bg-mama-lavender-light hover:bg-gray-200 hover:bg-mama-lavender-light rounded-lg transition-colors">
806
- Reset
807
- </button>
808
- <div class="flex items-center gap-3">
809
- <span id="settings-status" class="text-sm text-gray-500 text-gray-600"></span>
810
- <button onclick="settingsModule.saveAndRestart()" class="px-6 py-2 text-sm font-medium text-white bg-mama-yellow hover:bg-mama-yellow-hover rounded-lg transition-colors flex items-center gap-2">
811
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
812
- <path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
813
- <polyline points="17 21 17 13 7 13 7 21"/>
814
- <polyline points="7 3 7 8 15 8"/>
815
- </svg>
712
+ <div class="flex items-center justify-between mt-3 pt-3 border-t border-gray-200">
713
+ <button onclick="settingsModule.resetForm()" class="px-3 py-1.5 text-xs font-medium text-gray-600 bg-gray-100 hover:bg-gray-200 rounded transition-colors">Reset</button>
714
+ <div class="flex items-center gap-2">
715
+ <span id="settings-status" class="text-[10px] text-gray-500"></span>
716
+ <button onclick="settingsModule.saveAndRestart()" class="px-4 py-1.5 text-xs font-medium text-black bg-yellow-400 hover:bg-yellow-300 rounded transition-colors flex items-center gap-1.5">
717
+ <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg>
816
718
  Save &amp; Restart
817
719
  </button>
818
720
  </div>
@@ -1261,7 +1163,11 @@
1261
1163
  </div>
1262
1164
  <div class="flex justify-end gap-2 px-4 py-3 border-t border-gray-200 border-mama-lavender-dark bg-gray-50 bg-mama-lavender-light/50">
1263
1165
  <button class="px-4 py-2 text-sm font-medium text-gray-700 text-gray-700 bg-gray-100 bg-white hover:bg-gray-200 hover:bg-mama-lavender rounded-lg transition-colors" onclick="hideSaveDecisionForm()">Cancel</button>
1264
- <button class="px-4 py-2 text-sm font-medium text-white bg-mama-yellow hover:bg-mama-yellow-hover rounded-lg transition-colors" onclick="submitSaveDecision()">Save</button>
1166
+ <button
1167
+ class="px-4 py-2 text-sm font-medium text-white bg-mama-yellow hover:bg-mama-yellow-hover rounded-lg transition-colors"
1168
+ id="save-form-submit"
1169
+ onclick="submitSaveDecision()"
1170
+ >Save</button>
1265
1171
  </div>
1266
1172
  <div id="save-form-status" class="px-5 pb-4 text-center text-sm"></div>
1267
1173
  </div>
@@ -1375,6 +1281,7 @@
1375
1281
  import { DashboardModule } from '/viewer/js/modules/dashboard.js';
1376
1282
  import { SettingsModule } from '/viewer/js/modules/settings.js';
1377
1283
  import { SkillsModule } from '/viewer/js/modules/skills.js';
1284
+ import { API } from '/viewer/js/utils/api.js';
1378
1285
 
1379
1286
  const memory = new MemoryModule();
1380
1287
  const chat = new ChatModule(memory);
@@ -1934,10 +1841,7 @@
1934
1841
 
1935
1842
  async function updateMemoryStats() {
1936
1843
  try {
1937
- const response = await fetch('/api/dashboard/status');
1938
- if (!response.ok) return;
1939
-
1940
- const data = await response.json();
1844
+ const data = await API.get('/api/dashboard/status');
1941
1845
  const memory = data.memory || {};
1942
1846
 
1943
1847
  document.querySelector('#memory-stats-total p').textContent = memory.total || 0;
@@ -1989,8 +1893,7 @@
1989
1893
  console.log('[MAMA] Loading checkpoints...');
1990
1894
 
1991
1895
  try {
1992
- const response = await fetch('/api/checkpoints');
1993
- const data = await response.json();
1896
+ const data = await API.get('/api/checkpoints');
1994
1897
  checkpointsData = data.checkpoints || [];
1995
1898
 
1996
1899
  console.log('[MAMA] Loaded', checkpointsData.length, 'checkpoints');