Setup

Set up your development environment for contributing to ao-forge.

Overview

This guide will help you set up a development environment for contributing to ao-forge. We'll cover everything from cloning the repository to running tests.

Prerequisites

Before you begin, make sure you have the following installed:

Repository Setup

Clone the Repository

# Clone the repository
git clone https://github.com/ao-forge/ao-forge.git
cd ao-forge

# Add your fork as a remote
git remote add fork https://github.com/YOUR_USERNAME/ao-forge.git

Install Dependencies

# Install dependencies
npm install

# Or using pnpm
pnpm install

# Or using yarn
yarn install

Verify Installation

# Check if everything is working
npm run test

# Check if CLI is working
npm run build
node dist/cli.js --version

Development Environment

VS Code Setup

{
  "recommendations": [
    "ms-vscode.vscode-typescript-next",
    "bradlc.vscode-tailwindcss",
    "esbenp.prettier-vscode",
    "ms-vscode.vscode-eslint",
    "ms-vscode.vscode-json",
    "redhat.vscode-yaml",
    "ms-vscode.vscode-markdown"
  ]
}

Workspace Settings

{
  "typescript.preferences.importModuleSpecifier": "relative",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "files.associations": {
    "*.lua": "lua"
  }
}

Environment Variables

Create Environment File

# Copy example environment file
cp .env.example .env

# Edit environment file
nano .env

Environment Configuration

# .env
NODE_ENV=development
AO_ENV=testnet
AO_GATEWAY=https://arweave.net
AO_WALLET_PATH=./wallet.json

Project Structure

Directory Layout

ao-forge/
├── src/                    # Source code
│   ├── cli/               # CLI commands
│   ├── managers/          # Manager classes
│   ├── templates/         # Project templates
│   ├── utils/             # Utility functions
│   └── types/             # TypeScript types
├── templates/             # Project templates
├── docs/                  # Documentation
├── tests/                 # Test files
├── examples/              # Example projects
├── scripts/               # Build and utility scripts
├── .github/               # GitHub workflows
├── package.json           # Package configuration
├── tsconfig.json          # TypeScript configuration
├── jest.config.js         # Jest configuration
└── README.md              # Project README

Key Files

  • src/cli/index.ts - Main CLI entry point
  • src/managers/ - Manager classes for different functionality
  • templates/ - Project templates
  • tests/ - Test files
  • package.json - Package configuration and scripts

Development Workflow

Running the Development Server

# Start development server
npm run dev

# Watch for changes
npm run watch

# Build the project
npm run build

Running Tests

# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage

# Run specific test file
npm test -- tests/cli/init.test.ts

Linting and Formatting

# Run linter
npm run lint

# Fix linting issues
npm run lint:fix

# Format code
npm run format

# Check formatting
npm run format:check

Testing

Test Structure

// tests/cli/init.test.ts
import { InitCommand } from '../../src/cli/init'
import { ProjectManager } from '../../src/managers/project'

describe('InitCommand', () => {
  let initCommand: InitCommand
  let projectManager: ProjectManager

  beforeEach(() => {
    initCommand = new InitCommand()
    projectManager = new ProjectManager()
  })

  it('should create a new project', async () => {
    // Test implementation
  })
})

Test Utilities

// tests/utils/test-helpers.ts
import { execSync } from 'child_process'
import { mkdtemp, rm } from 'fs/promises'
import { tmpdir } from 'os'
import { join } from 'path'

export async function createTempDir(): Promise<string> {
  const tempDir = await mkdtemp(join(tmpdir(), 'ao-forge-test-'))
  return tempDir
}

export async function cleanupTempDir(dir: string): Promise<void> {
  await rm(dir, { recursive: true, force: true })
}

export function runCommand(command: string, cwd: string): string {
  return execSync(command, { cwd, encoding: 'utf8' })
}

Mocking

// tests/mocks/process-manager.mock.ts
export const mockProcessManager = {
  startProcess: jest.fn(),
  stopProcess: jest.fn(),
  listProcesses: jest.fn(),
  getStatus: jest.fn()
}

Building

Build Process

# Build the project
npm run build

# Build with type checking
npm run build:check

# Build for production
npm run build:prod

Build Configuration

{
  "scripts": {
    "build": "tsc",
    "build:check": "tsc --noEmit",
    "build:prod": "tsc && npm run optimize",
    "optimize": "terser dist/**/*.js -o dist/cli.min.js"
  }
}

Debugging

Debug Configuration

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug CLI",
      "type": "node",
      "request": "launch",
      "program": "${workspaceFolder}/dist/cli.js",
      "args": ["init", "test-project"],
      "console": "integratedTerminal",
      "skipFiles": ["<node_internals>/**"]
    }
  ]
}

Debug Commands

# Debug with Node.js
node --inspect dist/cli.js init test-project

# Debug with VS Code
# Set breakpoints and use F5 to start debugging

Git Workflow

Branch Strategy

# Create feature branch
git checkout -b feature/new-feature

# Create bugfix branch
git checkout -b bugfix/fix-issue

# Create hotfix branch
git checkout -b hotfix/critical-fix

Commit Messages

# Use conventional commits
git commit -m "feat: add new command for process management"
git commit -m "fix: resolve issue with build process"
git commit -m "docs: update installation guide"
git commit -m "test: add tests for new functionality"

Pull Request Process

  1. Create feature branch from main
  2. Make changes and commit
  3. Run tests and ensure they pass
  4. Create pull request with description
  5. Address review feedback
  6. Merge after approval

Code Style

TypeScript Guidelines

// Use interfaces for object shapes
interface User {
  id: string
  name: string
  email: string
}

// Use type aliases for unions
type Status = 'pending' | 'approved' | 'rejected'

// Use enums for constants
enum ErrorCode {
  NOT_FOUND = 'NOT_FOUND',
  VALIDATION_ERROR = 'VALIDATION_ERROR'
}

Naming Conventions

// Use PascalCase for classes
class ProjectManager {}

// Use camelCase for functions and variables
const projectName = 'my-project'
function createProject() {}

// Use UPPER_CASE for constants
const DEFAULT_PORT = 3000

Documentation

/**
 * Creates a new project with the specified options
 * @param options - Project creation options
 * @returns Promise that resolves when project is created
 * @throws {Error} When project creation fails
 */
async function createProject(options: CreateProjectOptions): Promise<void> {
  // Implementation
}

Troubleshooting

Common Issues

Build Failures

# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm install

# Check TypeScript errors
npm run build:check

Test Failures

# Run tests with verbose output
npm test -- --verbose

# Run specific test
npm test -- --testNamePattern="should create project"

Dependency Issues

# Check for outdated packages
npm outdated

# Update dependencies
npm update

# Check for security vulnerabilities
npm audit

Next Steps

Getting Help

Resources

Contact