src/cli/index.ts — top-level command dispatcher
Purpose
Section titled “Purpose”Argv → subcommand dispatch; the cli module’s contract. Hand-rolled
(no commander / yargs / cac) to keep the dependency tree slim and
behaviour trivially predictable. Each subcommand handler lives in a
sibling src/cli/<name>.ts.
Public surface
Section titled “Public surface”export async function run(argv: readonly string[]): Promise<number>
// Re-exports for tests:export { parseRunArgs, type RunArgs } from './run.js'export { parsePruneArgs, parseDuration, parseSize } from './cache.js'export { formatBytes } from './format.js'run(argv) returns the exit code. bin.ts calls
process.exit(await run(process.argv.slice(2))).
Subcommands
Section titled “Subcommands”| Argv first token | Handler |
|---|---|
run | cli/run.ts:runCmd(rest) |
watch | cli/watch.ts:watchCmd(rest) |
cache | cli/cache.ts:cacheCmd(rest) |
help / --help / -h / (empty) | cli/help.ts:printHelp() |
version / --version | process.stdout.write('vx <VERSION>\n') |
| anything else | print unknown command, then help, exit 1 |
Per-subcommand parsers / handlers carry their own argv-walk loops. See:
cli-run.md—vx runcli-watch.md—vx watchcli-cache.md—vx cache prunecli-help.md—vx helpcli-format.md— shared formatters
What this does NOT do
Section titled “What this does NOT do”- No global flags (no
--debug, no--quiet, no--color). Color is gated by env (NO_COLOR/FORCE_COLOR/ TTY). - No tab completion.
- No subcommand aliases beyond the help / version sugar.
tests/cli.test.ts covers the dispatcher table — help, version,
unknown subcommand. Per-subcommand parser tests live in
tests/cli.test.ts too (it’s one file).
Replacing this module
Section titled “Replacing this module”To swap in a parser library, keep run(argv): Promise<number> and
keep the per-subcommand re-exports stable (tests import them
directly). Everything else can change.