# @suaveplan/cli - Zero-dependency CLI toolkit: argument parser, command router, ANSI styling, output formatting, spinner, progress bar, interactive prompts ## Summary Enterprise-grade CLI framework for Node.js. Composable fluent API with subcommand routing, option parsing, OTel tracing, and a full set of terminal UI primitives. --- ## Documentation tree - [app](./src/app/app.md) — _(no submodules)_ - [app](./src/app/app.md) — _(no submodules)_ - [command](./src/command/command.md) — _(no submodules)_ - [command](./src/command/command.md) — _(no submodules)_ - [errors](./src/errors/errors.md) — _(no submodules)_ - [errors](./src/errors/errors.md) — _(no submodules)_ - [format](./src/output/format/format.md) — _(no submodules)_ - [format](./src/output/format/format.md) — _(no submodules)_ - [table](./src/output/table/table.md) — _(no submodules)_ - [table](./src/output/table/table.md) — _(no submodules)_ - [parser](./src/parser/parser.md) — _(no submodules)_ - [parser](./src/parser/parser.md) — _(no submodules)_ - [progress](./src/progress/progress.md) — _(no submodules)_ - [progress](./src/progress/progress.md) — _(no submodules)_ - [prompt](./src/prompt/prompt.md) — _(no submodules)_ - [prompt](./src/prompt/prompt.md) — _(no submodules)_ - [spinner](./src/spinner/spinner.md) — _(no submodules)_ - [spinner](./src/spinner/spinner.md) — _(no submodules)_ - [style](./src/style/style.md) — _(no submodules)_ - [style](./src/style/style.md) — _(no submodules)_ - [app](./src/app/app.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [format](./src/output/format/format.md) — _(no submodules)_- [format](./src/output/format/format.md) — _(no submodules)_- [table](./src/output/table/table.md) — _(no submodules)_- [table](./src/output/table/table.md) — _(no submodules)_- [parser](./src/parser/parser.md) — _(no submodules)_- [parser](./src/parser/parser.md) — _(no submodules)_- [progress](./src/progress/progress.md) — _(no submodules)_- [progress](./src/progress/progress.md) — _(no submodules)_- [prompt](./src/prompt/prompt.md) — _(no submodules)_- [prompt](./src/prompt/prompt.md) — _(no submodules)_- [spinner](./src/spinner/spinner.md) — _(no submodules)_- [spinner](./src/spinner/spinner.md) — _(no submodules)_- [style](./src/style/style.md) — _(no submodules)_- [style](./src/style/style.md) — _(no submodules)_- [app](./src/app/app.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [format](./src/output/format/format.md) — _(no submodules)_- [format](./src/output/format/format.md) — _(no submodules)_- [table](./src/output/table/table.md) — _(no submodules)_- [table](./src/output/table/table.md) — _(no submodules)_- [parser](./src/parser/parser.md) — _(no submodules)_- [parser](./src/parser/parser.md) — _(no submodules)_- [progress](./src/progress/progress.md) — _(no submodules)_- [progress](./src/progress/progress.md) — _(no submodules)_- [prompt](./src/prompt/prompt.md) — _(no submodules)_- [prompt](./src/prompt/prompt.md) — _(no submodules)_- [spinner](./src/spinner/spinner.md) — _(no submodules)_- [spinner](./src/spinner/spinner.md) — _(no submodules)_- [style](./src/style/style.md) — _(no submodules)_- [style](./src/style/style.md) — _(no submodules)_- [app](./src/app/app.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_- [format](./src/output/format/format.md) — _(no submodules)_- [format](./src/output/format/format.md) — _(no submodules)_- [table](./src/output/table/table.md) — _(no submodules)_- [table](./src/output/table/table.md) — _(no submodules)_- [parser](./src/parser/parser.md) — _(no submodules)_- [parser](./src/parser/parser.md) — _(no submodules)_- [progress](./src/progress/progress.md) — _(no submodules)_- [progress](./src/progress/progress.md) — _(no submodules)_- [prompt](./src/prompt/prompt.md) — _(no submodules)_- [prompt](./src/prompt/prompt.md) — _(no submodules)_- [spinner](./src/spinner/spinner.md) — _(no submodules)_- [spinner](./src/spinner/spinner.md) — _(no submodules)_- [style](./src/style/style.md) — _(no submodules)_- [style](./src/style/style.md) — _(no submodules)_- [app](./src/app/app.md) — _(no submodules)_- [command](./src/command/command.md) — _(no submodules)_ - [command](./src/command/command.md) — _(no submodules)_- [errors](./src/errors/errors.md) — _(no submodules)_ - [errors](./src/errors/errors.md) — _(no submodules)_- [format](./src/output/format/format.md) — _(no submodules)_ - [format](./src/output/format/format.md) — _(no submodules)_- [table](./src/output/table/table.md) — _(no submodules)_ - [table](./src/output/table/table.md) — _(no submodules)_- [parser](./src/parser/parser.md) — _(no submodules)_ - [parser](./src/parser/parser.md) — _(no submodules)_- [progress](./src/progress/progress.md) — _(no submodules)_ - [progress](./src/progress/progress.md) — _(no submodules)_- [prompt](./src/prompt/prompt.md) — _(no submodules)_ - [prompt](./src/prompt/prompt.md) — _(no submodules)_- [spinner](./src/spinner/spinner.md) — _(no submodules)_ - [spinner](./src/spinner/spinner.md) — _(no submodules)_- [style](./src/style/style.md) — _(no submodules)_ - [style](./src/style/style.md) — _(no submodules)_ ## Modules | Module | Path | Description | |---|---|---| | [App / cli()](src/app/app.md) | `app/app` | Application entry point and root command | | [Command](src/command/command.md) | `command/command` | Subcommand builder with fluent API | | [Parser](src/parser/parser.md) | `parser/parser` | Argv parser with options, positionals, and short flags | | [Errors](src/errors/errors.md) | `errors/errors` | Stable error codes and `CliError` class | | [Style](src/style/style.md) | `style/style` | ANSI color and formatting with chainable proxy styler | | [Format](src/output/format/format.md) | `output/format/format` | Text formatters: key-value, list, tree, columns, heading | | [Table](src/output/table/table.md) | `output/table/table` | ASCII/Unicode bordered table renderer | | [Spinner](src/spinner/spinner.md) | `spinner/spinner` | TTY-aware animated spinner with AbortSignal | | [Progress](src/progress/progress.md) | `progress/progress` | ASCII progress bar with TTY in-place update | | [Prompt](src/prompt/prompt.md) | `prompt/prompt` | Interactive prompts: text, password, confirm, select, multiselect | --- ## Quick Start ```ts import { cli } from "@suaveplan/cli"; const app = cli("myapp", "1.0.0"); app.description("My enterprise CLI tool"); app .command("build") .description("Build the project") .option("--output , -o", "output directory", "./dist") .option("--watch, -w", "watch for changes") .action(async (ctx) => { const { output, watch } = ctx.options; console.log(`Building to ${output}${watch ? " (watch mode)" : ""}...`); }); app .command("deploy") .description("Deploy to production") .argument("", "target environment") .action(async (ctx) => { const env = ctx.args["env"]; console.log(`Deploying to ${env}...`); }); await app.run(); ``` --- ## App / `cli()` Factory ```ts import { App, cli } from "@suaveplan/cli"; // Factory shorthand const app = cli("myapp", "1.0.0"); // Or full constructor const app = new App({ name: "myapp", version: "1.0.0", description: "My tool", writer: process.stdout.write.bind(process.stdout), onError: (err) => { console.error(err); process.exit(1); }, }); app.action(async (ctx) => { /* root action */ }); await app.run(process.argv.slice(2)); ``` **Options:** `enableVersion` (default `true`) and `enableHelp` (default `true`) control whether `--version` and `--help` flags are intercepted. Pass `{ signal: AbortSignal }` to `run()` to support cancellation. --- ## Commands ```ts const cmd = app .command("serve") .description("Start the dev server") .alias("s") .option("--port , -p", "port number", "3000") .argument("[dir]", "root directory") .example("myapp serve --port 8080 ./src") .action(async (ctx) => { const port = ctx.options["port"]; const dir = ctx.args["dir"] ?? "."; console.log(`Serving ${dir} on port ${port}`); }); // Nest subcommands arbitrarily deep const db = app.command("db").description("Database utilities"); db.command("migrate").action(async () => { /* ... */ }); db.command("seed").hidden().action(async () => { /* ... */ }); ``` --- ## Terminal UI ### Spinner ```ts import { createSpinner } from "@suaveplan/cli"; const sp = createSpinner({ text: "Building…" }); sp.start(); // later… sp.succeed("Build complete"); // or sp.fail("Build failed"); ``` ### Progress Bar ```ts import { createProgress } from "@suaveplan/cli"; const bar = createProgress({ total: 100, label: "Compiling" }); bar.update(42); bar.complete("Done"); ``` ### Interactive Prompts ```ts import { text, password, confirm, select, multiselect } from "@suaveplan/cli"; const name = await text("Your name?"); const pass = await password({ message: "Password?", validate: (v) => v.length >= 8 || "too short" }); const ok = await confirm("Continue?", reader); const env = await select({ message: "Environment:", choices: ["dev", "staging", "prod"] }); const tags = await multiselect({ message: "Tags:", choices: ["a", "b", "c"], min: 1, max: 3 }); ``` ### Style & Formatting ```ts import { style, createStyler, heading, list, table } from "@suaveplan/cli"; console.log(style.bold.green("Success!")); console.log(heading("Deploy Report", 1)); console.log(list(["Step 1", "Step 2", "Step 3"])); console.log(table(["Name", "Status"], [["api", "ok"], ["db", "ok"]])); ``` --- ## Error Codes All errors are `CliError` instances with stable string codes: | Code | Meaning | |---|---| | `cli.app.aborted` | Run cancelled via AbortSignal | | `cli.app.run_failed` | Uncaught error in action | | `cli.command.no_action` | Command has no action defined | | `cli.command.unknown_subcommand` | No matching subcommand found | | `cli.parse.unknown_option` | Unrecognised flag | | `cli.parse.missing_value` | Flag expects a value that wasn't provided | | `cli.parse.missing_argument` | Required positional argument missing | | `cli.parse.invalid_value` | Value not in allowed choices or wrong type | | `cli.parse.missing_required_option` | Required option not provided | --- ## OTel Every `App.run()` and `Command.execute()` call is wrapped in an OpenTelemetry span. Pass a tracer via `@opentelemetry/api` — no-op tracer is used by default, so no configuration is required.