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

@sylvanstack/cli

v1.0.0

Published

CLI for the Sylvan stack — project upgrades (codemods / migrations) and tooling

Readme

@sylvanstack/cli

CLI for the Sylvan stack. Today it ships project upgrades (codemods / migrations); it's structured to grow more commands (init, etc.).

npx @sylvanstack/cli status                                          # version + applied + pending
npx @sylvanstack/cli upgrade                                         # interactive wizard
npx @sylvanstack/cli upgrade --pending                               # apply all pending, in order
npx @sylvanstack/cli upgrade --pending --dry-run                     # preview pending
npx @sylvanstack/cli upgrade --list                                  # list all upgrades
npx @sylvanstack/cli upgrade 20260616-migrate-to-sylvanstack --dry-run # preview one
npx @sylvanstack/cli upgrade 20260616-migrate-to-sylvanstack           # apply one (cwd)

Run with no key for an interactive wizard (pick the upgrade → choose the directory → see the compatibility check → preview/apply). Pass a key + flags for scriptable/CI use. Built on commander (commands) + @clack/prompts (interactivity).

Commands

| Command | Purpose | | --- | --- | | status [dir] | Read-only: current @sylvanstack version, origin, applied + pending upgrades. | | upgrade [key] [dir] | Run a project upgrade. --pending applies all pending in order; --dry-run previews; --force overrides the version check; --commit commits each upgrade; --allow-dirty skips the clean-tree check; --install runs the package manager install when deps change; --param name=value sets a parameter (repeatable); --yes is non-interactive; --verbose lists every changed file (default: summary only); --list lists them. |

Pending = upgrades not yet in the ledger, whose targetVersion is newer than the project's current version, and whose appliesTo matches now — computed in order, so a project that started higher ignores older ones.

Git safety

Applying refuses on a dirty working tree (so each upgrade lands as one reviewable diff) — pass --allow-dirty to override. By default the CLI does not commit; review the diff and commit yourself. --commit makes one commit per upgrade (its changed files + the manifest, isolated via a pathspec), which pairs well with --pending across several upgrades; outside a git repo it no-ops. The only git-merge surface is the manifest's append-only appliedUpgrades — resolve any conflict by keeping both entries (the CLI dedupes by key).

Dependencies (install)

When an upgrade rewrites a package.json, the lockfile is left stale on purpose — install is not run by default (it's a heavy, network-dependent side effect, and a migration's renamed deps may not be published yet). Instead the CLI prints a next-step hint. Pass --install to run the install once after applying (the package manager is auto-detected from the lockfile — pnpm/yarn/npm/bun, defaulting to pnpm); across --pending it runs a single install at the end, not per upgrade. Interactively, it only asks to install when an auth token is actually available (env var or ~/.npmrc) — otherwise it tells you to set the token first, since the install would 404. A failed install is reported, not fatal.

By default the apply output is a one-line summary per upgrade; pass --verbose to list every changed file.

Parameters

Some upgrades need values (a registry URL, a token). The CLI resolves every parameter before writing anything — so a missing or invalid value fails fast, never halfway through a codemod (across --pending, params for all queued upgrades are resolved up-front).

  • Interactive (a TTY, no --yes): you're prompted for each value, pre-filled with any --param/default.
  • Non-interactive (--yes, or piped/CI): values come from --param name=value and env; an optional param falls back to its default, a missing required one is a clear error telling you which --param (or env var) to pass.
  • Secrets (secret: true params, e.g. a token) are masked, read from their env var as a fallback, and never written to the project. The migration writes a ${NPM_TOKEN} reference into the project .npmrc and uses the resolved value only to authenticate the install in that run — prefer the env var over --param so it stays out of shell history.
  • Local credentials — a token param flagged npmAuthForRegistry triggers an interactive setup: if a token is already available (the $SYLVANSTACK_NPM_TOKEN env var or ~/.npmrc) it's used as-is; otherwise you're asked where to put it — the SYLVANSTACK_NPM_TOKEN env var (appended to your shell profile, e.g. ~/.zshrc; recommended — scoped to Sylvan projects, mirrors CI/Vercel) or ~/.npmrc (0600, machine-wide) — then for the token, and it's written accordingly. Interactive-only; non-interactive/CI read $SYLVANSTACK_NPM_TOKEN from the environment.

Compatibility check

Before running, the CLI checks the project against the upgrade's appliesTo (semver, workspace-aware scan of all package.json files):

  • appliesTo.packages[] — each entry's declared version in the project must satisfy its range;
  • appliesTo.project (optional) — the project's own version (root package.json) must satisfy its range. This is how a future major upgrade enforces the project-major ↔ sylvanstack-major lock (e.g. project: { range: "1.x" }).

Outcome:

  • in range and proceeds;
  • out of range warning, and a real apply is refused unless --force;
  • not found / unparseable warning (already migrated, or not a consumer), proceeds as a no-op.

Upgrades

Each upgrade lives in src/upgrades/<YYYYMMDD-kebab-name>/ and exports an Upgrade (key, targetVersion = version it yields, appliesTo = initial-version guard, title, description, run). The date prefix keeps them sorted chronologically; targetVersion carries the semver mapping. To add one, create the folder and register it in src/upgrades/registry.ts. Upgrades run code transforms today and can wrap Sanity schema migrations later.

20260616-migrate-to-sylvanstack — "Migrate to SylvanStack 1.0.0" (→ v1.0.0)

Renames imports @origen-studio/* → @sylvanstack/* (subpaths like …/hooks/next.js preserved) and rewrites package.json dependency keys. The 4 lockstep libs (components, sanity, tracking, forms) are pinned to ^1.0.0; the vendored babel-plugin-remove-import-js-extension is renamed too but keeps its own version (it isn't part of the lockstep group). It rewrites .npmrc — drops the old Verdaccio registry + any stored auth token, and points the @sylvanstack scope at the registry with a ${SYLVANSTACK_NPM_TOKEN} reference (never the literal). It records the migration in the project's .sylvanstack/manifest.json.

Parameters: registry (default https://registry.npmjs.org/) and npmToken (secret, also read from $SYLVANSTACK_NPM_TOKEN). The token authenticates the follow-up install in that run — use a READ-ONLY token (it can reach the client bundle). Run interactively and it offers to save the token to your ~/.npmrc for future local installs. For CI / Vercel, set SYLVANSTACK_NPM_TOKEN in the environment (the committed .npmrc references it).

npm keys auth tokens by registry host, not package scope — so on the public npmjs registry this line covers that host (you can't write a @sylvanstack-only token). The protection is the token itself: a read-only granular token scoped to @sylvanstack. The scope-specific env var name also means only projects referencing ${SYLVANSTACK_NPM_TOKEN} ever send it — unrelated projects on your machine don't.

Project state — .sylvanstack/manifest.json

Applying an upgrade records it in a committed, tool-managed .sylvanstack/manifest.json (flagged with a leading "//" note — JSON has no comments — so it reads as do-not-edit). It holds appliedUpgrades (what ran) and origin (migration when stamped by the first upgrade, or scaffold when written by the planned init, which records a baseline instead of inheriting the starter's history). status / pending-detection read it. It never holds secrets.

Each record (and the origin) carries at (ISO timestamp), by (the git identity Name <email> that ran it, best-effort — omitted if git isn't configured), and via (the tool, e.g. @sylvanstack/[email protected]) — so by is who and via is what.