Skip to content

Command Guardrails for handling out of sequence cli commands and context aware error messages #117

@supernovahs

Description

@supernovahs

Command Flow Guardrails: Dependency Management for CLI Commands

Overview

Command Flow Guardrails detect when CLI commands are run out of expected sequence and provide context-aware error messages to guide users. This feature ensures commands like avs call (which depends on avs contract-deploy) fail gracefully with helpful guidance.

Key Components

  1. Command Dependency Definitions: Map of commands to their prerequisites
  2. Command History Tracking: In-memory registry of executed commands
  3. Dependency Checking Middleware: Validates dependencies before execution
  4. Contextual Error Messages: Guides users to the correct next actions

Implementation

1. Command Dependency Definition

// CommandDependency defines a command dependency relationship
type CommandDependency struct {
    Command       string     // Command that has dependencies
    DependsOn     []string   // Commands that must be run before this command
    ErrorMessage  string     // Helpful message when dependency isn't met
    CheckFunc     func() bool // Optional additional validation
}

// Sample dependencies
var CommandFlowDependencies = []CommandDependency{
    {
        Command:   "call",
        DependsOn: []string{"deploy-contracts"},
        ErrorMessage: "The 'avs call' command requires contract deployment. " +
            "Please run 'devkit avs devnet start' or 'devkit avs devnet deploy-contracts' first.",
        CheckFunc: checkContractsDeployed,
    },
    // Other dependencies...
}

2. Command Execution Tracking

// Track command execution history
var commandHistory = struct {
    executedCommands map[string]bool
    mu               sync.Mutex
}{
    executedCommands: make(map[string]bool),
}

// Record successful command execution
func recordCommandExecution(command string) {
    commandHistory.mu.Lock()
    defer commandHistory.mu.Unlock()
    commandHistory.executedCommands[command] = true
}

3. Dependency Checking Middleware

// Middleware that enforces command dependencies
func WithCommandDependencyCheck(action cli.ActionFunc) cli.ActionFunc {
    return func(ctx *cli.Context) error {
        cmdName := ctx.Command.Name
        
        // Skip checks for create command (entry point) 
        if cmdName == "create" {
            result := action(ctx)
            if result == nil {
                recordCommandExecution(cmdName)
            }
            return result
        }

        // Check dependencies
        for _, dep := range CommandFlowDependencies {
            if dep.Command == cmdName {
                for _, depCmd := range dep.DependsOn {
                    if !hasCommandBeenExecuted(depCmd) && 
                       !(dep.CheckFunc != nil && dep.CheckFunc()) {
                        return errors.New(dep.ErrorMessage)
                    }
                }
            }
        }

        // Execute command and record success
        result := action(ctx)
        if result == nil {
            recordCommandExecution(cmdName)
        }
        return result
    }
}

4. Integration with CLI Framework

func main() {
    
    actionChain := hooks.NewActionChain()
    actionChain.Use(WithCommandDependencyCheck)

    
    hooks.ApplyMiddleware(app.Commands, actionChain)
    
}

User Experience

When a user attempts to run a command before its prerequisites:

$ devkit avs call  signature="(uint256)" args="(5)"

Error: The 'avs call' command requires contract deployment. 
Please run 'devkit avs devnet start' or 'devkit avs devnet deploy-contracts' first.
  • Users receive clear error message about the correct command sequence and next steps.

Additional Validations

For complex dependencies that can't be verified by simple command history:

// Validation function example
func checkContractsDeployed() bool {
    // Check for config files with deployed contract addresses
    contextPath := filepath.Join("config", "contexts", "devnet.yaml")
    if _, err := os.Stat(contextPath); os.IsNotExist(err) {
        return false
    }
    
    // Parse YAML and verify contract addresses exist
    // [Implementation details...]
    
    return contractsExist
}

Open questions

  • Is there any check that should be made for create command ?

Example validations

  • Check that fork url is set before devnet start is called in the context file

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions