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

@verndale/ai-commit

v2.6.2

Published

AI-assisted conventional commits with bundled commitlint — one install, aligned rules

Readme

@verndale/ai-commit

AI-assisted Conventional Commits with bundled commitlint so generated messages match the same rules enforced in Git hooks.


Requirements

| Requirement | Notes | | --- | --- | | Node.js | >=24.14.0 (see engines in package.json) | | Package manager | This repo uses pnpm. Enable with Corepack: corepack enable. |


Quick start

Do this from the directory that contains your app’s package.json (in a monorepo that is often not the git repository root).

  1. Add the dependency

    pnpm add -D @verndale/ai-commit

    npm and Yarn work too (npm install -D @verndale/ai-commit). Where this doc says pnpm exec, use npx, yarn exec, or your usual equivalent.

  2. Run init (merges env files, configures Husky when needed, writes hooks, updates package.json when applicable)

    pnpm exec ai-commit init
  3. Install dependencies if init changed package.json or ran Husky for the first time — init prints a line like:

    Next: run \pnpm install` …orNext: run `cd … && pnpm install` …`

    Run that command (it picks pnpm / npm / yarn / bun from the nearest lockfile).

  4. Set your API key in .env and/or .env.local (same directory as that package.json):

    OPENAI_API_KEY=sk-...

    If both files define a key, .env.local wins.


How paths work

| Term | Meaning | | --- | --- | | Package root | First directory with package.json, walking up from your current directory toward the git root. If none is found, the current working directory is used. Env files and package.json edits use this directory. | | Git root | git rev-parse --show-toplevel. Husky and hook files live here (or under core.hooksPath). |

If package root and git root differ, hook scripts cd into the package root before running ai-commit.


What ai-commit init does (default)

Environment

  • Merges ai-commit-related keys into .env.local if that file exists; otherwise into .env (creates .env from the bundled template if missing). If .env.local exists, .env is not written for this merge.
  • --force never wholesale-replaces .env.local (append / document keys only).
  • Also updates the example env file on disk: prefers .env.local.example when it exists, then .env.example, then .env-example, else creates .env.example. If .env.local.example exists alongside .env.example and/or .env-example, .env.local.example is used and a warning is printed. If both .env.example and .env-example exist (and there is no .env.local.example), .env.example is used and a warning is printed.
  • The npm package still ships the hyphenated template as .env-example.

Husky

  • If the Husky shim .husky/_/h is missing (Husky not installed for this layout), runs npx husky@9 init at the git root. That sets core.hooksPath to .husky/_ and creates the h runner inside .husky/_/.
  • Hooks directory: Git’s core.hooksPath (relative to the git root), or <git-root>/.husky when unset. Invalid or out-of-repo paths fall back to .husky at the git root with a warning.

package.json (at package root)

  • Adds commit, prepare, and devDependencies.husky when missing.

Hook files

  • Husky 9 (core.hooksPath = .husky/_): Git runs short entry scripts under .husky/_/ that only source h. Husky’s h then executes the real scripts at .husky/prepare-commit-msg and .husky/commit-msg (parent folder). Init writes both layers: stubs in _/, and pnpm exec / npx commands in .husky/ (with optional cd into the package root in a monorepo).
  • core.hooksPath = .husky: One file per hook under .husky/ that sources _/h and runs the same commands (no separate stub layer).
  • Removes Husky’s default .husky/pre-commit when it is only npm / pnpm / yarn test (so commits are not blocked by tests). Custom pre-commit files are left alone.
  • Existing hook files are left unchanged unless you run ai-commit init --force. If a previous init put ai-commit commands inside .husky/_/ by mistake, init rewrites those entries back to the short stub without --force.

Init flags

| Flag | Behavior | | --- | --- | | (none) | Full setup: env files + Husky + hooks + package.json updates when applicable. | | --env-only | Only env / example-file merges — no Git hooks or Husky. | | --husky | Husky + hooks only — skips package.json merges. Use --workspace with --husky if you also need package.json updated again. | | --force | Replaces .env (when it is the merge target) and the resolved example file with the bundled template (destructive), and can overwrite existing hook files. Does not wholesale-replace .env.local. |

When behavior differs

| Situation | What happens | | --- | --- | | Not in a git repository | Env files under the current directory are updated; init reports that Git / Husky / hooks were skipped. | | Monorepo (package not at repo root) | Run init from the package folder that has package.json and depends on @verndale/ai-commit. Hooks stay at the repo root; generated scripts cd into your package first. | | .env.local exists | Ai-commit keys are merged only into .env.local; .env is not created or updated for that merge. | | Without --force | Missing keys are appended to the env merge target and example file; existing values are not wiped. |


Command cheat sheet

pnpm add -D @verndale/ai-commit
pnpm exec ai-commit init
# Follow the printed "Next: run …" line if shown, then set OPENAI_API_KEY in .env or .env.local

Optional:

pnpm exec ai-commit init --env-only   # env only, no hooks
pnpm exec ai-commit init --husky      # hooks + Husky; skips package.json merge
pnpm exec ai-commit init --force      # overwrite env/hooks per flag rules

Environment variables

| Variable | Purpose | | --- | --- | | OPENAI_API_KEY | Required for ai-commit run and for AI-backed prepare-commit-msg when you want generation. | | COMMIT_AI_MODEL | Optional model id (default gpt-4o-mini). |

Load order: .env, then .env.local (later file wins on duplicate keys).

Comments: On merge, init may add a # @verndale/ai-commit — … line above assignments when missing; it does not remove existing comments.

Optional keys for other tools: PR_* for @verndale/ai-pr; RELEASE_NOTES_AI_* for tools/semantic-release-notes.cjs; use GH_TOKEN or GITHUB_TOKEN for GitHub API calls outside Actions.


Commit policy (v2)

  • Mandatory scope — Headers look like type(scope): Subject or type(scope)!: when breaking. Scope is derived from staged paths (lib/core/message-policy.js), with fallback from package.json (e.g. ai-commit).
  • Typesbuild, chore, ci, docs, feat, fix, perf, refactor, revert, style, test.
  • Subject — Imperative, Beams-style (first word capitalized), max 50 characters, no trailing period.
  • Body / footer — Wrap at 72 characters when present.
  • Issues — If branch or diff mentions #123, footers may add Refs #n / Closes #n (no invented numbers).
  • Breaking changes — Only when policy detects governance-related files (commitlint, Husky, this package’s rules/preset); otherwise ! and BREAKING CHANGE: are stripped.
  • Staged diff for AI — Lockfiles and common binary globs are excluded from the text sent to the model (lib/core/git.js); path detection still uses the full staged file list.

Semver: v2 tightens commitlint (mandatory scope, stricter lengths). If you extend this preset, review lib/rules.js and adjust overrides as needed.


CLI reference

| Command | Purpose | | --- | --- | | ai-commit run | Build a message from the staged diff and run git commit. | | ai-commit init | Merge env files; configure Husky and hooks; update package.json when applicable. See Init flags. | | ai-commit prepare-commit-msg <file> [source] | Hook: fill an empty message; skips merge / squash. | | ai-commit lint --edit <file> | Hook: run commitlint with this package’s default config. |


package.json script (example)

{
  "scripts": {
    "commit": "ai-commit run"
  }
}

Husky (manual setup)

pnpm exec ai-commit init sets up Husky for you. With Husky 9, Git only executes files under core.hooksPath (usually .husky/_/). Each of those must be a short stub that sources h; Husky then runs the matching script one level up, e.g. .husky/prepare-commit-msg, where your pnpm exec ai-commit … (or npx) commands live.

.husky/_/prepare-commit-msg (entry — stub only)

#!/usr/bin/env sh
. "$(dirname -- "$0")/h"

.husky/prepare-commit-msg (commands Husky runs)

#!/usr/bin/env sh
pnpm exec ai-commit prepare-commit-msg "$1" "$2"

.husky/_/commit-msg and .husky/commit-msg follow the same pattern (stub vs pnpm exec ai-commit lint --edit "$1").

If core.hooksPath is .husky (not .husky/_), use a single file per hook: source . "$(dirname -- "$0")/_/h", then the same pnpm exec ai-commit … lines init would generate.

Generated hooks use pnpm exec ai-commit when pnpm-lock.yaml exists at the package root; otherwise npx --no ai-commit. In a monorepo, the .husky/ scripts cd into the package directory first. Edit the scripts if you use another runner.

Default pre-commit: Husky’s init also writes .husky/pre-commit with pnpm test (or npm test / yarn test). That file is not always the one Git runs when core.hooksPath is .husky/_, but ai-commit init still removes that stock .husky/pre-commit when it matches the known template so it does not surprise you later. If you add other lines (e.g. lint-staged), the file is left unchanged.

Already using Husky? If .husky/_/h exists, npx husky@9 init is not run again. package.json is only amended for missing commit, prepare, or devDependencies.husky. Existing prepare-commit-msg and commit-msg hooks are not overwritten unless you use ai-commit init --force.


commitlint without a second install

Use ai-commit lint --edit from hooks (see above).

To extend the preset in your own commitlint.config.js:

module.exports = {
  extends: ["@verndale/ai-commit"],
  rules: {
    // optional overrides
  },
};

Shared constants (types, line limits):

const rules = require("@verndale/ai-commit/rules");

GitHub Actions (CI snippet)

Use commitlint in your workflow — nothing calls back to this repository’s pipelines. After pnpm add -D @verndale/ai-commit, add a root commitlint.config.cjs (or .js) that extends: ["@verndale/ai-commit"] as above. @commitlint/cli is a dependency of this package, so pnpm exec commitlint works after install.

Save as .github/workflows/commitlint.yml (or merge the job into an existing workflow). Adjust branches / branches-ignore if your default branch is not main.

name: Commit message lint

on:
  pull_request:
    branches: [main]
    types: [opened, synchronize, reopened, edited]
  push:
    branches-ignore:
      - main

jobs:
  commitlint:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: "24.14.0"

      - name: Enable pnpm via Corepack
        run: corepack enable && corepack prepare [email protected] --activate

      - name: Get pnpm store path
        id: pnpm-cache
        run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT

      - name: Cache pnpm store
        uses: actions/cache@v4
        with:
          path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: |
            ${{ runner.os }}-pnpm-store-

      - name: Install dependencies
        run: pnpm install --frozen-lockfile

      - name: Lint PR title (squash merge becomes the commit on main)
        if: github.event_name == 'pull_request'
        env:
          PR_TITLE: ${{ github.event.pull_request.title }}
        run: |
          printf '%s\n' "$PR_TITLE" | pnpm exec commitlint --verbose

      - name: Lint commit messages (PR range)
        if: github.event_name == 'pull_request'
        run: |
          pnpm exec commitlint \
            --from "${{ github.event.pull_request.base.sha }}" \
            --to "${{ github.event.pull_request.head.sha }}" \
            --verbose

      - name: Lint last commit (push)
        if: github.event_name == 'push'
        run: |
          pnpm exec commitlint --from=HEAD~1 --to=HEAD --verbose

Workflow notes

| Topic | Detail | | --- | --- | | Node | Use a version that satisfies engines.node (see Requirements). | | npm or Yarn | Replace Corepack + pnpm with your install (npm ci, yarn install --immutable, etc.) and use npx --no commitlint or yarn exec commitlint. | | Config path | If commitlint cannot find your config, add --config path/to/commitlint.config.cjs to each invocation. | | Same rules as hooks | Matches .husky/commit-msg when it runs ai-commit lint --edit — both use the @verndale/ai-commit preset. |


Contributing

Local development, workflows in this repo, and publishing are documented in CONTRIBUTING.md.


License

MIT — see LICENSE.