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

shell-history-stats

v1.0.0

Published

πŸ”¨ Analyze your local shell history (fish, zsh, bash) and build statistics of the most used commands, subcommands and flags

Downloads

139

Readme

shell-history-stats

cli-available node version npm version downloads count size license github-ci

πŸ”¨ Analyze your local shell history and find out which commands, subcommands and flags you actually use - and which options you never touch.

npx shell-history-stats

shell-history-stats demo

Features ✨

  • 🐟 Reads fish, zsh and bash history, together or one at a time
  • 🎭 Expands your aliases, so gc counts as git commit and still shows which shorthand you typed
  • πŸ† Ranks your most used aliases, with the share of your typing they cover and the characters they save
  • 🚩 Reports the flags you actually use per command, with the share of runs that had no flags at all
  • 🌳 Breaks multitools into subcommands (git commit, npm run, docker build)
  • 🧡 Splits pipelines, so ls | grep foo counts as two invocations rather than one
  • 🎩 Sees through wrappers - sudo apt install counts towards apt, not sudo
  • πŸ•°οΈ Shows when you work by hour, weekday and month, and says how many entries lacked a timestamp
  • πŸ“ Ranks the directories you work in (fish records them)
  • 🩺 Flags likely typos and long commands that deserve an alias
  • πŸ›‘οΈ Masks anything that looks like a secret before it reaches the report
  • πŸ“„ Prints tables, or writes Markdown, JSON and a self-contained HTML page
  • πŸ“¦ Zero runtime dependencies

Installation πŸ“¦

npm install --global shell-history-stats

Or run it without installing:

npx shell-history-stats

Usage πŸš€

# every history file found on this machine
shell-history-stats

# one shell, longer rankings
shell-history-stats --shell fish --top 30

# a Markdown report for your notes
shell-history-stats --format markdown --out stats.md

# JSON and HTML from the last 90 days
shell-history-stats --format json,html --out report --since 90d

Options

| Option | Description | | :-- | :-- | | --shell <name> | Limit to one shell: fish, zsh or bash. Repeatable. | | --file <path> | Read this history file instead of the discovered ones. Repeatable. | | --format <list> | terminal, markdown, json, html. Comma separated. | | --out <path> | Write to a file. With several formats it is used as a prefix. | | --top <n> | Entries per ranking. Default 20. | | --since <date> | Only entries at or after 2026-01-01, or a span like 30d, 6m. | | --no-redact | Do not mask values that look like secrets. | | --no-aliases | Do not expand shell aliases into their target command. | | -h, --help | Show help. | | -v, --version | Show the version. |

Example output πŸ“Š

An excerpt from a run over a sample history - your own report also covers flags, working hours, directories and hygiene.

Entries: 1360   Invocations: 1377   Unique commands: 26
Ran without any flag: 894 of 1377 (64.9%)

Shells
β”Œβ”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Shell β”‚ Entries β”‚ Invocations β”‚  Share β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ fish  β”‚    1360 β”‚        1377 β”‚ 100.0% β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Top commands
β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ # β”‚ Command β”‚ Count β”‚ Share β”‚ No flags β”‚ Via alias          β”‚
β”œβ”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 1 β”‚ git     β”‚   585 β”‚ 42.5% β”‚    54.2% β”‚ gst (62), gp (28)  β”‚
β”‚ 2 β”‚ npm     β”‚   257 β”‚ 18.7% β”‚   100.0% β”‚ nrb (17), nrt (13) β”‚
β”‚ 3 β”‚ ls      β”‚   158 β”‚ 11.5% β”‚    44.3% β”‚ ll (34)            β”‚
β”‚ 4 β”‚ cd      β”‚    60 β”‚  4.4% β”‚   100.0% β”‚                    β”‚
β”‚ 5 β”‚ docker  β”‚    59 β”‚  4.3% β”‚    23.7% β”‚ dc (9)             β”‚
β””β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Most used aliases
227 of 1377 invocations (16.5%) were typed as an alias
β”Œβ”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ # β”‚ Alias β”‚ Expands to β”‚ Count β”‚ Of aliases β”‚ Chars saved β”‚
β”œβ”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 1 β”‚ gst   β”‚ git status β”‚    62 β”‚      27.3% β”‚         434 β”‚
β”‚ 2 β”‚ ll    β”‚ ls         β”‚    34 β”‚      15.0% β”‚         136 β”‚
β”‚ 3 β”‚ gp    β”‚ git push   β”‚    28 β”‚      12.3% β”‚         168 β”‚
β”‚ 4 β”‚ gd    β”‚ git diff   β”‚    24 β”‚      10.6% β”‚         144 β”‚
β”‚ 5 β”‚ gcm   β”‚ git commit β”‚    21 β”‚       9.3% β”‚         210 β”‚
β””β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

How it reads your history πŸ”

Each shell stores history differently, and the parser handles each one on its own terms.

| Shell | Format | Timestamps | | :-- | :-- | :-- | | fish | YAML-like, with optional paths: per entry | Always | | zsh | : <started>:<elapsed>;<command> | With EXTENDED_HISTORY | | bash | One command per line | Only with HISTTIMEFORMAT |

Sections that need a timestamp say how many entries they had to skip, so a bash-heavy machine never silently reports a partial picture.

[!NOTE] Aliases are read by asking your shell for its own alias table, because plugin frameworks like oh-my-zsh define most aliases at load time rather than in a file. Use --no-aliases to skip that step.

Privacy πŸ›‘οΈ

Everything runs locally - no network access, no telemetry. Values that look like credentials are masked before they reach any output, so a report is safe to paste into notes or an issue: API tokens, --password and -pSecret, user:password pairs in an argument or a connection URI, secrets carried by a header, and long opaque strings. Your home directory is shortened to ~, so a report does not name your account. Counts are computed before masking, so the numbers stay correct. Pass --no-redact if you want the raw text.

API πŸ“š

The package can also be used as a library:

import {
  discoverHistorySources,
  readHistorySources,
  parseEntries,
  buildReport,
  renderMarkdown,
} from "shell-history-stats";

const entries = readHistorySources(discoverHistorySources());
const report = buildReport(entries, parseEntries(entries), {
  top: 20,
  redactSecrets: true,
});

console.log(renderMarkdown(report));

Development πŸ› οΈ

npm install
npm test
npm run build

The landing page in site/ is static. npm run site:build copies the recorded demo next to it and renders site/report.html from demo/history.fish - a synthetic history kept in the repository so the sample report never contains anyone's real commands. Both generated files are ignored by git.

Known limitations 🧭

  • The contents of command substitutions ($(...), backticks) are counted as one opaque argument rather than analysed.
  • Typo detection is a heuristic: a rare command one edit away from a frequent one. Real tools with short names occasionally show up.
  • Only fish records working directories, so the directory ranking covers a subset of your history.

License πŸ“„

The MIT License @ 2026