Fallow
Skill pedroberaldo87/pedro-plugins/plugins/fallow/skills/fallow
Roda o Fallow (analisador estático JS/TS — código morto, duplicação, complexidade) num projeto, classifica os achados por tipo e nível de confiança, e entrega um relatório interativo (HTML com checkboxes) onde o usuário escolhe o que limpar. Depois limpa só o marcado com rede de segurança (preview → aplica → build/test). Trigger em "/fallow", "roda o fallow", "varre código morto", "analisa o projeto com fallow", "o que dá pra limpar aqui".From its SKILL.md
npx -y skills add pedroberaldo87/pedro-plugins --skill fallowAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
14.3 KB, ~4.2k tokens by cl100k_base, as published. Nobody here has run it
/fallow — varredura e limpeza guiada
Roda o Fallow, transforma a saída crua num relatório que o usuário escaneia e seleciona, e limpa só o que ele marcar — nunca às cegas.
Input
/fallow [projeto]
[projeto]= path absoluto, nome de pasta, ou vazio (usa o cwd).- Se o usuário disser só o apelido do projeto ("FINANCE", "TOOLS"), resolver para o path real (ex:
~/PROJETOS/app-finance).
O que você precisa saber sobre o Fallow (não pule — evita cagada)
- É análise estática sintática (parser Oxc, sem type-check). Constrói um grafo de imports/exports e marca como "morto" o que não é alcançável a partir dos entry points.
dead-codedepende 100% dos entry points. Entry não detectado → tudo abaixo vira falso "morto".dupesehealthNÃO dependem de entry → sempre confiáveis.fallow fixé conservador: só remove a keywordexport, deps dopackage.jsone membros de enum. NUNCA deleta arquivo. Deleção de arquivo órfão é a skill que faz, sempre com build/test depois.- Falsos-positivos sistemáticos conhecidos (já mapeados — devem estar silenciados no
.fallowrc.json, mas confira):- Client Vite (
apps/*/client): oindex.htmlnão vira entry → resolver comentry: ["apps/*/client/src/main.{jsx,tsx,js,ts}"]. - shadcn/ui (
components/ui/*): re-exportam a API Radix completa de propósito →ignoreExports: [{file, exports:["*"]}]. - Service workers / assets (
public/sw.js,static/*.css): registrados em runtime, nunca importados. Não silenciar viaignorePatterns public/**— isso cria órfãos colaterais; deixar aparecer e marcar como asset no relatório. - DI/decorators,
import()dinâmico,next/dynamic: podem mascarar uso → item vira "verificar", não "deletar".
- Client Vite (
Fluxo
1. Pré-check da config (BLOQUEANTE para dead-code)
- Checar se existe
<projeto>/.fallowrc.json(ou.fallowrc.jsonc/fallow.toml). Rodarnpx -y fallow config -r <projeto>e ver se carrega. - Se NÃO houver config: avisar o usuário que o relatório de código morto virá com falsos-positivos (entry points / bibliotecas), e oferecer calibrar primeiro (ver "Calibrar config" abaixo). Duplicação e complexidade seguem confiáveis mesmo sem config.
- Se houver: seguir.
2. Rodar e parsear JSON REAL
Rodar e capturar JSON (nunca parsear texto, nunca assumir formato):
npx -y fallow dead-code -r <projeto> --format json
npx -y fallow dupes -r <projeto> --format json
npx -y fallow health -r <projeto> --format json
Chaves reais dos JSON (confirmadas rodando — não chutar):
dead-code:unused_files,unused_exports,unused_types,unused_dependencies,unused_dev_dependencies,unused_enum_members,unused_class_members,circular_dependencies,re_export_cycles,unlisted_dependencies,boundary_violations. Cada item tempath/filee, em exports,exports/name.health: a lista étargets(não "refactoring_targets"), item ={path, priority, efficiency, recommendation, category, effort, confidence, factors, evidence, actions}. Também:health_score,vital_signs,hotspots,large_functions,file_scores.dupes:clone_groups(item ={instances, token_count, line_count, fingerprint, suggested_name, actions}) eclone_families(item ={files, groups, total_duplicated_lines, total_duplicated_tokens, suggestions, actions}) +stats.
Os dois motores (lib/) — não reimplementar à mão
A skill tem motores prontos e testados. O caminho normal é rodá-los, não recriar a lógica:
lib/report.py <projeto> [session]— roda os 3 fallow + a auditoria, classifica, e gera o HTML interativo dentro do projeto (<projeto>/.claude/visual/, fallback~/Desktop/claude-visual/fora de projeto — mesma cascata da skillvisual, replicada emresolve_visual_dir()). Imprime o path + um resumo JSON dos baldes.lib/audit.py <projeto> [--json]— auditoria isolada (oreport.pyjá a chama internamente). Útil pra rodar/inspecionar só a auditoria.
Antes de abrir o HTML: rodar plugins/visual/server/start.sh (live-sync). Depois open o arquivo.
3. Auditoria — o goal (confirmar cada afirmação do Fallow)
O Fallow é estático: afirma "órfão/morto" mas não enxerga cron/systemd, rota HTTP, import() dinâmico, uso via package.json, nem import dentro de .svelte/.vue/.astro (o parser dele é JS/TS puro). audit.py re-verifica com evidência real tanto cada unused_file quanto cada unused_export/unused_type (auditoria de símbolo: grep ancorado por todo o projeto, incluindo componentes), e classifica:
-
falso_positivo(🛑 não deletar) — achou uso real. Razão + prova (ex:deploy/README.mdrodando o script via systemd; ou um export importado dentro de um.svelte, que o Fallow não vê). Inclui propagação de vivacidade: um FP-raiz (ex: script de cron) é entry vivo → o que ele importa e o Fallow marcou como morto também é vivo.Enquadramento (comunicar ao usuário em humano): um falso-positivo não é bug do código nem código morto — é uma limitação intrínseca da análise estática. O Fallow lê só o grafo de imports (quem chama quem no código) e não enxerga gatilhos de fora: agendador do SO (cron/systemd), requisição HTTP (rota), import dinâmico, ou import num componente Svelte/Vue. O código está correto; não há o que corrigir nele. Por padrão a skill mantém os FPs visíveis no relatório (não suprime via
entry) — é escolha consciente, dá transparência. Suprimir é opção cosmética do usuário, não correção. -
usado_interno(↩ só interno) — export/tipo usado só dentro do próprio arquivo: oexporté redundante, mas o símbolo NÃO é morto (apagá-lo quebra o arquivo). Tirar só a keywordexporté opcional/cosmético. É o caso típico de uma "ponte" usada internamente (ex.: umsend()chamado pelos wrappers do mesmo módulo). -
dead_confirmado(✓ seguro) — 0 referências: nem import estático/dinâmico, nem uso de símbolo em arquivo nenhum (incl..svelte), nem cron/rota, nem uso interno. -
manual_cli(⚠ arquivar) — script sem refs e não agendado, mas é ferramenta CLI manual.
Goal de convergência (não-negociável): a auditoria roda repetidamente; cada rodada que descobre um buraco novo (FP que rodadas anteriores não pegaram) reinicia a contagem. Converge só quando 3 rodadas consecutivas dão fingerprint idêntico. Convergência prova determinismo — não prova correção: matches frouxos (substring de path, basename solto, símbolo genérico como POST/GET/send casando a palavra num comentário) geram falso-positivo de auditoria. Por isso os matches são ancorados (path com boundary, nome+extensão, \bsímbolo\b com descarte de comentário/prosa, infra de execução ≠ menção em doc de planejamento). Ao evoluir o audit.py, sempre re-validar contra uma auditoria manual de referência.
3b. Classificar os demais baldes
- 🧟 Código morto — arquivos E exports/tipos usam o veredito da auditoria (
falso_positivo/usado_interno/dead_confirmado), com a prova inline no item. Heurística de path só entra como fallback se a auditoria estiver indisponível — e nesse caso o item vai como⚠ verificar, nunca como morto afirmado. - 📦 Dependências não usadas —
unused_dependencies. Quick-win seguro (auto-fixable). Excluir as típicas-FP se aparecerem (@types/*,eslint,typescript,tsx, test runners,autoprefixer/@tailwindcss/postcss). - 🔁 Ciclos —
circular_dependencies+re_export_cycles. Não deletável; é refactor. - 👯 Duplicação —
clone_familiesordenadas portotal_duplicated_lines(maiores primeiro). Refactor manual (extrair módulo viasuggestions), nunca auto-fix. - 🧠 Complexidade —
targetsordenados porpriority(eefficiency= ROI); destacareffort: "low"como quick wins. Usarrecommendation(texto humano) eevidence(dados acionáveis).
4. Apresentar (relatório interativo) — OBRIGATÓRIO, SEMPRE
Esta etapa NÃO é opcional e NÃO está sujeita ao seu julgamento. Toda execução do /fallow — independente do volume (1 item ou 100), do tipo de projeto, ou de quão "óbvio" o resultado pareça — TEM que gerar o relatório HTML e abri-lo com open antes de qualquer limpeza ou conclusão. Apresentar os achados só no chat (tabela, lista, texto) NÃO substitui o relatório e é considerado falha de execução da skill. Se você está pensando "é pouca coisa, dá pra mostrar direto no chat" — pare: isso é exatamente o desvio proibido. Gere o HTML.
Gerar um HTML dark-theme self-contained em <projeto>/.claude/visual/YYYY-MM-DD-fallow-<projeto>.html (fallback ~/Desktop/claude-visual/ fora de projeto — o report.py resolve via resolve_visual_dir(), espelho da cascata do resolve-dir.sh da skill visual; reaproveitar o CSS e o daemon de live-sync — plugins/visual/server/start.sh + window.VISUAL_SESSION). Estrutura:
- Topo: saúde (health score) + contadores por balde + card da auditoria (goal): "convergiu em N rodadas idênticas" e os números (🛑 falso-positivo do Fallow · ✓ mortos reais · ↩ só uso interno · ⚠ scripts manuais).
- Seções colapsáveis por balde. Cada item = checkbox + path + tag de confiança (
✓ confirmadoverde /🛑 não deletarvermelho /⚠ verificaramarelo) + mini-resumo humano sempre visível. Ao expandir: bloco ⛔ Problema (humano + técnico) e bloco ✅ Solução (humano + técnico, com a ação e a prova da auditoria). - Botões: "Marcar só os seguros" (só
confirmado+ deps — nuncafp/verificar), "Limpar", "Copiar seleção" (+ live sync). - Abrir com
open. O usuário marca o que quer eliminar e diz "ok"/"pronto" (live sync) ou cola a seleção.
O formato pode variar com o volume — listas grandes (dezenas de itens) usam o relatório de lista com checkboxes; volumes pequenos podem reaproveitar a skill visual. Mas gerar e abrir um HTML é obrigatório nos dois casos — "pouco volume" nunca é motivo para pular o relatório e mostrar só no chat.
5. Limpar só o marcado (ordem de risco crescente)
Antes de qualquer escrita: garantir git limpo ou git stash/commit do estado atual (a skill avisa e faz). Trabalhar num branch se o projeto estiver no default.
- Deps não usadas →
npx fallow fix -r <projeto> --dry-run(preview) → mostrar o diff →npx fallow fix -r <projeto> --yes(escopo deps). - Exports 100% dead → para cada um,
npx fallow dead-code -r <projeto> --trace <file>:<export>confirma 0 referências →fallow fix. - Arquivos órfãos → confirmar via
--trace/grep + olhargit logdo arquivo; deletar; rodar build/test do app afetado. - Duplicação / complexidade → refactor manual dos maiores; nunca auto.
Após cada lote: rodar build + test do projeto (ou do app no monorepo). Comandos:
- FINANCE (pnpm):
pnpm build/pnpm test/pnpm lint. - TOOLS (monorepo, por app):
cd apps/<app> && npm run lint && npx tsc --noEmit(ver.claude/docs/patterns.md). - Se o build/test quebrar: reverter o lote (
git checkout/git stash pop) e reportar o que quebrou. Parar.
6. Relatório final
Resumir em linguagem humana (1-2 linhas por balde): o que foi removido, o que passou no build/test, o que ficou pendente (itens verificar não tocados), e quanto caiu cada métrica. Oferecer commit.
Calibrar config (quando o projeto não tem .fallowrc.json)
Criar <projeto>/.fallowrc.json (schema real — campos válidos: entry, ignorePatterns, workspaces.patterns, ignoreExports, ignoreDependencies, dynamicallyLoaded, ignoreDecorators, usedClassMembers, duplicates). Padrões que valem:
- Apps Vite com client aninhado →
entry: ["apps/*/client/src/main.jsx", ...](oindex.htmlnão é target válido deentry;workspaces.patterns: ["apps/*/client"]não funciona quando o pai já é workspace). - Express server aninhado não detectado →
entry: ["apps/*/server/index.js"]. - shadcn/ui →
ignoreExports: [{"file": "src/components/ui/*.tsx", "exports": ["*"]}]. - Código gerado →
ignorePatterns: ["prisma/migrations/**", "apps/**/.next/**", "apps/**/dist/**", "**/*.d.ts"]. - NÃO ignorar
public/**nemstatic/**em massa — cria órfãos colaterais (testado). Deixar assets aparecerem e marcar no relatório.
Loop de calibração (obrigatório): depois de escrever a config, rodar fallow dead-code --format json e medir o delta por categoria (script de bucket: agrupar unused_files por /client/, /components/, /lib/, etc.). Confirmar que o ruído sistemático sumiu (ex: bucket Vite → 0) sem o total subir por efeito colateral. Iterar até todo finding ser acionável.
Regras de ouro (não-negociáveis)
- Nunca declarar um finding "código morto" sem o entry point estar resolvido — verifique a config primeiro.
- Nunca deletar item
verificarsem--trace+ grep confirmando 0 referências. fallow fixtoca só export/deps/enum; deleção de arquivo é a skill, sempre com build/test depois.- Sempre commit/stash antes; sempre build/test depois de cada lote; reverter se quebrar.
- Apresentar problemas em linguagem humana (1-2 linhas), técnico no colapsável.
- SEMPRE gerar e abrir o relatório HTML (passo 4), em toda execução, qualquer volume. Mostrar achados só no chat = falha da skill. Não é decisão sua.
- O relatório RELATA tudo, inclusive os falso-positivos. Todo veredito da auditoria (🛑 FP, ↩ só interno, ✓ morto, ⚠ verificar) tem que aparecer no próprio HTML, com a prova inline. Proibido corrigir/ressalvar FP só no chat — se o usuário precisa olhar o relatório E o chat pra ter a verdade, a skill falhou. Se tem relatório, o relatório é a fonte única.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.