clay-server 2.14.0-beta.1 → 2.14.0-beta.10

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
@@ -809,6 +809,14 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
809
809
  if (msg.type === "init" && msg.sessions) {
810
810
  renderMateSessionList(msg.sessions);
811
811
  requestKnowledgeList();
812
+ // Override title bar with mate name (not session/project title)
813
+ if (dmTargetUser && dmTargetUser.isMate) {
814
+ var mateDN = dmTargetUser.displayName || "New Mate";
815
+ if (headerTitleEl) headerTitleEl.textContent = mateDN;
816
+ var tbPN = document.getElementById("title-bar-project-name");
817
+ if (tbPN) tbPN.textContent = mateDN;
818
+ updatePageTitle();
819
+ }
812
820
  }
813
821
  if (msg.type === "session_list") {
814
822
  renderMateSessionList(msg.sessions || []);
@@ -863,6 +871,11 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
863
871
  savedMainWs = null;
864
872
  }
865
873
  mateWs = null;
874
+ // If main ws is also closed (server shutdown), show disconnect screen
875
+ if (!ws || ws.readyState !== WebSocket.OPEN) {
876
+ setStatus("disconnected");
877
+ scheduleReconnect();
878
+ }
866
879
  };
867
880
  }
868
881
 
@@ -1804,6 +1817,32 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
1804
1817
  }
1805
1818
  }
1806
1819
 
1820
+ // --- Mate pre-thinking (instant dots before server responds) ---
1821
+ var matePreThinkingEl = null;
1822
+ function showMatePreThinking() {
1823
+ removeMatePreThinking();
1824
+ var mateName = dmTargetUser ? (dmTargetUser.displayName || "Mate") : "Mate";
1825
+ var mateAvatar = document.body.dataset.mateAvatarUrl || "";
1826
+ matePreThinkingEl = document.createElement("div");
1827
+ matePreThinkingEl.className = "thinking-item mate-thinking mate-pre-thinking";
1828
+ matePreThinkingEl.innerHTML =
1829
+ '<div class="mate-thinking-row" style="display:flex">' +
1830
+ '<img class="mate-thinking-avatar" src="' + escapeHtml(mateAvatar) + '" alt="">' +
1831
+ '<div class="mate-thinking-body">' +
1832
+ '<span class="mate-thinking-name">' + escapeHtml(mateName) + '</span>' +
1833
+ '<span class="mate-thinking-dots"><span></span><span></span><span></span></span>' +
1834
+ '</div>' +
1835
+ '</div>';
1836
+ addToMessages(matePreThinkingEl);
1837
+ scrollToBottom();
1838
+ }
1839
+ function removeMatePreThinking() {
1840
+ if (matePreThinkingEl) {
1841
+ matePreThinkingEl.remove();
1842
+ matePreThinkingEl = null;
1843
+ }
1844
+ }
1845
+
1807
1846
  // --- Config chip (model + mode + effort) ---
1808
1847
  var configChipWrap = $("config-chip-wrap");
1809
1848
  var configChip = $("config-chip");
@@ -2512,6 +2551,9 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
2512
2551
  var win = contextData.contextWindow;
2513
2552
  return win > 0 ? Math.round((used / win) * 100) : 0;
2514
2553
  },
2554
+ isMateDm: function () { return dmMode && dmTargetUser && dmTargetUser.isMate; },
2555
+ getMateName: function () { return dmTargetUser ? (dmTargetUser.displayName || "Mate") : "Mate"; },
2556
+ getMateAvatarUrl: function () { return document.body.dataset.mateAvatarUrl || ""; },
2515
2557
  });
2516
2558
 
2517
2559
  // isPlanFile, toolSummary, toolActivityText, shortPath -> modules/tools.js
@@ -3402,9 +3444,17 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
3402
3444
  projectName = msg.project || msg.cwd;
3403
3445
  if (msg.slug) currentSlug = msg.slug;
3404
3446
  try { localStorage.setItem("clay-project-name-" + (currentSlug || "default"), projectName); } catch (e) {}
3405
- headerTitleEl.textContent = projectName;
3406
- var tbProjectName = $("title-bar-project-name");
3407
- if (tbProjectName) tbProjectName.textContent = msg.title || projectName;
3447
+ // In mate DM, keep title as mate name (not project/session title)
3448
+ if (dmMode && dmTargetUser && dmTargetUser.isMate) {
3449
+ var _mateDN = dmTargetUser.displayName || "New Mate";
3450
+ headerTitleEl.textContent = _mateDN;
3451
+ var tbProjectName = $("title-bar-project-name");
3452
+ if (tbProjectName) tbProjectName.textContent = _mateDN;
3453
+ } else {
3454
+ headerTitleEl.textContent = projectName;
3455
+ var tbProjectName = $("title-bar-project-name");
3456
+ if (tbProjectName) tbProjectName.textContent = msg.title || projectName;
3457
+ }
3408
3458
  updatePageTitle();
3409
3459
  if (msg.version) {
3410
3460
  setPaletteVersion(msg.version);
@@ -3691,6 +3741,7 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
3691
3741
  break;
3692
3742
 
3693
3743
  case "thinking_start":
3744
+ removeMatePreThinking();
3694
3745
  startThinking();
3695
3746
  break;
3696
3747
 
@@ -3705,6 +3756,7 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
3705
3756
 
3706
3757
  case "delta":
3707
3758
  if (typeof msg.text !== "string") break;
3759
+ removeMatePreThinking();
3708
3760
  stopThinking();
3709
3761
  resetThinkingGroup();
3710
3762
  setActivity(null);
@@ -3712,6 +3764,7 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
3712
3764
  break;
3713
3765
 
3714
3766
  case "tool_start":
3767
+ removeMatePreThinking();
3715
3768
  stopThinking();
3716
3769
  markAllToolsDone();
3717
3770
  if (msg.name === "EnterPlanMode") {
@@ -4531,6 +4584,7 @@ import { initCommandPalette, handlePaletteSessionSwitch, setPaletteVersion } fro
4531
4584
  isMateDm: function () { return dmMode && dmTargetUser && dmTargetUser.isMate; },
4532
4585
  getMateName: function () { return dmTargetUser ? (dmTargetUser.displayName || "Mate") : "Mate"; },
4533
4586
  getMateAvatarUrl: function () { return document.body.dataset.mateAvatarUrl || ""; },
4587
+ showMatePreThinking: function () { showMatePreThinking(); },
4534
4588
  });
4535
4589
 
4536
4590
  // --- STT module (voice input via Web Speech API) ---
@@ -1376,15 +1376,51 @@ body.mate-dm-active .mate-thinking:not(.done) .mate-thinking-row {
1376
1376
  30% { transform: translateY(-4px); opacity: 1; }
1377
1377
  }
1378
1378
 
1379
- /* When done, hide mate row (JS does this too), show normal thinking header */
1379
+ /* When done, hide mate row (JS does this too), show compact expandable header */
1380
1380
  body.mate-dm-active .mate-thinking.done .mate-thinking-row {
1381
1381
  display: none;
1382
1382
  }
1383
1383
  body.mate-dm-active .mate-thinking.done .thinking-header {
1384
1384
  display: inline-flex !important;
1385
+ font-size: 12px;
1386
+ padding: 4px 10px;
1387
+ background: rgba(var(--overlay-rgb), 0.04);
1388
+ border-radius: 6px;
1389
+ opacity: 0.7;
1390
+ transition: opacity 0.15s;
1391
+ }
1392
+ body.mate-dm-active .mate-thinking.done .thinking-header:hover {
1393
+ opacity: 1;
1394
+ background: rgba(var(--overlay-rgb), 0.08);
1395
+ }
1396
+ body.mate-dm-active .mate-thinking .thinking-content {
1397
+ max-height: 0;
1398
+ overflow: hidden;
1399
+ transition: max-height 0.25s ease;
1400
+ }
1401
+ body.mate-dm-active .mate-thinking.expanded .thinking-content {
1402
+ max-height: 2000px;
1385
1403
  }
1386
1404
 
1387
- /* --- Mate Tool Group: subtle, compact --- */
1405
+ /* --- Mate Tool Group: compact, always collapsed with summary header --- */
1406
+ body.mate-dm-active .mate-tool-group {
1407
+ margin: 2px 0;
1408
+ }
1409
+ body.mate-dm-active .mate-tool-group .tool-group-header {
1410
+ font-size: 12px;
1411
+ padding: 4px 10px;
1412
+ background: rgba(var(--overlay-rgb), 0.04);
1413
+ border-radius: 6px;
1414
+ opacity: 0.7;
1415
+ transition: opacity 0.15s;
1416
+ }
1417
+ body.mate-dm-active .mate-tool-group .tool-group-header:hover {
1418
+ opacity: 1;
1419
+ background: rgba(var(--overlay-rgb), 0.08);
1420
+ }
1421
+ body.mate-dm-active .mate-tool-group .tool-group-label {
1422
+ font-size: 12px;
1423
+ }
1388
1424
  body.mate-dm-active .mate-tool-group .tool-item {
1389
1425
  border: none;
1390
1426
  background: none;
@@ -1395,49 +1431,120 @@ body.mate-dm-active .mate-tool-group .tool-name {
1395
1431
  color: var(--text-muted);
1396
1432
  }
1397
1433
 
1398
- /* --- Mate Permission: conversational style --- */
1434
+ /* --- Mate Permission: conversational chat bubble --- */
1399
1435
  body.mate-dm-active .mate-permission {
1400
- border-radius: 12px;
1401
- border: 1px solid var(--border);
1436
+ border: none;
1437
+ border-radius: 0;
1438
+ background: none;
1439
+ box-shadow: none;
1440
+ padding: 4px 16px;
1441
+ }
1442
+ body.mate-dm-active .mate-permission:hover {
1402
1443
  background: var(--bg-alt);
1403
- overflow: hidden;
1404
1444
  }
1405
- body.mate-dm-active .mate-permission .permission-header {
1406
- display: flex;
1407
- align-items: center;
1408
- gap: 10px;
1409
- padding: 12px 16px 8px;
1445
+ .mate-permission-ask {
1446
+ font-size: 15px;
1447
+ line-height: 1.46;
1448
+ color: var(--text);
1449
+ padding-left: 36px; /* align with name (avatar 28px + gap 8px) */
1450
+ margin-bottom: 8px;
1410
1451
  }
1411
- .mate-permission-avatar {
1412
- width: 24px;
1413
- height: 24px;
1414
- border-radius: 6px;
1415
- flex-shrink: 0;
1452
+ .mate-permission-details {
1453
+ padding-left: 36px;
1454
+ margin-bottom: 8px;
1455
+ font-size: 12px;
1456
+ color: var(--text-muted);
1416
1457
  }
1417
- body.mate-dm-active .mate-permission .permission-title {
1418
- font-size: 14px;
1419
- font-weight: 600;
1458
+ .mate-permission-details summary {
1459
+ cursor: pointer;
1460
+ user-select: none;
1420
1461
  }
1421
- body.mate-dm-active .mate-permission .permission-actions {
1422
- padding: 8px 16px 12px;
1462
+ .mate-permission-details pre {
1463
+ font-size: 11px;
1464
+ margin: 4px 0 0;
1465
+ padding: 8px;
1466
+ background: rgba(var(--overlay-rgb), 0.04);
1467
+ border-radius: 6px;
1468
+ overflow-x: auto;
1469
+ max-height: 200px;
1470
+ }
1471
+ .mate-permission-actions {
1472
+ display: flex;
1423
1473
  gap: 6px;
1474
+ padding-left: 36px;
1475
+ padding-bottom: 4px;
1476
+ }
1477
+ .mate-permission-reply {
1478
+ padding: 5px 14px;
1479
+ border-radius: 16px;
1480
+ font-size: 13px;
1481
+ font-weight: 500;
1482
+ font-family: inherit;
1483
+ cursor: pointer;
1484
+ border: 1px solid var(--border);
1485
+ background: var(--bg-alt);
1486
+ color: var(--text);
1487
+ transition: background 0.15s, border-color 0.15s;
1488
+ }
1489
+ .mate-permission-reply:hover {
1490
+ border-color: var(--text-dimmer);
1491
+ background: rgba(var(--overlay-rgb), 0.06);
1492
+ }
1493
+ .mate-permission-allow {
1494
+ background: var(--accent, #6c5ce7);
1495
+ color: #fff;
1496
+ border-color: var(--accent, #6c5ce7);
1497
+ }
1498
+ .mate-permission-allow:hover {
1499
+ opacity: 0.9;
1500
+ background: var(--accent, #6c5ce7);
1501
+ border-color: var(--accent, #6c5ce7);
1502
+ }
1503
+ .mate-permission-deny {
1504
+ color: var(--text-muted);
1505
+ }
1506
+ /* Resolved state */
1507
+ body.mate-dm-active .mate-permission.resolved .mate-permission-actions {
1508
+ pointer-events: none;
1509
+ }
1510
+ body.mate-dm-active .mate-permission.resolved .mate-permission-reply {
1511
+ display: none;
1512
+ }
1513
+ body.mate-dm-active .mate-permission.resolved .permission-decision-label {
1514
+ font-size: 12px;
1515
+ color: var(--text-dimmer);
1516
+ padding-left: 36px;
1517
+ }
1518
+
1519
+ /* --- Mate Activity: avatar + text (hidden, dots row is enough) --- */
1520
+ body.mate-dm-active .activity-inline {
1521
+ display: none;
1424
1522
  }
1425
1523
 
1426
- /* --- Mate Activity: avatar + text --- */
1427
- body.mate-dm-active .mate-activity {
1524
+ /* --- Mate AskUserQuestion: avatar + content layout (matches msg-assistant) --- */
1525
+ body.mate-dm-active .mate-ask-user {
1428
1526
  display: flex;
1429
- align-items: center;
1527
+ flex-direction: row;
1528
+ align-items: flex-start;
1430
1529
  gap: 8px;
1530
+ padding: 4px 16px;
1531
+ margin: 0;
1532
+ max-width: 100%;
1431
1533
  }
1432
- .mate-activity-avatar {
1433
- width: 20px;
1434
- height: 20px;
1435
- border-radius: 4px;
1534
+ body.mate-dm-active .mate-ask-user:hover {
1535
+ background: var(--bg-alt);
1536
+ }
1537
+ body.mate-dm-active .mate-ask-user > .dm-bubble-avatar {
1538
+ display: block;
1539
+ width: 36px;
1540
+ height: 36px;
1541
+ border-radius: 6px;
1436
1542
  flex-shrink: 0;
1543
+ margin-top: 2px;
1437
1544
  }
1438
- body.mate-dm-active .mate-activity .activity-text {
1439
- font-size: 13px;
1440
- color: var(--text-muted);
1545
+ body.mate-dm-active .mate-ask-user > .dm-bubble-content {
1546
+ flex: 1;
1547
+ min-width: 0;
1441
1548
  }
1442
1549
 
1443
1550
  /* --- Interstitial elements: indent to align with message content (16px pad + 36px avatar + 8px gap = 60px) --- */
@@ -105,6 +105,11 @@ export function sendMessage() {
105
105
  }
106
106
  ctx.ws.send(JSON.stringify(payload));
107
107
 
108
+ // Mate DM: show pre-thinking dots immediately (before server responds)
109
+ if (ctx.isMateDm && ctx.isMateDm()) {
110
+ ctx.showMatePreThinking();
111
+ }
112
+
108
113
  ctx.inputEl.value = "";
109
114
  sendInputSync();
110
115
  clearPendingImages();
@@ -112,9 +112,16 @@ function updateToolGroupHeader(group) {
112
112
  refreshIcons();
113
113
  }
114
114
 
115
- // Show group header only when 2+ visible tools
115
+ // Show group header only when 2+ visible tools (or always in mate DM)
116
116
  var header = group.el.querySelector(".tool-group-header");
117
- if (group.toolCount >= 2) {
117
+ var isMate = group.el.classList.contains("mate-tool-group");
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");
123
+ }
124
+ } else if (group.toolCount >= 2) {
118
125
  header.style.display = "";
119
126
  // When 2+ tools, ensure collapsed by default (unless user already toggled)
120
127
  if (!group.userToggled && !group.el.classList.contains("expanded-by-user")) {
@@ -182,6 +189,29 @@ export function renderAskUserQuestion(toolId, input) {
182
189
  container.className = "ask-user-container";
183
190
  container.dataset.toolId = toolId;
184
191
 
192
+ // Mate DM: wrap in avatar + content layout (same as msg-assistant)
193
+ var mateContentWrap = null;
194
+ if (ctx.isMateDm && ctx.isMateDm()) {
195
+ container.classList.add("mate-ask-user");
196
+ var mateName = ctx.getMateName();
197
+ var mateAvatar = ctx.getMateAvatarUrl();
198
+
199
+ var avi = document.createElement("img");
200
+ avi.className = "dm-bubble-avatar";
201
+ avi.src = mateAvatar;
202
+ container.appendChild(avi);
203
+
204
+ mateContentWrap = document.createElement("div");
205
+ mateContentWrap.className = "dm-bubble-content";
206
+
207
+ var headerEl = document.createElement("div");
208
+ headerEl.className = "dm-bubble-header";
209
+ headerEl.innerHTML =
210
+ '<span class="dm-bubble-name">' + escapeHtml(mateName) + '</span>' +
211
+ '<span class="dm-bubble-time">' + String(new Date().getHours()).padStart(2, "0") + ":" + String(new Date().getMinutes()).padStart(2, "0") + '</span>';
212
+ mateContentWrap.appendChild(headerEl);
213
+ }
214
+
185
215
  var answers = {};
186
216
  var multiSelections = {};
187
217
 
@@ -300,6 +330,20 @@ export function renderAskUserQuestion(toolId, input) {
300
330
  });
301
331
  container.appendChild(skipBtn);
302
332
 
333
+ // Mate DM: move all content into the bubble content wrapper
334
+ if (mateContentWrap) {
335
+ var children = [];
336
+ for (var ci = 0; ci < container.childNodes.length; ci++) {
337
+ if (container.childNodes[ci] !== container.querySelector(".dm-bubble-avatar")) {
338
+ children.push(container.childNodes[ci]);
339
+ }
340
+ }
341
+ for (var cj = 0; cj < children.length; cj++) {
342
+ mateContentWrap.appendChild(children[cj]);
343
+ }
344
+ container.appendChild(mateContentWrap);
345
+ }
346
+
303
347
  ctx.addToMessages(container);
304
348
  disableMainInput();
305
349
  ctx.setActivity(null);
@@ -378,25 +422,22 @@ export function renderPermissionRequest(requestId, toolName, toolInput, decision
378
422
  return;
379
423
  }
380
424
 
425
+ // Mate DM: render as conversational chat bubble instead of formal dialog
426
+ if (ctx.isMateDm && ctx.isMateDm()) {
427
+ renderMatePermission(requestId, toolName, toolInput);
428
+ return;
429
+ }
430
+
381
431
  var container = document.createElement("div");
382
432
  container.className = "permission-container";
383
- if (ctx.isMateDm()) container.classList.add("mate-permission");
384
433
  container.dataset.requestId = requestId;
385
434
 
386
435
  // Header
387
436
  var header = document.createElement("div");
388
437
  header.className = "permission-header";
389
- if (ctx.isMateDm()) {
390
- var mateName = ctx.getMateName();
391
- var mateAvatar = ctx.getMateAvatarUrl();
392
- header.innerHTML =
393
- '<img class="mate-permission-avatar" src="' + escapeHtml(mateAvatar) + '" alt="">' +
394
- '<span class="permission-title">' + escapeHtml(mateName) + ' wants to do something</span>';
395
- } else {
396
- header.innerHTML =
397
- '<span class="permission-icon">' + iconHtml("shield") + '</span>' +
398
- '<span class="permission-title">Permission Required</span>';
399
- }
438
+ header.innerHTML =
439
+ '<span class="permission-icon">' + iconHtml("shield") + '</span>' +
440
+ '<span class="permission-title">Permission Required</span>';
400
441
 
401
442
  // Body
402
443
  var body = document.createElement("div");
@@ -622,6 +663,108 @@ function sendPlanResponse(container, requestId, decision, feedback) {
622
663
  delete pendingPermissions[requestId];
623
664
  }
624
665
 
666
+ function matePermissionVerb(toolName) {
667
+ switch (toolName) {
668
+ case "Write": return "write to";
669
+ case "Edit": return "edit";
670
+ case "Read": return "read";
671
+ case "Bash": return "run a command on";
672
+ case "Grep": return "search";
673
+ case "Glob": return "search for files in";
674
+ case "WebFetch": return "fetch";
675
+ case "WebSearch": return "search the web for";
676
+ default: return "use " + toolName + " on";
677
+ }
678
+ }
679
+
680
+ function matePermissionTarget(toolName, toolInput) {
681
+ if (!toolInput || typeof toolInput !== "object") return "";
682
+ switch (toolName) {
683
+ case "Write": case "Edit": case "Read": return shortPath(toolInput.file_path);
684
+ case "Bash": return toolInput.description || (toolInput.command || "").substring(0, 60);
685
+ case "Grep": return toolInput.pattern || "";
686
+ case "Glob": return toolInput.pattern || "";
687
+ case "WebFetch": return toolInput.url || "";
688
+ case "WebSearch": return toolInput.query || "";
689
+ default: return "";
690
+ }
691
+ }
692
+
693
+ function renderMatePermission(requestId, toolName, toolInput) {
694
+ var mateName = ctx.getMateName();
695
+ var mateAvatar = ctx.getMateAvatarUrl();
696
+ var verb = matePermissionVerb(toolName);
697
+ var target = matePermissionTarget(toolName, toolInput);
698
+
699
+ var container = document.createElement("div");
700
+ container.className = "permission-container mate-permission";
701
+ container.dataset.requestId = requestId;
702
+
703
+ // Chat bubble: avatar + name + time
704
+ var headerRow = document.createElement("div");
705
+ headerRow.className = "dm-bubble-header";
706
+ headerRow.style.cssText = "display:flex;align-items:center;gap:8px;margin-bottom:6px";
707
+ headerRow.innerHTML =
708
+ '<img class="dm-bubble-avatar" src="' + escapeHtml(mateAvatar) + '" alt="" style="display:block;width:28px;height:28px;border-radius:6px">' +
709
+ '<span class="dm-bubble-name">' + escapeHtml(mateName) + '</span>' +
710
+ '<span class="dm-bubble-time">' + String(new Date().getHours()).padStart(2, "0") + ":" + String(new Date().getMinutes()).padStart(2, "0") + '</span>';
711
+ container.appendChild(headerRow);
712
+
713
+ // Conversational ask text
714
+ var askText = document.createElement("div");
715
+ askText.className = "mate-permission-ask";
716
+ var askMsg = "Can I " + verb + (target ? " " : "") + (target ? target : "") + "?";
717
+ askText.textContent = askMsg;
718
+ container.appendChild(askText);
719
+
720
+ // Collapsible details (subtle)
721
+ var details = document.createElement("details");
722
+ details.className = "mate-permission-details";
723
+ var detailsSummary = document.createElement("summary");
724
+ detailsSummary.textContent = "Details";
725
+ var detailsPre = document.createElement("pre");
726
+ detailsPre.textContent = JSON.stringify(toolInput, null, 2);
727
+ details.appendChild(detailsSummary);
728
+ details.appendChild(detailsPre);
729
+ container.appendChild(details);
730
+
731
+ // Quick reply buttons (chat-style)
732
+ var actions = document.createElement("div");
733
+ actions.className = "permission-actions mate-permission-actions";
734
+
735
+ var allowBtn = document.createElement("button");
736
+ allowBtn.className = "mate-permission-reply mate-permission-allow";
737
+ allowBtn.textContent = "Sure";
738
+ allowBtn.addEventListener("click", function () {
739
+ sendPermissionResponse(container, requestId, "allow");
740
+ });
741
+
742
+ var alwaysBtn = document.createElement("button");
743
+ alwaysBtn.className = "mate-permission-reply mate-permission-always";
744
+ alwaysBtn.textContent = "Always allow this";
745
+ alwaysBtn.addEventListener("click", function () {
746
+ sendPermissionResponse(container, requestId, "allow_always");
747
+ });
748
+
749
+ var denyBtn = document.createElement("button");
750
+ denyBtn.className = "mate-permission-reply mate-permission-deny";
751
+ denyBtn.textContent = "No";
752
+ denyBtn.addEventListener("click", function () {
753
+ sendPermissionResponse(container, requestId, "deny");
754
+ });
755
+
756
+ actions.appendChild(allowBtn);
757
+ actions.appendChild(alwaysBtn);
758
+ actions.appendChild(denyBtn);
759
+ container.appendChild(actions);
760
+
761
+ ctx.addToMessages(container);
762
+ pendingPermissions[requestId] = container;
763
+ refreshIcons();
764
+ ctx.setActivity(null);
765
+ ctx.scrollToBottom();
766
+ }
767
+
625
768
  function sendPermissionResponse(container, requestId, decision) {
626
769
  if (container.classList.contains("resolved")) return;
627
770
  container.classList.add("resolved");
@@ -1182,6 +1325,13 @@ export function startThinking() {
1182
1325
  var el = thinkingGroup.el;
1183
1326
  el.classList.remove("done");
1184
1327
  el.querySelector(".thinking-content").textContent = "";
1328
+ // Mate mode: restore dots row, hide thinking header
1329
+ if (el.classList.contains("mate-thinking")) {
1330
+ var dotsRow = el.querySelector(".mate-thinking-row");
1331
+ if (dotsRow) dotsRow.style.display = "flex";
1332
+ var header = el.querySelector(".thinking-header");
1333
+ if (header) header.style.display = "none";
1334
+ }
1185
1335
  currentThinking = { el: el, fullText: "", startTime: Date.now() };
1186
1336
  refreshIcons();
1187
1337
  ctx.scrollToBottom();
@@ -1252,12 +1402,15 @@ export function stopThinking(duration) {
1252
1402
  } else {
1253
1403
  currentThinking.el.querySelector(".thinking-duration").textContent = " " + secs.toFixed(1) + "s";
1254
1404
  }
1255
- // In mate mode: hide dots, show expandable thinking header
1405
+ // In mate mode: hide dots, show compact expandable thinking header
1256
1406
  if (currentThinking.el.classList.contains("mate-thinking")) {
1257
1407
  var dotsRow = currentThinking.el.querySelector(".mate-thinking-row");
1258
1408
  if (dotsRow) dotsRow.style.display = "none";
1259
1409
  var header = currentThinking.el.querySelector(".thinking-header");
1260
- if (header) header.style.display = "";
1410
+ if (header) {
1411
+ header.style.display = "";
1412
+ header.style.cursor = "pointer";
1413
+ }
1261
1414
  }
1262
1415
  currentThinking = null;
1263
1416
  }
@@ -1289,6 +1442,7 @@ export function createToolItem(id, name) {
1289
1442
 
1290
1443
  groupEl.querySelector(".tool-group-header").addEventListener("click", function () {
1291
1444
  groupEl.classList.toggle("collapsed");
1445
+ if (currentToolGroup) currentToolGroup.userToggled = true;
1292
1446
  });
1293
1447
 
1294
1448
  ctx.addToMessages(groupEl);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clay-server",
3
- "version": "2.14.0-beta.1",
3
+ "version": "2.14.0-beta.10",
4
4
  "description": "Web UI for Claude Code. Any device. Push notifications.",
5
5
  "bin": {
6
6
  "clay-server": "./bin/cli.js",