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

@bensandee/tooling

v0.27.1

Published

CLI tool to bootstrap and maintain standardized TypeScript project tooling

Downloads

3,335

Readme

@bensandee/tooling

CLI to bootstrap and maintain standardized TypeScript project tooling.

Installation

pnpm add -D @bensandee/tooling

# Or run directly
pnpm dlx @bensandee/tooling repo:sync

Conventions

The tool auto-detects project structure, CI platform, project type, and Docker packages from the filesystem. .tooling.json stores overrides only — omitted fields use detected defaults. Runtime commands (docker:build, checks:run, release:changesets) work without running repo:sync first.

| Convention | Detection | Default | Override via | | ----------------- | ----------------------------------------------------- | ---------------------------------------- | ------------------------------------ | | Project structure | pnpm-workspace.yaml present | single | structure in .tooling.json | | CI platform | .github/workflows/ or .forgejo/workflows/ dir | none | ci in .tooling.json | | Project type | Dependencies in package.json (react, node, library) | default | projectType in .tooling.json | | Docker packages | Dockerfile or docker/Dockerfile in package dirs | — | docker map in .tooling.json | | Formatter | Existing prettier config detected | oxfmt | formatter in .tooling.json | | Release strategy | Existing release config detected | monorepo: changesets, single: simple | releaseStrategy in .tooling.json |

CLI commands

Project management

| Command | Description | | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | tooling repo:sync [dir] | Detect, generate, and sync project tooling (idempotent). First run prompts for release strategy, CI platform (if not detected), and formatter (if Prettier found). Subsequent runs are non-interactive. | | tooling repo:sync --check [dir] | Dry-run drift detection. Exits 1 if files would change. CI-friendly. | | tooling checks:run | Run project checks (build, docker:build, typecheck, lint, test, format, knip, tooling:check, docker:check). Flags: --skip, --add, --fail-fast. |

Flags: --yes (accept all defaults), --no-ci, --no-prompt, --eslint-plugin

checks:run

Runs checks in order: build, docker:build, typecheck, lint, test, format (--check), knip, tooling:check, docker:check. Checks without a matching script in package.json are silently skipped.

The --skip flag supports glob patterns via picomatch:

# Skip all docker steps
tooling checks:run --skip 'docker:*'

# Skip specific checks
tooling checks:run --skip build,knip

The --add flag appends extra checks (must be defined in package.json):

tooling checks:run --add e2e

The generated ci:check script defaults to pnpm check --skip 'docker:*' since CI environments typically lack Docker support.

Release management

| Command | Description | | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | tooling release:changesets | Changesets version/publish for Forgejo CI. Flag: --dry-run. Env: FORGEJO_SERVER_URL, FORGEJO_REPOSITORY, FORGEJO_TOKEN. | | tooling release:simple | Streamlined release using commit-and-tag-version. | | tooling release:trigger | Trigger a release workflow. | | tooling forgejo:create-release | Create a Forgejo release from a tag. | | tooling changesets:merge | Merge a changesets version PR. |

Docker

| Command | Description | | ------------------------ | --------------------------------------------------- | | tooling docker:build | Build Docker images for discovered Docker packages. | | tooling docker:publish | Build, tag, and push Docker images to a registry. |

Docker packages are discovered automatically. Any package with a Dockerfile or docker/Dockerfile is a Docker package. Image names are derived as {root-package-name}-{package-name}, build context defaults to . (project root). For single-package repos, Dockerfile or docker/Dockerfile at the project root is checked.

When Docker packages are present, repo:sync generates a deploy workflow (.forgejo/workflows/publish.yml or .github/workflows/publish.yml) triggered on version tags (v*.*.*) that runs pnpm exec tooling docker:publish.

Overrides

To override defaults, add a docker entry to .tooling.json:

{
  "docker": {
    "server": {
      "dockerfile": "packages/server/docker/Dockerfile",
      "context": "."
    }
  }
}

The context field defaults to "." (project root) when omitted. Versions for tagging are read from each package's own package.json.

docker:build

Builds all discovered packages, or a single package with --package:

# Build all packages with docker config
tooling docker:build

# Build a single package (useful as an image:build script)
tooling docker:build --package packages/server

# Pass extra args to docker build
tooling docker:build -- --no-cache --build-arg FOO=bar

To give individual packages a standalone image:build script for local testing:

{
  "scripts": {
    "image:build": "pnpm exec tooling docker:build --package ."
  }
}

Flags: --package <dir> (build a single package)

docker:publish

Runs docker:build for all packages, then logs in to the registry, tags each image with semver variants from its own version field, pushes all tags, and logs out.

Tags generated per package: latest, vX.Y.Z, vX.Y, vX

Each package is tagged independently using its own version, so packages in a monorepo can have different release cadences. Packages without a version field are rejected at publish time.

Flags: --dry-run (build and tag only, skip login/push/logout)

Required environment variables:

| Variable | Description | | --------------------------- | --------------------------------------------------------------------- | | DOCKER_REGISTRY_HOST | Registry hostname (e.g. code.orangebikelabs.com) | | DOCKER_REGISTRY_NAMESPACE | Full namespace for tagging (e.g. code.orangebikelabs.com/bensandee) | | DOCKER_USERNAME | Registry username | | DOCKER_PASSWORD | Registry password |

Config file

.tooling.json stores overrides only — fields where the project differs from what convention/detection produces. A fully conventional project has {} or no .tooling.json at all.

Available override fields:

| Field | Type | Default (detected) | | -------------------- | ------- | -------------------------------------------------------------------------------- | | structure | string | "monorepo" if pnpm-workspace.yaml present, else "single" | | useEslintPlugin | boolean | true | | formatter | string | "prettier" if config found, else "oxfmt" | | setupVitest | boolean | true | | ci | string | Detected from workflow dirs, else "none" | | setupRenovate | boolean | true | | releaseStrategy | string | Detected from existing config, else monorepo: "changesets", single: "simple" | | projectType | string | Auto-detected from package.json deps | | detectPackageTypes | boolean | true |

Library API

The "." export provides type-only exports for programmatic use:

import type {
  ProjectConfig,
  GeneratorResult,
  GeneratorContext,
  Generator,
  DetectedProjectState,
  LegacyConfig,
} from "@bensandee/tooling";

| Type | Description | | ---------------------- | ----------------------------------------------------------------------------------------------- | | ProjectConfig | User config shape (persisted in .tooling.json) | | GeneratorContext | Context passed to generator functions (exists, read, write, remove, confirmOverwrite) | | GeneratorResult | Result from a generator (created/updated/skipped files) | | Generator | Generator function signature: (ctx: GeneratorContext) => Promise<GeneratorResult> | | DetectedProjectState | Detected existing project state (package manager, CI, etc.) | | LegacyConfig | Legacy config detection for migration |

Docker check

The @bensandee/tooling/docker-check export provides utilities for checking Docker Compose stacks via health checks.

Quick start

import { createRealExecutor, runDockerCheck } from "@bensandee/tooling/docker-check";
import type { CheckConfig } from "@bensandee/tooling/docker-check";

const config: CheckConfig = {
  compose: {
    cwd: "./deploy",
    composeFiles: ["docker-compose.yaml"],
    services: ["api", "db"],
  },
  buildCommand: "pnpm image:build",
  healthChecks: [
    {
      name: "API",
      url: "http://localhost:3000/health",
      validate: async (res) => res.ok,
    },
  ],
  timeoutMs: 120_000,
  pollIntervalMs: 5_000,
};

const result = await runDockerCheck(createRealExecutor(), config);
if (!result.success) {
  console.error(result.reason, result.message);
}

Exports

| Export | Description | | -------------------------------------- | ----------------------------------------------------------------- | | runDockerCheck(executor, config) | Full lifecycle: build, compose up, health check polling, teardown | | createRealExecutor() | Production executor (real shell, fetch, timers) | | composeUp(executor, config) | Start compose services | | composeDown(executor, config) | Stop and remove compose services | | composeLogs(executor, config) | Stream compose logs | | composePs(executor, config) | List running containers | | checkHttpHealth(executor, check) | Run a single HTTP health check | | getContainerHealth(executor, config) | Check container-level health status |

Types

| Type | Description | | --------------------- | ------------------------------------------------------------------------------------------ | | CheckConfig | Full check config (compose settings, build command, health checks, timeouts) | | ComposeConfig | Docker Compose settings (cwd, compose files, env file, services) | | HttpHealthCheck | Health check definition (name, URL, validate function) | | CheckResult | Result: { success: true, elapsedMs } or { success: false, reason, message, elapsedMs } | | DockerCheckExecutor | Side-effect abstraction (exec, fetch, timers) for testability | | ContainerInfo | Container status info from composePs |