cli

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 28, 2025 License: MIT Imports: 16 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