import { ProgressHandle, ProgressOptions, SpinnerHandle, SpinnerOptions, TableColumn, TableOptions } from "./activity.mjs"; import { ArgBuilder, ArgConfig, ArgSchema, InferArgs } from "./arg.mjs"; import { PromptConfig } from "./prompt.mjs"; import { FlagBuilder, FlagConfig, FlagSchema, InferFlags } from "./flag.mjs"; import { ErasedMiddlewareHandler, Middleware } from "./middleware.mjs"; import { RunOptions, RunResult } from "./run.mjs"; import { Colors } from "ansispeck"; //#region src/core/schema/command.d.ts /** * Widen the context type when adding middleware. * * The default `C = Record` uses an index signature where * every key maps to `never` — making property access a type error until * middleware extends it. Naive intersection (`Record & { user: string }`) * collapses all properties to `never` because `never & T = never`. * * This utility replaces `Record` entirely on the first * `.middleware()` call. Subsequent calls use plain intersection. */ type WidenContext, Output extends Record> = C extends Record ? Output : C & Output; /** * Widen the context type when adding command-scoped derived context. * * Validation-only derive handlers return `undefined` (or nothing), preserving `C`. * Context-producing derive handlers return an object that merges into `C` * using the same first-call replacement rules as middleware. */ type WidenDerivedContext, Output> = Awaited extends Record ? WidenContext> : C; /** * Compile-time state carried through the command builder chain. * * `F` accumulates named flag builders; `A` accumulates named arg builders. * Both start empty (`{}`) and grow as `.flag()` / `.arg()` are called. */ interface CommandConfig { /** Accumulated flag builders keyed by flag name. */ readonly flags: Record>; /** Accumulated arg builders keyed by arg name. */ readonly args: Record>; } /** * Parameters received by the interactive resolver function. * * `flags` contains partially resolved values — present for flags resolved * via CLI, env, or config, `undefined` for unresolved flags. The resolver * uses this to decide which prompts to show based on current state. */ interface InteractiveParams>> { /** Partially resolved flag values (after CLI/env/config, before prompts). */ readonly flags: Readonly>>; } /** * A record mapping flag names to prompt configs or falsy values. * * - `PromptConfig` — show this prompt for the flag * - `false | undefined | null | 0 | ''` — skip prompting for this flag * * Only flag names that need prompting should have truthy values. * Flags not mentioned are handled by their per-flag `.prompt()` config. */ type InteractiveResult = Readonly>; /** * Interactive resolver function for command-level prompt control. * * Called after CLI/env/config resolution but before per-flag prompts fire. * Receives partially resolved values and returns a prompt schema for * flags that should be prompted. Commands without `.interactive()` use * per-flag prompt configs directly. * * @example * ```ts * import { command, flag } from '@kjanat/dreamcli'; * * const deploy = command('deploy') * .flag('region', flag.enum(['us', 'eu', 'ap'])) * .interactive(({ flags }) => ({ * region: !flags.region && { * kind: 'select', * message: 'Select region', * }, * })) * .action(({ flags, out }) => { * out.log(`Deploying to ${flags.region}`); * }); * ``` */ type InteractiveResolver>> = (params: InteractiveParams) => InteractiveResult; /** * Type-erased interactive resolver stored on {@linkcode CommandSchema}. * * Advanced bridge type: most consumers should use {@link InteractiveResolver} * via {@linkcode command | command().interactive()} and never reference this alias directly. * * At runtime, the resolver receives `{ flags: Record }` * and returns `Record`. The phantom types * from `CommandBuilder` are erased. * * @internal */ type ErasedInteractiveResolver = (params: { readonly flags: Readonly>; }) => InteractiveResult; /** * Output channel available inside action handlers. * * Provides structured methods for stdout/stderr, JSON output, * spinners, progress bars, and tables. The real implementation lives in * `src/core/output/`; this interface defines the shape that handlers consume. */ interface Out { /** Write to stdout (normal output). */ log(message: string): void; /** Informational (may be suppressed in quiet mode). */ info(message: string): void; /** * Status line to stderr, suppressed in quiet mode. * * Keeps stdout clean for piping; for success and progress notes like * `Wrote ` that scripts silence with `--quiet`. */ status(message: string): void; /** Warning to stderr. */ warn(message: string): void; /** Error to stderr. */ error(message: string): void; /** * Request a process exit code without emitting error-shaped output. * * Use this for check/status commands that should print normal output but * still signal a non-zero status to scripts. This does not stop execution; * later calls overwrite earlier calls, and thrown errors still win. */ setExitCode(code: number): void; /** * Emit a structured JSON value to stdout. * * Always serialises `value` as JSON to stdout regardless of output * mode. Prefer this over `log(JSON.stringify(...))` so the output * channel can enforce consistent formatting and future features * (pretty-print in TTY, streaming JSON, etc.). */ json(value: unknown): void; /** * Whether the output channel is in JSON mode (`--json` flag active). * * Handlers can check this to skip decorative output (spinners, * progress bars, ANSI formatting) when machine-readable output is * expected. */ readonly jsonMode: boolean; /** * Whether stdout is connected to a TTY (terminal). * * Handlers can check this to decide whether to emit decorative output * (spinners, progress bars, ANSI color codes). When `false`, the output * is being piped or redirected — skip interactive decorations. * * Note: `jsonMode` takes precedence — when `jsonMode` is `true`, * decorative output should be suppressed regardless of `isTTY`. */ readonly isTTY: boolean; /** * Context-aware ANSI color palette (powered by `ansispeck`). * * Colors are enabled only when stdout is a TTY, JSON mode is off, and the * environment supports color (`NO_COLOR`, `FORCE_COLOR`, `--no-color`, * `--color`, `CI` are respected). When disabled, every formatter is an * identity function — `out.color.red('x')` returns `'x'` — so handlers can * style unconditionally without gating on `isTTY`/`jsonMode` themselves. * * @example * ```ts * .action(({ out }) => { * out.log(`${out.color.green('✔')} deployed ${out.color.bold('api')}`); * }); * ``` */ readonly color: Colors; /** * Whether OSC 8 terminal hyperlinks should be emitted. * * Honors `NO_HYPERLINKS`/`FORCE_HYPERLINKS` and the * `--no-hyperlinks`/`--hyperlinks` argv flags, falling back to `isTTY`. * Handlers rendering their own `out.color.link(...)` output can gate on * this to keep OSC 8 escapes out of piped or opted-out contexts. */ readonly isHyperlinkSupported: boolean; /** * Render tabular data. * * - **TTY mode** (non-JSON): Pretty-print aligned columns with headers. * - **JSON mode** (`--json`): Emit the rows as a JSON array to stdout. * - **Piped** (non-TTY, non-JSON): Same aligned text output as TTY * (useful for `grep`, `awk`, etc.). * - Pass `{ format: 'text', stream: 'stderr' }` to keep a human-readable * side channel while `json()` writes machine output to stdout. * * When `columns` is omitted, columns are auto-inferred from the keys * of the first row. Column headers default to the key name. * * When `columns` is provided, both text and JSON output are projected to * only the listed keys. * * @param rows - Array of row objects. */ table>(rows: readonly T[], options: TableOptions): void; /** * Render tabular data with explicit column selection. * * @param rows - Array of row objects. * @param columns - Column descriptors controlling which keys are shown and header labels. * @param options - Per-call rendering options (format, stream). */ table>(rows: readonly T[], columns?: readonly TableColumn[], options?: TableOptions): void; /** * Create a spinner for indeterminate progress feedback. * * Returns a handle for lifecycle control. In non-TTY/jsonMode, * returns a no-op handle (or static fallback if configured). * * @param text - Initial spinner text. * @param options - Fallback strategy for non-TTY environments. * @returns A {@link SpinnerHandle} for lifecycle control. */ spinner(text: string, options?: SpinnerOptions): SpinnerHandle; /** * Create a progress bar for measured work. * * Returns a handle for updating progress. Pass `total` for * determinate mode (percentage bar); omit for indeterminate (pulsing). * * @param options - Progress configuration (total, label, fallback). * @returns A {@link ProgressHandle} for updating progress. */ progress(options: ProgressOptions): ProgressHandle; /** * Stop the currently active spinner or progress handle, if any. * * TTY spinner and progress handles start `setInterval` timers that * prevent the process from exiting until a terminal method (`stop`, * `succeed`, `fail`, `done`) is called. If a handler throws before * reaching that call, the timer leaks and the process hangs. * * Call `stopActive()` in a `finally` block after handler execution * to guarantee cleanup. It is idempotent — safe to call when no * handle is active, or when the handle was already stopped. * * The framework calls this automatically in `runCommand()` and * `cli().run()`. Direct users of `createOutput()` should call it * themselves after the handler returns or throws. * * @example * ```ts * const out = createOutput({ isTTY: true }); * try { * await handler({ out }); * } finally { * out.stopActive(); * } * ``` */ stopActive(): void; } /** * Runtime metadata about the CLI program and current command execution. * * Available to action handlers and middleware. * * Populated by the CLI dispatch layer from {@link CLISchema} and * {@link CommandSchema}. For standalone `runCommand()` calls without * a CLI wrapper, a minimal meta is constructed from the command's own schema. */ interface CommandMeta { /** CLI program name (from `cli('name')` or package.json inference). */ readonly name: string; /** Binary display name used in help/usage (may differ from `name`). */ readonly bin: string; /** Program version, if set via `.version()` or discovered from package.json. */ readonly version: string | undefined; /** The leaf command name currently being executed. */ readonly command: string; } /** * The bag of values received by an action handler. * * - `args` — fully resolved positional arguments * - `flags` — fully resolved flags * - `ctx` — derive/middleware-provided context * - `out` — output channel * - `meta` — CLI program metadata (name, bin, version, command) * * The `C` parameter defaults to `Record`, making `ctx` * property access a type error until derive or middleware extends it. */ interface ActionParams>, A extends Record>, C extends Record = Record> { /** Fully resolved positional argument values, typed from `.arg()` definitions. */ readonly args: Readonly>; /** Fully resolved flag values, typed from `.flag()` definitions. */ readonly flags: Readonly>; /** Middleware/derive-provided context, typed from `.middleware()` and `.derive()` chains. */ readonly ctx: Readonly; /** Structured output channel for stdout, stderr, JSON, tables, and spinners. */ readonly out: Out; /** Runtime metadata about the CLI program and current command. */ readonly meta: CommandMeta; } /** * Action handler function signature. * * May be sync or async — the framework will `await` the return value * regardless. The `C` parameter carries the accumulated middleware * context type (defaults to empty). */ type ActionHandler>, A extends Record>, C extends Record = Record> = (params: ActionParams) => void | Promise; /** * Type-erased action handler stored on {@linkcode CommandBuilder}. * * The typed {@linkcode ActionHandler} from `.action()` is cast to this * erased form at the type-erasure boundary, keeping {@linkcode CommandBuilder} * covariant in its generic parameters. This enables structural * compatibility across TypeScript declaration-file boundaries where * generic inference may fall back to constraint types. * * Follows the same erasure pattern as {@link ErasedDeriveHandler} and * {@link ErasedMiddlewareHandler}. * * @internal */ type ErasedActionHandler = (params: { readonly args: Readonly>; readonly flags: Readonly>; readonly ctx: Readonly>; readonly out: Out; readonly meta: CommandMeta; }) => void | Promise; /** * The bag of values received by a derive handler. * * Identical to {@link ActionParams}: derives run after full resolution and * before the action handler, with typed args/flags/current context plus `out` * and `meta`. */ type DeriveParams>, A extends Record>, C extends Record = Record> = ActionParams; /** * Command-scoped typed pre-action handler. * * Derive handlers may: * - validate resolved input and throw {@linkcode CLIError} * - return nothing (or `undefined`) to continue without changing context * - return an object whose properties merge into `ctx` downstream * * Handlers may be async; the resolved value follows the same rules. * They cannot wrap downstream execution; use {@linkcode middleware} for that. */ type DeriveHandler>, A extends Record>, C extends Record = Record, Output extends Record | undefined = undefined> = (params: DeriveParams) => Output | Promise | void | Promise; /** * Type-erased derive handler stored on the command builder. * * @internal */ type ErasedDeriveHandler = (params: { readonly args: Readonly>; readonly flags: Readonly>; readonly ctx: Readonly>; readonly out: Out; readonly meta: CommandMeta; }) => undefined | Readonly> | Promise>>; /** * Internal execution step union preserving registration order across * {@linkcode CommandBuilder.derive | derive()} and {@linkcode CommandBuilder.middleware | middleware()}. * * @internal */ type ExecutionStep = { readonly kind: 'derive'; readonly handler: ErasedDeriveHandler; } | { readonly kind: 'middleware'; readonly handler: ErasedMiddlewareHandler; }; /** * Program metadata passed to a function-form example, resolved at render time. * * `name` is the actually-invoked program name (`options.help.binName`, falling * back to the command name) so examples stay truthful under symlinks, * `inheritName`, and `npx x` vs a global install. `version` is the program * version, or `undefined` when none is configured. */ interface ExampleMeta { readonly name: string; readonly version: string | undefined; } /** * An example command line: a literal string, or a function resolved at render * time with the program {@link ExampleMeta} (so the program name need not be * hardcoded). */ type ExampleCommand = string | ((meta: ExampleMeta) => string); /** A single usage example shown in help text. */ interface CommandExample { /** The command invocation (e.g. `'deploy production --force'`). */ readonly command: ExampleCommand; /** Optional description of what this example does. */ readonly description?: string; } /** Resolve an {@link ExampleCommand} to its string form for the given meta. */ declare function resolveExampleCommand(command: ExampleCommand, meta: ExampleMeta): string; /** * Runtime descriptor produced by {@link CommandBuilder}. * * Consumers (parser, help generator, CLI dispatcher) read this to * understand the command's shape — flags, args, aliases, subcommands, * middleware, and interactive resolver. */ interface CommandSchema { /** The command name (used for dispatch, e.g. `'deploy'`). */ readonly name: string; /** Human-readable description for help text. */ readonly description: string | undefined; /** Alternative names for this command. */ readonly aliases: readonly string[]; /** Whether this command is hidden from help listings. */ readonly hidden: boolean; /** Usage examples for help text. */ readonly examples: readonly CommandExample[]; /** Named flag schemas, keyed by flag name. */ readonly flags: Readonly>; /** Ordered positional arg entries (name + schema). */ readonly args: readonly CommandArgEntry[]; /** Whether an action handler has been registered. */ readonly hasAction: boolean; /** * Command-level interactive resolver for schema-driven prompt control. * * When set, called after CLI/env/config resolution with partially resolved * flag values. Returns prompt configs for flags that need interactive input. * Takes precedence over per-flag `.prompt()` configs for flags it returns * configs for; flags not mentioned fall back to their per-flag configs. * * @see InteractiveResolver */ readonly interactive: ErasedInteractiveResolver | undefined; /** * Middleware handlers to run before the action handler. * * Executed in registration order — first middleware registered runs * first and calls `next()` to proceed to subsequent middleware, * ending with the action handler. Context accumulates via intersection * at the type level and via object spread at runtime. */ readonly middleware: readonly ErasedMiddlewareHandler[]; /** * Nested subcommand schemas (for help rendering and completion). * * Pure data — no execution closures. Populated by `.command()` on * `CommandBuilder`. Empty for leaf commands. */ readonly commands: readonly CommandSchema[]; } /** * A named positional argument entry in the command schema. * * Pairs a user-facing arg name with its {@link ArgSchema} descriptor. * The array ordering in {@link CommandSchema.args} determines CLI position. */ interface CommandArgEntry { /** User-facing argument name (shown in help as ``). */ readonly name: string; /** Runtime descriptor controlling parsing, presence, and coercion. */ readonly schema: ArgSchema; } /** * A type-erased command entry for heterogeneous command storage. * * Advanced/internal bridge type: most consumers should work with * {@link CommandBuilder} and never reference `ErasedCommand` directly. * * Commands registered via `CLIBuilder.command()` have heterogeneous `F`, `A`, * and `C` type parameters. At the dispatch level we only need the runtime * schema (for name/alias matching and help) and the ability to delegate to * `runCommand()`. This interface captures exactly that contract. * * The `_execute` function closes over the original typed {@linkcode CommandBuilder}, * preserving full type safety inside the closure while presenting a * uniform interface to the dispatcher. * * Defined here (rather than in the CLI layer) so both {@linkcode CommandBuilder} and * `CLIBuilder` can reference it without circular imports. * * @internal */ interface ErasedCommand { /** Runtime schema for name matching and help rendering. */ readonly schema: CommandSchema; /** * Nested subcommands (name/alias → erased child). * * Built recursively by `eraseCommand()` in the CLI layer. * Empty map for leaf commands. The dispatch layer uses this for * recursive command tree traversal. * * @internal */ readonly subcommands: ReadonlyMap; /** Original command builder captured at the type-erasure boundary. */ readonly _command?: AnyCommandBuilder; /** Execute this command against argv. Closes over the typed CommandBuilder. */ readonly _execute: (argv: readonly string[], options?: RunOptions) => Promise; } /** * Structural subset of {@linkcode CommandBuilder} consumed by the execution pipeline. * * Avoids generic type parameters so any `CommandBuilder` satisfies * this interface structurally — no variance constraints, no inference needed. * Used by `runCommand()` and the shared executor to accept commands without * requiring TypeScript to resolve {@linkcode CommandBuilder}'s full generic signature. * * @internal */ interface RunnableCommand { readonly schema: CommandSchema; readonly handler: ErasedActionHandler | undefined; readonly _executionSteps: readonly ExecutionStep[]; } /** * Type-erased {@link CommandBuilder} for heterogeneous subcommand storage. * * Advanced helper alias: useful only when working on DreamCLI internals or * custom tooling that mirrors the framework's type-erasure boundary. * * Uses widest possible generic bounds so any `CommandBuilder` is * assignable. The CLI layer's `eraseCommand()` traverses these to build * the execution tree. * * @internal */ type AnyCommandBuilder = CommandBuilder>, Record>, Record>; /** * Immutable command schema builder. * * The type parameters `F` (flags), `A` (args), and `C` (context) are * phantom types that accumulate builder types as `.flag()`, `.arg()`, * `.derive()`, and `.middleware()` are chained. The `.action()` handler receives * fully typed `ActionParams`. * * `C` defaults to `Record`, making `ctx` property * access a type error until derive or middleware extends it. * * @example * ```ts * const deploy = command('deploy') * .description('Deploy to an environment') * .arg('target', arg.string().describe('Deploy target')) * .flag('force', flag.boolean().alias('f')) * .flag('region', flag.enum(['us', 'eu', 'ap'])) * .action(async ({ args, flags, out }) => { * // args.target: string * // flags.force: boolean * // flags.region: 'us' | 'eu' | 'ap' | undefined * out.log(`Deploying ${args.target}...`); * }); * ``` */ declare class CommandBuilder> = {}, A extends Record> = {}, C extends Record = Record> { /** @internal Runtime schema descriptor. */ readonly schema: CommandSchema; /** @internal The action handler, if registered (type-erased for covariance). */ readonly handler: ErasedActionHandler | undefined; /** * @internal Nested sub-command builders (type-erased for heterogeneous storage). * * Stored separately from `schema.commands` because builders carry action * handlers and phantom types needed by `eraseCommand()` in the CLI layer. * `schema.commands` holds pure `CommandSchema[]` for help/completion. */ readonly _subcommands: readonly AnyCommandBuilder[]; /** * @internal Execution steps in registration order. * * Distinct from `schema.middleware`: middleware handlers remain in schema * for backward compatibility, while derives stay command-local and builder- * scoped so future shared/global middleware can compose cleanly. */ readonly _executionSteps: readonly ExecutionStep[]; /** @internal Phantom brand for accumulated flag builder types. No runtime value. */ readonly _flags: F; /** @internal Phantom brand for accumulated arg builder types. No runtime value. */ readonly _args: A; /** @internal Phantom brand for accumulated context type. No runtime value. */ readonly _ctx: C; /** * Create a command builder from a pre-built schema descriptor. * * @param schema - Runtime command descriptor. * @param handler - Action handler, if registered. * @param subcommands - Nested sub-command builders (type-erased). * @param executionSteps - Derive/middleware steps in registration order. */ constructor(schema: CommandSchema, handler?: ErasedActionHandler, subcommands?: readonly AnyCommandBuilder[], executionSteps?: readonly ExecutionStep[]); /** * Register a command-level interactive resolver for schema-driven prompts. * * The resolver is called after CLI/env/config resolution with partially * resolved flag values. It returns a prompt schema for flags that need * interactive input based on the current state. * * For flags the resolver returns a {@linkcode PromptConfig}, that config is used * instead of any per-flag `.prompt()` config. For flags returned as falsy * (or not mentioned), per-flag `.prompt()` configs are used as fallback. * * Commands without `.interactive()` use per-flag prompt configs directly. * * @example * ```ts * const deploy = command('deploy') * .flag('region', flag.enum(['us', 'eu', 'ap'])) * .flag('force', flag.boolean()) * .interactive(({ flags }) => ({ * region: !flags.region && { * kind: 'select', * message: 'Select region', * }, * })) * .action(({ flags }) => { ... }); * ``` * * @param resolver - Function receiving partially resolved flags and returning prompt configs. * @returns The builder (for chaining). */ interactive(resolver: InteractiveResolver): CommandBuilder; /** * Register a command-scoped typed pre-action handler. * * Derive runs after full resolution and before the action handler. * It receives typed `{ args, flags, ctx, out, meta }` and may either: * * - return nothing (or `undefined`) for validation-only behavior * - return an object to merge additional properties into `ctx` * * Handlers may be async — the runtime awaits them before continuing. * * Unlike middleware, derive cannot wrap downstream execution and does not * use `next()`. Use {@linkcode middleware} for timing, logging, retries, cleanup, * or error-boundary patterns. * * Adding derive drops the current handler (like `.flag()`, `.arg()`, and * `.middleware()`) because the action handler's `ctx` type may change. * * @example * ```ts * command('deploy') * .flag('token', flag.string().env('AUTH_TOKEN')) * .derive(({ flags }) => { * if (!flags.token) { * throw new CLIError('Not authenticated', { * code: 'AUTH_REQUIRED', * suggest: 'Run `mycli login` or set AUTH_TOKEN', * }); * } * return { token: flags.token }; * }) * .action(({ ctx }) => { * ctx.token; // string * }); * ``` * * @param handler - Derive function receiving typed args/flags/ctx. * @returns The builder (for chaining). */ derive | undefined = undefined>(handler: DeriveHandler): CommandBuilder>; /** * Register middleware to run before the action handler. * * Middleware executes in registration order. Each middleware receives * `{ args, flags, ctx, out, meta, next }` and must call `next(additions)` * to continue the chain. Context additions are merged and become * typed downstream. * * Adding middleware widens `C` via intersection and drops the current * handler (like `.flag()` / `.arg()` — the handler's type signature * changes when context changes). * * @example * ```ts * import { CLIError, command, middleware } from '@kjanat/dreamcli'; * * interface User { * id: string; * email: string; * } * * async function getCurrentUser(): Promise { * return { id: 'u_123', email: 'dev@example.com' }; * } * * function startTrace(name: string): string { * return `trace:${name}`; * } * * // Resolve the current user and expose it as `ctx.user` downstream. * const auth = middleware<{ user: User }>(async ({ next }) => { * const user = await getCurrentUser(); * if (!user) { * throw new CLIError('Not authenticated', { code: 'AUTH_REQUIRED' }); * } * await next({ user }); * }); * * // Create a trace id for this command run and expose it as `ctx.traceId`. * const telemetry = middleware<{ traceId: string }>(async ({ meta, next }) => { * const traceId = startTrace(`${meta.name}.${meta.command}`); * await next({ traceId }); * }); * * command('deploy') * .middleware(auth) // C becomes { user: User } * .middleware(telemetry) // C becomes { user: User } & { traceId: string } * .action(({ ctx }) => { * ctx.user; // User — typed * ctx.traceId; // string — typed * }); * ``` * * @param m - {@link Middleware} instance created via {@linkcode middleware | middleware()}. * Middleware handlers receive `{ args, flags, ctx, out, meta, next }`. * @returns The builder (for chaining). */ middleware>(m: Middleware): CommandBuilder>; /** * Set the command's description for help text. * * Displayed below the usage line in `--help` output and next to the * command name in parent command/group help listings. * * @param text - One-line description of what the command does. * * @example * ```ts * command('deploy') * .description('Deploy the application to a target environment') * .action(({ out }) => { out.log('deploying...'); }); * * // $ mycli deploy --help * // Usage: deploy [flags] * // * // Deploy the application to a target environment * ``` * * @returns The builder (for chaining). */ description(text: string): CommandBuilder; /** * Add an alternative name for this command. * * Aliases are accepted during dispatch alongside the primary name. * Multiple aliases can be chained. Aliases are shown in help output. * * @param name - Alternative command name (e.g. `'d'` for `deploy`). * * @example * ```ts * command('deploy') * .alias('d') * .alias('push') * .action(({ out }) => { out.log('deploying...'); }); * * // All equivalent: * // $ mycli deploy * // $ mycli d * // $ mycli push * ``` * * @returns The builder (for chaining). */ alias(name: string): CommandBuilder; /** * Hide this command from help listings. * * The command remains fully functional and dispatchable — it just * won't appear in `--help` output or shell completions. Useful for * internal/debug commands. * * @example * ```ts * command('debug-dump') * .hidden() * .action(({ out }) => { out.log(JSON.stringify(internalState)); }); * * // $ mycli --help → 'debug-dump' is not listed * // $ mycli debug-dump → still works * ``` * * @returns The builder (for chaining). */ hidden(): CommandBuilder; /** * Add a usage example to help text. * * Examples are rendered in the "Examples:" section of `--help` output. * Call multiple times to add several examples. Each example shows a * shell invocation, optionally with a description. * * `cmd` may be a literal string or a function receiving the program * {@link ExampleMeta} (`name`, `version`), resolved at render time. Use the * function form to reference the invoked program name instead of hardcoding * it, so examples stay truthful under symlinks, `inheritName`, and * `npx x` vs a global install. * * @param cmd - The example command line, or a `(meta) => string` builder. * @param description - Optional one-line explanation of what the example does. * * @example * ```ts * command('deploy') * .arg('target', arg.string()) * .flag('force', flag.boolean().alias('f')) * .example('deploy production', 'Deploy to production') * .example((m) => `${m.name} deploy staging -f`, 'Force deploy to staging') * .action(({ args, flags }) => { ... }); * * // $ mycli deploy --help * // ... * // Examples: * // deploy production Deploy to production * // mycli deploy staging -f Force deploy to staging * ``` * * @returns The builder (for chaining). */ example(cmd: ExampleCommand, description?: string): CommandBuilder; /** * Register a named flag on this command. * * The flag name is added to the type-level `F` map. Duplicate flag names * are prevented at the type level via the `Exclude` constraint. * * The builder controls the flag's type, presence, aliases, env/config * bindings, and description. See {@link FlagBuilder} for available modifiers. * * @param name - Flag name: the `--name` CLI token and the matching key on `flags` * in the handler. The name is preserved as-is (no camelCasing); read non-identifier * names such as `'dry-run'` with bracket access (`flags['dry-run']`). * @param builder - Configured {@linkcode FlagBuilder} from {@linkcode flag | flag.string()}, * `flag.boolean()`, `flag.number()`, `flag.enum()`, `flag.array()`, or `flag.custom()`. * * @example * ```ts * command('serve') * .flag('port', flag.number() * .alias('p') * .env('PORT') * .default(3000) * .describe('Port to listen on')) * .flag('host', flag.string() * .env('HOST') * .default('localhost') * .describe('Bind address')) * .flag('verbose', flag.boolean() * .alias('v') * .describe('Enable verbose logging')) * .action(({ flags, out }) => { * flags.port; // number * flags.host; // string * flags.verbose; // boolean * out.log(`Listening on ${flags.host}:${flags.port}`); * }); * * // $ mycli serve --port 8080 -v * // $ PORT=9090 mycli serve * ``` * * @returns The builder (for chaining). */ flag>(name: N & Exclude, builder: B): CommandBuilder, A, C>; /** * Register a named positional argument on this command. * * Args are ordered by registration — position on the CLI matches the * order of `.arg()` calls. The arg name is added to the type-level `A` * map. Duplicate arg names are prevented at the type level via the * `Exclude` constraint. * * The builder controls the arg's type, presence, env binding, and * description. See {@link ArgBuilder} for available modifiers. * * @param name - Positional arg name (used in help text and `args.*`). * @param builder - Configured {@linkcode ArgBuilder} from `arg.string()`, `arg.number()`, * or `arg.custom()`. * * @example * ```ts * command('deploy') * // Required string arg — first positional * .arg('target', arg.string() * .env('DEPLOY_TARGET') * .describe('Deploy target')) * // Optional number arg — second positional * .arg('port', arg.number() * .env('PORT') * .default(3000) * .describe('Port number')) * .action(({ args }) => { * args.target; // string * args.port; // number * }); * * // Usage: deploy [flags] [port] * // $ mycli deploy production 8080 * // $ DEPLOY_TARGET=staging mycli deploy * ``` * * @returns The builder (for chaining). */ arg>(name: N & Exclude, builder: B): CommandBuilder, C>; /** * Register a nested subcommand on this command. * * The subcommand's builder is stored in `_subcommands` for the CLI layer's * `eraseCommand()` to traverse when building the execution tree. The * subcommand's `CommandSchema` is also appended to `schema.commands` for * help rendering and completion generation. * * Does not change `F`, `A`, or `C` — subcommands are type-erased at the * parent level (same semantics as `CLIBuilder.command()`). The handler is * preserved. * * @example * ```ts * const db = group('db') * .description('Database operations') * .command(migrateCmd) * .command(seedCmd); * ``` * * @param sub - Child {@link CommandBuilder} to nest under this command. * @returns The builder (for chaining). */ command>, A2 extends Record>, C2 extends Record>(sub: CommandBuilder): CommandBuilder; /** * Register the action handler for this command. * * The handler receives fully typed `{ args, flags, ctx, out, meta }` derived * from the accumulated `.flag()`, `.arg()`, `.derive()`, and `.middleware()` * definitions. * * May be synchronous or async. Return values are ignored; command handlers * communicate through `out`, thrown errors, and side effects. * * @param handler - Function receiving `ActionParams`. * * @example * ```ts * // Minimal * command('greet') * .arg('name', arg.string()) * .action(({ args, out }) => { * out.log(`Hello, ${args.name}!`); * }); * ``` * * @example * ```ts * // Full params — flags, args, context, output, metadata * command('deploy') * .arg('target', arg.string().env('DEPLOY_TARGET')) * .flag('force', flag.boolean().alias('f')) * .flag('region', flag.enum(['us', 'eu', 'ap']).env('REGION')) * .middleware(auth) * .action(async ({ args, flags, ctx, out, meta }) => { * args.target; // string * flags.force; // boolean * flags.region; // 'us' | 'eu' | 'ap' | undefined * ctx.user; // User (from auth middleware) * meta.command; // string * * const spinner = out.spinner('Deploying...'); * await deploy(args.target, { force: flags.force }); * spinner.stop(); * out.log('Done'); * }); * ``` * * @returns The builder (for chaining). */ action(handler: ActionHandler): CommandBuilder; } /** * Create a new command builder. * * @param name - The command name used for dispatch (e.g. `'deploy'`). * * @example * ```ts * import { arg, command, flag } from '@kjanat/dreamcli'; * * const greet = command('greet') * .arg('name', arg.string()) * .flag('loud', flag.boolean()) * .action(({ args, flags, out }) => { * const msg = `Hello, ${args.name}!`; * out.log(flags.loud ? msg.toUpperCase() : msg); * }); * ``` * * @returns A fresh {@link CommandBuilder} with empty flags, args, and context. */ declare function command(name: string): CommandBuilder; /** * Create a command builder intended for use as a command group. * * Semantically identical to {@linkcode command | command()} — a group is simply a command that * has subcommands registered via `.command()`. The separate factory * communicates intent: groups organise subcommands, leaf commands have actions. * * A group may also have its own `.action()` (e.g. `git remote` lists remotes * when invoked without a subcommand, but dispatches to `git remote add`, etc.). * * @param name - The group name used for dispatch (e.g. `'db'`). * * @example * ```ts * const db = group('db') * .description('Database operations') * .command(migrateCmd) * .command(seedCmd); * ``` * * @returns A fresh {@link CommandBuilder} with empty flags, args, and context. */ declare function group(name: string): CommandBuilder; //#endregion export { type ActionHandler, type ActionParams, type AnyCommandBuilder, type CommandArgEntry, CommandBuilder, type CommandConfig, type CommandExample, type CommandMeta, type CommandSchema, type DeriveHandler, type DeriveParams, type ErasedActionHandler, type ErasedCommand, type ErasedDeriveHandler, type ErasedInteractiveResolver, type ExampleCommand, type ExampleMeta, type InteractiveParams, type InteractiveResolver, type InteractiveResult, type Out, type RunnableCommand, type WidenContext, type WidenDerivedContext, command, group, resolveExampleCommand };