# app _(no submodules)_ ## Purpose `App` is the top-level entry point for a `@suaveplan/cli` application. It wraps a root `Command` and adds application-level concerns: version printing, help generation, `onError` handling, OTel span instrumentation on `run()`, and `AbortSignal` support. The `cli()` factory function creates an `App` with a name and optional version string in a single expression. `App` delegates all routing and parsing to the underlying `Command` hierarchy. Its primary responsibility is to intercept `--version`, `--help`, and abort signals before dispatching, and to wrap any thrown error with `CliError(CLI_CODES.APP.RUN_FAILED)` when an `onError` handler is registered. ## Features - Fluent builder: `.description()`, `.option()`, `.argument()`, `.action()`, `.command()`, `.example()` - `run(argv?, options?)` dispatches to the root command; defaults `argv` to `process.argv.slice(2)` - `--version` / `-V` prints the version string (if set) and exits cleanly - `--help` / `-h` prints `helpText()` and exits cleanly - `options.signal` (AbortSignal) — throws `CliError(CLI_CODES.APP.ABORTED)` immediately when already aborted - `onError` handler — catches thrown errors, wraps non-`CliError` in `CliError(CLI_CODES.APP.RUN_FAILED)`, and calls the handler instead of re-throwing - OTel span on every `run()` call: span name `cli.app.run`, attribute `cli.app` set to the app name; `SpanStatusCode.ERROR` set on failure - `cli(name, version?)` factory for single-expression app creation ## Usage: Basic Example ```ts import { cli } from "@suaveplan/cli/app/app"; const app = cli("deploy", "1.0.0") .description("Deployment toolkit"); app.command("up") .description("Bring services up") .action(async () => { console.log("Services are up"); }); await app.run(); ``` ## Usage: Advanced Example ```ts import { App } from "@suaveplan/cli/app/app"; const app = new App({ name: "myapp", version: "2.1.0", description: "My enterprise CLI", writer: (text) => process.stdout.write(text + "\n"), onError: (err) => { console.error(`Error [${err.code}]: ${err.message}`); process.exit(1); }, }); app .option("--verbose", "Enable verbose output") .action(async (ctx) => { if (ctx.options.verbose) console.log("Verbose mode on"); }); const controller = new AbortController(); process.on("SIGINT", () => controller.abort()); await app.run(process.argv.slice(2), { signal: controller.signal }); ``` ## API Reference ### `new App(config: AppConfig)` Creates a new app. Config fields: `name` (required), `version`, `description`, `enableHelp` (default true), `enableVersion` (default true), `onError`, `writer`. ### `app.name: string` The app's name as provided in config. ### `app.version: string | undefined` The app's version string, or `undefined` if not set. ### `app.description(text: string): this` Sets the app description shown in help text. ### `app.option(flags, description?, defaultValue?): this` Registers a root-level option. ### `app.argument(spec, description?): this` Registers a root-level positional argument. ### `app.action(fn: ActionFn): this` Sets the root action handler. ### `app.command(name: string): Command` Registers and returns a named sub-command. ### `app.example(text: string): this` Adds an example to the help output. ### `app.helpText(): string` Returns formatted multi-line help text for the root command. ### `app.run(argv?: string[], options?: { signal?: AbortSignal }): Promise` Executes the app. If `signal` is already aborted, throws `CliError(ABORTED)` immediately. Intercepts `--version` and `--help` before routing. Delegates to the root `Command.execute()`. ### `cli(name: string, version?: string): App` Factory function. Creates an `App` with `name` and optional `version`. ## Implementation Notes The `writer` config field injects the output sink, defaulting to `process.stdout.write`. This enables full testability without TTY or process coupling. The `onError` hook receives a `CliError` — if the thrown value was a plain `Error`, it is wrapped in `CliError(RUN_FAILED)` before being handed to the hook, so callers always receive a structured error with a stable code.