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

argoyle

v1.0.0

Published

Minimal, zero-dependency CLI argument parser with auto-generated help.

Readme

Argoyle

Minimal, zero-dependency CLI argument parser with auto-generated help.

Install

npm install argoyle

Usage

import Argoyle from "argoyle";

const cli = new Argoyle("1.0.0");

cli
  .line("Usage: mytool [options] <files...>")
  .line("")
  .option("out", {
    short: "o",
    value: "<path>",
    description: "Output directory",
  })
  .option("format", {
    short: "f",
    value: "[type]",
    description: "Output format",
  })
  .option("verbose", { short: "V", description: "Verbose output" })
  .option("port", {
    value: "<n>",
    description: "Port number",
    callback: (val) => parseInt(val, 10),
  })
  .line("")
  .line("Examples:")
  .line("  mytool --out dist -V file.txt");

// mytool --out dist -V --port 3000 file.txt
const { flags, positionals } = cli.parse();

console.log(flags); // { out: 'dist', format: null, verbose: true, port: 3000, version: false, help: false }
console.log(positionals); // ['file.txt']

Running mytool --help outputs:

Usage: mytool [options] <files...>

  -o, --out <path>    Output directory
  -f, --format [type] Output format
  -V, --verbose       Verbose output
      --port <n>      Port number
  -v, --version       Show version
  -h, --help          Show help

Examples:
  mytool --out dist -V file.txt

API

new Argoyle(version?)

Creates a new parser. Pass a version string to auto-register --version / -v.

.option(name, opts?)

Registers a CLI option. Returns this for chaining.

  • name - Option name (used as --name)
  • opts.short - Single-character short alias (used as -x)
  • opts.value - Value placeholder. Use <name> for required values, [name] for optional values. Omit for boolean flags.
  • opts.default - Default value. Boolean flags default to false, value options default to null.
  • opts.description - Description shown in help output.
  • opts.callback - Function called when the option is parsed. Receives the parsed value (true for boolean flags, a string for value options). Return a value to transform it, or return undefined to keep the original.

.line(text?)

Adds a text line to the help output. Use for headers, sections, and examples. Returns this for chaining.

.help()

Returns the formatted help string.

.parse(argv?)

Parses arguments and returns { flags, positionals }. Accepts either an explicit argv array or an options object. When called without arguments, it auto-detects user arguments from process.argv — using slice(2) for standard Node.js invocations (node script.js ...) and slice(1) for compiled binaries.

// Explicit argv
cli.parse(["--verbose", "file.txt"]);

// Custom offset for exotic runtimes with extra pre-argument entries
cli.parse({ offset: 3 });

// Stop at first positional (useful for subcommands)
cli.parse({ stopEarly: true });
  • flags - Object with parsed option values keyed by option name.
  • positionals - Array of non-option arguments.
  • stopEarly - When true, stops parsing at the first positional argument. Everything after it (including flags) is collected into positionals.

A bare -- stops option parsing. Everything after it is treated as positionals, even if it looks like a flag.

Built-in Options

When a version string is provided, --version / -v is auto-registered. --help / -h is always auto-registered. Both are placed after user-defined options in the help output and call process.exit(0) after printing.

These defaults are skipped if you register your own --version or --help.

Subcommands

Argoyle doesn't have built-in subcommand routing, but you can compose multiple instances using stopEarly:

import Argoyle from "argoyle";

const cli = new Argoyle("1.0.0");
cli.option("verbose", { short: "V", description: "Verbose output" });

const { flags, positionals } = cli.parse({ stopEarly: true });
// mytool -V serve --port 3000
// flags = { verbose: true, ... }
// positionals = ['serve', '--port', '3000']

if (positionals[0] === "serve") {
  const serve = new Argoyle();
  serve.option("port", {
    value: "<n>",
    description: "Port number",
    callback: (val) => parseInt(val, 10),
  });
  const { flags: serveFlags } = serve.parse(positionals.slice(1));
}

Nested subcommands work by chaining parsers:

// mytool remote add origin https://example.com
const root = new Argoyle("1.0.0");
root.option("verbose", { short: "V" });
const { positionals } = root.parse({ stopEarly: true });
// positionals = ['remote', 'add', 'origin', 'https://example.com']

if (positionals[0] === "remote") {
  const remote = new Argoyle();
  const { positionals: sub } = remote.parse({
    stopEarly: true,
    argv: positionals.slice(1),
  });
  // sub = ['add', 'origin', 'https://example.com']

  if (sub[0] === "add") {
    const [name, url] = sub.slice(1);
  }
}

Comparison

| | argoyle | commander | yargs | minimist | meow | arg | util.parseArgs | | -------------------- | -------- | --------- | ------- | -------- | -------- | -------- | ---------------- | | Unpacked size | ~18 KB | ~209 KB | ~231 KB | ~54 KB | ~411 KB | ~14 KB | 0 (built-in) | | Runtime deps | 0 | 0 | 6 | 0 | 0* | 0 | 0 | | TypeScript | Built-in | Built-in | @types | @types | Built-in | Built-in | @types/node | | Auto-help | Yes | Yes | Yes | No | Yes | No | No | | Subcommands | No | Yes | Yes | No | No | No | No | | -abc combined | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | --key=value | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | -- end-of-opts | Yes | Yes | Yes | Yes | Yes | Yes | Yes | | Callbacks | Yes | Yes | Yes | No | Partial | Yes | No |

* meow bundles its dependencies (including yargs-parser) at build time.

License

MIT

P.S.

The name is an homage to Gargoyles TV series, one of my favorite shows when I was a kid.

With ❤️, @stamat