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

@langecs/devtools

v0.2.0

Published

Visual inspector for LangECS worlds — live entity/component state, interactive mutation, flight-recorder timeline, OTLP trace waterfall, human-in-the-loop

Readme

@langecs/devtools

A visual inspector for LangECS worlds. One call attaches a local web GUI to a running world:

import { startDevtools } from '@langecs/devtools';

const server = await startDevtools(world);
console.log(server.url); // http://127.0.0.1:4477

Everything the engine knows is on screen, live:

| Panel | Shows | Lets you | |---|---|---| | Inspector | every entity's components as JSON trees; Messages rendered as a chat transcript | edit component values, add/remove components, despawn, send chat messages | | Systems | registered systems, effective queries (agent auto-tags included), matched entities, pending (dirty) pairs and why they're dirty | jump to matched entities | | Timeline | the flight recorder (R42): per step — scheduled/vetoed pairs, run durations, buffered writes, applied changes, spawns/despawns, dropped writes | inspect any step, jump to changed entities | | Traces | an OpenTelemetry span waterfall (runs → steps → systems → GenAI model/tool calls with token counts) | inspect attributes, events, errors per span | | Events | the live RunEvent stream of every run, including ctx.emit custom events (streaming tokens) | filter by type/text | | Interrupts | entities parked on AwaitingHuman (R33) | answer them — world.resume from a form | | Time travel | the persistence adapter's step history | restore any step boundary (forks the timeline) |

Mutations go through the engine's public external-mutation API and are idle-only (R16): while a run is in flight the server returns a clear error instead of corrupting a step. Nothing in the devtools bypasses engine invariants.

Install

npm i -D @langecs/devtools

A development dependency: it starts a local web server and is not meant to ship to production.

Your application must also declare a compatible @langecs/core; devtools shares that instance through its peer dependency. Install core explicitly, including with package managers that do not install peers automatically. Upgrade related @langecs packages together across 0.x minor versions.

ESM only, Node >= 20.

Options

const server = await startDevtools(world, {
  port: 4477,          // default; occupied ports fall forward (4478, ...)
  host: '127.0.0.1',   // bind address — keep it loopback unless you know better
  allowedHosts: [],    // extra hostnames accepted as a WebSocket Origin (see below)
  history: adapter,    // PersistenceAdapter with history()/loadStep() → enables time travel
  open: false,         // open the browser automatically
});
// ...
await server.close();

allowedHosts is for reaching the inspector under a name the bind address does not carry — a tailnet MagicDNS name, a container hostname, a reverse proxy. The upgrade guard accepts loopback and host; anything else loads the page and then hangs at "connecting", because only the WebSocket is refused. Hostnames only, no scheme or port, and it stays an allowlist ('*' is not special):

await startDevtools(world, { host: '0.0.0.0', allowedHosts: ['dev-box', 'dev-box.tailnet.ts.net'] });

Pass the same adapter the world persists to (e.g. MemoryAdapter from core or fsAdapter from @langecs/persist-fs) as history to light up time travel.

Traces: standards in, no lock-in

The server embeds a tiny OTLP/HTTP JSON receiver at POST /v1/traces. Any standards-compliant OpenTelemetry exporter can feed the trace view — typically @langecs/otel instrumentation exported through the standard OTel SDK:

import { instrumentWorld } from '@langecs/otel';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { BatchSpanProcessor, NodeTracerProvider } from '@opentelemetry/sdk-trace-node';

const provider = new NodeTracerProvider({
  spanProcessors: [
    new BatchSpanProcessor(new OTLPTraceExporter({ url: `${server.url}/v1/traces` })),
    // add a second processor to also export to Jaeger/Grafana/Honeycomb — same spans
  ],
});
provider.register();
instrumentWorld(world);

The receiver speaks OTLP/HTTP JSON (@opentelemetry/exporter-trace-otlp-http). Protobuf exporters get a 415 with a pointer to the JSON one.

How it connects

startDevtools uses the engine's observability surface (SPEC §14) — a passive event tap, external-change notifications, and read-only introspection. The UI talks JSON over a WebSocket (/ws); the protocol lives in src/protocol.ts. Observer callbacks are isolated by the engine (R45): a devtools bug can never change a run's outcome.

Development

The UI is a React + Vite app in ui/, built into dist/ui by pnpm build and served statically. To hack on the UI against a live world:

pnpm -C examples devtools-demo        # terminal 1: a demo world on :4477
pnpm -C packages/devtools dev:ui      # terminal 2: Vite dev server, proxied to :4477

Try it

pnpm build                       # builds the UI once
pnpm -C examples devtools-demo   # scripted world, no API key needed