clay-server 2.26.0-beta.5 → 2.26.0-beta.7
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 +496 -0
- package/lib/project.js +340 -17
- package/lib/public/app.js +111 -1
- package/lib/public/css/input.css +16 -5
- package/lib/public/css/overlays.css +181 -0
- package/lib/public/css/rewind.css +79 -0
- package/lib/public/css/server-settings.css +1 -0
- package/lib/public/css/title-bar.css +3 -3
- package/lib/public/index.html +24 -1
- package/lib/public/modules/context-sources.js +116 -29
- package/lib/public/modules/notifications.js +109 -1
- package/lib/sdk-bridge.js +3 -0
- package/lib/server.js +42 -0
- package/package.json +1 -1
|
@@ -123,6 +123,187 @@ button.top-bar-pill.pill-accent:hover { background: color-mix(in srgb, var(--acc
|
|
|
123
123
|
}
|
|
124
124
|
.pwa-standalone .top-bar-share-btn { display: none !important; }
|
|
125
125
|
|
|
126
|
+
/* Extension pill button — same style as share/install pills */
|
|
127
|
+
.ext-pill-wrap {
|
|
128
|
+
position: relative;
|
|
129
|
+
display: flex;
|
|
130
|
+
align-items: center;
|
|
131
|
+
}
|
|
132
|
+
.top-bar-ext-btn {
|
|
133
|
+
display: inline-flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
gap: 4px;
|
|
136
|
+
background: color-mix(in srgb, var(--text-muted) 10%, transparent);
|
|
137
|
+
color: var(--text-secondary);
|
|
138
|
+
border: none;
|
|
139
|
+
border-radius: 10px;
|
|
140
|
+
padding: 2px 10px;
|
|
141
|
+
font-family: inherit;
|
|
142
|
+
font-size: 11px;
|
|
143
|
+
font-weight: 600;
|
|
144
|
+
cursor: pointer;
|
|
145
|
+
white-space: nowrap;
|
|
146
|
+
line-height: 1;
|
|
147
|
+
transition: background 0.15s, color 0.15s;
|
|
148
|
+
}
|
|
149
|
+
.top-bar-ext-btn .lucide { width: 12px; height: 12px; }
|
|
150
|
+
.top-bar-ext-btn:hover { background: color-mix(in srgb, var(--text-muted) 18%, transparent); color: var(--text); }
|
|
151
|
+
@media (max-width: 768px) {
|
|
152
|
+
.top-bar-ext-btn span { display: none; }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* Extension popover */
|
|
156
|
+
.ext-popover {
|
|
157
|
+
display: none;
|
|
158
|
+
position: absolute;
|
|
159
|
+
top: calc(100% + 8px);
|
|
160
|
+
left: 0;
|
|
161
|
+
background: var(--code-bg);
|
|
162
|
+
border: 1px solid var(--border);
|
|
163
|
+
border-radius: 12px;
|
|
164
|
+
padding: 16px;
|
|
165
|
+
z-index: 200;
|
|
166
|
+
box-shadow: 0 8px 32px rgba(var(--shadow-rgb), 0.35);
|
|
167
|
+
width: 340px;
|
|
168
|
+
}
|
|
169
|
+
.ext-popover.visible { display: block; }
|
|
170
|
+
.ext-popover-header { margin-bottom: 8px; }
|
|
171
|
+
.ext-popover-title {
|
|
172
|
+
font-size: 14px;
|
|
173
|
+
font-weight: 700;
|
|
174
|
+
color: var(--text);
|
|
175
|
+
}
|
|
176
|
+
.ext-experimental {
|
|
177
|
+
font-size: 10px;
|
|
178
|
+
font-weight: 600;
|
|
179
|
+
color: var(--warning, #f59e0b);
|
|
180
|
+
background: color-mix(in srgb, var(--warning, #f59e0b) 12%, transparent);
|
|
181
|
+
padding: 2px 6px;
|
|
182
|
+
border-radius: 6px;
|
|
183
|
+
vertical-align: middle;
|
|
184
|
+
letter-spacing: 0.3px;
|
|
185
|
+
text-transform: uppercase;
|
|
186
|
+
position: relative;
|
|
187
|
+
top: -1px;
|
|
188
|
+
}
|
|
189
|
+
.ext-popover-sub {
|
|
190
|
+
font-size: 11px;
|
|
191
|
+
color: var(--text-muted);
|
|
192
|
+
margin-top: 2px;
|
|
193
|
+
}
|
|
194
|
+
.ext-popover-sub a {
|
|
195
|
+
color: var(--accent);
|
|
196
|
+
text-decoration: none;
|
|
197
|
+
}
|
|
198
|
+
.ext-popover-sub a:hover { text-decoration: underline; }
|
|
199
|
+
.ext-popover-desc {
|
|
200
|
+
font-size: 12px;
|
|
201
|
+
color: var(--text-secondary);
|
|
202
|
+
line-height: 1.5;
|
|
203
|
+
margin-bottom: 12px;
|
|
204
|
+
}
|
|
205
|
+
.ext-popover-download {
|
|
206
|
+
display: flex;
|
|
207
|
+
align-items: center;
|
|
208
|
+
justify-content: center;
|
|
209
|
+
gap: 6px;
|
|
210
|
+
width: 100%;
|
|
211
|
+
padding: 8px 0;
|
|
212
|
+
background: var(--accent);
|
|
213
|
+
color: #fff;
|
|
214
|
+
border: none;
|
|
215
|
+
border-radius: 8px;
|
|
216
|
+
font-family: inherit;
|
|
217
|
+
font-size: 12.5px;
|
|
218
|
+
font-weight: 600;
|
|
219
|
+
cursor: pointer;
|
|
220
|
+
transition: opacity 0.15s;
|
|
221
|
+
}
|
|
222
|
+
.ext-popover-download .lucide { width: 14px; height: 14px; }
|
|
223
|
+
.ext-popover-download:hover { opacity: 0.85; }
|
|
224
|
+
.ext-popover-download:disabled { opacity: 0.5; cursor: default; }
|
|
225
|
+
.ext-popover-status {
|
|
226
|
+
font-size: 11px;
|
|
227
|
+
color: var(--accent);
|
|
228
|
+
text-align: center;
|
|
229
|
+
margin-top: 6px;
|
|
230
|
+
}
|
|
231
|
+
.ext-popover-status.hidden { display: none; }
|
|
232
|
+
.ext-popover-divider {
|
|
233
|
+
height: 1px;
|
|
234
|
+
background: var(--border);
|
|
235
|
+
margin: 12px 0;
|
|
236
|
+
}
|
|
237
|
+
.ext-popover-guide-title {
|
|
238
|
+
font-size: 11px;
|
|
239
|
+
font-weight: 700;
|
|
240
|
+
color: var(--text-muted);
|
|
241
|
+
text-transform: uppercase;
|
|
242
|
+
letter-spacing: 0.5px;
|
|
243
|
+
margin-bottom: 8px;
|
|
244
|
+
}
|
|
245
|
+
.ext-popover-steps {
|
|
246
|
+
display: flex;
|
|
247
|
+
flex-direction: column;
|
|
248
|
+
gap: 6px;
|
|
249
|
+
}
|
|
250
|
+
.ext-popover-step {
|
|
251
|
+
font-size: 12px;
|
|
252
|
+
color: var(--text-secondary);
|
|
253
|
+
line-height: 1.5;
|
|
254
|
+
display: flex;
|
|
255
|
+
gap: 8px;
|
|
256
|
+
align-items: baseline;
|
|
257
|
+
}
|
|
258
|
+
.ext-snum {
|
|
259
|
+
display: inline-flex;
|
|
260
|
+
align-items: center;
|
|
261
|
+
justify-content: center;
|
|
262
|
+
width: 18px;
|
|
263
|
+
height: 18px;
|
|
264
|
+
border-radius: 50%;
|
|
265
|
+
background: var(--accent);
|
|
266
|
+
color: #fff;
|
|
267
|
+
font-size: 10px;
|
|
268
|
+
font-weight: 700;
|
|
269
|
+
flex-shrink: 0;
|
|
270
|
+
position: relative;
|
|
271
|
+
top: 1px;
|
|
272
|
+
}
|
|
273
|
+
.ext-popover-code {
|
|
274
|
+
font-family: "Roboto Mono", monospace;
|
|
275
|
+
font-size: 11px;
|
|
276
|
+
background: var(--bg-tertiary);
|
|
277
|
+
padding: 1px 5px;
|
|
278
|
+
border-radius: 4px;
|
|
279
|
+
cursor: pointer;
|
|
280
|
+
}
|
|
281
|
+
.ext-popover-code:hover { background: color-mix(in srgb, var(--accent) 15%, var(--bg-tertiary)); }
|
|
282
|
+
|
|
283
|
+
/* Extension connected state */
|
|
284
|
+
.top-bar-ext-btn.ext-connected {
|
|
285
|
+
background: color-mix(in srgb, var(--success, #22c55e) 12%, transparent);
|
|
286
|
+
color: var(--success, #22c55e);
|
|
287
|
+
}
|
|
288
|
+
.top-bar-ext-btn.ext-connected:hover {
|
|
289
|
+
background: color-mix(in srgb, var(--success, #22c55e) 20%, transparent);
|
|
290
|
+
color: var(--success, #22c55e);
|
|
291
|
+
}
|
|
292
|
+
.ext-popover-connected {
|
|
293
|
+
display: flex;
|
|
294
|
+
align-items: center;
|
|
295
|
+
gap: 6px;
|
|
296
|
+
padding: 8px 10px;
|
|
297
|
+
background: color-mix(in srgb, var(--success, #22c55e) 10%, transparent);
|
|
298
|
+
color: var(--success, #22c55e);
|
|
299
|
+
border-radius: 8px;
|
|
300
|
+
font-size: 12.5px;
|
|
301
|
+
font-weight: 600;
|
|
302
|
+
margin-bottom: 12px;
|
|
303
|
+
}
|
|
304
|
+
.ext-popover-connected .lucide { width: 15px; height: 15px; }
|
|
305
|
+
.ext-popover-connected.hidden { display: none; }
|
|
306
|
+
|
|
126
307
|
/* PWA install modal */
|
|
127
308
|
.pwa-modal {
|
|
128
309
|
position: fixed;
|
|
@@ -171,6 +171,85 @@
|
|
|
171
171
|
|
|
172
172
|
.sys-msg.error .sys-text { color: var(--error); }
|
|
173
173
|
|
|
174
|
+
/* ==========================================================================
|
|
175
|
+
Context Card (browser tab preview shown between user msg and assistant response)
|
|
176
|
+
========================================================================== */
|
|
177
|
+
|
|
178
|
+
.context-card {
|
|
179
|
+
max-width: 400px;
|
|
180
|
+
margin: 8px auto 12px;
|
|
181
|
+
padding: 12px;
|
|
182
|
+
background: var(--bg-alt);
|
|
183
|
+
border: 1px solid var(--border);
|
|
184
|
+
border-radius: 10px;
|
|
185
|
+
box-shadow: 0 1px 3px rgba(var(--shadow-rgb), 0.08);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.context-card-header {
|
|
189
|
+
display: flex;
|
|
190
|
+
align-items: center;
|
|
191
|
+
gap: 6px;
|
|
192
|
+
margin-bottom: 10px;
|
|
193
|
+
font-size: 11px;
|
|
194
|
+
color: var(--text-muted);
|
|
195
|
+
letter-spacing: 0.02em;
|
|
196
|
+
font-weight: 500;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.context-card-header .context-card-icon {
|
|
200
|
+
font-size: 13px;
|
|
201
|
+
opacity: 0.7;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.context-card-screenshot {
|
|
205
|
+
display: block;
|
|
206
|
+
width: 100%;
|
|
207
|
+
max-height: 200px;
|
|
208
|
+
object-fit: contain;
|
|
209
|
+
border-radius: 8px;
|
|
210
|
+
background: var(--bg);
|
|
211
|
+
cursor: pointer;
|
|
212
|
+
transition: transform 0.15s ease;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.context-card-screenshot:hover {
|
|
216
|
+
transform: scale(1.01);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.context-card-skeleton {
|
|
220
|
+
width: 100%;
|
|
221
|
+
height: 120px;
|
|
222
|
+
border-radius: 8px;
|
|
223
|
+
background: var(--bg);
|
|
224
|
+
animation: skeleton-shimmer 1.5s ease-in-out infinite;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.context-card-meta {
|
|
228
|
+
display: flex;
|
|
229
|
+
justify-content: space-between;
|
|
230
|
+
align-items: baseline;
|
|
231
|
+
margin-top: 8px;
|
|
232
|
+
gap: 12px;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
.context-card-title {
|
|
236
|
+
font-size: 12px;
|
|
237
|
+
color: var(--text-muted);
|
|
238
|
+
white-space: nowrap;
|
|
239
|
+
overflow: hidden;
|
|
240
|
+
text-overflow: ellipsis;
|
|
241
|
+
flex: 1;
|
|
242
|
+
min-width: 0;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.context-card-domain {
|
|
246
|
+
font-size: 11px;
|
|
247
|
+
color: var(--text-dimmer);
|
|
248
|
+
font-family: monospace;
|
|
249
|
+
white-space: nowrap;
|
|
250
|
+
flex-shrink: 0;
|
|
251
|
+
}
|
|
252
|
+
|
|
174
253
|
/* ==========================================================================
|
|
175
254
|
Activity Indicator
|
|
176
255
|
========================================================================== */
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
display: inline-flex;
|
|
24
24
|
align-items: center;
|
|
25
25
|
gap: 4px;
|
|
26
|
-
background: color-mix(in srgb,
|
|
27
|
-
color:
|
|
26
|
+
background: color-mix(in srgb, #3b82f6 12%, transparent);
|
|
27
|
+
color: #3b82f6;
|
|
28
28
|
border: none;
|
|
29
29
|
border-radius: 10px;
|
|
30
30
|
padding: 2px 10px;
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
.top-bar-update-btn .lucide { width: 12px; height: 12px; }
|
|
41
|
-
.top-bar-update-btn:hover { background: color-mix(in srgb,
|
|
41
|
+
.top-bar-update-btn:hover { background: color-mix(in srgb, #3b82f6 20%, transparent); }
|
|
42
42
|
|
|
43
43
|
/* --- Top bar actions (right-aligned group) --- */
|
|
44
44
|
.top-bar-actions {
|
package/lib/public/index.html
CHANGED
|
@@ -52,6 +52,28 @@
|
|
|
52
52
|
<div id="top-bar">
|
|
53
53
|
<div class="top-bar-left-pills">
|
|
54
54
|
<button id="pwa-install-pill" class="top-bar-install-btn hidden" title="Open as app"><i data-lucide="download"></i> Open as app</button>
|
|
55
|
+
<div id="ext-pill-wrap" class="ext-pill-wrap">
|
|
56
|
+
<button id="ext-pill" class="top-bar-ext-btn" title="Chrome Extension"><i data-lucide="puzzle"></i> Extension</button>
|
|
57
|
+
<div id="ext-popover" class="ext-popover">
|
|
58
|
+
<div class="ext-popover-header">
|
|
59
|
+
<div class="ext-popover-title">Clay for Chrome <span class="ext-experimental">Experimental</span></div>
|
|
60
|
+
<div class="ext-popover-sub">v0.1.0 · <a href="https://github.com/chadbyte/clay-chrome" target="_blank" rel="noopener">GitHub</a></div>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="ext-popover-connected hidden" id="ext-connected-banner"><i data-lucide="check-circle"></i> Extension connected</div>
|
|
63
|
+
<div class="ext-popover-desc" id="ext-popover-desc">Connect your browser to Clay. Gives Claude visibility into open tabs, console, network, DOM, and screenshots.</div>
|
|
64
|
+
<button class="ext-popover-download" id="ext-download-btn"><i data-lucide="download"></i> Download Extension (.zip)</button>
|
|
65
|
+
<div class="ext-popover-status hidden" id="ext-download-status"></div>
|
|
66
|
+
<div class="ext-popover-divider" id="ext-popover-divider"></div>
|
|
67
|
+
<div class="ext-popover-guide-title" id="ext-popover-guide-title">Installation</div>
|
|
68
|
+
<div class="ext-popover-steps">
|
|
69
|
+
<div class="ext-popover-step"><span class="ext-snum">1</span> Download above, then unzip to a permanent folder.</div>
|
|
70
|
+
<div class="ext-popover-step"><span class="ext-snum">2</span> Open <code id="ext-copy-url" class="ext-popover-code" title="Click to copy">chrome://extensions</code></div>
|
|
71
|
+
<div class="ext-popover-step"><span class="ext-snum">3</span> Enable <strong>Developer mode</strong> (top-right toggle).</div>
|
|
72
|
+
<div class="ext-popover-step"><span class="ext-snum">4</span> <strong>Load unpacked</strong> > select the unzipped folder.</div>
|
|
73
|
+
<div class="ext-popover-step"><span class="ext-snum">5</span> Refresh this page. Done!</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
55
77
|
<button id="share-pill" class="top-bar-share-btn" title="Share"><i data-lucide="qr-code"></i> Share</button>
|
|
56
78
|
<div id="update-pill-wrap" class="top-bar-update hidden">
|
|
57
79
|
<button id="update-pill" class="top-bar-update-btn"><i data-lucide="arrow-up-circle"></i> <span id="update-version"></span> is available. Update now</button>
|
|
@@ -420,9 +442,9 @@
|
|
|
420
442
|
<button id="context-sources-add" type="button" title="Add context source"><i data-lucide="plus"></i><span>Context Sources</span></button>
|
|
421
443
|
<div id="context-sources-picker" class="hidden">
|
|
422
444
|
<div class="context-picker-section" id="context-picker-terminals"></div>
|
|
445
|
+
<div class="context-picker-section" id="context-picker-tabs"></div>
|
|
423
446
|
</div>
|
|
424
447
|
</div>
|
|
425
|
-
<div id="suggestion-chips" class="hidden"></div>
|
|
426
448
|
<div id="input-row">
|
|
427
449
|
<div id="context-mini" class="hidden">
|
|
428
450
|
<div class="context-mini-bar">
|
|
@@ -431,6 +453,7 @@
|
|
|
431
453
|
<span class="context-mini-label" id="context-mini-label">0%</span>
|
|
432
454
|
</div>
|
|
433
455
|
<div id="image-preview-bar"></div>
|
|
456
|
+
<div id="suggestion-chips" class="hidden"></div>
|
|
434
457
|
<textarea id="input" rows="1" placeholder="Message Claude Code..." enterkeyhint="send" dir="auto"></textarea>
|
|
435
458
|
<div id="input-bottom">
|
|
436
459
|
<div id="attach-wrap">
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
// Context Sources — attach terminal output
|
|
1
|
+
// Context Sources — attach terminal output and browser tabs as context for Claude
|
|
2
2
|
|
|
3
3
|
var ctx = null;
|
|
4
4
|
var activeSourceIds = new Set();
|
|
5
5
|
var terminalList = []; // synced from terminal module's term_list
|
|
6
|
+
var browserTabList = []; // synced from Chrome extension via postMessage
|
|
6
7
|
|
|
7
8
|
export function initContextSources(_ctx) {
|
|
8
9
|
ctx = _ctx;
|
|
@@ -79,6 +80,36 @@ export function updateTerminalList(terminals) {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
// Called when Chrome extension sends tab list via postMessage
|
|
84
|
+
export function updateBrowserTabList(tabs) {
|
|
85
|
+
browserTabList = tabs || [];
|
|
86
|
+
|
|
87
|
+
// Remove active tab sources that no longer exist
|
|
88
|
+
var changed = false;
|
|
89
|
+
for (var id of activeSourceIds) {
|
|
90
|
+
if (id.startsWith("tab:")) {
|
|
91
|
+
var tabId = parseInt(id.split(":")[1], 10);
|
|
92
|
+
var found = false;
|
|
93
|
+
for (var i = 0; i < browserTabList.length; i++) {
|
|
94
|
+
if (browserTabList[i].id === tabId) { found = true; break; }
|
|
95
|
+
}
|
|
96
|
+
if (!found) {
|
|
97
|
+
activeSourceIds.delete(id);
|
|
98
|
+
changed = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (changed) saveToServer();
|
|
104
|
+
renderChips();
|
|
105
|
+
|
|
106
|
+
// If picker is open, re-render it
|
|
107
|
+
var picker = document.getElementById("context-sources-picker");
|
|
108
|
+
if (!picker.classList.contains("hidden")) {
|
|
109
|
+
renderPicker();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
82
113
|
function toggleSource(sourceId) {
|
|
83
114
|
if (activeSourceIds.has(sourceId)) {
|
|
84
115
|
activeSourceIds.delete(sourceId);
|
|
@@ -150,42 +181,87 @@ function renderChips() {
|
|
|
150
181
|
}
|
|
151
182
|
|
|
152
183
|
function renderPicker() {
|
|
153
|
-
|
|
154
|
-
|
|
184
|
+
// --- Terminals section ---
|
|
185
|
+
var termSection = document.getElementById("context-picker-terminals");
|
|
186
|
+
termSection.innerHTML = "";
|
|
155
187
|
|
|
156
|
-
var
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
188
|
+
var termLabel = document.createElement("div");
|
|
189
|
+
termLabel.className = "context-picker-section-label";
|
|
190
|
+
termLabel.textContent = "Terminals";
|
|
191
|
+
termSection.appendChild(termLabel);
|
|
160
192
|
|
|
161
193
|
if (terminalList.length === 0) {
|
|
162
|
-
var
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
194
|
+
var termEmpty = document.createElement("div");
|
|
195
|
+
termEmpty.className = "context-picker-empty";
|
|
196
|
+
termEmpty.textContent = "No terminals open";
|
|
197
|
+
termSection.appendChild(termEmpty);
|
|
198
|
+
} else {
|
|
199
|
+
for (var i = 0; i < terminalList.length; i++) {
|
|
200
|
+
var term = terminalList[i];
|
|
201
|
+
var termSourceId = "term:" + term.id;
|
|
202
|
+
var termActive = activeSourceIds.has(termSourceId);
|
|
168
203
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
var isActive = activeSourceIds.has(sourceId);
|
|
204
|
+
var termItem = document.createElement("div");
|
|
205
|
+
termItem.className = "context-picker-item" + (termActive ? " active" : "");
|
|
206
|
+
termItem.setAttribute("data-source-id", termSourceId);
|
|
173
207
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
208
|
+
termItem.innerHTML =
|
|
209
|
+
'<i data-lucide="square-terminal"></i>' +
|
|
210
|
+
'<span>' + escapeHtml(term.title || ("Terminal " + term.id)) + '</span>' +
|
|
211
|
+
'<i data-lucide="check" class="context-picker-check"></i>';
|
|
177
212
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
213
|
+
termItem.addEventListener("click", function() {
|
|
214
|
+
toggleSource(this.getAttribute("data-source-id"));
|
|
215
|
+
if (typeof lucide !== "undefined") lucide.createIcons();
|
|
216
|
+
});
|
|
182
217
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
218
|
+
termSection.appendChild(termItem);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// --- Browser Tabs section ---
|
|
223
|
+
var tabSection = document.getElementById("context-picker-tabs");
|
|
224
|
+
tabSection.innerHTML = "";
|
|
225
|
+
|
|
226
|
+
if (browserTabList.length > 0) {
|
|
227
|
+
var tabLabel = document.createElement("div");
|
|
228
|
+
tabLabel.className = "context-picker-section-label";
|
|
229
|
+
tabLabel.textContent = "Browser Tabs";
|
|
230
|
+
tabSection.appendChild(tabLabel);
|
|
231
|
+
|
|
232
|
+
for (var j = 0; j < browserTabList.length; j++) {
|
|
233
|
+
var tab = browserTabList[j];
|
|
234
|
+
var tabSourceId = "tab:" + tab.id;
|
|
235
|
+
var tabActive = activeSourceIds.has(tabSourceId);
|
|
236
|
+
|
|
237
|
+
var tabItem = document.createElement("div");
|
|
238
|
+
tabItem.className = "context-picker-item" + (tabActive ? " active" : "");
|
|
239
|
+
tabItem.setAttribute("data-source-id", tabSourceId);
|
|
240
|
+
|
|
241
|
+
var tabTitle = tab.title || tab.url || "Tab";
|
|
242
|
+
// Truncate long URLs for display
|
|
243
|
+
var tabDisplay = tabTitle.length > 50 ? tabTitle.slice(0, 47) + "..." : tabTitle;
|
|
244
|
+
|
|
245
|
+
var faviconHtml = "";
|
|
246
|
+
if (tab.favIconUrl) {
|
|
247
|
+
faviconHtml = '<img src="' + escapeHtml(tab.favIconUrl) + '" class="context-picker-favicon" onerror="this.style.display=\'none\';this.nextElementSibling.style.display=\'\'">' +
|
|
248
|
+
'<i data-lucide="globe" style="display:none"></i>';
|
|
249
|
+
} else {
|
|
250
|
+
faviconHtml = '<i data-lucide="globe"></i>';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
tabItem.innerHTML =
|
|
254
|
+
faviconHtml +
|
|
255
|
+
'<span title="' + escapeHtml(tab.url || "") + '">' + escapeHtml(tabDisplay) + '</span>' +
|
|
256
|
+
'<i data-lucide="check" class="context-picker-check"></i>';
|
|
257
|
+
|
|
258
|
+
tabItem.addEventListener("click", function() {
|
|
259
|
+
toggleSource(this.getAttribute("data-source-id"));
|
|
260
|
+
if (typeof lucide !== "undefined") lucide.createIcons();
|
|
261
|
+
});
|
|
187
262
|
|
|
188
|
-
|
|
263
|
+
tabSection.appendChild(tabItem);
|
|
264
|
+
}
|
|
189
265
|
}
|
|
190
266
|
|
|
191
267
|
if (typeof lucide !== "undefined") lucide.createIcons();
|
|
@@ -201,11 +277,22 @@ function getSourceLabel(id) {
|
|
|
201
277
|
}
|
|
202
278
|
return "Terminal " + termId;
|
|
203
279
|
}
|
|
280
|
+
if (id.startsWith("tab:")) {
|
|
281
|
+
var tabId = parseInt(id.split(":")[1], 10);
|
|
282
|
+
for (var j = 0; j < browserTabList.length; j++) {
|
|
283
|
+
if (browserTabList[j].id === tabId) {
|
|
284
|
+
var title = browserTabList[j].title || browserTabList[j].url || "";
|
|
285
|
+
return title.length > 30 ? title.slice(0, 27) + "..." : title;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return "Tab " + tabId;
|
|
289
|
+
}
|
|
204
290
|
return id;
|
|
205
291
|
}
|
|
206
292
|
|
|
207
293
|
function getSourceIcon(id) {
|
|
208
294
|
if (id.startsWith("term:")) return "square-terminal";
|
|
295
|
+
if (id.startsWith("tab:")) return "globe";
|
|
209
296
|
return "circle";
|
|
210
297
|
}
|
|
211
298
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { copyToClipboard } from './utils.js';
|
|
1
|
+
import { copyToClipboard, showToast } from './utils.js';
|
|
2
2
|
import { iconHtml, refreshIcons } from './icons.js';
|
|
3
3
|
|
|
4
4
|
var ctx;
|
|
@@ -155,6 +155,114 @@ export function initNotifications(_ctx) {
|
|
|
155
155
|
});
|
|
156
156
|
})();
|
|
157
157
|
|
|
158
|
+
// --- Extension pill popover ---
|
|
159
|
+
(function () {
|
|
160
|
+
var extPillWrap = $("ext-pill-wrap");
|
|
161
|
+
var extPillBtn = $("ext-pill");
|
|
162
|
+
var extPopover = $("ext-popover");
|
|
163
|
+
var extDownloadBtn = $("ext-download-btn");
|
|
164
|
+
var extDownloadStatus = $("ext-download-status");
|
|
165
|
+
var extCopyUrl = $("ext-copy-url");
|
|
166
|
+
if (!extPillWrap || !extPillBtn || !extPopover) return;
|
|
167
|
+
|
|
168
|
+
// Detect extension connection via postMessage from content.js
|
|
169
|
+
var extConnected = false;
|
|
170
|
+
var connectedBanner = $("ext-connected-banner");
|
|
171
|
+
var extDesc = $("ext-popover-desc");
|
|
172
|
+
var extDivider = $("ext-popover-divider");
|
|
173
|
+
var extGuideTitle = $("ext-popover-guide-title");
|
|
174
|
+
var extSteps = extPopover.querySelector(".ext-popover-steps");
|
|
175
|
+
|
|
176
|
+
function setExtConnected() {
|
|
177
|
+
if (extConnected) return;
|
|
178
|
+
extConnected = true;
|
|
179
|
+
extPillBtn.classList.add("ext-connected");
|
|
180
|
+
extPillBtn.innerHTML = '<i data-lucide="check"></i> Extension';
|
|
181
|
+
refreshIcons(extPillBtn);
|
|
182
|
+
if (connectedBanner) connectedBanner.classList.remove("hidden");
|
|
183
|
+
if (extDownloadBtn) extDownloadBtn.style.display = "none";
|
|
184
|
+
if (extDownloadStatus) extDownloadStatus.classList.add("hidden");
|
|
185
|
+
if (extDesc) extDesc.style.display = "none";
|
|
186
|
+
if (extDivider) extDivider.style.display = "none";
|
|
187
|
+
if (extGuideTitle) extGuideTitle.style.display = "none";
|
|
188
|
+
if (extSteps) extSteps.style.display = "none";
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
window.addEventListener("message", function (event) {
|
|
192
|
+
if (event.source !== window) return;
|
|
193
|
+
if (!event.data || event.data.source !== "clay-chrome-extension") return;
|
|
194
|
+
setExtConnected();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Toggle popover
|
|
198
|
+
extPillBtn.addEventListener("click", function (e) {
|
|
199
|
+
e.stopPropagation();
|
|
200
|
+
extPopover.classList.toggle("visible");
|
|
201
|
+
refreshIcons(extPopover);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
document.addEventListener("click", function (e) {
|
|
205
|
+
if (!extPopover.contains(e.target) && e.target !== extPillBtn && !extPillBtn.contains(e.target)) {
|
|
206
|
+
extPopover.classList.remove("visible");
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Download button
|
|
211
|
+
if (extDownloadBtn) {
|
|
212
|
+
extDownloadBtn.addEventListener("click", function (e) {
|
|
213
|
+
e.stopPropagation();
|
|
214
|
+
extDownloadBtn.disabled = true;
|
|
215
|
+
extDownloadBtn.innerHTML = iconHtml("loader") + " Downloading...";
|
|
216
|
+
refreshIcons(extDownloadBtn);
|
|
217
|
+
var loaderIcon = extDownloadBtn.querySelector(".lucide");
|
|
218
|
+
if (loaderIcon) loaderIcon.style.animation = "spin 1s linear infinite";
|
|
219
|
+
if (extDownloadStatus) {
|
|
220
|
+
extDownloadStatus.classList.remove("hidden");
|
|
221
|
+
extDownloadStatus.textContent = "Fetching from GitHub...";
|
|
222
|
+
extDownloadStatus.style.color = "";
|
|
223
|
+
}
|
|
224
|
+
fetch("/api/extension/download").then(function (resp) {
|
|
225
|
+
if (!resp.ok) throw new Error("Download failed (" + resp.status + ")");
|
|
226
|
+
return resp.blob();
|
|
227
|
+
}).then(function (blob) {
|
|
228
|
+
var url = URL.createObjectURL(blob);
|
|
229
|
+
var a = document.createElement("a");
|
|
230
|
+
a.href = url;
|
|
231
|
+
a.download = "clay-chrome-extension.zip";
|
|
232
|
+
document.body.appendChild(a);
|
|
233
|
+
a.click();
|
|
234
|
+
document.body.removeChild(a);
|
|
235
|
+
URL.revokeObjectURL(url);
|
|
236
|
+
if (extDownloadStatus) {
|
|
237
|
+
extDownloadStatus.textContent = "Download complete!";
|
|
238
|
+
extDownloadStatus.style.color = "var(--accent)";
|
|
239
|
+
}
|
|
240
|
+
showToast("Extension downloaded");
|
|
241
|
+
}).catch(function (err) {
|
|
242
|
+
if (extDownloadStatus) {
|
|
243
|
+
extDownloadStatus.textContent = "Failed: " + err.message;
|
|
244
|
+
extDownloadStatus.style.color = "var(--danger, #e53935)";
|
|
245
|
+
}
|
|
246
|
+
showToast("Download failed");
|
|
247
|
+
}).finally(function () {
|
|
248
|
+
extDownloadBtn.disabled = false;
|
|
249
|
+
extDownloadBtn.innerHTML = iconHtml("download") + " Download Extension (.zip)";
|
|
250
|
+
refreshIcons(extDownloadBtn);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Copy chrome://extensions URL
|
|
256
|
+
if (extCopyUrl) {
|
|
257
|
+
extCopyUrl.addEventListener("click", function (e) {
|
|
258
|
+
e.stopPropagation();
|
|
259
|
+
copyToClipboard("chrome://extensions").then(function () {
|
|
260
|
+
showToast("Copied chrome://extensions");
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
})();
|
|
265
|
+
|
|
158
266
|
// --- Settings: Check for updates ---
|
|
159
267
|
(function () {
|
|
160
268
|
var settingsUpdateCheck = $("settings-update-check");
|
package/lib/sdk-bridge.js
CHANGED
|
@@ -134,6 +134,7 @@ function createSDKBridge(opts) {
|
|
|
134
134
|
var mateDisplayName = opts.mateDisplayName || "";
|
|
135
135
|
var isMate = opts.isMate || (slug.indexOf("mate-") === 0);
|
|
136
136
|
var dangerouslySkipPermissions = opts.dangerouslySkipPermissions || false;
|
|
137
|
+
var mcpServers = opts.mcpServers || null;
|
|
137
138
|
var onProcessingChanged = opts.onProcessingChanged || function () {};
|
|
138
139
|
var onTurnDone = opts.onTurnDone || null;
|
|
139
140
|
|
|
@@ -1128,6 +1129,7 @@ function createSDKBridge(opts) {
|
|
|
1128
1129
|
agentProgressSummaries: true,
|
|
1129
1130
|
};
|
|
1130
1131
|
|
|
1132
|
+
if (mcpServers) queryOptions.mcpServers = mcpServers;
|
|
1131
1133
|
if (sm.currentModel) queryOptions.model = sm.currentModel;
|
|
1132
1134
|
if (sm.currentEffort) queryOptions.effort = sm.currentEffort;
|
|
1133
1135
|
if (sm.currentBetas && sm.currentBetas.length > 0) queryOptions.betas = sm.currentBetas;
|
|
@@ -1940,6 +1942,7 @@ function createSDKBridge(opts) {
|
|
|
1940
1942
|
abortController: session.abortController,
|
|
1941
1943
|
promptSuggestions: true,
|
|
1942
1944
|
agentProgressSummaries: true,
|
|
1945
|
+
mcpServers: mcpServers || undefined,
|
|
1943
1946
|
canUseTool: function(toolName, input, toolOpts) {
|
|
1944
1947
|
return handleCanUseTool(session, toolName, input, toolOpts);
|
|
1945
1948
|
},
|