clay-server 2.26.0-beta.18 → 2.26.0-beta.19
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/browser-mcp-server.js +4 -4
- package/lib/project.js +6 -2
- package/lib/public/app.js +12 -1
- package/lib/public/css/filebrowser.css +41 -4
- package/lib/public/css/rewind.css +17 -4
- package/lib/public/index.html +1 -0
- package/lib/public/modules/debate.js +2 -2
- package/lib/public/modules/terminal.js +62 -6
- package/package.json +1 -1
|
@@ -111,7 +111,7 @@ function create(sendCommand, getTabList, contextOps) {
|
|
|
111
111
|
// --- browser_screenshot ---
|
|
112
112
|
tools.push(tool(
|
|
113
113
|
"browser_screenshot",
|
|
114
|
-
"Capture a screenshot of a browser tab
|
|
114
|
+
"Capture a screenshot of a browser tab. Skip if the tab is already attached as a context source (data is auto-injected).",
|
|
115
115
|
buildShape({
|
|
116
116
|
tabId: { type: "number", description: "Tab ID" },
|
|
117
117
|
selector: { type: "string", description: "CSS selector to capture a specific element (optional)" },
|
|
@@ -134,7 +134,7 @@ function create(sendCommand, getTabList, contextOps) {
|
|
|
134
134
|
// --- browser_console ---
|
|
135
135
|
tools.push(tool(
|
|
136
136
|
"browser_console",
|
|
137
|
-
"Read captured console logs from a tab (
|
|
137
|
+
"Read captured console logs from a tab. Skip if the tab is already a context source (data is auto-injected).",
|
|
138
138
|
buildShape({
|
|
139
139
|
tabId: { type: "number", description: "Tab ID" },
|
|
140
140
|
}, ["tabId"]),
|
|
@@ -157,7 +157,7 @@ function create(sendCommand, getTabList, contextOps) {
|
|
|
157
157
|
// --- browser_network ---
|
|
158
158
|
tools.push(tool(
|
|
159
159
|
"browser_network",
|
|
160
|
-
"Read captured network requests (fetch/XHR) from a tab",
|
|
160
|
+
"Read captured network requests (fetch/XHR) from a tab. Skip if the tab is already a context source.",
|
|
161
161
|
buildShape({
|
|
162
162
|
tabId: { type: "number", description: "Tab ID" },
|
|
163
163
|
}, ["tabId"]),
|
|
@@ -181,7 +181,7 @@ function create(sendCommand, getTabList, contextOps) {
|
|
|
181
181
|
// --- browser_read_page ---
|
|
182
182
|
tools.push(tool(
|
|
183
183
|
"browser_read_page",
|
|
184
|
-
"Read page text content (innerText).
|
|
184
|
+
"Read page text content (innerText). Skip if the tab is already a context source (text is auto-injected). Use for tabs NOT in context sources, or to read a specific element via selector.",
|
|
185
185
|
buildShape({
|
|
186
186
|
tabId: { type: "number", description: "Tab ID" },
|
|
187
187
|
selector: { type: "string", description: "CSS selector to read specific element (optional)" },
|
package/lib/project.js
CHANGED
|
@@ -4236,7 +4236,8 @@ function createProjectContext(opts) {
|
|
|
4236
4236
|
data: screenshotData,
|
|
4237
4237
|
file: screenshotName,
|
|
4238
4238
|
tabTitle: tabLabel,
|
|
4239
|
-
tabUrl: tabInfo ? tabInfo.url : ""
|
|
4239
|
+
tabUrl: tabInfo ? tabInfo.url : "",
|
|
4240
|
+
tabFavIconUrl: tabInfo ? tabInfo.favIconUrl : ""
|
|
4240
4241
|
});
|
|
4241
4242
|
parts.push("[Screenshot saved: " + screenshotPath + "]");
|
|
4242
4243
|
}
|
|
@@ -4258,7 +4259,8 @@ function createProjectContext(opts) {
|
|
|
4258
4259
|
}
|
|
4259
4260
|
|
|
4260
4261
|
if (tabContextParts.length > 0) {
|
|
4261
|
-
fullText =
|
|
4262
|
+
fullText = "[The following browser tab data is automatically attached as context sources. Do NOT call browser_read_page, browser_console, browser_network, or browser_screenshot for these tabs — the data is already here.]\n\n" +
|
|
4263
|
+
tabContextParts.join("\n\n---\n\n") + "\n\n" + fullText;
|
|
4262
4264
|
}
|
|
4263
4265
|
|
|
4264
4266
|
// If screenshots were captured, send context preview cards and add to SDK images
|
|
@@ -4272,6 +4274,7 @@ function createProjectContext(opts) {
|
|
|
4272
4274
|
tab: {
|
|
4273
4275
|
title: ss.tabTitle || "",
|
|
4274
4276
|
url: ss.tabUrl || "",
|
|
4277
|
+
favIconUrl: ss.tabFavIconUrl || "",
|
|
4275
4278
|
screenshotFile: ss.file
|
|
4276
4279
|
}
|
|
4277
4280
|
};
|
|
@@ -4282,6 +4285,7 @@ function createProjectContext(opts) {
|
|
|
4282
4285
|
tab: {
|
|
4283
4286
|
title: ss.tabTitle || "",
|
|
4284
4287
|
url: ss.tabUrl || "",
|
|
4288
|
+
favIconUrl: ss.tabFavIconUrl || "",
|
|
4285
4289
|
screenshotUrl: "/p/" + slug + "/images/" + ss.file
|
|
4286
4290
|
}
|
|
4287
4291
|
});
|
package/lib/public/app.js
CHANGED
|
@@ -4388,6 +4388,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4388
4388
|
if (dhBar) dhBar.remove();
|
|
4389
4389
|
var dbBadges = document.querySelectorAll(".debate-header-badge");
|
|
4390
4390
|
for (var dbi = 0; dbi < dbBadges.length; dbi++) dbBadges[dbi].remove();
|
|
4391
|
+
// Clean up ended mode banner if debate is not active on this session
|
|
4392
|
+
if (debateEndedMode) exitDebateEndedMode();
|
|
4391
4393
|
}
|
|
4392
4394
|
scrollToBottom();
|
|
4393
4395
|
// Scroll to tool element if navigating from file edit history
|
|
@@ -4741,7 +4743,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4741
4743
|
header.className = "context-card-header";
|
|
4742
4744
|
var icon = document.createElement("span");
|
|
4743
4745
|
icon.className = "context-card-icon";
|
|
4744
|
-
icon.
|
|
4746
|
+
icon.innerHTML = iconHtml("globe");
|
|
4745
4747
|
header.appendChild(icon);
|
|
4746
4748
|
var label = document.createElement("span");
|
|
4747
4749
|
label.textContent = "Viewing tab";
|
|
@@ -4765,6 +4767,15 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
4765
4767
|
if (tabTitle || tabDomain) {
|
|
4766
4768
|
var meta = document.createElement("div");
|
|
4767
4769
|
meta.className = "context-card-meta";
|
|
4770
|
+
if (msg.tab.favIconUrl) {
|
|
4771
|
+
var fav = document.createElement("img");
|
|
4772
|
+
fav.className = "context-card-favicon";
|
|
4773
|
+
fav.src = msg.tab.favIconUrl;
|
|
4774
|
+
fav.width = 14;
|
|
4775
|
+
fav.height = 14;
|
|
4776
|
+
fav.onerror = function () { this.style.display = "none"; };
|
|
4777
|
+
meta.appendChild(fav);
|
|
4778
|
+
}
|
|
4768
4779
|
var titleEl = document.createElement("span");
|
|
4769
4780
|
titleEl.className = "context-card-title";
|
|
4770
4781
|
titleEl.textContent = tabTitle;
|
|
@@ -873,7 +873,8 @@
|
|
|
873
873
|
.terminal-tab.active { color: var(--text); border-color: var(--accent); }
|
|
874
874
|
.terminal-tab.exited { opacity: 0.5; }
|
|
875
875
|
|
|
876
|
-
|
|
876
|
+
|
|
877
|
+
.terminal-tab-more {
|
|
877
878
|
display: none;
|
|
878
879
|
align-items: center;
|
|
879
880
|
justify-content: center;
|
|
@@ -888,9 +889,44 @@
|
|
|
888
889
|
line-height: 1;
|
|
889
890
|
}
|
|
890
891
|
|
|
891
|
-
.terminal-tab:hover .terminal-tab-
|
|
892
|
-
.terminal-tab.active .terminal-tab-
|
|
893
|
-
.terminal-tab-
|
|
892
|
+
.terminal-tab:hover .terminal-tab-more,
|
|
893
|
+
.terminal-tab.active .terminal-tab-more { display: flex; }
|
|
894
|
+
.terminal-tab-more:hover { background: rgba(var(--overlay-rgb),0.1); color: var(--text); }
|
|
895
|
+
|
|
896
|
+
.terminal-tab-ctx {
|
|
897
|
+
position: fixed;
|
|
898
|
+
z-index: 9999;
|
|
899
|
+
min-width: 120px;
|
|
900
|
+
background: var(--bg-elevated, var(--bg));
|
|
901
|
+
border: 1px solid var(--border);
|
|
902
|
+
border-radius: 6px;
|
|
903
|
+
padding: 4px;
|
|
904
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
.terminal-tab-ctx-item {
|
|
908
|
+
display: flex;
|
|
909
|
+
align-items: center;
|
|
910
|
+
gap: 8px;
|
|
911
|
+
width: 100%;
|
|
912
|
+
padding: 6px 10px;
|
|
913
|
+
border: none;
|
|
914
|
+
border-radius: 4px;
|
|
915
|
+
background: transparent;
|
|
916
|
+
color: var(--text-secondary);
|
|
917
|
+
font-size: 12px;
|
|
918
|
+
cursor: pointer;
|
|
919
|
+
white-space: nowrap;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
.terminal-tab-ctx-item:hover {
|
|
923
|
+
background: rgba(var(--overlay-rgb),0.08);
|
|
924
|
+
color: var(--text);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.terminal-tab-ctx-danger:hover {
|
|
928
|
+
color: #e74c3c;
|
|
929
|
+
}
|
|
894
930
|
|
|
895
931
|
.terminal-tab-label { cursor: default; }
|
|
896
932
|
|
|
@@ -971,6 +1007,7 @@
|
|
|
971
1007
|
|
|
972
1008
|
.terminal-tab-body .xterm {
|
|
973
1009
|
height: 100%;
|
|
1010
|
+
overflow: hidden;
|
|
974
1011
|
}
|
|
975
1012
|
|
|
976
1013
|
/* --- Terminal key toolbar (mobile) --- */
|
|
@@ -197,8 +197,13 @@
|
|
|
197
197
|
}
|
|
198
198
|
|
|
199
199
|
.context-card-header .context-card-icon {
|
|
200
|
-
font-size: 13px;
|
|
201
200
|
opacity: 0.7;
|
|
201
|
+
display: inline-flex;
|
|
202
|
+
align-items: center;
|
|
203
|
+
}
|
|
204
|
+
.context-card-header .context-card-icon .lucide {
|
|
205
|
+
width: 14px;
|
|
206
|
+
height: 14px;
|
|
202
207
|
}
|
|
203
208
|
|
|
204
209
|
.context-card-screenshot {
|
|
@@ -226,10 +231,16 @@
|
|
|
226
231
|
|
|
227
232
|
.context-card-meta {
|
|
228
233
|
display: flex;
|
|
229
|
-
|
|
230
|
-
align-items: baseline;
|
|
234
|
+
align-items: center;
|
|
231
235
|
margin-top: 8px;
|
|
232
|
-
gap:
|
|
236
|
+
gap: 6px;
|
|
237
|
+
}
|
|
238
|
+
.context-card-favicon {
|
|
239
|
+
width: 14px;
|
|
240
|
+
height: 14px;
|
|
241
|
+
border-radius: 2px;
|
|
242
|
+
flex-shrink: 0;
|
|
243
|
+
object-fit: contain;
|
|
233
244
|
}
|
|
234
245
|
|
|
235
246
|
.context-card-title {
|
|
@@ -240,6 +251,8 @@
|
|
|
240
251
|
text-overflow: ellipsis;
|
|
241
252
|
flex: 1;
|
|
242
253
|
min-width: 0;
|
|
254
|
+
flex: 1;
|
|
255
|
+
min-width: 0;
|
|
243
256
|
}
|
|
244
257
|
|
|
245
258
|
.context-card-domain {
|
package/lib/public/index.html
CHANGED
|
@@ -2040,6 +2040,7 @@
|
|
|
2040
2040
|
<script src="https://cdn.jsdelivr.net/npm/@xterm/xterm@5/lib/xterm.min.js"></script>
|
|
2041
2041
|
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-fit@0/lib/addon-fit.min.js"></script>
|
|
2042
2042
|
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-web-links@0/lib/addon-web-links.min.js"></script>
|
|
2043
|
+
<script src="https://cdn.jsdelivr.net/npm/@xterm/addon-webgl@0/lib/addon-webgl.min.js"></script>
|
|
2043
2044
|
<script type="module" src="app.js"></script>
|
|
2044
2045
|
<div id="pwa-install-modal" class="pwa-modal hidden">
|
|
2045
2046
|
<div class="pwa-modal-backdrop"></div>
|
|
@@ -690,8 +690,8 @@ export function renderDebateEnded(entry) {
|
|
|
690
690
|
ctx.messagesEl.appendChild(statusLine);
|
|
691
691
|
refreshIcons();
|
|
692
692
|
|
|
693
|
-
//
|
|
694
|
-
|
|
693
|
+
// During history replay, don't activate ended mode banner.
|
|
694
|
+
// The debate is already over; status line in messages is sufficient.
|
|
695
695
|
}
|
|
696
696
|
|
|
697
697
|
export function renderDebateCommentInjected(entry) {
|
|
@@ -352,6 +352,16 @@ function createXtermForTab(tab) {
|
|
|
352
352
|
|
|
353
353
|
xterm.open(bodyEl);
|
|
354
354
|
|
|
355
|
+
// WebGL addon: pixel-perfect rendering (eliminates gaps in block characters)
|
|
356
|
+
// Must be loaded after xterm.open() so the rendering context is available.
|
|
357
|
+
if (typeof WebglAddon !== "undefined") {
|
|
358
|
+
try {
|
|
359
|
+
xterm.loadAddon(new WebglAddon.WebglAddon());
|
|
360
|
+
} catch (e) {
|
|
361
|
+
// WebGL not available, fall back to DOM renderer
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
355
365
|
// Route input to server
|
|
356
366
|
xterm.onData(function (data) {
|
|
357
367
|
if (ctx.ws && ctx.connected) {
|
|
@@ -481,14 +491,14 @@ function renderTabBar() {
|
|
|
481
491
|
startRenameTab(t, label);
|
|
482
492
|
});
|
|
483
493
|
|
|
484
|
-
var
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
494
|
+
var moreBtn = document.createElement("button");
|
|
495
|
+
moreBtn.className = "terminal-tab-more";
|
|
496
|
+
moreBtn.innerHTML = '<i data-lucide="ellipsis" style="width:12px;height:12px"></i>';
|
|
497
|
+
moreBtn.addEventListener("click", function (e) {
|
|
488
498
|
e.stopPropagation();
|
|
489
|
-
|
|
499
|
+
showTabContextMenu(e, t, label);
|
|
490
500
|
});
|
|
491
|
-
el.appendChild(
|
|
501
|
+
el.appendChild(moreBtn);
|
|
492
502
|
|
|
493
503
|
el.addEventListener("click", function () {
|
|
494
504
|
if (t.id !== activeTabId) {
|
|
@@ -504,6 +514,52 @@ function renderTabBar() {
|
|
|
504
514
|
refreshIcons();
|
|
505
515
|
}
|
|
506
516
|
|
|
517
|
+
// --- Tab context menu (three-dot) ---
|
|
518
|
+
function showTabContextMenu(e, tab, labelEl) {
|
|
519
|
+
var existing = document.querySelector(".terminal-tab-ctx");
|
|
520
|
+
if (existing) existing.remove();
|
|
521
|
+
|
|
522
|
+
var menu = document.createElement("div");
|
|
523
|
+
menu.className = "terminal-tab-ctx";
|
|
524
|
+
|
|
525
|
+
var renameItem = document.createElement("button");
|
|
526
|
+
renameItem.className = "terminal-tab-ctx-item";
|
|
527
|
+
renameItem.innerHTML = '<i data-lucide="pencil" style="width:13px;height:13px"></i> Rename';
|
|
528
|
+
renameItem.addEventListener("click", function () {
|
|
529
|
+
menu.remove();
|
|
530
|
+
startRenameTab(tab, labelEl);
|
|
531
|
+
});
|
|
532
|
+
menu.appendChild(renameItem);
|
|
533
|
+
|
|
534
|
+
var closeItem = document.createElement("button");
|
|
535
|
+
closeItem.className = "terminal-tab-ctx-item terminal-tab-ctx-danger";
|
|
536
|
+
closeItem.innerHTML = '<i data-lucide="trash-2" style="width:13px;height:13px"></i> Close';
|
|
537
|
+
closeItem.addEventListener("click", function () {
|
|
538
|
+
menu.remove();
|
|
539
|
+
closeTab(tab.id);
|
|
540
|
+
});
|
|
541
|
+
menu.appendChild(closeItem);
|
|
542
|
+
|
|
543
|
+
document.body.appendChild(menu);
|
|
544
|
+
refreshIcons();
|
|
545
|
+
|
|
546
|
+
// Position near the button
|
|
547
|
+
var rect = e.currentTarget.getBoundingClientRect();
|
|
548
|
+
menu.style.top = (rect.bottom + 4) + "px";
|
|
549
|
+
menu.style.left = rect.left + "px";
|
|
550
|
+
|
|
551
|
+
// Dismiss on outside click
|
|
552
|
+
function dismiss(ev) {
|
|
553
|
+
if (!menu.contains(ev.target)) {
|
|
554
|
+
menu.remove();
|
|
555
|
+
document.removeEventListener("mousedown", dismiss, true);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
setTimeout(function () {
|
|
559
|
+
document.addEventListener("mousedown", dismiss, true);
|
|
560
|
+
}, 0);
|
|
561
|
+
}
|
|
562
|
+
|
|
507
563
|
// --- Rename tab inline ---
|
|
508
564
|
function startRenameTab(tab, labelEl) {
|
|
509
565
|
var input = document.createElement("input");
|
package/package.json
CHANGED