Voltar às atualizações
New releaseSep 4, 2026

sonar v0.4.1

Ferramenta CLI para inspecionar e gerenciar serviços escutando em portas localhost

Compartilhar
██████    ███    ██████    ██    ██████
██           ██      ██  ██  ██      ██
██      ██   ██  ██  ██  ██  ██      ██
  ██  ██   ██  ██  ██  ██  ██  ████
    ██  ██       ██  ██  ██  ██  ██  ██
██████    ███    ██  ██  ██  ██  ██  ██

Saiba o que está sendo executado na sua máquina.

O Sonar mostra tudo o que está escutando em localhost e organiza em ordem: cada porta pertence a um grupo — normalmente o repositório de onde foi iniciado — e dentro desse grupo a um serviço nomeado. Inicie seus servidores de desenvolvimento com sonar start e o projeto inteiro se torna uma coisa só que você pode listar como uma árvore, aguardar, acompanhar e parar com um único comando. Contêineres Docker, projetos Compose e processos iniciados manualmente também são detectados, sem nenhuma configuração.

$ sonar list --tree
my-app  (3 ports, running)                        ~/code/my-app
├─ 5432  db          postgres:17                  http://localhost:5432
├─ 5173  frontend    vite (v5.4)                  http://localhost:5173
└─ 8000  api         uvicorn app:app              http://localhost:8000
ungrouped (1 port)
└─ 3000  next-server (v16.1.6)                    http://localhost:3000

Instalação

Homebrew (macOS / Linux)

brew install raskrebs/sonar/sonar

Homebrew 6 recusa fórmulas de taps de terceiros até que você confie no tap uma vez (Error: Refusing to load formula raskrebs/sonar/sonar from untrusted tap):

brew trust raskrebs/sonar

Script de instalação

curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | bash

Baixa o binário mais recente para ~/.local/bin e adiciona-o ao seu PATH, se necessário. Reinicie o terminal ou execute source ~/.zshrc.

No Windows (PowerShell):

irm https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.ps1 | iex

Local de instalação personalizado:

curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | SONAR_INSTALL_DIR=/usr/local/bin bash

Instale uma versão específica:

curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | SONAR_VERSION=vX.Y.Z bash
$env:SONAR_VERSION="vX.Y.Z"; irm https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.ps1 | iex

Usando Go

go install github.com/raskrebs/sonar@latest

Shell completions (tab-complete port numbers):

sonar completion zsh > "${fpath[1]}/_sonar"   # zsh
sonar completion bash > /etc/bash_completion.d/sonar  # bash
sonar completion fish | source                 # fish

Sessenta segundos

Descreva como o seu projeto é executado em um sonar.yaml na raiz do repositório, em vez de um dev.sh:

name: my-app
services:
  - name: db
    cmd: docker compose up db
    port: 5432
  - name: api
    cmd: uv run uvicorn app:app --port ${port}
    port: auto
    depends_on: [db]
  - name: frontend
    cmd: npm run dev -- --port ${port} --strictPort
    port: auto
    depends_on: [api]
    env:
      VITE_API_URL: ${api.url}

Em seguida, inicie-o:

sonar start
  ✓ db        http://localhost:5432   pid 41022  ~/.config/sonar/logs/my-app/db.log
  ✓ api       http://localhost:21408  pid 41040  ~/.config/sonar/logs/my-app/api.log
  ✓ frontend  http://localhost:21409  pid 41077  ~/.config/sonar/logs/my-app/frontend.log

3 started
following the logs; Ctrl+C stops the 3 services started here
api      | INFO:     Uvicorn running on http://127.0.0.1:21408
frontend | VITE v5.4  ready in 312 ms

O Sonar escolhe uma porta livre para cada serviço port: auto e informa a cada serviço onde os outros estão, para que um segundo worktree seja executado ao lado do primeiro sem que uma única porta entre em conflito. sonar start -d faz o mesmo em segundo plano, e sonar down o interrompe e devolve as portas. Em outro terminal:

sonar list --tree
my-app  (3 ports, running)                        ~/code/my-app
├─ 5432   db          postgres:17                 http://localhost:5432
├─ 21408  api         uvicorn app:app             http://localhost:21408
└─ 21409  frontend    vite (v5.4)                 http://localhost:21409

Sem sonar.yaml? sonar start -- npm run dev executa um comando como um serviço nomeado, e sonar list e sonar kill funcionam em qualquer coisa que esteja escutando.

Os exemplos abaixo marcados com # check são executados contra uma build nova por scripts/readme-check.sh em cada execução de CI.

Comandos

sonar list

sonar list
sonar list --tree
sonar list --group my-app
sonar list --json
# check
sonar list --stats             # CPU, memory, threads, uptime, state
sonar list --health            # HTTP health checks
sonar list --filter docker     # only Docker ports
sonar list --sort name         # port | pid | name | type
sonar list -a                  # include desktop apps
sonar list -c port,process,group,cpu,mem
sonar list --host user@server  # scan a remote machine over SSH

As colunas padrão são port, process, group, container, image, containerport, url, onde process mostra o nome que você deu à porta (sonar rename), depois o nome do serviço, depois o que foi detectado.

Colunas disponíveis: port, process, pid, type, url, group, cpu, mem, threads, uptime, state, connections, health, latency, container, image, containerport, compose, project, user, bind, ip.

Aplicativos de desktop e serviços de sistema que por acaso estejam escutando — Figma, Discord, Spotify, ControlCenter, pacotes .app do macOS, daemons em /System/Library/ — são ocultados a menos que você passe -a.

sonar start

Inicia um projeto a partir do seu sonar.yaml:

sonar start                    # every service in the nearest sonar.yaml
sonar start api frontend       # only these (they still wait for their dependencies)
sonar start ../other-project   # the sonar.yaml in or above another directory
sonar start -d                 # in the background, like `sonar up`

Em primeiro plano, o sonar inicia os serviços através do daemon, acompanha os seus logs com o nome do serviço à frente de cada linha, e quando prime Ctrl+C para os serviços que iniciou. Um serviço que já estava em execução é deixado em paz, e o sonar regressa por si próprio assim que todos os serviços que iniciou tiverem terminado.

Os argumentos antes de -- nomeiam um diretório ou serviços; tudo depois de -- é um comando. Ou execute um comando como um serviço nomeado num grupo:

sonar start -- npm run dev
sonar start --group my-app --name frontend -- npm run dev
sonar start --port 5173 -- npm run dev        # expected port, before it binds
sonar start --detach --name api -- uv run uvicorn app:app
sonar start --list

Nada precisa ser passado:

  • Group — --group, senão o name no sonar.yaml mais próximo, senão o nome do diretório raiz do git (um worktree se torna repo@worktree), senão o nome do diretório atual.
  • Name — --name, senão o serviço sonar.yaml cujo cmd corresponde, senão inferido a partir do comando (npm run dev → dev, uv run api → api, python -m uvicorn → uvicorn, ./dev.sh → dev.sh).
  • Port — --port é uma dica, não um vínculo: a execução aparece como starting até que a porta esteja realmente escutando, e o daemon a usa para corresponder o processo à porta.

O processo filho herda stdin, stdout, stderr, cwd e environment, além de SONAR_GROUP, SONAR_NAME e SONAR_RUN_ID. Ele recebe seu próprio process group, então sonar kill derruba toda a árvore — um dev server com seus watchers e workers. Ctrl+C é encaminhado, e o sonar sai com o exit code do processo filho.

Categorias