Commands API

Reference for command class structure and implementation in ao-forge.

Overview

ao-forge uses a command-based architecture where each CLI command is implemented as a class with specific methods and options. This document provides a comprehensive reference for all command classes.

Base Command Class

All commands extend from the base Command class:

abstract class Command {
  abstract name: string
  abstract description: string
  abstract options: CommandOption[]
  
  abstract execute(args: string[], options: Record<string, any>): Promise<void>
  
  protected validateArgs(args: string[]): boolean
  protected validateOptions(options: Record<string, any>): boolean
  protected showHelp(): void
  protected showError(message: string): void
}

interface CommandOption {
  name: string
  alias?: string
  description: string
  type: 'string' | 'boolean' | 'number'
  required?: boolean
  default?: any
}

Init Command

Creates a new ao-forge project.

class InitCommand extends Command {
  name = 'init'
  description = 'Create a new AO-powered application'
  
  options: CommandOption[] = [
    {
      name: 'framework',
      alias: 'f',
      description: 'Framework to use (nextjs, nuxtjs)',
      type: 'string'
    },
    {
      name: 'package-manager',
      alias: 'p',
      description: 'Package manager (npm, pnpm, yarn)',
      type: 'string',
      default: 'pnpm'
    },
    {
      name: 'template',
      alias: 't',
      description: 'Template to use',
      type: 'string',
      default: 'default'
    },
    {
      name: 'path',
      description: 'Path to create project',
      type: 'string'
    },
    {
      name: 'skip-install',
      description: 'Skip package installation',
      type: 'boolean',
      default: false
    },
    {
      name: 'force',
      description: 'Overwrite existing files',
      type: 'boolean',
      default: false
    }
  ]
  
  async execute(args: string[], options: Record<string, any>): Promise<void> {
    const projectName = args[0]
    if (!projectName) {
      this.showError('Project name is required')
      return
    }
    
    const projectManager = new ProjectManager()
    await projectManager.createProject({
      name: projectName,
      framework: options.framework,
      packageManager: options['package-manager'],
      template: options.template,
      path: options.path,
      skipInstall: options['skip-install'],
      force: options.force
    })
  }
}

Dev Command

Starts the development server.

class DevCommand extends Command {
  name = 'dev'
  description = 'Start the development server'
  
  options: CommandOption[] = [
    {
      name: 'port',
      description: 'Port for development server',
      type: 'number',
      default: 3000
    },
    {
      name: 'host',
      description: 'Host for development server',
      type: 'string',
      default: 'localhost'
    },
    {
      name: 'open',
      description: 'Open browser automatically',
      type: 'boolean',
      default: false
    },
    {
      name: 'framework',
      description: 'Framework to use',
      type: 'string'
    },
    {
      name: 'process',
      description: 'Start specific AO process',
      type: 'string'
    },
    {
      name: 'monitor',
      description: 'Enable process monitoring',
      type: 'boolean',
      default: false
    },
    {
      name: 'debug',
      description: 'Enable debug mode',
      type: 'boolean',
      default: false
    },
    {
      name: 'verbose',
      description: 'Verbose logging',
      type: 'boolean',
      default: false
    }
  ]
  
  async execute(args: string[], options: Record<string, any>): Promise<void> {
    const devServer = new DevServer({
      port: options.port,
      host: options.host,
      open: options.open,
      framework: options.framework,
      process: options.process,
      monitor: options.monitor,
      debug: options.debug,
      verbose: options.verbose
    })
    
    await devServer.start()
  }
}

AI Command

Generates code using AI.

class AICommand extends Command {
  name = 'ai'
  description = 'Generate code using AI'
  
  options: CommandOption[] = [
    {
      name: 'model',
      description: 'AI model to use',
      type: 'string',
      default: 'gpt-4'
    },
    {
      name: 'output',
      description: 'Output directory',
      type: 'string',
      default: './ao/'
    },
    {
      name: 'include-docs',
      description: 'Include documentation',
      type: 'boolean',
      default: false
    },
    {
      name: 'generate-types',
      description: 'Generate TypeScript types',
      type: 'boolean',
      default: false
    },
    {
      name: 'prompt',
      description: 'Custom prompt',
      type: 'string'
    },
    {
      name: 'prompt-file',
      description: 'Prompt from file',
      type: 'string'
    }
  ]
  
  async execute(args: string[], options: Record<string, any>): Promise<void> {
    const subcommand = args[0]
    const name = args[1]
    const description = args[2]
    
    if (!subcommand || !name || !description) {
      this.showError('Usage: ao-forge ai generate <type> <name> <description>')
      return
    }
    
    const aiManager = new AIManager()
    const result = await aiManager.generate({
      type: subcommand,
      name: name,
      description: description,
      model: options.model,
      output: options.output,
      includeDocs: options['include-docs'],
      generateTypes: options['generate-types'],
      prompt: options.prompt,
      promptFile: options['prompt-file']
    })
    
    if (result.success) {
      console.log('Code generated successfully!')
    } else {
      this.showError(result.error || 'Code generation failed')
    }
  }
}

Build Command

Builds the project for production.

class BuildCommand extends Command {
  name = 'build'
  description = 'Build the project for production'
  
  options: CommandOption[] = [
    {
      name: 'framework',
      description: 'Framework to use',
      type: 'string'
    },
    {
      name: 'output',
      description: 'Output directory',
      type: 'string',
      default: './dist'
    },
    {
      name: 'optimize',
      description: 'Enable optimization',
      type: 'boolean',
      default: true
    },
    {
      name: 'source-maps',
      description: 'Generate source maps',
      type: 'boolean',
      default: false
    },
    {
      name: 'minify',
      description: 'Minify assets',
      type: 'boolean',
      default: true
    },
    {
      name: 'static',
      description: 'Build for static hosting',
      type: 'boolean',
      default: false
    },
    {
      name: 'server',
      description: 'Build for server deployment',
      type: 'boolean',
      default: false
    },
    {
      name: 'process',
      description: 'Build AO processes',
      type: 'boolean',
      default: true
    },
    {
      name: 'deploy',
      description: 'Deploy after build',
      type: 'boolean',
      default: false
    },
    {
      name: 'platform',
      description: 'Deployment platform',
      type: 'string'
    },
    {
      name: 'env',
      description: 'Build environment',
      type: 'string',
      default: 'production'
    }
  ]
  
  async execute(args: string[], options: Record<string, any>): Promise<void> {
    const buildManager = new BuildManager()
    const result = await buildManager.build({
      framework: options.framework,
      output: options.output,
      optimize: options.optimize,
      sourceMaps: options['source-maps'],
      minify: options.minify,
      static: options.static,
      server: options.server,
      process: options.process,
      env: options.env
    })
    
    if (result.success) {
      console.log('Build completed successfully!')
      
      if (options.deploy) {
        const deployManager = new DeploymentManager()
        await deployManager.deploy({
          platform: options.platform,
          environment: options.env
        })
      }
    } else {
      this.showError('Build failed: ' + result.errors.join(', '))
    }
  }
}

Config Command

Manages configuration settings.

class ConfigCommand extends Command {
  name = 'config'
  description = 'Manage configuration settings'
  
  options: CommandOption[] = [
    {
      name: 'file',
      description: 'Configuration file path',
      type: 'string',
      default: './ao.config.yml'
    },
    {
      name: 'format',
      description: 'Output format (json, yaml)',
      type: 'string',
      default: 'yaml'
    }
  ]
  
  async execute(args: string[], options: Record<string, any>): Promise<void> {
    const subcommand = args[0]
    const key = args[1]
    const value = args[2]
    
    const configManager = new ConfigManager()
    
    switch (subcommand) {
      case 'get':
        if (!key) {
          this.showError('Key is required for get command')
          return
        }
        const configValue = await configManager.get(key, options.file)
        console.log(configValue)
        break
        
      case 'set':
        if (!key || !value) {
          this.showError('Key and value are required for set command')
          return
        }
        await configManager.set(key, value, options.file)
        console.log('Configuration updated')
        break
        
      case 'list':
        const config = await configManager.list(options.file)
        console.log(JSON.stringify(config, null, 2))
        break
        
      case 'validate':
        const validation = await configManager.validate(options.file)
        if (validation.valid) {
          console.log('Configuration is valid')
        } else {
          this.showError('Configuration validation failed: ' + validation.errors.join(', '))
        }
        break
        
      case 'reset':
        await configManager.reset(options.file)
        console.log('Configuration reset to defaults')
        break
        
      default:
        this.showError('Unknown subcommand: ' + subcommand)
    }
  }
}

Process Command

Manages AO processes.

class ProcessCommand extends Command {
  name = 'process'
  description = 'Manage AO processes'
  
  options: CommandOption[] = [
    {
      name: 'wallet',
      description: 'Wallet file path',
      type: 'string'
    },
    {
      name: 'module',
      description: 'Module ID',
      type: 'string'
    },
    {
      name: 'cron',
      description: 'Cron schedule',
      type: 'string'
    },
    {
      name: 'sqlite',
      description: 'Use SQLite module',
      type: 'boolean',
      default: false
    },
    {
      name: 'monitor',
      description: 'Enable monitoring',
      type: 'boolean',
      default: false
    }
  ]
  
  async execute(args: string[], options: Record<string, any>): Promise<void> {
    const subcommand = args[0]
    const processName = args[1]
    
    const processManager = new ProcessManager()
    
    switch (subcommand) {
      case 'start':
        await processManager.startProcess({
          name: processName,
          wallet: options.wallet,
          module: options.module,
          cron: options.cron,
          sqlite: options.sqlite,
          monitor: options.monitor
        })
        console.log('Process started successfully')
        break
        
      case 'stop':
        await processManager.stopProcess(processName)
        console.log('Process stopped successfully')
        break
        
      case 'restart':
        await processManager.restartProcess(processName)
        console.log('Process restarted successfully')
        break
        
      case 'list':
        const processes = await processManager.listProcesses()
        console.table(processes)
        break
        
      case 'status':
        const status = await processManager.getStatus(processName)
        console.log('Status:', status)
        break
        
      case 'monitor':
        await processManager.monitorProcess(processName)
        break
        
      default:
        this.showError('Unknown subcommand: ' + subcommand)
    }
  }
}

Version Command

Displays version information.

class VersionCommand extends Command {
  name = 'version'
  description = 'Display version information'
  
  options: CommandOption[] = [
    {
      name: 'verbose',
      description: 'Show detailed version information',
      type: 'boolean',
      default: false
    },
    {
      name: 'json',
      description: 'Output in JSON format',
      type: 'boolean',
      default: false
    }
  ]
  
  async execute(args: string[], options: Record<string, any>): Promise<void> {
    const versionInfo = await this.getVersionInfo(options.verbose)
    
    if (options.json) {
      console.log(JSON.stringify(versionInfo, null, 2))
    } else {
      this.displayVersion(versionInfo)
    }
  }
  
  private async getVersionInfo(verbose: boolean): Promise<VersionInfo> {
    const packageJson = await this.loadPackageJson()
    
    return {
      aoForge: packageJson.version,
      node: process.version,
      npm: await this.getNpmVersion(),
      aos: await this.getAOSVersion(),
      framework: await this.getFrameworkVersion(),
      packageManager: await this.getPackageManagerVersion()
    }
  }
  
  private displayVersion(info: VersionInfo): void {
    console.log(`ao-forge: ${info.aoForge}`)
    console.log(`Node.js: ${info.node}`)
    console.log(`npm: ${info.npm}`)
    
    if (info.aos) {
      console.log(`AOS CLI: ${info.aos}`)
    }
    
    if (info.framework) {
      console.log(`Framework: ${info.framework}`)
    }
    
    if (info.packageManager) {
      console.log(`Package Manager: ${info.packageManager}`)
    }
  }
}

interface VersionInfo {
  aoForge: string
  node: string
  npm: string
  aos?: string
  framework?: string
  packageManager?: string
}

Command Registry

Commands are registered in the main CLI application:

class CLI {
  private commands: Map<string, Command> = new Map()
  
  constructor() {
    this.registerCommands()
  }
  
  private registerCommands(): void {
    this.commands.set('init', new InitCommand())
    this.commands.set('dev', new DevCommand())
    this.commands.set('ai', new AICommand())
    this.commands.set('build', new BuildCommand())
    this.commands.set('config', new ConfigCommand())
    this.commands.set('process', new ProcessCommand())
    this.commands.set('version', new VersionCommand())
  }
  
  async execute(args: string[]): Promise<void> {
    const commandName = args[0]
    const command = this.commands.get(commandName)
    
    if (!command) {
      console.error(`Unknown command: ${commandName}`)
      this.showHelp()
      return
    }
    
    const { options, remainingArgs } = this.parseOptions(args.slice(1), command.options)
    await command.execute(remainingArgs, options)
  }
}

Best Practices

  1. Command Design - Keep commands focused and single-purpose
  2. Option Validation - Validate all options and arguments
  3. Error Handling - Provide clear error messages
  4. Help Text - Include comprehensive help information
  5. Testing - Write tests for all commands