droid-control

Par factory-ai · factory-plugins

Contrôlez des TUI en terminal et des applications web/Electron pour les tests, démos, assurance qualité et tâches d'utilisation de l'ordinateur. À utiliser lorsque vous devez automatiser une CLI, piloter un navigateur, enregistrer une démo ou capturer des artefacts de preuve.

npx skills add https://github.com/factory-ai/factory-plugins --skill droid-control

Contrôle Droid

Automatisez les terminaux et navigateurs. Trois décisions de routage, puis les atoms vous guident pour le reste.

Règles fondamentales

  1. Applications réelles, environnements réels. Le comportement non-déterministe (réponses LLM, latence réseau, sortie variable) est attendu. Gérez-le avec wait / wait-idle. Ne remplacez jamais par des fixtures ou données mockées.
  2. Engagez-vous dans l'exécution. Une fois que vous avez choisi un driver, exécutez le plan. Si quelque chose échoue en cours d'exécution, récupérez et réessayez — ne réévaluez pas l'approche.
  3. Les atoms sont autonomes. Chargez-en un et suivez sa mécanique. Aucune référence croisée nécessaire.
  4. tctl est le SEUL moyen de lancer des sessions enregistrées. tctl gère l'enregistrement en enveloppant asciinema rec autour du PTY — le tuistory brut n'a pas de capacité d'enregistrement et n'en aura jamais. N'appelez jamais tuistory launch directement ; les flags inconnus font crasher tuistory-relay. Toujours résoudre TCTL à son chemin absolu du système de fichiers avant utilisation, particulièrement quand on délègue à des workers (ils n'héritent pas de ${DROID_PLUGIN_ROOT}).
  5. Isolez chaque exécution. Plusieurs droids peuvent filmer simultanément sur la même machine. Les noms de session et chemins de sortie partagent un espace de noms global (/tmp/tctl-sessions/). Au début de chaque workflow, générez un ID d'exécution (RUN_ID=$(date +%s)-$$ ou similaire) et utilisez-le comme préfixe pour tous les noms de session et répertoire temporaire limité pour tous les fichiers de sortie :
    RUN_ID="$(date +%s)-$$"
    RUN_DIR="$(mktemp -d /tmp/droid-run-${RUN_ID}-XXXXXX)"
    # Noms de session : -s ${RUN_ID}-before, -s ${RUN_ID}-after
    # Chemins de sortie : ${RUN_DIR}/before.cast, ${RUN_DIR}/after.cast

    N'utilisez jamais de noms de session nus comme -s demo, -s before, -s after — ils entreront en collision avec des exécutions concurrentes.

Routage

Trois recherches indépendantes. Faites les trois, puis chargez l'union des skills qu'elles produisent.

1. Routage cible — qu'automatisez-vous ?

Cible Charger ces skills
Droid CLI (droid-dev, droid exec) droid-cli + backend tuistory via ${DROID_PLUGIN_ROOT}/bin/tctl
Droid CLI (preuve de terminal réel) true-input + droid-cli
Autre TUI terminal Backend tuistory via ${DROID_PLUGIN_ROOT}/bin/tctl
Autre TUI terminal (preuve de terminal réel) true-input
Page web ou application Electron agent-browser
Séquences d'octets de terminal brut true-input + pty-capture

tuistory est le défaut pour le travail en terminal. Utilisez true-input uniquement quand vous avez besoin de preuve de rendu réel du terminal.

2. Routage stage — qu'a besoin le workflow ?

Chaque workflow traverse des stages. Chargez les atoms pour chaque stage que vous utiliserez.

Stage Skill Quand charger
Capture capture Toujours — chaque workflow enregistre ou capture quelque chose
Compose compose Quand le livrable est un artefact produit (vidéo, captures d'écran annotées, image de comparaison)
Verify verify Toujours — chaque livrable est vérifié par rapport aux engagements

3. Routage artefact — compose a-t-il besoin d'outils de finition ?

Pertinent uniquement quand compose est chargé.

Besoin d'artefact Également charger
Finition vitrine (chrome de fenêtre, cadre de marque, arrière-plan cinématique) showcase
Effets et superpositions de frappes clavier (compose gère ceci — ce sont des champs dans le JSON props Remotion)

Forme du workflow

Commande (intention + engagements)
  → Routage cible (charger les atoms du driver)
  → Capture (enregistrement / capture d'écran / byte-capture)
  → Compose (assembler le livrable, si nécessaire)
  → Verify (vérifier par rapport aux engagements)
  → Rapport

Les commandes déclarent quoi produire. Les atoms possèdent le comment.

Disposition par défaut

Défaut : single. Un clip montrant la cible/l'état final. Choisissez ceci sauf si le livrable est fondamentalement une comparaison.

Cas Disposition
Nouvelle fonctionnalité (pas d'état antérieur significatif) single
Correction de bug, preuve en un clip du chemin fonctionnant single
Walkthrough / tutoriel / hero readme single
Preuve de régression (cassé vs corrigé) side-by-side
Refactorisation préservant le comportement (parité visuelle est le point) side-by-side
L'utilisateur demande explicitement une comparaison side-by-side

Ne synthétisez pas un état « avant » pour justifier side-by-side. S'il n'y a pas de ligne de base réelle, utilisez single.

Délégation

L'agent parent planifie et orchestre. Le travail mécanique s'exécute dans des sous-agents workers via l'outil Task. Cela garde le contexte du parent propre et active le parallélisme.

Quoi déléguer

Tâche Déléguer ? Pourquoi
Capturer clip (disposition single) OUI Le worker exécute le script d'interaction de bout en bout et retourne le chemin .cast
Capturer les deux clips (disposition de comparaison) OUI — run_in_background=true pour chacun Les branches sont indépendantes ; s'exécutent en parallèle
Rendu Remotion OUI Nécessite uniquement JSON props, chemins de clips, chemin de sortie. Exécute render-showcase.sh (gère conversion .cast, profils de fidélité, détection de durée, nettoyage)
Planification, scripting d'interaction NON — parent Nécessite le contexte PR et jugement éditorial
Construction de disposition et props NON — parent Nécessite des décisions éditoriales sur les effets, timing, labels
Vérification NON — parent Nécessite le contexte d'engagement
Seul ffprobe / vérification d'existence de fichier NON — inline Trop trivial pour le coût du subagent

Comment déléguer

Étape 0 : Résoudre les chemins et générer un ID d'exécution. Les workers n'héritent pas de ${DROID_PLUGIN_ROOT}. Résolvez une fois, collez partout :

TCTL="$(realpath "${DROID_PLUGIN_ROOT}/bin/tctl")"
RENDER="$(realpath "${DROID_PLUGIN_ROOT}/scripts/render-showcase.sh")"
RUN_ID="$(date +%s)-$$"
RUN_DIR="$(mktemp -d /tmp/droid-run-${RUN_ID}-XXXXXX)"

Utilisez ${RUN_DIR} pour tous les fichiers de sortie (enregistrements, props, vidéo rendue). Utilisez ${RUN_ID}- comme préfixe pour tous les noms de session. N'utilisez jamais de noms nus comme -s before ou chemins codés en dur comme /tmp/before.cast.

Donnez aux workers des commandes exactes avec les chemins absolus résolus — pas des instructions abstraites, pas tuistory, pas ${DROID_PLUGIN_ROOT}. Le parent pense ; le worker exécute :

Prompt Task pour un worker de capture :
  « Exécutez ces commandes dans l'ordre. Signalez le chemin du fichier de sortie et les erreurs.
   1. /abs/path/to/bin/tctl launch "droid-dev" -s 1712345678-42-before --backend tuistory \
        --repo-root /abs/path/to/baseline/worktree \
        --cols 120 --rows 36 --record /tmp/droid-run-1712345678-42-xxxx/before.cast \
        --env FORCE_COLOR=3 --env COLORTERM=truecolor
   2. /abs/path/to/bin/tctl -s 1712345678-42-before wait ">" --timeout 15000
   3. /abs/path/to/bin/tctl -s 1712345678-42-before type "hello world"
   4. /abs/path/to/bin/tctl -s 1712345678-42-before press enter
   5. /abs/path/to/bin/tctl -s 1712345678-42-before wait-idle
   6. /abs/path/to/bin/tctl -s 1712345678-42-before close »
Prompt Task pour un worker de rendu Remotion :
  « Exécutez cette commande. Signalez le chemin du fichier de sortie et les erreurs.
   /abs/path/to/scripts/render-showcase.sh \
     --props /tmp/droid-run-1712345678-42-xxxx/showcase-props.json \
     --output /tmp/droid-run-1712345678-42-xxxx/demo.mp4 \
     /tmp/droid-run-1712345678-42-xxxx/before.cast /tmp/droid-run-1712345678-42-xxxx/after.cast »

Modèle de capture parallèle (flux de comparaison uniquement)

Applicable uniquement quand le tableau Disposition par défaut ci-dessus sélectionne side-by-side. Pour une disposition single, lancez un seul worker de capture et ignorez cette section.

Pour les démos de comparaison avant/après, lancez les deux workers de capture simultanément :

1. Le parent construit le script d'interaction (identique pour les deux branches)
2. Lancer worker A : capturer la branche baseline/référence avec `--repo-root` défini à ce worktree
3. Lancer worker B : capturer la branche candidate/changement avec `--repo-root` défini à ce worktree
4. Attendre que les deux se complètent (TaskOutput)
5. Collecter les chemins .cast des résultats
6. Continuer vers compose

Outillage partagé

Les drivers de terminal utilisent le wrapper tctl unifié. agent-browser a son propre CLI et n'utilise pas tctl.

Les drivers peuvent être combinés dans un workflow — p. ex., tctl pour une CLI et agent-browser pour une interface web avec laquelle elle interagit.

Prérequis

Stage Plateforme Requis Optionnel
tuistory Tous tuistory, asciinema, agg tmux
true-input Linux/Wayland cage, wtype, terminal Wayland, /dev/dri/* grim, wf-recorder
true-input Windows (KVM) libvirt, qemu, VM KVM avec SPICE + SSH, variables d'env DROID_VM_* virt-manager
true-input macOS (QEMU) qemu, socat, VM macOS avec SSH, variables d'env DROID_MAC_*
agent-browser Tous agent-browser (+ agent-browser install)
compose Tous ffmpeg, ffprobe, agg
showcase Tous Node.js (>= 18), Chrome/Chromium

Commandes d'installation

# Driver tuistory + enregistrement
npm install -g tuistory                              # driver PTY virtuel
pip install asciinema                                # enregistrement terminal (tctl enveloppe ceci)
cargo install --git https://github.com/asciinema/agg  # convertisseur .cast -> .gif (compose en a besoin)

# Driver true-input (Linux/Wayland)
sudo apt-get install -y cage wtype                   # requis : compositeur headless + injection de frappe
sudo apt-get install -y grim wf-recorder             # optionnel : capture d'écran + enregistrement vidéo

# Driver agent-browser
agent-browser install                                # une fois : télécharge Chromium fourni

# Compose + showcase (rendu vidéo)
sudo apt-get install -y ffmpeg                       # traitement vidéo (inclut ffprobe)
cd ${DROID_PLUGIN_ROOT}/remotion && npm install       # dépendances Remotion
# Chrome ou Chromium doit être installé pour le rendu Remotion

Skills similaires