clay-server 2.13.0-beta.6 → 2.13.0-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/public/app.js CHANGED
@@ -71,6 +71,7 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
71
71
  // --- Mate WS (separate connection to mate project) ---
72
72
  var mateWs = null;
73
73
  var mateProjectSlug = null;
74
+ var savedActiveSessionId = null; // main project session ID saved during mate DM
74
75
 
75
76
  // --- Home Hub ---
76
77
  var homeHub = $("home-hub");
@@ -629,8 +630,17 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
629
630
  // Hide terminal button (not relevant for mate)
630
631
  var termBtn = document.getElementById("terminal-toggle-btn");
631
632
  if (termBtn) termBtn.style.display = "none";
632
- // Apply mate color to chat title bar
633
+ // Apply mate color to chat title bar and panels
633
634
  var mateColor = (targetUser.profile && targetUser.profile.avatarColor) || targetUser.avatarColor || "#7c3aed";
635
+ document.body.style.setProperty("--mate-color", mateColor);
636
+ document.body.classList.add("mate-dm-active");
637
+ // Build mate avatar URL for DM bubble injection
638
+ var mp = targetUser.profile || {};
639
+ var mateAvatarUrl = "https://api.dicebear.com/9.x/" + (mp.avatarStyle || targetUser.avatarStyle || "bottts") + "/svg?seed=" + encodeURIComponent(mp.avatarSeed || targetUser.avatarSeed || targetUser.id) + "&size=36";
640
+ var myUser = cachedAllUsers.find(function (u) { return u.id === myUserId; });
641
+ var myAvatarUrl = "https://api.dicebear.com/9.x/" + ((myUser && myUser.avatarStyle) || "thumbs") + "/svg?seed=" + encodeURIComponent((myUser && (myUser.avatarSeed || myUser.username)) || myUserId) + "&size=36";
642
+ document.body.dataset.mateAvatarUrl = mateAvatarUrl;
643
+ document.body.dataset.myAvatarUrl = myAvatarUrl;
634
644
  var titleBarContent = document.querySelector(".title-bar-content");
635
645
  if (titleBarContent) {
636
646
  titleBarContent.style.background = mateColor;
@@ -696,6 +706,7 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
696
706
  if (resizeHandle) resizeHandle.classList.remove("dm-mode");
697
707
  hideMateSidebar();
698
708
  hideKnowledge();
709
+ if (isSchedulerOpen()) closeScheduler();
699
710
  disconnectMateWs();
700
711
  // Restore terminal button
701
712
  var termBtn = document.getElementById("terminal-toggle-btn");
@@ -713,7 +724,14 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
713
724
  var mateTag = dmHeaderBar.querySelector(".dm-header-mate-tag");
714
725
  if (mateTag) mateTag.remove();
715
726
  }
716
- // Reset chat title bar
727
+ // Reset chat title bar and mate color
728
+ document.body.style.removeProperty("--mate-color");
729
+ document.body.classList.remove("mate-dm-active");
730
+ delete document.body.dataset.mateAvatarUrl;
731
+ delete document.body.dataset.myAvatarUrl;
732
+ // Remove injected DM bubble avatars
733
+ var bubbleAvatars = messagesEl.querySelectorAll(".dm-bubble-avatar");
734
+ for (var ba = 0; ba < bubbleAvatars.length; ba++) bubbleAvatars[ba].remove();
717
735
  var titleBarContent = document.querySelector(".title-bar-content");
718
736
  if (titleBarContent) {
719
737
  titleBarContent.style.background = "";
@@ -779,6 +797,7 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
779
797
  mateWs.onopen = function () {
780
798
  // Swap main ws to mateWs so all UI (input, model selector, etc.) routes through mate project
781
799
  savedMainWs = ws;
800
+ savedActiveSessionId = activeSessionId;
782
801
  ws = mateWs;
783
802
  connected = true;
784
803
  };
@@ -858,6 +877,11 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
858
877
  mateWs.close();
859
878
  mateWs = null;
860
879
  }
880
+ // Restore main project's active session ID
881
+ if (savedActiveSessionId) {
882
+ activeSessionId = savedActiveSessionId;
883
+ savedActiveSessionId = null;
884
+ }
861
885
  mateProjectSlug = null;
862
886
  // If main WS was disconnected while in mate DM, reconnect now
863
887
  if (ws && ws.readyState !== 1) {
@@ -1512,6 +1536,13 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
1512
1536
  dmConversations: function () { return cachedDmConversations || []; },
1513
1537
  myUserId: function () { return myUserId; },
1514
1538
  selectSession: function (id) {
1539
+ // Close any open panels before switching
1540
+ if (isSchedulerOpen()) closeScheduler();
1541
+ var stickyPanel = document.getElementById("sticky-notes-panel");
1542
+ if (stickyPanel && !stickyPanel.classList.contains("hidden")) {
1543
+ var stickyBtn = document.getElementById("sticky-notes-sidebar-btn");
1544
+ if (stickyBtn) stickyBtn.click();
1545
+ }
1515
1546
  if (ws && ws.readyState === 1) {
1516
1547
  ws.send(JSON.stringify({ type: "switch_session", id: id }));
1517
1548
  }
@@ -2528,7 +2559,34 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
2528
2559
  }
2529
2560
 
2530
2561
 
2531
- div.appendChild(bubble);
2562
+ // Mate DM: wrap avatar + header + bubble in DM-like layout
2563
+ if (document.body.classList.contains("mate-dm-active") && document.body.dataset.myAvatarUrl) {
2564
+ var avi = document.createElement("img");
2565
+ avi.className = "dm-bubble-avatar dm-bubble-avatar-me";
2566
+ avi.src = document.body.dataset.myAvatarUrl;
2567
+ div.appendChild(avi);
2568
+
2569
+ var contentWrap = document.createElement("div");
2570
+ contentWrap.className = "dm-bubble-content";
2571
+
2572
+ var header = document.createElement("div");
2573
+ header.className = "dm-bubble-header";
2574
+ var myU = cachedAllUsers.find(function (u) { return u.id === myUserId; });
2575
+ var nameSpan = document.createElement("span");
2576
+ nameSpan.className = "dm-bubble-name";
2577
+ nameSpan.textContent = myU ? myU.displayName : "Me";
2578
+ header.appendChild(nameSpan);
2579
+ var timeSpan = document.createElement("span");
2580
+ timeSpan.className = "dm-bubble-time";
2581
+ var nowH = new Date();
2582
+ timeSpan.textContent = String(nowH.getHours()).padStart(2, "0") + ":" + String(nowH.getMinutes()).padStart(2, "0");
2583
+ header.appendChild(timeSpan);
2584
+ contentWrap.appendChild(header);
2585
+ contentWrap.appendChild(bubble);
2586
+ div.appendChild(contentWrap);
2587
+ } else {
2588
+ div.appendChild(bubble);
2589
+ }
2532
2590
 
2533
2591
  // Action bar below bubble (icons visible on hover)
2534
2592
  var actions = document.createElement("div");
@@ -2562,7 +2620,40 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
2562
2620
  currentMsgEl = document.createElement("div");
2563
2621
  currentMsgEl.className = "msg-assistant";
2564
2622
  currentMsgEl.dataset.turn = turnCounter;
2565
- currentMsgEl.innerHTML = '<div class="md-content" dir="auto"></div>';
2623
+ // Inject mate avatar + header for DM bubble style
2624
+ if (document.body.classList.contains("mate-dm-active") && document.body.dataset.mateAvatarUrl) {
2625
+ var avi = document.createElement("img");
2626
+ avi.className = "dm-bubble-avatar dm-bubble-avatar-mate";
2627
+ avi.src = document.body.dataset.mateAvatarUrl;
2628
+ currentMsgEl.appendChild(avi);
2629
+
2630
+ var contentWrap = document.createElement("div");
2631
+ contentWrap.className = "dm-bubble-content";
2632
+
2633
+ var header = document.createElement("div");
2634
+ header.className = "dm-bubble-header";
2635
+ var nameSpan = document.createElement("span");
2636
+ nameSpan.className = "dm-bubble-name";
2637
+ nameSpan.textContent = (dmTargetUser && dmTargetUser.displayName) || "Mate";
2638
+ header.appendChild(nameSpan);
2639
+ var timeSpan = document.createElement("span");
2640
+ timeSpan.className = "dm-bubble-time";
2641
+ var nowA = new Date();
2642
+ timeSpan.textContent = String(nowA.getHours()).padStart(2, "0") + ":" + String(nowA.getMinutes()).padStart(2, "0");
2643
+ header.appendChild(timeSpan);
2644
+ contentWrap.appendChild(header);
2645
+
2646
+ var mdDiv = document.createElement("div");
2647
+ mdDiv.className = "md-content";
2648
+ mdDiv.dir = "auto";
2649
+ contentWrap.appendChild(mdDiv);
2650
+ currentMsgEl.appendChild(contentWrap);
2651
+ } else {
2652
+ var mdDiv = document.createElement("div");
2653
+ mdDiv.className = "md-content";
2654
+ mdDiv.dir = "auto";
2655
+ currentMsgEl.appendChild(mdDiv);
2656
+ }
2566
2657
  addToMessages(currentMsgEl);
2567
2658
  currentFullText = "";
2568
2659
  }
@@ -4434,6 +4525,7 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
4434
4525
  initSTT({
4435
4526
  inputEl: inputEl,
4436
4527
  addSystemMessage: addSystemMessage,
4528
+ scrollToBottom: scrollToBottom,
4437
4529
  });
4438
4530
 
4439
4531
  // --- User profile (Discord-style popover on user island) ---
@@ -4574,6 +4666,8 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
4574
4666
  if (!myPermissions.scheduledTasks) {
4575
4667
  var schBtn = document.getElementById("scheduler-btn");
4576
4668
  if (schBtn) schBtn.style.display = "none";
4669
+ var mateSchBtn = document.getElementById("mate-scheduler-btn");
4670
+ if (mateSchBtn) mateSchBtn.style.display = "none";
4577
4671
  }
4578
4672
  if (!myPermissions.createProject) {
4579
4673
  var addProjBtn = document.getElementById("icon-strip-add");
@@ -798,8 +798,10 @@
798
798
  .mate-knowledge-header {
799
799
  display: flex;
800
800
  align-items: center;
801
- padding: 10px 16px;
801
+ height: 48px;
802
+ padding: 0 16px;
802
803
  flex-shrink: 0;
804
+ border-bottom: 1px solid var(--border-subtle);
803
805
  }
804
806
  .mate-knowledge-title-wrap {
805
807
  display: flex;
@@ -1130,3 +1132,194 @@
1130
1132
  margin-right: 8px;
1131
1133
  vertical-align: middle;
1132
1134
  }
1135
+
1136
+ /* --- Mate color theming for panels --- */
1137
+
1138
+ /* Match panel header heights to sidebar header (48px) */
1139
+ body.mate-dm-active .mate-knowledge-header,
1140
+ body.mate-dm-active .scheduler-top-bar,
1141
+ body.mate-dm-active .notes-archive-header {
1142
+ height: 48px;
1143
+ box-sizing: border-box;
1144
+ border-bottom: 1px solid rgba(255, 255, 255, 0.15);
1145
+ }
1146
+
1147
+ /* Knowledge header */
1148
+ body.mate-dm-active .mate-knowledge-header {
1149
+ background: var(--mate-color);
1150
+ color: #fff;
1151
+ }
1152
+ body.mate-dm-active .mate-knowledge-header .lucide,
1153
+ body.mate-dm-active .mate-knowledge-header h2 {
1154
+ color: #fff;
1155
+ }
1156
+ body.mate-dm-active .mate-knowledge-header-actions button {
1157
+ color: rgba(255, 255, 255, 0.85);
1158
+ }
1159
+ body.mate-dm-active .mate-knowledge-header-actions button:hover {
1160
+ color: #fff;
1161
+ background: rgba(255, 255, 255, 0.15);
1162
+ }
1163
+ body.mate-dm-active .mate-knowledge-count {
1164
+ color: rgba(255, 255, 255, 0.7);
1165
+ }
1166
+
1167
+ /* Scheduler top bar (main header) */
1168
+ body.mate-dm-active .scheduler-top-bar {
1169
+ background: var(--mate-color);
1170
+ color: #fff;
1171
+ }
1172
+ body.mate-dm-active .scheduler-top-title,
1173
+ body.mate-dm-active .scheduler-top-title .lucide {
1174
+ color: #fff;
1175
+ }
1176
+ body.mate-dm-active .scheduler-close-btn {
1177
+ color: rgba(255, 255, 255, 0.85);
1178
+ }
1179
+ body.mate-dm-active .scheduler-close-btn:hover {
1180
+ color: #fff;
1181
+ background: rgba(255, 255, 255, 0.15);
1182
+ }
1183
+ body.mate-dm-active .scheduler-scope-toggle {
1184
+ color: rgba(255, 255, 255, 0.7);
1185
+ }
1186
+ body.mate-dm-active .scheduler-scope-label {
1187
+ color: rgba(255, 255, 255, 0.7);
1188
+ }
1189
+ body.mate-dm-active .scheduler-scope-label[data-side="off"],
1190
+ body.mate-dm-active .scheduler-scope-toggle.active .scheduler-scope-label[data-side="on"] {
1191
+ color: #fff;
1192
+ }
1193
+
1194
+ /* Scheduler: breathing room below top-bar */
1195
+ body.mate-dm-active .scheduler-sidebar,
1196
+ body.mate-dm-active .scheduler-content {
1197
+ padding-top: 12px;
1198
+ }
1199
+
1200
+ /* Sticky Notes header */
1201
+ body.mate-dm-active .notes-archive-header {
1202
+ background: var(--mate-color);
1203
+ color: #fff;
1204
+ }
1205
+ body.mate-dm-active .notes-archive-header .lucide,
1206
+ body.mate-dm-active .notes-archive-header h2 {
1207
+ color: #fff;
1208
+ }
1209
+ body.mate-dm-active .notes-archive-count {
1210
+ color: rgba(255, 255, 255, 0.7);
1211
+ }
1212
+ body.mate-dm-active .notes-archive-header button {
1213
+ color: rgba(255, 255, 255, 0.85);
1214
+ }
1215
+ body.mate-dm-active .notes-archive-header button:hover {
1216
+ color: #fff;
1217
+ background: rgba(255, 255, 255, 0.15);
1218
+ }
1219
+
1220
+ /* ==========================================================================
1221
+ Mate DM: Chat bubble style (messenger feel)
1222
+ ========================================================================== */
1223
+
1224
+ /* --- Avatar (injected by JS into .msg-user / .msg-assistant) --- */
1225
+ .dm-bubble-avatar {
1226
+ width: 36px;
1227
+ height: 36px;
1228
+ border-radius: 6px;
1229
+ flex-shrink: 0;
1230
+ display: none;
1231
+ object-fit: cover;
1232
+ margin-top: 2px;
1233
+ }
1234
+ body.mate-dm-active .dm-bubble-avatar {
1235
+ display: block;
1236
+ }
1237
+
1238
+ /* --- DM bubble header (name + time) --- */
1239
+ .dm-bubble-content {
1240
+ flex: 1;
1241
+ min-width: 0;
1242
+ }
1243
+ .dm-bubble-header {
1244
+ display: flex;
1245
+ align-items: baseline;
1246
+ gap: 8px;
1247
+ }
1248
+ .dm-bubble-name {
1249
+ font-weight: 700;
1250
+ font-size: 15px;
1251
+ color: var(--text);
1252
+ }
1253
+ .dm-bubble-time {
1254
+ font-size: 12px;
1255
+ color: var(--text-dimmer);
1256
+ }
1257
+
1258
+ /* --- Shared: Slack-style flat layout for both user & assistant --- */
1259
+ body.mate-dm-active .msg-user,
1260
+ body.mate-dm-active .msg-assistant {
1261
+ display: flex;
1262
+ flex-direction: row;
1263
+ align-items: flex-start;
1264
+ gap: 8px;
1265
+ max-width: 100%;
1266
+ padding: 4px 16px;
1267
+ margin: 0;
1268
+ border-radius: 0;
1269
+ }
1270
+ body.mate-dm-active .msg-user:hover,
1271
+ body.mate-dm-active .msg-assistant:hover {
1272
+ background: var(--bg-alt);
1273
+ }
1274
+
1275
+ /* --- User messages --- */
1276
+ body.mate-dm-active .msg-user {
1277
+ justify-content: flex-start; /* left-aligned like DM */
1278
+ }
1279
+ body.mate-dm-active .msg-user .dm-bubble-avatar-me {
1280
+ order: -1; /* avatar first (left) */
1281
+ }
1282
+ body.mate-dm-active .msg-user .bubble {
1283
+ background: none;
1284
+ border-radius: 0;
1285
+ padding: 0;
1286
+ max-width: 100%;
1287
+ font-size: 15px;
1288
+ line-height: 1.46;
1289
+ white-space: pre-wrap;
1290
+ word-wrap: break-word;
1291
+ }
1292
+ body.mate-dm-active .msg-user .msg-actions {
1293
+ display: none;
1294
+ }
1295
+
1296
+ /* --- Assistant messages --- */
1297
+ body.mate-dm-active .msg-assistant .dm-bubble-content {
1298
+ flex: 1;
1299
+ min-width: 0;
1300
+ }
1301
+ body.mate-dm-active .msg-assistant .md-content {
1302
+ background: none;
1303
+ border-radius: 0;
1304
+ padding: 0;
1305
+ }
1306
+
1307
+ /* Hide turn meta in mate DM */
1308
+ body.mate-dm-active .turn-meta {
1309
+ display: none;
1310
+ }
1311
+
1312
+ /* --- Interstitial elements: indent to align with message content (16px pad + 36px avatar + 8px gap = 60px) --- */
1313
+ body.mate-dm-active .thinking-item,
1314
+ body.mate-dm-active .tool-item,
1315
+ body.mate-dm-active .tool-group,
1316
+ body.mate-dm-active .plan-card,
1317
+ body.mate-dm-active .permission-container,
1318
+ body.mate-dm-active .ask-user-container,
1319
+ body.mate-dm-active .subagent-log,
1320
+ body.mate-dm-active .conflict-msg,
1321
+ body.mate-dm-active .context-overflow-msg,
1322
+ body.mate-dm-active .sys-msg,
1323
+ body.mate-dm-active .activity-inline {
1324
+ padding-left: 60px;
1325
+ }
@@ -18,8 +18,10 @@
18
18
  .scheduler-top-bar {
19
19
  display: flex;
20
20
  align-items: center;
21
- padding: 10px 16px;
21
+ height: 48px;
22
+ padding: 0 16px;
22
23
  flex-shrink: 0;
24
+ border-bottom: 1px solid var(--border-subtle);
23
25
  }
24
26
  .scheduler-top-title {
25
27
  display: flex;
@@ -96,7 +98,7 @@
96
98
  display: flex;
97
99
  flex-direction: row;
98
100
  gap: 10px;
99
- padding: 0 10px 10px;
101
+ padding: 12px 10px 10px;
100
102
  min-height: 0;
101
103
  overflow: hidden;
102
104
  }
@@ -531,8 +531,10 @@
531
531
  .notes-archive-header {
532
532
  display: flex;
533
533
  align-items: center;
534
- padding: 10px 16px;
534
+ height: 48px;
535
+ padding: 0 16px;
535
536
  flex-shrink: 0;
537
+ border-bottom: 1px solid var(--border-subtle);
536
538
  }
537
539
 
538
540
  .notes-archive-title-wrap {
@@ -203,6 +203,7 @@
203
203
  <button id="mate-knowledge-btn"><i data-lucide="book-open"></i> <span>Knowledge</span><span id="mate-knowledge-count" class="sidebar-badge hidden"></span></button>
204
204
  <button id="mate-sticky-notes-btn"><i data-lucide="sticky-note"></i> <span>Sticky Notes</span></button>
205
205
  <button id="mate-skills-btn"><i data-lucide="puzzle"></i> <span>Skills</span></button>
206
+ <button id="mate-scheduler-btn"><i data-lucide="calendar-clock"></i> <span>Scheduled Tasks</span></button>
206
207
  </div>
207
208
  <div class="mate-sidebar-sessions-header">
208
209
  <span>Conversations</span>
@@ -1,6 +1,7 @@
1
1
  import { escapeHtml } from './utils.js';
2
2
  import { iconHtml, refreshIcons } from './icons.js';
3
3
  import { hideKnowledge } from './mate-knowledge.js';
4
+ import { isSchedulerOpen, closeScheduler } from './scheduler.js';
4
5
 
5
6
  var getMateWs = null;
6
7
  var currentMateId = null;
@@ -58,6 +59,14 @@ export function initMateSidebar(mateWsGetter) {
58
59
  if (origBtn) origBtn.click();
59
60
  });
60
61
  }
62
+ var mateSchedulerBtn = document.getElementById("mate-scheduler-btn");
63
+ if (mateSchedulerBtn) {
64
+ mateSchedulerBtn.addEventListener("click", function () {
65
+ hideKnowledge();
66
+ var origBtn = document.getElementById("scheduler-btn");
67
+ if (origBtn) origBtn.click();
68
+ });
69
+ }
61
70
  }
62
71
 
63
72
  export function showMateSidebar(mateId, mateData) {
@@ -293,6 +302,14 @@ function renderMateSessionItem(s) {
293
302
 
294
303
  el.addEventListener("click", (function (id) {
295
304
  return function () {
305
+ // Close any open panels
306
+ hideKnowledge();
307
+ if (isSchedulerOpen()) closeScheduler();
308
+ var stickyBtn = document.getElementById("sticky-notes-sidebar-btn");
309
+ var stickyPanel = document.getElementById("sticky-notes-panel");
310
+ if (stickyPanel && !stickyPanel.classList.contains("hidden")) {
311
+ if (stickyBtn) stickyBtn.click();
312
+ }
296
313
  var ws = getMateWs ? getMateWs() : null;
297
314
  if (ws && ws.readyState === 1) {
298
315
  ws.send(JSON.stringify({ type: "switch_session", id: id }));
@@ -182,6 +182,7 @@ function startRecording() {
182
182
 
183
183
  ctx.inputEl.value = text;
184
184
  autoResize();
185
+ if (ctx.scrollToBottom) ctx.scrollToBottom();
185
186
  };
186
187
 
187
188
  recognition.onerror = function(e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.13.0-beta.6",
3
+ "version": "2.13.0-beta.8",
4
4
  "description": "Web UI for Claude Code. Any device. Push notifications.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",