Cliffy

website·Indexed 32 days ago

https://cliffy.io/

A powerful and versatile library for creating interactive command-line tools, featuring a type-safe command module with auto-generated help and shell completions, a prompt module for interactive inputs, a flags parser with built-in validations, and a parser-agnostic self-upgrade API supporting providers like JSR, npm, Deno Land, GitHub, and GitLab. Documentation covers version v1.3.1.

Tokens
34.3K
Snippets
173
Records
229
Agent score
67%

What's inside Cliffy

  1. Overview of Cliffy CLI library

    Cliffy is a platform-independent library used to create interactive command-line tools. It is compatible with Deno, Node.js, and Bun. The library is divided into two primary functional areas: the command module for building CLI structures (commands, options, and arguments) and the prompt module for creating interactive user experiences (input, select, toggle, etc.).
  2. Use Cliffy's built-in 'did-you-mean' suggestions

    Cliffy provides built-in 'did-you-mean' support to improve user and developer experience. When a user executes an invalid command or provides an unknown option, Cliffy automatically analyzes the input and suggests the closest matching valid option or command.
    $ deno run examples/command/demo.ts --barr
    error: Unknown option "--barr". Did you mean option "--bar"?
  3. Use the KeyCode interface to handle parsed ANSI sequences

    v1.3.1
    The KeyCode interface is used to represent a parsed ANSI sequence resulting from a keypress. It provides detailed information about the key pressed, including its name, the raw ANSI sequence, and the state of modifier keys.
    {
      "name": "up",
      "sequence": "\x1b[A",
      "code": "[A",
      "ctrl": false,
      "meta": false,
      "shift": false
    }
  4. Understand and use Upgrade Providers in Cliffy

    A provider is a registry adapter used by the upgrade() function and the UpgradeCommand to identify available versions of a CLI and their download locations.

    • upgrade() accepts a single provider.
    • UpgradeCommand accepts an array of providers: the first is the default, and others can be selected by the user via the --registry flag.

    Available providers include:

    • Package Registries: JsrProvider (JSR), NpmProvider (npm).
    • CDNs: DenoLandProvider (deno.land/x), NestLandProvider (nest.land).
    • Git Repositories: GithubProvider (GitHub), GitlabProvider (GitLab).
    • Custom: UrlProvider (any URL).

    Note: GithubProvider, GitlabProvider, and UrlProvider support upgrading standalone executables by downloading release assets.

  5. Implement self-upgrade functionality for CLI tools using @cliffy/upgrade

    @cliffy/upgrade is a parser-agnostic API that allows CLI tools to download a newer version of themselves and replace the current installation. It supports both script-based installs (via runtime package managers) and standalone binaries (e.g., deno compile, bun build --compile, or Node single executable applications). It is independent of @cliffy/command and @cliffy/flags and can be used with any argument parser.
  6. Use the KeyPressEvent interface to handle keyboard input

    The KeyPressEvent represents a keypress event in Cliffy. It inherits most properties from the KeyCode interface and provides detailed information about the key pressed, including its name, ANSI sequence, and modifier states.
    {
      "name": "up",
      "sequence": "\x1b[A",
      "code": "[A",
      "ctrlKey": false,
      "metaKey": false,
      "shiftKey": false,
      "altKey": false
    }
  7. Handle Cliffy command errors and exits

    By default, when a ValidationError is thrown (due to invalid options, arguments, or environment variables), Cliffy prints the auto-generated help text, the error message, and calls Deno.exit(validationError.exitCode ?? 1). Other runtime errors are thrown by default. You can modify this behavior using .throwErrors(), .noExit(), or by registering a custom error handler via .error().
  8. Generate and display auto-help for Cliffy commands

    Cliffy automatically generates help text based on the command's name, version, description, meta information, options, sub-commands, environment variables, and examples. By default, users can trigger this help using the -h or --help flags. The -h flag prints a condensed version (first line of descriptions), while --help prints the full description.
    import { Command } from "@cliffy/command";
    
    await new Command()
      .name("help-option-and-command")
      .version("0.1.0")
      .description("Sample description ...")
      .env(
        "EXAMPLE_ENVIRONMENT_VARIABLE=<value:boolean>",
        "Environment variable description ...",
      )
      .example(
        "Some example",
        "Example content ...\n\nSome more example content ...",
      )
      .parse();
  9. Understand Cliffy command type inference

    Since v0.21.0, Cliffy uses strict types by default. Option types, environment-variable names, and general types are automatically inferred, meaning developers generally do not need to define generic parameters manually for standard command setups.
  10. Implement a help command in Cliffy

    The HelpCommand prints auto-generated help documentation. It functions similarly to the --help option but allows users to pass a specific child command name as an argument to view help for that sub-command. Using the .global() method makes the help command available across all child commands.
    import { Command } from "@cliffy/command";
    import { HelpCommand } from "@cliffy/command/help";
    
    await new Command()
      .version("0.1.0")
      .description("Sample description ...")
      .env(
        "EXAMPLE_ENVIRONMENT_VARIABLE=<value:boolean>",
        "Environment variable description ...",
      )
      .command("help", new HelpCommand().global())
      .parse();
  11. Implement custom OS signal handlers in Cliffy prompts

    By default, Cliffy calls Deno.exit(0) when a user presses Ctrl+C. To implement a custom signal handler (e.g., using Deno.addSignalListener), you must enable the cbreak option in your prompt configuration. This allows OS signals to pass through to Deno.

    Constraints and Caveats:

    • The cbreak option is currently only supported on Linux and macOS; it is not supported in Bun.
    • When using cbreak with interactive prompts like Select or Toggle, you must manually show the cursor and clear the stdout before calling Deno.exit(), otherwise the terminal state may remain corrupted.
    import { tty } from "@cliffy/ansi/tty";
    import { Toggle } from "@cliffy/prompt/toggle";
    
    // Register a custom handler for SIGINT (Ctrl+C)
    Deno.addSignalListener("SIGINT", () => {
      // Manually restore terminal state before exiting
      tty.cursorLeft.eraseDown.cursorShow();
      console.log("interrupted!");
      Deno.exit(1);
    });
    
    const confirmed = await Toggle.prompt({
      message: "Please confirm",
      cbreak: true, // Enable pass-through of OS signals
    });
    
    console.log({ confirmed });
  12. Configure upgrade logging and verbosity

    The upgrade() function is silent by default. To report progress, pass a logger object containing log, info, warn, and error methods (e.g., the console object). Use verbose: true to include the output of the runtime's install command.
    await upgrade({
      name: "my-cli",
      from: "1.0.0",
      to: "latest",
      provider: new GithubProvider({ repository: "user/my-cli" }),
      logger: console,
      verbose: true,
    });