██████╗ ███████╗ ██╗ ██╗ ██████╗ ██████╗ ██╗ ██╗███████╗
██╔══██╗██╔════╝ ██║ ██║██╔═══██╗██╔═══██╗██║ ██╔╝██╔════╝
██████╔╝███████╗ ███████║██║ ██║██║ ██║█████╔╝ ███████╗
██╔═══╝ ╚════██║ ██╔══██║██║ ██║██║ ██║██╔═██╗ ╚════██║
██║ ███████║ ██║ ██║╚██████╔╝╚██████╔╝██║ ██╗███████║
╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
Claude Code hooks exclusivos para ProStaff API
╔══════════════════════════════════════════════════════════════════════════════╗
║ PS-HOOKS - Claude Code Developer Toolkit para ProStaff API ║
╠══════════════════════════════════════════════════════════════════════════════╣
║ Comprime output de CLI, injeta contexto de dominio e gerencia modo de ║
║ trabalho - exclusivo para sessoes no repositorio prostaff-api. ║
║ ║
║ reducao medida contra saida real: rspec 99%, rubocop 91%, brakeman 91% ║
║ reproduza com `npm run measure`; os numeros sao testados, não estimativa ║
╚══════════════════════════════════════════════════════════════════════════════╝
▶ Funcionalidades (clique para expandir)
┌─────────────────────────────────────────────────────────────────────────────┐
│ [■] Command Compressor - rspec, brakeman, rubocop, docker logs filtrados │
│ [■] Domain Detector - git status detecta modulo ativo automaticamente │
│ [■] Context Injector - injeta so o slice relevante do CLAUDE.md │
│ [■] Mode Commander - skills de plugin: /ps:domain, /ps:check, ... │
│ [■] Statusline Badge - [PS:AI] / [PS:AUTH] / [PS:MATCHES] etc │
│ [■] Zero Dependencies - Node.js stdlib apenas, sem npm install │
│ [■] Project-scoped - ativa exclusivamente em sessoes prostaff-api │
│ [■] Fail-safe - erro no filtro cai para output bruto, sem perda │
└─────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────┐
│ 01 · Como Funciona │
│ 02 · Instalacao │
│ 03 · Hooks Implementados │
│ 04 · Filtros de Comandos │
│ 05 · Dominios ProStaff │
│ 06 · Comandos /ps: │
│ 07 · Statusline │
│ 08 · Estrutura do Projeto │
│ 09 · Referencia de Inspiracao │
└──────────────────────────────────────────────────────┘
Tres hooks independentes atuam em momentos diferentes da sessao Claude Code:
SESSION START
─────────────
session-start.js
→ git status do prostaff-api
→ detecta dominio ativo (auth / ai / matches / ...)
→ injeta contexto minimo especifico ao dominio
→ escreve flag para statusline
DURANTE A SESSAO (por tool call Bash)
──────────────────────────────────────
pre-tool-use.js (PreToolUse hook)
→ le o comando Bash que Claude quer executar
→ verifica se e um comando ProStaff conhecido
→ reescreve para: node ps-filter.js <tipo> -- <comando original>
→ ps-filter.js executa o comando real + comprime output
POR COMANDO
───────────
skills/<nome>/SKILL.md (skill do plugin ps)
→ /ps:help, /ps:domain, /ps:check, /ps:full
→ /ps:domain executa bin/ps-domain.js e grava o estado da sessao
Fluxo do command compressor em detalhe:
Claude executa: bundle exec rspec spec/controllers/players_controller_spec.rb
|
pre-tool-use.js intercepta (PreToolUse)
|
reescreve o comando para:
node /path/bin/ps-filter.js rspec -- bundle exec rspec spec/...
|
ps-filter.js roda o comando original via sh -c
|
lib/filters/rspec.js comprime o output
|
Claude ve:
FAILURES (1):
1) PlayersController GET /players returns players list
Error: expected the response to have status code 200 but it was 401
At: ./spec/controllers/api/v1/players_controller_spec.rb:45
SUMMARY: 45 examples, 1 failure
Os comandos /ps: sao skills de plugin. Um comando com : no nome so existe
nesse formato: o TUI resolve qualquer texto que comece com / contra o registry
de comandos antes de submeter, e aborta com Unknown command se nao achar. Um
hook de UserPromptSubmit nunca chega a ver o texto.
Instalar como plugin (carrega hooks e comandos juntos):
# permanente, carrega em toda sessao como ps@skills-dir
ln -s /caminho/para/prostaff-hooks ~/.claude/skills/prostaff-hooks
# ou so na sessao atual, para testar
claude --plugin-dir /caminho/para/prostaff-hooksConferir o que foi carregado:
claude plugin list
claude plugin details psStatusline (opcional, e o unico passo que o plugin nao cobre): o manifesto de
plugin nao tem campo para statusLine, entao o badge continua vindo do
install.sh.
bash /caminho/para/prostaff-hooks/install.sh /caminho/para/prostaff-api
npm testO install.sh tambem serve para quem prefere registrar os hooks direto no
settings.json do projeto em vez de instalar o plugin. Ele faz backup do
arquivo existente, aborta se nao for JSON valido, e e idempotente. Nesse caminho
os comandos /ps: nao existem, porque dependem do plugin.
╔══════════════════════╦════════════════════════════════════════════════════════╗
║ HOOK ║ ARQUIVO ║
╠══════════════════════╬════════════════════════════════════════════════════════╣
║ SessionStart ║ hooks/session-start.js ║
║ ║ → detecta dominio via git status ║
║ ║ → injeta contexto minimo do dominio ativo ║
╠══════════════════════╬════════════════════════════════════════════════════════╣
║ PreToolUse (Bash) ║ hooks/pre-tool-use.js ║
║ ║ → reescreve comandos conhecidos para ps-filter ║
║ ║ → ativa so em sessoes prostaff-api ║
╠══════════════════════╬════════════════════════════════════════════════════════╣
║ (removido) ║ UserPromptSubmit nao existe mais: o TUI intercepta ║
║ ║ /ps: antes do hook. Virou skill de plugin. ║
╚══════════════════════╩════════════════════════════════════════════════════════╝
Ativacao condicional: os hooks verificam o cwd que o runtime manda no payload (com fallback para transcript_path e process.cwd()) - se nao incluirem prostaff-api, fazem process.exit(0) imediatamente sem interferir em outros projetos.
Veredito pelo exit code: o ps-filter.js propaga o codigo de saida real do comando, e comando morto por sinal ou timeout vira codigo diferente de zero. O filtro so extrai detalhe; quem decide se passou e o exit code. Quando o comando falha e o filtro nao consegue explicar por que, a saida bruta e preservada.
╔═══════════════════════════════╦═══════════════╦══════════════════════════════╗
║ COMANDO ORIGINAL ║ FILTRO ║ OUTPUT ║
╠═══════════════════════════════╬═══════════════╬══════════════════════════════╣
║ bundle exec rspec ║ rspec.js ║ Failures + summary apenas ║
║ rspec ║ ║ ║
╠═══════════════════════════════╬═══════════════╬══════════════════════════════╣
║ brakeman ║ brakeman.js ║ HIGH/MEDIUM apenas ║
║ (injeta -f json -q auto) ║ ║ ║
╠═══════════════════════════════╬═══════════════╬══════════════════════════════╣
║ bundle exec rubocop ║ rubocop.js ║ Agrupado por cop, top 10 ║
║ rubocop ║ ║ ║
╠═══════════════════════════════╬═══════════════╬══════════════════════════════╣
║ docker compose logs ║ docker.js ║ Erros + ultimas 30 linhas ║
║ docker <container> logs ║ ║ ║
╠═══════════════════════════════╬═══════════════╬══════════════════════════════╣
║ rails db:migrate ║ rails.js ║ Migrations + erros apenas ║
║ bundle exec rails db:migrate ║ ║ ║
╚═══════════════════════════════╩═══════════════╩══════════════════════════════╝
npm run measure roda os filtros contra saida real, guardada em
tests/fixtures/, e imprime esta tabela. Os mesmos cenarios rodam no npm test,
cobrando dois criterios: a reducao nao caiu e o sinal sobreviveu.
| cenario | antes | depois | reducao |
|---|---|---|---|
| rspec, suite nao carrega (203 erros) | 194.551 | 1.604 | 99,2% |
| rubocop, 61 offenses em 553 arquivos | 17.201 | 1.491 | 91,3% |
| rails db:migrate, 138 migrations | 103.678 | 9.491 | 90,8% |
| brakeman, 1 warning HIGH | 2.335 | 214 | 90,8% |
| rspec, 43 falhas em 3330 exemplos | 129.707 | 16.585 | 87,2% |
| docker logs, postgres em 222 linhas | 18.851 | 3.631 | 80,7% |
| rspec, 4 falhas em 40 exemplos | 1.904 | 1.069 | 43,9% |
Caracteres, nao tokens. Capturado contra
prostaff-api com RuboCop 1.81,
Brakeman 8.0 e RSpec 3.13; a proveniencia de cada arquivo esta em
tests/fixtures/PROVENIENCIA.md.
Nao ha um numero unico, e a ultima linha e a mais honesta. A reducao depende de quanto a ferramenta fala: a saida comprimida tem tamanho quase constante, entao quanto maior a saida original, maior a reducao. Suite pequena que falha em quatro exemplos economiza pouco, porque nao havia muito a economizar. O ganho aparece onde doi, que e a saida de 190 KB.
Estes numeros so existem porque a medicao encontrou quatro filtros quebrados. Antes dela, o compressor do brakeman entregava 500 caracteres de metadata de scan e escondia o unico warning HIGH do projeto, com otimos 76% de reducao. Um filtro que apaga tudo reduz 100%: e por isso que o teste cobra o sinal junto com a taxa.
O
rails db:migrateera o oposto: guardava toda linha de DDL e todo tempo por operacao, entao num banco zerado reduzia 5,8% - passthrough justamente onde a janela precisava dele. Agora o corpo de cada migration vira contagem quando o run passa de cinco, e a migration que nao concluiu mantem o corpo inteiro, porque e a que se quer ver.
▶ Exemplos de output comprimido
RSpec (antes: ~400 linhas, depois: ~10 linhas)
FAILURES (2):
1) Api::V1::PlayersController GET /api/v1/players returns players list
Error: expected the response to have status code 200 but it was 401
At: ./spec/controllers/api/v1/players_controller_spec.rb:45
2) Player model validates presence of summoner_name
Error: expected #<Player summoner_name: nil> to be valid
At: ./spec/models/player_spec.rb:12
SUMMARY: 89 examples, 2 failures
Brakeman (antes: ~200 linhas JSON, depois: ~8 linhas)
BRAKEMAN: 3 warnings (H:1 M:1 L:1)
HIGH:
app/controllers/players_controller.rb:45 [SQL Injection] Possible SQL injection
code: Player.where("summoner_name LIKE '#{params[:search]}'")
MEDIUM:
app/services/riot_sync_service.rb:12 [SSRF] Request to user-supplied URL
RuboCop (antes: ~500 linhas, depois: ~12 linhas)
RUBOCOP: 219 offenses em 145 files
TOP COPS:
[C] Metrics/MethodLength: 34x (app/services/riot_sync_service.rb:45, app/models/player.rb:120, ...)
[C] Metrics/CyclomaticComplexity: 18x (app/controllers/analytics/..., ...)
[C] Layout/TrailingWhitespace: 15x (app/controllers/..., ...)
...
O session-start.js detecta o dominio ativo lendo git status --short do prostaff-api e mapeando os arquivos modificados:
╔═════════════╦══════════════════════════════════╦══════════════════════════════╗
║ DOMINIO ║ DETECTADO POR ║ AGENT INDICADO ║
╠═════════════╬══════════════════════════════════╬══════════════════════════════╣
║ ai ║ modules/ai_intelligence/ ║ ai-intelligence-specialist ║
║ auth ║ modules/authentication/ ║ security-specialist ║
║ analytics ║ analytics/ ║ rails-api-engineer ║
║ scouting ║ scouting/ ║ rails-api-engineer ║
║ matches ║ matches/ ║ rails-api-engineer ║
║ ║ ║ lol-domain-expert ║
║ players ║ players/ ║ rails-api-engineer ║
║ infra ║ docker-compose, Gemfile, ║ devops-infra-specialist ║
║ ║ .github/workflows/ ║ ║
║ testing ║ spec/ ║ qa-specialist ║
║ general ║ (default) ║ rails-api-engineer ║
╚═════════════╩══════════════════════════════════╩══════════════════════════════╝
Cada dominio injeta um contexto minimo (~5-8 linhas) em vez do CLAUDE.md completo (~300 linhas).
/ps:help # lista todos os comandos
/ps:domain # mostra o dominio detectado na sessao atual
/ps:domain <nome> # forca um dominio manualmente (ex: /ps:domain ai)
/ps:check # roda brakeman + rubocop com saida comprimida
/ps:full # mostra como ver a saida bruta dos comandosPara rodar os filtros manualmente (sem hooks ativos):
node /home/bullet/PROJETOS/prostaff-hooks/bin/ps-filter.js rspec -- bundle exec rspec
node /home/bullet/PROJETOS/prostaff-hooks/bin/ps-filter.js brakeman -- brakeman
node /home/bullet/PROJETOS/prostaff-hooks/bin/ps-filter.js rubocop -- bundle exec rubocop --format jsonO statusline.sh le o arquivo flag ~/.claude/.ps-domain e exibe o badge do dominio ativo:
[PS:AI] [PS:AUTH] [PS:ANALYTICS] [PS:SCOUTING]
[PS:MATCHES] [PS:PLAYERS] [PS:INFRA] [PS:TEST]
Configurar em ~/.claude/settings.json:
{
"statusCommand": "/home/bullet/PROJETOS/prostaff-hooks/statusline.sh"
}prostaff-hooks/
├── PRD.md # Product Requirements Document
├── README.md
├── package.json # Sem dependencias externas
├── install.sh # Injeta hooks no prostaff-api/.claude/settings.json
├── statusline.sh # Badge [PS:DOMINIO] para statusline
│
├── hooks/
│ ├── pre-tool-use.js # PreToolUse: reescreve comandos -> ps-filter
│ ├── session-start.js # SessionStart: dominio + contexto minimo
│ └── hooks.json # registro dos hooks no plugin
│
├── bin/
│ ├── ps-filter.js # CLI: executa cmd original + aplica filtro
│ └── ps-domain.js # CLI: le ou define o dominio da sessao
│
├── lib/
│ ├── domain-detector.js # git status -> dominio (modulo isolado p/ testes)
│ ├── domain-store.js # dominio da sessao em disco
│ ├── domains.js # lista de dominios validos
│ ├── project.js # raiz do projeto e versao do Rails pelo lockfile
│ ├── shell.js # quoting de caminho que vira linha de comando
│ └── filters/
│ ├── rspec.js # Failures + summary
│ ├── brakeman.js # HIGH/MEDIUM apenas (parse JSON)
│ ├── rubocop.js # Agrupado por cop, top 10
│ ├── bundler_audit.js # Advisories por gem
│ ├── docker.js # Erros + ultimas 30 linhas significativas
│ ├── rails.js # Migrations executadas + erros
│ └── outcome.js # Veredito por exit code, nao por texto
│
└── skills/ # Comandos /ps: do plugin
├── ps-help/SKILL.md # /ps:help
├── ps-domain/SKILL.md # /ps:domain
├── ps-check/SKILL.md # /ps:check
└── ps-full/SKILL.md # /ps:full
╔══════════════════╦═════════════════════════════════════════════════════════════╗
║ PROJETO ║ CONTRIBUICAO PARA PROSTAFF-HOOKS ║
╠══════════════════╬═════════════════════════════════════════════════════════════╣
║ RTK ║ Arquitetura PreToolUse rewrite - ps-filter.js segue o ║
║ (Rust Token ║ mesmo padrao: interceptar, executar real, comprimir, ║
║ Killer) ║ preservar exit code. 100+ comandos genericos → 6 especificos║
╠══════════════════╬═════════════════════════════════════════════════════════════╣
║ Caveman ║ SessionStart hook para injecao de contexto. Flag file para ║
║ ║ comunicar estado entre hooks (session-start → statusline). ║
║ ║ O /ps: veio depois, e como skill de plugin. ║
╚══════════════════╩═════════════════════════════════════════════════════════════╝
Diferenciais exclusivos do prostaff-hooks:
- Filtros escritos para o formato exato de output do ProStaff (brakeman com
-f json, rubocop--format json) - Domain detection mapeada para os 8 modulos do ProStaff API
- Contexto de dominio inclui regras de segurança especificas (
organization_scoped,SHA256, SSRF whitelist) e o agente Claude Code indicado para cada modulo - Project-scoped: zero interferencia em outros projetos
- Nenhuma dependencia npm - startup < 20ms por invocacao
Projeto privado · ProStaff.gg · 2026