Skip to content

command()

function command(cmd: cli.Command): cli.Command

command() returns its argument unchanged. Its whole job is type inference: it lets you define a command as a standalone value and still get run(args) typed from the arguments and options you declared.

import { command } from 'clibuilder'
const build = command({
name: 'build',
description: 'build the project',
options: { watch: { description: 'rebuild on change', alias: ['w'] } },
run(args) {
this.ui.info(args.watch ? 'watching' : 'building once')
}
})

Commands passed inline to .command() or .default() are inferred without it — reach for command() when the command lives in its own variable or its own file.

Field Type Description
name string The command’s name on the command line. Required for named commands; omitted for a .default() command.
description string Shown in the help message.
alias string[] Alternate names — alias: ['rm'] makes app remove answer to app rm.
arguments Argument[] Positional arguments, in order.
options Options Named options, keyed by option name.
config z.ZodTypeAny The schema this command’s config must satisfy. Declaring it triggers the config load.
context Record<string, any> Arbitrary values handed back on this.context — the seam for injecting I/O in tests.
commands Command[] Sub-commands.
onUsageError UsageErrorHandler Takes over how usage errors are reported for this command and its sub-commands. See Reporting usage errors yourself.
run function What the command does.

A command must have either a run or a commands. A command with commands and no run is a group: invoking it prints its help message.

type Argument = {
name: string
description: string
type?: z.ZodType<any>
}

Positional, matched in declaration order. type defaults to string. An array type makes the argument variadic, consuming the remaining positionals; z.optional() makes it optional. Argument values are coerced to the declared type — see Arguments & Options.

arguments: [
{ name: 'src', description: 'source file' },
{ name: 'dest', description: 'destination', type: z.optional(z.string()) }
]
type Options = Record<string, {
description: string
type?: z.ZodType<any>
default?: z.infer<Type>
alias?: Array<string | { alias: string; hidden: boolean }>
conflicts?: string[] // options this one cannot be used with
}>

type defaults to a flag (boolean | undefined). Option values are coerced to the declared type, and a value that fails is a usage error.

options: {
port: { description: 'port to listen on', type: z.number(), default: 3000, alias: ['p'] },
quiet: { description: 'suppress output', alias: ['q', { alias: 'shh', hidden: true }] }
}

A hidden alias works but is left out of the help message.

run(this: RunContext, args: RunArgs): Promise<any> | any

Declare it as a method, not an arrow function — this is what carries the command’s context.

Property Type Description
this.ui UI Output — info, warn, error, debug, showHelp, showVersion.
this.config z.infer<ConfigType> The loaded, validated config. undefined when the command declared no config.
this.cwd string The directory the CLI was invoked from.
this.keywords string[] The CLI’s plugin keywords.
this.context Context Whatever the command declared as context.

An object holding every declared argument and option by name, plus the built-in optionsargs.help is always present.

Whatever run() returns (or resolves to) becomes the resolved value of parse(), and the result from testCommand().

The argument a plugin’s activate() receives:

type PluginActivationContext = {
addCommand(command: cli.Command): void
register<T>(key: ValueKey<T> | CollectionKey<T>, value: T): void
get<T>(key: ValueKey<T>): T | undefined
get<T>(key: CollectionKey<T>): readonly Contribution<T>[]
has(key: RegistryKey<unknown>): boolean
host: { name: string; version: string }
}
import { command, type PluginActivationContext } from 'clibuilder'
export function activate({ addCommand }: PluginActivationContext) {
addCommand(command({ name: 'sing', description: 'sing a song', run() { this.ui.info('🎵') } }))
}

defineKey() creates a single-value capability key; the first plugin to register one wins. Use defineCollectionKey() for values contributed by multiple plugins. Command run() methods receive the same read-only registry as this.registry, which is the preferred place to resolve values.