cli

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 19, 2025 License: Apache-2.0 Imports: 18 Imported by: 0

README

Forge v2 CLI Framework

Enterprise-grade CLI framework for building command-line tools with Forge. Features commands, subcommands, flags, middleware, prompts, tables, plugins, and seamless Forge App integration.

Features

Commands & Subcommands - Hierarchical command structure
Comprehensive Flags - String, int, bool, slice, duration with validation
Interactive Prompts - Input, confirm, select, multi-select with arrow key navigation ⬆️⬇️
Space Bar Selection - Toggle multi-select with spacebar (modern UX) ⎵
Progress Indicators - Progress bars and spinners
Table Output - Formatted, colored tables with multiple styles
Middleware - Before/after command hooks
Plugin System - Modular, composable commands
CLI-Optimized Logger - Color-coded, simple output
Auto-Generated Help - Automatic help text generation
Shell Completion - Bash, Zsh, Fish completion
Forge Integration - Access to DI container and services

Installation

go get github.com/xraph/forge/cli

Quick Start

Simple CLI
package main

import (
    "fmt"
    "os"
    "github.com/xraph/forge/cli"
)

func main() {
    app := cli.New(cli.Config{
        Name:        "mytool",
        Version:     "1.0.0",
        Description: "My awesome CLI tool",
    })

    helloCmd := cli.NewCommand(
        "hello",
        "Say hello",
        func(ctx cli.CommandContext) error {
            name := ctx.String("name")
            if name == "" {
                name = "World"
            }
            ctx.Success(fmt.Sprintf("Hello, %s!", name))
            return nil
        },
        cli.WithFlag(cli.NewStringFlag("name", "n", "Name to greet", "")),
    )

    app.AddCommand(helloCmd)

    if err := app.Run(os.Args); err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(cli.GetExitCode(err))
    }
}

Usage:

$ mytool hello --name=John
✓ Hello, John!

Commands & Subcommands

// Create parent command
projectCmd := cli.NewCommand("project", "Project management", nil)

// Add subcommands
newCmd := cli.NewCommand("new", "Create project", createProject)
listCmd := cli.NewCommand("list", "List projects", listProjects)
deleteCmd := cli.NewCommand("delete", "Delete project", deleteProject)

projectCmd.AddSubcommand(newCmd)
projectCmd.AddSubcommand(listCmd)
projectCmd.AddSubcommand(deleteCmd)

app.AddCommand(projectCmd)

Usage:

$ mytool project new --name=myapp
$ mytool project list
$ mytool project delete --name=myapp

Flags

Flag Types
// String flag
cli.NewStringFlag("name", "n", "Your name", "default")

// Int flag
cli.NewIntFlag("port", "p", "Port number", 8080)

// Bool flag
cli.NewBoolFlag("verbose", "v", "Verbose output", false)

// String slice flag
cli.NewStringSliceFlag("tags", "t", "Tags", []string{})

// Duration flag
cli.NewDurationFlag("timeout", "", "Timeout", 30*time.Second)
Flag Validation
// Required flag
cli.NewStringFlag("api-key", "", "API key", "", cli.Required())

// Range validation
cli.NewIntFlag("port", "p", "Port", 8080, cli.ValidateRange(1, 65535))

// Enum validation
cli.NewStringFlag("env", "e", "Environment", "dev",
    cli.ValidateEnum("dev", "staging", "prod"),
)
Using Flags
func myCommand(ctx cli.CommandContext) error {
    name := ctx.String("name")
    port := ctx.Int("port")
    verbose := ctx.Bool("verbose")
    
    if ctx.Flag("name").IsSet() {
        // Name was explicitly provided
    }
    
    return nil
}

Interactive Prompts

Arrow Key Navigation 🎯

Select and multi-select now support arrow key navigation for a modern CLI experience!

func interactive(ctx cli.CommandContext) error {
    // Simple prompt
    name, err := ctx.Prompt("What's your name?")
    if err != nil {
        return err
    }
    
    // Confirm prompt
    confirmed, err := ctx.Confirm("Are you sure?")
    if err != nil {
        return err
    }
    
    // Select with arrow keys ↑/↓
    // Navigate with arrows, Enter to select, Esc to cancel
    env, err := ctx.Select("Choose environment:", []string{
        "development",
        "staging",
        "production",
    })
    if err != nil {
        return err
    }
    
    // Multi-select with Space bar
    // Navigate with arrows, Space to toggle, Enter to confirm
    features, err := ctx.MultiSelect("Select features:", []string{
        "database",
        "cache",
        "events",
    })
    if err != nil {
        return err
    }
    
    return nil
}

Interactive Controls:

  • ↑/↓ or j/k - Navigate options
  • Space - Toggle selection (multi-select)
  • Enter - Confirm selection
  • Esc/q - Cancel

Visual Example:

Choose environment:
  ↑/↓: Navigate  │  Enter: Select  │  Esc/q: Cancel

    development
  ▸ staging        ← Current selection (bold + highlighted)
    production

Multi-Select Example:

Select features:
  ↑/↓: Navigate  │  Space: Select/Deselect  │  Enter: Confirm

  ▸ [✓] database   ← Cursor here, selected
    [ ] cache
    [✓] events     ← Selected but not at cursor

Note: Automatically falls back to number input in non-interactive terminals

Progress Indicators

Progress Bar
func download(ctx cli.CommandContext) error {
    total := 100
    progress := ctx.ProgressBar(total)
    
    for i := 0; i <= total; i++ {
        time.Sleep(50 * time.Millisecond)
        progress.Set(i)
    }
    
    progress.Finish("Download complete!")
    return nil
}
Spinner
func process(ctx cli.CommandContext) error {
    spinner := ctx.Spinner("Processing...")
    
    // Long-running task
    time.Sleep(5 * time.Second)
    
    spinner.Stop(cli.Green("✓ Processing complete!"))
    return nil
}

Update spinner message:

spinner := ctx.Spinner("Starting...")
spinner.Update("Loading data...")
spinner.Update("Processing...")
spinner.Stop(cli.Green("✓ Done!"))

Async Select & Multi-Select

Load options dynamically from APIs, databases, or any async source:

Async Select
func selectEnv(ctx cli.CommandContext) error {
    // Define loader function
    loader := func(ctx context.Context) ([]string, error) {
        // Fetch from API, database, etc.
        return fetchEnvironmentsFromAPI(ctx)
    }
    
    // Shows spinner while loading, then prompts
    env, err := ctx.SelectAsync("Choose environment:", loader)
    if err != nil {
        return err
    }
    
    ctx.Success("Selected: " + env)
    return nil
}
Async Multi-Select
func selectFeatures(ctx cli.CommandContext) error {
    loader := func(ctx context.Context) ([]string, error) {
        return fetchAvailableFeaturesFromAPI(ctx)
    }
    
    features, err := ctx.MultiSelectAsync("Select features:", loader)
    if err != nil {
        return err
    }
    
    return nil
}
With Retry (Flaky Network)
// Automatically retries on failure with exponential backoff
region, err := ctx.SelectWithRetry("Choose region:", loader, 3)

Visual Flow:

⠋ Loading options...    ← Spinner during load
✓ Options loaded

Choose environment:     ← Select prompt
↑/↓: Navigate  │  Enter: Select

▸ Production
  Staging
  Development

See ASYNC_SELECT_AND_SPINNER.md for complete guide

Table Output

func list(ctx cli.CommandContext) error {
    table := ctx.Table()
    
    table.SetHeader([]string{"ID", "Name", "Status"})
    table.AppendRow([]string{"1", "Project A", cli.Green("Active")})
    table.AppendRow([]string{"2", "Project B", cli.Yellow("Paused")})
    table.AppendRow([]string{"3", "Project C", cli.Red("Stopped")})
    
    table.Render()
    return nil
}

Output:

┌────┬───────────┬────────┐
│ ID │ Name      │ Status │
├────┼───────────┼────────┤
│ 1  │ Project A │ Active │
│ 2  │ Project B │ Paused │
│ 3  │ Project C │ Stopped│
└────┴───────────┴────────┘

Plugin System

// Define a plugin
type DatabasePlugin struct {
    *cli.BasePlugin
}

func NewDatabasePlugin() cli.Plugin {
    plugin := &DatabasePlugin{
        BasePlugin: cli.NewBasePlugin(
            "database",
            "1.0.0",
            "Database management commands",
        ),
    }
    
    migrateCmd := cli.NewCommand("db:migrate", "Run migrations", migrate)
    seedCmd := cli.NewCommand("db:seed", "Seed database", seed)
    
    plugin.AddCommand(migrateCmd)
    plugin.AddCommand(seedCmd)
    
    return plugin
}

// Register plugin
app := cli.New(cli.Config{Name: "myapp", Version: "1.0.0"})
app.RegisterPlugin(NewDatabasePlugin())

Forge App Integration

import (
    "github.com/xraph/forge"
    "github.com/xraph/forge/cli"
)

func main() {
    // Create Forge app
    app := forge.NewApp(forge.AppConfig{
        Name:    "my-service",
        Version: "1.0.0",
    })
    
    // Register a service
    forge.RegisterSingleton(app.Container(), "database", func(c forge.Container) (*Database, error) {
        return NewDatabase(), nil
    })
    
    // Create CLI with Forge integration
    cliApp := cli.NewForgeIntegratedCLI(app, cli.Config{
        Name:    "my-service-cli",
        Version: "1.0.0",
    })
    
    // Add command that uses Forge services
    migrateCmd := cli.NewCommand(
        "migrate",
        "Run database migrations",
        func(ctx cli.CommandContext) error {
            // Access Forge service via DI
            db, err := cli.GetService[*Database](ctx, "database")
            if err != nil {
                return err
            }
            
            return db.Migrate()
        },
    )
    
    cliApp.AddCommand(migrateCmd)
    cliApp.Run(os.Args)
}

Built-in Forge commands:

  • info - Show application information
  • health - Check application health
  • extensions - List registered extensions

Middleware

// Logging middleware
func loggingMiddleware(next cli.CommandHandler) cli.CommandHandler {
    return func(ctx cli.CommandContext) error {
        start := time.Now()
        ctx.Logger().Info("Command: %s", ctx.Command().Name())
        
        err := next(ctx)
        
        ctx.Logger().Info("Duration: %v", time.Since(start))
        return err
    }
}

// Auth middleware
func authMiddleware(next cli.CommandHandler) cli.CommandHandler {
    return func(ctx cli.CommandContext) error {
        token := ctx.String("token")
        if token == "" {
            return cli.NewError("authentication required", cli.ExitUnauthorized)
        }
        return next(ctx)
    }
}

// Use middleware
cmd := cli.NewCommand("deploy", "Deploy", deployHandler)
cmd.Before(loggingMiddleware)
cmd.Before(authMiddleware)

CLI-Optimized Logger

logger := cli.NewCLILogger(
    cli.WithColors(true),
    cli.WithLevel(cli.InfoLevel),
)

logger.Success("Operation completed!")  // Green ✓
logger.Info("Processing...")            // Blue [INFO]
logger.Warning("Slow response")         // Yellow [!]
logger.Error("Failed to connect")       // Red ✗
logger.Debug("Detailed info")           // Gray [DEBUG]

Color Utilities

// Color functions
cli.Green("Success!")
cli.Red("Error!")
cli.Yellow("Warning!")
cli.Blue("Info")
cli.Gray("Debug")

// Combined styles
cli.BoldGreen("Important!")
cli.Bold("Emphasis")
cli.Underline("Link")

Shell Completion

Generate completion scripts:

// Add completion command
completionCmd := cli.NewCommand(
    "completion",
    "Generate shell completion",
    func(ctx cli.CommandContext) error {
        shell := ctx.String("shell")
        
        switch shell {
        case "bash":
            return cli.GenerateBashCompletion(app, os.Stdout)
        case "zsh":
            return cli.GenerateZshCompletion(app, os.Stdout)
        case "fish":
            return cli.GenerateFishCompletion(app, os.Stdout)
        }
        return nil
    },
    cli.WithFlag(cli.NewStringFlag("shell", "s", "Shell type", "bash")),
)

Install:

# Bash
mytool completion --shell=bash > /etc/bash_completion.d/mytool

# Zsh
mytool completion --shell=zsh > ~/.zsh/completion/_mytool

# Fish
mytool completion --shell=fish > ~/.config/fish/completions/mytool.fish

Examples

See the examples/ directory for complete examples:

  • simple/ - Basic CLI with one command
  • subcommands/ - CLI with command hierarchy
  • interactive/ - CLI using prompts, progress, tables
  • plugin/ - CLI with custom plugins
  • forge_integration/ - CLI integrated with Forge App

Testing

Run tests:

go test ./...

Design

Follows the design specification in v2/design/019-cli-framework.md.

License

See main Forge project license.

Documentation

Index

Constants

View Source
const (
	ExitSuccess       = 0
	ExitError         = 1
	ExitUsageError    = 2
	ExitNotFound      = 127
	ExitUnauthorized  = 126
	ExitInternalError = 3
)

Common exit codes.

Variables

View Source
var (
	// Color functions for output.
	Green   = color.New(color.FgGreen).SprintFunc()
	Red     = color.New(color.FgRed).SprintFunc()
	Yellow  = color.New(color.FgYellow).SprintFunc()
	Blue    = color.New(color.FgBlue).SprintFunc()
	Cyan    = color.New(color.FgCyan).SprintFunc()
	Magenta = color.New(color.FgMagenta).SprintFunc()
	White   = color.New(color.FgWhite).SprintFunc()
	Gray    = color.New(color.FgHiBlack).SprintFunc()

	// Style functions.
	Bold      = color.New(color.Bold).SprintFunc()
	Underline = color.New(color.Underline).SprintFunc()
	Italic    = color.New(color.Italic).SprintFunc()

	// Combined styles.
	BoldGreen  = color.New(color.FgGreen, color.Bold).SprintFunc()
	BoldRed    = color.New(color.FgRed, color.Bold).SprintFunc()
	BoldYellow = color.New(color.FgYellow, color.Bold).SprintFunc()
	BoldBlue   = color.New(color.FgBlue, color.Bold).SprintFunc()
)
View Source
var (
	// ErrCommandNotFound is returned when a command is not found.
	ErrCommandNotFound = errors.New("command not found")

	// ErrFlagRequired is returned when a required flag is missing.
	ErrFlagRequired = errors.New("required flag missing")

	// ErrFlagInvalid is returned when a flag value is invalid.
	ErrFlagInvalid = errors.New("invalid flag value")

	// ErrInvalidArguments is returned when arguments are invalid.
	ErrInvalidArguments = errors.New("invalid arguments")

	// ErrPluginNotFound is returned when a plugin is not found.
	ErrPluginNotFound = errors.New("plugin not found")

	// ErrPluginAlreadyRegistered is returned when trying to register a duplicate plugin.
	ErrPluginAlreadyRegistered = errors.New("plugin already registered")

	// ErrCircularDependency is returned when plugins have circular dependencies.
	ErrCircularDependency = errors.New("circular plugin dependency detected")
)

Functions

func AppFromContext

func AppFromContext(ctx CommandContext) (forge.App, bool)

AppFromContext retrieves the Forge app from a command context.

func Colorize

func Colorize(colorFunc func(...any) string, s string) string

Colorize applies a color function to a string if colors are enabled.

func ConfigureColors

func ConfigureColors(config ColorConfig)

ConfigureColors configures the global color settings.

func FormatError

func FormatError(err error, colors bool) string

FormatError formats an error for display.

func GenerateBashCompletion

func GenerateBashCompletion(cli CLI, w io.Writer) error

GenerateBashCompletion generates bash completion script.

func GenerateFishCompletion

func GenerateFishCompletion(cli CLI, w io.Writer) error

GenerateFishCompletion generates fish completion script.

func GenerateZshCompletion

func GenerateZshCompletion(cli CLI, w io.Writer) error

GenerateZshCompletion generates zsh completion script.

func GetExitCode

func GetExitCode(err error) int

GetExitCode extracts the exit code from an error.

func GetService

func GetService[T any](ctx CommandContext, name string) (T, error)

GetService retrieves a service from the Forge app via DI.

func MultiSelectAsync

func MultiSelectAsync(ctx context.Context, question string, loader OptionsLoader) ([]string, error)

MultiSelectAsync prompts for multiple selections with async-loaded options Shows a spinner while loading options.

func MultiSelectWithProgressFeedback

func MultiSelectWithProgressFeedback(ctx context.Context, question string, loader ProgressLoader) ([]string, error)

MultiSelectWithProgressFeedback prompts for multiple selections with progress feedback.

func MultiSelectWithRetry

func MultiSelectWithRetry(ctx context.Context, question string, loader OptionsLoader, maxRetries int) ([]string, error)

MultiSelectWithRetry prompts for multiple selections with retry on failure.

func MustGetApp

func MustGetApp(ctx CommandContext) forge.App

MustGetApp retrieves the Forge app from context or panics.

func MustGetService

func MustGetService[T any](ctx CommandContext, name string) T

MustGetService retrieves a service from the Forge app or panics.

func PromptPassword

func PromptPassword(question string) (string, error)

PromptPassword prompts for a password (hidden input).

func PromptWithDefault

func PromptWithDefault(question, defaultValue string) (string, error)

PromptWithDefault prompts with a default value.

func SelectAsync

func SelectAsync(ctx context.Context, question string, loader OptionsLoader) (string, error)

SelectAsync prompts for selection with async-loaded options Shows a spinner while loading options.

func SelectWithProgressFeedback

func SelectWithProgressFeedback(ctx context.Context, question string, loader ProgressLoader) (string, error)

SelectWithProgressFeedback prompts with detailed progress feedback.

func SelectWithRetry

func SelectWithRetry(ctx context.Context, question string, loader OptionsLoader, maxRetries int) (string, error)

SelectWithRetry prompts for selection with retry on failure Useful for loading from flaky sources.

func WithApp

func WithApp(app forge.App) func(*Config)

WithApp creates a CLI with Forge app integration.

Types

type BasePlugin

type BasePlugin struct {
	// contains filtered or unexported fields
}

BasePlugin provides a base implementation for plugins.

func NewBasePlugin

func NewBasePlugin(name, version, description string) *BasePlugin

NewBasePlugin creates a new base plugin.

func (*BasePlugin) AddCommand

func (p *BasePlugin) AddCommand(cmd Command)

AddCommand adds a command to the plugin.

func (*BasePlugin) AddDependency

func (p *BasePlugin) AddDependency(dep string)

AddDependency adds a dependency to the plugin.

func (*BasePlugin) Commands

func (p *BasePlugin) Commands() []Command

Commands returns the commands provided by this plugin.

func (*BasePlugin) Dependencies

func (p *BasePlugin) Dependencies() []string

Dependencies returns the plugin dependencies.

func (*BasePlugin) Description

func (p *BasePlugin) Description() string

Description returns the plugin description.

func (*BasePlugin) Initialize

func (p *BasePlugin) Initialize() error

Initialize is called when the plugin is registered.

func (*BasePlugin) Name

func (p *BasePlugin) Name() string

Name returns the plugin name.

func (*BasePlugin) SetCommands

func (p *BasePlugin) SetCommands(commands []Command)

SetCommands sets the commands for the plugin.

func (*BasePlugin) SetDependencies

func (p *BasePlugin) SetDependencies(dependencies []string)

SetDependencies sets the dependencies for the plugin.

func (*BasePlugin) Version

func (p *BasePlugin) Version() string

Version returns the plugin version.

type CLI

type CLI interface {
	// Identity
	Name() string
	Version() string
	Description() string

	// Commands
	AddCommand(cmd Command) error
	Commands() []Command
	Run(args []string) error

	// Global flags
	Flag(name string, opts ...FlagOption) Flag

	// Configuration
	SetOutput(w io.Writer)
	SetErrorHandler(handler func(error))

	// Plugin support
	RegisterPlugin(plugin Plugin) error
	Plugins() []Plugin
}

CLI represents a command-line application.

func New

func New(config Config) CLI

New creates a new CLI application.

func NewForgeIntegratedCLI

func NewForgeIntegratedCLI(app forge.App, config Config) CLI

NewForgeIntegratedCLI creates a CLI with Forge app integration and common commands.

type CLIError

type CLIError struct {
	Message  string
	ExitCode int
	Cause    error
}

CLIError represents a CLI-specific error with an exit code.

func NewError

func NewError(message string, exitCode int) *CLIError

NewError creates a new CLI error.

func WrapError

func WrapError(err error, message string, exitCode int) *CLIError

WrapError wraps an existing error with a CLI error.

func (*CLIError) Error

func (e *CLIError) Error() string

func (*CLIError) Unwrap

func (e *CLIError) Unwrap() error

type CLILogger

type CLILogger struct {
	// contains filtered or unexported fields
}

CLILogger is a CLI-friendly logger with color support.

func NewCLILogger

func NewCLILogger(opts ...LoggerOption) *CLILogger

NewCLILogger creates a new CLI logger.

func (*CLILogger) Debug

func (l *CLILogger) Debug(msg string, args ...any)

Debug logs a debug message (gray).

func (*CLILogger) Error

func (l *CLILogger) Error(msg string, args ...any)

Error logs an error message (red).

func (*CLILogger) Info

func (l *CLILogger) Info(msg string, args ...any)

Info logs an informational message (blue).

func (*CLILogger) NewLine

func (l *CLILogger) NewLine()

NewLine writes a blank line.

func (*CLILogger) Print

func (l *CLILogger) Print(msg string, args ...any)

Print writes a message without any formatting.

func (*CLILogger) Printf

func (l *CLILogger) Printf(format string, args ...any)

Printf writes a formatted message without any log level.

func (*CLILogger) Println

func (l *CLILogger) Println(args ...any)

Println writes a message followed by a newline.

func (*CLILogger) Separator

func (l *CLILogger) Separator()

Separator writes a separator line.

func (*CLILogger) SetColors

func (l *CLILogger) SetColors(enabled bool)

SetColors enables or disables colored output.

func (*CLILogger) SetLevel

func (l *CLILogger) SetLevel(level LogLevel)

SetLevel sets the minimum log level.

func (*CLILogger) SetOutput

func (l *CLILogger) SetOutput(w io.Writer)

SetOutput sets the output writer.

func (*CLILogger) Success

func (l *CLILogger) Success(msg string, args ...any)

Success logs a success message (green).

func (*CLILogger) Warning

func (l *CLILogger) Warning(msg string, args ...any)

Warning logs a warning message (yellow).

type ColorConfig

type ColorConfig struct {
	Enabled    bool
	ForceColor bool
	NoColor    bool
}

ColorConfig controls color output behavior.

func DefaultColorConfig

func DefaultColorConfig() ColorConfig

DefaultColorConfig returns the default color configuration.

type Command

type Command interface {
	// Identity
	Name() string
	Description() string
	Usage() string
	Aliases() []string

	// Execution
	Run(ctx CommandContext) error

	// Subcommands
	AddSubcommand(cmd Command) error
	Subcommands() []Command
	FindSubcommand(name string) (Command, bool)

	// Flags
	Flags() []Flag
	AddFlag(flag Flag)

	// Middleware
	Before(fn MiddlewareFunc) Command
	After(fn MiddlewareFunc) Command

	// Parent (for navigation)
	SetParent(parent Command)
	Parent() Command
}

Command represents a CLI command.

func NewCommand

func NewCommand(name, description string, handler CommandHandler, opts ...CommandOption) Command

NewCommand creates a new command.

type CommandContext

type CommandContext interface {
	// Arguments
	Args() []string
	Arg(index int) string
	NArgs() int

	// Flags
	Flag(name string) FlagValue
	String(name string) string
	Int(name string) int
	Bool(name string) bool
	StringSlice(name string) []string
	Duration(name string) int64

	// Output
	Println(a ...any)
	Printf(format string, a ...any)
	Error(err error)
	Success(msg string)
	Warning(msg string)
	Info(msg string)

	// Input
	Prompt(question string) (string, error)
	Confirm(question string) (bool, error)
	Select(question string, options []string) (string, error)
	MultiSelect(question string, options []string) ([]string, error)

	// Async Input (with spinner feedback)
	SelectAsync(question string, loader OptionsLoader) (string, error)
	MultiSelectAsync(question string, loader OptionsLoader) ([]string, error)
	SelectWithRetry(question string, loader OptionsLoader, maxRetries int) (string, error)
	MultiSelectWithRetry(question string, loader OptionsLoader, maxRetries int) ([]string, error)

	// Progress
	ProgressBar(total int) ProgressBar
	Spinner(message string) Spinner

	// Tables
	Table() TableWriter

	// Context
	Context() context.Context

	// App integration (optional, returns nil if not running with Forge app)
	App() forge.App

	// Command reference
	Command() Command

	// Logger
	Logger() *CLILogger
}

CommandContext provides context to command execution.

type CommandHandler

type CommandHandler func(ctx CommandContext) error

CommandHandler is a function that handles command execution.

type CommandOption

type CommandOption func(*command)

CommandOption is a functional option for configuring commands.

func WithAfter

func WithAfter(fn MiddlewareFunc) CommandOption

WithAfter adds an after middleware.

func WithAliases

func WithAliases(aliases ...string) CommandOption

WithAliases sets command aliases.

func WithBefore

func WithBefore(fn MiddlewareFunc) CommandOption

WithBefore adds a before middleware.

func WithFlag

func WithFlag(flag Flag) CommandOption

WithFlag adds a flag to the command.

func WithFlags

func WithFlags(flags ...Flag) CommandOption

WithFlags adds multiple flags to the command.

func WithSubcommand

func WithSubcommand(sub Command) CommandOption

WithSubcommand adds a subcommand.

func WithUsage

func WithUsage(usage string) CommandOption

WithUsage sets a custom usage string.

type Config

type Config struct {
	Name         string
	Version      string
	Description  string
	Output       io.Writer
	ErrorHandler func(error)
	Logger       *CLILogger
	App          forge.App // Optional Forge app integration
}

Config configures a CLI application.

type Flag

type Flag interface {
	Name() string
	ShortName() string
	Description() string
	DefaultValue() any
	Required() bool
	Type() FlagType
	Validate(value any) error
}

Flag represents a command-line flag.

func NewBoolFlag

func NewBoolFlag(name, shortName, description string, defaultValue bool, opts ...FlagOption) Flag

NewBoolFlag creates a bool flag.

func NewDurationFlag

func NewDurationFlag(name, shortName, description string, defaultValue time.Duration, opts ...FlagOption) Flag

NewDurationFlag creates a duration flag.

func NewFlag

func NewFlag(name string, flagType FlagType, opts ...FlagOption) Flag

NewFlag creates a new flag.

func NewIntFlag

func NewIntFlag(name, shortName, description string, defaultValue int, opts ...FlagOption) Flag

NewIntFlag creates an int flag.

func NewStringFlag

func NewStringFlag(name, shortName, description, defaultValue string, opts ...FlagOption) Flag

NewStringFlag creates a string flag.

func NewStringSliceFlag

func NewStringSliceFlag(name, shortName, description string, defaultValue []string, opts ...FlagOption) Flag

NewStringSliceFlag creates a string slice flag.

type FlagOption

type FlagOption func(*flagConfig)

FlagOption is a functional option for configuring flags.

func Required

func Required() FlagOption

Required marks the flag as required.

func ValidateEnum

func ValidateEnum(allowed ...string) FlagOption

ValidateEnum validates that a string flag is one of the allowed values.

func ValidateRange

func ValidateRange(min, max int) FlagOption

ValidateRange validates that an int flag is within a range.

func WithAlias

func WithAlias(alias string) FlagOption

WithAlias sets a short name alias for the flag.

func WithBoolFlag

func WithBoolFlag(name, shortName, description string, defaultValue bool, opts ...FlagOption) FlagOption

WithBoolFlag creates a bool flag.

func WithDefault

func WithDefault(value any) FlagOption

WithDefault sets a default value for the flag.

func WithDescription

func WithDescription(desc string) FlagOption

WithDescription sets the description for the flag.

func WithDurationFlag

func WithDurationFlag(name, shortName, description string, defaultValue time.Duration, opts ...FlagOption) FlagOption

WithDurationFlag creates a duration flag.

func WithIntFlag

func WithIntFlag(name, shortName, description string, defaultValue int, opts ...FlagOption) FlagOption

WithIntFlag creates an int flag.

func WithStringFlag

func WithStringFlag(name, shortName, description, defaultValue string, opts ...FlagOption) FlagOption

WithStringFlag creates a string flag.

func WithStringSliceFlag

func WithStringSliceFlag(name, shortName, description string, defaultValue []string, opts ...FlagOption) FlagOption

WithStringSliceFlag creates a string slice flag.

func WithValidator

func WithValidator(validator func(any) error) FlagOption

WithValidator sets a custom validator for the flag.

type FlagType

type FlagType int

FlagType represents the type of a flag.

const (
	StringFlagType FlagType = iota
	IntFlagType
	BoolFlagType
	StringSliceFlagType
	DurationFlagType
)

type FlagValue

type FlagValue interface {
	String() string
	Int() int
	Bool() bool
	StringSlice() []string
	Duration() time.Duration
	IsSet() bool
	Raw() any
}

FlagValue represents a parsed flag value.

type LogLevel

type LogLevel int

LogLevel represents the severity level of a log message.

const (
	DebugLevel LogLevel = iota
	InfoLevel
	SuccessLevel
	WarningLevel
	ErrorLevel
)

type LoggerOption

type LoggerOption func(*loggerConfig)

LoggerOption is a functional option for configuring the logger.

func WithColors

func WithColors(enabled bool) LoggerOption

WithColors enables or disables colored output.

func WithLevel

func WithLevel(level LogLevel) LoggerOption

WithLevel sets the minimum log level.

func WithOutput

func WithOutput(w io.Writer) LoggerOption

WithOutput sets the output writer.

func WithPrefix

func WithPrefix(prefix string) LoggerOption

WithPrefix sets a prefix for all log messages.

type MiddlewareFunc

type MiddlewareFunc func(next CommandHandler) CommandHandler

MiddlewareFunc is a function that wraps a CommandHandler.

type OptionsLoader

type OptionsLoader func(ctx context.Context) ([]string, error)

OptionsLoader is a function that loads options asynchronously.

type Plugin

type Plugin interface {
	// Name returns the unique name of the plugin
	Name() string

	// Version returns the plugin version
	Version() string

	// Description returns a human-readable description
	Description() string

	// Commands returns the commands provided by this plugin
	Commands() []Command

	// Dependencies returns the names of plugins this plugin depends on
	Dependencies() []string

	// Initialize is called when the plugin is registered
	// This allows the plugin to perform setup before commands are added
	Initialize() error
}

Plugin represents a CLI plugin that can provide commands.

type PluginMetadata

type PluginMetadata struct {
	Name         string
	Version      string
	Description  string
	Dependencies []string
	Commands     []string // Command names provided by this plugin
}

PluginMetadata contains information about a registered plugin.

type PluginRegistry

type PluginRegistry struct {
	// contains filtered or unexported fields
}

PluginRegistry manages CLI plugins.

func NewPluginRegistry

func NewPluginRegistry() *PluginRegistry

NewPluginRegistry creates a new plugin registry.

func (*PluginRegistry) All

func (r *PluginRegistry) All() []Plugin

All returns all registered plugins.

func (*PluginRegistry) Count

func (r *PluginRegistry) Count() int

Count returns the number of registered plugins.

func (*PluginRegistry) Get

func (r *PluginRegistry) Get(name string) (Plugin, error)

Get retrieves a plugin by name.

func (*PluginRegistry) GetMetadata

func (r *PluginRegistry) GetMetadata(name string) (*PluginMetadata, error)

GetMetadata returns metadata for a specific plugin.

func (*PluginRegistry) Has

func (r *PluginRegistry) Has(name string) bool

Has checks if a plugin exists.

func (*PluginRegistry) Metadata

func (r *PluginRegistry) Metadata() []*PluginMetadata

Metadata returns metadata for all plugins.

func (*PluginRegistry) Names

func (r *PluginRegistry) Names() []string

Names returns the names of all registered plugins sorted alphabetically.

func (*PluginRegistry) Register

func (r *PluginRegistry) Register(plugin Plugin) error

Register registers a plugin.

func (*PluginRegistry) RegisterAll

func (r *PluginRegistry) RegisterAll(plugins []Plugin) error

RegisterAll registers multiple plugins with dependency resolution.

type ProgressBar

type ProgressBar interface {
	Set(current int)
	Increment()
	Finish(message string)
}

ProgressBar displays a progress bar.

type ProgressLoader

type ProgressLoader func(ctx context.Context, progress func(current, total int, message string)) ([]string, error)

SelectWithProgress prompts for selection with progress feedback Useful when loading takes multiple steps.

type Spinner

type Spinner interface {
	Update(message string)
	Stop(message string)
}

Spinner displays a spinner animation.

type TableAlignment

type TableAlignment int

TableAlignment defines column alignment.

const (
	AlignLeft TableAlignment = iota
	AlignCenter
	AlignRight
)

type TableStyle

type TableStyle int

TableStyle defines the table border style.

const (
	StyleDefault TableStyle = iota
	StyleRounded
	StyleSimple
	StyleCompact
	StyleMarkdown
)

type TableWriter

type TableWriter interface {
	SetHeader(headers []string)
	AppendRow(row []string)
	SetAlignment(alignment TableAlignment)
	SetColumnAlignment(column int, alignment TableAlignment)
	SetStyle(style TableStyle)
	SetMaxColumnWidth(width int)
	SetMinColumnWidth(width int)
	Render()
}

TableWriter provides table formatting.

Directories

Path Synopsis
examples
async_select command
interactive command
plugin command
simple command
subcommands command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL