Communitygithub.com

shenmituzi/img-share

Skill DSH: compartilhe capturas de tela do navegador e imagens locais no chat (miniatura + tela cheia, visível no celular)

O que é img-share?

O skill img-share permite que imagens, sejam capturas de tela do navegador ou arquivos locais, sejam inseridas no chat como miniaturas clicáveis que abrem em tela cheia, com suporte a acesso por dispositivos móveis. Ele funciona em múltiplas plataformas (Linux, macOS, WSL e Windows nativo) e é útil quando o usuário deseja compartilhar imagens de forma que outros possam visualizá-las e ampliá-las facilmente, mesmo pelo celular. O skill automatiza todo o fluxo: captura a página com o skill web-access, salva a imagem, escolhe a estratégia de exposição (via host público ou túnel separado), e insere a miniatura + link no chat. Antes de agir, o skill verifica a acessibilidade pública do host para decidir se reutiliza o domínio do host ou abre um túnel explícito, sempre com garantias de que endereços locais não sejam apresentados como públicos.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add shenmituzi/img-share

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Skill img-share

Transforme capturas de tela do navegador ou imagens locais em imagens clicáveis no chat (miniatura + clique para ver original), acessíveis também no celular/outros dispositivos. Funciona em várias plataformas (Linux, macOS, WSL e Windows nativo).

whenToUse (Quando acionar)

  • O usuário pede "abra um site/página e me envie uma captura de tela";
  • O usuário cola uma imagem no chat e quer que ela "possa ser vista e ampliada no celular";
  • O usuário deseja transformar uma imagem do workspace em uma miniatura clicável no chat.

Dependências

DependênciaUsoComo obter
skill web-accessCaptura de tela (navegador via CDP)Instalar: https://github.com/eze-is/web-access
python3/pythonOrquestrador (serve.py)Já vem com o sistema
cloudflaredTúnel público alternativoMac: brew install cloudflared; Windows: winget install Cloudflare.cloudflared; Linux: vide README oficial; ou defina CLOUDFLARED=/caminho
ffmpeg (opcional)Montagem de grade de múltiplas imagensInstalação do sistema (usado por scripts/montage.sh)

Passos de execução

  1. Determinação da acessibilidade do host (obrigatório, primeiro passo) — Decide a base da URL da imagem e se um túnel público separado é necessário. A URL da imagem deve seguir o endereço do host; não crie um túnel separado com origem diferente só para "funcionar":

    SituaçãoConclusão (ação)
    O host já está túnelado/acessível publicamente (o celular do usuário acessa a sessão por esse endereço) e o host expõe um caminho estático de imagens (ex.: /img/*)Coloque a imagem no diretório estático do host, incorpore com o endereço público do host, não abra novo túnel
    O host é publicamente acessível, mas não expõe um caminho estático de imagensNão faça fallback silencioso: primeiro avise o usuário "é necessário configurar um mapeamento estático no host"; só após consentimento explícito use o "túnel alternativo explícito"
    O host é apenas localhost (ex.: DSH_WEB_URL=http://127.0.0.1:*, sem túnel)A imagem só fica acessível localmente — o celular nem consegue acessar a sessão. Avise o usuário para expor o host publicamente primeiro, ou, com consentimento, use o túnel alternativo explícito; não incorpore endereços localhost/127.0.0.1 afirmando que são visíveis pelo celular
    Não foi possível detectar / situação incertaNão adivinhe; pergunte ao usuário: "Qual endereço você usa para acessar esta sessão no celular (domínio público ou localhost)?" Depois siga a tabela

    Como detectar: leia variáveis de ambiente (DSH_WEB_URL, DSH_PUBLIC_BASE, DSH_IMG_BASE, etc.), verifique configurações de rota estática do host; se nada for encontrado, considere "host não forneceu" e siga a tabela ("pergunte/avise"), não faça fallback silencioso abrindo outro túnel.

    Contrato do host (acordo futuro, ainda não implementado pelos hosts atuais): se o host expuser DSH_PUBLIC_BASE / DSH_IMG_BASE ou declarações de caminho estático equivalentes, o agente deve priorizar colocar as imagens sob o domínio do host; quando não fornecido, não assuma que existe.

  2. Captura de tela (se necessário): use o skill web-access, comando /screenshot, para renderizar a página em PNG.

    • Se o CDP/Chromium não funcionar em ambiente restrito (sem internet/problemas de processo), faça fallback para captura em nuvem: use thum.io / mshots / microlink etc., com parâmetros ?wait=N&width=W, e após o retorno verifique se a proporção de pixels não brancos é > limite e o número de clusters de cor > N; só considere válida se não for uma imagem em branco.
  3. Salvar imagem: coloque no workspace (ex.: img/x.png, nome ASCII/sem espaços).

  4. Compartilhar (conforme conclusão do passo 0, uma das duas opções):

    • Caminho do host (quando o passo 0 determina que o host pode ser reutilizado): coloque a imagem no diretório estático exposto pelo host, incorpore https://<domínio do host>/img/x.png; não abra túnel independente.
    • Fallback explícito (quando o passo 0 determina que é necessário fallback e o usuário concordou): compartilhe apenas este arquivo, não o diretório inteiro; inicie servidor de imagens [apenas localhost] + túnel público, valide de ponta a ponta, e emita PUBLIC_BASE:
      bash <skill>/scripts/setup.sh <img>/x.png        # Unix/WSL
      python <skill>/scripts/serve.py --share <img>/x.png   # Windows nativo
      
  5. Inserir na resposta (miniatura = URL da imagem original, clique abre em tela cheia):

    [![Descrição](https://<base>/x.png)](https://<base>/x.png)
    

    A base deve ser o resultado do passo 0 (endereço público do host, ou endereço do túnel explícito com consentimento do usuário); é proibido incorporar localhost/127.0.0.1 e afirmar que é visível pelo celular. Informe ao usuário: a miniatura aparece no chat, clique para abrir a imagem original; o celular também pode acessar pelo mesmo endereço público (verificado que o DSH consegue renderizar imagens markdown públicas).

  6. Após compartilhar → remover túnel (apenas no cenário de fallback explícito, para evitar exposição prolongada):

    bash <skill>/scripts/teardown.sh                  # Para servidor de imagens + túnel + limpeza
    

Tratamento de falhas

  • Acessibilidade do host indeterminada: não adivinhe, não abra túnel silencioso; primeiro pergunte ao usuário qual endereço ele usa para acessar a sessão pelo celular (veja passo 0).
  • Host público mas sem caminho estático de imagens: avise o usuário para configurar mapeamento estático ou, com consentimento, use fallback explícito, explicando que o túnel terá origem diferente do host.
  • Falta de dependências: serve.py reporta "falta cloudflared/python" — instale conforme instruções ou defina CLOUDFLARED; falta web-access para captura → use captura em nuvem (veja acima) ou peça para o usuário enviar a imagem.
  • Porta ocupada: serve.py escolhe automaticamente uma porta livre.
  • Domínio do túnel não obtido (rede lenta/desconectada do Cloudflare): serve.py tenta novamente com polling; se ainda falhar, informa "não foi possível criar túnel" e cai para apenas rede local (fornece endereço local e explica que para celular é necessário que o host/serviço esteja publicamente acessível).
  • Validação de ponta a ponta falhou: serve.py faz curl do arquivo real para validar (200 = sucesso); se falhar, remove o túnel, evitando "parece ativo mas dá 404".
  • Domínio muda: túneis rápidos mudam de domínio ao reiniciar, URLs antigas ficam inválidas; caminho do host não tem esse problema; para cenários de fallback, use túnel nomeado/domínio fixo para maior estabilidade.

Autoverificação do ambiente (Agente deve fazer antes)

Antes de começar, detecte: consegue acessar a internet (curl um endereço público), consegue iniciar processo do navegador (CDP), o host é publicamente acessível (veja passo 0). Se não houver internet nem CDP → use captura em nuvem + avise que são necessárias permissões mais altas; não forneça uma imagem que "parece funcionar mas na verdade está quebrada".

Segurança (ações padrão, não apenas lembretes)

  • Compartilhe apenas o arquivo especificado: serve.py copia o arquivo para um subdiretório com nome aleatório antes de iniciar o servidor, nunca expõe o diretório img/ inteiro (caso contrário, a URL do túnel listaria/baixaria todos os arquivos do diretório); o mesmo vale para o diretório estático do host: coloque apenas o arquivo a ser compartilhado.
  • Servidor de imagens escuta apenas 127.0.0.1 (rede local não consegue acesso direto); a URL do túnel público não tem autenticação — remova o túnel imediatamente após o compartilhamento.
  • Para mais segurança: adicione um token aleatório à URL / use túnel de curta duração; não compartilhe imagens sensíveis.
  • Não coloque todas as imagens em público: apenas a(s) imagem(ns) deste compartilhamento específico devem ficar em um diretório/túnel acessível publicamente.

Prioridade do túnel do host (conforme passo 0)

  • URL da imagem segue o endereço do host: quando o host já está túnelado/publicamente acessível, a imagem deve ser servida sob o mesmo domínio (ex.: caminho estático /img/*) — o celular do usuário carrega a imagem ao abrir a sessão, sem necessidade (e sem permissão) de abrir um túnel temporário com origem diferente.
  • Se o host expõe uma regra estática /img/ via dsh-trust-proxy ou similar, a URL da imagem será algo como https://<domínio DSH>/img/x.png, funcionando entre dispositivos sem túnel extra.
  • O túnel cloudflared independente do serve.py é apenas um fallback portátil (funciona em qualquer máquina): use-o apenas quando o passo 0 determinar que o host não pode ser reutilizado publicamente e o usuário concordar, deixando claras suas limitações (origem diferente do host, túnel rápido muda de domínio ao reiniciar).

Limites

  • Processo precisa ser persistente / removível: serve.py registra o PID para o teardown; em sessões DSH, o serviço precisa sobreviver entre mensagens (use fundo gerenciado + teardown explícito).
  • Nomes de arquivo: use ASCII, sem espaços; os scripts validam a existência do arquivo; caracteres chineses/espaços são tratados por codificação URL, mas é recomendável evitá-los.
  • Workspaces diferentes: cada sessão tem seu próprio workspace; compartilhe conforme o caminho da sessão; serve.py usa diretório temporário do sistema, não depende do workspace.

Habilidades Relacionadas