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

@statedelta/cli

v0.2.0

Published

CLI for StateDelta - state management, chain resolution, and interactive sessions

Downloads

22

Readme

@statedelta/cli

CLI do ecossistema StateDelta. O sd resolve documentos, lança runtimes, roda eles como serviços em background sobre Unix socket e fala com eles remotamente — tudo sobre o contrato IRuntime.

⚠️ Status: DEFERRED — Axiom-specialist. O CLI foi escrito quando o launcher e a engine Axiom moravam no mesmo repo. Os comandos step/run/delta/state/snapshot/ps/remote e todo o server/ expõem o contrato IRuntime/IEngine — API interna da Axiom, não do protocolo 1.0 (@statedelta/protocol), que define TRunning como genérico. Hoje o CLI está fora dos pipes do monorepo (pnpm typecheck/build/test excluem ele explicitamente). Para reviver: ou migra-se pro repo statedelta-axiom como CLI da engine concreta, ou faz-se uma reescrita protocol-only (sem o server, só resolve/load/init/chain/workspace). Ver docs/WORK-STATUS.md §3.1.


Filosofia

O CLI é um orquestrador fino em cima de três libs do StateDelta:

  • @statedelta/launcher — transforma URL em IRuntime pronto
  • @statedelta/gateway — I/O (HTTP/HTTPS, filesystem, custom)
  • @statedelta/engine-axiom — adapter de engine padrão pré-conectado

Dois modos de operação:

┌────────────────────────────────┬─────────────────────────────────┐
│  One-shot (sem estado)         │  Daemon (com estado)            │
│                                │                                 │
│  sd resolve / load / chain     │  sd run + sd ps + sd use        │
│  Cada comando abre o doc,      │  Engine roda como processo em   │
│  faz o que precisa, sai.       │  background; o CLI conversa     │
│  Útil pra inspeção.            │  via Unix socket; comandos      │
│                                │  remotos (sd tick/step/effect)  │
│                                │  conectam na instância ativa.   │
└────────────────────────────────┴─────────────────────────────────┘

Duas camadas de organização:

┌────────────────────────────────┬─────────────────────────────────┐
│  Workspace (filesystem)        │  Global (~/.sd/)                │
│                                │                                 │
│  sd init / state / delta       │  sd config                      │
│  Pasta de projeto com sd.json  │  Config global + registry de    │
│  + state, deltas/, snapshots/. │  instâncias. Persiste entre     │
│                                │  shells.                        │
└────────────────────────────────┴─────────────────────────────────┘

Heurísticas:

  • Só inspecionando? Passe a URL/path direto pro sd load ou sd chain. Não precisa de workspace.
  • Editando um projeto? Roda sd init uma vez, depois sd state/sd delta/sd snapshot operam nos arquivos do workspace.
  • Dirigindo um runtime vivo? sd run pra subir o daemon, depois sd use <id> e qualquer sd tick/sd step/sd effect dirige.

Instalação

pnpm add -g @statedelta/cli
# binário: sd (alias: statedelta)

Dentro deste monorepo:

pnpm --filter @statedelta/cli build
node packages/cli/dist/bin/sd.js <command>

Opções globais

Funcionam na maioria dos comandos:

| Flag | Efeito | |---|---| | --json | Saída em JSON (machine-readable) | | --help | Ajuda do comando | | --version | Versão do CLI |

Variáveis de ambiente:

| Var | Efeito | |---|---| | SD_JSON=1 | Força modo JSON globalmente | | EDITOR | Editor usado por sd state edit (default: code) |


Índice de comandos

| Categoria | Comandos | |---|---| | Workspace | init, workspace info/list, config init/get/set/list/reset/path | | Documentos | state show/create/edit, delta create/list/show/info/validate, chain, snapshot save/load/list/delete, load | | Servidor (daemon) | run, ps, use | | Remoto (cliente) | tick, step, effect, info, stop, resources, rules, handlers, context | | Definições (DSL) | def resource, def rule, def handler | | Cache | cache status, cache clear |


Referência

Workspace

sd init [name]

Cria um workspace novo numa pasta.

sd init meuprojeto
sd init meuprojeto --template tictactoe
sd init . --yes

| Opção | Default | Descrição | |---|---|---| | -t, --template <name> | blank | Um de: blank, tictactoe, battleship | | -f, --force | false | Sobrescreve pasta existente | | -y, --yes | false | Pula prompts, usa defaults |

Layout do workspace:

<name>/
├── sd.json          # config do workspace (name, version, head, state, chain)
├── state.json       # corpo do StateDoc (declaração do universo)
├── deltas/          # DeltaDocs
├── snapshots/       # dumps de snapshot
└── .sd/             # cache local

sd.json é o ponto de entrada — todo comando de workspace lê dele.

sd workspace

Inspeciona e lista workspaces.

sd workspace                   # info do workspace atual
sd workspace info              # comando explícito
sd workspace list              # lista workspaces conhecidos (~/.sd/workspaces.json)
sd workspace list --json

O registry global em ~/.sd/workspaces.json é populado por sd init e por switches manuais.

sd config

Gerencia configuração global em ~/.sd/config.json.

sd config init                       # inicializa config
sd config get editor                 # lê valor
sd config set editor vim             # grava valor
sd config set defaultEngine [email protected]
sd config list
sd config list --json
sd config reset                      # restaura defaults
sd config path                       # imprime path do config

Chaves comuns:

| Chave | Propósito | |---|---| | editor | Editor usado por sd state edit | | defaultEngine | Engine usado quando o doc não declara requires.engine | | cacheDir | Override da localização do cache |


Documentos

sd state

Gerencia o corpo do StateDoc do workspace.

sd state                       # resumo rápido do state.json
sd state show                  # metadata completa
sd state show --json
sd state create                # cria StateDoc vazio
sd state create --from template.json
sd state create --force
sd state edit                  # abre state.json no $EDITOR

Shape em disco (StateFile):

{
  "type": "state",
  "name": "meu-projeto",
  "version": "1.0.0",
  "requires": { "engine": "[email protected]" },
  "body": {
    "states":  [...],
    "actions": [...],
    "rules":   [...]
  }
}

body é opaco pro CLI — o engine adapter interpreta quando o launcher boota.

sd delta

Gerencia DeltaDocs em deltas/.

sd delta create chapter-1
sd delta create chapter-2 --extends ./deltas/chapter-1.json
sd delta create scoring -d "Adiciona regras de pontuação"
sd delta create cleanup --no-head     # não atualiza head no sd.json

sd delta list
sd delta list --json

sd delta show chapter-1               # conteúdo bruto
sd delta info chapter-1               # resumo parseado
sd delta info chapter-1 --json
sd delta validate ./deltas/foo.json

| Subcomando | Opções | |---|---| | create <name> | -e, --extends <path>, -d, --description <text>, --no-head | | list | --json | | show <name> | — | | info <name> | --json | | validate <path> | — |

sd chain [source]

Inspeciona a cadeia de extends (root → head) sem instanciar engine.

sd chain                                  # usa head do workspace
sd chain ./deltas/head.json
sd chain https://example.com/save.json
sd chain --deps                           # mostra deps[] por node
sd chain --verbose                        # paths completos + detalhes extras
sd chain --json

| Opção | Descrição | |---|---| | -d, --deps | Mostra deps[] por node | | -v, --verbose | Paths completos + metadata | | --json | Saída em JSON |

Internamente usa partial-fetch (~4 KB por node) via Chain → Gateway.

sd snapshot

Snapshots vivem em snapshots/<name>.snapshot.json dentro do workspace.

sd snapshot save  v1
sd snapshot save  v1 --force
sd snapshot load  v1
sd snapshot list
sd snapshot list  --json
sd snapshot delete v1
sd snapshot                       # default: conta os snapshots

| Subcomando | Opções | |---|---| | save <name> | -f, --force | | load <name> | — (aceita path de arquivo ou nome do workspace) | | list | --json | | delete <name> | — |

sd load [source]

Pipeline completo — chain → fetch → validação de requires → instanciação do engine → replay do estado. O runtime é fechado ao final (one-shot).

sd load                                # usa head do workspace
sd load ./deltas/save.json
sd load https://example.com/save.json
sd load --full                         # cadeia completa + marcadores ROOT/HEAD
sd load --state                        # dump dos state ids → valores
sd load --verify                       # verifica hashes de integridade
sd load --json

| Opção | Descrição | |---|---| | -f, --full | Imprime cadeia completa com nomes + marcadores ROOT/HEAD | | -s, --state | Dump de cada state id após replay | | --verify | Verifica hashes de integridade (?integrity=…) | | --json | Saída em JSON |


Servidor (daemon)

sd run [source]

Sobe o engine como processo em background ouvindo num Unix socket (ou porta TCP). Registra a instância em ~/.sd/instances/.

sd run                              # usa head do workspace
sd run ./deltas/save.json
sd run -p 7878                      # TCP no lugar de socket
sd run -f                           # foreground, com logs no terminal
sd run -v                           # output verboso

| Opção | Descrição | |---|---| | -p, --port <n> | Bind em porta TCP em vez de Unix socket | | -f, --foreground | Não destacha; streama logs no terminal atual | | -v, --verbose | Saída de progresso/log verbosa |

A instância recebe um ID auto-gerado. sd ps lista as ativas, sd use <id> seleciona a instância ativa pros próximos comandos remotos, sd stop mata.

sd ps

Lista instâncias do engine.

sd ps                # só rodando
sd ps -a             # inclui paradas/expiradas
sd ps -q             # só os IDs
sd ps --json

| Opção | Descrição | |---|---| | -a, --all | Inclui instâncias paradas | | -q, --quiet | Imprime só os IDs | | --json | Saída em JSON |

Cada entrada: id, source, pid, tick, startedAt, uptime, status.

sd use [id]

Define a instância ativa pros próximos comandos remotos.

sd use                              # mostra ativa atual
sd use 7f3a                         # define ativa
sd use --clear                      # remove ativa
sd use --json

| Opção | Descrição | |---|---| | -c, --clear | Limpa o ponteiro de instância ativa | | --json | Saída em JSON |

O ponteiro vive em ~/.sd/active.json e sobrevive entre shells.


Remoto (cliente)

Falam com uma instância rodando (iniciada via sd run). Usam a instância ativa do sd use ou aceitam -i <id>.

sd tick

Tick atual do engine.

sd tick
sd tick -i 7f3a
sd tick --json

sd step [n]

Executa um ou mais ticks.

sd step              # 1 tick
sd step 10           # 10 ticks
sd step 100 --json

sd effect <id> [payload]

Aplica um effect externo (tick one-shot).

sd effect player:move '{"dx":1,"dy":0}'
sd effect seed 12345
sd effect "ui:click" '{"x":100,"y":200}' --json

O payload é parseado como JSON quando parece JSON; caso contrário tratado como string.

sd info

Info do servidor + uptime.

sd info
sd info -i 7f3a --json

sd stop [instance]

Para um servidor rodando.

sd stop                  # para a instância ativa
sd stop 7f3a             # para uma instância específica
sd stop --all            # para tudo
sd stop --json

sd resources [id] · sd rules [id] · sd handlers [id] · sd context [key]

Inspeciona internals do engine numa instância rodando.

sd resources             # todos
sd resources hp          # um
sd rules                 # todas as rules
sd rules my-rule
sd handlers
sd context user.name

Em runtime closed (default), discovery de actions/rules retorna NOT_GOVERNED. Pra usar essas queries é preciso subir o engine em modo governed.


Definições (DSL helpers)

Helpers compactos que mutam um servidor rodando antes do tick zerar (só em tick === -1). Úteis pra experimentação ao vivo; em produção prefira declarar tudo no body do StateDoc.

sd def resource <id> <type>

sd def resource hp counter --initial 100 --min 0 --max 100
sd def resource board matrix --initial '[[null,null],[null,null]]'
sd def resource info record --spread --initial '{"name":"hero"}'
sd def resource game statemachine \
    --initial menu \
    --transitions '[["menu","playing"],["playing","won"]]'
sd def resource hp counter -i 7f3a

| Opção | Descrição | |---|---| | --initial <value> | Valor inicial (JSON) | | --min <n> / --max <n> | Bounds (counter) | | --spread | Spread mode (record) | | --transitions <json> | Transições (statemachine) | | -i, --instance <id> | Instância alvo | | --json | Saída em JSON |

sd def rule <id>

sd def rule low-hp \
  --when '{"path":"hp:value","op":"lt","value":20}' \
  --effects '[{"emit":"warn:low-hp"}]' \
  --priority 100
sd def rule on-damage --on damaged \
  --effects '[{"state":"score","op":"inc","value":5}]'
sd def rule combo --ttl 5 --change "hp" --effects '[...]'

| Opção | Descrição | |---|---| | --when <expr> | Condição (JSON) | | --on <event> | Disparador por evento | | --effects <json> | Array de effects (JSON) | | --change <paths> | Paths observados pra trigger por mudança | | --ttl <n> | Time-to-live (ticks) | | --priority <n> | Prioridade da rule | | -i, --instance <id> | Instância alvo | | --json | Saída em JSON |

sd def handler <id>

sd def handler damage \
  --params '{"type":"object","properties":{"amount":{"type":"number"}}}' \
  --execute '[{"state":"hp","op":"dec","value":{"$":"params.amount"}}]'

| Opção | Descrição | |---|---| | --execute <json> | Array de directives (JSON) | | --params <json> | JSON Schema dos params | | -i, --instance <id> | Instância alvo | | --json | Saída em JSON |


Cache

sd cache status                # stats do cache
sd cache status --json
sd cache clear                 # limpa tudo
sd cache clear --headers       # só cache de header da chain
sd cache clear --snapshots     # só cache de snapshots
sd cache clear --local         # só cache do workspace (.sd/)
sd cache clear --global        # só cache global (~/.sd/cache/)
sd cache clear -y              # pula confirmação

API REST do servidor

Quando sd run está vivo, o daemon expõe o runtime via HTTP — pelo Unix socket em ~/.sd/sockets/<id>.sock ou pela porta TCP escolhida em -p. Todas as respostas têm o envelope:

{
  "success": true,
  "data": { /* payload específico do endpoint */ }
}

ou, em caso de erro:

{
  "success": false,
  "error": { "code": "STRING_CODE", "message": "..." }
}

Inspeção do runtime

| Método | Path | Retorno | |---|---|---| | GET | / | { id, source, pid, tick, phase, mode, startedAt, uptime, uptimeFormatted } | | GET | /info | mesmo de / | | GET | /tick | { tick: number } | | GET | /phase | { phase: "created" \| "booted" \| "running" \| "finished" } | | GET | /idle | { idle: boolean } | | GET | /capabilities | Inventário de capabilities do runtime (flags + providers) | | GET | /physics | Leis imutáveis declaradas no realm |

Modo de operação

O runtime tem dois modos: live (gameplay normal, registra effects no buffer) e recovery (reaplica buffer pra reconstrução determinística; sem side effects).

| Método | Path | Body / Retorno | |---|---|---| | GET | /mode | { mode: "live" \| "recovery" } | | POST | /mode | Body { mode: "live" \| "recovery" }{ mode } |

Leitura de estado

| Método | Path | Retorno | |---|---|---| | GET | /state | { [stateId]: value } — todos os states visíveis | | GET | /state/ids | { ids: string[] } | | GET | /state/:id | { id, value } (value = objeto completo do state) | | GET | /state/:id/:field | { id, field, value } (campo específico) |

Filtros de visibilidade dependem do modo: em closed, só states exportados pelo realm aparecem; em governed, tudo.

Avanço de tick

| Método | Path | Body | Retorno | |---|---|---|---| | POST | /step | { input?, n? } | { tick, stepsExecuted, results[] } | | POST | /effect | { id, data? } | { applied, tick, result } |

input segue o shape canônico de StepInput:

{
  "effects":  [{ "id": "...", "data": {...} }],
  "provides": [...]   // só em modo "recovery"
}

n (default 1) executa N steps consecutivos com o mesmo input.

Drenagem do buffer

| Método | Path | Retorno | |---|---|---| | GET | /delta | { entries: BufferEntry[] } |

Cada entrada é discriminada (type: "effect" ou type: "provide"). Drena tudo acumulado desde a última chamada (cursor avança).

Snapshot / Recover

Erros vêm como dados (não throw) — mesmo envelope { success, ... }.

| Método | Path | Body / Retorno | |---|---|---| | GET | /snapshot | Retorna o RuntimeSnapshot completo { id, mode, capabilities?, realm, persistence? } | | POST | /recover | Body: RuntimeSnapshot{ recovered, tick } |

Códigos comuns de erro em /recover: SNAPSHOT_ID_MISMATCH, SNAPSHOT_MODE_MISMATCH, RESTORE_PHASE_INVALID.

Controle do servidor

| Método | Path | Descrição | |---|---|---| | POST | /stop | Shutdown gracioso |

Conectando de fora do CLI

Unix socket (default):

curl --unix-socket ~/.sd/sockets/<id>.sock http://localhost/info
curl --unix-socket ~/.sd/sockets/<id>.sock \
     -X POST -H 'content-type: application/json' \
     -d '{"id":"player:move","data":{"dx":1,"dy":0}}' \
     http://localhost/effect

TCP (quando subiu com sd run -p 7878):

curl http://localhost:7878/info

API programática (Node/TS)

Tudo que o binário faz é alcançável a partir de código.

Entry points

import {
  run,           // entry do CLI — parseia argv e dispatcha
  program,       // Program do commander (pra montar subcomandos custom)
} from "@statedelta/cli";

run();
// ou:
program.parse(process.argv);

Launcher service

import {
  createCliLauncher,
  resolveChainOnly,
  launchWithRuntime,
  isUrl,
  resolveSource,
  validateSource,
  createDefaultProviders,
} from "@statedelta/cli";

// Launcher pré-conectado: FileProvider + HttpProvider + Axiom adapter.
const launcher = createCliLauncher({ maxDepth: 100 });

const docs = await resolveChainOnly("./deltas/save.json");
const result = await launchWithRuntime("./deltas/save.json", {
  onProgress: (p) => console.log(`${p.phase}: ${p.percent}%`),
});
const runtime = result.engine;
console.log(runtime.getTick(), runtime.state.get("score", "value"));

LauncherServiceOptions:

interface LauncherServiceOptions {
  maxDepth?: number;
  verify?: boolean;
  onProgress?: (progress: LaunchProgress) => void;
  defaultEngine?: string;
}

Workspace / config services

import {
  WorkspaceManagerImpl as WorkspaceManager,
  ConfigManagerImpl   as ConfigManager,
  OutputFormatterImpl as OutputFormatter,
} from "@statedelta/cli";

const ws = await WorkspaceManager.detect(process.cwd());
if (ws.isInWorkspace()) {
  console.log(ws.getStatePath(), ws.getHeadPath());
}

const cfg = await ConfigManager.load();
const editor = cfg.get<string>("editor");

const out = new OutputFormatter({ isTTY: process.stdout.isTTY });
out.table(rows);
out.tree(nodes);

Tipos exportados

import type {
  SDConfig,
  SDPreferences,
  SDProviders,
  SDWorkspace,
  SDEngineConfig,
  SDChainConfig,
  CLIContext,
  ConfigManager as IConfigManager,
  WorkspaceManager as IWorkspaceManager,
  OutputFormatter as IOutputFormatter,
  TreeNode,
  CommandMeta,
  DeltaHeader,
  StateFile,            // { type, name, version, requires, body }
  SnapshotInfo,
} from "@statedelta/cli";

Exemplos

Inspecionar um save remoto

sd chain https://example.com/save.json
sd load  https://example.com/save.json --state --json

Criar e dirigir um workspace

sd init mygame --template tictactoe
cd mygame

sd state show
sd delta create chapter-1
sd load --state

# Daemon
sd run -f &
sd ps
sd use $(sd ps -q | head -1)
sd tick
sd effect player:move '{"row":0,"col":0}'
sd step 5
sd stop

Embed programático

import { createCliLauncher } from "@statedelta/cli";
import { writeFileSync } from "node:fs";

const launcher = createCliLauncher();
const result = await launcher.launchWithResult("./save.json");
const snap = result.engine.snapshot();
if (snap.ok) {
  writeFileSync("./snap.json", JSON.stringify(snap.value, null, 2));
}

Caveats

  • Endpoints Vanilla-era (/resources, /rules, /handlers, /context, /savepoint, /rollback, /commands, /command) foram removidos na migração pro IRuntime. A superfície CLI (sd resources/sd rules/sd handlers/sd context) continua existindo mas agora aponta pras queries de discovery do runtime — a maioria é governed-only e retorna NOT_GOVERNED em closed.
  • sd def * escreve num engine rodando antes do tick 0. O adapter do Axiom aceita o caminho imperativo só com mainMode: "governed". Sem isso, prefira declarar tudo no body do StateDoc.
  • Snapshots são workspace-scoped por default (vão pra snapshots/<name>.snapshot.json). Pra destinos arbitrários, use a API programática (runtime.snapshot()).

Ver também

Licença

MIT