clay-server 2.14.0-beta.9 → 2.14.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.
@@ -2,6 +2,7 @@ import { escapeHtml } from './utils.js';
2
2
  import { iconHtml, refreshIcons } from './icons.js';
3
3
  import { hideKnowledge } from './mate-knowledge.js';
4
4
  import { isSchedulerOpen, closeScheduler } from './scheduler.js';
5
+ import { openSearch as openSessionSearch } from './session-search.js';
5
6
 
6
7
  var getMateWs = null;
7
8
  var currentMateId = null;
@@ -14,6 +15,15 @@ var avatarEl = null;
14
15
  var nameEl = null;
15
16
  var newSessionBtn = null;
16
17
 
18
+ // Search state
19
+ var searchBtn = null;
20
+ var searchContainer = null;
21
+ var searchInput = null;
22
+ var searchClearBtn = null;
23
+ var searchQuery = "";
24
+ var searchMatchIds = null;
25
+ var searchDebounce = null;
26
+
17
27
  export function initMateSidebar(mateWsGetter) {
18
28
  getMateWs = mateWsGetter;
19
29
  columnEl = document.getElementById("mate-sidebar-column");
@@ -31,6 +41,49 @@ export function initMateSidebar(mateWsGetter) {
31
41
  });
32
42
  }
33
43
 
44
+ // Session search
45
+ searchBtn = document.getElementById("mate-search-session-btn");
46
+ searchContainer = document.getElementById("mate-session-search");
47
+ searchInput = document.getElementById("mate-session-search-input");
48
+ searchClearBtn = document.getElementById("mate-session-search-clear");
49
+
50
+ if (searchBtn) {
51
+ searchBtn.addEventListener("click", function () {
52
+ if (searchContainer && searchContainer.classList.contains("hidden")) {
53
+ openSearch();
54
+ } else {
55
+ closeSearch();
56
+ }
57
+ });
58
+ }
59
+ if (searchClearBtn) {
60
+ searchClearBtn.addEventListener("click", closeSearch);
61
+ }
62
+ if (searchInput) {
63
+ searchInput.addEventListener("input", function () {
64
+ var q = searchInput.value.trim();
65
+ searchQuery = q;
66
+ if (searchDebounce) clearTimeout(searchDebounce);
67
+ if (!q) {
68
+ searchMatchIds = null;
69
+ renderMateSessionList(null);
70
+ return;
71
+ }
72
+ searchDebounce = setTimeout(function () {
73
+ var ws = getMateWs ? getMateWs() : null;
74
+ if (ws && ws.readyState === 1) {
75
+ ws.send(JSON.stringify({ type: "search_sessions", query: q }));
76
+ }
77
+ }, 200);
78
+ });
79
+ searchInput.addEventListener("keydown", function (e) {
80
+ e.stopPropagation();
81
+ if (e.key === "Escape") closeSearch();
82
+ });
83
+ searchInput.addEventListener("keyup", function (e) { e.stopPropagation(); });
84
+ searchInput.addEventListener("keypress", function (e) { e.stopPropagation(); });
85
+ }
86
+
34
87
  // Name hover: show seed data tooltip
35
88
  if (nameEl) {
36
89
  nameEl.addEventListener("mouseenter", function () {
@@ -257,8 +310,38 @@ export function hideMateSidebar() {
257
310
  if (columnEl) columnEl.classList.add("hidden");
258
311
  }
259
312
 
313
+ function openSearch() {
314
+ if (searchContainer) searchContainer.classList.remove("hidden");
315
+ if (searchBtn) searchBtn.classList.add("active");
316
+ if (searchInput) { searchInput.value = ""; searchInput.focus(); }
317
+ searchQuery = "";
318
+ searchMatchIds = null;
319
+ }
320
+
321
+ function closeSearch() {
322
+ if (searchContainer) searchContainer.classList.add("hidden");
323
+ if (searchBtn) searchBtn.classList.remove("active");
324
+ if (searchInput) searchInput.value = "";
325
+ searchQuery = "";
326
+ searchMatchIds = null;
327
+ if (searchDebounce) { clearTimeout(searchDebounce); searchDebounce = null; }
328
+ renderMateSessionList(null);
329
+ }
330
+
331
+ export function handleMateSearchResults(msg) {
332
+ if (msg.query !== searchQuery) return;
333
+ var ids = new Set();
334
+ if (msg.results) {
335
+ for (var i = 0; i < msg.results.length; i++) {
336
+ ids.add(msg.results[i].id);
337
+ }
338
+ }
339
+ searchMatchIds = ids;
340
+ renderMateSessionList(null);
341
+ }
342
+
260
343
  export function renderMateSessionList(sessions) {
261
- cachedSessions = sessions || [];
344
+ if (sessions) cachedSessions = sessions;
262
345
  if (!listEl) return;
263
346
  listEl.innerHTML = "";
264
347
 
@@ -272,7 +355,16 @@ export function renderMateSessionList(sessions) {
272
355
 
273
356
  for (var i = 0; i < cachedSessions.length; i++) {
274
357
  var s = cachedSessions[i];
275
- listEl.appendChild(renderMateSessionItem(s));
358
+ var el = renderMateSessionItem(s);
359
+ // Apply search filter
360
+ if (searchMatchIds !== null) {
361
+ if (searchMatchIds.has(s.id)) {
362
+ el.classList.add("search-match");
363
+ } else {
364
+ el.classList.add("search-dimmed");
365
+ }
366
+ }
367
+ listEl.appendChild(el);
276
368
  }
277
369
  refreshIcons();
278
370
  }
@@ -310,6 +402,7 @@ function renderMateSessionItem(s) {
310
402
  if (stickyPanel && !stickyPanel.classList.contains("hidden")) {
311
403
  if (stickyBtn) stickyBtn.click();
312
404
  }
405
+ var pendingQuery = searchQuery || "";
313
406
  var ws = getMateWs ? getMateWs() : null;
314
407
  if (ws && ws.readyState === 1) {
315
408
  ws.send(JSON.stringify({ type: "switch_session", id: id }));
@@ -320,6 +413,11 @@ function renderMateSessionItem(s) {
320
413
  items[j].classList.remove("active");
321
414
  }
322
415
  el.classList.add("active");
416
+ // Open in-session search with the sidebar search query
417
+ if (pendingQuery) {
418
+ closeSearch();
419
+ setTimeout(function () { openSessionSearch(pendingQuery); }, 400);
420
+ }
323
421
  };
324
422
  })(s.id));
325
423
 
@@ -6,6 +6,7 @@ import { parseEmojis } from './markdown.js';
6
6
  import { showMateProfilePopover } from './profile.js';
7
7
  import { closeArchive } from './sticky-notes.js';
8
8
  import { closeScheduler } from './scheduler.js';
9
+ import { openSearch as openSessionSearch } from './session-search.js';
9
10
 
10
11
  var ctx;
11
12
 
@@ -462,9 +463,14 @@ function renderSessionItem(s) {
462
463
  el.addEventListener("click", (function (id) {
463
464
  return function () {
464
465
  if (ctx.ws && ctx.connected) {
466
+ var pendingQuery = searchQuery || "";
465
467
  ctx.ws.send(JSON.stringify({ type: "switch_session", id: id }));
466
468
  dismissOverlayPanels();
467
469
  closeSidebar();
470
+ if (pendingQuery) {
471
+ closeSearch();
472
+ setTimeout(function () { openSessionSearch(pendingQuery); }, 400);
473
+ }
468
474
  }
469
475
  };
470
476
  })(s.id));
@@ -116,10 +116,15 @@ function updateToolGroupHeader(group) {
116
116
  var header = group.el.querySelector(".tool-group-header");
117
117
  var isMate = group.el.classList.contains("mate-tool-group");
118
118
  if (isMate) {
119
- // Mate DM: always show header and collapse
120
- header.style.display = "";
121
- if (!group.userToggled) {
122
- group.el.classList.add("collapsed");
119
+ // Mate DM: hide entire group when no tools, show collapsed when tools exist
120
+ if (group.toolCount === 0) {
121
+ group.el.style.display = "none";
122
+ } else {
123
+ group.el.style.display = "";
124
+ header.style.display = "";
125
+ if (!group.userToggled) {
126
+ group.el.classList.add("collapsed");
127
+ }
123
128
  }
124
129
  } else if (group.toolCount >= 2) {
125
130
  header.style.display = "";
@@ -189,17 +194,27 @@ export function renderAskUserQuestion(toolId, input) {
189
194
  container.className = "ask-user-container";
190
195
  container.dataset.toolId = toolId;
191
196
 
192
- // Mate DM: inject avatar + name header into ask-user container
197
+ // Mate DM: wrap in avatar + content layout (same as msg-assistant)
198
+ var mateContentWrap = null;
193
199
  if (ctx.isMateDm && ctx.isMateDm()) {
200
+ container.classList.add("mate-ask-user");
194
201
  var mateName = ctx.getMateName();
195
202
  var mateAvatar = ctx.getMateAvatarUrl();
196
- var mateHeader = document.createElement("div");
197
- mateHeader.className = "dm-bubble-header ask-user-mate-header";
198
- mateHeader.innerHTML =
199
- '<img class="dm-bubble-avatar" src="' + escapeHtml(mateAvatar) + '" alt="" style="display:block;width:28px;height:28px;border-radius:6px">' +
203
+
204
+ var avi = document.createElement("img");
205
+ avi.className = "dm-bubble-avatar";
206
+ avi.src = mateAvatar;
207
+ container.appendChild(avi);
208
+
209
+ mateContentWrap = document.createElement("div");
210
+ mateContentWrap.className = "dm-bubble-content";
211
+
212
+ var headerEl = document.createElement("div");
213
+ headerEl.className = "dm-bubble-header";
214
+ headerEl.innerHTML =
200
215
  '<span class="dm-bubble-name">' + escapeHtml(mateName) + '</span>' +
201
216
  '<span class="dm-bubble-time">' + String(new Date().getHours()).padStart(2, "0") + ":" + String(new Date().getMinutes()).padStart(2, "0") + '</span>';
202
- container.appendChild(mateHeader);
217
+ mateContentWrap.appendChild(headerEl);
203
218
  }
204
219
 
205
220
  var answers = {};
@@ -320,6 +335,20 @@ export function renderAskUserQuestion(toolId, input) {
320
335
  });
321
336
  container.appendChild(skipBtn);
322
337
 
338
+ // Mate DM: move all content into the bubble content wrapper
339
+ if (mateContentWrap) {
340
+ var children = [];
341
+ for (var ci = 0; ci < container.childNodes.length; ci++) {
342
+ if (container.childNodes[ci] !== container.querySelector(".dm-bubble-avatar")) {
343
+ children.push(container.childNodes[ci]);
344
+ }
345
+ }
346
+ for (var cj = 0; cj < children.length; cj++) {
347
+ mateContentWrap.appendChild(children[cj]);
348
+ }
349
+ container.appendChild(mateContentWrap);
350
+ }
351
+
323
352
  ctx.addToMessages(container);
324
353
  disableMainInput();
325
354
  ctx.setActivity(null);
@@ -639,72 +668,71 @@ function sendPlanResponse(container, requestId, decision, feedback) {
639
668
  delete pendingPermissions[requestId];
640
669
  }
641
670
 
642
- function matePermissionVerb(toolName) {
643
- switch (toolName) {
644
- case "Write": return "write to";
645
- case "Edit": return "edit";
646
- case "Read": return "read";
647
- case "Bash": return "run a command on";
648
- case "Grep": return "search";
649
- case "Glob": return "search for files in";
650
- case "WebFetch": return "fetch";
651
- case "WebSearch": return "search the web for";
652
- default: return "use " + toolName + " on";
653
- }
654
- }
671
+ function matePermissionInfo(toolName, toolInput) {
672
+ var input = toolInput && typeof toolInput === "object" ? toolInput : {};
673
+ var verb = "use " + toolName;
674
+ var target = "";
655
675
 
656
- function matePermissionTarget(toolName, toolInput) {
657
- if (!toolInput || typeof toolInput !== "object") return "";
658
676
  switch (toolName) {
659
- case "Write": case "Edit": case "Read": return shortPath(toolInput.file_path);
660
- case "Bash": return toolInput.description || (toolInput.command || "").substring(0, 60);
661
- case "Grep": return toolInput.pattern || "";
662
- case "Glob": return toolInput.pattern || "";
663
- case "WebFetch": return toolInput.url || "";
664
- case "WebSearch": return toolInput.query || "";
665
- default: return "";
666
- }
677
+ case "Write": verb = "write to"; target = shortPath(input.file_path); break;
678
+ case "Edit": verb = "edit"; target = shortPath(input.file_path); break;
679
+ case "Read": verb = "read"; target = shortPath(input.file_path); break;
680
+ case "Bash": verb = "run"; target = input.description || (input.command || "").substring(0, 80); break;
681
+ case "Grep": verb = "search"; target = input.pattern || ""; break;
682
+ case "Glob": verb = "search for files in"; target = input.pattern || ""; break;
683
+ case "WebFetch": verb = "fetch"; target = input.url || ""; break;
684
+ case "WebSearch": verb = "search the web for"; target = input.query || ""; break;
685
+ }
686
+ return { verb: verb, target: target };
667
687
  }
668
688
 
669
689
  function renderMatePermission(requestId, toolName, toolInput) {
670
690
  var mateName = ctx.getMateName();
671
691
  var mateAvatar = ctx.getMateAvatarUrl();
672
- var verb = matePermissionVerb(toolName);
673
- var target = matePermissionTarget(toolName, toolInput);
692
+ var info = matePermissionInfo(toolName, toolInput);
693
+ var askMsg = "Can I " + info.verb + (info.target ? " " + info.target : "") + "?";
674
694
 
675
695
  var container = document.createElement("div");
676
696
  container.className = "permission-container mate-permission";
677
697
  container.dataset.requestId = requestId;
678
698
 
679
- // Chat bubble: avatar + name + time
699
+ // Avatar (left column)
700
+ var avi = document.createElement("img");
701
+ avi.className = "dm-bubble-avatar dm-bubble-avatar-mate";
702
+ avi.src = mateAvatar;
703
+ avi.alt = "";
704
+ container.appendChild(avi);
705
+
706
+ // Content (right column)
707
+ var content = document.createElement("div");
708
+ content.className = "dm-bubble-content";
709
+
710
+ // Name + time header
680
711
  var headerRow = document.createElement("div");
681
712
  headerRow.className = "dm-bubble-header";
682
- headerRow.style.cssText = "display:flex;align-items:center;gap:8px;margin-bottom:6px";
683
713
  headerRow.innerHTML =
684
- '<img class="dm-bubble-avatar" src="' + escapeHtml(mateAvatar) + '" alt="" style="display:block;width:28px;height:28px;border-radius:6px">' +
685
714
  '<span class="dm-bubble-name">' + escapeHtml(mateName) + '</span>' +
686
715
  '<span class="dm-bubble-time">' + String(new Date().getHours()).padStart(2, "0") + ":" + String(new Date().getMinutes()).padStart(2, "0") + '</span>';
687
- container.appendChild(headerRow);
716
+ content.appendChild(headerRow);
688
717
 
689
- // Conversational ask text
690
- var askText = document.createElement("div");
691
- askText.className = "mate-permission-ask";
692
- var askMsg = "Can I " + verb + (target ? " " : "") + (target ? target : "") + "?";
693
- askText.textContent = askMsg;
694
- container.appendChild(askText);
718
+ // Ask text
719
+ var askEl = document.createElement("div");
720
+ askEl.className = "mate-perm-ask";
721
+ askEl.textContent = askMsg;
722
+ content.appendChild(askEl);
695
723
 
696
- // Collapsible details (subtle)
724
+ // Collapsible details
697
725
  var details = document.createElement("details");
698
- details.className = "mate-permission-details";
699
- var detailsSummary = document.createElement("summary");
700
- detailsSummary.textContent = "Details";
701
- var detailsPre = document.createElement("pre");
702
- detailsPre.textContent = JSON.stringify(toolInput, null, 2);
703
- details.appendChild(detailsSummary);
704
- details.appendChild(detailsPre);
705
- container.appendChild(details);
706
-
707
- // Quick reply buttons (chat-style)
726
+ details.className = "mate-perm-details";
727
+ var summary = document.createElement("summary");
728
+ summary.textContent = "Details";
729
+ var pre = document.createElement("pre");
730
+ pre.textContent = JSON.stringify(toolInput, null, 2);
731
+ details.appendChild(summary);
732
+ details.appendChild(pre);
733
+ content.appendChild(details);
734
+
735
+ // Buttons
708
736
  var actions = document.createElement("div");
709
737
  actions.className = "permission-actions mate-permission-actions";
710
738
 
@@ -717,7 +745,7 @@ function renderMatePermission(requestId, toolName, toolInput) {
717
745
 
718
746
  var alwaysBtn = document.createElement("button");
719
747
  alwaysBtn.className = "mate-permission-reply mate-permission-always";
720
- alwaysBtn.textContent = "Always allow this";
748
+ alwaysBtn.textContent = "Always allow";
721
749
  alwaysBtn.addEventListener("click", function () {
722
750
  sendPermissionResponse(container, requestId, "allow_always");
723
751
  });
@@ -732,7 +760,9 @@ function renderMatePermission(requestId, toolName, toolInput) {
732
760
  actions.appendChild(allowBtn);
733
761
  actions.appendChild(alwaysBtn);
734
762
  actions.appendChild(denyBtn);
735
- container.appendChild(actions);
763
+ content.appendChild(actions);
764
+
765
+ container.appendChild(content);
736
766
 
737
767
  ctx.addToMessages(container);
738
768
  pendingPermissions[requestId] = container;
@@ -1323,20 +1353,20 @@ export function startThinking() {
1323
1353
  var mateAvatar = ctx.getMateAvatarUrl();
1324
1354
  el.classList.add("mate-thinking");
1325
1355
  el.innerHTML =
1356
+ '<img class="dm-bubble-avatar dm-bubble-avatar-mate" src="' + escapeHtml(mateAvatar) + '" alt="">' +
1357
+ '<div class="dm-bubble-content">' +
1326
1358
  '<div class="mate-thinking-row">' +
1327
- '<img class="mate-thinking-avatar" src="' + escapeHtml(mateAvatar) + '" alt="">' +
1328
- '<div class="mate-thinking-body">' +
1329
- '<span class="mate-thinking-name">' + escapeHtml(mateName) + '</span>' +
1359
+ '<span class="dm-bubble-name">' + escapeHtml(mateName) + '</span>' +
1330
1360
  '<span class="mate-thinking-dots"><span></span><span></span><span></span></span>' +
1331
1361
  '</div>' +
1332
- '</div>' +
1333
1362
  '<div class="thinking-header" style="display:none">' +
1334
1363
  '<span class="thinking-chevron">' + iconHtml("chevron-right") + '</span>' +
1335
1364
  '<span class="thinking-label">Thinking</span>' +
1336
1365
  '<span class="thinking-duration"></span>' +
1337
1366
  '<span class="thinking-spinner">' + iconHtml("loader", "icon-spin") + '</span>' +
1338
1367
  '</div>' +
1339
- '<div class="thinking-content"></div>';
1368
+ '<div class="thinking-content"></div>' +
1369
+ '</div>';
1340
1370
  } else {
1341
1371
  el.innerHTML =
1342
1372
  '<div class="thinking-header">' +
@@ -1405,9 +1435,11 @@ export function createToolItem(id, name) {
1405
1435
  toolGroupCounter++;
1406
1436
  var groupEl = document.createElement("div");
1407
1437
  groupEl.className = "tool-group";
1408
- if (ctx.isMateDm()) groupEl.classList.add("mate-tool-group");
1438
+ var isMateToolGroup = ctx.isMateDm();
1439
+ if (isMateToolGroup) groupEl.classList.add("mate-tool-group");
1409
1440
  groupEl.dataset.groupId = "g" + toolGroupCounter;
1410
- groupEl.innerHTML =
1441
+
1442
+ var toolGroupInner =
1411
1443
  '<div class="tool-group-header" style="display:none">' +
1412
1444
  '<span class="tool-group-chevron">' + iconHtml("chevron-right") + '</span>' +
1413
1445
  '<span class="tool-group-bullet"></span>' +
@@ -1416,6 +1448,15 @@ export function createToolItem(id, name) {
1416
1448
  '</div>' +
1417
1449
  '<div class="tool-group-items"></div>';
1418
1450
 
1451
+ if (isMateToolGroup) {
1452
+ var mateAvatar = ctx.getMateAvatarUrl();
1453
+ groupEl.innerHTML =
1454
+ '<img class="dm-bubble-avatar dm-bubble-avatar-mate" src="' + escapeHtml(mateAvatar) + '" alt="">' +
1455
+ '<div class="dm-bubble-content">' + toolGroupInner + '</div>';
1456
+ } else {
1457
+ groupEl.innerHTML = toolGroupInner;
1458
+ }
1459
+
1419
1460
  groupEl.querySelector(".tool-group-header").addEventListener("click", function () {
1420
1461
  groupEl.classList.toggle("collapsed");
1421
1462
  if (currentToolGroup) currentToolGroup.userToggled = true;
package/lib/sdk-bridge.js CHANGED
@@ -1675,13 +1675,10 @@ function createSDKBridge(opts) {
1675
1675
  send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [] });
1676
1676
  return;
1677
1677
  }
1678
- try {
1679
- await session.queryInstance.setEffort(effort);
1680
- sm.currentEffort = effort;
1681
- send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [] });
1682
- } catch (e) {
1683
- send({ type: "error", text: "Failed to set effort: " + (e.message || e) });
1684
- }
1678
+ // SDK Query interface has no setEffort method.
1679
+ // Store the effort level — it will be applied via queryOptions.effort on the next query.
1680
+ sm.currentEffort = effort;
1681
+ send({ type: "config_state", model: sm.currentModel || "", mode: sm.currentPermissionMode || "default", effort: sm.currentEffort, betas: sm.currentBetas || [] });
1685
1682
  }
1686
1683
 
1687
1684
  async function setPermissionMode(session, mode) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.14.0-beta.9",
3
+ "version": "2.14.0",
4
4
  "description": "Web UI for Claude Code. Any device. Push notifications.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",