Files
command-center/agent/managed-skills/browser-screenshot-disk-and-cookies/SKILL.md
T

4.2 KiB
Raw Blame History

name, description
name description
browser-screenshot-disk-and-cookies Save omp managed-browser screenshots to real files (tab.screenshot path is silently ignored), prove/clear cookie state (clearCookies is domain-scoped), and get embedded-image commits past the secret gate.

omp managed browser from Eval: screenshots, cookies, page reads

Friction-earned 2026-10-21 (cookie-state proof on a local stack), same day (static HTML guide verification — four wasted API calls from signature guesses), re-earned same day on the franksign screenshot-walkthrough campaign (19 embedded PNGs, two cookie traps, one secret-gate false positive).

Screenshots to real files

  • tab.screenshot({ path }) returns the image to the model but the path option is silently ignored on the managed-browser path — no file appears on disk.
  • Working recipe: re-capture raw and decode base64 to disk:
    await tab.run(async ({ page }, p) => {
      const r = await page.screenshot({ encoding: "base64", type: "png" });
      await Bun.write(p, Buffer.from(typeof r === "string" ? r : r.data, "base64"));
    }, { args: ["/tmp/x.png"] });
    
    This puppeteer variant returns the base64 string directly, not {data} — handle both or you write undefined.
  • computer.window("Firefox").screenshot() fails (captureWindow: unavailable under niri) — don't go that way.
  • Downscale before embedding: magick "$f" -resize 1000x "$f" keeps dark-theme UI PNGs at 20–80 kB each.
  • Cookies DO cross browser.open calls: the headless browser is one shared process with one jar (a stale persona session from an earlier campaign hijacked an "anonymous" walkthrough tab).
  • tab.clearCookies() is domain-scoped to the current page origin — running it on about:blank clears nothing and silently leaves the previous session live (a "signer" tab showed the admin's dashboard). Correct sequence: goto(app-origin) → clearCookies() → reload(), then verify with page.cookies(), not with page text.
  • Cookie proof (ground truth):
    const cs = await page.cookies()
    return cs.map(c => `${c.name}=${c.value.slice(0,12)}… dom=${c.domain} exp=${c.expires}`).join("\n")
    

Committing screenshots: the secret-gate false positive

  • Data-URI PNGs in a diff WILL trip shape-based secret gates (ASIA[A-Z0-9]{16} etc. appear as random substrings in base64 streams, worse with case-insensitive grep).
  • Prove noise, don't assume: run the gate's own pattern with grep -oEi over git diff --cached and eyeball the matches (image-byte substrings, not credentials; confirm screenshots show passwords masked).
  • Then use the gate's sanctioned override with the evidence in the commit body: ALLOW_SECRETS=1 git commit -m "... ALLOW_SECRETS: the N hits are ASIA-shape coincidences inside PNG base64 ...". Never --no-verify.

API signatures (guesses cost calls)

  • browser.open({ url, name }) — options object; browser.open(url) → TypeError.
  • tab.wait(ms) does not exist → await Bun.sleep(ms).
  • tab.run(fnOrCode) executes in an isolated Node/Puppeteer realm ({ tab, page, browser }, plus args as trailing params), NOT the page — document is not defined means you wanted tab.evaluate(exprString) (page-global expression; no top-level return; wrap an IIFE when you need one).
  • tab.text("svg") etc. are direct page helpers — prefer them over evaluate for plain reads.
  • For app UIs with labelled forms, role/textbox[name="Exact label *"] beats label=...: visible labels often include a required-marker the source selector lacks.

Eval cell output

  • log(...) inside a JS eval cell can be swallowed (printed nothing across several runs); return from the cell always shows. Put every value you need to see into the return string.

Static page verification loop

Serve with python3 -m http.server <port> -d <dir> spawned via Bun.spawn, open, tab.evaluate anchor cross-check (hrefs vs ids), img census (complete && naturalWidth > 0), screenshots, tab.close(), proc.kill(9). If a rendered label looks wrong in a low-res screenshot, read the real DOM text before "fixing" markup — &lt;id&gt; renders as <id> and misreads as </id> at thumbnail size.