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

repo-version-manager

v1.1.1

Published

Interactive CLI to manage the global version of a repo or monorepo and the individual version of each of its services, with git integration (branches, tags, rebase)

Downloads

127

Readme

Repo Version Manager (rpvm)

CI npm version npm downloads install size license

Interactive CLI to version a repository — or every service inside a monorepo — from your terminal, with git integration (branches, tags, rebase). You stay in control: rpvm never pushes.

rpvm release demo

Why rpvm?

Tools like semantic-release or changesets automate versioning from commit conventions and CI pipelines. rpvm takes the opposite approach: a short interactive session where you decide every bump, review a summary of exactly what will happen, and nothing leaves your machine until you push it yourself.

  • 🎛️ Interactive and explicit — pick every bump from a prompt; no commit-message conventions to learn.
  • 🧩 Monorepo-aware — one global version for the repo, plus an individual version per service.
  • 🚦 Guard rails — a service never bumps above the global bump, and from the main branch only patch (hotfix) releases are allowed.
  • 🔄 Git taken care of — syncs with origin (fetch + rebase), then creates the release commit and the annotated tag for you.
  • 🙅 Never pushes — commits and tags stay local; the CLI prints the exact push command for you to run.
  • 🧪 Dry runrpvm release --dry-run walks the whole flow without touching a single file.

Quick start

npm install -g repo-version-manager

cd your-repo
rpvm init      # one-time setup: mode, services, versions and branches
rpvm release   # every time you want to cut a new version

Requires Node.js ≥ 18.19. The package installs a single binary: rpvm.

Commands

rpvm init — set up the repository (once)

Run it from the repository root. It asks you, with sensible defaults auto-detected from your project:

  • Whether the repo is a monorepo with services (detected from your folder structure).
  • In monorepo mode, which first-level folders are services (folders with a package.json come preselected) and each service's initial version.
  • The global version (defaults to the root package.json version when available).
  • For services that are Expo/React Native apps with committed ios//android/ folders (or the repo root itself, in single-repo mode), whether rpvm should also manage their native versions on every release (see Expo / React Native apps).
  • The main branch (main/master) and the development branch (develop/development).

It then writes the config and version files (see Generated files), updates the package.json versions, commits everything (🔖 RPVM init vX.Y.Z) and, optionally, creates the initial vX.Y.Z tag.

rpvm release — cut a new version

The everyday command — the one recorded in the demo above. It checks that the working tree is clean and that you are on the main or the development branch, rebases onto origin, and then walks you through the bumps: first the global one, then (in monorepo mode) one per service. It ends with a summary like this, and nothing is written until you confirm it:

◇  Release v1.3.0 summary ────╮
│                             │
│  global  1.2.3 → 1.3.0      │
│  api     0.9.1 → 0.10.0     │
│  web     2.1.0 (unchanged)  │
│                             │
├─────────────────────────────╯

On confirmation it writes the version files — including the native files of managed Expo apps — creates the release commit and the annotated tag, and prints the exact push command for when you're ready. Add --dry-run to walk the whole flow and see the list of actions without modifying anything.

rpvm status — where am I?

Shows the global version (and each service's version in monorepo mode) and warns when a package.json is out of sync with its .version file:

┌   rpvm status
│
◇  Versions ───────────────────────────────╮
│                                          │
│  global  v1.2.3  ✔ package.json in sync  │
│                                          │
├──────────────────────────────────────────╯
│
└  main: main · develop: develop · current: develop

For managed Expo apps it also shows one line per native target (android, ios, app.json) with its version, build number and sync state.

How a release works

flowchart TD
    start(["rpvm release"]) --> checks{"Working tree clean?<br/>On main or develop?"}
    checks -- no --> abort(["Abort — nothing modified"])
    checks -- yes --> sync["Sync with origin (fetch + rebase)<br/>develop: onto origin/develop, then origin/main<br/>main: onto origin/main"]
    sync --> bump["Choose the global bump<br/>(from main: patch only)"]
    bump --> services["Monorepo: choose each service's bump<br/>(never above the global one)"]
    services --> summary{"Summary — confirm?"}
    summary -- no --> abort
    summary -- yes --> write["Write .version, package.json<br/>and native (Expo) version files"]
    write --> tag["Commit 🔖 RPVM release vX.Y.Z<br/>+ annotated tag vX.Y.Z"]
    tag --> push(["You push when ready —<br/>rpvm prints the exact command"])

The rules behind the flow:

  • A service bump never exceeds the global one (patch < minor < major); a service may also stay unchanged.
  • From the main branch only patch releases are generated — features ship through the development branch; main is for hotfixes.
  • Git tags (vX.Y.Z) track the global version.
  • On the development branch the suggested push uses --force-with-lease (the branch was just rebased); on main it never suggests forcing.

Expo / React Native apps

For Expo apps whose native folders are committed (ejected / expo prebuild), bumping the version means touching several native files. When native management is enabled for a service during rpvm init, every release that bumps that service also updates:

| Platform | File | Fields | |---|---|---| | Android | android/app/build.gradle | versionName, versionCode | | iOS | ios/<App>.xcodeproj/project.pbxproj | MARKETING_VERSION, CURRENT_PROJECT_VERSION (all build configurations) | | iOS | ios/<App>/Info.plist | CFBundleShortVersionString, CFBundleVersion — only when the values are literals; entries using $(MARKETING_VERSION)-style variables are left to the pbxproj | | Expo | app.json | expo.version, plus expo.ios.buildNumber / expo.android.versionCode when the project already declares them |

How it works:

  • The semver version written to the native files is the service version (or the global version in single-repo mode).
  • Build numbers (versionCode, CFBundleVersion/CURRENT_PROJECT_VERSION) are not semver: rpvm uses a single shared build number per app and auto-increments it on every release — one past the highest build number found on any platform, so store uploads stay monotonic.
  • All edits are surgical text replacements: the rest of the file (formatting, comments, other settings) is untouched.
  • If a value cannot be updated safely (versionCode computed from a Gradle variable, config in app.config.js/ts instead of app.json), rpvm warns and asks you to update it manually instead of guessing.
  • --dry-run lists the exact native files that would be written.

The selection is stored in .rpvmrc.json under the expo key ("." refers to the repository root):

{
  "monorepo": true,
  "services": ["api", "mobile"],
  "expo": {
    "mobile": { "ios": true, "android": true, "syncAppJson": true }
  }
}

Generated files

| File | Where | Content | |---|---|---| | .rpvmrc.json | root | mode (monorepo or not), branches, service list and Expo native targets | | .version | root | global repository version | | .version | each service (monorepo mode) | service version — the source of truth, package.json follows it |

FAQ

The rebase hit conflicts. Is my repo in a weird state? No. rpvm aborts the rebase and exits without modifying anything. Resolve the conflicts manually (git rebase origin/<branch>) and run rpvm release again.

rpvm status warns that a package.json is out of sync. .version is the source of truth. Someone edited a package.json version by hand — set it back to the .version value (the next release will rewrite it anyway).

Can I use it without a remote? Without git at all? Yes. With no origin remote, the sync step is skipped (you'll see a warning). With no git repository, rpvm only manages the version files — no commits, no tags.

I cut a release locally and regret it. How do I undo it? As long as you haven't pushed: git tag -d vX.Y.Z && git reset --hard HEAD~1. That's the point of never pushing automatically.

Why only patch from main? Main represents what's in production. New features go through the development branch and reach main via a regular release; anything released directly from main is by definition a hotfix.

Development

git clone https://github.com/Gcuencam/repo-version-manager.git
cd repo-version-manager
npm install
npm run dev        # tsup in watch mode
npm run typecheck
npm test
npm run build
npm link           # try `rpvm` locally

To regenerate the README demo GIF (requires vhs):

bash demo/setup.sh && vhs demo/demo.tape

Found a bug or have an idea? Open an issue.

License

MIT