mop-agent 0.1.15 → 0.1.16

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.
@@ -1,3 +1,6 @@
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+
1
4
  :root {
2
5
  --mop-red: #742220;
3
6
  --mop-green: #2d4a3e;
@@ -125,7 +128,6 @@ button {
125
128
  position: relative;
126
129
  min-width: 0;
127
130
  display: flex;
128
- border-right: 1px solid rgba(254, 249, 225, .16);
129
131
  }
130
132
 
131
133
  .mop-app-brand {
@@ -266,8 +268,9 @@ button {
266
268
  .mop-sidebar-primary {
267
269
  display: grid;
268
270
  gap: 3px;
269
- margin-bottom: 22px;
271
+ margin-bottom: 0;
270
272
  }
273
+ .mop-workspace-nav { margin-bottom: 22px; }
271
274
 
272
275
  .mop-sidebar-primary a,
273
276
  .mop-nav-section a,
@@ -369,6 +372,123 @@ button {
369
372
  .mop-account-copy strong { font-size: 12px; }
370
373
  .mop-account-copy small { color: rgba(254, 249, 225, .52); font-size: 9px; letter-spacing: .09em; text-transform: uppercase; }
371
374
 
375
+ .mop-account-drawer-scrim {
376
+ position: fixed;
377
+ inset: 0;
378
+ z-index: 80;
379
+ padding: 0;
380
+ border: 0;
381
+ background: rgba(20, 34, 29, .58);
382
+ box-shadow: none;
383
+ cursor: default;
384
+ }
385
+
386
+ .mop-account-drawer {
387
+ position: fixed;
388
+ top: 0;
389
+ right: 0;
390
+ bottom: 0;
391
+ z-index: 90;
392
+ width: min(390px, 100vw);
393
+ display: flex;
394
+ flex-direction: column;
395
+ padding: 18px;
396
+ color: var(--mop-green);
397
+ border-left: 2px solid var(--mop-green);
398
+ background:
399
+ linear-gradient(rgba(255, 253, 242, .9), rgba(254, 249, 225, .96)),
400
+ repeating-linear-gradient(0deg, transparent 0, transparent 7px, rgba(116, 34, 32, .045) 7px, rgba(116, 34, 32, .045) 8px);
401
+ box-shadow: -8px 0 0 rgba(45, 74, 62, .14);
402
+ animation: mop-drawer-enter 150ms steps(5, end);
403
+ }
404
+
405
+ @keyframes mop-drawer-enter {
406
+ from { transform: translateX(100%); }
407
+ to { transform: translateX(0); }
408
+ }
409
+
410
+ .mop-account-drawer-header {
411
+ display: flex;
412
+ align-items: center;
413
+ justify-content: space-between;
414
+ gap: 16px;
415
+ padding-bottom: 16px;
416
+ border-bottom: 1px solid rgba(45, 74, 62, .28);
417
+ }
418
+ .mop-account-drawer-header > div { display: grid; gap: 4px; }
419
+ .mop-account-drawer-header span {
420
+ color: var(--mop-red);
421
+ font-family: "SFMono-Regular", Consolas, monospace;
422
+ font-size: 9px;
423
+ font-weight: 900;
424
+ letter-spacing: .16em;
425
+ }
426
+ .mop-account-drawer-header strong { font-family: "SFMono-Regular", Consolas, monospace; font-size: 20px; }
427
+ .mop-account-drawer-header button {
428
+ width: 36px;
429
+ height: 36px;
430
+ border: 1px solid rgba(45, 74, 62, .38);
431
+ background: var(--mop-paper);
432
+ color: var(--mop-green);
433
+ font-size: 21px;
434
+ cursor: pointer;
435
+ }
436
+
437
+ .mop-account-drawer-profile {
438
+ display: grid;
439
+ grid-template-columns: 58px minmax(0, 1fr);
440
+ align-items: center;
441
+ gap: 13px;
442
+ margin-top: 20px;
443
+ padding: 16px;
444
+ border: 1px solid rgba(45, 74, 62, .38);
445
+ border-bottom-width: 4px;
446
+ background: rgba(255, 253, 242, .78);
447
+ }
448
+ .mop-account-drawer-avatar {
449
+ width: 58px;
450
+ height: 58px;
451
+ display: grid;
452
+ place-items: center;
453
+ background: var(--mop-red);
454
+ color: var(--mop-cream);
455
+ font-family: "SFMono-Regular", Consolas, monospace;
456
+ font-size: 22px;
457
+ font-weight: 900;
458
+ }
459
+ .mop-account-drawer-profile > div { min-width: 0; display: grid; gap: 5px; }
460
+ .mop-account-drawer-profile strong,
461
+ .mop-account-drawer-profile span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
462
+ .mop-account-drawer-profile strong { font-size: 15px; }
463
+ .mop-account-drawer-profile > div span { color: rgba(45, 74, 62, .62); font-size: 11px; }
464
+
465
+ .mop-account-drawer-details { margin: 18px 0 0; }
466
+ .mop-account-drawer-details > div {
467
+ display: flex;
468
+ align-items: center;
469
+ justify-content: space-between;
470
+ gap: 16px;
471
+ padding: 11px 4px;
472
+ border-bottom: 1px solid rgba(45, 74, 62, .18);
473
+ }
474
+ .mop-account-drawer-details dt { color: rgba(45, 74, 62, .58); font-size: 11px; }
475
+ .mop-account-drawer-details dd { margin: 0; color: var(--mop-red); font-size: 11px; font-weight: 800; }
476
+ .mop-account-drawer-spacer { flex: 1; }
477
+
478
+ .mop-account-logout {
479
+ width: 100%;
480
+ min-height: 46px;
481
+ display: flex;
482
+ align-items: center;
483
+ justify-content: center;
484
+ gap: 9px;
485
+ border: 1px solid var(--mop-red);
486
+ border-bottom-width: 4px;
487
+ background: var(--mop-red);
488
+ color: var(--mop-cream);
489
+ cursor: pointer;
490
+ }
491
+
372
492
  .mop-app-main {
373
493
  grid-area: main;
374
494
  min-width: 0;
@@ -413,6 +533,170 @@ button {
413
533
  box-shadow: 2px 2px 0 rgba(45, 74, 62, .08);
414
534
  }
415
535
 
536
+ .mop-primary-link {
537
+ display: inline-flex;
538
+ align-items: center;
539
+ gap: 9px;
540
+ min-height: 40px;
541
+ padding: 9px 14px;
542
+ border: 1px solid var(--mop-red);
543
+ border-bottom-width: 4px;
544
+ background: var(--mop-red);
545
+ color: var(--mop-cream);
546
+ font-family: "SFMono-Regular", Consolas, monospace;
547
+ font-size: 10px;
548
+ font-weight: 900;
549
+ letter-spacing: .08em;
550
+ text-decoration: none;
551
+ }
552
+
553
+ .mop-brain-page { width: min(100%, 1320px); }
554
+ .mop-brain-heading { margin-bottom: 26px; }
555
+ .mop-main-brain {
556
+ min-height: 250px;
557
+ display: grid;
558
+ grid-template-columns: 180px minmax(0, 1fr) 210px;
559
+ align-items: center;
560
+ gap: 30px;
561
+ padding: clamp(22px, 4vw, 42px);
562
+ overflow: hidden;
563
+ background:
564
+ radial-gradient(circle at 17% 50%, rgba(116, 34, 32, .13), transparent 25%),
565
+ rgba(255, 253, 242, .88);
566
+ }
567
+ .mop-main-brain-orbit { position: relative; width: 154px; height: 154px; display: grid; place-items: center; }
568
+ .mop-main-brain-orbit::before,
569
+ .mop-main-brain-orbit::after {
570
+ content: "";
571
+ position: absolute;
572
+ inset: 10px;
573
+ border: 1px solid rgba(116, 34, 32, .28);
574
+ border-radius: 50%;
575
+ }
576
+ .mop-main-brain-orbit::after { inset: 27px; border-color: rgba(45, 74, 62, .32); }
577
+ .mop-main-brain-orbit i { position: absolute; width: 9px; height: 9px; background: var(--mop-red); box-shadow: 0 0 0 4px rgba(116, 34, 32, .1); }
578
+ .mop-main-brain-orbit i:nth-child(2) { top: 14px; right: 35px; }
579
+ .mop-main-brain-orbit i:nth-child(3) { bottom: 28px; left: 11px; background: #d7a52e; }
580
+ .mop-main-brain-orbit i:nth-child(4) { right: 6px; bottom: 50px; background: #4fa676; }
581
+ .mop-main-brain-core {
582
+ position: relative;
583
+ z-index: 2;
584
+ width: 72px;
585
+ height: 72px;
586
+ display: grid;
587
+ place-items: center;
588
+ border-radius: 50%;
589
+ background: var(--mop-red);
590
+ color: var(--mop-cream);
591
+ font-family: "SFMono-Regular", Consolas, monospace;
592
+ font-size: 27px;
593
+ font-weight: 900;
594
+ box-shadow: 0 0 0 8px rgba(116, 34, 32, .1), 5px 5px 0 rgba(45, 74, 62, .16);
595
+ }
596
+ .mop-main-brain-copy h2 { margin: 2px 0 9px; font-family: "SFMono-Regular", Consolas, monospace; font-size: clamp(25px, 3vw, 38px); }
597
+ .mop-main-brain-copy > p:not(.mop-page-kicker):not(.mop-brain-message) { max-width: 660px; margin: 0; color: rgba(45, 74, 62, .68); line-height: 1.65; }
598
+ .mop-main-brain-actions { display: flex; align-items: center; flex-wrap: wrap; gap: 15px; margin-top: 22px; }
599
+ .mop-main-brain-actions button,
600
+ .mop-brain-linker > button {
601
+ min-height: 40px;
602
+ padding: 9px 14px;
603
+ border: 1px solid var(--mop-green);
604
+ border-bottom-width: 3px;
605
+ background: var(--mop-green);
606
+ color: var(--mop-cream);
607
+ font-size: 10px;
608
+ font-weight: 900;
609
+ cursor: pointer;
610
+ }
611
+ .mop-main-brain-actions a { color: var(--mop-red); font-size: 12px; font-weight: 800; }
612
+ .mop-brain-message { margin: 12px 0 0; color: var(--mop-red); font-size: 12px; }
613
+ .mop-main-brain-stats { display: grid; align-self: stretch; border-left: 1px solid rgba(45, 74, 62, .2); }
614
+ .mop-main-brain-stats div { display: grid; align-content: center; gap: 2px; padding: 11px 0 11px 23px; border-bottom: 1px solid rgba(45, 74, 62, .15); }
615
+ .mop-main-brain-stats div:last-child { border-bottom: 0; }
616
+ .mop-main-brain-stats strong { color: var(--mop-red); font-family: "SFMono-Regular", Consolas, monospace; font-size: 24px; }
617
+ .mop-main-brain-stats span { color: rgba(45, 74, 62, .58); font-size: 10px; text-transform: uppercase; letter-spacing: .08em; }
618
+
619
+ .mop-brain-linker {
620
+ display: grid;
621
+ grid-template-columns: minmax(180px, 1fr) auto;
622
+ align-items: center;
623
+ gap: 14px;
624
+ margin: 18px 0;
625
+ padding: 15px 17px;
626
+ }
627
+ .mop-brain-linker > div { display: grid; gap: 3px; }
628
+ .mop-brain-linker > div span { color: rgba(45, 74, 62, .58); font-size: 11px; }
629
+ .mop-brain-linker code { grid-column: 1 / -1; overflow-x: auto; padding: 10px; background: rgba(45, 74, 62, .07); color: var(--mop-red); font-size: 11px; }
630
+ .mop-brain-columns { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
631
+ .mop-brain-section { min-width: 0; padding: 19px; }
632
+ .mop-brain-section > header,
633
+ .mop-brain-approvals > header { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding-bottom: 14px; border-bottom: 1px solid rgba(45, 74, 62, .2); }
634
+ .mop-brain-section header h2,
635
+ .mop-brain-approvals header h2 { margin: 0; font-family: "SFMono-Regular", Consolas, monospace; font-size: 17px; }
636
+ .mop-brain-section > header > span,
637
+ .mop-brain-approvals > header > span { min-width: 32px; padding: 5px 7px; border: 1px solid rgba(45, 74, 62, .3); color: var(--mop-red); text-align: center; font-size: 10px; font-weight: 900; }
638
+ .mop-brain-empty { min-height: 155px; display: grid; place-content: center; text-align: center; }
639
+ .mop-brain-empty strong { font-size: 13px; }
640
+ .mop-brain-empty p { max-width: 290px; margin: 5px 0; color: rgba(45, 74, 62, .5); font-size: 12px; }
641
+ .mop-brain-note-list,
642
+ .mop-brain-project-list,
643
+ .mop-brain-approvals ul { list-style: none; margin: 0; padding: 0; }
644
+ .mop-brain-note-list li { display: grid; grid-template-columns: 10px minmax(0, 1fr); gap: 11px; padding: 13px 2px; border-bottom: 1px solid rgba(45, 74, 62, .13); }
645
+ .mop-brain-note-dot { width: 8px; height: 8px; margin-top: 5px; background: #4fa676; }
646
+ .mop-brain-note-list div { min-width: 0; }
647
+ .mop-brain-note-list strong { font-size: 13px; }
648
+ .mop-brain-note-list p { margin: 4px 0; color: rgba(45, 74, 62, .65); font-size: 12px; line-height: 1.55; }
649
+ .mop-brain-note-list small,
650
+ .mop-brain-project-list small { color: rgba(45, 74, 62, .48); font-size: 9px; text-transform: uppercase; letter-spacing: .06em; }
651
+ .mop-brain-project-list li { display: grid; grid-template-columns: 9px minmax(0, 1fr) auto; align-items: center; gap: 11px; min-height: 58px; padding: 9px 2px; border-bottom: 1px solid rgba(45, 74, 62, .13); }
652
+ .mop-project-status { width: 8px; height: 8px; background: rgba(45, 74, 62, .3); }
653
+ .mop-project-status.is-online { background: #4fa676; box-shadow: 0 0 0 3px rgba(79, 166, 118, .12); }
654
+ .mop-brain-project-list div { min-width: 0; display: grid; gap: 4px; }
655
+ .mop-brain-project-list div a { overflow: hidden; color: var(--mop-green); font-size: 13px; font-weight: 800; text-overflow: ellipsis; white-space: nowrap; }
656
+ .mop-brain-project-list > li > a { color: var(--mop-red); font-size: 10px; font-weight: 900; }
657
+ .mop-brain-approvals { margin-top: 18px; padding: 19px; }
658
+ .mop-brain-approvals li { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 2px; border-bottom: 1px solid rgba(45, 74, 62, .14); }
659
+ .mop-brain-approvals li > div:first-child { display: grid; gap: 4px; }
660
+ .mop-brain-approvals code { color: var(--mop-red); font-size: 10px; }
661
+ .mop-brain-approvals small { color: rgba(45, 74, 62, .5); }
662
+ .mop-brain-approvals li > div:last-child { display: flex; gap: 7px; }
663
+ .mop-brain-approvals button { padding: 7px 10px; border: 1px solid var(--mop-green); background: var(--mop-green); color: var(--mop-cream); font-size: 9px; cursor: pointer; }
664
+ .mop-brain-approvals button:last-child { border-color: var(--mop-red); background: var(--mop-red); }
665
+
666
+ .mop-graph-view { height: calc(100vh - 70px); min-height: 560px; display: grid; grid-template-rows: 54px minmax(0, 1fr); overflow: hidden; background: #171918; color: #e9e5d4; }
667
+ .mop-graph-toolbar { display: grid; grid-template-columns: minmax(220px, 1fr) minmax(220px, 420px) auto; align-items: center; gap: 16px; padding: 8px 15px; border-bottom: 1px solid rgba(255, 255, 255, .1); background: #202221; }
668
+ .mop-graph-toolbar-left { min-width: 0; display: flex; align-items: center; gap: 12px; }
669
+ .mop-graph-toolbar-left a { width: 30px; height: 30px; display: grid; place-items: center; color: #e9e5d4; border: 1px solid rgba(255, 255, 255, .12); text-decoration: none; }
670
+ .mop-graph-toolbar-left strong { font-size: 12px; }
671
+ .mop-graph-toolbar-left span { color: rgba(233, 229, 212, .46); font-size: 10px; }
672
+ .mop-graph-search { display: flex; align-items: center; gap: 8px; min-width: 0; height: 34px; padding: 0 10px; border: 1px solid rgba(255, 255, 255, .14); background: rgba(0, 0, 0, .18); }
673
+ .mop-graph-search input { width: 100%; border: 0; background: transparent; color: #e9e5d4; box-shadow: none; outline: 0; font-size: 11px; }
674
+ .mop-graph-toolbar > button { min-height: 34px; padding: 7px 11px; border: 1px solid rgba(255, 255, 255, .14); background: transparent; color: #e9e5d4; font-size: 10px; cursor: pointer; }
675
+ .mop-graph-canvas { min-height: 0; position: relative; }
676
+ .mop-graph-canvas .react-flow__controls { border: 1px solid rgba(255, 255, 255, .12); box-shadow: none; }
677
+ .mop-graph-canvas .react-flow__controls-button { border: 0; border-bottom: 1px solid rgba(255, 255, 255, .09); background: #242625; fill: #e9e5d4; }
678
+ .mop-memory-graph-node { position: relative; display: flex; align-items: center; gap: 6px; color: rgba(233, 229, 212, .68); font-size: 9px; white-space: nowrap; cursor: grab; }
679
+ .mop-memory-node-dot { flex: 0 0 auto; width: 10px; height: 10px; border-radius: 50%; box-shadow: 0 0 0 3px rgba(255, 255, 255, .035); }
680
+ .mop-memory-graph-node.is-main .mop-memory-node-dot { width: 28px; height: 28px; box-shadow: 0 0 0 7px rgba(228, 184, 63, .12), 0 0 28px rgba(228, 184, 63, .22); }
681
+ .mop-memory-graph-node.is-main .mop-memory-node-label { color: #f4e6ad; font-size: 12px; font-weight: 900; }
682
+ .mop-memory-graph-node.is-selected .mop-memory-node-dot { outline: 2px solid #fff; outline-offset: 3px; }
683
+ .mop-graph-handle { width: 1px !important; height: 1px !important; min-width: 0 !important; min-height: 0 !important; opacity: 0; }
684
+ .mop-graph-view.hide-labels .mop-memory-node-label { display: none; }
685
+ .mop-graph-filters,
686
+ .mop-graph-inspector { position: absolute; z-index: 5; border: 1px solid rgba(255, 255, 255, .12); background: rgba(31, 33, 32, .92); backdrop-filter: blur(8px); }
687
+ .mop-graph-filters { top: 14px; right: 14px; width: 168px; display: grid; gap: 8px; padding: 12px; }
688
+ .mop-graph-filters > strong { margin-bottom: 2px; font-size: 10px; text-transform: uppercase; letter-spacing: .11em; }
689
+ .mop-graph-filters label { display: grid; grid-template-columns: 14px 8px 1fr; align-items: center; gap: 7px; color: rgba(233, 229, 212, .68); font-size: 10px; }
690
+ .mop-graph-filters input { margin: 0; box-shadow: none; }
691
+ .mop-graph-filters label > span { width: 7px; height: 7px; border-radius: 50%; }
692
+ .mop-graph-inspector { right: 14px; bottom: 14px; width: min(280px, calc(100% - 28px)); display: grid; grid-template-columns: 10px minmax(0, 1fr); gap: 7px 9px; padding: 15px; }
693
+ .mop-graph-inspector > button { position: absolute; top: 6px; right: 6px; width: 26px; height: 26px; border: 0; background: transparent; color: #e9e5d4; box-shadow: none; cursor: pointer; }
694
+ .mop-graph-inspector > span { width: 9px; height: 9px; margin-top: 2px; border-radius: 50%; }
695
+ .mop-graph-inspector small { color: rgba(233, 229, 212, .46); font-size: 8px; letter-spacing: .12em; }
696
+ .mop-graph-inspector strong,
697
+ .mop-graph-inspector p { grid-column: 2; }
698
+ .mop-graph-inspector p { margin: 0; color: rgba(233, 229, 212, .58); font-size: 10px; line-height: 1.5; }
699
+
416
700
  .mop-sidebar-scrim { display: none; }
417
701
 
418
702
  /* Assistant content now lives inside the shared shell. */
@@ -458,6 +742,87 @@ button {
458
742
  background: linear-gradient(transparent, var(--mop-cream) 28%);
459
743
  }
460
744
 
745
+ .mop-prompt-box {
746
+ width: min(calc(100% - 32px), 800px);
747
+ margin: 0 auto;
748
+ border-radius: 26px !important;
749
+ border-bottom-width: 4px !important;
750
+ box-shadow: 4px 4px 0 rgba(45, 74, 62, .13) !important;
751
+ }
752
+ .mop-prompt-textarea { box-shadow: none !important; font: inherit; line-height: 1.55; }
753
+ .mop-prompt-round-button,
754
+ .mop-prompt-send {
755
+ width: 34px;
756
+ height: 34px;
757
+ display: grid;
758
+ place-items: center;
759
+ padding: 0;
760
+ border: 0;
761
+ border-radius: 999px !important;
762
+ box-shadow: none;
763
+ cursor: pointer;
764
+ }
765
+ .mop-prompt-round-button { background: transparent; color: var(--mop-green); }
766
+ .mop-prompt-round-button:hover { background: rgba(45, 74, 62, .1); }
767
+ .mop-prompt-round-button.is-listening { background: var(--mop-red); color: var(--mop-cream); animation: mop-listening-pulse 900ms steps(2, end) infinite; }
768
+ .mop-prompt-send { background: var(--mop-red); color: var(--mop-cream); }
769
+ .mop-prompt-send:disabled { opacity: .38; cursor: not-allowed; }
770
+ .mop-prompt-tool-button,
771
+ .mop-prompt-active-tool {
772
+ min-height: 34px;
773
+ display: flex;
774
+ align-items: center;
775
+ gap: 7px;
776
+ padding: 0 10px;
777
+ border: 0;
778
+ border-radius: 999px !important;
779
+ background: transparent;
780
+ color: var(--mop-green);
781
+ box-shadow: none;
782
+ cursor: pointer;
783
+ }
784
+ .mop-prompt-tool-button:hover { background: rgba(45, 74, 62, .1); }
785
+ .mop-prompt-active-tool { border: 1px solid rgba(116, 34, 32, .32); color: var(--mop-red); background: rgba(116, 34, 32, .06); }
786
+ .mop-prompt-popover { border-radius: 14px !important; }
787
+ .mop-prompt-popover-item {
788
+ width: 100%;
789
+ min-height: 38px;
790
+ display: flex;
791
+ align-items: center;
792
+ gap: 9px;
793
+ padding: 8px 10px;
794
+ border: 0;
795
+ border-radius: 8px !important;
796
+ background: transparent;
797
+ color: var(--mop-green);
798
+ box-shadow: none;
799
+ text-align: left;
800
+ cursor: pointer;
801
+ }
802
+ .mop-prompt-popover-item:hover { background: rgba(45, 74, 62, .09); }
803
+ .mop-prompt-preview-trigger { padding: 0; border: 0; border-radius: 12px !important; background: transparent; box-shadow: none; cursor: zoom-in; }
804
+ .mop-prompt-remove-image {
805
+ position: absolute;
806
+ top: -5px;
807
+ right: -5px;
808
+ width: 22px;
809
+ height: 22px;
810
+ display: grid;
811
+ place-items: center;
812
+ padding: 0;
813
+ border: 2px solid var(--mop-paper);
814
+ border-radius: 999px !important;
815
+ background: var(--mop-green);
816
+ color: var(--mop-cream);
817
+ box-shadow: none;
818
+ cursor: pointer;
819
+ }
820
+ .mop-prompt-error { margin: 3px 10px 5px; color: var(--mop-red); font-size: 11px; }
821
+
822
+ @keyframes mop-listening-pulse {
823
+ 50% { opacity: .58; }
824
+ }
825
+
461
826
  .mop-chat-history {
462
827
  min-width: 0;
463
828
  min-height: 0;
@@ -584,6 +949,39 @@ button {
584
949
  letter-spacing: .13em;
585
950
  text-transform: uppercase;
586
951
  }
952
+ .mop-apps-layout { display: grid; grid-template-columns: minmax(220px, .72fr) minmax(320px, 1.28fr); gap: 18px; }
953
+ .mop-app-catalog { display: grid; align-content: start; gap: 6px; }
954
+ .mop-app-catalog > button {
955
+ width: 100%;
956
+ min-height: 62px;
957
+ display: grid;
958
+ grid-template-columns: 36px minmax(0, 1fr) 8px;
959
+ align-items: center;
960
+ gap: 11px;
961
+ padding: 9px 11px;
962
+ border: 1px solid rgba(45, 74, 62, .2);
963
+ background: rgba(254, 249, 225, .48);
964
+ color: var(--mop-green);
965
+ text-align: left;
966
+ cursor: pointer;
967
+ }
968
+ .mop-app-catalog > button.is-active { border-color: var(--mop-red); border-left-width: 4px; background: rgba(116, 34, 32, .06); }
969
+ .mop-app-catalog > button > span { width: 34px; height: 34px; display: grid; place-items: center; background: var(--mop-green); color: var(--mop-cream); font-size: 17px; }
970
+ .mop-app-catalog > button > div { min-width: 0; display: grid; gap: 4px; }
971
+ .mop-app-catalog strong { font-size: 12px; }
972
+ .mop-app-catalog small { overflow: hidden; color: rgba(45, 74, 62, .48); font-size: 8px; letter-spacing: .07em; text-overflow: ellipsis; white-space: nowrap; }
973
+ .mop-app-catalog i { width: 7px; height: 7px; background: rgba(45, 74, 62, .24); }
974
+ .mop-app-catalog i.is-online { background: #4fa676; box-shadow: 0 0 0 3px rgba(79, 166, 118, .12); }
975
+ .mop-app-config-panel { display: grid; align-content: start; gap: 15px; padding: 18px; border: 1px solid rgba(45, 74, 62, .28); border-bottom-width: 4px; background: rgba(254, 249, 225, .55); }
976
+ .mop-app-config-panel > header { display: grid; grid-template-columns: 48px minmax(0, 1fr); align-items: center; gap: 12px; padding-bottom: 14px; border-bottom: 1px solid rgba(45, 74, 62, .18); }
977
+ .mop-app-config-panel > header > span { width: 46px; height: 46px; display: grid; place-items: center; background: var(--mop-red); color: var(--mop-cream); font-size: 20px; }
978
+ .mop-app-config-panel h3 { margin: 0; font-family: "SFMono-Regular", Consolas, monospace; font-size: 17px; }
979
+ .mop-app-config-panel header p { margin: 4px 0 0; color: rgba(45, 74, 62, .58); font-size: 11px; line-height: 1.45; }
980
+ .mop-app-runtime-status { display: flex; align-items: center; gap: 8px; color: rgba(45, 74, 62, .58); font-size: 10px; }
981
+ .mop-app-runtime-status > span { width: 8px; height: 8px; background: #d7a52e; }
982
+ .mop-app-runtime-status > span.is-ready { background: #4fa676; }
983
+ .mop-app-enabled-toggle { display: flex; align-items: center; gap: 9px; color: var(--mop-green); font-size: 12px; }
984
+ .mop-app-enabled-toggle input { width: 16px; height: 16px; box-shadow: none; }
587
985
  .mop-assistant-welcome img { width: 100%; height: 100%; object-fit: contain; }
588
986
 
589
987
  @media (prefers-reduced-transparency: reduce) {
@@ -651,6 +1049,20 @@ button {
651
1049
  .mop-assistant-composer-wrap { padding: 26px 12px 12px; }
652
1050
  .mop-settings-grid { grid-template-columns: 1fr; }
653
1051
  .mop-user-invite-form { grid-template-columns: 1fr !important; }
1052
+ .mop-main-brain { grid-template-columns: 1fr; text-align: center; }
1053
+ .mop-main-brain-orbit { margin: 0 auto; }
1054
+ .mop-main-brain-copy > p:not(.mop-page-kicker):not(.mop-brain-message) { margin-inline: auto; }
1055
+ .mop-main-brain-actions { justify-content: center; }
1056
+ .mop-main-brain-stats { grid-template-columns: repeat(3, 1fr); border-top: 1px solid rgba(45, 74, 62, .2); border-left: 0; }
1057
+ .mop-main-brain-stats div { padding: 12px 4px; border-right: 1px solid rgba(45, 74, 62, .15); border-bottom: 0; }
1058
+ .mop-brain-linker { grid-template-columns: 1fr; }
1059
+ .mop-brain-columns { grid-template-columns: 1fr; }
1060
+ .mop-apps-layout { grid-template-columns: 1fr; }
1061
+ .mop-graph-view { height: calc(100vh - 62px); min-height: 520px; }
1062
+ .mop-graph-toolbar { grid-template-columns: minmax(0, 1fr) auto; gap: 7px; }
1063
+ .mop-graph-toolbar-left span { display: none; }
1064
+ .mop-graph-search { grid-column: 1 / -1; grid-row: 2; }
1065
+ .mop-graph-filters { width: 142px; }
654
1066
  }
655
1067
 
656
1068
  .mop-back-workspace-btn {
@@ -676,4 +1088,8 @@ button {
676
1088
  @media (min-width: 761px) and (max-width: 1050px) {
677
1089
  .mop-assistant-page { grid-template-columns: minmax(0, 1fr) 235px; }
678
1090
  .mop-chat-history { padding-inline: 9px; }
1091
+ .mop-main-brain { grid-template-columns: 150px minmax(0, 1fr); }
1092
+ .mop-main-brain-stats { grid-column: 1 / -1; grid-template-columns: repeat(3, 1fr); border-top: 1px solid rgba(45, 74, 62, .2); border-left: 0; }
1093
+ .mop-main-brain-stats div { padding: 12px; border-right: 1px solid rgba(45, 74, 62, .15); border-bottom: 0; }
1094
+ .mop-apps-layout { grid-template-columns: 210px minmax(0, 1fr); }
679
1095
  }
@@ -6,6 +6,16 @@ import { useMemoryCore } from "@/components/AppShell";
6
6
 
7
7
  type Masked = { configured: boolean; provider?: string; model?: string | null; keyHint?: string };
8
8
  type Member = { id: string; email: string; name: string; role: string };
9
+ type AppId = "telegram" | "discord" | "whatsapp" | "slack" | "webhook";
10
+ type AppConfig = { appId: AppId; configured: boolean; enabled: boolean; keyHint: string; updatedAt: number };
11
+
12
+ const APP_CATALOG: Array<{ id: AppId; name: string; icon: string; description: string; secretLabel: string; fieldLabel: string; fieldKey: string; runtime: boolean }> = [
13
+ { id: "telegram", name: "Telegram", icon: "✈", description: "Private bot conversations and project-bound chats.", secretLabel: "Bot token", fieldLabel: "Bot username (optional)", fieldKey: "username", runtime: true },
14
+ { id: "discord", name: "Discord", icon: "◈", description: "Guild channels, direct messages and project replies.", secretLabel: "Bot token", fieldLabel: "Application ID (optional)", fieldKey: "applicationId", runtime: true },
15
+ { id: "whatsapp", name: "WhatsApp", icon: "◉", description: "Meta Cloud API account and phone-number configuration.", secretLabel: "Access token", fieldLabel: "Phone number ID", fieldKey: "phoneNumberId", runtime: false },
16
+ { id: "slack", name: "Slack", icon: "⌗", description: "Workspace bot configuration for future channel routing.", secretLabel: "Bot token", fieldLabel: "App ID", fieldKey: "appId", runtime: false },
17
+ { id: "webhook", name: "Webhook", icon: "↗", description: "Signed custom automation endpoint configuration.", secretLabel: "Signing secret", fieldLabel: "Endpoint URL", fieldKey: "endpoint", runtime: false },
18
+ ];
9
19
 
10
20
  export default function SettingsPage() {
11
21
  const { settingsSection: section } = useMemoryCore();
@@ -124,7 +134,7 @@ export default function SettingsPage() {
124
134
  </form>
125
135
  {providerMsg && <p style={messageStyle}>{providerMsg}</p>}
126
136
  </>
127
- ) : (
137
+ ) : section === "users" ? (
128
138
  <>
129
139
  <div style={sectionHeading}>
130
140
  <div>
@@ -165,6 +175,8 @@ export default function SettingsPage() {
165
175
  {userMsg && <p style={messageStyle}>{userMsg}</p>}
166
176
  </div>
167
177
  </>
178
+ ) : (
179
+ <AppsSettings />
168
180
  )}
169
181
  </section>
170
182
  </div>
@@ -172,6 +184,95 @@ export default function SettingsPage() {
172
184
  );
173
185
  }
174
186
 
187
+ function AppsSettings() {
188
+ const [configs, setConfigs] = useState<AppConfig[]>([]);
189
+ const [selected, setSelected] = useState<AppId>("telegram");
190
+ const [secret, setSecret] = useState("");
191
+ const [fieldValue, setFieldValue] = useState("");
192
+ const [enabled, setEnabled] = useState(true);
193
+ const [message, setMessage] = useState("");
194
+ const app = APP_CATALOG.find((item) => item.id === selected)!;
195
+ const current = configs.find((config) => config.appId === selected);
196
+
197
+ function loadApps() {
198
+ fetch("/api/apps").then((response) => response.json()).then((result) => setConfigs(result.apps ?? [])).catch(() => {});
199
+ }
200
+
201
+ useEffect(loadApps, []);
202
+
203
+ useEffect(() => {
204
+ setEnabled(current?.enabled ?? true);
205
+ setSecret("");
206
+ setFieldValue("");
207
+ setMessage("");
208
+ }, [selected, current?.enabled]);
209
+
210
+ async function save(event: React.FormEvent) {
211
+ event.preventDefault();
212
+ setMessage("Saving encrypted configuration…");
213
+ const response = await fetch("/api/apps", {
214
+ method: "POST",
215
+ headers: { "content-type": "application/json" },
216
+ body: JSON.stringify({
217
+ appId: selected,
218
+ secret: secret || undefined,
219
+ enabled,
220
+ fields: fieldValue ? { [app.fieldKey]: fieldValue } : undefined,
221
+ }),
222
+ });
223
+ const result = await response.json();
224
+ if (response.ok) {
225
+ setConfigs(result.apps ?? []);
226
+ setSecret("");
227
+ setFieldValue("");
228
+ setMessage(app.runtime ? "Saved. Restart MOP-AGENT to activate this bot runtime." : "Configuration saved securely. Runtime adapter will use it when enabled.");
229
+ } else {
230
+ setMessage(`Unable to save: ${result.error ?? response.status}`);
231
+ }
232
+ }
233
+
234
+ return (
235
+ <>
236
+ <div style={sectionHeading}>
237
+ <div><p className="mop-page-kicker">CHANNELS & INTEGRATIONS</p><h2 style={titleStyle}>Apps</h2></div>
238
+ <span style={statusBadge}>{configs.filter((config) => config.enabled).length} ENABLED</span>
239
+ </div>
240
+
241
+ <div className="mop-apps-layout">
242
+ <div className="mop-app-catalog">
243
+ {APP_CATALOG.map((item) => {
244
+ const config = configs.find((entry) => entry.appId === item.id);
245
+ return (
246
+ <button type="button" key={item.id} className={selected === item.id ? "is-active" : ""} onClick={() => setSelected(item.id)}>
247
+ <span>{item.icon}</span>
248
+ <div><strong>{item.name}</strong><small>{config?.configured ? (config.enabled ? "CONFIGURED · ENABLED" : "CONFIGURED · PAUSED") : "NOT CONFIGURED"}</small></div>
249
+ <i className={config?.enabled ? "is-online" : ""} />
250
+ </button>
251
+ );
252
+ })}
253
+ </div>
254
+
255
+ <form className="mop-app-config-panel" onSubmit={save}>
256
+ <header><span>{app.icon}</span><div><h3>{app.name}</h3><p>{app.description}</p></div></header>
257
+ <div className="mop-app-runtime-status">
258
+ <span className={app.runtime ? "is-ready" : ""} />
259
+ {app.runtime ? "Runtime adapter available" : "Configuration registry ready · adapter expansion planned"}
260
+ </div>
261
+ <label style={labelStyle}>{app.secretLabel}
262
+ <input type="password" required={!current?.configured} value={secret} onChange={(event) => setSecret(event.target.value)} placeholder={current?.configured ? `Saved key ${current.keyHint} · leave blank to keep` : `Enter ${app.secretLabel.toLowerCase()}`} style={inputStyle} />
263
+ </label>
264
+ <label style={labelStyle}>{app.fieldLabel}
265
+ <input value={fieldValue} onChange={(event) => setFieldValue(event.target.value)} placeholder={current?.configured ? "Leave blank to keep saved value" : app.fieldLabel} style={inputStyle} />
266
+ </label>
267
+ <label className="mop-app-enabled-toggle"><input type="checkbox" checked={enabled} onChange={(event) => setEnabled(event.target.checked)} /><span>Enable this integration</span></label>
268
+ <button type="submit" style={primaryButton}>SAVE {app.name.toUpperCase()}</button>
269
+ {message && <p style={messageStyle}>{message}</p>}
270
+ </form>
271
+ </div>
272
+ </>
273
+ );
274
+ }
275
+
175
276
  const adminBadge: CSSProperties = { padding: "7px 10px", color: "#fef9e1", background: "#742220", fontFamily: '"SFMono-Regular", Consolas, monospace', fontSize: 10, fontWeight: 900, letterSpacing: ".12em" };
176
277
  const sectionHeading: CSSProperties = { display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, marginBottom: 20, paddingBottom: 15, borderBottom: "1px solid rgba(45,74,62,.24)" };
177
278
  const titleStyle: CSSProperties = { margin: 0, fontFamily: '"SFMono-Regular", Consolas, monospace', fontSize: 22 };