Executando o Script check
Este skill é a fonte única da verdade para executar o script check do package.json em fluxos de trabalho lt-dev. Qualquer revisor, rebaser ou orquestrador que precise garantir a executabilidade do projeto deve seguir este procedimento à risca — duplicar as regras entre agentes leva a divergências.
Objetivo: Uma execução
checkverdadeiramente verde (código de saída 0) é um pré-requisito inegociável para que qualquer revisão ou rebase seja considerado completo. O único resíduo aceitável é uma vulnerabilidade de dependência upstream onde toda a escada de escalação de correção foi esgotada.
Quando Usar Este Skill
| Chamador | Fase | Gatilho | Modo |
|---|---|---|---|
/lt-dev:review | Fase 1.5 | Antes de gerar qualquer revisor especializado | Advisory |
lt-dev:code-reviewer | Fase 1.5 | Antes da revisão de passagem única (pular se o orquestrador já executou) | Advisory |
lt-dev:test-reviewer | (briefing de entrada) | Respeita a semântica de pular definida aqui | Advisory |
/lt-dev:take-ticket | PASSO 8 | Depois que todos os pilares de teste estão verdes | Bloqueante |
/lt-dev:git:ship | PASSO 1, PASSO 4b | Pré-voo, e após a re-verificação pós-rebase | Bloqueante |
/lt-dev:ticket-cycle | via take-ticket + git:ship | Ciclo completo | Bloqueante |
lt-dev:branch-rebaser | Fase 6.5 | Após lint/format, antes dos testes | Bloqueante |
Modos dos Chamadores
O procedimento é idêntico em ambos os modos. Apenas o que acontece com um erro não resolvido difere, e essa diferença é o ponto central da distinção:
- Advisory — o trabalho do chamador é relatar. Uma falha no
checké exibida como um achado Crítico e o fluxo continua, porque o usuário ainda deseja o restante da revisão. - Bloqueante — o trabalho do chamador é entregar. Uma falha no
checkinterrompe o fluxo. Nada é enviado, nenhum MR/PR é criado, nada é mesclado.
Todo caminho que leva a um MR/PR ou a uma mesclagem executa no modo Bloqueante. Uma falha no check que chega à branch base custa para toda a equipe: o CI fica vermelho para todos, o próximo take-ticket parte de código quebrado, e a pessoa que eventualmente conserta não tem ideia de qual mudança causou o problema. É por isso que a escada no Passo 3 não tem limite de iterações e por que a lista de resíduos no Passo 5 é tão estreita.
Procedimento
Passo 1 — Descobrir scripts check
Use o script auxiliar dedicado (localizado no plugin lt-dev):
bash "${CLAUDE_PLUGIN_ROOT}/scripts/discover-check-scripts.sh"
A saída é TSV, um projeto por linha:
<caminho do package.json>\t<script check>\t<inclui_testes:no|unit+api|yes>\t<gerenciador de pacotes>
Valores de includes_tests — os chamadores decidem o que fazer com cada um, a descoberta em si não prescreve comportamento:
| Valor | Significado | Cobertura Playwright |
|---|---|---|
no | Nenhum executor de teste detectado na cadeia do check. | Não coberto. |
unit+api | A cadeia do check delega para o wrapper check.mjs do lt, que executa etapas de teste Unit (app) + API (api) e deliberadamente pula Playwright (Playwright executa via lt dev test / CI — veja scripts/check.mjs). | Não coberto — Playwright ainda deve ser executado separadamente, se necessário. |
yes | Correspondência direta de padrão com test, vitest, jest ou playwright na cadeia do check (transitivamente, um nível de resolução composta). O escopo é o que o script define. | Desconhecido — os chamadores devem verificar localmente se a cobertura Playwright é necessária. |
O auxiliar:
- Usa
git ls-files "package.json" "**/package.json"para respeitar.gitignoree pularnode_modules - Analisa JSON via
jq→node -e→ cadeia de fallbackgrep+sed(funciona mesmo semjqinstalado) - Resolve scripts compostos de um único nível (
"check": "pnpm run ci"→ busca porci) - Detecta o gerenciador de pacotes por projeto através do arquivo de bloqueio (
pnpm-lock.yaml→pnpm, etc.; padrãopnpm)
Se o auxiliar não retornar nada → nenhum projeto define check → pule o restante deste skill.
Passo 1a — Sem correções sugeridas do oxlint
oxlint --fix-suggestions aplica correções que o próprio oxlint marca como possivelmente alteradoras de comportamento: sua sugestão no-console deleta a chamada. --fix-dangerously vai além. Os modelos atuais não passam nenhuma delas, mas projetos de modelos mais antigos ainda o fazem, no wrapper do check, em lint:fix, lint-staged ou no próprio scripts/check.mjs do projeto. lt fullstack update as remove na raiz do workspace e no app (apenas arquivos rastreados e limpos); o projeto API mantém seus próprios arquivos, então um acerto lá é removido manualmente ou usando o arquivo atual do nest-server-starter. Observado em nest-server (2026-09, claude-code PR #10): um hook de commit transformou um console.log em um corpo de função vazio e ainda relatou "passou". Antes do Passo 2, procure por um uso de qualquer uma das flags; uma menção em um comentário não conta:
git grep -n -E "(^|[[:space:]\"'])(--fix-suggestions|--fix-dangerously)" -- '*package.json' '*.lintstagedrc*' '*lint-staged.config.*' '*scripts/check.mjs' \
| grep -v -E '^[^:]+:[0-9]+:[[:space:]]*(//|/?\*|#)'
O segundo filtro descarta linhas de comentário: o wrapper atual do nest-server-starter explica em um comentário por que passa apenas --fix simples.
Em um acerto, o check executa sem correção automática:
- Execute o wrapper lt como sua porta de entrada somente leitura:
<pm> run check --no-fix(npm:npm run check -- --no-fix). Todo wrapper que ainda passa uma das flags já conhece--no-fix. Onde a cadeia do próprio projeto chamalint:fix, ou seu próprioscripts/check.mjsé um dos acertos, execute as etapas desse projeto comlintem vez delint:fix. - Corrija achados de lint manualmente ou com
oxlint --fixsimples; formate com o formatador do projeto como de costume. - Nomeie cada acerto (
arquivo:linha) no relatório do Passo 8 com seu remédio:lt fullstack updatepara a raiz e o app, remover a flag manualmente (ou o arquivo atual do nest-server-starter) para o projeto API.
Passo 2 — Executar check por projeto
Para cada projeto descoberto, cd para seu diretório e execute o script check com o gerenciador de pacotes detectado:
cd "$(dirname <caminho do package.json>)"
<gerenciador de pacotes> run check
Capture stdout, stderr e código de saída. Acompanhe um contador de iterações começando em 1.
Passo 3 — Loop de correção automática (iterar até ficar verdadeiramente verde)
Se o check de um projeto sair com código não-zero:
- Analise todos os erros da execução atual (typecheck, lint, build, imports faltantes, incompatibilidades de tipo, símbolos não utilizados, achados de auditoria, etc.)
- Corrija todo erro na causa raiz via
Read+Edit. Erros pré-existentes também são corrigidos — não importa se um erro veio deste diff ou já estava lá para a executabilidade do projeto, e umcheckvermelho bloqueia a próxima pessoa exatamente da mesma forma de qualquer maneira. Limites de escopo não se aplicam à executabilidade. A única questão que decide algo aqui é "isso pode ser corrigido?", e enquanto a resposta for sim, é corrigido. - Re-execute
checkdo zero. Nunca confie em estado parcial. - Continue iterando até que uma destas condições terminais seja atingida:
- (a) VERDE —
checksai com 0 → concluído para este projeto - (b) ESTAGNADO — uma iteração completa não produziu redução líquida na contagem de erros
- (a) VERDE —
- Sem limite máximo de iterações. Enquanto cada iteração reduzir estritamente a contagem de erros, continue. O objetivo é o verde verdadeiro.
Uma exceção restrita, e é sobre colisão, não sobre escopo. O ponto 2 permanece: um erro pré-existente é corrigido, porque um check vermelho bloqueia a próxima pessoa independentemente de quem o escreveu. O que o ponto 2 não cobre é um erro dentro de trabalho não commitado no qual outra sessão ativa está no meio de uma edição — remodelar isso não é uma questão de escopo, são duas sessões editando um arquivo, e o par retorna a uma refatoração reescrita tendo perdido mais tempo do que a correção economizou. Onde a árvore está suja e bash "${CLAUDE_PLUGIN_ROOT}/scripts/change-provenance.sh" atribui o caminho com falha a um par ativo: corrija se for trivial e autocontido (um import faltante, uma violação de formatação, um console.log perdido), e caso contrário, relate como um bloqueador nomeando o autor, mais um SOLVED carregando o diagnóstico para que eles possam corrigir seu próprio trabalho em uma etapa. Ninguém ativo, ou nada atribuível: o ponto 2 se aplica inalterado.
ESTAGNADO é um sinal para mudar de abordagem, não permissão para parar. A contagem para de cair quando a mesma correção está sendo repetida, então a próxima iteração deve atacar o erro de forma diferente: leia o arquivo com falha por completo em vez de aplicar patches ao redor da linha relatada, verifique se dois erros compartilham uma causa, veja como um módulo irmão funcional resolve a mesma coisa, execute a etapa com falha sozinha para ver a saída que a execução agregada engoliu, verifique se é um dos perigos conhecidos nos Passos 6.5 a 6.8. Somente quando uma abordagem genuinamente diferente foi tentada e a contagem ainda se mantém, a classificação residual do Passo 5 se aplica — e no modo Bloqueante, tudo exceto uma vulnerabilidade de dependência com escada esgotada ainda interrompe o fluxo.
Passo 4 — Achados de auditoria: escada de escalação de correção obrigatória
Quando pnpm audit / npm audit / yarn audit (invocado por check) relata uma vulnerabilidade, esgote esta escada antes de classificar o achado como Aceito. Re-execute check após cada etapa.
| # | Etapa | Comando (pnpm / npm / yarn) |
|---|---|---|
| 1 | Atualizar para a última compatível | pnpm update <pkg> / npm update <pkg> / yarn upgrade <pkg> |
| 2 | Remediação automática | pnpm audit --fix / npm audit fix / yarn audit --fix |
| 3 | Forçar upgrade semver-major | pnpm audit --fix --force / npm audit fix --force |
| 4 | Avançar dependência direta para o próximo major se o advisory listar correção lá | pnpm add <pkg>@<major> / npm install <pkg>@<major> / yarn add <pkg>@<major> |
| 5 | Forçar versão de dependência transitiva | Bloco pnpm.overrides / resolutions (yarn) / overrides (npm) no package.json, então reinstalar |
| 6 | Avançar o CONSUMIDOR, não o pacote vulnerável | a dependência direta que o puxa, e o framework lt se o framework o fixar (@lenne.tech/nest-server / @lenne.tech/nuxt-extensions) — um /lt-dev:maintenance:maintain completo é a forma aprofundada |
| 7 | Aplicar patch no consumidor — apenas sob as condições abaixo | pnpm patch <pkg> → patchedDependencies |
| 8 | Substituir o pacote | Mudar para uma alternativa mantida se abandonado |
A Etapa 6 é o degrau que é pulado, e é o que mais frequentemente funciona. As etapas 1 a 5 todas empurram o pacote vulnerável para frente. Quando isso falha, a razão geralmente não é o pacote vulnerável — é o consumidor o segurando, ao fixar um intervalo vulnerável ou ao usar uma API que o major corrigido removeu. Então a pergunta a fazer é "quem mantém esta versão aqui?", e a resposta é uma dependência direta, ou um framework cujo fix um override não consegue superar. Um override é um fix, e um fix é estritamente pior do que um bump de versão real: ele diverge a árvore do que upstream testa, e apodrece silenciosamente. Faça o bump onde ele existe.
A Etapa 7 (patching) é estreita de propósito, e a estreiteza é o ponto. Quando o major corrigido apenas falha ao carregar — um export default removido, um ponto de entrada renomeado — um patch de uma linha parece fechar o advisory corretamente em vez de suprimi-lo. Às vezes funciona. Três condições precisam ser atendidas primeiro, e a terceira é a que geralmente falha:
- O patch tem como alvo um caminho estável no pacote vulnerável, e é fixado em uma versão exata. O que quebra um patch não é
dist/como tal — pacotes publicados enviamdist/e nada mais — é um caminho que se move entre versões.dist/chunks/<hash>.mjsé renomeado pela próxima build e o patch então falha para todos na equipe;dist/index.mjsé o ponto de entrada do próprio pacote e permanece. Um patch que nomeia um símbolo minificado ainda é aceitável com o fix de versão, porque o fix transforma o risco em uma falha ruidosa depnpm installem vez de um patch silencioso incorreto. Aplique patch na dependência vulnerável, não em um consumidor que por acaso a importa — veja o caso mensurado abaixo, onde a primeira avaliação olhou para o chunk do consumidor e rejeitou o degrau nessa base. - Pese o fechamento de produção contra o custo de manutenção. Um patch é uma obrigação contínua em cada bump futuro, então para um caminho de ferramentas de desenvolvimento que não pode alcançar a produção, ele pode gastar mais do que compra — em um único projeto. Um TEMPLATE inverte essa aritmética: cada projeto gerado herda um patch, enquanto um resíduo teria que ser re-argumentado em cada um deles. Isso é um julgamento, não um veto; as condições 1 e 3 são as difíceis.
- Carregar não é o mesmo que funcionar. Um major que removeu um export geralmente também mudou comportamento, então um import corrigido faz o módulo importar enquanto deixa o consumidor rodando contra uma API na qual nunca foi testado. Se você não pode dizer o que mais mudou naquele major e por que não importa aqui, o patch é um palpite vestido de correção.
Aplique patch no pacote VULNERÁVEL, não no consumidor. Esta é a distinção que decide se o degrau funciona, e é fácil errar, porque o erro aponta para o consumidor. Medido, lt-crm 2026-10-06: @nuxt/[email protected] faz import Git from 'simple-git', e avançar simple-git para a única linha corrigida (4.x, que removeu aquele export default) fez nuxt prepare abortar com does not provide an export named 'default'. A primeira avaliação olhou para o próprio dist/chunks/module-main.mjs do devtools, encontrou o import lá, e rejeitou o patch na condição 1 — um chunk compilado — que foi o veredito certo sobre o arquivo errado. O patch pertence um nível abaixo, no próprio dist/index.mjs do simple-git, onde uma única linha adicionada re-exporta como default a mesma fábrica que o módulo já exporta como simpleGit. Nada sobre o código endurecido muda; apenas a superfície do módulo retorna.
Com isso, todas as três condições se mantêm: é o pacote vulnerável em vez de um artefato do consumidor, está fixado em uma versão exata (patchedDependencies: { '[email protected]': … } mais o alvo do override), e a API que o devtools realmente chama — branch, revparse, log — é estável através dos majors (simple-git não removeu nada que devtools usa). A Etapa 7 é aceita aqui.
Passo 5 — Classificar resíduos
Se, após esgotar a escada, restar um erro:
| Resíduo | Ação em Advisory | Ação em Bloqueante | Explicação |
|---|---|---|---|
| Vulnerabilidade de dependência onde a escada completa foi executada e a Etapa 8 foi tentada/esgotada | Relatar como Crítico com o degrau mais alto da escada alcançado. | Não bloqueia — mas listar no relatório. | Nenhum código próprio foi alterado; a vulnerabilidade está em um artefato publicado. Bloquear impede todo o trabalho da equipe. |
| Qualquer outro erro (typecheck, lint, build, etc.) | Relatar como Crítico. | BLOQUEIA. Nada avança. | A executabilidade está quebrada. Nenhum código que não executa deve ser mesclado. |
Passo 6 — Relatar resultado
Retorne uma estrutura de dados contendo:
- status:
green|red - detalhes por projeto: lista de objetos com:
project: caminho dopackage.jsonstatus:green|red|stallediterations: número de iteraçõespackageManager: pacote usadostdout: saída padrão da execução finalstderr: saída de erro da execução finalerrors:** lista de objetos de erro (quandoredoustalled):type:vulnerability|typecheck|lint|build|otherfile: caminho do arquivo (quando aplicável)message: mensagem do errofixAttempted: correção tentadaescalationStep: degrau da escada alcançado (para vulnerabilidades)resolved:true|false
- mdReport: relatório em Markdown formatado para humanos
Passo 7 — Modo Bloqueante: interromper ou continuar
Se qualquer projeto estiver red ou stalled e o modo for Bloqueante, interrompa todo o fluxo de trabalho com uma mensagem de erro. Não crie MR/PR, não mescle, não envie.
Passo 8 — Relatório de resumo (Advisory e Bloqueante, quando bloqueante permite continuação)
Produza um resumo Markdown:
## Resultado da Execução do `check`
**Status Geral:** <green|red>
**Modo:** <Advisory|Bloqueante>
### Projetos
| Projeto | Status | Iterações |
|---------|--------|-----------|
| <caminho> | <status> | <n> |
### Achados Críticos
<lista de erros não resolvidos com tipo, arquivo, correção tentada>
### Detalhes
<qualquer contexto adicional relevante>
Notas Técnicas
- O script
discover-check-scripts.shestá localizado em${CLAUDE_PLUGIN_ROOT}/scripts/ - O script
change-provenance.shestá em${CLAUDE_PLUGIN_ROOT}/scripts/ - A resolução de scripts compostos é de nível único (
"check": "pnpm run ci"→ apenas buscaci, não resolve recursivamente) - A detecção do gerenciador de pacotes prioriza:
pnpm-lock.yaml→pnpmpackage-lock.json→npmyarn.lock→yarn- Padrão:
pnpm
- A saída deve ser capturada com redirecionamento de saída padrão (stdout) e saída de erro (stderr)
- O código de saída deve ser capturado via
$?ou uma construção equivalente - O contador de iterações começa em 1
- O loop de correção automática não tem limite máximo de iterações, mas estagna se nenhuma redução líquida for observada após uma iteração completa
- A Etapa 7 (patching) requer que todas as três condições sejam atendidas; caso contrário, permanece na Etapa 6 ou avança para a Etapa 8