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

vanilla-shell

v1.0.0

Published

A POSIX-like shell for the browser using ZenFS and virtual commands

Readme

vanilla-shell

A lightweight, extensible shell for the browser built in TypeScript. Uses ZenFS with IndexedDB for persistent storage. Based on mrsh with virtual command support inspired by Vorpal.js.

🎵 This project was mostly vibecoded

Philosophy

This is not a POSIX-accurate shell. The built-in commands handle simple, common cases — they don't aim for full compatibility with their Unix counterparts.

Instead, vanilla-shell prioritizes:

  • Easy extension with JavaScript — register async functions as commands with a simple API
  • Deep browser integration — explore the synergy between CLI workflows and DOM manipulation
  • Hackability over correctness — a playground for experimenting with shell UX in the browser

Looking for a "real" shell?

If you need binary compatibility or full POSIX compliance, check out these excellent alternatives:

| Project | Approach | Best For | |---------|----------|----------| | WebVM | x86 JIT to Wasm (CheerpX) | Running unmodified Linux binaries | | v86 | Full x86 hardware emulation | Booting real OSes (Linux, Windows 98) | | JSLinux | x86/RISC-V emulation | The OG browser Linux by Fabrice Bellard | | Runno | WASI runtime | Embedding code runners in docs | | Browsix | Unix syscalls in browser | Research, multi-process apps |

vanilla-shell is for when you want something lightweight, JS-native, and fun to extend

Features

  • Shell Parsing: POSIX-inspired shell grammar including:

    • Pipes (|) and command chains (&&, ||)
    • I/O redirections (>, >>, <, 2>, etc.)
    • Variable expansion ($VAR, ${VAR:-default})
    • Command substitution ($(...) and `...`)
    • Control flow (if/then/else/fi, for, while, case)
    • Subshells and brace groups
  • Persistent Virtual Filesystem: Complete filesystem using ZenFS with IndexedDB

    • Create, read, edit, and delete files
    • Full directory structure support
    • Persists across browser sessions and page reloads
  • Virtual Commands: Register TypeScript functions as shell commands

    • Declarative command definition with options and arguments
    • Automatic argument parsing
    • Built-in help generation
  • XTerm.js Integration: Beautiful terminal emulation

    • Full keyboard support
    • Command history (up/down arrows)
    • Tab completion for commands and files
    • Cursor movement and editing

Installation

npm install

Development

# Start development server
npm run dev

# Type check
npm run typecheck

# Build for production
npm run build

Usage

Basic Shell Usage

import { Shell } from 'vanilla-shell';

const shell = new Shell({
  stdout: (text) => console.log(text),
  stderr: (text) => console.error(text),
});

// Execute commands
await shell.execute('echo "Hello, World!"');
await shell.execute('ls -la');
await shell.execute('cat /home/user/file.txt');

Registering Virtual Commands

import { Shell } from 'vanilla-shell';

const shell = new Shell();

// Simple command
shell.command('greet')
  .description('Greet someone')
  .option('-n, --name', 'Name to greet', { hasValue: true })
  .action(async (ctx) => {
    const name = ctx.args.name || 'World';
    ctx.stdout(`Hello, ${name}!\n`);
    return 0;
  });

// Use the command
await shell.execute('greet --name Alice');

XTerm.js Integration

import { TerminalShell } from 'vanilla-shell/demo/terminal';

const terminal = await TerminalShell.create({
  container: document.getElementById('terminal')!,
  welcomeMessage: 'Welcome to my shell!',
});

// Access the shell for customization
const shell = terminal.getShell();
shell.command('custom')
  .description('My custom command')
  .action(async (ctx) => {
    ctx.stdout('Hello from custom command!\n');
    return 0;
  });

Built-in Commands

| Command | Description | |---------|-------------| | echo | Print arguments | | pwd | Print working directory | | cd | Change directory | | ls | List directory contents | | cat | Display file contents | | mkdir | Create directories | | rm | Remove files/directories | | rmdir | Remove empty directories | | touch | Create empty files | | cp | Copy files | | mv | Move/rename files | | head | Output first lines of files | | tail | Output last lines of files | | wc | Word, line, character count | | grep | Search for patterns | | printf | Format and print data | | export | Set environment variables | | unset | Remove environment variables | | env | Print environment | | test / [ | Evaluate expressions | | true | Return success | | false | Return failure | | exit | Exit the shell | | clear | Clear the screen | | help | Show available commands |

Shell Features

Variable Expansion

# Simple expansion
echo $HOME
echo ${USER}

# Default values
echo ${NAME:-default}
echo ${NAME:=assigned}

# String length
echo ${#PATH}

# Pattern removal
echo ${PATH%:*}
echo ${PATH#*:}

Control Flow

# If statement
if test -f /home/user/file.txt; then
  cat /home/user/file.txt
else
  echo "File not found"
fi

# For loop
for i in a b c; do
  echo $i
done

# While loop
while test $count -lt 10; do
  count=$((count + 1))
done

# Case statement
case $var in
  a) echo "It's a";;
  b) echo "It's b";;
  *) echo "Unknown";;
esac

Pipes and Redirections

# Pipes
cat file.txt | grep pattern | wc -l

# Output redirection
echo "Hello" > file.txt
echo "World" >> file.txt

# Input redirection
cat < input.txt

Architecture

src/
├── shell/
│   ├── ast.ts         # Abstract Syntax Tree types
│   ├── shell.ts       # Main execution engine
│   ├── filesystem.ts  # ZenFS wrapper with IndexedDB
│   └── commands.ts    # Virtual command system
├── parser/
│   ├── lexer.ts       # Tokenizer
│   └── parser.ts      # Shell grammar parser
├── builtins/
│   └── index.ts       # Built-in commands
├── demo/
│   ├── terminal.ts    # XTerm.js integration
│   └── main.ts        # Demo entry point
└── index.ts           # Main exports

Credits

  • mrsh - The original POSIX shell this is based on
  • Vorpal.js - Inspiration for the virtual command system
  • ZenFS - Browser filesystem with IndexedDB persistence
  • XTerm.js - Terminal emulator for the browser

License

MIT