Bunli
API Reference

createCLI

Create a new CLI instance with configuration

Creates a new CLI instance with automatic configuration loading from bunli.config.ts.

Syntax

function createCLI<TPlugins extends readonly BunliPlugin[] = []>(
  configOverride?: BunliConfigInput & {
    plugins?: TPlugins;
    generated?: string | boolean;
  },
  runtimeDeps?: CreateCLIRuntimeDeps,
): Promise<CLI<MergeStores<TPlugins>>>;

Type Parameters

TPlugins

An array of typed plugin instances. When provided, the CLI's type signature includes the merged store type from all plugins, enabling full type safety for context.store in handlers.

Parameters

configOverride (optional)

Override specific configuration values or provide configuration inline.

interface BunliConfigInput {
  name?: string;
  version?: string;
  description?: string;
  commands?: {
    entry?: string | string[];
    directory?: string;
    generateReport?: boolean;
  };
  plugins?: PluginConfig[];
  build?: BuildConfig;
  dev?: DevConfig;
  test?: TestConfig;
  release?: ReleaseConfig;
  tui?: {
    renderer?: {
      bufferMode?: "alternate" | "standard";
    };
    image?: {
      mode?: "off" | "auto" | "on";
      protocol?: "auto" | "kitty";
      width?: number;
      height?: number;
    };
  };
  help?: {
    renderer?: HelpRenderer;
  };
}

New in Bunli 0.4.0: Configuration is automatically loaded from bunli.config.ts. You only need to provide overrides for runtime-specific settings like plugins with custom options.

Returns

A CLI instance with the following methods:

interface CLI<TStore = any> {
  // Register a command
  command<TCommandStore = unknown>(cmd: Command<any, TCommandStore>): void;

  // Initialize the CLI (no-op, kept for lifecycle symmetry)
  init(): Promise<void>;

  // Run the CLI with arguments
  run(argv?: string[]): Promise<void>;

  // Execute a named command programmatically
  execute(commandName: string, args?: string[]): Promise<void>;
  execute<T extends keyof RegisteredCommands>(
    commandName: T,
    options: CommandOptions<T>,
  ): Promise<void>;
  execute<T extends keyof RegisteredCommands>(
    commandName: T,
    args: string[],
    options: CommandOptions<T>,
  ): Promise<void>;
}

Examples

With automatic config loading from bunli.config.ts:

// cli.ts
import { createCLI } from "@bunli/core";
import greetCommand from "./commands/greet.js";

const cli = await createCLI();

cli.command(greetCommand);

await cli.run();
// bunli.config.ts
import { defineConfig } from "@bunli/core";

export default defineConfig({
  name: "my-cli",
  version: "1.0.0",
  description: "My awesome CLI tool",
});

With Typed Plugins

When using plugins, pass them as a const tuple to get full type safety:

import { createCLI } from "@bunli/core";
import { aiAgentPlugin } from "@bunli/plugin-ai-detect";
import { configMergerPlugin } from "@bunli/plugin-config";

const cli = await createCLI({
  plugins: [aiAgentPlugin(), configMergerPlugin({ sources: [".myrc.json"] })] as const,
});

// Handlers now have typed access to plugin stores via context.store

With Explicit Registration

// cli.ts
import { createCLI } from "@bunli/core";
import build from "./commands/build.js";
import test from "./commands/test.js";
import deploy from "./commands/deploy.js";

const cli = await createCLI();

cli.command(build);
cli.command(test);
cli.command(deploy);

await cli.run();

Programmatic Execution

Use execute() to run commands from code without going through the CLI argv parsing:

const cli = await createCLI({
  plugins: [myPlugin] as const,
});

cli.command(myCommand);

// Execute with positional args only
await cli.execute("my-command", ["--flag", "value"]);

// Execute with typed options (requires generated types)
await cli.execute("deploy", { env: "production", dryRun: true });

// Execute with both args and options
await cli.execute("deploy", ["--env", "production"], { dryRun: true });

// Nested commands use slash syntax
await cli.execute("git/push", { remote: "origin", branch: "main" });

Automatic Features

When you create a CLI with createCLI, you get:

  • Automatic help generation - --help flag shows available commands
  • Version display - --version flag shows CLI version
  • Command routing - Automatically routes to the correct command
  • Error handling - Friendly error messages for unknown commands
  • Nested command support - Commands can have subcommands
  • Alias support - Commands can have shortcuts
  • Plugin system - Extend functionality with type-safe plugins
  • Type-safe context - Plugin stores are fully typed in commands
  • TUI rendering - Commands with render: show interactive views
  • Format flags - --format json|yaml|toon for structured output

Help Output

Running with --help shows:

$ my-cli --help
my-cli v1.0.0
My awesome CLI tool

Commands:
  hello                Say hello
  build                Build the project
  test                 Run tests

Error Handling

Unknown commands show helpful messages:

$ my-cli unknown
Unknown command: unknown

Did you mean 'unix'?

Available commands:
  build   deploy   hello   test

The CLI automatically handles help flags at any level. For example, my-cli build --help shows help for the build command specifically.

See Also

On this page