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

@mihairo/cmt

v1.2.0

Published

Zero-dependency conventional commits CLI — interactive picker, linter, and git hook installer. One bash script, works in any repo.

Readme

cmt

Conventional Commits CLI — zero dependencies, one bash script.

npm Conventional Commits License: MIT


Install

npm (any project — no Node required at runtime)

npm install -g @mihairo/cmt

Homebrew

brew tap mihairo/tap
brew install cmt

curl (no package manager)

curl -fsSL https://raw.githubusercontent.com/mihai-ro/cmt/main/cmt \
  -o ~/.local/bin/cmt && chmod +x ~/.local/bin/cmt

Usage

cmt <command> [flags]

  init [--husky] [--lint]   create .cmt.json + install git hook(s)
  commit                     interactive commit builder
  lint [file]                lint a message file or stdin  →  exit 1 on error
  log [n]                    pretty log of last n commits  (default: 20)
  types                      list available commit types
  uninstall                  remove cmt-managed hooks and .cmt.json
  version

Set up a repo:

cd my-project
cmt init                 # picker hook only
cmt init --lint          # picker + lint git commit -m "..." commits
cmt init --husky         # husky v9 format  (.husky/prepare-commit-msg)
cmt init --husky --lint  # both hooks, husky format

Guided interactive commit:

git add .
git commit     # triggers the interactive picker automatically
# or:
cmt commit     # run directly

Lint from anywhere:

echo "feat(api): add login" | cmt lint          # exit 0
echo "bad message"          | cmt lint          # exit 1

# lint every commit on a branch (CI)
git log --format="%s" origin/main..HEAD | while IFS= read -r msg; do
  echo "$msg" | cmt lint || exit 1
done

Commit format

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

Breaking change:

feat!: drop support for Node 14
feat(api)!: redesign endpoints
BREAKING CHANGE: /auth now returns JWT

Built-in types

| Type | Emoji | SemVer impact | | ---------- | ----- | ------------- | | feat | ✨ | minor | | fix | 🐛 | patch | | docs | 📚 | — | | style | 💅 | — | | refactor | ♻️ | — | | perf | ⚡ | patch | | test | 🧪 | — | | build | 🏗️ | — | | ci | 🔧 | — | | chore | 🔩 | — | | revert | ⏪ | patch |


Configuration — .cmt.json

cmt init creates .cmt.json at your repo root with a $schema pointer. VS Code, JetBrains, and any JSON Language Server will autocomplete and validate it automatically — no extension needed.

{
  "$schema": "https://raw.githubusercontent.com/mihai-ro/cmt/main/schema/cmt.schema.json",
  "customTypes": [
    {
      "type": "wip",
      "emoji": "🚧",
      "semver": "none",
      "description": "Work in progress"
    },
    {
      "type": "security",
      "emoji": "🔒",
      "semver": "patch",
      "description": "Security fix"
    }
  ],
  "scopes": ["auth", "api", "ui", "db"],
  "rules": {
    "maxHeaderLength": 72,
    "requireScope": false,
    "allowBreakingChanges": ["feat", "fix"],
    "disallowUpperCaseDescription": false,
    "disallowTrailingPeriod": false
  }
}

Scopes — when the scopes array is non-empty, cmt commit shows an arrow-key picker with your configured scopes, a "custom" option for free-text entry, and a "skip" option. Leave scopes empty to always use free-text input.

Commit .cmt.json — your whole team shares the same types, scopes, and rules.


Hooks

prepare-commit-msg (always installed)

Intercepts plain git commit, runs the interactive picker, and writes the message — so git never opens its editor. Skips amends, merges, squashes, and any commit that already has a source message.

commit-msg (opt-in via --lint)

Lints the final commit message. Catches git commit -m "...", --amend, and commits from GUI tools:

cmt init --lint

Both hooks follow the same append/create pattern — if a hook file already exists they append a clearly-marked block rather than overwriting it. cmt uninstall removes only the cmt blocks, leaving any other content intact.


Integrations

Husky v9

cmt init --husky --lint    # writes .husky/prepare-commit-msg + .husky/commit-msg
git add .husky/            # commit them — every teammate gets them on clone

lint-staged

Add to .husky/pre-commit:

npx lint-staged

cmt handles commit message linting separately — the two hooks are completely independent.

GitHub Actions

- name: Lint commit messages
  run: |
    git log --format="%s" origin/main..HEAD | while IFS= read -r msg; do
      echo "$msg" | cmt lint || exit 1
    done

Git operations and hook behaviour

| Operation | Hook fires? | Result | | --------------------- | ---------------- | ------------------------------------ | | git commit | ✅ | picker runs | | git commit -m "..." | ✅ with --lint | linted | | git commit --amend | ✅ with --lint | linted | | git merge --no-ff | ✅ | ⏭ skipped (auto-generated message) | | git revert | ✅ | ⏭ skipped (auto-generated message) | | fixup! / squash! | ✅ | ⏭ skipped | | git pull --rebase | ✅ | ✅ passes (replays existing commits) | | Empty/aborted commit | ✅ | ⏭ skipped |


Lint rules

| Rule | Config key | Default | On fail | | ----------------------------------------- | ------------------------------ | -------- | ---------- | | Header format type(scope)?: description | — | required | ❌ error | | Valid type | — | required | ❌ error | | Non-empty description | — | required | ❌ error | | Blank line before body | — | required | ❌ error | | Scope required | requireScope | false | ❌ error | | Uppercase description | disallowUpperCaseDescription | false | ⚠️ / ❌ | | Trailing period | disallowTrailingPeriod | false | ⚠️ / ❌ | | Header length | maxHeaderLength | 72 | ⚠️ warning |

Warnings exit 0. Errors exit 1.


Why not commitlint + husky + commitizen?

| | cmt | commitlint + husky | commitizen | | -------------------------- | ------------------ | ------------------ | --------------- | | Runtime dependencies | 0 | ~15 npm packages | Python + pip | | Works in any language repo | ✅ | ❌ needs Node | ❌ needs Python | | Install | copy one file | npm install | pip install | | Interactive commit prompt | ✅ | via cz-commitlint | ✅ | | Commit-msg linting | ✅ opt-in --lint | ✅ | ✅ | | Husky v9 support | ✅ | native | via config | | JSON Schema / intellisense | ✅ | partial | ❌ | | Custom types + scopes | ✅ .cmt.json | ✅ | ✅ |


License

MIT