Zum Hauptinhalt springen

Befehlsautorenschaft

Diese Anleitung erklärt, wie Sie einen Seitenbefehl in der Otto-Erweiterungslaufzeit hinzufügen, ohne Protokoll-, Auth- oder Lebenszyklusgarantien zu brechen. Nach Abschluss dieser Schritte ist Ihr Befehl über otto commands list discoverbar, über otto cmd ausführbar und über otto test testbar.

Bevor Sie beginnen​

Wahrheitsquelle​

AnliegenPfad
Befehlstypen und Metadatenverträgeextension/src/commands/types.ts
Seitenbefehlsregistrierungextension/src/commands/index.ts
Seitenbefehlsorchestrierungextension/src/runtime/command-runtime.ts
Aktionsausführungsdispatchextension/src/runtime/command-executor.ts

Schritte​

1. Befehlsmodul erstellen​

Erstellen Sie extension/src/commands/<site>/<command-id>.ts. Deklarieren Sie Metadaten, die dem tatsächlichen Laufzeitverhalten entsprechen — Laufzeit verwendet Metadaten, um die Ausführung zu steuern und Eingaben zu bereinigen, bevor Ihr Handler läuft.

import type { SiteCommand } from '../types.js';

export const getItemsCommand: SiteCommand = {
metadata: {
site: 'example.com',
id: 'getItems',
displayName: 'Get Items',
requiresAuth: false,
inputFields: [
{ name: 'limit', type: 'number', optional: true, description: 'Max items to return' }
]
},
async execute(ctx, input) {
const limit = Number((input as { limit?: number }).limit ?? 20);
const items = await ctx.executeScript((max: number) => {
return Array.from(document.querySelectorAll('[data-item]'))
.slice(0, max)
.map((el) => ({ text: (el.textContent ?? '').trim() }));
}, [limit]);
return { count: items.length, items };
}
};

2. Metadatenvertrag verstehen​

FeldErforderlichZweck
siteJaSeitenbundle-Eigentum und Tab-URL-Validierung
idJaBefehlskennung, die in command.run / command.test verwendet wird
requiresAuthJaOb Auth-Vorabprüfung vor execute läuft
requiresDebuggerFocusNeinOpt-in für Fokus-Emulation über chrome.debugger
preloadHostNeinNavigation zum Host vor execute garantieren
inputFieldsNeinDeklaratives Eingabeschema; steuert Laufzeitvalidierung
inputAtLeastOneOfNeinCross-Feld-bedingte Anforderung

3. Execute mit begrenzter, deterministischer Logik implementieren​

Halten Sie execute(ctx, input, authMode) begrenzt: keine Endlosschleifen, kein unbegrenztes DOM-Scraping. Geben Sie deterministische Fehler zurück, anstatt stille Wiederholungen zu verwenden. Automatisieren Sie niemals Anmeldeübermittlung.

4. Seitenfehler explizit behandeln​

Bei Verwendung von ctx.executeScript oder ctx.executeScriptWithDomHelpers kann Chromium Seitenwerfe stillschweigend verschlucken. Verwenden Sie dieses Muster, um Seitenfehler zu erhalten:

const result = await ctx.executeScriptWithDomHelpers(async () => {
try {
// Ihre Seitenlogik hier
return { ok: true };
} catch (error) {
return {
__ottoSerializedCommandError: true,
code: 'site_specific_error_code',
message: error instanceof Error ? error.message : 'site_specific_error_code',
};
}
}, []);

if (ctx.isSerializedScriptError(result)) {
return result;
}

Dies hält Befehlsfehler deterministisch und zeigt spezifische seitendiagnostiken (z.B. reddit_post_comment_comcomposer_missing) in otto test-Ausgabe.

5. Test-Hook für Stream-Befehle hinzufügen (optional)​

Für Befehle, die Netzwerkereignisse streamen, fügen Sie test(ctx, input, helpers) hinzu. Siehe Befehlsautorenschaft-Vorlagen für eine kopierfertige Stream-Test-Hook-Vorlage.

6. Befehl im Seitenbundle registrieren​

Fügen Sie Ihren Befehl zu extension/src/commands/index.ts im relevanten Seitenbundle hinzu. Der Befehl ist jetzt über command.list discoverbar.

7. Tests schreiben​

Fügen Sie Tests hinzu, die Validierungsgates, Auth-Vorabprüfungsverhalten und Execute/Test-Fallback-Semantik abdecken. Siehe die Testmatrix unten.

Laufzeitvalidierungsverhalten​

Laufzeit validiert Eingaben strikt, wenn inputFields deklariert ist:

BedingungFehlercode
Unbekannter Eingabeschlüsselunexpected_command_input
Fehlendes erforderliches Feldmissing_command_input
Typ-Nichtübereinstimmunginvalid_command_input_type
Nicht erfüllte Cross-Feld-Bedingungmissing_command_input_one_of

Validierungsfehler lehnen den Befehl ab, bevor execute läuft. Befehlshandler erhalten immer bereinigte, validierte Eingaben.

Erfolg überprüfen​

Nach der Registrierung Ihres Befehls:

# Bestätigen Sie, dass er in der Discovery erscheint
otto commands list --site example.com

# Führen Sie ihn mit otto test aus
otto test example.com getItems

# Mit expliziter Eingabe ausführen
otto test example.com getItems --payload '{"limit": 5}'

# Zielseiteninhalt schnell inspizieren (Standard ist Markdown)
otto extract-content https://example.com

Ein erfolgreicher Lauf gibt ein JSON-Ergebnis mit messageType: result zurück und beendet sich mit Code 0.

Für extraktionslastiges Debugging, bevorzugen Sie otto extract-content gegenüber handgeschriebenen primitiven Sequenzen. Es konsolidiert die Ausgabewahl an einem Ort:

  • --format markdown (Standard) für schnelles Seitenverständnis
  • --format clean_html --selector <css> für Selektor-Discovery und DOM-Debugging
  • --format distilled_html für leserlichkeits sichere artikelstilige Erfassung
  • --format raw_html --selector <css> nur, wenn genaue ungefilterte Markierung erforderlich ist
  • --format text --tab-session <id> für sichtbare Textextraktion aus verwalteten Tabs

Sicherheitsregeln​

  • Automatisieren Sie niemals Anmeldeübermittlung. Verwenden Sie manual_login_required-Übergabe für Auth-erforderliche Befehle.
  • Halten Sie die Seiten-URL-Validierung strikt. Befehle laufen nur auf passenden Tab-Domains.
  • Geben Sie deterministische Vorbedingungsfehler zurück, anstatt stille Wiederholungen zu verwenden.
  • Halten Sie die Befehlsausgabe frei von sensiblen Werten.
  • Halten Sie die Ausgabeform so stabil, dass sie für CLI- und Agenten-Parsing geeignet ist.

Testmatrix​

SzenarioWarum es wichtig ist
Erfolgreiche Ausführung mit gültiger EingabeBestätigt Happy-Path-Vertrag und Payload-Form
Fehlende erforderliche EingabeÜberprüft Metadatenvalidierungs-Gating
Unerwarteter EingabeschlüsselVerhindert verstecktes/Legacy-Payload-Driften
requiresAuth-Befehl auf nicht authentifizierter SeiteÜberprüft explizite manual_login_required-Übergabe
command.test Stream-DeklarationspfadBestätigt Stream-Lebenszyklus und Listener-Manifest-Verhalten
command.test Execute-Fallback-PfadStellt Kompatibilität für Befehle ohne benutzerdefinierten Test-Hook sicher

Nächste Schritte​