@ulpi/browse 0.7.1 → 0.7.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ulpi/browse",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/ulpi-io/browse"
package/skill/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: browse
3
- version: 2.5.0
3
+ version: 2.5.1
4
4
  description: |
5
5
  Fast web browsing for AI coding agents via persistent headless Chromium daemon. Navigate to any URL,
6
6
  read page content, click elements, fill forms, run JavaScript, take screenshots,
@@ -261,7 +261,8 @@ browse accessibility Accessibility tree snapshot (ARIA)
261
261
  ```
262
262
  browse snapshot Full accessibility tree with @refs
263
263
  browse snapshot -i Interactive elements only — terse flat list (minimal tokens)
264
- browse snapshot -i -v Interactive elements — verbose indented tree with props
264
+ browse snapshot -i -f Interactive elements — full indented tree with props
265
+ browse snapshot -i -V Interactive elements — viewport only (skip below-fold)
265
266
  browse snapshot -c Compact (no empty structural elements)
266
267
  browse snapshot -C Cursor-interactive (detect divs with cursor:pointer/onclick/tabindex)
267
268
  browse snapshot -d <N> Limit depth to N levels
@@ -420,6 +421,7 @@ browse video status Check if recording is active
420
421
  ```
421
422
  browse status Server health, uptime, session count
422
423
  browse instances List all running browse servers (instance, PID, port, status)
424
+ browse version Print CLI version
423
425
  browse stop Shutdown server
424
426
  browse restart Kill + restart server
425
427
  browse inspect Open DevTools (requires BROWSE_DEBUG_PORT)
package/src/cli.ts CHANGED
@@ -612,7 +612,7 @@ Inspection: js <expr> | eval <file> | css <sel> <prop> | attrs <sel>
612
612
  cookies | storage [set <k> <v>] | perf
613
613
  value <sel> | count <sel> | clipboard [write <text>]
614
614
  Visual: screenshot [path] | pdf [path] | responsive [prefix]
615
- Snapshot: snapshot [-i] [-v] [-c] [-C] [-d N] [-s sel]
615
+ Snapshot: snapshot [-i] [-f] [-V] [-c] [-C] [-d N] [-s sel]
616
616
  Find: find role|text|label|placeholder|testid <query> [name]
617
617
  Compare: diff <url1> <url2> | screenshot-diff <baseline> [current]
618
618
  Multi-step: chain (reads JSON from stdin)
@@ -639,7 +639,8 @@ Options:
639
639
 
640
640
  Snapshot flags:
641
641
  -i Interactive elements only (terse flat list by default)
642
- -v Verbosefull indented tree with props (use with -i)
642
+ -f Full — indented tree with props and children (use with -i)
643
+ -V Viewport — only elements visible in current viewport
643
644
  -c Compact — remove empty structural elements
644
645
  -C Cursor-interactive — detect divs with cursor:pointer,
645
646
  onclick, tabindex, data-action (missed by ARIA tree)
package/src/snapshot.ts CHANGED
@@ -31,8 +31,9 @@ const INTERACTIVE_ROLES = new Set([
31
31
 
32
32
  interface SnapshotOptions {
33
33
  interactive?: boolean; // -i: only interactive elements (terse flat list by default)
34
- verbose?: boolean; // -v: full indented ARIA tree with props/children (overrides -i terse default)
34
+ full?: boolean; // -f: full indented ARIA tree with props/children (overrides -i terse default)
35
35
  compact?: boolean; // -c: remove empty structural elements
36
+ viewport?: boolean; // -V: only elements visible in current viewport
36
37
  depth?: number; // -d N: limit tree depth
37
38
  selector?: string; // -s SEL: scope to CSS selector
38
39
  cursor?: boolean; // -C: detect cursor-interactive elements (divs with cursor:pointer, onclick, tabindex)
@@ -73,9 +74,13 @@ export function parseSnapshotArgs(args: string[]): SnapshotOptions {
73
74
  case '--compact':
74
75
  opts.compact = true;
75
76
  break;
76
- case '-v':
77
- case '--verbose':
78
- opts.verbose = true;
77
+ case '-f':
78
+ case '--full':
79
+ opts.full = true;
80
+ break;
81
+ case '-V':
82
+ case '--viewport':
83
+ opts.viewport = true;
79
84
  break;
80
85
  case '-C':
81
86
  case '--cursor':
@@ -422,12 +427,15 @@ export async function handleSnapshot(
422
427
  refMap.set(ref, locator);
423
428
 
424
429
  // Format output line
425
- // -i without -v: terse flat list (no indent, no props, no children)
426
- const terse = opts.interactive && !opts.verbose;
430
+ // -i without -f: terse flat list (no indent, no props, no children)
431
+ const terse = opts.interactive && !opts.full;
427
432
  let outputLine: string;
428
433
  if (terse) {
429
434
  outputLine = `@${ref} [${node.role}]`;
430
- if (node.name) outputLine += ` "${node.name}"`;
435
+ if (node.name) {
436
+ const name = node.name.length > 30 ? node.name.slice(0, 30) + '...' : node.name;
437
+ outputLine += ` "${name}"`;
438
+ }
431
439
  } else {
432
440
  outputLine = `${indent}@${ref} [${node.role}]`;
433
441
  if (node.name) outputLine += ` "${node.name}"`;
@@ -438,6 +446,36 @@ export async function handleSnapshot(
438
446
  output.push(outputLine);
439
447
  }
440
448
 
449
+ // Viewport filter: remove elements below the visible viewport
450
+ if (opts.viewport) {
451
+ const vp = page.viewportSize();
452
+ if (vp) {
453
+ const toRemove = new Set<string>();
454
+ await Promise.all(
455
+ Array.from(refMap.entries()).map(async ([ref, loc]) => {
456
+ try {
457
+ const box = await loc.boundingBox({ timeout: 500 });
458
+ if (!box || box.y >= vp.height || box.y + box.height <= 0) {
459
+ toRemove.add(ref);
460
+ }
461
+ } catch {
462
+ toRemove.add(ref);
463
+ }
464
+ })
465
+ );
466
+ for (const ref of toRemove) {
467
+ refMap.delete(ref);
468
+ }
469
+ // Remove output lines for filtered refs
470
+ for (let i = output.length - 1; i >= 0; i--) {
471
+ const match = output[i].match(/@(e\d+)/);
472
+ if (match && toRemove.has(match[1])) {
473
+ output.splice(i, 1);
474
+ }
475
+ }
476
+ }
477
+ }
478
+
441
479
  // Cursor-interactive detection: supplement ARIA tree with DOM-level scan
442
480
  if (opts.cursor) {
443
481
  const result = await appendCursorElements(evalCtx, locatorRoot, opts, output, refMap, refCounter, bm);