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 +57 -3
- package/lib/public/css/mates.css +138 -31
- package/lib/public/modules/input.js +5 -0
- package/lib/public/modules/tools.js +170 -16
- package/package.json +1 -1
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
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
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) ---
|
package/lib/public/css/mates.css
CHANGED
|
@@ -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
|
|
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:
|
|
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
|
|
1434
|
+
/* --- Mate Permission: conversational chat bubble --- */
|
|
1399
1435
|
body.mate-dm-active .mate-permission {
|
|
1400
|
-
border
|
|
1401
|
-
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
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
padding:
|
|
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-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1452
|
+
.mate-permission-details {
|
|
1453
|
+
padding-left: 36px;
|
|
1454
|
+
margin-bottom: 8px;
|
|
1455
|
+
font-size: 12px;
|
|
1456
|
+
color: var(--text-muted);
|
|
1416
1457
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1458
|
+
.mate-permission-details summary {
|
|
1459
|
+
cursor: pointer;
|
|
1460
|
+
user-select: none;
|
|
1420
1461
|
}
|
|
1421
|
-
|
|
1422
|
-
|
|
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
|
|
1427
|
-
body.mate-dm-active .mate-
|
|
1524
|
+
/* --- Mate AskUserQuestion: avatar + content layout (matches msg-assistant) --- */
|
|
1525
|
+
body.mate-dm-active .mate-ask-user {
|
|
1428
1526
|
display: flex;
|
|
1429
|
-
|
|
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-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
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-
|
|
1439
|
-
|
|
1440
|
-
|
|
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
|
-
|
|
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
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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)
|
|
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);
|