Communitygithub.com

fourth3950/ego-lite

Automatisez des tâches web avec un navigateur léger et haute performance conçu pour les agents IA.

Qu'est-ce que ego-lite ?

ego-browser expose un navigateur Chromium réel via un runtime Node.js accessible en ligne de commande (CLI). Il offre des facades comme `page`, `page.locator(...)`, `browser` et `taskSpaces` qui suivent les conventions de Playwright (noms et signatures), ainsi que des capacités spécifiques comme `taskSpaces`, `site`, `fetch` et `cdp`. Conçu principalement pour les agents IA et les environnements d'automatisation (Claude Code, Cursor, Codex), il permet d'exécuter des scripts JavaScript complexes en une seule invocation Bash, en evitant les appels multiples et en garantissant la fiabilité. Les 'espaces de tâche' isolent les contextes de navigation tout en héritant de l'état de connexion de l'utilisateur, et le système impose des règles strictes de complétion : ne finaliser une tâche qu'après avoir prouvé que chaque postcondition est satisfaite, en utilisant une invocation Bash dédiée pour `taskSpaces.complete()`. Cette approche réduit les erreurs liées aux changements d'état imprévus et améliore la robustesse des automatisations web.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add fourth3950/ego-lite

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

ego-browser

ego-browser expose un navigateur Chromium réel via un runtime Node.js accessible en ligne de commande (CLI). Ses facades préchargées page, page.locator(...), browser et taskSpaces suivent les noms et les signatures de Playwright ; taskSpaces, site, fetch et cdp fournissent des capacités spécifiques à ego-browser.

Pour les problèmes d'installation, de configuration ou de connexion, lisez references/install.md.

Exécutez les travaux du navigateur avec l'outil Bash comme suit : ego-browser nodejs <<'EOF' ... EOF. Placez le code JavaScript directement dans le heredoc ; ne créez pas de fichier .js, n'importez pas Playwright, ne lancez pas un autre navigateur et n'inventez pas de noms d'aide.

Un heredoc est uniquement le conteneur JavaScript ; l'invocation Bash est le cycle d'exécution. Par défaut, utilisez une seule invocation Bash pour l'ensemble de la tâche navigateur. Chaque await est une opération interne, pas une limite d'étape. Avant le lancement, encodez dans le script chaque observation prévisible, action, attente, extraction, vérification et alternative bornée. Utilisez immédiatement les résultats du navigateur en JavaScript et continuez à vous adapter dans le processus jusqu'à ce que la tâche soit terminée ; ne sortez pas simplement pour inspecter une sortie intermédiaire ou planifier l'action suivante. Lancez une autre commande Bash uniquement pour une intervention utilisateur ou externe requise, une inspection visuelle qui ne peut pas avoir lieu dans le processus, ou une défaillance au niveau du processus que le script ne peut pas gérer.

Choisissez la route fiable la moins dépendante de l'état avant d'inspecter les contrôles de la page. Lorsque la tâche spécifie un résultat ou des contraintes mais pas une interaction requise, préférez un état déjà correct ou une URL ou route de site stable connue qui les encode directement ; vérifiez l'état final du résultat au lieu de rejouer des filtres, des tris ou une navigation équivalents via l'interface utilisateur. Utilisez les contrôles de la page lorsque l'utilisateur a demandé cette interaction, que l'interaction elle-même est testée ou qu'aucun équivalent fiable n'est connu. N'inventez jamais une route fragile.

Traitez une postcondition déjà satisfaite comme un travail terminé. Avant de manipuler un contrôle dont la valeur requise peut déjà être visible, effectuez uniquement la plus petite lecture nécessaire pour décider de cet état. Si elle correspond, n'ouvrez pas son éditeur, ne rejouez pas l'interaction et ne la lisez pas à nouveau ; passez directement aux résultats non satisfaits restants. Les mots comme « définir », « sélectionner » ou « s'assurer » décrivent l'état final requis, sauf si l'utilisateur exige explicitement la transition ou que l'interaction elle-même est testée.

Séparez le travail du navigateur de la fin du terminal. useOrCreate commence ou reprend un objectif utilisateur ; conservez son task.id retourné et réutilisez le même id ou le même nom exact jusqu'à ce que cet objectif soit terminal. Gardez chaque observation prévisible, action, attente, extraction et vérification compacte, mais n'appelez pas taskSpaces.complete(...) dans une invocation Bash qui détermine encore si l'objectif est satisfait. Terminez d'abord le travail du navigateur et affichez la preuve que chaque résultat demandé et toute portée ou limite de couverture requise ont été prouvés. Ce n'est qu'après avoir examiné cette sortie préalable qu'une invocation Bash finale dédiée peut compléter l'espace de tâche original ; elle n'effectue aucun travail de page ou browser. Cet unique engagement de cycle de vie est l'exception à la règle par défaut d'une invocation, pas une étape ou un cycle de navigateur. Des résultats partiels non vides ou plausibles, une page bloquée, des tentatives épuisées ou une tentative de repli ne constituent pas une preuve de fin. keep: true préserve un résultat terminal pour l'utilisateur ; il ne maintient pas une tâche non terminée en vie.

Gelez la fenêtre temporelle pour le travail en cours ou relatif à une date. Établissez « aujourd'hui/actuel/le plus récent » une fois à partir de l'environnement utilisateur/tâche ou de l'état de page actuel explicitement vérifié avant de collecter des enregistrements. Traitez les horodatages de contenu comme des données, pas comme l'horloge. Les enregistrements plus anciens révélés par le défilement, la virtualisation, le rechargement, le cache ou un lot de résultats modifié ne doivent pas remplacer cette ancre. Continuez à évaluer les enregistrements par rapport à la fenêtre d'origine ; ne rebasez pas silencieusement la tâche sur la date de contenu la plus récente observée.

Démarrage rapide

Chaque exemple de cette compétence est délibérément composite. Adaptez son URL, ses sélecteurs et ses données à la tâche utilisateur.

ego-browser nodejs <<'EOF'
const task = await taskSpaces.useOrCreate('inspect example page')
await browser.openOrReuseTab('https://example.com', { wait: true, timeout: 20000 })

const heading = await page.getByRole('heading').first().innerText()
const info = await page.info()
if (!heading || !('url' in info)) throw new Error('Example page was not ready')

const result = { taskSpaceId: task.id, heading, url: info.url }
console.log(JSON.stringify(result, null, 2))
EOF

Gardez tout le travail prévisible à l'intérieur du script jusqu'à ce que la tâche soit terminée. Émettez les résultats finaux avec console.log(...).

Modèles composites

Extraire, choisir, naviguer, vérifier

Sur une page de liste ou de recherche, extrayez des candidats structurés avant de choisir. Gardez l'extraction, le choix, l'action, l'attente, la vérification et le nettoyage dans une seule invocation Bash.

ego-browser nodejs <<'EOF'
const task = await taskSpaces.useOrCreate('compare search results')
await browser.openOrReuseTab('https://example.com/search?q=browser+automation', {
  wait: true,
  timeout: 20000,
})

const cards = page.locator('article')
const items = await cards.evaluateAll((nodes) =>
  nodes.map((node) => ({
    title: node.querySelector('h2')?.textContent?.trim(),
    href: node.querySelector('a')?.href,
  })),
)
const chosenIndex = items.findIndex((item) => item.title && item.href)
if (chosenIndex < 0) throw new Error('No usable result: ' + JSON.stringify(items))

const before = await page.url()
const navigation = page.waitForURL((url) => url.href !== before, { timeout: 15000 })
await cards.nth(chosenIndex).getByRole('link').first().click()
if (!(await navigation)) throw new Error('Chosen result did not navigate')

const info = await page.info()
if (!('url' in info) || info.url === before) throw new Error('Navigation was not verified')
const result = { chosen: items[chosenIndex], opened: info.url }
console.log(JSON.stringify(result, null, 2))
EOF

Remplir, déclencher, attendre, relire

Enregistrez les attentes de requête/réponse avant l'action qui les déclenche, puis vérifiez l'état résultant de la page plutôt que de considérer le clic comme un succès.

ego-browser nodejs <<'EOF'
const task = await taskSpaces.useOrCreate('search orders')
await browser.openOrReuseTab('https://example.com/orders', { wait: true, timeout: 20000 })

const responsePromise = page.waitForResponse(
  (response) => response.url().includes('/api/orders') && response.ok(),
  { timeout: 15000 },
)
await page.getByLabel('Search orders').fill('pending')
await page.getByRole('button', { name: /search/i }).click()
const response = await responsePromise

const rows = await page.locator('table tbody tr').allInnerTexts()
if (!rows.length) throw new Error('Search completed but returned no visible rows')
const result = { status: response.status(), rows }
console.log(JSON.stringify(result, null, 2))
EOF

Rafraîchir les handles d'onglets, basculer, inspecter

Traitez targetId comme un handle de courte durée. Découvrez, validez et utilisez-le dans la même invocation Bash.

ego-browser nodejs <<'EOF'
const task = await taskSpaces.useOrCreate('review generated report')
const tabs = await browser.listTabs({ includeChrome: false })
const reportTab = tabs.find((tab) => tab.url.includes('/reports/'))
if (!reportTab?.targetId) throw new Error('Report tab not found: ' + JSON.stringify(tabs))

await browser.switchTab(reportTab.targetId)
const info = await page.info()
const heading = await page.getByRole('heading').first().innerText()
if (!('url' in info) || !info.url.includes('/reports/')) throw new Error('Wrong tab selected')
const result = { taskSpaceId: task.id, heading, url: info.url }
console.log(JSON.stringify(result, null, 2))
EOF

Carte d'exécution

  • page : navigation et état (goto, reload, url, title, info), localisateurs sémantiques, attentes, snapshot, screenshot, screencast, evaluate, keyboard, mouse, téléchargements et vidange d'événements.
  • page.locator(selector) : chaînage et filtrage ; first / nth / last ; méthodes de clic, survol, dragTo, scrollIntoViewIfNeeded, formulaire, clavier, téléchargement, lecture d'état, collection, évaluation d'élément, capture d'écran et attente.
  • browser : listTabs, currentTab, switchTab, openOrReuseTab, closeTab, ensureRealTab, iframeTarget.
  • taskSpaces : list, switch, new, useOrCreate, claim, complete, handOff, takeOver, waitForAgentControl.
  • fetch.server effectue des requêtes côté Node ; fetch.browser effectue des requêtes dans l'origine de la page actuelle. Utilisez cdp uniquement comme issue de secours.
  • console.log est le canal de sortie. Utilisez console.log(help('page')), console.log(help('locator')) ou un autre appel help(name) lorsqu'une signature exacte n'est pas claire.

Règles d'exécution

  • page.url() est asynchrone dans ego-browser ; utilisez toujours await page.url(). Un prédicat page.waitForURL(...) reçoit un objet URL, inspectez donc url.href, url.pathname ou url.searchParams. Il attend load par défaut ; utilisez waitUntil: 'commit' uniquement lorsque vous avancez intentionnellement avant le chargement.
  • page.waitForURL, page.waitForLoadState, page.waitForSelector, l'attente du localisateur et page.waitForFunction retournent une valeur fausse en cas de délai d'attente dépassé. Vérifiez le résultat ou vérifiez immédiatement l'état requis avant de continuer.
  • Enregistrez les attentes de requête, de réponse ou de navigation avant l'action qui les déclenche. Préférez les attentes basées sur l'état ; n'utilisez page.waitForTimeout(...) que pour un bref ajustement visuel et maintenez-le à 2000 ms ou moins.
  • Préférez les localisateurs sémantiques stables. Lorsque la structure de la page est inconnue, collectez les contrôles ou candidats pertinents une fois avec evaluateAll, allInnerTexts ou une autre lecture bornée, dérivez les actions suivantes en JavaScript et continuez dans le même heredoc au lieu d'énumérer des suppositions de sélecteur entre les commandes.
  • Les actions sur un seul élément et les lectures requises—y compris les localisateurs CSS bruts et xpath= bruts—sont strictes et attendent automatiquement. Pour zéro correspondance, confirmez le chargement, l'onglet actif et l'état de la modale/superposition avant de corriger le localisateur. Pour plusieurs correspondances, inspectez count() / allInnerTexts(), affinez sémantiquement ou avec filter(...), et n'utilisez first() / nth() qu'après avoir confirmé que les doublons sont légitimes. Laissez une action réussie faire avancer le script ; lisez l'état lorsqu'il détermine une branche et une fois pour les postconditions finales requises de la tâche, pas après chaque action. Un état requis déjà satisfait n'a pas besoin d'être rejoué.
  • En cas d'échec, utilisez une observation ciblée pour changer de stratégie de manière significative. Ne répétez pas des localisateurs ou des commandes quasi identiques ; passez à un chemin sémantique, DOM ou visuel stable basé sur les preuves.
  • Préservez les transitions visibles explicitement demandées par l'utilisateur et les limites d'arrêt. Lorsqu'un clic requis peut naviguer dans l'onglet actuel ou en ouvrir un autre, cliquez une fois et résolvez le résultat à partir de await page.url() plus un browser.listTabs() rafraîchi dans le même script ; ne remplacez pas le clic par une navigation directe simplement parce que sa destination est connue. N'avalez pas les échecs des actions requises.

Espaces de tâche

Un espace de tâche est un contexte de navigation isolé avec ses propres onglets qui hérite de l'état de connexion de l'utilisateur. Sélectionnez-le une fois près du début du premier script Bash avec taskSpaces.useOrCreate(nameOrId). Si une dépendance externe rend une commande ultérieure inévitable, sélectionnez le même task.id numérique retourné ou le même nom d'objectif court exact avant de continuer ; créez un nouvel espace uniquement pour un objectif utilisateur distinct. Préservez les faits déjà vérifiés entre les commandes au lieu de redémarrer la configuration.

useOrCreate réutilise ou crée des espaces appartenant à l'agent. Si l'espace correspondant appartient à l'utilisateur, il sélectionne l'espace sans le réclamer, donc le travail du navigateur rencontre l'arrêt brutal du contrôle utilisateur. Après confirmation explicite de l'utilisateur pour y travailler, utilisez taskSpaces.list() → taskSpaces.claim(id) → browser.listTabs() → browser.switchTab(targetId).

Chaque espace a ownership: 'agent' | 'agentDelegatedToUser' | 'user':

Opération sur un espace appartenant à l'utilisateurComportement
taskSpaces.switchLève une exception ; ne bascule que les espaces appartenant à l'agent
taskSpaces.claimTransfère la propriété à l'agent et sélectionne l'espace
taskSpaces.handOff / complete(..., { keep: true })Ignore avec { done: false, skipped: 'user-owned' }
taskSpaces.complete(..., { keep: false })Réclame, puis ferme l'espace
taskSpaces.takeOver / waitForAgentControlN'effectue aucune vérification de propriété

Vérifiez le résultat done de handOff et complete avant de revendiquer le succès.

Traitez la complétion comme un engagement terminal séparé de l'exécution du navigateur. Terminez l'invocation Bash de travail sans complétion après avoir capturé et imprimé l'URL finale, les valeurs et autres preuves. Examinez cette sortie : chaque postcondition demandée et toute portée ou limite de couverture requise doit être prouvée, pas seulement probable. Si elles sont prouvées, exécutez une invocation Bash finale dédiée qui appelle taskSpaces.complete(nameOrId, { keep }) au plus une fois pour l'id original ou le nom exact, vérifie done et n'effectue aucun travail page ou browser. Si quoi que ce soit n'est pas satisfait ou n'est pas prouvé, continuez dans le même espace de tâche original à la place ; une correction, une nouvelle tentative ou une phase ultérieure n'est pas un nouvel objectif. keep est obligatoire. Par défaut, false ; utilisez true uniquement lorsque l'utilisateur a demandé de conserver la page terminée, doit agir manuellement dessus, ou que le résultat ne peut pas être livré sous forme d'URL, fichier, artefact ou résumé. Fermez les onglets provisoires au fur et à mesure et ne conservez que les onglets dont l'utilisateur a besoin.

Ne codez jamais en dur, ne recopiez pas manuellement et ne renommez pas un targetId en id. Obtenez-le et utilisez-le dans l'invocation Bash actuelle. Si une autre commande est véritablement nécessaire, rafraîchissez browser.listTabs() et validez les résultats de find(...) avant de basculer ou de fermer. browser.iframeTarget(...) retourne une chaîne target-id ou null, pas un objet.

Transfert de contrôle

Une erreur « l'utilisateur contrôle », « inactif » ou « non assigné » est un arrêt brutal pour l'ensemble de la tâche. Ne réessayez pas, ne contournez pas et n'appelez pas taskSpaces.takeOver automatiquement. Demandez à l'utilisateur et attendez.

Pour la connexion, un captcha ou une autre étape manuelle, terminez...

Skills associés