Volver a actualizaciones
Nuevo releaseSep 4, 2026

sonar v0.4.1

Herramienta CLI para inspeccionar y gestionar servicios que escuchan en puertos de localhost

Compartir
██████    ███    ██████    ██    ██████
██           ██      ██  ██  ██      ██
██      ██   ██  ██  ██  ██  ██      ██
  ██  ██   ██  ██  ██  ██  ██  ████
    ██  ██       ██  ██  ██  ██  ██  ██
██████    ███    ██  ██  ██  ██  ██  ██

Know what's running on your machine.

Sonar shows everything listening on localhost and puts it in order: every port belongs to a group — normally the repository it was started from — and inside that group to a named service. Start your dev servers with sonar start and the whole project becomes one thing you can list as a tree, wait for, tail, and stop with a single command. Docker containers, Compose projects and processes you started by hand are picked up too, without any configuration.

$ 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

Instalación

Homebrew (macOS / Linux)

brew install raskrebs/sonar/sonar

Homebrew 6 rechaza las fórmulas de taps de terceros hasta que confíes en el tap una vez (Error: Refusing to load formula raskrebs/sonar/sonar from untrusted tap):

brew trust raskrebs/sonar

Script de instalación

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

Descarga el último binario en ~/.local/bin y lo añade a tu PATH si es necesario. Reinicia tu terminal o ejecuta source ~/.zshrc.

En Windows (PowerShell):

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

Ubicación de instalación personalizada:

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

Instalar una versión 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

Uso de Go

go install github.com/raskrebs/sonar@latest

Completados de shell (autocompletado con tabulador de números de puerto):

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

Sesenta segundos

Describe cómo se ejecuta tu proyecto en un sonar.yaml en la raíz del repositorio, en lugar de un 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}

Luego inícialo:

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

Sonar elige un puerto libre para cada servicio con port: auto y le indica a cada servicio dónde están los demás, de modo que un segundo worktree se ejecuta junto al primero sin que un solo puerto entre en conflicto. sonar start -d hace lo mismo en segundo plano, y sonar down lo detiene y libera los puertos. En otra 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

¿No hay sonar.yaml? sonar start -- npm run dev ejecuta un comando como un servicio con nombre, y sonar list y sonar kill funcionan con cualquier cosa que esté escuchando.

Los ejemplos a continuación marcados con # check se ejecutan contra una compilación nueva mediante scripts/readme-check.sh en cada ejecución 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

Las columnas predeterminadas son port, process, group, container, image, containerport, url, donde process muestra el nombre que le diste al puerto (sonar rename), luego el nombre del servicio, y después lo que se detectó.

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

Las aplicaciones de escritorio y los servicios del sistema que casualmente están escuchando — Figma, Discord, Spotify, ControlCenter, los bundles .app de macOS, los daemons de /System/Library/ — están ocultos a menos que pases -a.

sonar start

Inicia un proyecto desde su 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`

En primer plano, sonar inicia los servicios a través del daemon, sigue sus logs con el nombre del servicio delante de cada línea, y cuando pulsas Ctrl+C detiene los servicios que inició. Un servicio que ya estaba en ejecución se deja intacto, y sonar regresa por sí solo una vez que todos los servicios que inició han finalizado.

Los argumentos antes de -- nombran un directorio o servicios; todo lo que va después de -- es un comando. O ejecuta un comando como un servicio con nombre dentro de un 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

No hay que pasar nada:

  • Group — --group, si no, el name en el sonar.yaml más cercano, si no, el nombre del directorio raíz de git (un worktree se convierte en repo@worktree), si no, el nombre del directorio actual.
  • Name — --name, si no, el servicio de sonar.yaml cuyo cmd coincida, si no, inferido del comando (npm run dev → dev, uv run api → api, python -m uvicorn → uvicorn, ./dev.sh → dev.sh).
  • Port — --port es una sugerencia, no un vínculo: la ejecución se muestra como starting hasta que el puerto esté realmente escuchando, y el daemon lo usa para emparejar el proceso con el puerto.

El hijo hereda stdin, stdout, stderr, cwd y el entorno, además de SONAR_GROUP, SONAR_NAME y SONAR_RUN_ID. Obtiene su propio grupo de procesos, así que sonar kill derriba todo el árbol — un servidor de desarrollo con sus watchers y workers. Ctrl+C se reenvía, y sonar sale con el código de salida del hijo.

Categorías