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

@niah/igrep

v0.2.5

Published

Fast indexed regex search CLI

Readme

igrep

igrep is a fast, persistent, indexed regex search CLI. It stores no files in the searched project: indexes live under the operating system cache directory ($XDG_CACHE_HOME/niah/igrep on Linux and compatible systems), keyed by the canonical root path.

CLI

igrep index --root PATH [--force]
igrep status --root PATH
igrep search --root PATH --pattern PATTERN --json \
  [--fixed-strings] [--ignore-case] \
  [--include GLOB]... [--exclude GLOB]... [--max-results N]
igrep bench --root PATH [--pattern LITERAL]...

Search emits JSON Lines. Match records contain an absolute path, a 1-based line_number, and line. The final record is always a summary:

{"type":"summary","indexed":true,"candidate_files":12,"total_files":500,"elapsed_ms":4}

Exit status is 0 when at least one line matches, 1 when none match, and 2 for usage, regex, filesystem, or index errors. An absent index is built automatically. --include patterns are ORed; excludes take precedence. indexed reports whether sparse-term pruning was possible; fallback summaries also include fallback_reason. Summaries may include query_terms, while index and status report the term count, postings bytes, index format, and algorithm.

The index respects Git ignores, global Git ignores, .ignore, and hidden-file conventions. UTF-8 text files up to 16 MiB are indexed; NUL-containing and non-UTF-8 files are skipped. A changed Git HEAD rebuilds the index. Dirty and untracked Git files are indexed into a transient in-memory sparse overlay on every search (deleted paths are removed from baseline candidates). Non-Git roots compare indexed file metadata before searching.

How candidate pruning works

The index uses frequency-weighted sparse n-grams rather than exhaustive fixed trigrams. At index time, the linear-time BuildAllNgrams monotonic-stack algorithm emits at most roughly twice as many terms as input bytes. At query time, BuildCoveringNgrams emits a minimal covering subset with a maximum term length of 16 bytes. Index-time terms longer than that cap are discarded because no query can request them. Every query term is guaranteed to occur in the retained index terms of every document containing that query literal.

Rare byte pairs receive high priority and common pairs low priority, producing longer, more selective terms around rare source-code sequences. Equal buckets use a deterministic hash tie-break. ASCII is lowercased before both indexing and extraction. For Unicode ignore-case searches, files containing non-ASCII bytes are conservatively added back to the candidate set.

The on-disk layout matches Cursor's described design: a sorted hash→offset lookup table (terms.bin) and a contiguous postings file (postings.bin). Only the lookup table is memory-mapped; posting lists are read at the resolved offsets. Storing 64-bit content hashes instead of raw n-gram bytes keeps the table dense and is safe because collisions only widen candidates. Terms that occur in a single file store that file id directly in the lookup value, so singleton postings never touch postings.bin. Regex HIR is analyzed conservatively: mandatory concatenated literals are intersected and fully constrained alternation branches are unioned. Short literals, classes without a mandatory literal, optional-only expressions, and alternations containing an unconstrained branch fall back to direct scanning. Pruning admits false positives but not false negatives; Rust's regex engine performs final verification.

For Git repositories, the persisted index is tied to the current HEAD. Modified and untracked files form a dirty overlay that is removed from baseline candidates and re-indexed in memory with the same sparse n-gram algorithm; only overlay candidates that survive pruning are verified. Deleted paths are omitted.

npm

npm install @niah/igrep

The package installs the release binary and verifies it against SHA256SUMS. It exports:

import { binPathFor, igrepPath, resolveIgrepPath } from "@niah/igrep";

binPathFor({ os: "linux", arch: "x64" }); // .../bin/linux-x64/igrep
console.log(igrepPath); // current platform binary path

Binaries live under bin/<platform>-<arch>/igrep (same layout as @vscode/ripgrep-universal). Set IGREP_BINARY_PATH to force a local binary, or IGREP_SKIP_DOWNLOAD=1 to skip postinstall downloads. The package also exposes an igrep executable that forwards all arguments and exit status to the native CLI.

Releasing

Publishing is tag-driven via GitHub Actions, authenticated with the NPM_TOKEN repository secret.

  1. Bump version in both package.json and Cargo.toml (keep them equal), and run a build so Cargo.lock picks up the new version — the release job builds with --locked and fails on a stale lockfile.
  2. Commit and push to main.
  3. Tag and push: git tag -a vX.Y.Z -m "vX.Y.Z" && git push origin vX.Y.Z
  4. .github/workflows/release.yml builds all platform binaries, creates the GitHub release, then publishes @niah/igrep from the npm-publish environment.

Moving to npm Trusted Publishing (OIDC) means configuring a Trusted Publisher on npmjs.com listing workflow release.yml, repository ineedthis/igrep, and environment npm-publish, then dropping both registry-url from the setup-node step and NODE_AUTH_TOKEN from the publish step. Without the publisher registered, npm never starts the token exchange and the publish fails with ENEEDAUTH.

Development

Rust 1.91.1 is the supported toolchain.

ASDF_RUST_VERSION=1.91.1 cargo fmt --check
ASDF_RUST_VERSION=1.91.1 cargo clippy --all-targets -- -D warnings
ASDF_RUST_VERSION=1.91.1 cargo test
IGREP_BINARY_PATH=/path/to/igrep npm test

Frequency table

src/bigram_weights.bin is a checked-in 256x256 one-byte bucket table. It was generated from source-like UTF-8 files in the VS Code/Code OSS repository at commit 6452d926be4e943fd55958104d64674eb40df7a2:

python3 scripts/generate_bigram_weights.py \
  /Users/mcloutier/Sites/code src/bigram_weights.bin

The recorded corpus contained 24,579 files and 346,820,496 bytes. The table SHA-256 is 6bb77b6822edebf1adeb59455f0404d99c048104cae08ee34f90c3994ee9a6c7. The script deterministically filters generated/dependency directories, folds ASCII case, counts overlapping pairs, and logarithmically maps low frequency to high weight. End-user indexing never trains or changes these weights. A future table change must also change the index algorithm/version.

Benchmarking

The deterministic benchmark builds a legacy v0.1 trigram inverted index in the same hash→offset layout beside the current sparse index, then compares term count, index bytes, query term count, and baseline candidate count:

ASDF_RUST_VERSION=1.91.1 cargo run --release -- \
  bench --root /path/to/corpus --pattern function --pattern workbench

See THIRD_PARTY_NOTICES.md for attribution of the sparse n-gram algorithms.

Licensed under the MIT License.