Dev Browser Skill
Browser-Automatisierung, die den Seitenstatus über Skriptausführungen hinweg beibehält. Schreibe kleine, fokussierte Skripte, um Aufgaben schrittweise zu erledigen. Sobald du einen Teil eines Workflows nachgewiesen hast und wiederholte Arbeit anfällt, kannst du ein Skript schreiben, um die wiederholte Arbeit in einer einzigen Ausführung zu erledigen.
Wahl des Ansatzes
- Lokale/quelloffene Seiten: Lies zuerst den Quellcode, um Selektoren direkt zu schreiben
- Unbekannte Seitenlayouts: Verwende
getAISnapshot(), um Elemente zu entdecken undselectSnapshotRef(), um mit ihnen zu interagieren - Visuelles Feedback: Erstelle Screenshots, um zu sehen, was der Benutzer sieht
Einrichtung
Zwei Modi verfügbar. Frage den Benutzer, falls unklar, welcher verwendet werden soll.
Standalone-Modus (Standard)
Startet einen neuen Chromium-Browser für frische Automatisierungssitzungen.
./skills/dev-browser/server.sh &
Füge das --headless-Flag hinzu, wenn der Benutzer es wünscht. Warte auf die Ready-Meldung, bevor du Skripte ausführst.
Erweiterungsmodus
Stellt eine Verbindung zum vorhandenen Chrome-Browser des Benutzers her. Verwende dies, wenn:
- Der Benutzer bereits auf Websites angemeldet ist und du Dinge hinter einer authentifizierten Erfahrung erledigen sollst, die keine lokale Entwicklung ist.
- Der Benutzer dich bittet, die Erweiterung zu verwenden.
Wichtig: Der Kernablauf bleibt derselbe. Du erstellst benannte Seiten innerhalb seines Browsers.
Starte den Relay-Server:
cd skills/dev-browser && npm i && npm run start-extension &
Warte auf Waiting for extension to connect... gefolgt von Extension connected in der Konsole. So weißt du, dass ein Client verbunden ist und der Browser bereit ist, gesteuert zu werden.
Workflow:
- Skripte rufen
client.page(„name“)auf, genau wie im normalen Modus, um neue Seiten zu erstellen / mit bestehenden zu verbinden. - Die Automatisierung läuft in der tatsächlichen Browsersitzung des Benutzers.
Wenn die Erweiterung noch nicht verbunden ist, sage dem Benutzer, er soll sie starten und aktivieren. Download-Link: https://github.com/SawyerHood/dev-browser/releases
Schreiben von Skripten
Führe alle Skripte aus dem Verzeichnis
skills/dev-browser/aus. Der Import-Alias@/erfordert die Konfiguration dieses Verzeichnisses.
Führe Skripte inline mit Heredocs aus:
cd skills/dev-browser && npx tsx <<'EOF'
import { connect, waitForPageLoad } from "@/client.js";
const client = await connect();
// Erstelle eine Seite mit benutzerdefinierter Viewport-Größe (optional)
const page = await client.page("example", { viewport: { width: 1920, height: 1080 } });
await page.goto("https://example.com");
await waitForPageLoad(page);
console.log({ title: await page.title(), url: page.url() });
await client.disconnect();
EOF
Schreibe nur dann in tmp/-Dateien, wenn das Skript wiederverwendet werden muss, komplex ist oder der Benutzer es explizit anfordert.
Schlüsselprinzipien
- Kleine Skripte: Jedes Skript macht EINE Sache (navigieren, klicken, ausfüllen, prüfen)
- Zustand auswerten: Protokolliere/gib den Zustand am Ende zurück, um nächste Schritte zu entscheiden
- Beschreibende Seitennamen: Verwende „checkout“, „login“, nicht „main“
- Trennen zum Beenden:
await client.disconnect()– Seiten bleiben auf dem Server bestehen - Einfaches JS in evaluate:
page.evaluate()läuft im Browser – keine TypeScript-Syntax
Workflow-Schleife
Folge diesem Muster für komplexe Aufgaben:
- Schreibe ein Skript, um eine Aktion auszuführen
- Führe es aus und beobachte die Ausgabe
- Werte aus – hat es funktioniert? Wie ist der aktuelle Zustand?
- Entscheide – ist die Aufgabe erledigt oder brauchen wir ein weiteres Skript?
- Wiederhole, bis die Aufgabe erledigt ist
Kein TypeScript im Browser-Kontext
Code, der an page.evaluate() übergeben wird, läuft im Browser, der kein TypeScript versteht:
// ✅ Richtig: normales JavaScript
const text = await page.evaluate(() => {
return document.body.innerText;
});
// ❌ Falsch: TypeScript-Syntax führt zur Laufzeit zu Fehlern
const text = await page.evaluate(() => {
const el: HTMLElement = document.body; // Typannotation bricht im Browser!
return el.innerText;
});
Daten scrapen
Zum Scrapen großer Datensätze solltest du Netzwerkanfragen abfangen und wiederholen, anstatt durch das DOM zu scrollen. Siehe references/scraping.md für die vollständige Anleitung zu Request-Erfassung, Schema-Erkennung und paginierter API-Wiedergabe.
Client-API
const client = await connect();
// Hole oder erstelle eine benannte Seite (Viewport gilt nur für neue Seiten)
const page = await client.page("name");
const pageWithSize = await client.page("name", { viewport: { width: 1920, height: 1080 } });
const pages = await client.list(); // Liste aller Seitennamen
await client.close("name"); // Schließe eine Seite
await client.disconnect(); // Trennen (Seiten bleiben bestehen)
// ARIA-Snapshot-Methoden
const snapshot = await client.getAISnapshot("name"); // Hole den Accessibility-Baum
const element = await client.selectSnapshotRef("name", "e5"); // Hole Element per Referenz
Das page-Objekt ist eine standardmäßige Playwright Page.
Warten
import { waitForPageLoad } from "@/client.js";
await waitForPageLoad(page); // Nach der Navigation
await page.waitForSelector(".results"); // Auf bestimmte Elemente warten
await page.waitForURL("**/success"); // Auf bestimmte URL warten
Seitenzustand inspizieren
Screenshots
await page.screenshot({ path: "tmp/screenshot.png" });
await page.screenshot({ path: "tmp/full.png", fullPage: true });
ARIA-Snapshot (Elementerkennung)
Verwende getAISnapshot(), um Seitenelemente zu entdecken. Gibt den Accessibility-Baum im YAML-Format zurück:
- banner:
- link "Hacker News" [ref=e1]
- navigation:
- link "new" [ref=e2]
- main:
- list:
- listitem:
- link "Article Title" [ref=e8]
- link "328 comments" [ref=e9]
- contentinfo:
- textbox [ref=e10]
- /placeholder: "Search"
Interpretation von refs:
[ref=eN]– Elementreferenz für Interaktion (nur sichtbare, klickbare Elemente)[checked],[disabled],[expanded]– Elementzustände[level=N]– Überschriftenebene/url:,/placeholder:– Elementeigenschaften
Interaktion mit refs:
const snapshot = await client.getAISnapshot("hackernews");
console.log(snapshot); // Finde die benötigte Referenz
const element = await client.selectSnapshotRef("hackernews", "e2");
await element.click();
Fehlerbehebung
Der Seitenzustand bleibt nach Fehlern bestehen. Fehlersuche mit:
cd skills/dev-browser && npx tsx <<'EOF'
import { connect } from "@/client.js";
const client = await connect();
const page = await client.page("hackernews");
await page.screenshot({ path: "tmp/debug.png" });
console.log({
url: page.url(),
title: await page.title(),
bodyText: await page.textContent("body").then((t) => t?.slice(0, 200)),
});
await client.disconnect();
EOF