Auflösung natürlichsprachlicher Selektoren
Ein .demo-Skript sagt, was es bedeutet:
selectors:
composer = ask "das Nachrichtenfeld unten im Chat"
Ihre Aufgabe ist es, herauszufinden, was das tatsächlich im Live-DOM ist, und es in
scripts/<name>.selectors.json zu schreiben, damit script.mjs es in einen gewöhnlichen
Selector kompilieren und driver.mjs eine deterministische Aufnahme machen kann.
Sie sind der Resolver. Nichts in der Pipeline ruft ein Modell auf – script.mjs
liest die Sidecar-Datei und weigert sich, ohne sie zu kompilieren. Die Auflösung erfolgt hier,
einmalig, vor der Aufzeichnung, weil das Timing der Aufnahme die Video-Zeitleiste ist und
eine Modell-Roundtrip während eines Laufs zu toter Luft im fertigen Video führen würde.
Bevor Sie beginnen
- Die App muss erreichbar sein und, falls ein Login erforderlich ist, bereits angemeldet im Chrome des Benutzers. Das ist der Sinn der Erweiterung: Sie greift auf die echte Sitzung zu, also gibt es kein SSO-Ritual und keinen E-Mail-Code zum Ausfüllen.
- Lesen Sie zuerst das Skript. Sie benötigen den
app:/target:-Header für die URL und die Beats, weil Selektoren in der Reihenfolge des Ablaufs aufgelöst werden müssen (siehe unten).
Vorgehen
-
Holen Sie die Arbeitsliste.
cd pipeline node script.mjs ../scripts/<name>.demo --intentsJSON auf stdout: jeder
ask-Selector, sein Intent und seine aktuelle Auflösung (null, falls ungelöst). Lösen Sie die Null-Einträge auf. Lösen Sie den Rest nur dann erneut auf, wenn der Benutzer sagt, dass der Ablauf beschädigt ist. -
Laden Sie die Browser-Tools in EINEM ToolSearch-Aufruf, rufen Sie dann
tabs_context_mcpauf, bevor Sie etwas anderes tun. Erstellen Sie einen neuen Tab mittabs_create_mcp, es sei denn, der Benutzer hat auf einen vorhandenen verwiesen. -
Gehen Sie den Ablauf in der Beat-Reihenfolge durch. Dies ist der Teil, der leicht falsch gemacht wird: Viele Selektoren existieren nicht auf der Startseite. Eine Ergebnistabelle erscheint erst, nachdem eine Frage gesendet wurde; ein „Stop“-Steuerelement existiert nur, während etwas generiert wird. Gehen Sie also die Beats des Skripts Schritt für Schritt durch und lösen Sie jeden
askin dem Moment auf, in dem sein Element auf dem Bildschirm ist.Live-Daten. Bevor Sie einen Schritt ausführen, der etwas erstellt, ändert, sendet oder löscht, halten Sie inne und fragen Sie den Benutzer.
feature.demosendet vier Nachrichten an ein echtes Salesmessage-Konto. Fahren Sie mit der Maus, anstatt zu klicken, wenn Sie nur etwas lokalisieren müssen, und klicken Sie niemals auf ein destruktives Steuerelement, um „zu sehen, was es ist“. -
Finden Sie das Element und wählen Sie den haltbarsten Griff. In der Reihenfolge der Präferenz:
Bevorzugt Warum [data-testid=...],data-test,data-qadort platziert, um ausgewählt zu werden; überlebt Redesigns eine stabile idgut, es sei denn, sie sieht generiert aus ( :r3a:,id-1a2b)Button/Link nach exaktem accessible-name → btn:Nameder Treiber btn:matcht Text,aria-labelund inneresimg[alt][aria-label=...],[role=...]stabil und in der Regel semantisch semantische Struktur ( main table,nav a[href="/teams"])überlebt Styling-Änderungen Verwenden Sie niemals:
nth-child-Ketten, generierte Klassennamen (css-1a2b3c, lange Tailwind-Stapel) oder irgendetwas, das auf generierten Inhalt angewiesen ist. Letzteres ist die Falle, die diese ganze Funktion vermeiden soll – eine Modellantwort wird bei jedem Durchlauf anders formuliert, sodass ein Selektor, der auf ihren Text matcht, ein Glücksspiel ist. Verankern Sie sich stattdessen am Container oder an einem Abschlusssignal. -
Überprüfen Sie, bevor Sie es schreiben. Bestätigen Sie für jeden Kandidaten mit
javascript_tool, dass er exakt ein Element matcht und dass das Element sichtbar ist:const q = 'div[data-testid="chat-input"]'; const n = document.querySelectorAll(q); console.log(JSON.stringify({ q, count: n.length, visible: n[0] ? !!(n[0].offsetWidth || n[0].offsetHeight) : false, tag: n[0]?.tagName, editable: n[0]?.isContentEditable, }));Lesen Sie es mit
read_console_messageszurück. Mehr als ein Treffer oder null bedeutet, dass Sie weitersuchen müssen – schreiben Sie keinen Selektor, den Sie nicht match gesehen haben. -
Schreiben Sie die Sidecar-Datei,
scripts/<name>.selectors.json:{ "resolvedAgainst": "https://claude.ai/new", "resolvedAt": "2026-08-10T09:00:00Z", "resolvedBy": "claude-in-chrome", "selectors": { "das Nachrichtenfeld unten im Chat": { "spec": "div[data-testid=\"chat-input\"]", "evidence": "contenteditable tiptap div, aria-label 'Schreibe eine Nachricht', 1 Treffer, sichtbar" } } }Schlüssel nach dem Intent-Text, wortwörtlich aus dem Skript – eine Umbenennung eines Selektors oder eine Neuanordnung des Blocks darf keine Auflösung verwaist lassen.
specist, was auch immer der Treiber akzeptiert: ein roher Puppeteer-Selektor,btn:Text|Altoder::-p-text(Teilstring).evidenceist das, was Sie tatsächlich beobachtet haben; schreiben Sie es so, dass die nächste Person erkennen kann, ob es noch gültig ist. -
Bestätigen und zurückgeben.
node script.mjs ../scripts/<name>.demo --intents # erwarte 0 ungelöste node script.mjs ../scripts/<name>.demo --print # kompiliertBerichten Sie, was Sie aufgelöst haben, worüber Sie raten mussten und was Sie übersprungen haben, weil es einen destruktiven Schritt erforderte.
Wenn Sie einen nicht auflösen können
Sagen Sie es und stoppen Sie; erfinden Sie keinen Selektor. Ein ungelöster Intent ist ein sauberer Kompilierungsfehler, bevor Chrome überhaupt gestartet wird. Ein falscher Intent führt mitten in der Aufnahme zu einem Fehler – der teure Ort für einen Fehler. Wenn zwei Elemente gleich gut auf die Beschreibung passen, fragen Sie den Benutzer, welches gemeint war,
anstatt zu raten.
Fallstricke
| Symptom | Ursache / Lösung |
|---|---|
| Das Element ist nicht auf der Seite | Es erscheint später im Ablauf. Gehen Sie die Beats in der richtigen Reihenfolge durch; lösen Sie jeden Intent auf, wenn sein Element tatsächlich auf dem Bildschirm ist |
| Zwei Elemente passen | Die Beschreibung ist mehrdeutig. Engen Sie sie mit dem Benutzer ein und formulieren Sie dann auch den ask im Skript um, damit die nächste Auflösung eindeutig ist |
| Selektor funktioniert jetzt, bricht beim nächsten Durchlauf | Er ist auf generierten Inhalt oder eine generierte Klasse angewiesen. Verankern Sie ihn neu an einer Testid, einer Rolle oder einem Container |
Ein wait ... gone-Anker | Diese sind von Natur aus flüchtig (z. B. ein Stop-Button während der Generierung). Lösen Sie ihn auf, während er auf dem Bildschirm ist, und bevorzugen Sie aria-label – es ändert sich weniger als der Text |
| Auflösung nach einem Redesign verschoben | Löschen Sie nur diesen Schlüssel aus der Sidecar-Datei und führen Sie sie erneut aus. Das .demo ändert sich nicht; das ist der Sinn |
| Dialog blockiert die Erweiterung | Klicken Sie nicht auf Dinge, die confirm/alert öffnen. Ein modaler Dialog friert die Erweiterung ein, bis er manuell geschlossen wird |