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ência | Uso | Como obter |
|---|---|---|
| skill web-access | Captura de tela (navegador via CDP) | Instalar: https://github.com/eze-is/web-access |
| python3/python | Orquestrador (serve.py) | Já vem com o sistema |
| cloudflared | Túnel público alternativo | Mac: brew install cloudflared; Windows: winget install Cloudflare.cloudflared; Linux: vide README oficial; ou defina CLOUDFLARED=/caminho |
| ffmpeg (opcional) | Montagem de grade de múltiplas imagens | Instalação do sistema (usado por scripts/montage.sh) |
Passos de execução
-
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ção Conclusã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 imagens Nã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 incerta Nã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_BASEou 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. -
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.
- 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
-
Salvar imagem: coloque no workspace (ex.:
img/x.png, nome ASCII/sem espaços). -
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
- 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
-
Inserir na resposta (miniatura = URL da imagem original, clique abre em tela cheia):
[](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).
-
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 comohttps://<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.