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

@frmlabz/release

v0.2.0

Published

Fragment-based release versioning for frmlabz repositories: fragments, cuts, admission checks and release PRs.

Readme


description: The frm-release CLI (@frmlabz/release) — fragment-based release versioning shared by frmlabz repos; install, commands, config schema, CI wiring, version policy, and adoption. updated_at: 2026-10-05

@frmlabz/release

One implementation of the fragment-based release model (release-versioning.md) for every frmlabz repo on the dev -> staging -> main ladder. It allocates versions, renders changelogs from fragments, validates that admission and promotions are correct, and opens release PRs. Deploying (images, digests, manifests, Flux, signing, SDK publishing) stays in each repo.

Zero runtime dependencies; Node 24+, git, and gh for pr. cut runs pnpm ls to list affected workspaces.

Install

pnpm add -D -E @frmlabz/release

Pin it exactly. Exempt it from the release-age gate, because the tool and the repos move together:

# pnpm-workspace.yaml
minimumReleaseAgeExclude:
  - "@frmlabz/release"

Add a matching Renovate packageRules entry with minimumReleaseAge: null for @frmlabz/release. A bump is a reviewed PR like any other.

Commands

| Command | What it does | | --- | --- | | frm-release fragment <slug> [--category c] [--components a,b] [--breaking] [--body text] | Creates release/unreleased/YYYYMMDD-HHMM-<slug>.md. Without --body the fragment stays invalid until its outcome is written. | | frm-release cut <major\|minor\|patch> | On dev or hotfix/*: fetches origin, allocates the next version above everything on the ladder, renders release/changelogs/vX.Y.Z.md, updates release/version.txt, consumes the fragments, validates and commits. Never pushes. | | frm-release validate [--mode m] [--base ref] [--head ref] [--source ref] [--staged] [--fetch] [--allow-cut] | Runs one validation (see below). --staged validates the index, for pre-commit; --fetch first fetches the configured branches. | | frm-release pr <staging\|prod> [--draft] [--dry-run] [-- <gh flags>] | Opens release(staging): vX (dev → staging) or release(prod): vX (staging → main). The body is the changelogs the base lacks. Extra gh flags are presentation only (--reviewer, --label); routing flags are refused. |

Typical justfile:

fragment SLUG *FLAGS:
    pnpm exec frm-release fragment {{SLUG}} {{FLAGS}}

release KIND:
    pnpm exec frm-release cut {{KIND}}

release-pr ENV *FLAGS:
    pnpm exec frm-release pr {{ENV}} {{FLAGS}}

Validation modes

| Mode | Use | Checks | | --- | --- | --- | | auto (default) | hooks, PR CI | In a PR (GITHUB_BASE_REF), enforces the ladder (staging ← dev; main ← staging or hotfix/*) and picks cut, promote, hotfix or feature. Locally: feature, or hotfix on a hotfix/* branch with a new version. A branch other than dev is judged from its single latest base shared with origin/dev and local dev (from origin/dev alone when that base is ambiguous), so a cut on local dev that is not pushed yet is inherited, not owned. | | feature | feature branches, dev | Release-relevant changes carry a new or edited fragment; version.txt and changelogs are untouched (except cuts on dev/hotfix); migration rules. | | cut | PR into staging, push to staging | No fragments left; cut changelogs immutable; new version above the floor; changelog re-renders byte-for-byte from its cut parent; main's latest cut merged; nothing release-relevant after the cut; migration rules. | | hotfix | PR from hotfix/* into main | cut against main, plus: no new migration while staging holds migrations main lacks. | | promote | PR staging → main | Same version as staging and above main's; every cut on main kept; no fragments; changelog and promoteFiles identical to staging; no new changelogs; no other tree difference except promoteIgnorePaths. | | main-push | push to main | The pushed commit must be a merge whose first parent is --base (the previous main head). Second parent on origin/staging → promote; otherwise hotfix against --base. Squash, rebase and direct pushes are refused. Skip bot deploy commits in the workflow. | | migrations | ad hoc | Migration rules only. |

Migration rules: files on the baseline (staging, or main for hotfixes) are frozen; new files are <migrationsDir>/YYYYMMDDHHMMSS_name.sql, flat, carry no release version, and sort above the baseline's highest timestamp. Historical files in version folders stay valid.

Configuration: release/config.json

{
  "releasePaths": ["apps/**", "packages/**", "db/migrations/**", "package.json", "pnpm-lock.yaml"],
  "ignorePaths": ["**/*.md", "**/test/**", "**/*.test.*"],
  "components": ["api", "web", "database", "deployment", "tooling", "deps"],
  "migrationsDir": "db/migrations",
  "branches": ["dev", "staging", "main"],
  "timezone": "Europe/Belgrade",
  "promoteFiles": ["deployment/releases/{version}.yaml"],
  "promoteIgnorePaths": ["deployment/manifests/prod/**", "deployment/releases/prod-current.txt"]
}

Validation reads the config committed with the tree it judges (the index for --staged), so a local edit cannot loosen a check.

| Key | Required | Meaning | | --- | --- | --- | | releasePaths, ignorePaths | yes | Globs (path.matchesGlob) deciding which changes need a fragment. | | components | yes | Allowed fragment components. Removing one later does not invalidate older cuts. | | migrationsDir | yes | Migration root for the ordering rules. | | branches | no | ["dev","staging","main"] (default) or ["dev","staging"] for a project without production: hotfixes, promotions and pr prod are refused. | | timezone | no | Time zone for fragment stamps and cut dates. Default Europe/Belgrade. | | promoteFiles | no | Files staging must have deployed before promotion, identical on main. {version} is substituted. Default shown. | | promoteIgnorePaths | for promote | Main-only deploy state the promotion may differ in; list exactly what the prod deploy workflow commits. Everything else must equal staging. |

CI wiring

Hooks (husky or core.hooksPath):

# pre-commit
pnpm exec frm-release validate --staged
# pre-push: fetch first so the floor and merge bases are current
pnpm exec frm-release validate --fetch

Workflows that do not install dependencies can run the pinned version directly:

- name: Validate release
  env:
    npm_config_min_release_age: "0"
  run: npx --yes "@frmlabz/release@$(node -p 'require("./package.json").devDependencies["@frmlabz/release"]')" validate --fetch
  • PR into any branch: validate --fetch (auto). Check out with fetch-depth: 0.
  • Push to staging (skip the bot's [skip deploy] commits): validate --mode cut --base "${{ github.event.before }}" --head "$GITHUB_SHA".
  • Push to main (skip bot commits): validate --mode main-push --base "${{ github.event.before }}"; branch the deploy on the printed mode or reuse the same HEAD^2-on-staging test.

Renovate PRs get one generated deps fragment from the reusable workflow in this repository; its PAT push re-runs the PR checks:

on:
  pull_request:
    branches: [dev]
    types: [opened, reopened, synchronize]
permissions:
  contents: read
jobs:
  fragment:
    uses: frmlabz/tools/.github/workflows/renovate-fragment.yml@<sha> # main
    with:
      runner: '"self-hosted"'
    secrets:
      bot-token: ${{ secrets.DEPLOY_BOT_PAT }}

Add "gitIgnoredAuthors": ["41898282+github-actions[bot]@users.noreply.github.com"] to renovate.json so Renovate keeps rebasing the PR, and do not use branch automerge: it lands updates without a PR, so no fragment.

To skip CI on Renovate PRs, give each pull-request job if: ${{ !(github.base_ref == 'dev' && startsWith(github.head_ref, 'renovate/')) }}. Keep the skip scoped to dev: a skipped job satisfies a required status check, so an unscoped skip lets a renovate/* branch through the staging and main rulesets. Nothing else then validates the PR, so merge it only after its fragment / fragment check passes.

Version policy

Different branches can pin different tool versions, and every validation re-renders the cuts in its range, so the output format is a compatibility contract:

  • Only cuts added in the validated range are re-rendered; older changelogs are compared by blob and never re-rendered.
  • Fragments are parsed with the config committed at the cut parent.
  • Patch: fixes that never reject a history an earlier version accepted. Minor: new modes, optional config keys, new checks on new commits only. Major: any change to rendered output or the fragment grammar, or a check that rejects existing valid history. A rendering change must add a format marker to new changelogs and keep rendering unmarked ones as format 1.

Adoption

  1. Add release/config.json, the devDependency, the release-age exclusions, hooks and justfile recipes.
  2. release/version.txt must exist on dev (seed v0.0.0 for a new project). Every branch's version.txt counts toward the floor, so the first cut continues the existing numbering.
  3. Move migrations that are not yet on staging out of version folders: git mv <dir>/vX.Y.Z/<ts>_name.sql <dir>/<ts>_name.sql. Point migration creation at the flat directory.
  4. The config (with promoteIgnorePaths) must reach staging and main through the normal train before the first promotion is validated, because validation reads it from the judged tree.
  5. Replace bespoke release scripts (intent validation, migration order, release PR, PR source branch) with the commands above, wire the workflows, then frm-release fragment + frm-release cut minor for the first release.

Development

npm test   # node:test against temporary git repos; no network

Publishing runs from .github/workflows/release-package.yml when package.json carries a version not yet on npm.