← Commit history

skill: teach the new first-class page-driving verbs (browser_scroll / browser_set_viewport / browser_screenshot_element) + eval helpers, replacing the hand-rolled evals; pkg 1.8.29

John Lauer ·175353b9a4 · ·parent 026795f
2 files changed +30−22
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "adom-desktop-puppeteer-bridge",-  "version": "1.8.28",+  "version": "1.8.29",   "type": "app",   "description": "The pup SKILL PACK \u2014 the AI skills that teach a cloud/container AI how to drive the Adom Desktop Puppeteer (pup) bridge (browser_* verbs): the everyday `pup` skill plus focused sub-skills for windows/sessions/tabs, screenshots+recording, browsers+Chrome install, and driving the Adom wiki. Installs into ~/.claude/skills + ~/.codex/skills. DOCS ONLY \u2014 this is NOT the bridge runtime. The bridge itself (the Node program that drives the browser) runs on the DESKTOP: Adom Desktop bundles it and auto-installs/updates it, and it's published separately on the Releases tab as adom-bridge-puppeteer-v<ver>.zip. So the pkg version (skills, bumps often) and the Release version (runtime, bumps rarely) differ on purpose. TL;DR: pkg install = the skills for your AI; the bridge = the Release zip, which Adom Desktop manages for you.",   "keywords": [
skills/pup-screenshots-recording/SKILL.md+29−21
@@ -60,34 +60,42 @@ adom-desktop browser_lower_os_window '{"sessionId":"demo-web"}'   # tuck it away - A pup window can record from the **background** too, but for a demo the user will actually watch, raise it   first (that's an explicit "show me" case where `foreground` is warranted). -## Driving & verifying tricky pages (shadow DOM, nested scroll) — verify by DOM, not by eye+## Driving & verifying tricky pages (shadow DOM, nested scroll) — use the first-class verbs -When you need to find, count, or confirm something on a component-heavy page (an app, a wiki widget), a-naive `document.querySelectorAll` plus eyeballing a screenshot can quietly lie. Three traps + fixes,-learned live auditing a "Download for your machine" card:+Component-heavy pages (an app, a wiki widget) break the naive path: `document.querySelector` misses shadow+content, `window.scrollTo` no-ops when the page scrolls inside a nested `<div>`, `fullPage` returns only the+viewport, and a sized window can even come up ~170px wide. As of **v1.8.21 pup has first-class verbs for+all of it** — reach for these instead of hand-rolling evals: -**1. Shadow DOM — a plain query can't see inside a web component.** If a widget's innards live in a shadow-root, `querySelectorAll` returns empty. But **first check whether it's even shadow DOM** — many "empty"-results just mean your selector is wrong on plain DOM. Deep-survey for shadow roots (and pierce them the-same way if present — recurse into `.shadowRoot`):+- **`browser_screenshot_element { sessionId, selector? | text?, closest?, padding?, deep? }`** — screenshot+  ONE element. Resolve by CSS **selector** (most reliable) or visible **text** (pierces shadow DOM), scrolled+  into view first. **This is usually the whole answer to "capture just this card."** Text matches the+  *tightest* text node — to grab the enclosing card add `closest:".card"`; and if the phrase is split across+  spans or appears in prose too, use a **selector** (e.g. `.download-card`).+- **`browser_scroll { sessionId, dy?/dx? | toSelector?/toText?, block?, behavior? }`** — scrolls the ACTUAL+  scrolling element (nearest scrollable ancestor, not `window`). Scroll by delta or to an element/text+  (shadow-piercing). Returns `{ scrollElement, scrollTop, scrollHeight, clientHeight, atBottom }` so you can+  confirm it landed — no more overshoot from hand-computed offsets.+- **`browser_set_viewport { sessionId, width, height, deviceScaleFactor? }`** — pins the viewport+  deterministically (fixes a too-small innerWidth). `browser_open_window { width, height }` now applies it on+  open, so a sized window renders at the size you asked for.+- **`$deep(sel)` / `$$deep(sel)` / `deepText(txt)`** are auto-injected into every page, so `browser_eval` can+  pierce shadow roots directly — no hand-rolled walk:  ```bash-adom-desktop browser_eval '{"sessionId":"...","expr":"(function(){const hosts=[],walk=r=>{for(const el of r.querySelectorAll(\"*\")){if(el.shadowRoot){hosts.push(el.tagName.toLowerCase()),walk(el.shadowRoot)}}};walk(document);return JSON.stringify({shadowHosts:hosts})})()"}'+adom-desktop browser_eval '{"sessionId":"...","expr":"$$deep(\"a[href]\").length"}'   # counts across shadow roots ``` -**2. Nested scroll containers — `window.scroll*` does nothing.** Many layouts put content in an INNER-scroll box, so `window.scrollTo` / reading `scrollY` don't move it and your screenshot **overshoots** the-target. Scroll the **element** — `scrollIntoView` walks up to whatever container actually scrolls:+**Still verify by DOM, then by eye.** To count cards/links/rows, count in `browser_eval` by document-Y+(`rect.top + window.scrollY`) — immune to an overshot screenshot — then `browser_screenshot_element` (or+`browser_scroll` + `browser_screenshot`) to confirm. And **first check whether a page is even shadow DOM**+before assuming: a shadow survey (`$$deep` finding more than `querySelectorAll`) tells you; often an "empty"+result just means a wrong selector on plain DOM. -```js-el.scrollIntoView({ block: 'center' })   // NOT window.scrollTo(...)-```--**3. Count in the DOM, confirm with the eye — in that order.** To count cards/links/rows, count in-`browser_eval` using positions (`rect.top + window.scrollY` = document-Y), which is immune to overshot-screenshots. THEN `scrollIntoView` the element and screenshot to confirm visually. Agreement across-DOM-count + position-cluster + screenshot beats any single signal.+**fullPage caveat:** `browser_screenshot { fullPage:true }` only covers *document*-level scroll. On a+nested-scroll SPA it returns just the viewport and a `nestedScroll:true` hint — use `browser_screenshot_element`+for one region, or `browser_scroll` through the container. -Reminder: `browser_eval` allows **no semicolons** — use the comma operator or an IIFE (as above). If a+Reminder: `browser_eval` allows **no semicolons** — use the comma operator or an IIFE. If a screenshot lands on the wrong content, don't trust it — it almost always means an inner scroll container; re-scroll the element, don't nudge the window.