Communitygithub.com

shenmituzi/img-share

Partage de captures d'écran de navigateur ou d'images locales dans le chat (vignette + plein écran, visible sur téléphone).

Qu'est-ce que img-share ?

Cette compétence d'agent IA permet de partager des captures d'écran de navigateur ou des images locales sous forme de vignettes cliquables dans le chat, avec un affichage plein écran accessible également depuis un téléphone ou un autre appareil. Elle fonctionne sur Linux, macOS, WSL et Windows natif. L'agent détermine automatiquement si l'hôte du chat est déjà accessible publiquement (via un tunnel existant) ou s'il doit ouvrir un tunnel éphémère avec Cloudflared pour exposer l'image. Dans ce dernier cas, il sert uniquement le fichier partagé, jamais un répertoire entier, et le détruit après usage. La compétence utilise web-access pour les captures via CDP, avec repli vers des services cloud (thum.io, mshots, microlink) si le navigateur local est indisponible. Elle inclut une validation de bout en bout et désactive le tunnel dès que l'image n'est plus nécessaire, garantissant sécurité et fiabilité.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add shenmituzi/img-share

Demander à votre IA préférée

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

Documentation

Compétence img-share

Transformez une capture d'écran de navigateur ou une image locale en image cliquable et agrandissable dans le chat (vignette + affichage original), accessible depuis un téléphone ou un autre appareil. Fonctionne sur Linux, macOS, WSL et Windows natif.

Quand déclencher (whenToUse)

  • L'utilisateur demande de "prendre une capture d'écran d'un site/page" ;
  • L'utilisateur colle une image dans le chat et souhaite qu'elle soit "visible sur téléphone, cliquable pour zoomer sur les détails" ;
  • L'utilisateur veut qu'une image de l'espace de travail devienne une image intégrée cliquable dans le chat.

Dépendances

DépendanceUtilisationInstallation
web-access skillCapture d'écran (navigateur piloté par CDP)Doit être installée : https://github.com/eze-is/web-access
python3/pythonOrdonnanceur (serve.py)Inclus avec le système
cloudflaredTunnel public de replimacOS : brew install cloudflared ; Windows : winget install Cloudflare.cloudflared ; Linux : voir le README officiel ; ou définissez CLOUDFLARED=/chemin
ffmpeg (optionnel)Assemblage d'images en grilleInstallation système (utilisé par scripts/montage.sh)

Étapes d'exécution

  1. Déterminer l'accessibilité de l'hôte (obligatoire, en premier) — décide de l'URL de base de l'image et s'il faut ouvrir un tunnel public séparé. L'URL de l'image doit suivre celle de l'hôte ; ne créez pas de tunnel sur une source différente de celle de l'hôte simplement pour "que ça fonctionne" :

    RésultatAction
    L'hôte est déjà tunnelé / accessible publiquement (le téléphone de l'utilisateur accède à la session via cette adresse), et l'hôte expose un chemin statique pour les images (ex. /img/*)Placer l'image dans le répertoire statique de l'hôte, l'URL intégrée utilise l'adresse publique de l'hôte, pas de nouveau tunnel
    L'hôte est public mais n'expose pas de chemin statique pour les imagesNe pas silencieusement basculer : informer d'abord l'utilisateur "il faut configurer un mappage statique pour les images" ; n'utiliser le « tunnel de repli explicite » qu'après accord de l'utilisateur
    L'hôte est uniquement en localhost (ex. DSH_WEB_URL=http://127.0.0.1:* sans tunnel public)L'image n'est disponible qu'en local/réseau local — le téléphone ne peut pas accéder à la session. Demander d'abord à l'utilisateur de rendre l'hôte public, ou, avec son accord, utiliser le repli explicite ; ne jamais intégrer une adresse localhost/127.0.0.1 en prétendant qu'elle est visible sur téléphone
    Impossible de détecter / incertainNe pas deviner, demander à l'utilisateur : "Par quelle adresse (nom de domaine public ou localhost) ton téléphone accède-t-il à cette session ?" puis suivre le tableau ci-dessus

    Méthode de détection : lire les variables d'environnement (DSH_WEB_URL, DSH_PUBLIC_BASE, DSH_IMG_BASE etc.) ; consulter la configuration de routage statique de l'hôte ; si rien n'est trouvé, considérer que « l'hôte ne fournit rien » et suivre le tableau (« demander à l'utilisateur / informer »), ne pas basculer silencieusement vers un autre tunnel.

    Contrat hôte (prévisionnel, non encore fourni par les hôtes DSH actuels) : si l'hôte expose DSH_PUBLIC_BASE / DSH_IMG_BASE ou une déclaration équivalente de chemin statique, l'agent doit obligatoirement placer l'image sous le domaine de l'hôte ; en leur absence, ne pas supposer leur existence.

  2. Capturer (si nécessaire) : utiliser le skill web-access, /screenshot pour rendre la page en PNG.

    • Si CDP/Chromium ne peut pas s'exécuter dans l'environnement restreint (pas d'accès réseau, plantage), replier vers une capture cloud : utiliser thum.io / mshots / microlink etc. avec ?wait=N&width=W, vérifier après retour que le ratio de pixels non blancs > seuil, nombre de clusters de couleur > N ; n'utiliser que si l'image n'est pas vierge.
  3. Stocker l'image : placer dans l'espace de travail (ex. img/x.png, nom de fichier en ASCII / sans espaces).

  4. Partager (selon le résultat de l'étape 0, deux choix) :

    • Chemin hôte (si l'étape 0 détermine qu'on peut réutiliser l'hôte) : copier l'image dans le répertoire statique exposé par l'hôte, intégrer https://<domaine_hôte>/img/x.png ; ne pas ouvrir de tunnel indépendant.
    • Repli explicite (si l'étape 0 détermine qu'un repli est nécessaire et que l'utilisateur a donné son accord) : partager uniquement ce fichier, pas un répertoire entier ; lancer un serveur d'image [boucle locale uniquement] + tunnel public, vérification de bout en bout, sortir PUBLIC_BASE :
      bash <skill>/scripts/setup.sh <img>/x.png        # Unix/WSL
      python <skill>/scripts/serve.py --share <img>/x.png   # Windows natif
      
  5. Intégrer dans la réponse (vignette = URL de l'image originale, cliquer pour ouvrir l'original en plein écran) :

    [![description](https://<base>/x.png)](https://<base>/x.png)
    

    La base doit être le résultat de l'étape 0 (adresse publique de l'hôte, ou adresse du tunnel explicite avec accord de l'utilisateur) ; interdiction d'incorporer localhost/127.0.0.1 et de prétendre que c'est visible sur téléphone. Informer l'utilisateur : une vignette apparaît dans le chat, cliquer ouvre l'original ; le téléphone peut aussi accéder via la même adresse publique (vérifié que DSH sait rendre les images publiques en markdown).

  6. Partage terminé → démonter le tunnel (scénario de repli explicite, éviter une exposition prolongée) :

    bash <skill>/scripts/teardown.sh                  # arrêter le serveur + tunnel + nettoyage
    

Gestion des échecs

  • Impossible de déterminer l'accessibilité de l'hôte : ne pas deviner, ne pas ouvrir silencieusement un tunnel ; demander d'abord à l'utilisateur l'adresse d'accès de son téléphone (voir étape 0).
  • Hôte public mais sans chemin statique pour les images : informer l'utilisateur de configurer un mappage statique, ou, avec son accord, utiliser le repli explicite en précisant que ce tunnel est sur une source différente de l'hôte.
  • Dépendances manquantes : serve.py signale « cloudflared/python manquant » → installer ou définir CLOUDFLARED ; capture : si web-access manque, passer en capture cloud (voir ci-dessus) ou demander à l'utilisateur de fournir l'image.
  • Port occupé : serve.py choisit automatiquement un port libre.
  • Impossible d'obtenir le nom de domaine du tunnel (lent réseau / coupure Cloudflare) : serve.py réessaie en polling ; en cas d'échec, informer « impossible de créer le tunnel réseau » et revenir à local/réseau local uniquement (fournir l'adresse locale, préciser que pour le téléphone il faut d'abord rendre l'hôte/service accessible publiquement).
  • Échec de la vérification de bout en bout : serve.py fait un curl sur le nom de fichier réel (200 requis) ; en cas d'échec, tout démonter pour éviter "ça a l'air actif mais c'est en fait 404".
  • Changement de domaine du tunnel : les tunnels rapides changent de nom de domaine au redémarrage, rendant les URLs intégrées obsolètes ; ce problème n'existe pas avec le chemin hôte ; pour une stabilité à long terme dans un scénario de repli, utiliser un tunnel nommé / domaine fixe.

Auto-vérification de l'environnement (l'agent doit le faire au préalable)

Avant de commencer, détecter : peut-on accéder au réseau public (faire un curl vers une adresse publique) ? Peut-on lancer un processus navigateur (CDP) ? L'hôte est-il accessible publiquement (voir étape 0) ? Si accès réseau ET CDP sont impossibles → passer en capture cloud + indiquer que des privilèges plus élevés sont nécessaires, ne pas donner à l'utilisateur une image "qui a l'air fonctionnelle mais qui est en fait cassée".

Sécurité (actions par défaut, pas un simple rappel)

  • Partager uniquement le fichier désigné : serve.py copie le fichier à partager dans un sous-répertoire au nom aléatoire puis démarre le service ; jamais tout le répertoire img/ (sinon l'URL du tunnel permettrait de lister/télécharger tous les fichiers du répertoire) ; pareil pour le répertoire statique de l'hôte : ne placer que le fichier à partager.
  • Le serveur d'image écoute uniquement sur 127.0.0.1 (pas accessible directement depuis le réseau local) ; l'URL du tunnel public n'a pas d'authentification — démonter immédiatement après le partage.
  • Pour plus de sécurité : ajouter un jeton aléatoire à l'URL / utiliser un tunnel à durée limitée ; ne pas partager d'images sensibles.
  • Ne pas exposer toutes les images publiquement : seules les images « à partager cette fois-ci » doivent se trouver dans le répertoire / tunnel accessible publiquement.

Priorité au tunnel hôte (voir étape 0)

  • L'URL de l'image suit celle de l'hôte : si l'hôte est déjà tunnelé / public, l'image doit être placée sous le même domaine (ex. chemin statique /img/*) — le téléphone de l'utilisateur la charge immédiatement dans la session, sans besoin ni justification d'ouvrir un tunnel temporaire sur une source différente.
  • Si l'hôte expose des règles statiques /img/ via dsh-trust-proxy ou similaire, l'URL de l'image est du type https://<domaine_DSH>/img/x.png, multi-appareils, sans tunnel supplémentaire.
  • Le tunnel cloudflared indépendant de serve.py n'est qu'un repli portable (utilisable sur n'importe quelle machine) : utilisé uniquement lorsque l'étape 0 détermine que « l'hôte n'est pas réutilisable publiquement » ET avec l'accord informé de l'utilisateur, en précisant ses limitations (source différente de l'hôte, changement de nom de domaine au redémarrage du tunnel rapide).

Limites

  • Le processus doit être persistant / démontable : serve.py enregistre le PID pour le teardown ; dans une session DSH, le service doit survivre entre sessions (utiliser un arrière-plan géré + teardown explicite).
  • Noms de fichiers : ASCII, sans espaces ; les scripts vérifient l'existence du fichier ; les noms avec caractères chinois/espaces sont encodés en URL, mais il est conseillé de les éviter.
  • Espace de travail différent : chaque session a son propre espace de travail ; serve.py utilise le répertoire temporaire système, ne dépend pas de l'espace de travail.

Skills associés