@ericmhalvorsen/aperture 0.2.1

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.
@@ -0,0 +1,600 @@
1
+ export function injectStyles() {
2
+ if (typeof document === "undefined")
3
+ return;
4
+ const styleId = "aperture-styles";
5
+ if (document.getElementById(styleId))
6
+ return;
7
+ const style = document.createElement("style");
8
+ style.id = styleId;
9
+ style.textContent = `
10
+ :root {
11
+ --ap-bg: #0f0f10;
12
+ --ap-bg-glass: rgba(15, 15, 16, 0.92);
13
+ --ap-border: rgba(255, 255, 255, 0.10);
14
+ --ap-text: #f3f4f6;
15
+ --ap-text-secondary: #9ca3af;
16
+ --ap-text-muted: #6b7280;
17
+ --ap-accent: #6366f1;
18
+ --ap-accent-hover: #4f46e5;
19
+ --ap-btn-deny-bg: rgba(255, 255, 255, 0.06);
20
+ --ap-btn-deny-border: rgba(255, 255, 255, 0.12);
21
+ --ap-btn-deny-text: #d1d5db;
22
+ --ap-warning-bg: rgba(239, 68, 68, 0.10);
23
+ --ap-warning-border: rgba(239, 68, 68, 0.25);
24
+ --ap-warning-text: #fca5a5;
25
+ --ap-shadow: 0 24px 64px rgba(0, 0, 0, 0.50);
26
+ }
27
+
28
+ @media (prefers-color-scheme: light) {
29
+ :root {
30
+ --ap-bg: #ffffff;
31
+ --ap-bg-glass: rgba(255, 255, 255, 0.96);
32
+ --ap-border: rgba(0, 0, 0, 0.10);
33
+ --ap-text: #111827;
34
+ --ap-text-secondary: #4b5563;
35
+ --ap-text-muted: #9ca3af;
36
+ --ap-btn-deny-bg: rgba(0, 0, 0, 0.04);
37
+ --ap-btn-deny-border: rgba(0, 0, 0, 0.10);
38
+ --ap-btn-deny-text: #374151;
39
+ --ap-warning-bg: rgba(239, 68, 68, 0.06);
40
+ --ap-warning-border: rgba(239, 68, 68, 0.18);
41
+ --ap-warning-text: #b91c1c;
42
+ --ap-shadow: 0 24px 64px rgba(0, 0, 0, 0.15);
43
+ }
44
+ }
45
+
46
+ #aperture-badge,
47
+ #aperture-dialog-overlay,
48
+ #aperture-dialog,
49
+ #aperture-dialog .aperture-header,
50
+ #aperture-dialog .aperture-icon,
51
+ #aperture-dialog .aperture-title-container,
52
+ #aperture-dialog .aperture-title,
53
+ #aperture-dialog .aperture-subtitle,
54
+ #aperture-dialog .aperture-body,
55
+ #aperture-dialog .aperture-list,
56
+ #aperture-dialog .aperture-list li,
57
+ #aperture-dialog .aperture-options,
58
+ #aperture-dialog .aperture-checkbox-label,
59
+ #aperture-dialog .aperture-checkbox-label input,
60
+ #aperture-dialog .aperture-checkbox-desc,
61
+ #aperture-dialog .aperture-warning-box,
62
+ #aperture-dialog .aperture-footer,
63
+ #aperture-dialog .aperture-btn {
64
+ all: initial;
65
+ box-sizing: border-box;
66
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
67
+ }
68
+
69
+ #aperture-badge {
70
+ position: fixed;
71
+ bottom: 12px;
72
+ right: 12px;
73
+ z-index: 2147483646;
74
+ display: flex;
75
+ align-items: center;
76
+ gap: 8px;
77
+ padding: 6px 12px;
78
+ border-radius: 20px;
79
+ background: var(--ap-bg-glass);
80
+ backdrop-filter: blur(12px);
81
+ -webkit-backdrop-filter: blur(12px);
82
+ border: 1px solid var(--ap-border);
83
+ color: var(--ap-text);
84
+ font-size: 11px;
85
+ font-weight: 500;
86
+ box-shadow: var(--ap-shadow);
87
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
88
+ cursor: pointer;
89
+ user-select: none;
90
+ }
91
+
92
+ #aperture-badge:hover {
93
+ transform: translateY(-2px);
94
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.30);
95
+ }
96
+
97
+ #aperture-badge .dot {
98
+ width: 8px;
99
+ height: 8px;
100
+ border-radius: 50%;
101
+ transition: background-color 0.3s ease;
102
+ }
103
+
104
+ #aperture-badge .dot.connected {
105
+ background-color: #10b981;
106
+ box-shadow: 0 0 8px #10b981;
107
+ animation: aperture-pulse 2s infinite;
108
+ }
109
+
110
+ #aperture-badge .dot.connecting {
111
+ background-color: #f59e0b;
112
+ box-shadow: 0 0 8px #f59e0b;
113
+ }
114
+
115
+ #aperture-badge .dot.disconnected {
116
+ background-color: #ef4444;
117
+ box-shadow: 0 0 8px #ef4444;
118
+ }
119
+
120
+ @keyframes aperture-pulse {
121
+ 0% { transform: scale(1); opacity: 1; }
122
+ 50% { transform: scale(1.2); opacity: 0.7; }
123
+ 100% { transform: scale(1); opacity: 1; }
124
+ }
125
+
126
+ #aperture-dialog-overlay {
127
+ position: fixed;
128
+ inset: 0;
129
+ background: rgba(0, 0, 0, 0.45);
130
+ backdrop-filter: blur(6px);
131
+ -webkit-backdrop-filter: blur(6px);
132
+ z-index: 2147483647;
133
+ display: flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ opacity: 0;
137
+ transition: opacity 0.2s ease;
138
+ color-scheme: light dark;
139
+ }
140
+
141
+ #aperture-dialog {
142
+ background: var(--ap-bg-glass);
143
+ backdrop-filter: blur(20px);
144
+ -webkit-backdrop-filter: blur(20px);
145
+ border: 1px solid var(--ap-border);
146
+ border-radius: 16px;
147
+ width: 400px;
148
+ max-width: 92vw;
149
+ max-height: 90vh;
150
+ overflow-y: auto;
151
+ box-shadow: var(--ap-shadow);
152
+ padding: 24px;
153
+ color: var(--ap-text);
154
+ transform: scale(0.96);
155
+ transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
156
+ line-height: 1.5;
157
+ }
158
+
159
+ #aperture-dialog-overlay.active {
160
+ opacity: 1;
161
+ }
162
+
163
+ #aperture-dialog-overlay.active #aperture-dialog {
164
+ transform: scale(1);
165
+ }
166
+
167
+ #aperture-dialog .aperture-header {
168
+ display: flex;
169
+ align-items: center;
170
+ gap: 14px;
171
+ margin-bottom: 20px;
172
+ }
173
+
174
+ #aperture-dialog .aperture-icon {
175
+ width: 42px;
176
+ height: 42px;
177
+ border-radius: 12px;
178
+ background: linear-gradient(135deg, var(--ap-accent), var(--ap-accent-hover));
179
+ display: flex;
180
+ align-items: center;
181
+ justify-content: center;
182
+ font-size: 20px;
183
+ line-height: 1;
184
+ flex-shrink: 0;
185
+ }
186
+
187
+ #aperture-dialog .aperture-title-container {
188
+ display: flex;
189
+ flex-direction: column;
190
+ }
191
+
192
+ #aperture-dialog .aperture-title {
193
+ font-size: 16px;
194
+ font-weight: 600;
195
+ color: var(--ap-text);
196
+ margin: 0;
197
+ }
198
+
199
+ #aperture-dialog .aperture-subtitle {
200
+ font-size: 12px;
201
+ color: var(--ap-text-secondary);
202
+ margin: 2px 0 0 0;
203
+ }
204
+
205
+ #aperture-dialog .aperture-body {
206
+ display: block;
207
+ font-size: 13px;
208
+ color: var(--ap-text-secondary);
209
+ margin-bottom: 20px;
210
+ }
211
+
212
+ #aperture-dialog .aperture-list {
213
+ display: block;
214
+ margin: 12px 0 0 24px;
215
+ padding: 0;
216
+ color: var(--ap-text-secondary);
217
+ list-style-type: disc;
218
+ }
219
+
220
+ #aperture-dialog .aperture-list li {
221
+ display: list-item;
222
+ color: inherit;
223
+ margin-bottom: 6px;
224
+ font-size: 13px;
225
+ line-height: 1.4;
226
+ }
227
+
228
+ #aperture-dialog .aperture-options {
229
+ display: flex;
230
+ flex-direction: column;
231
+ gap: 14px;
232
+ margin-bottom: 20px;
233
+ border-top: 1px solid var(--ap-border);
234
+ border-bottom: 1px solid var(--ap-border);
235
+ padding: 16px 0;
236
+ }
237
+
238
+ #aperture-dialog .aperture-checkbox-label {
239
+ display: flex;
240
+ align-items: flex-start;
241
+ gap: 10px;
242
+ font-size: 13px;
243
+ color: var(--ap-text);
244
+ cursor: pointer;
245
+ user-select: none;
246
+ line-height: 1.4;
247
+ }
248
+
249
+ #aperture-dialog .aperture-checkbox-label input[type="checkbox"] {
250
+ margin-top: 2px;
251
+ width: 16px;
252
+ height: 16px;
253
+ accent-color: var(--ap-accent);
254
+ cursor: pointer;
255
+ flex-shrink: 0;
256
+ appearance: auto;
257
+ -webkit-appearance: checkbox;
258
+ }
259
+
260
+ #aperture-dialog .aperture-checkbox-desc {
261
+ font-size: 11px;
262
+ color: var(--ap-text-muted);
263
+ margin-top: 2px;
264
+ display: block;
265
+ line-height: 1.35;
266
+ }
267
+
268
+ #aperture-dialog .aperture-warning-box {
269
+ background: var(--ap-warning-bg);
270
+ border: 1px solid var(--ap-warning-border);
271
+ border-radius: 8px;
272
+ padding: 10px 12px;
273
+ margin-top: 6px;
274
+ margin-left: 26px;
275
+ font-size: 12px;
276
+ color: var(--ap-warning-text);
277
+ display: none;
278
+ line-height: 1.4;
279
+ }
280
+
281
+ #aperture-dialog .aperture-warning-box.visible {
282
+ display: block;
283
+ }
284
+
285
+ #aperture-dialog .aperture-footer {
286
+ display: flex;
287
+ gap: 10px;
288
+ justify-content: flex-end;
289
+ flex-wrap: wrap;
290
+ }
291
+
292
+ #aperture-dialog .aperture-btn {
293
+ display: inline-block;
294
+ padding: 8px 14px;
295
+ font-size: 13px;
296
+ font-weight: 500;
297
+ border-radius: 8px;
298
+ cursor: pointer;
299
+ transition: all 0.15s ease;
300
+ border: 1px solid transparent;
301
+ white-space: nowrap;
302
+ line-height: 1;
303
+ }
304
+
305
+ #aperture-dialog .aperture-btn-deny {
306
+ background: var(--ap-btn-deny-bg);
307
+ color: var(--ap-btn-deny-text);
308
+ border-color: var(--ap-btn-deny-border);
309
+ }
310
+
311
+ #aperture-dialog .aperture-btn-deny:hover {
312
+ background: var(--ap-btn-deny-text);
313
+ color: var(--ap-bg);
314
+ border-color: var(--ap-btn-deny-text);
315
+ }
316
+
317
+ #aperture-dialog .aperture-btn-allow {
318
+ background: linear-gradient(135deg, var(--ap-accent), var(--ap-accent-hover));
319
+ color: #fff;
320
+ border-color: transparent;
321
+ }
322
+
323
+ #aperture-dialog .aperture-btn-allow:hover {
324
+ transform: translateY(-1px);
325
+ box-shadow: 0 4px 12px rgba(99, 102, 241, 0.35);
326
+ }
327
+ `;
328
+ document.head.appendChild(style);
329
+ }
330
+ import { html, render } from "lit-html";
331
+ function createDialogOverlay(onDismiss) {
332
+ const overlay = document.createElement("div");
333
+ overlay.id = "aperture-dialog-overlay";
334
+ document.body.appendChild(overlay);
335
+ const cleanup = () => {
336
+ overlay.classList.remove("active");
337
+ setTimeout(() => {
338
+ overlay.remove();
339
+ }, 300);
340
+ document.removeEventListener("keydown", escHandler);
341
+ };
342
+ const escHandler = (e) => {
343
+ if (e.key === "Escape") {
344
+ cleanup();
345
+ onDismiss?.();
346
+ }
347
+ };
348
+ document.addEventListener("keydown", escHandler);
349
+ const outsideClickHandler = (e) => {
350
+ if (e.target === overlay) {
351
+ cleanup();
352
+ onDismiss?.();
353
+ }
354
+ };
355
+ overlay.addEventListener("click", outsideClickHandler);
356
+ const activate = () => {
357
+ setTimeout(() => {
358
+ overlay.classList.add("active");
359
+ }, 10);
360
+ };
361
+ return { overlay, cleanup, activate };
362
+ }
363
+ export async function requestDisplayMedia() {
364
+ try {
365
+ return await navigator.mediaDevices.getDisplayMedia({
366
+ video: { displaySurface: "browser" },
367
+ audio: false,
368
+ });
369
+ }
370
+ catch (err) {
371
+ console.warn("[Aperture] Failed to acquire screen share stream for screenshots:", err);
372
+ return null;
373
+ }
374
+ }
375
+ export function showApprovalDialog(agentName, onApprovalStateChange) {
376
+ return new Promise((resolve) => {
377
+ if (typeof document === "undefined") {
378
+ resolve({ approved: false, capabilities: [] });
379
+ return;
380
+ }
381
+ const { overlay, cleanup, activate } = createDialogOverlay(() => {
382
+ resolve({ approved: false, capabilities: [], dismissed: true });
383
+ });
384
+ let allowScreenshot = true;
385
+ let allowEval = true;
386
+ let remember24h = true;
387
+ const handleDismiss = () => {
388
+ cleanup();
389
+ resolve({ approved: false, capabilities: [], dismissed: true });
390
+ };
391
+ const handleDeny = () => {
392
+ cleanup();
393
+ resolve({ approved: false, capabilities: [] });
394
+ };
395
+ const handleAllow = async () => {
396
+ const ttlMs = remember24h ? 24 * 60 * 60 * 1000 : 60 * 60 * 1000;
397
+ const capabilities = ["console", "dom", "network", "storage"];
398
+ if (allowEval)
399
+ capabilities.push("evaluate");
400
+ if (allowScreenshot) {
401
+ const stream = await requestDisplayMedia();
402
+ if (stream) {
403
+ onApprovalStateChange({ stream });
404
+ capabilities.push("screenshot");
405
+ }
406
+ }
407
+ cleanup();
408
+ resolve({ approved: true, capabilities, ttlMs });
409
+ };
410
+ const renderDialog = () => {
411
+ const template = html `
412
+ <div id="aperture-dialog">
413
+ <div class="aperture-header">
414
+ <div class="aperture-icon">🔌</div>
415
+ <div class="aperture-title-container">
416
+ <h3 class="aperture-title">Agent Bridge</h3>
417
+ <p class="aperture-subtitle">${agentName} wants to access this tab</p>
418
+ </div>
419
+ </div>
420
+
421
+ <div class="aperture-body">
422
+ By allowing, the agent will be able to:
423
+ <ul class="aperture-list">
424
+ <li>Read the current page URL, title, and visible text</li>
425
+ <li>Query the DOM and read element attributes / contents</li>
426
+ <li>View console logs (errors, warnings, info, debug)</li>
427
+ <li>Monitor network requests made by this page</li>
428
+ <li>Read localStorage and cookies for this origin</li>
429
+ ${allowScreenshot ? html `<li id="aperture-perm-screenshot">Capture screenshots of the page</li>` : ""}
430
+ ${allowEval ? html `<li id="aperture-perm-eval">Execute arbitrary JavaScript in this page</li>` : ""}
431
+ </ul>
432
+ </div>
433
+
434
+ <div class="aperture-options">
435
+ <label class="aperture-checkbox-label">
436
+ <input
437
+ type="checkbox"
438
+ id="aperture-allow-screenshot"
439
+ .checked=${allowScreenshot}
440
+ @change=${(e) => {
441
+ allowScreenshot = e.target.checked;
442
+ }}
443
+ />
444
+ <div>
445
+ <strong>Allow screenshot capture</strong>
446
+ <div class="aperture-checkbox-desc">Requests browser tab/screen sharing for live views</div>
447
+ </div>
448
+ </label>
449
+
450
+ <label class="aperture-checkbox-label">
451
+ <input
452
+ type="checkbox"
453
+ id="aperture-allow-eval"
454
+ .checked=${allowEval}
455
+ @change=${(e) => {
456
+ allowEval = e.target.checked;
457
+ }}
458
+ />
459
+ <div>
460
+ <strong>Allow JavaScript evaluation</strong>
461
+ <div class="aperture-checkbox-desc">Enables arbitrary JS execution in this page (dangerous)</div>
462
+ </div>
463
+ </label>
464
+
465
+ <label class="aperture-checkbox-label">
466
+ <input
467
+ type="checkbox"
468
+ id="aperture-remember-24h"
469
+ .checked=${remember24h}
470
+ @change=${(e) => {
471
+ remember24h = e.target.checked;
472
+ }}
473
+ />
474
+ <div>
475
+ <strong>Trust this device for 24 hours</strong>
476
+ <div class="aperture-checkbox-desc">Otherwise approval resets after 1 hour</div>
477
+ </div>
478
+ </label>
479
+
480
+ <div id="aperture-eval-warning" class="aperture-warning-box ${allowEval ? "visible" : ""}">
481
+ ⚠️ Warning: Allowing evaluation lets the agent run any command or access any sensitive data on this origin.
482
+ </div>
483
+ </div>
484
+
485
+ <div class="aperture-footer">
486
+ <button id="aperture-btn-dismiss" class="aperture-btn aperture-btn-deny" @click=${handleDismiss}>Dismiss</button>
487
+ <button id="aperture-btn-deny" class="aperture-btn aperture-btn-deny" @click=${handleDeny}>Deny</button>
488
+ <button id="aperture-btn-allow" class="aperture-btn aperture-btn-allow" @click=${handleAllow}>Allow for this session</button>
489
+ </div>
490
+ </div>
491
+ `;
492
+ render(template, overlay);
493
+ };
494
+ renderDialog();
495
+ activate();
496
+ });
497
+ }
498
+ export function showStatusDialog(options) {
499
+ if (typeof document === "undefined")
500
+ return;
501
+ if (document.getElementById("aperture-dialog-overlay"))
502
+ return;
503
+ const { overlay, cleanup } = createDialogOverlay();
504
+ const isMac = navigator.platform.toLowerCase().includes("mac");
505
+ const shortcut = isMac ? "Cmd+Shift+A" : "Ctrl+Shift+A";
506
+ const handleClose = () => cleanup();
507
+ const handleRevoke = () => {
508
+ options.revokeApproval();
509
+ options.onApprovalStateChange({
510
+ approved: false,
511
+ capabilities: [],
512
+ stream: null,
513
+ });
514
+ cleanup();
515
+ };
516
+ const handleHideBadge = () => {
517
+ if (options.isBadgeHidden()) {
518
+ options.showBadge();
519
+ }
520
+ else {
521
+ options.hideBadgeFor24h();
522
+ }
523
+ cleanup();
524
+ };
525
+ const renderDialog = () => {
526
+ const connectionStatus = options.wsReadyState === WebSocket.OPEN ? "Connected" : "Disconnected";
527
+ const sessionStatus = options.denied
528
+ ? "Denied"
529
+ : options.approved
530
+ ? "Approved"
531
+ : "Pending Approval";
532
+ const hasScreenshot = options.capabilities.includes("screenshot");
533
+ const hasEval = options.capabilities.includes("evaluate");
534
+ const badgeHidden = options.isBadgeHidden();
535
+ const hideButtonText = badgeHidden
536
+ ? "Show badge"
537
+ : "Hide badge for 24 hours";
538
+ const template = html `
539
+ <div id="aperture-dialog">
540
+ <div class="aperture-header">
541
+ <div class="aperture-icon">⚙️</div>
542
+ <div class="aperture-title-container">
543
+ <h3 class="aperture-title">Agent Bridge</h3>
544
+ <p class="aperture-subtitle">${options.approved ? "Session active" : "Waiting for approval"}</p>
545
+ </div>
546
+ </div>
547
+
548
+ <div class="aperture-body">
549
+ <div style="margin-bottom: 12px; display: flex; justify-content: space-between; font-size: 13px;">
550
+ <span>Connection:</span>
551
+ <strong style="color: ${connectionStatus === "Connected" ? "#10b981" : "#ef4444"};">${connectionStatus}</strong>
552
+ </div>
553
+ <div style="margin-bottom: 12px; display: flex; justify-content: space-between; font-size: 13px;">
554
+ <span>Status:</span>
555
+ <strong style="color: ${sessionStatus === "Approved" ? "#10b981" : sessionStatus === "Denied" ? "#ef4444" : "#f59e0b"};">${sessionStatus}</strong>
556
+ </div>
557
+
558
+ ${options.approved ? html `
559
+ <div style="margin-top: 16px; padding-top: 12px; border-top: 1px solid var(--ap-border);">
560
+ <div style="font-size: 12px; color: var(--ap-text-muted); margin-bottom: 8px;">Enabled capabilities:</div>
561
+ <ul style="font-size: 13px; margin: 0; padding-left: 20px; color: var(--ap-text);">
562
+ <li>Console logs</li>
563
+ <li>DOM queries</li>
564
+ <li>Network requests</li>
565
+ <li>Storage access</li>
566
+ ${hasScreenshot ? html `<li>Screenshots</li>` : ""}
567
+ ${hasEval ? html `<li>JavaScript evaluation</li>` : ""}
568
+ </ul>
569
+ </div>
570
+ ` : ""}
571
+ </div>
572
+
573
+ <div class="aperture-footer">
574
+ ${options.approved
575
+ ? html `
576
+ <button id="aperture-status-btn-revoke" class="aperture-btn aperture-btn-deny" @click=${handleRevoke}>Revoke</button>
577
+ <button id="aperture-status-btn-close" class="aperture-btn aperture-btn-allow" @click=${handleClose}>Close</button>
578
+ `
579
+ : html `
580
+ <div style="width: 100%; text-align: center; color: var(--ap-text-muted); font-size: 13px;">
581
+ Waiting for agent connection...
582
+ </div>
583
+ `}
584
+ </div>
585
+
586
+ <div style="margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--ap-border); text-align: center;">
587
+ <button id="aperture-status-btn-hide" class="aperture-btn aperture-btn-deny" style="width: 100%;" @click=${handleHideBadge}>${hideButtonText}</button>
588
+ <div style="margin-top: 8px; font-size: 11px; color: var(--ap-text-muted);">
589
+ Re-open with <kbd style="font-family: monospace; background: var(--ap-btn-deny-bg); border: 1px solid var(--ap-btn-deny-border); border-radius: 4px; padding: 1px 4px; font-size: 10px;">${shortcut}</kbd>
590
+ </div>
591
+ </div>
592
+ </div>
593
+ `;
594
+ render(template, overlay);
595
+ };
596
+ renderDialog();
597
+ setTimeout(() => {
598
+ overlay.classList.add("active");
599
+ }, 10);
600
+ }
@@ -0,0 +1,60 @@
1
+ declare global {
2
+ interface Window {
3
+ __apertureInstance__: ApertureClient;
4
+ __APERTURE_PORT__: number;
5
+ __APERTURE_URL__: string;
6
+ __vite_inject__: unknown;
7
+ }
8
+ }
9
+ export interface CustomToolDefinition {
10
+ description: string;
11
+ inputSchema: object;
12
+ handler: (client: ApertureClient, args: Record<string, any>) => any | Promise<any>;
13
+ }
14
+ interface BridgeConfig {
15
+ serverUrl: string;
16
+ onApprovalRequest?: (agentName: string) => Promise<{
17
+ approved: boolean;
18
+ capabilities: string[];
19
+ dismissed?: boolean;
20
+ }>;
21
+ customTools?: Record<string, CustomToolDefinition>;
22
+ }
23
+ export declare class ApertureClient {
24
+ private ws;
25
+ private config;
26
+ private approved;
27
+ private denied;
28
+ private capabilities;
29
+ private screenCaptureStream;
30
+ private badgeElement;
31
+ private focusListenersAdded;
32
+ constructor(config: BridgeConfig);
33
+ private registerKeyboardShortcut;
34
+ private isBadgeHidden;
35
+ private hideBadgeFor24h;
36
+ private showBadge;
37
+ private loadCachedApproval;
38
+ private saveApproval;
39
+ private revokeApproval;
40
+ connect(): void;
41
+ disconnect(): void;
42
+ private reportFocusState;
43
+ private send;
44
+ private updateBadge;
45
+ private handleToolCall;
46
+ private approvalPendingPromise;
47
+ private getOrWaitApproval;
48
+ private getApproval;
49
+ captureScreenshotFromStream(): Promise<string>;
50
+ stopScreenCapture(): void;
51
+ setMediaStream(stream: MediaStream): void;
52
+ private requestScreenCapture;
53
+ private openStatusDialog;
54
+ }
55
+ export declare function initAperture(options?: {
56
+ port?: number;
57
+ serverUrl?: string;
58
+ customTools?: Record<string, CustomToolDefinition>;
59
+ }): ApertureClient | undefined;
60
+ export {};