npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

teley-cli

v0.5.0

Published

Terminal trace and log viewer for Teley. Point your OpenTelemetry or Sentry SDK at a room DSN and watch traces stream in as a live waterfall.

Readme


teley-cli generates a DSN and renders traces, logs, and metrics as they stream in. No account, no config file.

Built with OpenTUI (React bindings), so the waterfall needs FFI: Bun, or Node 26.4+ with --experimental-ffi.

⚡ Run

bunx teley-cli                         # live room, waterfall in your terminal
bunx teley-cli mcp                     # serve the room to a coding agent over MCP
bunx teley-cli --demo                  # sample data, no network
bunx teley-cli --new                   # start a fresh room (new DSN)
bunx teley-cli --json                  # no TUI, newline-delimited JSON on stdout
bunx teley-cli --local                 # receive telemetry here, nothing leaves the machine

The DSN and OTLP endpoint are printed in the header. Point your SDK at either one, run your app, and spans appear.

The TUI needs FFI, so either Bun, or Node 26.4+ with node --experimental-ffi are needed. Everything else (--json, mcp, --local) runs on Node/Bun alike.

📡 Send your data

Both protocols land in the same room. Swap in the session ID from the header.

| Purpose | Endpoint | | ----------- | ------------------------------- | | Sentry DSN | https://<room-id>@teley.dev/0 | | OTLP ingest | https://teley.dev/r/<room-id> |

Sentry.init({ dsn: 'https://<room-id>@teley.dev/0', tracesSampleRate: 1.0 });
// or
new OTLPTraceExporter({ url: 'https://teley.dev/r/<room-id>' });

Traces, logs, and metrics all go to that one OTLP endpoint, in JSON or protobuf, gzipped or not. See the main README for full SDK snippets.

✨ What you get

  • Live waterfall. Time-proportional span bars with the real hierarchy, span-kind badges, and errors in red.
  • Span details. Kind, duration, status, span id, and every attribute for the selected span.
  • Logs view. The full log stream with severity colors, correlated with the traces in the same room.
  • Metric charts. Drawn in the terminal itself, out of braille: counters and gauges as lines, histogram buckets as bars. A metric split by attributes is charted as one series per attribute set, not folded into an average.
  • Both protocols. OTLP and Sentry envelopes render in one timeline, each tagged with its source.
  • Sessions that persist. Your room is reused across runs, so a restart does not invalidate the DSN you configured.
  • Pipeable. --json drops the TUI and streams the room as newline-delimited JSON, for jq, a file, or CI.
  • Readable by agents. teley mcp hands the same room to a coding agent as MCP tools, so it can run your app and read the span tree back.
  • Offline if you want. --local makes the CLI the ingest endpoint, so telemetry never leaves your machine.

⌨️ Keys

| Key | Action | | ------------------------ | --------------------------------------------- | | / | Cycle the Traces, Logs, and Metrics views | | / (or j / k) | Navigate the focused panel | | tab | Cycle focus: list → detail → connection links | | / y | Copy the focused DSN or OTLP endpoint | | c | Clear the local view | | q | Quit |

With the trace list focused, / moves between traces. With the waterfall focused, it moves between spans and the attribute panel follows along. In the metrics view / always moves between series, since a chart has nothing to walk inside one, and tab swaps the series list for a stats and attributes panel.

🧾 JSON output

--json skips the TUI entirely and streams the room to stdout as newline-delimited JSON, one object per line. Same room, no terminal rendering, so it pipes and greps.

bunx teley-cli --json | jq 'select(.type == "trace" and .trace.status_code == 2)'
bunx teley-cli --json > run.ndjson         # keep a run for later
bunx teley-cli --json --demo               # sample data, to see the shape

The first line is the session, so a script can read the DSN it should point an SDK at. Every line after it is telemetry:

{ "type": "session", "version": "0.1.7", "room_id": "…", "host": "teley.dev", "dsn": "…", "otlp": "…", "time": "…" }
{ "type": "trace", "trace": { … }, "spans": [ … ], "time": "…" }
{ "type": "log", "log": { … }, "time": "…" }
{ "type": "metric", "metric": { … }, "time": "…" }

trace, log, and metric carry the same shapes the web app uses (shared/parsers/types.ts). A metric line is one data point, so a series arrives as many lines; group them by name and attributes to reassemble it. A trace appears on a new line every time more of it arrives: trace is the running summary over every span seen so far, while spans holds only the spans from that update, so lines never repeat a span.

Nothing else is written to stdout. Connection state stays out of the stream, and a fatal error (a room already claimed by another token) goes to stderr with exit code 1. ctrl-c exits 0.

🏕️ Local mode

--local makes the cli process the ingest endpoint. Your app posts OTLP or Sentry envelopes straight to it on localhost, and nothing leaves the machine.

bunx teley-cli --local               # ingest on 127.0.0.1:8788
bunx teley-cli --local --port 4318   # the conventional OTLP/HTTP port
bunx teley-cli --local --port 0      # let the OS pick, printed in the header
bunx teley-cli mcp --local           # same, serving an agent

It accepts the same formats as teley.dev: JSON or protobuf, gzipped or not, and Sentry envelopes. The CLI still reports its own crashes; see below.

🤖 MCP for Coding agents

teley mcp serves the room over MCP on stdio, so an agent can instrument your app, run it, and read the traces back without a terminal.

claude mcp add teley -- bunx teley-cli mcp
// or by hand, in .mcp.json
{
  "mcpServers": {
    "teley": { "command": "bunx", "args": ["teley-cli", "mcp"] },
  },
}

| Tool | What it does | | ----------------- | -------------------------------------------------------------------------------- | | get_dsn | The room's DSN and OTLP endpoint, to point an SDK at | | wait_for_traces | Blocks until the room goes quiet, returns what arrived (idle_ms, timeout_ms) | | list_traces | Captured traces, newest first (limit, errors_only, service) | | get_trace | One trace as an indented span tree (include_attributes for the metadata) | | list_logs | Captured logs (min_severity, trace_id) | | list_metrics | Captured metric series with their current reading and range (name, service) | | clear_captured | Drops what the server is holding, so the next run starts clean |

The loop is: get_dsn → point the SDK at it → run the app → wait_for_tracesget_trace on whatever looks wrong. Results come back as text sized for a model to read, not raw payloads:

     +0ms  POST /checkout                    213.0ms  server  ERROR
  +10.0ms    GET inventory-service            59.0ms  client
  +80.0ms    db.query orders                 120.0ms  client  ERROR

Call wait_for_traces before or while the app runs, not after it exits: it reports what arrives from the moment it is called.

It watches the same room as the TUI and the web app, so you can follow along while the agent works.

It starts empty every time your MCP client starts it.

📮 What the CLI reports about itself

teley-cli reports its own faults, the way any installed program does. That is the CLI's health, and it is a different thing from the telemetry you point at it.

Never sent, in any mode: your spans, logs, metrics, attribute values or payload bodies.

Sent: crashes and stack traces from the CLI's own code, and counters about its operation, which mode it ran in, how many payloads it accepted or rejected and why, connection close codes, and how long each MCP tool took and how it ended. A crash also carries the runtime it ran under, the OS and architecture, and the CLI's resolved dependency versions.

🛠️ Local development

From this directory:

bun install
bun run dev              # bun run src/index.tsx
bun run dev --demo
bun run typecheck
bun run test             # bun test; chart.ts and metrics.ts are pure, so they
                         # are covered directly
bun run build            # bundle to dist/ (what gets published)

The published package is a single Bun-bundled dist/index.js with deps kept external. The cross-package imports from shared/ are inlined at build time.

With the CLI running and a worker up, inject a sample trace:

bun run scripts/send-test-trace.ts --host localhost:8787