@tangle-network/browser-agent-driver 0.25.0 → 0.27.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/brain/index.d.ts.map +1 -1
- package/dist/brain/index.js +42 -0
- package/dist/brain/index.js.map +1 -1
- package/dist/drivers/cursor-overlay.d.ts +1 -1
- package/dist/drivers/cursor-overlay.d.ts.map +1 -1
- package/dist/drivers/cursor-overlay.js +264 -0
- package/dist/drivers/cursor-overlay.js.map +1 -1
- package/dist/drivers/overlay-label.d.ts +18 -10
- package/dist/drivers/overlay-label.d.ts.map +1 -1
- package/dist/drivers/overlay-label.js +70 -24
- package/dist/drivers/overlay-label.js.map +1 -1
- package/dist/drivers/playwright.d.ts +10 -0
- package/dist/drivers/playwright.d.ts.map +1 -1
- package/dist/drivers/playwright.js +78 -0
- package/dist/drivers/playwright.js.map +1 -1
- package/dist/drivers/types.d.ts +9 -0
- package/dist/drivers/types.d.ts.map +1 -1
- package/dist/runner/fan-out.d.ts +105 -0
- package/dist/runner/fan-out.d.ts.map +1 -0
- package/dist/runner/fan-out.js +291 -0
- package/dist/runner/fan-out.js.map +1 -0
- package/dist/runner/runner.d.ts.map +1 -1
- package/dist/runner/runner.js +52 -0
- package/dist/runner/runner.js.map +1 -1
- package/dist/skills/macro-loader.d.ts +1 -1
- package/dist/skills/macro-loader.d.ts.map +1 -1
- package/dist/supervisor/policy.js +11 -0
- package/dist/supervisor/policy.js.map +1 -1
- package/dist/types.d.ts +36 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/viewer/viewer.html +157 -23
- package/package.json +1 -1
|
@@ -240,6 +240,56 @@ export const CURSOR_OVERLAY_INIT_SCRIPT = `
|
|
|
240
240
|
overflow: 'hidden',
|
|
241
241
|
});
|
|
242
242
|
|
|
243
|
+
// ── Gen 34 Hydra View — fan-out grid (live thumbnails of sub-tabs) ─────
|
|
244
|
+
// Full-viewport dim overlay + grid of live sub-tab screenshot cells.
|
|
245
|
+
// Cells lay out based on count: 1→1, 2→1x2, 3-4→2x2, 5-6→2x3, 7-8→2x4.
|
|
246
|
+
// Each cell background updates via updateFanOutCell(i, dataUrl, meta).
|
|
247
|
+
const hydra = document.createElement('div');
|
|
248
|
+
hydra.id = '__bad_overlay_hydra';
|
|
249
|
+
Object.assign(hydra.style, {
|
|
250
|
+
position: 'fixed',
|
|
251
|
+
inset: '0',
|
|
252
|
+
display: 'none',
|
|
253
|
+
background: 'radial-gradient(ellipse at center, rgba(11,18,32,0.80) 0%, rgba(11,18,32,0.95) 100%)',
|
|
254
|
+
backdropFilter: 'blur(6px)',
|
|
255
|
+
alignItems: 'center',
|
|
256
|
+
justifyContent: 'center',
|
|
257
|
+
flexDirection: 'column',
|
|
258
|
+
gap: '20px',
|
|
259
|
+
transition: 'opacity 400ms ease',
|
|
260
|
+
opacity: '0',
|
|
261
|
+
pointerEvents: 'none',
|
|
262
|
+
});
|
|
263
|
+
const hydraTitle = document.createElement('div');
|
|
264
|
+
Object.assign(hydraTitle.style, {
|
|
265
|
+
fontSize: '11px',
|
|
266
|
+
fontWeight: '700',
|
|
267
|
+
letterSpacing: '0.16em',
|
|
268
|
+
textTransform: 'uppercase',
|
|
269
|
+
color: '#7aa2ff',
|
|
270
|
+
textAlign: 'center',
|
|
271
|
+
});
|
|
272
|
+
hydraTitle.textContent = 'Fan-out · investigating branches in parallel';
|
|
273
|
+
const hydraGrid = document.createElement('div');
|
|
274
|
+
hydraGrid.id = '__bad_overlay_hydra_grid';
|
|
275
|
+
Object.assign(hydraGrid.style, {
|
|
276
|
+
display: 'grid',
|
|
277
|
+
gap: '16px',
|
|
278
|
+
maxWidth: '1200px',
|
|
279
|
+
maxHeight: '70vh',
|
|
280
|
+
padding: '0 40px',
|
|
281
|
+
});
|
|
282
|
+
const hydraCounter = document.createElement('div');
|
|
283
|
+
Object.assign(hydraCounter.style, {
|
|
284
|
+
fontSize: '13px',
|
|
285
|
+
color: '#e6ebf5',
|
|
286
|
+
fontWeight: '600',
|
|
287
|
+
textAlign: 'center',
|
|
288
|
+
});
|
|
289
|
+
hydra.appendChild(hydraTitle);
|
|
290
|
+
hydra.appendChild(hydraGrid);
|
|
291
|
+
hydra.appendChild(hydraCounter);
|
|
292
|
+
|
|
243
293
|
// Append to documentElement (not body) so the overlay is not affected by
|
|
244
294
|
// body's stacking context — many modern sites apply transform/will-change
|
|
245
295
|
// to body which would clip a max-z-index child appended to body.
|
|
@@ -262,6 +312,7 @@ export const CURSOR_OVERLAY_INIT_SCRIPT = `
|
|
|
262
312
|
root.appendChild(ring);
|
|
263
313
|
root.appendChild(cursor);
|
|
264
314
|
root.appendChild(label);
|
|
315
|
+
root.appendChild(hydra);
|
|
265
316
|
}
|
|
266
317
|
attach();
|
|
267
318
|
|
|
@@ -418,6 +469,219 @@ export const CURSOR_OVERLAY_INIT_SCRIPT = `
|
|
|
418
469
|
} catch { /* cosmetic */ }
|
|
419
470
|
},
|
|
420
471
|
|
|
472
|
+
// ── Gen 34 Hydra API ─────────────────────────────────────────────
|
|
473
|
+
/**
|
|
474
|
+
* Begin a fan-out: render the dim overlay + grid of N labeled cells.
|
|
475
|
+
* Cells start in "queued" state (empty). Call updateFanOutCell(i, ...)
|
|
476
|
+
* as sub-agent screenshots stream in.
|
|
477
|
+
*
|
|
478
|
+
* labels: human-readable label per cell, one per sub-agent.
|
|
479
|
+
* originX/originY: optional viewport coord where the fan-out was
|
|
480
|
+
* initiated — cells burst outward from this point (default: center).
|
|
481
|
+
*/
|
|
482
|
+
fanOutStart(labels, originX, originY) {
|
|
483
|
+
try {
|
|
484
|
+
const n = Math.max(1, Math.min(8, labels.length));
|
|
485
|
+
// Layout: 1→1, 2→1x2, 3-4→2x2, 5-6→3x2, 7-8→4x2
|
|
486
|
+
const cols = n === 1 ? 1 : n === 2 ? 2 : n <= 4 ? 2 : n <= 6 ? 3 : 4;
|
|
487
|
+
const rows = Math.ceil(n / cols);
|
|
488
|
+
hydraGrid.style.gridTemplateColumns = 'repeat(' + cols + ', 1fr)';
|
|
489
|
+
hydraGrid.style.gridTemplateRows = 'repeat(' + rows + ', 1fr)';
|
|
490
|
+
// Cell size: scale to fit. For a 1200x600 viewport budget:
|
|
491
|
+
const cellW = Math.floor(1120 / cols) - 10;
|
|
492
|
+
const cellH = Math.floor(Math.min(520 / rows, cellW * 0.7));
|
|
493
|
+
// Clear prior cells
|
|
494
|
+
while (hydraGrid.firstChild) hydraGrid.removeChild(hydraGrid.firstChild);
|
|
495
|
+
const originPx = typeof originX === 'number' && typeof originY === 'number'
|
|
496
|
+
? { x: originX, y: originY }
|
|
497
|
+
: { x: window.innerWidth / 2, y: window.innerHeight / 2 };
|
|
498
|
+
for (let i = 0; i < n; i++) {
|
|
499
|
+
const cell = document.createElement('div');
|
|
500
|
+
cell.className = '__bad_hydra_cell';
|
|
501
|
+
cell.dataset.index = String(i);
|
|
502
|
+
Object.assign(cell.style, {
|
|
503
|
+
position: 'relative',
|
|
504
|
+
width: cellW + 'px',
|
|
505
|
+
height: cellH + 'px',
|
|
506
|
+
background: '#0b1220',
|
|
507
|
+
backgroundSize: 'cover',
|
|
508
|
+
backgroundPosition: 'center top',
|
|
509
|
+
border: '2px solid rgba(122,162,255,0.55)',
|
|
510
|
+
borderRadius: '10px',
|
|
511
|
+
overflow: 'hidden',
|
|
512
|
+
boxShadow: '0 10px 30px rgba(0,0,0,0.55), inset 0 0 0 1px rgba(122,162,255,0.2)',
|
|
513
|
+
opacity: '0',
|
|
514
|
+
transform: 'translate(' + (originPx.x - window.innerWidth / 2) + 'px, ' + (originPx.y - window.innerHeight / 2) + 'px) scale(0.15)',
|
|
515
|
+
transition: 'transform 480ms cubic-bezier(0.34, 1.56, 0.64, 1), opacity 300ms ease, border-color 300ms ease, box-shadow 300ms ease',
|
|
516
|
+
});
|
|
517
|
+
// Header strip: label + live elapsed
|
|
518
|
+
const header = document.createElement('div');
|
|
519
|
+
Object.assign(header.style, {
|
|
520
|
+
position: 'absolute',
|
|
521
|
+
top: '0', left: '0', right: '0',
|
|
522
|
+
padding: '6px 10px',
|
|
523
|
+
background: 'linear-gradient(180deg, rgba(11,18,32,0.95) 0%, rgba(11,18,32,0.0) 100%)',
|
|
524
|
+
color: '#e6ebf5',
|
|
525
|
+
fontSize: '11px',
|
|
526
|
+
fontWeight: '700',
|
|
527
|
+
letterSpacing: '0.04em',
|
|
528
|
+
display: 'flex',
|
|
529
|
+
justifyContent: 'space-between',
|
|
530
|
+
alignItems: 'center',
|
|
531
|
+
});
|
|
532
|
+
const headerLabel = document.createElement('span');
|
|
533
|
+
headerLabel.textContent = labels[i] || ('branch-' + (i + 1));
|
|
534
|
+
const headerTimer = document.createElement('span');
|
|
535
|
+
headerTimer.className = '__bad_hydra_timer';
|
|
536
|
+
headerTimer.style.cssText = 'font-family:SF Mono,Menlo,monospace;font-size:10px;color:#9aa3b8;font-weight:500;';
|
|
537
|
+
headerTimer.textContent = '0.0s';
|
|
538
|
+
header.appendChild(headerLabel);
|
|
539
|
+
header.appendChild(headerTimer);
|
|
540
|
+
cell.appendChild(header);
|
|
541
|
+
// Verdict chip (hidden until complete)
|
|
542
|
+
const chip = document.createElement('div');
|
|
543
|
+
chip.className = '__bad_hydra_chip';
|
|
544
|
+
Object.assign(chip.style, {
|
|
545
|
+
position: 'absolute',
|
|
546
|
+
bottom: '8px',
|
|
547
|
+
left: '8px',
|
|
548
|
+
padding: '3px 10px',
|
|
549
|
+
background: 'rgba(11,18,32,0.92)',
|
|
550
|
+
color: '#ffffff',
|
|
551
|
+
fontSize: '10px',
|
|
552
|
+
fontWeight: '700',
|
|
553
|
+
letterSpacing: '0.05em',
|
|
554
|
+
textTransform: 'uppercase',
|
|
555
|
+
borderRadius: '6px',
|
|
556
|
+
opacity: '0',
|
|
557
|
+
transition: 'opacity 220ms ease',
|
|
558
|
+
});
|
|
559
|
+
cell.appendChild(chip);
|
|
560
|
+
hydraGrid.appendChild(cell);
|
|
561
|
+
}
|
|
562
|
+
hydra.style.display = 'flex';
|
|
563
|
+
hydraCounter.textContent = '0 / ' + n + ' branches complete';
|
|
564
|
+
// Next frame: fade in + animate cells to their grid positions
|
|
565
|
+
requestAnimationFrame(() => {
|
|
566
|
+
hydra.style.opacity = '1';
|
|
567
|
+
const cells = hydraGrid.children;
|
|
568
|
+
for (let i = 0; i < cells.length; i++) {
|
|
569
|
+
const c = cells[i];
|
|
570
|
+
// Staggered burst: 0ms, 60ms, 120ms, ...
|
|
571
|
+
setTimeout(function () {
|
|
572
|
+
c.style.opacity = '1';
|
|
573
|
+
c.style.transform = 'translate(0, 0) scale(1)';
|
|
574
|
+
}, i * 60);
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
// Start the elapsed-time ticker
|
|
578
|
+
hydra.__tickerStart = Date.now();
|
|
579
|
+
if (hydra.__ticker) clearInterval(hydra.__ticker);
|
|
580
|
+
hydra.__ticker = setInterval(function () {
|
|
581
|
+
const elapsed = (Date.now() - hydra.__tickerStart) / 1000;
|
|
582
|
+
const cells = hydraGrid.children;
|
|
583
|
+
for (let i = 0; i < cells.length; i++) {
|
|
584
|
+
const cell = cells[i];
|
|
585
|
+
if (cell.__completedAt) continue;
|
|
586
|
+
const timer = cell.querySelector('.__bad_hydra_timer');
|
|
587
|
+
if (timer) timer.textContent = elapsed.toFixed(1) + 's';
|
|
588
|
+
}
|
|
589
|
+
}, 100);
|
|
590
|
+
} catch { /* cosmetic */ }
|
|
591
|
+
},
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* Update cell N with a fresh screenshot (data URL) and/or metadata.
|
|
595
|
+
* Call this at 2-5 FPS from the runner's screenshot streamer.
|
|
596
|
+
* meta: { action?: string, turn?: number }
|
|
597
|
+
*/
|
|
598
|
+
fanOutUpdateCell(index, dataUrl, meta) {
|
|
599
|
+
try {
|
|
600
|
+
const cell = hydraGrid.children[index];
|
|
601
|
+
if (!cell) return;
|
|
602
|
+
if (dataUrl) {
|
|
603
|
+
cell.style.backgroundImage = 'url("' + dataUrl + '")';
|
|
604
|
+
}
|
|
605
|
+
// eslint-disable-next-line no-empty
|
|
606
|
+
if (meta) { /* reserved for future overlays inside the cell */ }
|
|
607
|
+
} catch { /* cosmetic */ }
|
|
608
|
+
},
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Mark cell N as complete with a verdict. kind is one of
|
|
612
|
+
* 'positive' | 'cleared' | 'review' | 'info'. Final state: border
|
|
613
|
+
* recolors, chip fades in, timer freezes.
|
|
614
|
+
*/
|
|
615
|
+
fanOutCompleteCell(index, kind, verdictText) {
|
|
616
|
+
try {
|
|
617
|
+
const cell = hydraGrid.children[index];
|
|
618
|
+
if (!cell) return;
|
|
619
|
+
cell.__completedAt = Date.now();
|
|
620
|
+
const palette = (kind === 'positive' ? { c: '#fb7185', bg: 'rgba(251,113,133,0.25)' }
|
|
621
|
+
: kind === 'cleared' ? { c: '#4ade80', bg: 'rgba(74,222,128,0.25)' }
|
|
622
|
+
: kind === 'review' ? { c: '#fbbf24', bg: 'rgba(251,191,36,0.25)' }
|
|
623
|
+
: { c: '#7aa2ff', bg: 'rgba(122,162,255,0.25)' });
|
|
624
|
+
cell.style.borderColor = palette.c;
|
|
625
|
+
cell.style.boxShadow = '0 10px 30px rgba(0,0,0,0.55), inset 0 0 0 1px ' + palette.c + ', 0 0 24px ' + palette.bg;
|
|
626
|
+
const chip = cell.querySelector('.__bad_hydra_chip');
|
|
627
|
+
if (chip) {
|
|
628
|
+
chip.style.background = palette.bg;
|
|
629
|
+
chip.style.color = palette.c;
|
|
630
|
+
chip.style.border = '1px solid ' + palette.c;
|
|
631
|
+
chip.textContent = (verdictText || kind).slice(0, 32);
|
|
632
|
+
chip.style.opacity = '1';
|
|
633
|
+
}
|
|
634
|
+
// Update global counter
|
|
635
|
+
const total = hydraGrid.children.length;
|
|
636
|
+
let done = 0;
|
|
637
|
+
for (let i = 0; i < total; i++) if (hydraGrid.children[i].__completedAt) done++;
|
|
638
|
+
hydraCounter.textContent = done + ' / ' + total + ' branches complete';
|
|
639
|
+
} catch { /* cosmetic */ }
|
|
640
|
+
},
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Collapse the grid: cells fly inward to center, merge into a result
|
|
644
|
+
* tile, then dissolve. Returns after ~800ms when the animation is
|
|
645
|
+
* done (but does NOT hide the overlay — caller invokes fanOutDismiss).
|
|
646
|
+
*/
|
|
647
|
+
fanOutCollapse() {
|
|
648
|
+
try {
|
|
649
|
+
if (hydra.__ticker) { clearInterval(hydra.__ticker); hydra.__ticker = null; }
|
|
650
|
+
const cells = hydraGrid.children;
|
|
651
|
+
const cx = window.innerWidth / 2;
|
|
652
|
+
const cy = window.innerHeight / 2;
|
|
653
|
+
for (let i = 0; i < cells.length; i++) {
|
|
654
|
+
const c = cells[i];
|
|
655
|
+
const rect = c.getBoundingClientRect();
|
|
656
|
+
const dx = cx - (rect.left + rect.width / 2);
|
|
657
|
+
const dy = cy - (rect.top + rect.height / 2);
|
|
658
|
+
c.style.transition = 'transform 520ms cubic-bezier(0.6, 0, 0.4, 1), opacity 400ms ease';
|
|
659
|
+
c.style.transform = 'translate(' + dx + 'px, ' + dy + 'px) scale(0.2)';
|
|
660
|
+
c.style.opacity = '0';
|
|
661
|
+
}
|
|
662
|
+
hydraTitle.style.transition = 'opacity 400ms ease';
|
|
663
|
+
hydraCounter.style.transition = 'opacity 400ms ease';
|
|
664
|
+
setTimeout(function () { hydraTitle.style.opacity = '0'; hydraCounter.style.opacity = '0'; }, 200);
|
|
665
|
+
} catch { /* cosmetic */ }
|
|
666
|
+
},
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Hide the Hydra overlay entirely. Call after fanOutCollapse has
|
|
670
|
+
* finished + the parent agent has resumed.
|
|
671
|
+
*/
|
|
672
|
+
fanOutDismiss() {
|
|
673
|
+
try {
|
|
674
|
+
hydra.style.opacity = '0';
|
|
675
|
+
setTimeout(function () {
|
|
676
|
+
hydra.style.display = 'none';
|
|
677
|
+
hydraTitle.style.opacity = '1';
|
|
678
|
+
hydraCounter.style.opacity = '1';
|
|
679
|
+
while (hydraGrid.firstChild) hydraGrid.removeChild(hydraGrid.firstChild);
|
|
680
|
+
if (hydra.__ticker) { clearInterval(hydra.__ticker); hydra.__ticker = null; }
|
|
681
|
+
}, 400);
|
|
682
|
+
} catch { /* cosmetic */ }
|
|
683
|
+
},
|
|
684
|
+
|
|
421
685
|
hide() {
|
|
422
686
|
box.style.opacity = '0';
|
|
423
687
|
label.style.opacity = '0';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-overlay.js","sourceRoot":"","sources":["../../src/drivers/cursor-overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG
|
|
1
|
+
{"version":3,"file":"cursor-overlay.js","sourceRoot":"","sources":["../../src/drivers/cursor-overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4pBzC,CAAA"}
|
|
@@ -2,18 +2,26 @@
|
|
|
2
2
|
* Cursor-overlay label builder.
|
|
3
3
|
*
|
|
4
4
|
* The overlay renders a single short label string next to the animated
|
|
5
|
-
* cursor.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* cursor. The label is the PRIMARY channel of agent intent visible to
|
|
6
|
+
* anyone watching a recorded video — it needs to read like a human
|
|
7
|
+
* narrator, not like a debug log.
|
|
8
|
+
*
|
|
9
|
+
* Gen 34 rewrite: natural-English sentences.
|
|
10
|
+
*
|
|
11
|
+
* Before: `type "JOHN SMITH" · Last Name: insert criteria`
|
|
12
|
+
* After: `Typing "JOHN SMITH" into Last Name`
|
|
9
13
|
*
|
|
10
14
|
* Design rules:
|
|
11
|
-
* - Labels MUST fit on one line at ~13px. Target max
|
|
15
|
+
* - Labels MUST fit on one line at ~13px. Target max 56 chars rendered.
|
|
12
16
|
* - Truncate with an ellipsis; never wrap.
|
|
13
17
|
* - Verb-only is the SAFE FALLBACK — never throw, never return empty.
|
|
14
|
-
* - Target
|
|
15
|
-
*
|
|
16
|
-
*
|
|
18
|
+
* - Target names get aggressive cleanup: strip trailing punctuation,
|
|
19
|
+
* drop generic role-restatements, drop verbose suffixes like
|
|
20
|
+
* "insert criteria" / "search input" that ARIA labels carry but
|
|
21
|
+
* viewers don't need.
|
|
22
|
+
* - Start every action with a verb-in-progress ("Typing", "Clicking",
|
|
23
|
+
* "Pressing") for readability. Status-bar shorthand ("click · X")
|
|
24
|
+
* was good for devs; bad for anyone else.
|
|
17
25
|
*/
|
|
18
26
|
import type { Action } from '../types.js';
|
|
19
27
|
export interface OverlayLabelContext {
|
|
@@ -26,8 +34,8 @@ export interface OverlayLabelContext {
|
|
|
26
34
|
* Build a single-line label string for the cursor overlay given an action
|
|
27
35
|
* and (optionally) the resolved target element's accessible name.
|
|
28
36
|
*
|
|
29
|
-
* Always returns a non-empty string. Falls back to
|
|
30
|
-
* missing context.
|
|
37
|
+
* Always returns a non-empty string. Falls back to a bare verb-phrase
|
|
38
|
+
* ("Clicking", "Typing") on any missing context. Never throws.
|
|
31
39
|
*/
|
|
32
40
|
export declare function formatOverlayLabel(action: Action, ctx?: OverlayLabelContext): string;
|
|
33
41
|
//# sourceMappingURL=overlay-label.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay-label.d.ts","sourceRoot":"","sources":["../../src/drivers/overlay-label.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"overlay-label.d.ts","sourceRoot":"","sources":["../../src/drivers/overlay-label.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAyFzC,MAAM,WAAW,mBAAmB;IAClC,wEAAwE;IACxE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,GAAE,mBAAwB,GAAG,MAAM,CAsCxF"}
|
|
@@ -1,17 +1,31 @@
|
|
|
1
|
-
const MAX_LABEL_LEN =
|
|
2
|
-
const MAX_TEXT_PREVIEW =
|
|
3
|
-
const MAX_NAME_PREVIEW =
|
|
1
|
+
const MAX_LABEL_LEN = 56;
|
|
2
|
+
const MAX_TEXT_PREVIEW = 32;
|
|
3
|
+
const MAX_NAME_PREVIEW = 28;
|
|
4
4
|
/**
|
|
5
5
|
* Role names that are generic; including them in the label adds no info.
|
|
6
|
-
* NOTE: "Search" is NOT here — a button labeled "Search" is informative
|
|
7
|
-
* (OFAC, Google, etc.). "searchbox" IS here — that's the role spilling
|
|
8
|
-
* through as a name when an input has no label, which just restates what
|
|
9
|
-
* the viewer already sees from the cursor's position on the textbox.
|
|
6
|
+
* NOTE: "Search" is NOT here — a button labeled "Search" is informative.
|
|
10
7
|
*/
|
|
11
8
|
const GENERIC_NAMES = new Set([
|
|
12
9
|
'button', 'link', 'textbox', 'input', 'field', 'searchbox',
|
|
13
10
|
'combobox', 'listbox', 'option', 'checkbox', 'radio', 'switch',
|
|
14
11
|
]);
|
|
12
|
+
/**
|
|
13
|
+
* Suffixes ARIA labels / placeholders often carry that bloat the label
|
|
14
|
+
* without adding meaning. "Last Name: insert criteria" → "Last Name".
|
|
15
|
+
* Matching is case-insensitive and trims any trailing punctuation.
|
|
16
|
+
*/
|
|
17
|
+
const NOISE_SUFFIXES = [
|
|
18
|
+
/\s*[:,]?\s*insert (?:criteria|name|value|text)\s*$/i,
|
|
19
|
+
/\s*[:,]?\s*search input\s*$/i,
|
|
20
|
+
/\s*[:,]?\s*search field\s*$/i,
|
|
21
|
+
/\s*[:,]?\s*input field\s*$/i,
|
|
22
|
+
/\s*[:,]?\s*text input\s*$/i,
|
|
23
|
+
/\s*[:,]?\s*enter (?:text|value|name|keyword|query)\s*$/i,
|
|
24
|
+
/\s*[:,]?\s*type (?:here|name|text)\s*$/i,
|
|
25
|
+
/\s*[:,]?\s*required\s*$/i,
|
|
26
|
+
/\s*[*]\s*$/, // trailing asterisks from "Required *" fields
|
|
27
|
+
/[:;,]\s*$/, // any trailing punctuation
|
|
28
|
+
];
|
|
15
29
|
function truncate(s, max) {
|
|
16
30
|
const collapsed = s.replace(/\s+/g, ' ').trim();
|
|
17
31
|
if (collapsed.length <= max)
|
|
@@ -21,7 +35,22 @@ function truncate(s, max) {
|
|
|
21
35
|
function cleanName(name) {
|
|
22
36
|
if (!name)
|
|
23
37
|
return undefined;
|
|
24
|
-
|
|
38
|
+
let c = name.replace(/\s+/g, ' ').trim();
|
|
39
|
+
if (!c)
|
|
40
|
+
return undefined;
|
|
41
|
+
// Strip noise suffixes iteratively — an ARIA name like
|
|
42
|
+
// "Last Name: insert criteria, required *" has three layers to peel.
|
|
43
|
+
let changed = true;
|
|
44
|
+
while (changed) {
|
|
45
|
+
changed = false;
|
|
46
|
+
for (const re of NOISE_SUFFIXES) {
|
|
47
|
+
const stripped = c.replace(re, '').trim();
|
|
48
|
+
if (stripped !== c && stripped.length > 0) {
|
|
49
|
+
c = stripped;
|
|
50
|
+
changed = true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
25
54
|
if (!c)
|
|
26
55
|
return undefined;
|
|
27
56
|
if (GENERIC_NAMES.has(c.toLowerCase()))
|
|
@@ -38,52 +67,69 @@ function displayHost(url) {
|
|
|
38
67
|
return url.replace(/^https?:\/\//, '').replace(/\/.*$/, '').slice(0, MAX_NAME_PREVIEW);
|
|
39
68
|
}
|
|
40
69
|
}
|
|
70
|
+
/** Press keys get friendlier names — "Enter" / "Tab" / arrow glyphs. */
|
|
71
|
+
function friendlyKey(key) {
|
|
72
|
+
const k = key.trim();
|
|
73
|
+
const map = {
|
|
74
|
+
'Enter': 'Enter',
|
|
75
|
+
'Return': 'Enter',
|
|
76
|
+
'Tab': 'Tab',
|
|
77
|
+
'Escape': 'Esc',
|
|
78
|
+
'Backspace': '⌫',
|
|
79
|
+
'Delete': 'Del',
|
|
80
|
+
'ArrowUp': '↑',
|
|
81
|
+
'ArrowDown': '↓',
|
|
82
|
+
'ArrowLeft': '←',
|
|
83
|
+
'ArrowRight': '→',
|
|
84
|
+
};
|
|
85
|
+
return map[k] ?? k;
|
|
86
|
+
}
|
|
41
87
|
/**
|
|
42
88
|
* Build a single-line label string for the cursor overlay given an action
|
|
43
89
|
* and (optionally) the resolved target element's accessible name.
|
|
44
90
|
*
|
|
45
|
-
* Always returns a non-empty string. Falls back to
|
|
46
|
-
* missing context.
|
|
91
|
+
* Always returns a non-empty string. Falls back to a bare verb-phrase
|
|
92
|
+
* ("Clicking", "Typing") on any missing context. Never throws.
|
|
47
93
|
*/
|
|
48
94
|
export function formatOverlayLabel(action, ctx = {}) {
|
|
49
95
|
const name = cleanName(ctx.targetName);
|
|
50
96
|
switch (action.action) {
|
|
51
97
|
case 'click': {
|
|
52
|
-
return truncate(name ? `
|
|
98
|
+
return truncate(name ? `Clicking ${name}` : 'Clicking', MAX_LABEL_LEN);
|
|
53
99
|
}
|
|
54
100
|
case 'type': {
|
|
55
101
|
const text = truncate(action.text ?? '', MAX_TEXT_PREVIEW);
|
|
56
102
|
if (text && name)
|
|
57
|
-
return truncate(`
|
|
103
|
+
return truncate(`Typing “${text}” into ${name}`, MAX_LABEL_LEN);
|
|
58
104
|
if (text)
|
|
59
|
-
return truncate(`
|
|
60
|
-
return name ? truncate(`
|
|
105
|
+
return truncate(`Typing “${text}”`, MAX_LABEL_LEN);
|
|
106
|
+
return name ? truncate(`Typing into ${name}`, MAX_LABEL_LEN) : 'Typing';
|
|
61
107
|
}
|
|
62
108
|
case 'press': {
|
|
63
|
-
const key = action.key
|
|
109
|
+
const key = action.key ? friendlyKey(action.key) : '';
|
|
64
110
|
if (key && name)
|
|
65
|
-
return truncate(`
|
|
66
|
-
return truncate(key ? `
|
|
111
|
+
return truncate(`Pressing ${key} in ${name}`, MAX_LABEL_LEN);
|
|
112
|
+
return truncate(key ? `Pressing ${key}` : 'Pressing a key', MAX_LABEL_LEN);
|
|
67
113
|
}
|
|
68
114
|
case 'hover': {
|
|
69
|
-
return truncate(name ? `
|
|
115
|
+
return truncate(name ? `Hovering ${name}` : 'Hovering', MAX_LABEL_LEN);
|
|
70
116
|
}
|
|
71
117
|
case 'select': {
|
|
72
118
|
const val = truncate(action.value ?? '', MAX_TEXT_PREVIEW);
|
|
73
119
|
if (val && name)
|
|
74
|
-
return truncate(`
|
|
120
|
+
return truncate(`Selecting “${val}” in ${name}`, MAX_LABEL_LEN);
|
|
75
121
|
if (val)
|
|
76
|
-
return truncate(`
|
|
77
|
-
return name ? truncate(`
|
|
122
|
+
return truncate(`Selecting “${val}”`, MAX_LABEL_LEN);
|
|
123
|
+
return name ? truncate(`Selecting in ${name}`, MAX_LABEL_LEN) : 'Selecting';
|
|
78
124
|
}
|
|
79
125
|
case 'scroll': {
|
|
80
|
-
return truncate(`
|
|
126
|
+
return truncate(`Scrolling ${action.direction}`, MAX_LABEL_LEN);
|
|
81
127
|
}
|
|
82
128
|
case 'navigate': {
|
|
83
|
-
return truncate(`
|
|
129
|
+
return truncate(`Navigating to ${displayHost(action.url)}`, MAX_LABEL_LEN);
|
|
84
130
|
}
|
|
85
131
|
case 'wait': {
|
|
86
|
-
return truncate(`
|
|
132
|
+
return truncate(`Waiting ${action.ms}ms`, MAX_LABEL_LEN);
|
|
87
133
|
}
|
|
88
134
|
default:
|
|
89
135
|
return action.action;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay-label.js","sourceRoot":"","sources":["../../src/drivers/overlay-label.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"overlay-label.js","sourceRoot":"","sources":["../../src/drivers/overlay-label.ts"],"names":[],"mappings":"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"}
|
|
@@ -121,6 +121,16 @@ export declare class PlaywrightDriver implements Driver {
|
|
|
121
121
|
* to celebrate the moment.
|
|
122
122
|
*/
|
|
123
123
|
pushOverlayBadge(kind: 'positive' | 'cleared' | 'review' | 'info', text: string): Promise<void>;
|
|
124
|
+
/** Start the fan-out overlay. Renders the dim + grid of N labeled cells. */
|
|
125
|
+
fanOutStart(labels: string[]): Promise<void>;
|
|
126
|
+
/** Stream a JPEG dataURL into cell N. Call at 2-5 FPS during fan-out. */
|
|
127
|
+
fanOutUpdateCell(index: number, dataUrl?: string): Promise<void>;
|
|
128
|
+
/** Mark cell N complete with a verdict kind + chip text. */
|
|
129
|
+
fanOutCompleteCell(index: number, kind: 'positive' | 'cleared' | 'review' | 'info', verdictText?: string): Promise<void>;
|
|
130
|
+
/** Collapse the grid (cells fly to center, merge). ~500ms animation. */
|
|
131
|
+
fanOutCollapse(): Promise<void>;
|
|
132
|
+
/** Dismiss the fan-out overlay (fade out). Call after collapse finishes. */
|
|
133
|
+
fanOutDismiss(): Promise<void>;
|
|
124
134
|
getPage(): Page;
|
|
125
135
|
getUrl(): string;
|
|
126
136
|
inspectSelectorHref(selector: string): Promise<string | undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../../src/drivers/playwright.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,YAAY,CAAC;AACnD,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAUrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAkF/D,iDAAiD;AACjD,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,aAAa,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,qCAAqC;IACrC,YAAY,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,uBAAuB;IACtC,2BAA2B;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,6CAA6C;IAC7C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,qEAAqE;IACrE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,sEAAsE;IACtE,cAAc,CAAC,EAAE,QAAQ,GAAG,OAAO,GAAG,MAAM,CAAC;IAC7C,6EAA6E;IAC7E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;6DAEyD;IACzD,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,qBAAa,gBAAiB,YAAW,MAAM;IAgB3C,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,OAAO;IAhBjB,OAAO,CAAC,QAAQ,CAA4B;IAC5C,OAAO,CAAC,UAAU,CAA2B;IAC7C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,YAAY,CAAK;IACzB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB,CAAC,CAAgB;IAC7C,uFAAuF;IACvF,OAAO,CAAC,WAAW,CAAoB;gBAG7B,IAAI,EAAE,IAAI,EACV,OAAO,GAAE,uBAA4B;IAU/C;;;OAGG;YACW,oBAAoB;IA2ClC;;;;;;;OAOG;YACW,uBAAuB;IAgErC;;;OAGG;YACW,oBAAoB;IAqBlC,0DAA0D;IAC1D,aAAa,IAAI,aAAa,GAAG,SAAS;IAI1C;;;;;;;OAOG;IACG,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IActD;;;;OAIG;IACG,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBvF;;;;;OAKG;IACG,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"playwright.d.ts","sourceRoot":"","sources":["../../src/drivers/playwright.ts"],"names":[],"mappings":"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"}
|
|
@@ -328,6 +328,84 @@ export class PlaywrightDriver {
|
|
|
328
328
|
}
|
|
329
329
|
catch { /* cosmetic */ }
|
|
330
330
|
}
|
|
331
|
+
// ── Gen 34 Hydra API ───────────────────────────────────────────────
|
|
332
|
+
/** Start the fan-out overlay. Renders the dim + grid of N labeled cells. */
|
|
333
|
+
async fanOutStart(labels) {
|
|
334
|
+
if (!this.options.showCursor)
|
|
335
|
+
return;
|
|
336
|
+
if (this.cursorInstallPromise)
|
|
337
|
+
await this.cursorInstallPromise.catch(() => undefined);
|
|
338
|
+
try {
|
|
339
|
+
const ls = labels.slice(0, 8);
|
|
340
|
+
await this.page.evaluate((l) => {
|
|
341
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
342
|
+
const ov = window.__bad_overlay;
|
|
343
|
+
if (ov && typeof ov.fanOutStart === 'function')
|
|
344
|
+
ov.fanOutStart(l);
|
|
345
|
+
}, ls).catch(() => { });
|
|
346
|
+
}
|
|
347
|
+
catch { /* cosmetic */ }
|
|
348
|
+
}
|
|
349
|
+
/** Stream a JPEG dataURL into cell N. Call at 2-5 FPS during fan-out. */
|
|
350
|
+
async fanOutUpdateCell(index, dataUrl) {
|
|
351
|
+
if (!this.options.showCursor)
|
|
352
|
+
return;
|
|
353
|
+
if (this.cursorInstallPromise)
|
|
354
|
+
await this.cursorInstallPromise.catch(() => undefined);
|
|
355
|
+
try {
|
|
356
|
+
await this.page.evaluate(({ i, d }) => {
|
|
357
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
358
|
+
const ov = window.__bad_overlay;
|
|
359
|
+
if (ov && typeof ov.fanOutUpdateCell === 'function')
|
|
360
|
+
ov.fanOutUpdateCell(i, d);
|
|
361
|
+
}, { i: index, ...(dataUrl ? { d: dataUrl } : {}) }).catch(() => { });
|
|
362
|
+
}
|
|
363
|
+
catch { /* cosmetic */ }
|
|
364
|
+
}
|
|
365
|
+
/** Mark cell N complete with a verdict kind + chip text. */
|
|
366
|
+
async fanOutCompleteCell(index, kind, verdictText) {
|
|
367
|
+
if (!this.options.showCursor)
|
|
368
|
+
return;
|
|
369
|
+
if (this.cursorInstallPromise)
|
|
370
|
+
await this.cursorInstallPromise.catch(() => undefined);
|
|
371
|
+
try {
|
|
372
|
+
await this.page.evaluate(({ i, k, t }) => {
|
|
373
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
374
|
+
const ov = window.__bad_overlay;
|
|
375
|
+
if (ov && typeof ov.fanOutCompleteCell === 'function')
|
|
376
|
+
ov.fanOutCompleteCell(i, k, t);
|
|
377
|
+
}, { i: index, k: kind, ...(verdictText ? { t: verdictText } : {}) }).catch(() => { });
|
|
378
|
+
}
|
|
379
|
+
catch { /* cosmetic */ }
|
|
380
|
+
}
|
|
381
|
+
/** Collapse the grid (cells fly to center, merge). ~500ms animation. */
|
|
382
|
+
async fanOutCollapse() {
|
|
383
|
+
if (!this.options.showCursor)
|
|
384
|
+
return;
|
|
385
|
+
try {
|
|
386
|
+
await this.page.evaluate(() => {
|
|
387
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
388
|
+
const ov = window.__bad_overlay;
|
|
389
|
+
if (ov && typeof ov.fanOutCollapse === 'function')
|
|
390
|
+
ov.fanOutCollapse();
|
|
391
|
+
}).catch(() => { });
|
|
392
|
+
}
|
|
393
|
+
catch { /* cosmetic */ }
|
|
394
|
+
}
|
|
395
|
+
/** Dismiss the fan-out overlay (fade out). Call after collapse finishes. */
|
|
396
|
+
async fanOutDismiss() {
|
|
397
|
+
if (!this.options.showCursor)
|
|
398
|
+
return;
|
|
399
|
+
try {
|
|
400
|
+
await this.page.evaluate(() => {
|
|
401
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
402
|
+
const ov = window.__bad_overlay;
|
|
403
|
+
if (ov && typeof ov.fanOutDismiss === 'function')
|
|
404
|
+
ov.fanOutDismiss();
|
|
405
|
+
}).catch(() => { });
|
|
406
|
+
}
|
|
407
|
+
catch { /* cosmetic */ }
|
|
408
|
+
}
|
|
331
409
|
getPage() {
|
|
332
410
|
return this.page;
|
|
333
411
|
}
|