clay-server 2.14.0-beta.8 → 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);
@@ -398,25 +427,22 @@ export function renderPermissionRequest(requestId, toolName, toolInput, decision
398
427
  return;
399
428
  }
400
429
 
430
+ // Mate DM: render as conversational chat bubble instead of formal dialog
431
+ if (ctx.isMateDm && ctx.isMateDm()) {
432
+ renderMatePermission(requestId, toolName, toolInput);
433
+ return;
434
+ }
435
+
401
436
  var container = document.createElement("div");
402
437
  container.className = "permission-container";
403
- if (ctx.isMateDm()) container.classList.add("mate-permission");
404
438
  container.dataset.requestId = requestId;
405
439
 
406
440
  // Header
407
441
  var header = document.createElement("div");
408
442
  header.className = "permission-header";
409
- if (ctx.isMateDm()) {
410
- var mateName = ctx.getMateName();
411
- var mateAvatar = ctx.getMateAvatarUrl();
412
- header.innerHTML =
413
- '<img class="mate-permission-avatar" src="' + escapeHtml(mateAvatar) + '" alt="">' +
414
- '<span class="permission-title">' + escapeHtml(mateName) + ' wants to do something</span>';
415
- } else {
416
- header.innerHTML =
417
- '<span class="permission-icon">' + iconHtml("shield") + '</span>' +
418
- '<span class="permission-title">Permission Required</span>';
419
- }
443
+ header.innerHTML =
444
+ '<span class="permission-icon">' + iconHtml("shield") + '</span>' +
445
+ '<span class="permission-title">Permission Required</span>';
420
446
 
421
447
  // Body
422
448
  var body = document.createElement("div");
@@ -642,6 +668,109 @@ function sendPlanResponse(container, requestId, decision, feedback) {
642
668
  delete pendingPermissions[requestId];
643
669
  }
644
670
 
671
+ function matePermissionInfo(toolName, toolInput) {
672
+ var input = toolInput && typeof toolInput === "object" ? toolInput : {};
673
+ var verb = "use " + toolName;
674
+ var target = "";
675
+
676
+ switch (toolName) {
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 };
687
+ }
688
+
689
+ function renderMatePermission(requestId, toolName, toolInput) {
690
+ var mateName = ctx.getMateName();
691
+ var mateAvatar = ctx.getMateAvatarUrl();
692
+ var info = matePermissionInfo(toolName, toolInput);
693
+ var askMsg = "Can I " + info.verb + (info.target ? " " + info.target : "") + "?";
694
+
695
+ var container = document.createElement("div");
696
+ container.className = "permission-container mate-permission";
697
+ container.dataset.requestId = requestId;
698
+
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
711
+ var headerRow = document.createElement("div");
712
+ headerRow.className = "dm-bubble-header";
713
+ headerRow.innerHTML =
714
+ '<span class="dm-bubble-name">' + escapeHtml(mateName) + '</span>' +
715
+ '<span class="dm-bubble-time">' + String(new Date().getHours()).padStart(2, "0") + ":" + String(new Date().getMinutes()).padStart(2, "0") + '</span>';
716
+ content.appendChild(headerRow);
717
+
718
+ // Ask text
719
+ var askEl = document.createElement("div");
720
+ askEl.className = "mate-perm-ask";
721
+ askEl.textContent = askMsg;
722
+ content.appendChild(askEl);
723
+
724
+ // Collapsible details
725
+ var details = document.createElement("details");
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
736
+ var actions = document.createElement("div");
737
+ actions.className = "permission-actions mate-permission-actions";
738
+
739
+ var allowBtn = document.createElement("button");
740
+ allowBtn.className = "mate-permission-reply mate-permission-allow";
741
+ allowBtn.textContent = "Sure";
742
+ allowBtn.addEventListener("click", function () {
743
+ sendPermissionResponse(container, requestId, "allow");
744
+ });
745
+
746
+ var alwaysBtn = document.createElement("button");
747
+ alwaysBtn.className = "mate-permission-reply mate-permission-always";
748
+ alwaysBtn.textContent = "Always allow";
749
+ alwaysBtn.addEventListener("click", function () {
750
+ sendPermissionResponse(container, requestId, "allow_always");
751
+ });
752
+
753
+ var denyBtn = document.createElement("button");
754
+ denyBtn.className = "mate-permission-reply mate-permission-deny";
755
+ denyBtn.textContent = "No";
756
+ denyBtn.addEventListener("click", function () {
757
+ sendPermissionResponse(container, requestId, "deny");
758
+ });
759
+
760
+ actions.appendChild(allowBtn);
761
+ actions.appendChild(alwaysBtn);
762
+ actions.appendChild(denyBtn);
763
+ content.appendChild(actions);
764
+
765
+ container.appendChild(content);
766
+
767
+ ctx.addToMessages(container);
768
+ pendingPermissions[requestId] = container;
769
+ refreshIcons();
770
+ ctx.setActivity(null);
771
+ ctx.scrollToBottom();
772
+ }
773
+
645
774
  function sendPermissionResponse(container, requestId, decision) {
646
775
  if (container.classList.contains("resolved")) return;
647
776
  container.classList.add("resolved");
@@ -1224,20 +1353,20 @@ export function startThinking() {
1224
1353
  var mateAvatar = ctx.getMateAvatarUrl();
1225
1354
  el.classList.add("mate-thinking");
1226
1355
  el.innerHTML =
1356
+ '<img class="dm-bubble-avatar dm-bubble-avatar-mate" src="' + escapeHtml(mateAvatar) + '" alt="">' +
1357
+ '<div class="dm-bubble-content">' +
1227
1358
  '<div class="mate-thinking-row">' +
1228
- '<img class="mate-thinking-avatar" src="' + escapeHtml(mateAvatar) + '" alt="">' +
1229
- '<div class="mate-thinking-body">' +
1230
- '<span class="mate-thinking-name">' + escapeHtml(mateName) + '</span>' +
1359
+ '<span class="dm-bubble-name">' + escapeHtml(mateName) + '</span>' +
1231
1360
  '<span class="mate-thinking-dots"><span></span><span></span><span></span></span>' +
1232
1361
  '</div>' +
1233
- '</div>' +
1234
1362
  '<div class="thinking-header" style="display:none">' +
1235
1363
  '<span class="thinking-chevron">' + iconHtml("chevron-right") + '</span>' +
1236
1364
  '<span class="thinking-label">Thinking</span>' +
1237
1365
  '<span class="thinking-duration"></span>' +
1238
1366
  '<span class="thinking-spinner">' + iconHtml("loader", "icon-spin") + '</span>' +
1239
1367
  '</div>' +
1240
- '<div class="thinking-content"></div>';
1368
+ '<div class="thinking-content"></div>' +
1369
+ '</div>';
1241
1370
  } else {
1242
1371
  el.innerHTML =
1243
1372
  '<div class="thinking-header">' +
@@ -1306,9 +1435,11 @@ export function createToolItem(id, name) {
1306
1435
  toolGroupCounter++;
1307
1436
  var groupEl = document.createElement("div");
1308
1437
  groupEl.className = "tool-group";
1309
- if (ctx.isMateDm()) groupEl.classList.add("mate-tool-group");
1438
+ var isMateToolGroup = ctx.isMateDm();
1439
+ if (isMateToolGroup) groupEl.classList.add("mate-tool-group");
1310
1440
  groupEl.dataset.groupId = "g" + toolGroupCounter;
1311
- groupEl.innerHTML =
1441
+
1442
+ var toolGroupInner =
1312
1443
  '<div class="tool-group-header" style="display:none">' +
1313
1444
  '<span class="tool-group-chevron">' + iconHtml("chevron-right") + '</span>' +
1314
1445
  '<span class="tool-group-bullet"></span>' +
@@ -1317,6 +1448,15 @@ export function createToolItem(id, name) {
1317
1448
  '</div>' +
1318
1449
  '<div class="tool-group-items"></div>';
1319
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
+
1320
1460
  groupEl.querySelector(".tool-group-header").addEventListener("click", function () {
1321
1461
  groupEl.classList.toggle("collapsed");
1322
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.8",
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",