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

diffstalker

v0.12.3

Published

Interactive terminal UI for git staging, committing, and live diff review

Readme

diffstalker

A live, always-on view of everything changing in your git repos — open it in your browser or your terminal. It watches your repositories in real time, follows you as you switch projects, and shows word-level diffs so you always know exactly what changed.

The web UI, live: your working-tree changes with word-level diffs and per-hunk edit times ("1 minute ago"). Point it at a repo and leave it open — it updates itself.

Why diffstalker?

Keep up with AI. When AI assistants edit your code, changes happen fast. diffstalker gives you a live picture of what's being modified — as it happens — so you review changes in the moment instead of reconstructing them afterward. The Journal view even keeps a running timeline of every edit.

Always-on visibility. Put it on a second monitor and forget about it. As you switch between projects, diffstalker follows along — showing your current changes, staged files, and diffs without you ever needing to alt-tab or type git status.

Runs in the browser. A daemon does the git work and serves a full web UI over HTTP. Open a tab, keep it on a spare screen, and watch your repos live — no terminal required. Prefer the terminal? The same daemon backs a TUI too.

Dead-simple integration. Follow mode watches one plain text file for repository paths. Any script, hook, or tool can write to it. Add two lines to your shell config and every cd into a git repo updates the display automatically.

The web UI

The engine runs as a background daemon, diffstalkerd, which serves a Vue 3 web app over the same REST + Server-Sent Events it uses internally. Run it on a port and open it in your browser:

npm install -g diffstalkerd
diffstalkerd --port 7337
# then open http://localhost:7337

That's it. The UI streams live over SSE — status, diffs, and the change timeline all update on their own. Follow mode is on by default, so the view switches with you as you move between projects (or open any repo by its absolute path from the switcher, top-left).

Five views

Changes — your working tree, live (shown above). A grouped file list (Modified / Untracked / Staged) beside the selected file's diff, with word-level highlighting and per-hunk edit times. Click + / on a row to stage or unstage.

Journal — a running timeline of every change as it happens, tracked per hunk. Each entry has a timestamp, path, a kind (created / edited / expanded / shrunk / reverted / renamed), stats, and its own diff. When a hunk changes again, the older entry collapses and a fresh one appears at the bottom.

History — the commit log beside a full commit detail: metadata and a multi-file diff.

Compare — a GitHub-PR-style view against any base branch: a collapsible commits list, a file tree, and stacked per-file diffs. Toggle between unified and side-by-side layout.

Explorer — a lazy file tree with git-status decoration beside syntax-highlighted file content.

Plus, everywhere: word-level diff highlighting, an app-wide unified / split diff toggle, optional syntax highlighting in diffs, follow and auto mode, search (Ctrl+P — file names, file contents, or the open file's outline, each named on the overlay so you never have to remember which key), six themes, a hotkeys overlay (?), and a layout that reflows for portrait (vertical) monitors.

The web UI is a viewer with one write: file-level stage / unstage from the Changes list. Commit, discard, hunk-level staging, and remote/branch operations live in the terminal UI. See the Web UI section of FEATURES.md for the full list.

Security: the daemon has no authentication, so it binds loopback only — a unix socket, or --port on 127.0.0.1 (there is no option to bind a routable interface). While on a port it also runs an origin guard: a Host allow-list blocks DNS-rebinding and cross-site requests are rejected (CSRF), plus a strict CSP and hardening headers on every response. To reach it from another machine, use an SSH tunnel (ssh -L 7337:localhost:7337 …). See SECURITY.md.

The terminal UI

The same daemon backs a terminal client, diffstalker, for when you'd rather stay in the shell. It auto-spawns the daemon for you on first run:

npm install -g diffstalker
diffstalker              # current directory
diffstalker /path/to/repo
diffstalker --follow     # watch for repo changes (great on a second monitor)

diffstalker terminal — diff view Stage files and review changes with word-level diff highlighting.

diffstalker terminal — history view Browse commit history and inspect past changes.

The terminal UI is the full-power client — staging, hunk staging, commit and amend, discard, PR compare, and remote/branch operations. Its five views map to keys 15 (Diff, Commit, History, PR, Explorer); press ? for the full keybinding reference.

Follow mode

Follow mode is what makes diffstalker "stalk" — it tracks whichever repo you're working in. The daemon watches ~/.cache/diffstalker/target; write or append a repository path to that file and the display switches to it (it reads the last non-empty line, so both styles work). It's on by default.

Integration examples

Shell hook — update on every cd:

# Add to .bashrc or .zshrc
diffstalker_notify() {
    [[ -d .git ]] && echo "$PWD" > ~/.cache/diffstalker/target
}
cd() { builtin cd "$@" && diffstalker_notify; }

Tmux — update on pane/window switch:

# In .tmux.conf
set-hook -g pane-focus-in 'run-shell "tmux display -p \"#{pane_current_path}\" > ~/.cache/diffstalker/target"'

Neovim — update when changing buffers:

-- In init.lua
vim.api.nvim_create_autocmd({"BufEnter"}, {
  callback = function()
    local root = vim.fn.finddir('.git/..', vim.fn.expand('%:p:h') .. ';')
    if root ~= '' then
      local f = io.open(os.getenv('HOME') .. '/.cache/diffstalker/target', 'w')
      if f then f:write(vim.fn.fnamemodify(root, ':p:h')); f:close() end
    end
  end
})

Any script:

echo "/path/to/repo" > ~/.cache/diffstalker/target   # overwrite
echo "/path/to/repo" >> ~/.cache/diffstalker/target  # append (also works)

The file-based approach is intentionally simple. IDE plugins, window manager hooks, project switchers, git hooks — if it can write to a file, it can drive diffstalker.

Architecture

One engine, two front-ends. The git state lives in diffstalkerd, a Node http daemon that serves @diffstalker/core (headless git state) over REST + Server-Sent Events. Both clients are pure daemon clients that hold no in-process git of their own:

  • the web UI (Vue 3) is served by the daemon at GET / over the same REST + SSE, same-origin;
  • the terminal UI installs diffstalkerd as a dependency and auto-spawns it on a unix socket.

Because the state is one shared service, both stay live over the same event stream.

Installation

Linux. That is what diffstalker is built and tested on. The daemon's default transport is a unix socket under $XDG_RUNTIME_DIR, so macOS (which does not set it) needs an explicit --socket PATH, and native Windows is not supported — use WSL2. Requires Node 20.19 or newer, and git on PATH.

Web UI (the daemon that serves it):

npm install -g diffstalkerd
diffstalkerd --port 7337    # open http://localhost:7337

--port adds the browser's transport: the daemon still binds its usual unix socket, so the terminal UI attaches to this same daemon rather than starting a second one, and both clients watch one git state. The port carries a reduced API (reads plus file staging); commit, discard and every remote operation stay on the owner-only socket.

Terminal UI (pulls in diffstalkerd automatically and spawns it for you):

npm install -g diffstalker

Arch Linux — one AUR package gives you both bins and the web UI. It builds the current main, so it tracks the repo rather than the published releases:

yay -S diffstalker-git      # or paru -S diffstalker-git

The package ships a systemd user service, so the daemon and its web UI can just be running:

systemctl --user enable --now diffstalkerd
# web UI at http://diffstalker.localhost:7337/

If that fails with diffstalker: /usr/bin/diffstalker exists in filesystem, an earlier npm install -g diffstalker or npm link owns the path — npm's prefix on Arch is /usr, so its bins land in pacman's territory unowned, and pacman will not install over a file no package owns. The build warns about this before it happens; clear it and retry:

sudo npm rm -g diffstalker diffstalkerd     # also drops /usr/lib/node_modules
yay -S diffstalker-git

Or from source (the repo is a bun workspace of several packages):

git clone https://github.com/yogh-io/diffstalker.git
cd diffstalker
bun install && bun run build       # builds all packages
cd packages/cli && bun link        # link the `diffstalker` bin
# or run it directly: bun run start

For a local web UI in development:

bun run dev:web                    # Vite dev server (HMR) at http://localhost:5173
bun run serve                      # dev daemon from source (always current, Bun
                                   # inspector) serving the web UI at :17337.
                                   # bun run serve /path/to/repo ... pre-opens repos.

Keybindings (terminal UI)

| Action | Keys | |--------|------| | Navigate | / or j/k | | Switch panes | Tab | | Switch views | 1-5 | | Toggle stage | Space or Enter | | Stage/unstage all | Shift+A / Shift+Z | | Discard changes | d (with confirmation) | | Fuzzy file finder | Ctrl+P or / in Explorer | | Resize panes | [ / ] | | Toggle line wrap | w | | Themes | t | | Help | ? |

Full keybinding reference available with ? in either UI.

Themes

Six built-in themes (both UIs) — the web has a switcher top-right; the terminal uses t:

| Theme | Description | |-------|-------------| | Dark / Light | Default palettes | | Dark / Light (colorblind) | Blue/red palette for color vision deficiency | | Dark / Light (ANSI) | Uses your terminal's 16 colors for full consistency |

Configuration

Terminal UI config: ~/.config/diffstalker/config.json

{
  "theme": "dark",
  "splitRatio": 0.4,
  "targetFile": "~/.cache/diffstalker/target"
}

CLI options

Terminal UIdiffstalker [options] [path]:

  -f, --follow [FILE]  Watch file for repo paths
  -s, --socket PATH    diffstalkerd socket to attach to or spawn on
      --instance NAME  Attach to the daemon named NAME (spawns it if absent)
  -d, --debug          Log path changes to stderr
  -h, --help           Show help

Daemondiffstalkerd [options]:

  --port N             Bind TCP port N (loopback only) and serve the web UI at GET /
  --socket PATH        Bind a unix socket instead of a port
  --instance NAME      Bind <NAME>.sock, so several daemons can coexist
  --no-follow          Disable follow mode
  --follow-file PATH   Hook file to watch (default: ~/.cache/diffstalker/target)

See packages/daemon/README.md for the full endpoint table and follow-mode notes.

License

MIT