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

vipvot

v0.4.0

Published

A Bun-native, zero-dependency, TypeScript port of cobra.

Readme

vipvot

A zero-dependency TypeScript port of spf13/cobra. Built with Bun, runs on Node 20+ and Bun 1.3+.

Why

Cobra is the de-facto CLI framework for Go (Kubernetes, Hugo, gh, docker, GitHub CLI). The TypeScript ecosystem has good CLI libraries — commander, oclif, clipanion, Stricli — but none match cobra's exact shape: command groups in help, declarative flag-group constraints (mutex / required-together / one-required), inheritable persistent flags, the five-stage hook chain, POSIX/GNU pflag semantics, 33 of pflag's flag types — and a public surface that lets you port cobra Go code by mechanical rewrite.

vipvot is that shape — in TypeScript, with no runtime dependencies, and differential-tested against a real cobra binary. The build targets Bun for the single-binary bun build --compile workflow (the closest analog to go build of a cobra app), but the published ESM package runs in Node 20+ too.

Why "vipvot"?

vipvot is viper + pivot with the second i dropped. Two things at once:

  • Viper — a snake-nod to cobra. cobra is an elapid; viper is a viperid; both are venomous colubrids in the same kingdom. A different family of the same animal, the same way a TypeScript port is a different language of the same library.
  • Pivot — what the library actually does. It's the pivot point between Go cobra and Bun TypeScript. Cobra Go code translates into vipvot TypeScript by mechanical rewrite, and the reverse is just as direct. &cobra.Command{...}Command({...}). PascalCase ↔ camelCase. struct literal ↔ factory call. A CLI written in vipvot can flip back to Go cobra (or vice versa) without rethinking the model.

So the name carries both: the snake adjacent to cobra, and the joint where bun and Go meet.

See design-docs/01-name.md for the full naming rationale.

What you get

Parser

  • POSIX/GNU flag parsing — short combining (-vvv, -xVALUE), long flags, -- terminator
  • Universal --no-foo boolean negation
  • All edge cases verified byte-for-byte against the cobra/pflag oracle

33 flag types (most of pflag — see COMPARISON.md for the missing ones: IPSlice, IPNetSlice, UintSlice, plus the niche Func / BoolFunc / TextVar / TimeVar callbacks)

  • Scalars: string, boolean, int, int8/16/32/64, uint/uint8/16/32/64, float32/64, count, duration
  • Slices: stringSlice (CSV-aware), stringArray, intSlice, int32/64Slice, float32/64Slice, boolSlice, durationSlice
  • Maps: stringToString, stringToInt, stringToInt64
  • Network: ip, ipMask, ipNet (CIDR)
  • Bytes: bytesHex, bytesBase64

Command tree

  • Command({...}) callable factory — no new keyword
  • Persistent (inherited) flags
  • Five-stage hook chain: persistentPreRun → preRun → run → postRun → persistentPostRun, with cobra-style ancestor-walk inheritance for the persistent stages
  • Args validators: MinimumNArgs, MaximumNArgs, ExactArgs, RangeArgs, OnlyValidArgs, NoArgs, ArbitraryArgs, MatchAll
  • Flag-group constraints: markFlagsRequiredTogether, markFlagsMutuallyExclusive, markFlagsOneRequired
  • Command groups in --help: cmd.addGroup({ id, title }) + child groupId for sectioned listings
  • disableFlagParsing for proxy commands; disableFlagsInUseLine for help cosmetics
  • fParseErrWhitelist: { unknownFlags: true } for proxy/wrapper commands that forward argv
  • annotations map for external tooling

Custom flag types

  • Value interface (set / toString / type) — pflag.Value-equivalent
  • cmd.flags().varP(value, name, short, description) and var() (long-only)
  • Help renderer reads the Value's type() and toString() automatically

Help & error handling

  • Cobra-equivalent help format byte-for-byte (sections, alignment, type markers, defaults)
  • --help / -h auto-injection; <cmd> help [path] auto-dispatch
  • setOut / setErr writers with parent-chain inheritance
  • setHelpFunc to override --help rendering; setUsageFunc to override the usage block printed on parse errors
  • Auto-print on error: Error: <msg> + usage block to stderr (cobra parity); suppress with silenceErrors / silenceUsage
  • "Did you mean?" Levenshtein-based suggestions for unknown subcommands; configurable via suggestFor / disableSuggestions / suggestionsMinimumDistance
  • Error wording byte-for-byte identical to pflag/cobra (verified against the oracle)

Doc generators (vipvot/doc subpath)

  • genMarkdown / genMarkdownTree — per-command markdown
  • genYaml / genYamlTree — YAML for tooling that consumes the command tree as data
  • genReST / genReSTTree — reStructuredText
  • genMan / genManTree — roff-formatted man pages

Format pinned byte-for-byte against the cobra oracle.

Shell completion (vipvot/completion subpath)

  • genBashCompletion, genZshCompletion, genFishCompletion, genPowerShellCompletion
  • validArgsFunction(cmd, args, prefix) for dynamic positional completions
  • registerFlagCompletionFunc(name, fn) for per-flag-value completion (walks parent chain for inherited persistent flags)
  • ShellCompDirective* constants — NoSpace, NoFileComp, FilterFileExt, FilterDirs, KeepOrder
  • disableDescriptions strips value\tdesc to bare values for shells that don't render descriptions
  • Generators only loaded when imported — no bundle cost for users that don't need them

Bundle

  • Core bundle: ~30 KB minified, ~8.5 KB gzipped
  • vipvot/doc and vipvot/completion lazily loaded via subpath imports
  • Zero runtime dependencies

Quick taste

Cobra Go and vipvot TypeScript side-by-side — the only forced changes are the struct-literal → factory call, PascalCase → camelCase, and &variableref<T>().

Go:

var name string
var verbose int

var rootCmd = &cobra.Command{
    Use:   "myapp",
    Short: "my CLI",
    RunE: func(cmd *cobra.Command, args []string) error {
        fmt.Printf("hello, %s\n", name)
        return nil
    },
}

func init() {
    rootCmd.PersistentFlags().StringVarP(&name, "name", "n", "world", "who to greet")
    rootCmd.PersistentFlags().CountVarP(&verbose, "verbose", "v", "verbose level")
    rootCmd.MarkFlagRequired("name")
}

TypeScript:

import { Command, ref } from "vipvot";

const name = ref("world");
const verbose = ref(0);

const rootCmd = Command({
  use: "myapp",
  short: "my CLI",
  runE: (cmd, args) => {
    console.log(`hello, ${name.value}`);
  },
});

rootCmd.persistentFlags().stringVarP(name, "name", "n", "world", "who to greet");
rootCmd.persistentFlags().countVarP(verbose, "verbose", "v", "verbose level");
rootCmd.markFlagRequired("name");

await rootCmd.execute();

See COMPARISON.md for the side-by-side feature table and design-docs/02-cobra-mapping.md for the full per-symbol concordance.

Worked example: a small CLI with subcommands

import { Command, ref, ExactArgs } from "vipvot";

const root = Command({
  use: "todo",
  short: "task tracker",
});

// `todo add <title>` — leaf command with positional arg validation
const title = ref("");
const priority = ref(0);
const add = Command({
  use: "add <title>",
  short: "add a task",
  args: ExactArgs(1),
  run: (_cmd, args) => {
    title.value = args[0]!;
    console.log(`added: ${title.value} (priority ${priority.value})`);
  },
});
add.flags().intVarP(priority, "priority", "p", 0, "priority (0-3)");
root.addCommand(add);

// `todo list --tag urgent` — flag-driven leaf command
const tags = ref<string[]>([]);
const list = Command({
  use: "list",
  short: "list tasks",
  run: () => {
    console.log(`filtering by tags: [${tags.value.join(", ")}]`);
  },
});
list.flags().stringSliceVarP(tags, "tag", "t", [], "filter by tag");
root.addCommand(list);

// Persistent flag — `--verbose` works on every subcommand
const verbose = ref(false);
root.persistentFlags().boolVarP(verbose, "verbose", "v", false, "verbose output");

await root.execute();

Development

See AGENTS.md for the full developer guide.

bun install
bun test            # 545+ tests; uses committed oracle fixtures — no Go needed
bun run typecheck   # tsgo (TypeScript 7 native preview)
bun run lint        # oxlint, default config
bun run format      # oxfmt

To regenerate oracle fixtures (requires Go):

bun run oracle:build
bun run oracle:capture

License

vipvot's source code is MIT-licensed — see LICENSE.

The shell-completion script templates in src/completion/ are adapted from cobra (Apache License 2.0). See NOTICE for the third-party attribution and licenses/cobra-LICENSE-2.0.txt for the full upstream license text.