Skip to content

Implement cli-dev: CLI application development #14

@vredchenko

Description

@vredchenko

Summary

The cli-dev plugin provides scaffolding and conventions for building CLI applications across multiple languages, with a preference for zx (scripted shell via JavaScript) over raw bash. This is valuable because CLI app setup involves many boilerplate decisions (argument parsing library, output formatting, error handling, distribution) that the plugin standardizes.

Original Intent

Guidelines for CLI development. Conventions, npm and Python libs, and use zx npm instead of bash where possible.

Commands

/cli-dev:init

Purpose: Initialize a new CLI application project with appropriate scaffolding.

Behavior:

  1. Ask user for:

    • CLI name
    • Language/runtime: TypeScript/Bun (default), TypeScript/Node, Python, Go
    • CLI type: single-command tool, multi-command CLI, interactive REPL
  2. Generate project based on language choice:

    TypeScript/Bun (default):

    <name>/
    ├── src/
    │   ├── index.ts          # Entry point with shebang
    │   ├── commands/
    │   │   └── example.ts    # Example command
    │   └── utils/
    │       ├── cli.ts        # Argument parsing setup
    │       └── output.ts     # Colored output helpers
    ├── tests/
    │   └── example.test.ts
    ├── package.json
    ├── tsconfig.json
    ├── biome.json
    └── README.md
    
    • Arg parser: commander (most popular, well-typed) or yargs (if complex subcommands)
    • Shell commands: zx for anything that would otherwise be a bash script
    • Output formatting: chalk for colors, cli-table3 for tables, ora for spinners

    Python:

    <name>/
    ├── src/<name>/
    │   ├── __init__.py
    │   ├── __main__.py       # Entry point
    │   ├── cli.py            # Typer app definition
    │   └── commands/
    │       └── example.py
    ├── tests/
    │   └── test_example.py
    ├── pyproject.toml         # With [project.scripts] entry
    └── README.md
    
    • Arg parser: typer (type-based CLI, click under the hood)
    • Output: rich for colors/tables/progress

    Go:

    <name>/
    ├── cmd/
    │   ├── root.go           # Cobra root command
    │   └── example.go        # Example subcommand
    ├── internal/
    │   └── output.go         # Output helpers
    ├── main.go
    ├── go.mod
    └── README.md
    
    • Arg parser: cobra (industry standard)
    • Output: lipgloss for styling, bubbles for TUI components
  3. Install dependencies for chosen language

  4. Set up entry point with:

    • Help text (--help)
    • Version flag (--version)
    • Verbose/quiet flags
    • Color/no-color support
  5. Make entry point executable (chmod +x, shebang line)

  6. Output summary of created files

Edge cases:

  • Directory not empty → warn and offer to scaffold into existing project
  • Name conflicts with existing system commands → warn

/cli-dev:command

Purpose: Add a new subcommand to an existing CLI application.

Behavior:

  1. Detect language from existing project structure

  2. Ask user for:

    • Command name
    • Description
    • Arguments (positional)
    • Options/flags (with types and defaults)
  3. Generate command file based on language:

    TypeScript (commander):

    import { Command } from "commander";
    
    export const greetCommand = new Command("greet")
      .description("Greet a user by name")
      .argument("<name>", "Name to greet")
      .option("-l, --loud", "Use uppercase", false)
      .action((name: string, options: { loud: boolean }) => {
        const greeting = `Hello, ${name}!`;
        console.log(options.loud ? greeting.toUpperCase() : greeting);
      });

    Python (typer):

    import typer
    from rich.console import Console
    
    console = Console()
    
    def greet(
        name: str = typer.Argument(help="Name to greet"),
        loud: bool = typer.Option(False, "--loud", "-l", help="Use uppercase"),
    ) -> None:
        """Greet a user by name."""
        greeting = f"Hello, {name}!"
        console.print(greeting.upper() if loud else greeting)

    Go (cobra):

    var greetCmd = &cobra.Command{
        Use:   "greet [name]",
        Short: "Greet a user by name",
        Args:  cobra.ExactArgs(1),
        Run: func(cmd *cobra.Command, args []string) {
            // ...
        },
    }
  4. Register the command in the main CLI entry point

  5. Generate a test file for the command

  6. Output: created files + example usage

Edge cases:

  • Command name already exists → warn
  • No CLI framework detected → suggest running /cli-dev:init first

/cli-dev:release (new)

Purpose: Prepare the CLI for distribution.

Behavior:

  1. Detect language and determine distribution strategy:

    Language Strategy Command
    TypeScript/Bun Compile to binary bun build --compile
    TypeScript/Node npm publish npm publish
    Python PyPI publish uv build && uv publish
    Go Cross-compile GOOS=linux GOARCH=amd64 go build
  2. For Bun compiled binaries:

    • Cross-compile for targets: bun-linux-x64, bun-darwin-arm64, bun-linux-arm64
    • Package into dist/ directory
  3. Update version in manifest

  4. Generate/update CHANGELOG.md entry

  5. Create git tag (but don't push — defer to gitflow plugin)

  6. Output distribution artifacts and next steps

Edge cases:

  • No version in manifest → ask user
  • Existing release workflow (GitHub Actions) → suggest using it instead

Hooks

PostToolUse: zx_suggestion

Trigger: Write tool, when creating/editing a .sh or .bash file with more than 20 lines

Behavior:

  • Output: 💡 Consider using zx (JavaScript) instead of bash for complex scripts. See: https://google.github.io/zx/
  • Do NOT block — informational only
  • Only trigger once per file

File Manifest

File Est. Lines Purpose
commands/init.md 110-130 Initialize CLI project
commands/command.md 80-100 Add new subcommand
commands/release.md 70-90 Prepare for distribution
hooks/zx_suggestion.md 20-30 Suggest zx over bash
README.md 150-180 Full plugin documentation
.claude-plugin/plugin.json 15-20 Plugin manifest

README Outline

  1. Overview — CLI development across languages, zx-first for scripts

  2. Quick Start — Installation + /cli-dev:init

  3. Commands — Table with all 3 commands

  4. Language Comparison

    Feature Bun/TS Python Go
    Arg parser commander typer cobra
    Output chalk + cli-table3 rich lipgloss
    Shell ops zx subprocess os/exec
    Binary bun --compile pyinstaller/shiv go build
    Startup ~30ms ~100ms ~5ms
  5. Project Templates — Directory layout per language

  6. zx Guide — When and how to use zx instead of bash

  7. Distribution — Publishing and cross-compilation

  8. Recommended Libraries — Per-language table of CLI utilities

Prerequisites

  • Language-specific runtime (Bun, Python, Go)
  • zx (installed automatically via bun add google/zx or bunx zx)

Quality Checklist

  • Each command .md is 60+ lines with concrete steps
  • README is 100+ lines with examples and reference tables
  • Multi-language support is concrete (not just "detect language")
  • zx preference over bash is documented with rationale
  • Plugin provides clear value (scaffolding + consistent structure)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions