screenpipe-mcp 0.4.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +58 -559
- package/manifest.json +5 -1
- package/package.json +2 -2
- package/src/index.ts +58 -606
- package/ui/search.html +559 -0
package/ui/search.html
ADDED
|
@@ -0,0 +1,559 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>screenpipe search</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
box-sizing: border-box;
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
16
|
+
background: #0a0a0a;
|
|
17
|
+
color: #fafafa;
|
|
18
|
+
padding: 16px;
|
|
19
|
+
min-height: 100vh;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.container {
|
|
23
|
+
max-width: 700px;
|
|
24
|
+
margin: 0 auto;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.header {
|
|
28
|
+
display: flex;
|
|
29
|
+
align-items: center;
|
|
30
|
+
gap: 10px;
|
|
31
|
+
margin-bottom: 20px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.header h1 {
|
|
35
|
+
font-size: 18px;
|
|
36
|
+
font-weight: 600;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.logo {
|
|
40
|
+
width: 24px;
|
|
41
|
+
height: 24px;
|
|
42
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
43
|
+
border-radius: 6px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.search-box {
|
|
47
|
+
display: flex;
|
|
48
|
+
gap: 8px;
|
|
49
|
+
margin-bottom: 16px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.search-input {
|
|
53
|
+
flex: 1;
|
|
54
|
+
padding: 12px 16px;
|
|
55
|
+
border: 1px solid #333;
|
|
56
|
+
border-radius: 8px;
|
|
57
|
+
background: #1a1a1a;
|
|
58
|
+
color: #fff;
|
|
59
|
+
font-size: 14px;
|
|
60
|
+
outline: none;
|
|
61
|
+
transition: border-color 0.2s;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.search-input:focus {
|
|
65
|
+
border-color: #666;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.search-input::placeholder {
|
|
69
|
+
color: #666;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.btn {
|
|
73
|
+
padding: 12px 20px;
|
|
74
|
+
border: none;
|
|
75
|
+
border-radius: 8px;
|
|
76
|
+
font-size: 14px;
|
|
77
|
+
font-weight: 500;
|
|
78
|
+
cursor: pointer;
|
|
79
|
+
transition: all 0.2s;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.btn-primary {
|
|
83
|
+
background: #fff;
|
|
84
|
+
color: #000;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.btn-primary:hover {
|
|
88
|
+
background: #e0e0e0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.btn-secondary {
|
|
92
|
+
background: #1a1a1a;
|
|
93
|
+
color: #fff;
|
|
94
|
+
border: 1px solid #333;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.btn-secondary:hover {
|
|
98
|
+
background: #252525;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.filters {
|
|
102
|
+
display: flex;
|
|
103
|
+
gap: 8px;
|
|
104
|
+
margin-bottom: 20px;
|
|
105
|
+
flex-wrap: wrap;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.filter-btn {
|
|
109
|
+
padding: 6px 14px;
|
|
110
|
+
border: 1px solid #333;
|
|
111
|
+
border-radius: 20px;
|
|
112
|
+
background: transparent;
|
|
113
|
+
color: #888;
|
|
114
|
+
font-size: 13px;
|
|
115
|
+
cursor: pointer;
|
|
116
|
+
transition: all 0.2s;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.filter-btn:hover {
|
|
120
|
+
border-color: #555;
|
|
121
|
+
color: #fff;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.filter-btn.active {
|
|
125
|
+
background: #fff;
|
|
126
|
+
color: #000;
|
|
127
|
+
border-color: #fff;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.stats {
|
|
131
|
+
display: flex;
|
|
132
|
+
gap: 20px;
|
|
133
|
+
padding: 12px 16px;
|
|
134
|
+
background: #1a1a1a;
|
|
135
|
+
border-radius: 8px;
|
|
136
|
+
margin-bottom: 20px;
|
|
137
|
+
font-size: 13px;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.stat {
|
|
141
|
+
display: flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
gap: 6px;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.stat-value {
|
|
147
|
+
font-weight: 600;
|
|
148
|
+
color: #fff;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.stat-label {
|
|
152
|
+
color: #666;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.results {
|
|
156
|
+
display: flex;
|
|
157
|
+
flex-direction: column;
|
|
158
|
+
gap: 12px;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.result-card {
|
|
162
|
+
background: #1a1a1a;
|
|
163
|
+
border: 1px solid #252525;
|
|
164
|
+
border-radius: 10px;
|
|
165
|
+
padding: 16px;
|
|
166
|
+
transition: border-color 0.2s;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.result-card:hover {
|
|
170
|
+
border-color: #333;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.result-header {
|
|
174
|
+
display: flex;
|
|
175
|
+
justify-content: space-between;
|
|
176
|
+
align-items: flex-start;
|
|
177
|
+
margin-bottom: 10px;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.result-type {
|
|
181
|
+
display: inline-flex;
|
|
182
|
+
align-items: center;
|
|
183
|
+
gap: 6px;
|
|
184
|
+
padding: 4px 10px;
|
|
185
|
+
border-radius: 4px;
|
|
186
|
+
font-size: 11px;
|
|
187
|
+
font-weight: 600;
|
|
188
|
+
text-transform: uppercase;
|
|
189
|
+
letter-spacing: 0.5px;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.type-ocr {
|
|
193
|
+
background: rgba(59, 130, 246, 0.2);
|
|
194
|
+
color: #60a5fa;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.type-audio {
|
|
198
|
+
background: rgba(34, 197, 94, 0.2);
|
|
199
|
+
color: #4ade80;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.type-ui {
|
|
203
|
+
background: rgba(168, 85, 247, 0.2);
|
|
204
|
+
color: #c084fc;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.result-time {
|
|
208
|
+
font-size: 12px;
|
|
209
|
+
color: #666;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.result-app {
|
|
213
|
+
font-size: 13px;
|
|
214
|
+
color: #888;
|
|
215
|
+
margin-bottom: 8px;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.result-text {
|
|
219
|
+
font-size: 14px;
|
|
220
|
+
line-height: 1.5;
|
|
221
|
+
color: #ccc;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.result-actions {
|
|
225
|
+
display: flex;
|
|
226
|
+
gap: 8px;
|
|
227
|
+
margin-top: 12px;
|
|
228
|
+
padding-top: 12px;
|
|
229
|
+
border-top: 1px solid #252525;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.action-btn {
|
|
233
|
+
padding: 6px 12px;
|
|
234
|
+
border: 1px solid #333;
|
|
235
|
+
border-radius: 6px;
|
|
236
|
+
background: transparent;
|
|
237
|
+
color: #888;
|
|
238
|
+
font-size: 12px;
|
|
239
|
+
cursor: pointer;
|
|
240
|
+
transition: all 0.2s;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.action-btn:hover {
|
|
244
|
+
border-color: #555;
|
|
245
|
+
color: #fff;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.empty-state {
|
|
249
|
+
text-align: center;
|
|
250
|
+
padding: 60px 20px;
|
|
251
|
+
color: #666;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.empty-state h3 {
|
|
255
|
+
font-size: 16px;
|
|
256
|
+
margin-bottom: 8px;
|
|
257
|
+
color: #888;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.loading {
|
|
261
|
+
display: flex;
|
|
262
|
+
justify-content: center;
|
|
263
|
+
padding: 40px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.spinner {
|
|
267
|
+
width: 24px;
|
|
268
|
+
height: 24px;
|
|
269
|
+
border: 2px solid #333;
|
|
270
|
+
border-top-color: #fff;
|
|
271
|
+
border-radius: 50%;
|
|
272
|
+
animation: spin 0.8s linear infinite;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
@keyframes spin {
|
|
276
|
+
to { transform: rotate(360deg); }
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.hidden {
|
|
280
|
+
display: none;
|
|
281
|
+
}
|
|
282
|
+
</style>
|
|
283
|
+
</head>
|
|
284
|
+
<body>
|
|
285
|
+
<div class="container">
|
|
286
|
+
<div class="header">
|
|
287
|
+
<div class="logo"></div>
|
|
288
|
+
<h1>screenpipe search</h1>
|
|
289
|
+
</div>
|
|
290
|
+
|
|
291
|
+
<div class="search-box">
|
|
292
|
+
<input
|
|
293
|
+
type="text"
|
|
294
|
+
id="query"
|
|
295
|
+
class="search-input"
|
|
296
|
+
placeholder="search your screen history, audio, and more..."
|
|
297
|
+
onkeydown="if(event.key==='Enter')search()"
|
|
298
|
+
/>
|
|
299
|
+
<button class="btn btn-primary" onclick="search()">search</button>
|
|
300
|
+
</div>
|
|
301
|
+
|
|
302
|
+
<div class="filters">
|
|
303
|
+
<button class="filter-btn active" data-type="all" onclick="setFilter('all')">all</button>
|
|
304
|
+
<button class="filter-btn" data-type="ocr" onclick="setFilter('ocr')">screen</button>
|
|
305
|
+
<button class="filter-btn" data-type="audio" onclick="setFilter('audio')">audio</button>
|
|
306
|
+
<button class="filter-btn" data-type="ui" onclick="setFilter('ui')">ui elements</button>
|
|
307
|
+
</div>
|
|
308
|
+
|
|
309
|
+
<div id="stats" class="stats hidden">
|
|
310
|
+
<div class="stat">
|
|
311
|
+
<span class="stat-value" id="result-count">0</span>
|
|
312
|
+
<span class="stat-label">results</span>
|
|
313
|
+
</div>
|
|
314
|
+
<div class="stat">
|
|
315
|
+
<span class="stat-value" id="time-range">-</span>
|
|
316
|
+
<span class="stat-label">time range</span>
|
|
317
|
+
</div>
|
|
318
|
+
</div>
|
|
319
|
+
|
|
320
|
+
<div id="loading" class="loading hidden">
|
|
321
|
+
<div class="spinner"></div>
|
|
322
|
+
</div>
|
|
323
|
+
|
|
324
|
+
<div id="results" class="results">
|
|
325
|
+
<div class="empty-state">
|
|
326
|
+
<h3>search your digital history</h3>
|
|
327
|
+
<p>type a query above to search through your screen recordings and audio transcriptions</p>
|
|
328
|
+
</div>
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
|
|
332
|
+
<script>
|
|
333
|
+
let currentFilter = 'all';
|
|
334
|
+
let pendingRequestId = null;
|
|
335
|
+
|
|
336
|
+
// MCP App communication layer
|
|
337
|
+
const mcp = {
|
|
338
|
+
requestId: 0,
|
|
339
|
+
|
|
340
|
+
callTool: function(name, args) {
|
|
341
|
+
this.requestId++;
|
|
342
|
+
pendingRequestId = this.requestId;
|
|
343
|
+
window.parent.postMessage({
|
|
344
|
+
jsonrpc: '2.0',
|
|
345
|
+
id: this.requestId,
|
|
346
|
+
method: 'tools/call',
|
|
347
|
+
params: { name, arguments: args }
|
|
348
|
+
}, '*');
|
|
349
|
+
return this.requestId;
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
sendMessage: function(text) {
|
|
353
|
+
window.parent.postMessage({
|
|
354
|
+
jsonrpc: '2.0',
|
|
355
|
+
method: 'message/send',
|
|
356
|
+
params: { content: text }
|
|
357
|
+
}, '*');
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// listen for messages from host
|
|
362
|
+
window.addEventListener('message', (event) => {
|
|
363
|
+
const data = event.data;
|
|
364
|
+
|
|
365
|
+
// handle tool results
|
|
366
|
+
if (data?.result || data?.method === 'tool/result') {
|
|
367
|
+
hideLoading();
|
|
368
|
+
const result = data.result || data.params?.result;
|
|
369
|
+
if (result) {
|
|
370
|
+
displayResults(result);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// handle errors
|
|
375
|
+
if (data?.error) {
|
|
376
|
+
hideLoading();
|
|
377
|
+
showError(data.error.message || 'search failed');
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
function setFilter(type) {
|
|
382
|
+
currentFilter = type;
|
|
383
|
+
document.querySelectorAll('.filter-btn').forEach(btn => {
|
|
384
|
+
btn.classList.toggle('active', btn.dataset.type === type);
|
|
385
|
+
});
|
|
386
|
+
// re-run search with new filter if there's a query
|
|
387
|
+
const query = document.getElementById('query').value;
|
|
388
|
+
if (query) {
|
|
389
|
+
search();
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function search() {
|
|
394
|
+
const query = document.getElementById('query').value;
|
|
395
|
+
showLoading();
|
|
396
|
+
|
|
397
|
+
const args = {
|
|
398
|
+
q: query || undefined,
|
|
399
|
+
content_type: currentFilter,
|
|
400
|
+
limit: 20
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
mcp.callTool('search-content', args);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function showLoading() {
|
|
407
|
+
document.getElementById('loading').classList.remove('hidden');
|
|
408
|
+
document.getElementById('results').innerHTML = '';
|
|
409
|
+
document.getElementById('stats').classList.add('hidden');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function hideLoading() {
|
|
413
|
+
document.getElementById('loading').classList.add('hidden');
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function showError(message) {
|
|
417
|
+
document.getElementById('results').innerHTML = `
|
|
418
|
+
<div class="empty-state">
|
|
419
|
+
<h3>error</h3>
|
|
420
|
+
<p>${escapeHtml(message)}</p>
|
|
421
|
+
</div>
|
|
422
|
+
`;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
function displayResults(data) {
|
|
426
|
+
const results = data.data || data || [];
|
|
427
|
+
const container = document.getElementById('results');
|
|
428
|
+
const statsEl = document.getElementById('stats');
|
|
429
|
+
|
|
430
|
+
if (!Array.isArray(results) || results.length === 0) {
|
|
431
|
+
container.innerHTML = `
|
|
432
|
+
<div class="empty-state">
|
|
433
|
+
<h3>no results found</h3>
|
|
434
|
+
<p>try a different search term or adjust your filters</p>
|
|
435
|
+
</div>
|
|
436
|
+
`;
|
|
437
|
+
statsEl.classList.add('hidden');
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// update stats
|
|
442
|
+
document.getElementById('result-count').textContent = results.length;
|
|
443
|
+
|
|
444
|
+
// calculate time range
|
|
445
|
+
const timestamps = results
|
|
446
|
+
.map(r => r.content?.timestamp)
|
|
447
|
+
.filter(Boolean)
|
|
448
|
+
.map(t => new Date(t).getTime())
|
|
449
|
+
.sort((a, b) => a - b);
|
|
450
|
+
|
|
451
|
+
if (timestamps.length > 1) {
|
|
452
|
+
const start = new Date(timestamps[0]);
|
|
453
|
+
const end = new Date(timestamps[timestamps.length - 1]);
|
|
454
|
+
document.getElementById('time-range').textContent = formatTimeRange(start, end);
|
|
455
|
+
} else {
|
|
456
|
+
document.getElementById('time-range').textContent = 'now';
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
statsEl.classList.remove('hidden');
|
|
460
|
+
|
|
461
|
+
// render results
|
|
462
|
+
container.innerHTML = results.map(result => {
|
|
463
|
+
const content = result.content || {};
|
|
464
|
+
const type = result.type?.toLowerCase() || 'unknown';
|
|
465
|
+
const text = content.text || content.transcription || '';
|
|
466
|
+
const app = content.app_name || content.device_name || 'unknown';
|
|
467
|
+
const window = content.window_name || '';
|
|
468
|
+
const time = content.timestamp ? formatTime(new Date(content.timestamp)) : '';
|
|
469
|
+
|
|
470
|
+
return `
|
|
471
|
+
<div class="result-card">
|
|
472
|
+
<div class="result-header">
|
|
473
|
+
<span class="result-type type-${type}">${getTypeIcon(type)} ${type}</span>
|
|
474
|
+
<span class="result-time">${time}</span>
|
|
475
|
+
</div>
|
|
476
|
+
<div class="result-app">${escapeHtml(app)}${window ? ' - ' + escapeHtml(window) : ''}</div>
|
|
477
|
+
<div class="result-text">${escapeHtml(truncate(text, 300))}</div>
|
|
478
|
+
<div class="result-actions">
|
|
479
|
+
<button class="action-btn" onclick="copyText('${escapeJs(text)}')">copy</button>
|
|
480
|
+
<button class="action-btn" onclick="askAbout('${escapeJs(text.substring(0, 100))}')">ask AI</button>
|
|
481
|
+
</div>
|
|
482
|
+
</div>
|
|
483
|
+
`;
|
|
484
|
+
}).join('');
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function getTypeIcon(type) {
|
|
488
|
+
switch(type) {
|
|
489
|
+
case 'ocr': return '';
|
|
490
|
+
case 'audio': return '';
|
|
491
|
+
case 'ui': return '';
|
|
492
|
+
default: return '';
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function formatTime(date) {
|
|
497
|
+
const now = new Date();
|
|
498
|
+
const diff = now - date;
|
|
499
|
+
|
|
500
|
+
if (diff < 60000) return 'just now';
|
|
501
|
+
if (diff < 3600000) return Math.floor(diff / 60000) + 'm ago';
|
|
502
|
+
if (diff < 86400000) return Math.floor(diff / 3600000) + 'h ago';
|
|
503
|
+
|
|
504
|
+
return date.toLocaleDateString('en-US', {
|
|
505
|
+
month: 'short',
|
|
506
|
+
day: 'numeric',
|
|
507
|
+
hour: 'numeric',
|
|
508
|
+
minute: '2-digit'
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function formatTimeRange(start, end) {
|
|
513
|
+
const diff = end - start;
|
|
514
|
+
if (diff < 3600000) return Math.floor(diff / 60000) + ' min';
|
|
515
|
+
if (diff < 86400000) return Math.floor(diff / 3600000) + ' hours';
|
|
516
|
+
return Math.floor(diff / 86400000) + ' days';
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
function truncate(str, len) {
|
|
520
|
+
if (!str) return '';
|
|
521
|
+
if (str.length <= len) return str;
|
|
522
|
+
return str.substring(0, len) + '...';
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function escapeHtml(str) {
|
|
526
|
+
if (!str) return '';
|
|
527
|
+
return str
|
|
528
|
+
.replace(/&/g, '&')
|
|
529
|
+
.replace(/</g, '<')
|
|
530
|
+
.replace(/>/g, '>')
|
|
531
|
+
.replace(/"/g, '"')
|
|
532
|
+
.replace(/'/g, ''');
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function escapeJs(str) {
|
|
536
|
+
if (!str) return '';
|
|
537
|
+
return str
|
|
538
|
+
.replace(/\\/g, '\\\\')
|
|
539
|
+
.replace(/'/g, "\\'")
|
|
540
|
+
.replace(/"/g, '\\"')
|
|
541
|
+
.replace(/\n/g, '\\n')
|
|
542
|
+
.replace(/\r/g, '\\r');
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function copyText(text) {
|
|
546
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
547
|
+
// could show a toast here
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function askAbout(text) {
|
|
552
|
+
mcp.sendMessage(`Tell me more about: "${text}"`);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// auto-focus search input
|
|
556
|
+
document.getElementById('query').focus();
|
|
557
|
+
</script>
|
|
558
|
+
</body>
|
|
559
|
+
</html>
|