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

whatsapp-tui-ts

v0.5.4

Published

WhatsApp TUI client with vim keybindings

Downloads

2,099

Readme

whatsapp-tui

A WhatsApp client that lives in your terminal. Vim keybindings, native image rendering, real-time messaging, full chat history, and optional native macOS notifications via a tiny background daemon.

Built with Bun + Baileys + OpenTUI + SolidJS. Stores everything locally in SQLite — your messages never leave your machine except to talk to WhatsApp's servers.

brew install alkautsarf/tap/whatsapp-tui
wa

Scan the QR code on first launch and you're in.


Why

Because the official WhatsApp app is heavy, the web client breaks every few weeks, and neither one fits a keyboard-driven workflow. wa-tui treats WhatsApp the way mutt treats email: a small, fast, vim-friendly TUI that pulls real protocol traffic over baileys, persists everything to local SQLite, and gets out of your way.

This is a TypeScript rewrite of the original Rust whatsapp-tui by chilldawg/christopher (TopengDev). Same project name, same data dir convention, same vim spirit — different implementation language and stack.

Features

Messaging

  • Send + receive text, images, videos, audio, stickers, documents
  • Reply to any message (text or media) with proper quoted previews
  • Forward messages (f) — picker for any chat, full media re-upload for older messages
  • Delete messages (d) — for me (local-only) or for everyone (within WA's 2-hour window)
  • React to messages (e) — emoji picker, renders inline next to the timestamp
  • Auto-mark-read for the chat you're viewing
  • Delivery receipts and read status
  • Unread badges that don't ghost back (no double-counting)

Media

  • Inline image and sticker rendering via phosphor-cli (Kitty graphics protocol — works in Ghostty, kitty, WezTerm, and any tmux pane with allow-passthrough on)
  • Enter opens videos, audio, documents in your system viewer (QuickTime, Preview, etc.)
  • @path inline file completion for sending — type @~/Downloads/, get a fuzzy picker
  • Save any media (s) to ~/Downloads/wa-tui/ with a confirmation prompt
  • Drag-drop a file from Finder onto the input box (also works mid-message in groups)

Group features

  • @ opens a participant picker in groups, file picker in DMs (context-aware)
  • Mentions render as @chris 2 locally (not raw @628xxxxxxxxxxx) and resolve correctly on the recipient's WhatsApp
  • @/path and @~/path in groups falls through to the file picker so you can still attach files via @
  • gi chord opens contact / group info: phone or member list, status text, group description, admin marker

Composing

  • Ctrl+G opens $EDITOR for composing long messages, multi-line text, or anything you'd rather not type into a tiny input box
  • Ctrl+E opens an emoji picker
  • Ctrl+V paste image from clipboard
  • Long pastes show a truncated preview but preserve full text on send
  • Reply/quote any message, including media. Esc while composing clears the reply (cancel without sending).

Navigation

  • j/k chat list navigation, J/K message list scroll
  • / search chats (or messages within the current chat when focused on messages)
  • Ctrl+P command palette (includes "Restart wa-tui" for in-app restart)
  • ? keybinding reference overlay
  • i/Esc for INSERT/NORMAL modes
  • gg/G jump to top/bottom
  • y yank message text to clipboard (OSC 52, works through tmux)

Reliability

  • Full history sync from baileys, persisted to local SQLite (WAL mode)
  • Socket liveness check forces reconnect if WhatsApp stops sending frames (zombie socket recovery)
  • Background daemon can fire native notifications even when wa-tui is in another tmux session

Native macOS notifications (optional)

  • Banner popups with the WhatsApp icon, Glass sound, and proper Notification Center grouping
  • Per-chat rate limiting (3s)
  • Respects WhatsApp mute settings
  • Suppresses when you're actually viewing the chat (uses xterm focus reporting to know whether the wa-tui terminal is in front)
  • See Native notifications setup below

Install

Homebrew (macOS — recommended)

brew install alkautsarf/tap/whatsapp-tui
wa

npm (cross-platform — requires bun)

bun install -g whatsapp-tui-ts
wa

From source

git clone https://github.com/alkautsarf/whatsapp-tui-ts
cd whatsapp-tui-ts
bun install
bun run start

First run

On first launch wa-tui shows a QR code in the terminal. Open WhatsApp on your phone → Settings → Linked Devices → Link a Device → scan it. Auth state is saved to ~/.local/share/whatsapp-tui/auth_state/ and reused on subsequent runs.

After scanning, history sync begins automatically. Depending on how much chat history you have, this can take anywhere from a few seconds to a few minutes. Press q (NORMAL mode) anytime to quit.

Quick start

launch wa-tui
   │
   ▼
chat list (NORMAL mode)
   │
   ├─ j/k        navigate chats
   ├─ /          search chats
   ├─ Enter      open selected chat
   ├─ Ctrl+P     command palette
   └─ q          quit
                │
                ▼
chat view (NORMAL mode)
   │
   ├─ J/K        scroll messages
   ├─ i          enter INSERT mode (compose)
   ├─ r          reply to selected message
   ├─ Ctrl+G     open $EDITOR for long compose
   ├─ Esc        back to chat list
   └─ Enter      open media (image/video/audio)
                │
                ▼
INSERT mode (compose box)
   │
   ├─ type message
   ├─ @path      inline file picker
   ├─ Enter      send
   ├─ Esc        back to NORMAL
   └─ Ctrl+G     open external editor

Native notifications (macOS only, optional)

By default wa-tui has no native notifications — the brew install only ships the main wa binary. To get OS-level banners with the WhatsApp icon, install the optional notifier daemon once:

git clone https://github.com/alkautsarf/whatsapp-tui-ts
cd whatsapp-tui-ts/notifier
./install.sh

The installer:

  1. Builds a tiny Swift app (WhatsAppTuiNotifier.app, ~100 lines)
  2. Extracts the WhatsApp icon from /Applications/WhatsApp.app
  3. Installs to ~/Applications/
  4. Sets up a launchd plist so it starts at login
  5. Triggers the macOS permission prompt — click Allow
  6. Fires a test notification ("Notifier installed successfully")

That's it. From then on, every message wa-tui receives that passes the notification gate (not from you, not in the chat you're actively viewing, not muted, not status@broadcast, rate-limited at 3s/chat) fires a native notification with the WhatsApp icon and Glass sound.

The daemon survives wa-tui upgrades (independent app at ~/Applications/). To uninstall:

cd notifier
./uninstall.sh

Recommended macOS notification settings

After install, open System Settings → Notifications → WhatsApp and set:

| Setting | Value | |---|---| | Allow Notifications | ON | | Banner Style | Persistent (not Temporary — Temporary auto-dismisses) | | Notification Grouping | Off (so consecutive messages don't coalesce) | | Sounds | ON |

Why an opt-in daemon?

Three reasons:

  1. Brew best practices: brew formulas should not write to ~/Library/LaunchAgents/ or ~/Applications/. Auto-installing a background daemon without consent is invasive.
  2. Cross-platform: Linux/Windows users get wa-tui via brew/npm with no notifications, no errors, no broken installs.
  3. Code signing: bundling unsigned .app files via brew can trigger Gatekeeper warnings on stricter Macs. Manual install via local swiftc builds without quarantine and skips that whole headache.

A wa install-notifier subcommand that wraps this is on the followup list.

Tip: run wa-tui in a background tmux session

If you use tmux, bind a key to switch to a persistent wa-tui session so it keeps running and receiving messages without sitting in your main session:

# ~/.tmux.conf.local
bind a run-shell '~/.tmux/scripts/wa-toggle.sh'
# ~/.tmux/scripts/wa-toggle.sh
#!/bin/bash
SESSION_NAME=wa-tui
if [ "$(tmux display-message -p '#{session_name}')" = "$SESSION_NAME" ]; then
  tmux switch-client -l
else
  tmux has-session -t "$SESSION_NAME" 2>/dev/null \
    || tmux new-session -d -s "$SESSION_NAME" "wa"
  tmux switch-client -t "$SESSION_NAME"
fi

prefix a now toggles between your current session and a persistent wa-tui session that survives across tmux sessions.

Note: tmux display-popup cannot render Kitty graphics — popups are not panes and have no allow-passthrough scope. Use switch-client to a real session instead, like the script above does.

Data dir

Everything wa-tui stores lives at ~/.local/share/whatsapp-tui/:

~/.local/share/whatsapp-tui/
├── auth_state/           # baileys credentials (do not delete unless re-pairing)
├── app.db                # SQLite — chats, contacts, messages, groups
├── app.db-wal            # SQLite WAL
├── app.db-shm            # SQLite shared memory
├── media/                # downloaded images/videos/audio/documents
└── tui.log               # wa-tui's log file

Existing Rust whatsapp-tui users

If you previously ran the original Rust whatsapp-tui, it uses the same data dir. The schemas are completely incompatible — when you brew install this TS rewrite, it'll detect the foreign schema and refuse to start with instructions:

mv ~/.local/share/whatsapp-tui ~/.local/share/whatsapp-tui.rust-backup
wa

Your Rust data is preserved in the .rust-backup directory and you can keep using the Rust version with --data-dir if you want both.

Development

git clone https://github.com/alkautsarf/whatsapp-tui-ts
cd whatsapp-tui-ts
bun install
bun run start              # run from source
bun run start:repl         # baileys REPL for debugging WhatsApp protocol directly

Project layout

src/
├── index.tsx              # entry point — boots renderer, baileys, store, focus tracking
├── wa/
│   ├── client.ts          # baileys connection, auth state, liveness check
│   ├── handlers.ts        # event handlers (messages, chats, contacts, presence, groups)
│   ├── media.ts           # media download + raw message cache
│   └── message-types.ts   # MEDIA_TYPES, SKIP_MESSAGE_TYPES, mediaLabel()
├── store/
│   ├── db.ts              # SQLite init, schema, foreign-DB detection
│   └── queries.ts         # all prepared statements + StoreQueries interface
├── ui/
│   ├── app.tsx            # root TUI component
│   ├── state.tsx          # SolidJS store + ReactiveBridge
│   ├── keys.ts            # vim key dispatch
│   ├── image.ts           # phosphor-cli inline image rendering
│   ├── layout.tsx         # split layout
│   └── components/        # chat-list, messages, input, header, etc.
└── utils/
    ├── notify.ts          # writes /tmp/wa-tui-notif/<ts>-<rand>.json
    ├── terminal-focus.ts  # xterm focus reporting (CSI 1004)
    ├── log.ts, paths.ts
    └── ...

notifier/
├── Sources/main.swift     # WhatsAppTuiNotifier.app (~100 LOC Swift)
├── Resources/Info.plist
├── build.sh               # swiftc compile + assemble bundle
├── install.sh             # build + install + launchd + permission prompt
└── uninstall.sh

Tests + checks

bunx tsc --noEmit          # type check
bun run test.ts            # baileys validation harness

Releasing

The project uses a single source-only tarball — no per-arch matrix. bun install runs at brew install time so the correct OpenTUI native modules get pulled per platform automatically.

./scripts/release.sh       # builds whatsapp-tui-vX.Y.Z-source.tar.gz

Acknowledgments

  • chilldawg / christopher (TopengDev) — the original Rust whatsapp-tui and the spirit behind the project. This TS rewrite started as an experiment and grew into a parallel implementation
  • Baileys — pure-TypeScript WhatsApp Web protocol library, the reason this works at all
  • OpenTUI + SolidJS — the rendering stack
  • phosphor-cli — terminal image rendering for Kitty graphics protocol

License

MIT