import { C as ErasedActionHandler, E as ExecutionStep, G as ArgConfig, Jn as schemaBrand, Ln as HelpThemeFactory, Nt as FlagBuilder, Pt as FlagConfig, U as Verbosity, W as ArgBuilder, _ as CommandDefinition, b as CommandSchema, g as CommandBuilder } from "./index-BziI2aKc.mjs"; import { H as Builtins, U as BuiltinsConfig, b as ParseOptions, n as RunResult, t as RunOptions, u as CLIPlugin } from "./index-DWsnGZlx.mjs"; import { n as RuntimeAdapter } from "./adapter-D0hbBNVB.mjs"; import { h as PackageJsonData, s as FormatLoader } from "./index-DOfClfYR.mjs"; import { Colors } from "ansispeck"; //#region src/core/completion/shells/shared.d.ts /** * Options for completion script generation. * * Passed to individual shell generators alongside the CLI schema. * * These options affect the generated script text, not runtime completion * behavior after installation. */ interface CompletionOptions { /** * Override the generated shell function name prefix. * * Defaults to the CLI name from the schema. This is mainly useful when * embedding multiple generated scripts in the same environment and you want * deterministic, collision-free helper names. * * @example * ```ts * generateCompletion(schema, 'bash', { functionPrefix: 'acme' }); * ``` */ readonly functionPrefix?: string; /** * Controls which root-level surface shell completion exposes when a * default command exists. * * - `'subcommands'` keeps hybrid CLIs command-centric at the root while * still exposing default-command flags for a single visible default * command. * - `'surface'` exposes the default command's root-usable flags at the * root whenever a visible default command exists. * * @defaultValue `'subcommands'` */ readonly rootMode?: 'subcommands' | 'surface'; } //#endregion //#region src/core/completion/shell.d.ts /** * Supported shell targets for completion script generation. * * `bash`, `zsh`, `fish`, and `powershell` are implemented today. */ type Shell = 'bash' | 'zsh' | 'fish' | 'powershell'; /** * Implemented shell values as a frozen readonly non-empty tuple. * * Use this tuple for user-facing validation and shell selection UIs. * It intentionally matches the shipped {@link Shell} union exactly so docs, * help output, and completion generation advertise the same support surface. * * @see {@link Shell} for the union type matching these entries. */ declare const SHELLS: Readonly; //#endregion //#region src/core/cli/compiled.d.ts /** * Executable form of one registered command. */ interface CompiledCommand { /** The very {@linkcode CommandSchema} object the public schema tree holds. */ readonly schema: CommandSchema; /** Action handler, `undefined` for commands that only group subcommands. */ readonly handler: ErasedActionHandler | undefined; /** Derive and middleware steps in registration order. */ readonly steps: readonly ExecutionStep[]; /** Nested subcommands, keyed by name and by every alias. */ readonly subcommands: ReadonlyMap; } /** * Executable state of a CLI program. */ interface CompiledCLI { /** Top-level commands in registration order. */ readonly commands: readonly CompiledCommand[]; /** The default command, `undefined` when none is registered. */ readonly defaultCommand: CompiledCommand | undefined; /** Plugins in registration order. */ readonly plugins: readonly CLIPlugin[]; } //#endregion //#region src/core/cli/help-links.d.ts /** * OSC 8 hyperlink targets for the root-help header. * * Set via `CLIBuilder.links()`; fields left `undefined` are derived from * manifest metadata when `.manifest()` is active. */ interface HelpLinks { /** URL the program name links to (e.g. the repository or homepage). */ readonly name: string | undefined; /** URL the version links to (e.g. the release tag). */ readonly version: string | undefined; } //#endregion //#region src/core/cli/index.d.ts /** * Runtime descriptor for the CLI program. * * Stores the program name, version, description, and registered command schemas.\ * Sealed by {@linkcode createCLISchema} and rebuilt by each {@linkcode CLIBuilder} step. */ interface CLISchema { /** Type-only seal produced by {@link createCLISchema}. */ readonly [schemaBrand]: 'cli'; /** Program name (used in help text, usage lines, and completion scripts). */ readonly name: string; /** * Whether `.run()` should replace `name` with the invoked program name. * * Set via the `cli({ inherit: true })` factory form. */ readonly inheritName: boolean; /** Program version (shown by `--version`). */ readonly version: string | undefined; /** Program description (shown in root help). */ readonly description: string | undefined; /** Schemas of the registered commands, in registration order. */ readonly commands: readonly CommandSchema[]; /** * Schema of the default command dispatched when no subcommand matches. * * When set, the CLI root behaves like a hybrid command group: subcommands * dispatch by name as usual, but empty argv or flags-only argv falls * through to this command instead of showing root help. * * Set via the {@linkcode CLIBuilder.default | .default()} builder method * or the `defaultCommand` field of {@link CLIDefinition}. */ readonly defaultCommand: CommandSchema | undefined; /** * Whether the default command is also exposed as a named top-level route. * * Set by `.default(cmd, { route: true })`. When `true`, `mycli ` * dispatches to the default command (in addition to the bare/flags-only root * surface behavior) and the command is listed in the root `Commands:` * section. When `false` (the default), the default is the root surface only. */ readonly defaultCommandRouted: boolean; /** * Config discovery settings. * * When defined, {@linkcode CLIBuilder.run | .run()} auto-discovers and loads a config file before command dispatch. * * Set via the {@linkcode CLIBuilder.config | .config()} builder method. */ readonly configSettings: ConfigSettings | undefined; /** * Manifest auto-discovery settings. When defined, `.run()` discovers the * nearest manifest (`package.json`, `deno.json`, `jsr.json`, …) and merges * metadata before dispatch. * * Set via the {@linkcode CLIBuilder.manifest | .manifest()} builder method. */ readonly packageJsonSettings: ResolvedManifestSettings | undefined; /** * OSC 8 hyperlink targets for the root-help header (name/version). * * Set via the {@linkcode CLIBuilder.links | .links()} builder method. * Fields left `undefined` are derived from manifest metadata * (`repository` / `homepage`) when manifest discovery ({@linkcode * CLIBuilder.manifest | .manifest()}) is active. */ readonly helpLinks: HelpLinks | undefined; /** Whether built-in `.completions()` registration (command or flag) is active. */ readonly hasBuiltInCompletions: boolean; /** * Eager `--completions ` flag configuration. * * Set when `.completions({ as: 'flag' })` is used instead of the default * `completions` subcommand. When defined, the planner intercepts * `--completions ` before dispatch, prints the script, and exits; * root help advertises the flag in its `Flags:` section. */ readonly completionsFlag: CompletionsFlagConfig | undefined; /** * Consumer-configured root-help defaults. * * Set via the {@linkcode CLIBuilder.help | .help()} builder method and merged * under runtime `options.help` (runtime wins) before rendering. */ readonly helpConfig: HelpConfig | undefined; /** * Flag-parsing behavior settings ({@link ParseOptions}). * * Set via the `cli(name, { flags })` / `cli({ flags })` factory forms. */ readonly flagSettings: ParseOptions | undefined; /** * Which built-in flags the root still owns. * * Every built-in starts `'on'`. Set via the * {@linkcode CLIBuilder.builtins | .builtins()} builder method or the * `builtins` field of {@link CLIDefinition}; a built-in set to `'off'` * releases its tokens to the commands. */ readonly builtins: Builtins; } /** * Options for {@link CLIBuilder.completions}: the generator options plus where * the built-in completion is exposed. */ interface CompletionRegistrationOptions extends CompletionOptions { /** * Where the built-in shell completion is exposed. * * - `'command'` registers a `completions` subcommand (the default). * - `'flag'` exposes an eager `--completions ` flag on the CLI root * instead, keeping the root free of a `completions` subcommand. * * @defaultValue `'command'` */ readonly as?: 'command' | 'flag'; } /** * Configuration for the eager `--completions ` flag. * * Stored in {@link CLISchema} when `.completions({ as: 'flag' })` is used. * */ interface CompletionsFlagConfig { /** Shell targets the flag accepts (mirrors {@link SHELLS}). */ readonly shells: readonly Shell[]; /** Generator options captured at build time (e.g. `functionPrefix`, `rootMode`). */ readonly options: CompletionOptions | undefined; } /** * Consumer-facing root-help configuration set via {@linkcode CLIBuilder.help}. * * Every field is optional; unset fields fall back to built-in defaults and may * be overridden per call through runtime `options.help`. */ interface HelpConfig { /** * Render the default command's arguments and flags inline at the root. * * @defaultValue `true` */ readonly inlineDefault?: boolean; /** * Also list the default command in the root `Commands:` table. * * By default the default command is the root surface and is omitted from the * command list (its args/flags render inline instead). * * @defaultValue `false` */ readonly showDefaultInCommands?: boolean; /** * Show the `Run ' --help' for more information.` hint. * * Defaults to showing the hint only when visible subcommands exist. */ readonly footer?: boolean; /** Maximum line width (columns). */ readonly width?: number; /** Emit OSC 8 hyperlinks in the header when supported. */ readonly hyperlinks?: boolean; /** * Order of flags in the `Flags:` table. * * - `'alphabetical'` — short-aliased flags first, then alphabetical by name. * - `'declaration'` — the order `.flag()` was called. * * Ignored when {@link HelpConfig.sortFlags} is set. * * @defaultValue `'alphabetical'` */ readonly flagOrder?: 'alphabetical' | 'declaration'; /** * Custom comparator over flag long names for the `Flags:` table. When set, * it wins over {@link HelpConfig.flagOrder}. * * @defaultValue `undefined` (use `flagOrder`) */ readonly sortFlags?: (a: string, b: string) => number; /** * Theme overrides for help output, merged over the built-in theme. * * The factory receives the gated ansispeck palette (same instance as * `out.color`), so overrides follow the output channel's color policy. * It is never invoked when color is off — themed help cannot leak escapes * into piped, `--json`, or `NO_COLOR` output. * * @defaultValue `undefined` (built-in theme) */ readonly theme?: HelpThemeFactory; /** * Theme overrides used only by function-form flag and argument descriptions. * Each supplied role merges over the resolved global theme. * * @defaultValue `undefined` (use the global theme) */ readonly descriptionTheme?: HelpThemeFactory; } /** * Config discovery settings for automatic config file loading. * * Stored in {@link CLISchema} and consumed by {@linkcode CLIBuilder.run()} to call * {@link discoverConfig} before dispatching to a command. */ interface ConfigSettings { /** Type-only seal produced by {@link createCLISchema}. */ readonly [schemaBrand]: 'config'; /** * Application name used to build config search paths. * * Search paths: `.{appName}.json` (cwd), `{appName}.config.json` (cwd), * and `{configDir}/{appName}/config.json` where `configDir` is * `$XDG_CONFIG_HOME` / `~/.config` on Unix or `%APPDATA%` / * `%USERPROFILE%\\AppData\\Roaming` on Windows. */ readonly appName: string; /** Additional format loaders beyond the built-in JSON loader. */ readonly loaders: readonly FormatLoader[] | undefined; } /** * Manifest auto-discovery settings — the resolved/normalized shape stored in * the schema. * * Stored in {@link CLISchema} and consumed by `CLIBuilder.run()` to * call {@link discoverManifest} before dispatching to a command. * * Note: the schema FIELD name (`packageJsonSettings`) keeps its `packageJson` * prefix for backward compatibility — renaming it would break consumers reading * `app.schema.packageJsonSettings`. The type itself is generically named (it * holds discovery config for any manifest — `package.json`, `deno.json`, * `jsr.json`). */ interface ResolvedManifestSettings { /** * Infer CLI name from manifest `bin` keys or `name` field. * * When `true`, the discovered name replaces the `cli(name)` value. * Explicit `.version()`/`.description()` calls still take precedence * over discovered values. * * @defaultValue `false` */ readonly inferName: boolean; /** * Strip a leading `@scope/` from the inferred `name` fallback. * * Only consulted when {@link ResolvedManifestSettings.inferName | `inferName`} * is `true` and the name comes from the manifest `name` field (not a `bin` * key, which is never scoped). * * @defaultValue `true` */ readonly stripScope: boolean; /** * Explicit filesystem anchor for discovery; overrides `adapter.cwd`. * * Resolved to a string path before storage. When set, `discoverManifest` * walks up from here instead of the runtime cwd. Required for installable * CLIs whose version should reflect THEIR OWN package, not the consumer's * working directory. */ readonly from: string | undefined; /** * Candidate manifest filenames, in per-directory priority order * (e.g. `['deno.json', 'deno.jsonc', 'jsr.json']` for a Deno CLI). */ readonly files: readonly string[]; /** * Pre-loaded data; skips filesystem discovery, uses values verbatim. * * @example * ```ts * import pkg from './package.json' with { type: 'json' }; * * cli('mycli').manifest(pkg); * ``` */ readonly data: PackageJsonData | undefined; } /** * Input shape for {@link CLISchema.configSettings}, accepted by * {@link createCLISchema}. * * Mirrors {@link ConfigSettings} with `loaders` optional. */ interface ConfigSettingsDefinition { /** Application name used to build config search paths. */ readonly appName: string; /** * Additional format loaders beyond the built-in JSON loader. * @defaultValue `undefined` */ readonly loaders?: readonly FormatLoader[] | undefined; } /** * Input shape accepted by {@link createCLISchema}. * * Every field except `name` is optional. Commands accept either * {@link CommandDefinition | definitions} or already-built * {@link CommandSchema | schemas}. Plugins are execution state and have no * definition field. */ interface CLIDefinition { /** Program name used in help text, usage lines, and completion scripts. */ readonly name: string; /** * Whether `.run()` should replace `name` with the invoked program name. * @defaultValue `false` */ readonly inheritName?: boolean | undefined; /** * Program version shown by `--version`. * @defaultValue `undefined` */ readonly version?: string | undefined; /** * Program description shown in root help. * @defaultValue `undefined` */ readonly description?: string | undefined; /** * Whether the default command is also exposed as a named top-level route. * @defaultValue `false` */ readonly defaultCommandRouted?: boolean | undefined; /** * Config discovery settings, as a definition or an already-built value. * @defaultValue `undefined` */ readonly configSettings?: ConfigSettingsDefinition | ConfigSettings | undefined; /** * Manifest auto-discovery settings. * @defaultValue `undefined` */ readonly packageJsonSettings?: ResolvedManifestSettings | undefined; /** * OSC 8 hyperlink targets for the root-help header. * @defaultValue `undefined` */ readonly helpLinks?: HelpLinks | undefined; /** * Whether built-in `.completions()` registration is active. * @defaultValue `false` */ readonly hasBuiltInCompletions?: boolean | undefined; /** * Eager `--completions ` flag configuration. * @defaultValue `undefined` */ readonly completionsFlag?: CompletionsFlagConfig | undefined; /** * Consumer-configured root-help defaults. * @defaultValue `undefined` */ readonly helpConfig?: HelpConfig | undefined; /** * Flag-parsing behavior settings. * @defaultValue `undefined` */ readonly flagSettings?: ParseOptions | undefined; /** * Which built-in flags the root keeps. * @defaultValue every built-in `'on'` */ readonly builtins?: BuiltinsConfig | undefined; /** * Registered command definitions or built schemas, in registration order. * @defaultValue `[]` */ readonly commands?: readonly (CommandDefinition | CommandSchema)[] | undefined; /** * Default command dispatched when no subcommand matches. * @defaultValue `undefined` */ readonly defaultCommand?: CommandDefinition | CommandSchema | undefined; } /** * Create a {@link CLISchema} from a plain definition object. * * Most consumers should prefer {@link cli | cli()}, which returns a * {@link CLIBuilder} carrying the execution graph. `createCLISchema()` builds a * description only: it normalizes commands recursively through * {@link createCommandSchema}, so handlers and execution steps are not part of * the result and the schema cannot be executed. * * Feeding a built schema back in produces a deep-equal schema. * * @param definition - Program name plus optional metadata and commands. * @returns A fully populated {@link CLISchema}. * @throws {CLIError} With code `'INVALID_SCHEMA'` when the program name is * empty, a `builtins` entry is neither `'on'` nor `'off'`, a command name at * any depth is empty, a flag or arg at any depth is named `__proto__`, or a * flag record at any depth has a replaced prototype. * @throws {CLIError} With code `'FLAG_NAME_COLLISION'` when two flags on one * command share a spelling, at any depth of the command tree. * @throws {CLIError} With code `'PROPAGATED_FLAG_COLLISION'` when a command flag * shadows a spelling propagated from an ancestor command. * @throws {CLIError} With code `'INVALID_BUILDER_STATE'` when a positional comes * after a variadic one, or `'DUPLICATE_STDIN_INPUT'` when two inputs on one * command consume stdin and either is exclusive. * @throws {CLIError} With code `'RESERVED_FLAG'` when a command spells a flag * the same way as a root-owned flag (`--json`, `--quiet`/`-q`, `--help`/`-h`, * `--version`/`-V` once `version` is set, and `--completions` once * `completionsFlag` is set), by name, alias, or negated spelling. A built-in * set to `'off'` in `builtins` is not reserved. * * @example * ```ts * const schema = createCLISchema({ * name: 'mycli', * version: '1.0.0', * commands: [{ name: 'deploy', flags: { force: { kind: 'boolean' } } }], * }); * ``` */ declare function createCLISchema(definition: CLIDefinition): CLISchema; /** * Options for {@linkcode CLIBuilder.execute | .execute()}, the process-free * execution surface. * * Derives from {@linkcode RunOptions} with every input injected explicitly. */ interface CLIExecuteOptions extends RunOptions {} /** * Options for {@linkcode CLIBuilder.run | .run()}. * * Derives from {@linkcode CLIExecuteOptions}, adding the CLI-level runtime adapter. */ interface CLIRunOptions extends CLIExecuteOptions { /** * Runtime adapter providing platform-specific I/O, argv, env, etc. * * Replaces the default Node adapter. */ readonly adapter?: RuntimeAdapter; } /** * Inputs for {@linkcode resolveRenderContext}. Pass the host facts (TTY * status, environment) and any explicit overrides; the resolver applies the * same gating `.execute()`/`.run()` feed into the output channel. */ interface RenderContextOptions { /** * Whether stdout is connected to a TTY (e.g. `process.stdout.isTTY`). * * @defaultValue `false` */ readonly isTTY?: boolean; /** * JSON mode when argv carries no root `--json`. An explicit `--json=false` * in argv wins over this. * * @defaultValue detected from a pre-separator `--json` in `argv` */ readonly jsonMode?: boolean; /** * Output verbosity when argv carries no root `--quiet`/`-q`. An explicit * `--quiet=false` in argv wins over this. * * @defaultValue detected from a pre-separator `--quiet`/`-q` in `argv`, * otherwise `'normal'` */ readonly verbosity?: Verbosity; /** * Explicitly enable or disable colors, winning over the auto-gate. * * @defaultValue auto — `isTTY && !jsonMode` and environment support */ readonly color?: boolean; /** * Environment variables consulted for `NO_HYPERLINKS`/`FORCE_HYPERLINKS` * (e.g. `process.env`). * * @defaultValue `{}` */ readonly env?: Readonly>; /** * Which built-in flags the CLI still owns, matching its * {@linkcode CLIBuilder.builtins | .builtins()} call. A built-in set to * `'off'` is not read out of `argv` here either. * * @defaultValue every built-in `'on'` */ readonly builtins?: BuiltinsConfig; } /** * Seals {@linkcode RenderContext} against structural construction outside the * framework. * * @internal */ declare const renderContextBrand: unique symbol; /** * The output decisions the framework will make for a given argv, resolved * before `.run()`. * * `RenderContext` is a framework-created, non-exhaustive value: obtain * instances from {@linkcode resolveRenderContext} — do not implement it. New * readonly members may be added in minor releases. */ interface RenderContext { /** Framework-construction seal. Obtain values from `resolveRenderContext()`; do not implement this interface. */ readonly [renderContextBrand]: never; /** Whether a pre-separator `--json` puts the run in JSON mode. */ readonly jsonMode: boolean; /** Active verbosity after pre-separator `--quiet`/`-q` detection. */ readonly verbosity: Verbosity; /** The TTY status the output channel will carry. */ readonly isTTY: boolean; /** * The gated ANSI palette the output channel will expose as `out.color` — * identity formatters when color is off; `color.isColorSupported` is the * boolean gate. */ readonly color: Colors; /** Whether OSC 8 hyperlinks should be emitted (see `out.isHyperlinkSupported`). */ readonly isHyperlinkSupported: boolean; } /** * Resolve the render context for content built before `.run()`. * * Content styled ahead of execution — hand-rendered banners, custom help, or * anything else emitted outside an action handler — has no `out` to consult, * which pushes consumers into re-deriving the framework's decisions from raw * argv (`argv.includes('--json')` misreads a post-`--` literal). This probe * runs the same composition `.execute()`/`.run()` feed into the output * channel — `--`-aware `--json` detection, the color gate, and the hyperlink * override — so pre-run styling matches the channel that will render. * * @param argv - Raw argv tokens (NOT including the binary/script path, * i.e. equivalent to `process.argv.slice(2)`). * @param options - Host facts and overrides. * @returns The resolved output decisions. * * @example * ```ts * const ctx = resolveRenderContext(process.argv.slice(2), { * isTTY: process.stdout.isTTY === true, * env: process.env, * }); * const banner = ctx.color.bold('mycli'); * ``` */ declare function resolveRenderContext(argv: readonly string[], options?: RenderContextOptions): RenderContext; /** * Options for {@linkcode CLIBuilder.default | .default()}. */ interface DefaultCommandOptions { /** * Also expose the default command under its own name as a routable * top-level command. * * By default a default command is the root *surface* only — `mycli` (bare or * flags-only) runs it, but `mycli ` does not route to it (the token * is consumed as the default's first positional). Set `route: true` for CLIs * that intentionally expose both forms: `mycli` and `mycli ` become * the same command, and it is listed in the root `Commands:` section beside * its siblings. * * The name wins over positional interpretation: with `route: true`, a * positional value equal to the command's own name is consumed as the route, * so pass such a value after `--` (`mycli -- `). * * @defaultValue `false` */ readonly route?: boolean; } /** * Immutable CLI program builder. * * Registers commands, handles root-level `--help`/`--version`, and * dispatches to the matched command based on argv. * * Two execution paths: * - `.execute(argv, options?)` — testable, returns {@linkcode RunResult} * - `.run(options?)` — production entry, reads `process.argv`, exits process * * @example * ```ts * import { cli, command, flag, arg } from '@kjanat/dreamcli'; * * const deploy = command('deploy') * .arg('target', arg.string()) * .flag('force', flag.boolean().alias('f')) * .action(({ args, flags, out }) => { * out.log(`Deploying ${args.target}...`); * }); * * cli('mycli') * .version('1.0.0') * .command(deploy) * .run(); * ``` */ declare class CLIBuilder { /** @internal Runtime schema descriptor. */ readonly schema: CLISchema; private constructor(); /** * Build a CLI builder around a schema and its compiled execution graph. * * @param schema - Runtime schema descriptor. * @param compiled - Compiled commands, default command, and plugins. * @returns The builder, with its compiled state registered. * * @internal */ static _from(schema: CLISchema, compiled: CompiledCLI): CLIBuilder; /** * Set the program version (shown by `--version`). * * Declaring a version also reserves `--version`/`-V` on every registered * command, so this rejects a command that already declares either spelling. * * @param v - Semantic version string. * @returns The builder (for chaining). * @throws {@link CLIError} `RESERVED_FLAG` when a registered command spells * `--version` or `-V` as a flag name, an alias, or a negated spelling. */ version(v: string): CLIBuilder; /** * Choose which built-in flags the root keeps. * * `--help`/`-h`, `--json`, and `--quiet`/`-q` are root-owned by default and * never reach a command handler. Setting one to `'off'` releases every * spelling it answers to: the root stops reading it out of argv, root help * stops advertising it under `Global options:`, and a command may declare it * as an ordinary flag. `RunOptions.jsonMode` and `RunOptions.verbosity` * keep working either way, since only argv-driven activation is disabled. * * `version` and `completions` are absent by design, since `.version()` and * `.completions()` are opt-in and a CLI declines those by omission. * * Call multiple times to set built-ins incrementally; the last mode given for * a built-in wins. Turning one back `'on'` re-checks every registered command * for a collision. Call this **before** registering the commands that declare * a released flag, since `.command()` rejects the flag while the root still * owns the token. * * @param config - Built-in modes to apply over the current state. * @returns The builder (for chaining). * @throws {@link CLIError} `INVALID_SCHEMA` when a value is neither `'on'` nor `'off'`. * @throws {@link CLIError} `RESERVED_FLAG` when a registered command already * declares a flag spelled like a built-in this call keeps or restores. * @see {@link BuiltinsConfig} for the accepted keys and modes. * @see https://dreamcli.kjanat.dev/guide/output#taking-a-built-in-over * * @example * ```ts * // `--json` names the document the command validates. * cli('schematool') * .builtins({ json: 'off' }) * .default( * command('validate') * .flag('json', flag.string().describe('Document to validate')) * .action(({ flags, out }) => out.log(flags.json)), * ) * .run(); * ``` */ builtins(config: BuiltinsConfig): CLIBuilder; /** * Set the program description (shown in root help). * * @param text - Short description displayed in root help output. * @returns The builder (for chaining). */ description(text: string): CLIBuilder; /** * Make the root-help header clickable with OSC 8 hyperlinks. * * Links the program name and version on the first line of root `--help` * output in terminals that support * [OSC 8 hyperlinks](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda). * The escapes are only emitted when stdout is a TTY (overridable via * `options.help.hyperlinks`), and only in the header — usage lines, the * `--help` hint, the commands table, and completion scripts stay plain. * * URLs not provided here are derived from manifest metadata when * `.manifest()` is active (works with both filesystem discovery and * pre-loaded data): * - **name** → normalized `repository` URL, falling back to `homepage` * - **version** → forge release tag (`{repo}/releases/tag/v{version}` on * GitHub, `{repo}/-/releases/v{version}` on GitLab) * * @param links - Explicit URLs; omit to derive everything from the manifest. * @returns The builder (for chaining). * * @example * ```ts * // Derive both links from the manifest repository/homepage: * cli('mycli') * .manifest() * .links() * .run(); * * // Explicit URLs (no package.json required): * cli('mycli') * .version('1.0.0') * .links({ * name: 'https://github.com/me/mycli', * version: 'https://github.com/me/mycli/releases/tag/v1.0.0', * }) * .run(); * ``` */ links(links?: { readonly name?: string | URL; readonly version?: string | URL; }): CLIBuilder; /** * Configure root-help rendering defaults. * * Stored on the schema and merged **under** any runtime `options.help` * (runtime wins). Call multiple times to set fields incrementally. * * @param config - Help rendering options (see {@link HelpConfig}). * @returns The builder (for chaining). * * @example * ```ts * // Echo the default command under Commands and never show the footer: * cli('mycli') * .help({ showDefaultInCommands: true, footer: false }) * .default(serve) * .run(); * ``` */ help(config: HelpConfig): CLIBuilder; /** * Enable automatic config file discovery. * * When enabled, `.run()` probes standard paths before dispatching, * first match wins, no merging: * 1. Project scope — for `$CWD` and each ancestor directory up to the * filesystem root, nearest first: * `.{appName}.json`, `{appName}.config.json`, `.config/{appName}.json` * 2. User scope — `{dir}/{appName}/config.json` for each user config * root (`$XDG_CONFIG_HOME` / `~/.config` on Unix, plus * `~/Library/Application Support` on macOS, * `%APPDATA%` / `%USERPROFILE%\\AppData\\Roaming` on Windows) * 3. System scope — `/etc/{appName}/config.json` on Linux and macOS * * The user can override the path via `--config ` or `--config=`. * * Loaded config feeds into the resolution chain * (CLI → env → **config** → prompt → default) for flags that * declare `.config('dotted.path')`. * * Has no effect in `.execute()` (which receives config via * `options.config` directly). * * @param appName - Name used to build search paths. * @param loaders - Additional {@link FormatLoader}s (JSON is built-in). * @returns The builder (for chaining). */ config(appName: string, loaders?: readonly FormatLoader[]): CLIBuilder; /** * Register a custom config format loader. * * Adds a {@link FormatLoader} incrementally — call multiple times to * register multiple formats. Loaders registered later for the same * extension override earlier ones. * * Requires `.config()` to have been called first (sets the app name). * * @param loader - Format loader (or extensions + parse function). * @returns The builder (for chaining). * * @example Bun built-in parsers * ```ts * import { configFormat } from '@kjanat/dreamcli'; * * cli('myapp') * .config('myapp') * .configLoader(configFormat(['yaml', 'yml'], Bun.YAML.parse)) * .configLoader(configFormat(['toml'], Bun.TOML.parse)) * .run(); * ``` * * @example npm package parsers * ```ts * import { configFormat } from '@kjanat/dreamcli'; * import { parse as parseYaml } from 'yaml'; * import { parse as parseTOML } from '@iarna/toml'; * * cli('myapp') * .config('myapp') * .configLoader(configFormat(['yaml', 'yml'], parseYaml)) * .configLoader(configFormat(['toml'], parseTOML)) * .run(); * ``` */ configLoader(loader: FormatLoader): CLIBuilder; /** * Enable manifest metadata from pre-loaded data. * * Pass an already-imported manifest (`package.json`, `deno.json`, `jsr.json`) * to skip filesystem discovery entirely — useful for bundled or installable * CLIs where the version should be locked at build time. The data's * `version`/`description` are merged into the CLI schema immediately, so this * form works in **both** `.run()` and `.execute()` (the filesystem-free path). * Explicit `.version()`/`.description()` calls still take precedence, and the * data form does not infer the CLI name — `inferName` / `{ scope }` are * available only on the discovery (settings) form. For a pre-loaded manifest * whose scoped `name` should drive the CLI name, set the name explicitly via * `cli(name)` (or call {@link inferCliName} on the data yourself). * * Detected by field shape: an object carrying at least one of * `name`/`version`/`description`/`bin`/`homepage`/`repository`. An empty `{}` * or a settings-shaped object falls through to the settings overload. * * @param data - Pre-loaded manifest metadata. * @throws {@link CLIError} `RESERVED_FLAG` when the data carries a version and * a registered command spells `--version` or `-V` as a flag name, an alias, * or a negated spelling. * * @example * ```ts * import denoCfg from './deno.json' with { type: 'json' }; * * // No filesystem; works in .run() AND .execute(): * cli('mycli') * .manifest(denoCfg) * .command(deploy) * .run(); * ``` */ manifest(data: PackageJsonData): CLIBuilder; /** * Enable automatic manifest metadata discovery. * * When enabled, `.run()` walks up from `cwd` (or {@link ManifestSettings.from}) * to find the nearest manifest among {@link ManifestSettings.files} and merges * its `version`/`description` into the CLI schema. Explicit `.version()` / * `.description()` calls always take precedence. * * Files are parsed as JSON with a JSONC fallback — `package.json`, `deno.json`, * `jsr.json`, and `deno.jsonc` all qualify, including files with `//` / block * comments or trailing commas. A file that fails both parses is skipped * (discovery keeps walking). * * Has no effect in `.execute()` (filesystem-free) — use the data overload. * * A discovered version lands at `.run()` time, past every build-time check, so * the `RESERVED_FLAG` guard re-runs there. A registered command that spells * `--version` or `-V` as a flag name, an alias, or a negated spelling then fails * startup, writing the error and its suggestion to stderr (a JSON error envelope * on stdout under `--json`) and exiting with the error's exit code instead of * throwing. * * @param settings - Optional settings: * - `files`: candidate manifest filenames in priority order * (default `['package.json']`). * - `inferName`: infer the CLI name from `bin` keys or `name`. Pass * `{ scope: 'keep' }` to keep a leading `@scope/` (stripped by default). * - `from`: anchor discovery to a file/URL/path instead of `cwd`. Pass * `import.meta.url` for installable CLIs that must report THEIR OWN * version. If the consumer's ambient `ImportMeta` omits `url`, pass * `import.meta` instead. Also accepts string paths, `file:` URL strings, * or `URL` instances. * * @example * ```ts * // Deno CLI: discover OUR deno.json (then jsr.json), keep the scope in name: * cli('mycli') * .manifest({ * files: ['deno.json', 'jsr.json'], * from: import.meta.url, * inferName: { scope: 'keep' }, * }) * .command(deploy) * .run(); * ``` */ manifest(settings?: ManifestSettings): CLIBuilder; /** * Register a command with the CLI program. * * The command's schema joins {@link CLISchema.commands}; its handler and * subcommand tree are compiled into the builder's execution graph. * * @param cmd - {@link CommandBuilder} to register. * @returns The builder (for chaining). * @throws {@link CLIError} `RESERVED_FLAG` when the command, or one of its * nested subcommands, spells a root-owned flag (`--json`, `--quiet`/`-q`, * `--help`/`-h`, and `--version`/`-V` once * {@link CLIBuilder.version | .version()} is set) as a flag name, an alias, * or a negated spelling. A built-in released through * {@link CLIBuilder.builtins | .builtins()} is not reserved. */ command>, A extends Record>, C extends Record>(cmd: CommandBuilder): CLIBuilder; /** * Register a command as the default — dispatched when no subcommand is given. * * The CLI root behaves like a hybrid command group: named subcommands * dispatch normally, but empty argv or flags-only argv falls through to * this command instead of showing root help. * * The default command is the CLI's root *surface*: its flags and arguments * are rendered inline in root help. By default it is **not** a named * subcommand — it cannot be invoked by its own name (`mycli mycmd` does not * route to it) and it is omitted from the root `Commands:` list (re-enable * listing with `.help({ showDefaultInCommands: true })`). Only one default is * allowed. * * Pass `{ route: true }` to *also* expose the command under its own name as a * routable top-level command: `mycli` and `mycli ` then run the same * command object, and it is listed in `Commands:` beside its siblings. This * avoids duplicating the command just to keep both forms equivalent during a * v3 migration. * * @example * ```ts * // Single-command CLI — no subcommand name needed: * // mytool --force production * cli('mytool') * .default(deploy) * .run(); * * // Multi-command CLI with a default: * // mytool production → runs deploy * // mytool status → runs status * cli('mytool') * .default(deploy) * .command(status) * .run(); * * // Default that is also a named route — `mytool` and `mytool status` are * // the same surface, and `status` is listed beside `logs`: * cli('mytool') * .default(status, { route: true }) * .command(logs) * .run(); * ``` * * @param cmd - {@link CommandBuilder} to register as the default. * @param options - Default-command options. `{ route: true }` also exposes * the command under its own name (see {@link DefaultCommandOptions}). * @returns The builder (for chaining). * @throws {@link CLIError} `RESERVED_FLAG` when the command, or one of its * nested subcommands, spells a root-owned flag (`--json`, `--quiet`/`-q`, * `--help`/`-h`, and `--version`/`-V` once * {@link CLIBuilder.version | .version()} is set) as a flag name, an alias, * or a negated spelling. A built-in released through * {@link CLIBuilder.builtins | .builtins()} is not reserved. */ default>, A extends Record>, C extends Record>(cmd: CommandBuilder, options?: DefaultCommandOptions): CLIBuilder; /** * Register a CLI plugin. * * Plugins run in registration order. At each lifecycle stage, all hooks for * the first plugin run before hooks for the second plugin, and so on. * * @param definition - A frozen {@link CLIPlugin} created by {@link plugin}. * @returns The builder (for chaining). * @see {@link plugin} to construct plugin definitions. */ plugin(definition: CLIPlugin): CLIBuilder; /** * Register built-in shell completion. * * By default (`{ as: 'command' }`) this registers a `completions` subcommand * that accepts a `shell` argument and writes the script to stdout. With * `{ as: 'flag' }` it instead exposes an eager `--completions ` flag on * the CLI root — no subcommand is registered, so a default command stays the * lone root surface. The flag may be given without a value to auto-detect the * shell from `$SHELL` / `$PSModulePath`. * * In subcommand mode, call this **after** registering all other commands so * the completion script includes the full command set: that path snapshots the * schema (and completion options) at call time, so commands registered * afterwards will not appear in that subcommand's generated script. In flag * mode, generation runs at execution time from the final builder schema, so * registration order does not matter. * * @example * ```ts * // Subcommand form (default): * cli('mycli') * .version('1.0.0') * .command(deploy) * .completions({ rootMode: 'surface' }) * .run(); * * // Eager-flag form, ideal for single-command CLIs: * cli('mycli') * .completions({ as: 'flag' }) * .default(serve) * .run(); * ``` */ completions(options?: CompletionRegistrationOptions): CLIBuilder; /** * Execute the CLI program against explicit argv. * * This is the testable execution path — no process state is touched. * Returns a structured {@linkcode RunResult} with exit code and captured output. * * @param argv - Raw argv tokens (NOT including the binary/script path, * i.e. equivalent to `process.argv.slice(2)`). * @param options - Injectable runtime state. * @returns Structured result with exit code and captured output. */ execute(argv: readonly string[], options?: CLIExecuteOptions): Promise; /** * Run the CLI program as a production entry point. * * Reads argv from the runtime adapter, dispatches to the matched * command, writes output to real streams, and exits the process. * * This is the **only** place that touches process state (via the * adapter). For testing, use `.execute()` instead — or provide a * test adapter via `options.adapter`. * * Defaults to {@linkcode createAdapter | createAdapter()} when no adapter is provided, * which auto-detects the runtime (Node.js, Bun) and creates * the appropriate adapter. * * @param options - Optional runtime configuration including adapter. */ run(options?: CLIRunOptions): Promise; } /** * CLI-name inference control for {@link ManifestSettings.inferName}. * * - `false` (or omitted): do not infer the name. * - `true`: infer, stripping a leading `@scope/` from the `name` fallback. * - `{ scope: 'keep' }`: infer, keeping the full scoped name. * - `{ scope: 'strip' }`: infer, stripping the scope (explicit form of `true`). * * `scope` is required in the object form: an empty `{}` is rejected so that an * options object can never silently enable inference (use `true` for that). */ type InferNameOption = boolean | { readonly scope: 'keep' | 'strip'; }; /** Discovery settings accepted by {@link CLIBuilder.manifest}. */ interface ManifestSettings { /** Infer the CLI name from `bin` keys or `name`. @defaultValue `false` */ readonly inferName?: InferNameOption; /** * Anchor discovery to a file/URL/path instead of `cwd`. Normally, pass * `import.meta.url`. Pass `import.meta` whole as a compatibility form when a * project `tsconfig.json` `lib` override drops the runtime's ambient * `ImportMeta` extras and direct `.url` access does not type-check. */ readonly from?: string | URL | ImportMeta; /** * Candidate manifest filenames in priority order — NOT npm's `files` publish * globs. Discovery probes each name per directory and takes the first that * parses. * * @defaultValue `['package.json']` */ readonly files?: readonly string[]; } /** * Options for the `cli({...})` factory form. * * This form is useful when the displayed CLI name should be inferred from the * current runtime invocation instead of always being hard-coded. */ interface CLIOptions { /** * Explicit fallback CLI name. * * Used by `.execute()`, and by `.run()` when runtime name inheritance is * disabled or the invocation name cannot be inferred. * * @defaultValue `'cli'` */ readonly name?: string; /** * Replace `name` with the invoked program basename during `.run()`. * * Examples: * - `node ./bin/mycli.ts` → `mycli.ts` * - `/usr/local/bin/mycli` → `mycli` * * @defaultValue `false` */ readonly inherit?: boolean; /** * Flag-parsing behavior settings (e.g. `{ caseParity: false }` to accept * only declared flag spellings). Shares the {@link ParseOptions} contract * used by `parse()` and `RunOptions.flags`. */ readonly flags?: ParseOptions; } /** * Create a new CLI program builder. * * The CLI name is used in help text, usage lines, and generated completion scripts. * * @example * ```ts * cli('mycli') * .version('1.0.0') * .description('My awesome tool') * .command(deploy) * .command(login) * .run(); * * cli({ inherit: true }) * .command(deploy) * .run(); * ``` */ declare function cli(name: string, options?: Omit): CLIBuilder; /** Create a new CLI program builder from an options object. */ declare function cli(options: CLIOptions): CLIBuilder; /** * Report whether the calling module is the process entrypoint, cross-runtime. * * Node, Bun, and Deno set `import.meta.main` on the module invoked directly; * projects with the runtime's ambient types can read that property directly. * This helper is a compatibility form for projects whose `tsconfig.json` `lib` * override drops those `ImportMeta` extras: passing `import.meta` whole avoids * a direct `.main` access without requiring global augmentation. * * @param meta - The calling module's `import.meta`. * @returns `true` when the module was run as the entrypoint. * * @example * ```ts * if (isMainModule(import.meta)) cli('mycli').command(deploy).run(); * ``` */ declare function isMainModule(meta: ImportMeta): boolean; //#endregion export { SHELLS as C, HelpLinks as S, CompletionOptions as T, ResolvedManifestSettings as _, CLIRunOptions as a, isMainModule as b, CompletionsFlagConfig as c, DefaultCommandOptions as d, HelpConfig as f, RenderContextOptions as g, RenderContext as h, CLIOptions as i, ConfigSettings as l, ManifestSettings as m, CLIDefinition as n, CLISchema as o, InferNameOption as p, CLIExecuteOptions as r, CompletionRegistrationOptions as s, CLIBuilder as t, ConfigSettingsDefinition as u, cli as v, Shell as w, resolveRenderContext as x, createCLISchema as y };