clay-server 2.20.0-beta.1 → 2.20.0-beta.2

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.
package/lib/public/app.js CHANGED
@@ -8,7 +8,7 @@ import { initMateKnowledge, requestKnowledgeList, renderKnowledgeList, handleKno
8
8
  import { initMateMemory, renderMemoryList, hideMemory } from './modules/mate-memory.js';
9
9
  import { initRewind, setRewindMode, showRewindModal, clearPendingRewindUuid, addRewindButton } from './modules/rewind.js';
10
10
  import { initNotifications, showDoneNotification, playDoneSound, isNotifAlertEnabled, isNotifSoundEnabled } from './modules/notifications.js';
11
- import { initInput, clearPendingImages, handleInputSync, autoResize, builtinCommands, sendMessage, hasSendableContent } from './modules/input.js';
11
+ import { initInput, clearPendingImages, handleInputSync, autoResize, builtinCommands, sendMessage, hasSendableContent, setScheduleBtnDisabled } from './modules/input.js';
12
12
  import { initQrCode, triggerShare } from './modules/qrcode.js';
13
13
  import { initFileBrowser, loadRootDirectory, refreshTree, handleFsList, handleFsRead, handleDirChanged, refreshIfOpen, handleFileChanged, handleFileHistory, handleGitDiff, handleFileAt, getPendingNavigate, closeFileViewer, resetFileBrowser } from './modules/filebrowser.js';
14
14
  import { initTerminal, openTerminal, closeTerminal, resetTerminals, handleTermList, handleTermCreated, handleTermOutput, handleTermExited, handleTermClosed, sendTerminalCommand } from './modules/terminal.js';
@@ -75,6 +75,7 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
75
75
  var cachedDmConversations = [];
76
76
  var dmRemovedUsers = {}; // { userId: true } - users explicitly removed from favorites
77
77
  var cachedMatesList = []; // Cached list of mates for user strip
78
+ var cachedAvailableBuiltins = []; // Deleted built-in mates available for re-add
78
79
 
79
80
  // --- Mate WS (separate connection to mate project) ---
80
81
  var mateWs = null;
@@ -835,15 +836,74 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
835
836
  }
836
837
  })();
837
838
 
838
- function handleMateCreatedInApp(mate) {
839
+ function handleMateCreatedInApp(mate, msg) {
839
840
  if (!mate) return;
840
841
  cachedMatesList.push(mate);
842
+ if (msg && msg.availableBuiltins) cachedAvailableBuiltins = msg.availableBuiltins;
843
+ if (msg && msg.dmFavorites) cachedDmFavorites = msg.dmFavorites;
841
844
  renderUserStrip(cachedAllUsers, cachedOnlineIds, myUserId, cachedDmFavorites, cachedDmConversations, dmUnread, dmRemovedUsers, cachedMatesList);
842
- // Store pending interview data so we can auto-send after DM opens
843
- pendingMateInterview = mate;
845
+ // Built-in mates handle their own onboarding via CLAUDE.md, skip auto-interview
846
+ if (!mate.builtinKey) {
847
+ pendingMateInterview = mate;
848
+ }
844
849
  openDm(mate.id);
845
850
  }
846
851
 
852
+ function renderAvailableBuiltins(builtins) {
853
+ // Append deleted built-in mates to the mates list in the picker
854
+ var matesList = document.querySelector(".dm-mates-list");
855
+ if (!matesList) return;
856
+ if (!builtins || builtins.length === 0) return;
857
+
858
+ for (var i = 0; i < builtins.length; i++) {
859
+ (function (b) {
860
+ var item = document.createElement("div");
861
+ item.className = "dm-user-picker-item dm-user-picker-builtin-item";
862
+ item.style.opacity = "0.5";
863
+
864
+ var av = document.createElement("img");
865
+ av.className = "dm-user-picker-avatar";
866
+ av.src = b.avatarCustom || "";
867
+ av.alt = b.displayName;
868
+ item.appendChild(av);
869
+
870
+ var nameWrap = document.createElement("div");
871
+ nameWrap.style.cssText = "flex:1;min-width:0;";
872
+ var nameEl = document.createElement("span");
873
+ nameEl.className = "dm-user-picker-name";
874
+ nameEl.textContent = b.displayName;
875
+ nameWrap.appendChild(nameEl);
876
+ var bioEl = document.createElement("div");
877
+ bioEl.style.cssText = "font-size:11px;color:var(--text-dimmer);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;";
878
+ bioEl.textContent = "Deleted";
879
+ nameWrap.appendChild(bioEl);
880
+ item.appendChild(nameWrap);
881
+
882
+ var addBtn = document.createElement("button");
883
+ addBtn.style.cssText = "border:none;background:none;cursor:pointer;padding:2px 6px;color:var(--accent, #6366f1);font-size:12px;font-weight:600;";
884
+ addBtn.textContent = "+ Add";
885
+ addBtn.title = "Re-add " + b.displayName;
886
+ addBtn.addEventListener("click", function (e) {
887
+ e.stopPropagation();
888
+ if (ws && ws.readyState === 1) {
889
+ ws.send(JSON.stringify({ type: "mate_readd_builtin", builtinKey: b.key }));
890
+ }
891
+ closeDmUserPicker();
892
+ });
893
+ item.appendChild(addBtn);
894
+
895
+ item.addEventListener("click", function () {
896
+ if (ws && ws.readyState === 1) {
897
+ ws.send(JSON.stringify({ type: "mate_readd_builtin", builtinKey: b.key }));
898
+ }
899
+ closeDmUserPicker();
900
+ });
901
+
902
+ matesList.appendChild(item);
903
+ })(builtins[i]);
904
+ }
905
+ }
906
+
847
907
  var pendingMateInterview = null;
848
908
 
849
909
  function buildMateInterviewPrompt(mate) {
@@ -1885,6 +1945,7 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
1885
1945
  getHistoryFrom: function () { return historyFrom; },
1886
1946
  get permissions() { return myPermissions; },
1887
1947
  get projectList() { return cachedProjects || []; },
1948
+ availableBuiltins: function () { return cachedAvailableBuiltins || []; },
1888
1949
  };
1889
1950
  initSidebar(sidebarCtx);
1890
1951
  initIconStrip(sidebarCtx);
@@ -1901,6 +1962,7 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
1901
1962
  currentSlug: function () { return mateProjectSlug || currentSlug; },
1902
1963
  projectList: function () { return cachedProjects || []; },
1903
1964
  matesList: function () { return cachedMatesList || []; },
1965
+ availableBuiltins: function () { return cachedAvailableBuiltins || []; },
1904
1966
  allUsers: function () { return cachedAllUsers || []; },
1905
1967
  dmConversations: function () { return cachedDmConversations || []; },
1906
1968
  myUserId: function () { return myUserId; },
@@ -2852,6 +2914,9 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
2852
2914
  function addToMessages(el) {
2853
2915
  if (prependAnchor) messagesEl.insertBefore(el, prependAnchor);
2854
2916
  else messagesEl.appendChild(el);
2917
+ if (scheduledMsgEl && el !== scheduledMsgEl && scheduledMsgEl.parentNode === messagesEl) {
2918
+ messagesEl.appendChild(scheduledMsgEl);
2919
+ }
2855
2920
  }
2856
2921
 
2857
2922
  var newMsgBtn = $("new-msg-btn");
@@ -3596,13 +3661,12 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3596
3661
  popoverText = typeLabel + " limit exceeded";
3597
3662
  updateRateLimitIndicator(msg);
3598
3663
  startRateLimitCountdown(null, msg.resetsAt, null);
3599
- // Track for schedule mode
3664
+ // Track rate limit reset time
3600
3665
  rateLimitResetsAt = msg.resetsAt;
3601
3666
  if (rateLimitResetTimer) clearTimeout(rateLimitResetTimer);
3602
3667
  rateLimitResetTimer = setTimeout(function () {
3603
3668
  rateLimitResetsAt = null;
3604
3669
  rateLimitResetTimer = null;
3605
- exitScheduleMode();
3606
3670
  }, msg.resetsAt - Date.now() + 1000);
3607
3671
  } else {
3608
3672
  var pct = msg.utilization ? Math.round(msg.utilization * 100) : null;
@@ -3613,32 +3677,6 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3613
3677
  showRateLimitPopover(popoverText, isRejected);
3614
3678
  }
3615
3679
 
3616
- // --- Schedule mode (rate limit) ---
3617
-
3618
- var scheduleModeActive = false;
3619
-
3620
- function enterScheduleMode() {
3621
- if (scheduleModeActive) return;
3622
- scheduleModeActive = true;
3623
- var inputRow = document.getElementById("input-row");
3624
- if (inputRow) inputRow.classList.add("input-rate-limited");
3625
- if (inputEl) {
3626
- inputEl.dataset.originalPlaceholder = inputEl.placeholder;
3627
- inputEl.placeholder = "Schedule message after limit resets...";
3628
- }
3629
- }
3630
-
3631
- function exitScheduleMode() {
3632
- if (!scheduleModeActive) return;
3633
- scheduleModeActive = false;
3634
- var inputRow = document.getElementById("input-row");
3635
- if (inputRow) inputRow.classList.remove("input-rate-limited");
3636
- if (inputEl && inputEl.dataset.originalPlaceholder) {
3637
- inputEl.placeholder = inputEl.dataset.originalPlaceholder;
3638
- delete inputEl.dataset.originalPlaceholder;
3639
- }
3640
- }
3641
-
3642
3680
  // --- Scheduled message in chat history ---
3643
3681
 
3644
3682
  var scheduledMsgEl = null;
@@ -3647,15 +3685,15 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3647
3685
  function addScheduledMessageBubble(text, resetsAt) {
3648
3686
  removeScheduledMessageBubble();
3649
3687
  var wrap = document.createElement("div");
3650
- wrap.className = "scheduled-msg-wrap";
3688
+ wrap.className = "msg-user scheduled-msg-wrap";
3651
3689
  wrap.id = "scheduled-msg-bubble";
3652
3690
 
3653
3691
  var bubble = document.createElement("div");
3654
- bubble.className = "scheduled-msg-bubble";
3692
+ bubble.className = "bubble scheduled-msg-bubble";
3655
3693
 
3656
- var textEl = document.createElement("div");
3657
- textEl.className = "scheduled-msg-text";
3694
+ var textEl = document.createElement("span");
3658
3695
  textEl.textContent = text;
3696
+ bubble.appendChild(textEl);
3659
3697
 
3660
3698
  var metaEl = document.createElement("div");
3661
3699
  metaEl.className = "scheduled-msg-meta";
@@ -3672,7 +3710,7 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3672
3710
  var cancelBtn = document.createElement("button");
3673
3711
  cancelBtn.className = "scheduled-msg-cancel";
3674
3712
  cancelBtn.title = "Cancel scheduled message";
3675
- cancelBtn.innerHTML = iconHtml("x");
3713
+ cancelBtn.textContent = "\u00d7";
3676
3714
  cancelBtn.addEventListener("click", function () {
3677
3715
  if (ws && ws.readyState === 1) {
3678
3716
  ws.send(JSON.stringify({ type: "cancel_scheduled_message" }));
@@ -3680,10 +3718,9 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3680
3718
  });
3681
3719
  metaEl.appendChild(cancelBtn);
3682
3720
 
3683
- bubble.appendChild(textEl);
3684
- bubble.appendChild(metaEl);
3685
3721
  wrap.appendChild(bubble);
3686
- messagesEl.appendChild(wrap);
3722
+ wrap.appendChild(metaEl);
3723
+ addToMessages(wrap);
3687
3724
  scheduledMsgEl = wrap;
3688
3725
  scrollToBottom();
3689
3726
 
@@ -3709,8 +3746,6 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3709
3746
  }
3710
3747
  updateCountdown();
3711
3748
  scheduledCountdownTimer = setInterval(updateCountdown, 1000);
3712
-
3713
- refreshIcons(wrap);
3714
3749
  }
3715
3750
 
3716
3751
  function removeScheduledMessageBubble() {
@@ -3724,6 +3759,7 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3724
3759
  }
3725
3760
  }
3726
3761
 
3762
+
3727
3763
  // --- Fast Mode State ---
3728
3764
 
3729
3765
  var fastModeIndicatorEl = null;
@@ -3958,6 +3994,7 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
3958
3994
  if (savedMainWs === this) return;
3959
3995
 
3960
3996
  if (connectTimeoutId) { clearTimeout(connectTimeoutId); connectTimeoutId = null; }
3997
+ closeDmUserPicker();
3961
3998
  setStatus("disconnected");
3962
3999
  processing = false;
3963
4000
  setActivity(null);
@@ -4621,10 +4658,6 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
4621
4658
  if (isNotifAlertEnabled() && !window._pushSubscription) showDoneNotification();
4622
4659
  if (isNotifSoundEnabled()) playDoneSound();
4623
4660
  }
4624
- // Enter schedule mode if rate limited (regardless of exit code)
4625
- if (rateLimitResetsAt && rateLimitResetsAt > Date.now()) {
4626
- enterScheduleMode();
4627
- }
4628
4661
  break;
4629
4662
 
4630
4663
  case "stderr":
@@ -4661,21 +4694,19 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
4661
4694
 
4662
4695
  case "scheduled_message_queued":
4663
4696
  addScheduledMessageBubble(msg.text, msg.resetsAt);
4664
- exitScheduleMode();
4697
+ setScheduleBtnDisabled(true);
4665
4698
  break;
4666
4699
 
4667
4700
  case "scheduled_message_sent":
4668
4701
  removeScheduledMessageBubble();
4702
+ setScheduleBtnDisabled(false);
4669
4703
  processing = true;
4670
4704
  setStatus("processing");
4671
4705
  break;
4672
4706
 
4673
4707
  case "scheduled_message_cancelled":
4674
4708
  removeScheduledMessageBubble();
4675
- // Re-enter schedule mode if still rate limited
4676
- if (rateLimitResetsAt && rateLimitResetsAt > Date.now()) {
4677
- enterScheduleMode();
4678
- }
4709
+ setScheduleBtnDisabled(false);
4679
4710
  break;
4680
4711
 
4681
4712
  case "auto_continue_scheduled":
@@ -4946,11 +4977,12 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
4946
4977
  break;
4947
4978
 
4948
4979
  case "mate_created":
4949
- handleMateCreatedInApp(msg.mate);
4980
+ handleMateCreatedInApp(msg.mate, msg);
4950
4981
  break;
4951
4982
 
4952
4983
  case "mate_deleted":
4953
4984
  cachedMatesList = cachedMatesList.filter(function (m) { return m.id !== msg.mateId; });
4985
+ if (msg.availableBuiltins) cachedAvailableBuiltins = msg.availableBuiltins;
4954
4986
  renderUserStrip(cachedAllUsers, cachedOnlineIds, myUserId, cachedDmFavorites, cachedDmConversations, dmUnread, dmRemovedUsers, cachedMatesList);
4955
4987
  // Clean up background WS for deleted mate
4956
4988
  var delSlug = "mate-" + msg.mateId;
@@ -4993,9 +5025,14 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
4993
5025
 
4994
5026
  case "mate_list":
4995
5027
  cachedMatesList = msg.mates || [];
5028
+ cachedAvailableBuiltins = msg.availableBuiltins || [];
4996
5029
  renderUserStrip(cachedAllUsers, cachedOnlineIds, myUserId, cachedDmFavorites, cachedDmConversations, dmUnread, dmRemovedUsers, cachedMatesList);
4997
5030
  break;
4998
5031
 
5032
+ case "mate_available_builtins":
5033
+ // Handled via mate_list.availableBuiltins now
5034
+ break;
5035
+
4999
5036
  case "mate_error":
5000
5037
  showToast(msg.error || "Mate operation failed", "error");
5001
5038
  break;
@@ -5435,9 +5472,6 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
5435
5472
  getMateName: function () { return dmTargetUser ? (dmTargetUser.displayName || "Mate") : "Mate"; },
5436
5473
  getMateAvatarUrl: function () { return document.body.dataset.mateAvatarUrl || ""; },
5437
5474
  showMatePreThinking: function () { showMatePreThinking(); },
5438
- isScheduleMode: function () { return scheduleModeActive; },
5439
- getRateLimitResetsAt: function () { return rateLimitResetsAt; },
5440
- exitScheduleMode: exitScheduleMode,
5441
5475
  });
5442
5476
 
5443
5477
  // --- @Mention module ---
@@ -5447,6 +5481,7 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
5447
5481
  inputEl: inputEl,
5448
5482
  messagesEl: messagesEl,
5449
5483
  matesList: function () { return cachedMatesList || []; },
5484
+ availableBuiltins: function () { return cachedAvailableBuiltins || []; },
5450
5485
  scrollToBottom: scrollToBottom,
5451
5486
  addUserMessage: addUserMessage,
5452
5487
  addCopyHandler: addCopyHandler,
@@ -5462,6 +5497,7 @@ import { initDebate, handleDebateStarted, handleDebateResumed, handleDebateTurn,
5462
5497
  scrollToBottom: scrollToBottom,
5463
5498
  addCopyHandler: addCopyHandler,
5464
5499
  matesList: function () { return cachedMatesList || []; },
5500
+ availableBuiltins: function () { return cachedAvailableBuiltins || []; },
5465
5501
  currentMateId: function () { return (dmTargetUser && dmTargetUser.isMate) ? dmTargetUser.id : null; },
5466
5502
  });
5467
5503
 
@@ -830,13 +830,17 @@
830
830
  border: 1px solid var(--border);
831
831
  border-radius: 12px;
832
832
  padding: 8px;
833
- width: 220px;
833
+ width: 300px;
834
+ max-height: 70vh;
835
+ overflow-y: auto;
834
836
  box-shadow: 0 8px 24px rgba(var(--shadow-rgb), 0.5);
835
837
  z-index: 10001;
836
838
  animation: ctxMenuAppear 0.15s ease-out;
837
839
  display: flex;
838
840
  flex-direction: column;
839
841
  gap: 4px;
842
+ scrollbar-width: thin;
843
+ scrollbar-color: var(--border) transparent;
840
844
  }
841
845
 
842
846
  .dm-user-picker-search {
@@ -861,11 +865,27 @@
861
865
  }
862
866
 
863
867
  .dm-user-picker-list {
864
- max-height: 200px;
868
+ overflow: visible;
869
+ }
870
+
871
+ .dm-user-picker-list.dm-mates-list {
872
+ max-height: 336px; /* ~7 items at ~48px each */
865
873
  overflow-y: auto;
866
874
  overflow-x: hidden;
867
875
  scrollbar-width: thin;
868
876
  scrollbar-color: var(--border) transparent;
877
+ mask-image: linear-gradient(to bottom, black 80%, transparent 100%);
878
+ -webkit-mask-image: linear-gradient(to bottom, black 80%, transparent 100%);
879
+ }
880
+
881
+ .dm-user-picker-list.dm-mates-list.scrolled-bottom {
882
+ mask-image: linear-gradient(to bottom, transparent 0%, black 35%);
883
+ -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 35%);
884
+ }
885
+
886
+ .dm-user-picker-list.dm-mates-list.no-overflow {
887
+ mask-image: none;
888
+ -webkit-mask-image: none;
869
889
  }
870
890
 
871
891
  .dm-user-picker-list::-webkit-scrollbar {
@@ -919,6 +939,39 @@
919
939
  text-align: center;
920
940
  }
921
941
 
942
+ .dm-picker-fav-btn,
943
+ .dm-picker-del-btn {
944
+ flex-shrink: 0;
945
+ border: none;
946
+ background: none;
947
+ cursor: pointer;
948
+ padding: 4px;
949
+ border-radius: 4px;
950
+ display: flex;
951
+ align-items: center;
952
+ opacity: 0.5;
953
+ transition: opacity 0.15s, color 0.15s;
954
+ }
955
+
956
+ .dm-picker-fav-btn:hover,
957
+ .dm-picker-del-btn:hover {
958
+ opacity: 1;
959
+ }
960
+
961
+ .dm-picker-del-btn:hover {
962
+ color: var(--danger, #e74c3c) !important;
963
+ }
964
+
965
+ .dm-picker-fav-btn svg,
966
+ .dm-picker-del-btn svg {
967
+ width: 16px;
968
+ height: 16px;
969
+ }
970
+
971
+ .dm-picker-fav .dm-picker-fav-btn {
972
+ opacity: 1;
973
+ }
974
+
922
975
  /* --- Worktree folder groups --- */
923
976
  .icon-strip-group {
924
977
  display: flex;
@@ -340,7 +340,8 @@
340
340
  }
341
341
 
342
342
  #attach-file-btn,
343
- #attach-image-btn {
343
+ #attach-image-btn,
344
+ #schedule-btn {
344
345
  width: 36px;
345
346
  height: 36px;
346
347
  border-radius: 50%;
@@ -356,10 +357,12 @@
356
357
  }
357
358
 
358
359
  #attach-file-btn .lucide,
359
- #attach-image-btn .lucide { width: 20px; height: 20px; }
360
+ #attach-image-btn .lucide,
361
+ #schedule-btn .lucide { width: 20px; height: 20px; flex-shrink: 0; }
360
362
 
361
363
  #attach-file-btn:hover,
362
- #attach-image-btn:hover { background: rgba(var(--overlay-rgb), 0.06); color: var(--text); }
364
+ #attach-image-btn:hover,
365
+ #schedule-btn:hover { background: rgba(var(--overlay-rgb), 0.06); color: var(--text); }
363
366
 
364
367
  #send-btn {
365
368
  flex-shrink: 0;
@@ -668,52 +671,69 @@
668
671
  }
669
672
 
670
673
  /* ==========================================================================
671
- Rate Limit Schedule Mode
674
+ Message Scheduling
672
675
  ========================================================================== */
673
676
 
674
- /* Input area styling when rate limited */
675
- #input-row.input-rate-limited {
676
- border-color: var(--warning, #d97706);
677
- box-shadow: 0 0 0 1px color-mix(in srgb, var(--warning, #d97706) 20%, transparent);
677
+ /* Schedule button inline expand (like STT pill) */
678
+ #schedule-btn {
679
+ transition: width 0.2s ease, border-radius 0.2s ease, background 0.15s, color 0.15s, padding 0.2s ease;
680
+ overflow: hidden;
681
+ white-space: nowrap;
682
+ gap: 6px;
683
+ position: relative;
678
684
  }
679
685
 
680
- #input-row.input-rate-limited:focus-within {
681
- border-color: var(--warning, #d97706);
682
- box-shadow: 0 0 0 1px color-mix(in srgb, var(--warning, #d97706) 30%, transparent);
686
+ #schedule-btn.schedule-expanded {
687
+ width: auto;
688
+ padding: 0 10px 0 8px;
689
+ border-radius: 18px;
683
690
  }
684
691
 
685
- /* Scheduled message bubble in chat */
686
- .scheduled-msg-wrap {
687
- display: flex;
688
- justify-content: flex-end;
689
- padding: 4px 16px;
692
+ #schedule-btn.schedule-active {
693
+ color: var(--accent);
694
+ background: var(--accent-bg, rgba(99,102,241,0.15));
695
+ }
696
+
697
+ .schedule-inline-input {
698
+ width: 48px;
699
+ padding: 2px 4px;
700
+ border: 1px solid var(--border);
701
+ border-radius: 6px;
702
+ background: var(--bg);
703
+ color: var(--text);
704
+ font-size: 12px;
705
+ text-align: center;
706
+ outline: none;
707
+ }
708
+ .schedule-inline-input:focus {
709
+ border-color: var(--accent);
690
710
  }
691
711
 
692
- .scheduled-msg-bubble {
693
- max-width: 75%;
694
- padding: 10px 14px;
695
- border-radius: 12px;
696
- background: color-mix(in srgb, var(--warning, #d97706) 8%, var(--bg-alt));
697
- border: 1px dashed color-mix(in srgb, var(--warning, #d97706) 40%, transparent);
712
+ .schedule-delay-label {
713
+ font-size: 12px;
714
+ font-weight: 600;
715
+ color: inherit;
698
716
  }
699
717
 
700
- .scheduled-msg-text {
701
- font-size: 14px;
702
- color: var(--text);
703
- line-height: 1.5;
704
- white-space: pre-wrap;
705
- word-break: break-word;
718
+ /* Scheduled message bubble: accent-tinted user bubble */
719
+ .scheduled-msg-wrap .bubble {
720
+ background: color-mix(in srgb, var(--accent) 18%, var(--user-bubble, var(--bg-alt)));
721
+ border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
706
722
  }
707
723
 
724
+ .scheduled-msg-wrap .msg-user-rewind-btn,
725
+ .scheduled-msg-wrap .msg-actions { display: none !important; }
726
+
708
727
  .scheduled-msg-meta {
709
728
  display: flex;
710
729
  align-items: center;
711
730
  gap: 6px;
712
- margin-top: 8px;
731
+ padding-right: 4px;
713
732
  font-size: 12px;
714
- color: var(--warning, #d97706);
733
+ color: var(--accent);
715
734
  }
716
735
 
736
+ .scheduled-msg-icon svg,
717
737
  .scheduled-msg-icon .lucide {
718
738
  width: 14px;
719
739
  height: 14px;
@@ -398,6 +398,7 @@
398
398
  <button id="attach-file-btn" type="button" aria-label="Attach file" title="Attach file"><i data-lucide="paperclip"></i></button>
399
399
  <button id="attach-image-btn" type="button" aria-label="Attach image" title="Attach image"><i data-lucide="image"></i></button>
400
400
  <button id="stt-btn" type="button" aria-label="Voice input" title="Voice input"><i data-lucide="mic"></i></button>
401
+ <button id="schedule-btn" type="button" aria-label="Schedule message" title="Schedule message"><i data-lucide="clock"></i></button>
401
402
  </div>
402
403
  <div id="input-bottom-right">
403
404
  <div id="config-chip-wrap" class="hidden">
Binary file
Binary file
Binary file