Skip to content

Onboarding Wizard

The Onboarding module provides a step-by-step setup wizard with validation, security hardening, and configuration generation.

Overview

Guide users through initial setup:

  • Step-by-Step Flow - 6 built-in steps
  • Input Validation - Zod schemas for all inputs
  • Security - Path traversal prevention, command whitelisting
  • Configuration Generation - Creates config.json, .env, .mcp.json
  • Event System - Track progress and errors

Installation

typescript
import {
  OnboardingWizard,
  createOnboardingWizard,
  DEFAULT_STEPS,
  WELL_KNOWN_MCP_SERVERS,
  SAFE_MCP_COMMANDS,
} from '@aiversum/aiv-agents/onboarding';

Quick Start

typescript
const wizard = createOnboardingWizard({
  configDir: '~/.aiv',
});

// Track progress
wizard.on('step:complete', ({ step }) => {
  console.log(`✓ ${step.name}`);
});

wizard.on('progress', ({ percentage }) => {
  console.log(`Progress: ${percentage}%`);
});

// Start the wizard
wizard.start();

// Complete each step
await wizard.completeStep();  // Welcome
await wizard.completeStep({   // Provider
  type: 'anthropic',
  apiKey: 'sk-ant-...',
});
await wizard.completeStep({   // Workspace
  rootPath: '~/aiv-workspace',
  createStructure: true,
});
await wizard.completeStep([]); // MCP (skip)
await wizard.completeStep();   // Validate
await wizard.completeStep();   // Complete

// Get result
const result = wizard.getResult();
console.log('Config saved to:', result.configPath);

Built-in Steps

StepIDRequiredDescription
1welcomeYesIntroduction to AIV
2providerYesConfigure AI provider
3workspaceYesSet up workspace
4mcpNoConfigure MCP servers
5validateYesTest configuration
6completeYesSave configuration

Step Details

1. Welcome

No input required. Displays introduction.

typescript
await wizard.completeStep();

2. Provider Configuration

Configure your AI provider:

typescript
// Anthropic
await wizard.completeStep({
  type: 'anthropic',
  apiKey: 'sk-ant-api03-...',
  model: 'claude-sonnet-4-20250514', // Optional
});

// Azure OpenAI
await wizard.completeStep({
  type: 'azure',
  endpoint: 'https://resource.openai.azure.com',
  apiKey: '...', // Optional if using az login
  model: 'gpt-4o',
});

// OpenRouter
await wizard.completeStep({
  type: 'openrouter',
  apiKey: 'sk-or-v1-...',
  model: 'anthropic/claude-sonnet-4',
});

3. Workspace Configuration

Set up your working directory:

typescript
await wizard.completeStep({
  rootPath: '~/aiv-workspace',
  vaultPath: '~/aiv-workspace/vault',     // Optional
  projectsPath: '~/aiv-workspace/projects', // Optional
  createStructure: true,
});

When createStructure is true, creates:

aiv-workspace/
├── vault/
├── projects/
├── inbox/
└── reports/

4. MCP Servers (Optional)

Configure Model Context Protocol servers:

typescript
// Use well-known servers
const servers = wizard.getWellKnownServers();
// [
//   { name: 'microsoft-learn', ... },
//   { name: 'context7', ... },
//   { name: 'filesystem', ... },
// ]

// Enable some
await wizard.completeStep([
  { name: 'context7', enabled: true, command: 'npx', args: ['-y', '@context7/mcp-server'] },
]);

// Or skip
wizard.skipStep('User chose to skip');

5. Validation

Tests the configuration:

typescript
await wizard.completeStep();
// Validates:
// - Provider has API key (except Azure with az login)
// - Workspace is configured
// - No duplicate MCP server names

6. Complete

Saves configuration files:

typescript
await wizard.completeStep();
// Creates:
// - ~/.aiv/config.json
// - ~/.aiv/.env (with API keys)
// - {workspace}/.mcp.json (if MCP configured)

Going Back

typescript
if (wizard.goBack()) {
  console.log('Returned to previous step');
}

Skipping Optional Steps

typescript
const mcpStep = wizard.getCurrentStep();
if (!mcpStep.required) {
  wizard.skipStep('User chose to skip MCP setup');
}

Aborting

typescript
wizard.abort('User cancelled');

// Check if aborted
if (wizard.isAborted()) {
  console.log('Wizard was aborted');
}

Resetting

typescript
wizard.reset();
// Returns to initial state

Events

typescript
wizard.on('step:start', ({ step }) => {
  console.log(`Starting: ${step.name}`);
});

wizard.on('step:complete', ({ step, data }) => {
  console.log(`Completed: ${step.name}`);
});

wizard.on('step:skip', ({ step, reason }) => {
  console.log(`Skipped: ${step.name} - ${reason}`);
});

wizard.on('step:error', ({ step, error }) => {
  console.error(`Error in ${step.name}:`, error);
});

wizard.on('validation:start', ({ step }) => {
  console.log(`Validating ${step.name}...`);
});

wizard.on('validation:complete', ({ step, result }) => {
  if (!result.valid) {
    console.error('Validation failed:', result.errors);
  }
});

wizard.on('progress', ({ currentStep, totalSteps, percentage }) => {
  console.log(`Step ${currentStep + 1}/${totalSteps} (${percentage}%)`);
});

wizard.on('complete', ({ result }) => {
  console.log('Wizard complete!');
  console.log('Config:', result.configPath);
  console.log('Created:', result.createdPaths);
});

wizard.on('abort', ({ reason }) => {
  console.log(`Aborted: ${reason}`);
});

Custom Steps

Register custom step handlers:

typescript
import { registerStepHandler } from '@aiversum/aiv-agents/onboarding';

registerStepHandler('custom-step', async (step, context, input) => {
  // Validate input
  if (!input || typeof input !== 'object') {
    return {
      success: false,
      error: new Error('Invalid input'),
      warnings: [],
    };
  }

  // Perform step logic
  const result = await doSomething(input);

  return {
    success: true,
    data: result,
    warnings: [],
  };
});

// Use custom steps
const wizard = createOnboardingWizard({
  steps: [
    ...DEFAULT_STEPS.slice(0, 3),
    {
      id: 'custom-step',
      name: 'Custom',
      description: 'My custom step',
      required: true,
      status: 'pending',
      order: 3,
    },
    ...DEFAULT_STEPS.slice(3),
  ],
});

Security Features

API Key Validation

typescript
// Format validation
'sk-ant-...'  // Anthropic ✓
'sk-or-...'   // OpenRouter ✓
'invalid'     // Error ✗

// No whitespace
'key with spaces'  // Error ✗

Path Validation

typescript
// Path traversal blocked
'../../../etc/passwd'  // Error ✗

// Null bytes blocked
'/path\0/file'  // Error ✗

// Invalid characters blocked
'<script>alert(1)</script>'  // Error ✗

MCP Command Whitelisting

Only allowed commands:

  • npx
  • node
  • python
  • python3
  • uvx
  • docker
typescript
// Safe
{ command: 'npx', args: ['-y', '@test/mcp'] }  // ✓

// Blocked
{ command: '/bin/bash', args: ['-c', 'rm -rf /'] }  // Error ✗

Environment Variable Validation

typescript
// Name must be uppercase
{ env: { 'API_KEY': 'value' } }  // ✓
{ env: { 'apiKey': 'value' } }   // Error ✗

// No newlines in values
{ env: { 'KEY': 'value\nmalicious' } }  // Error ✗

File Permissions

Generated files have secure permissions:

  • config.json - 0o600 (owner read/write)
  • .env - 0o600 (owner read/write)
  • Config directory - 0o700 (owner only)

State Management

typescript
// Get current state
const state = wizard.getState();
// {
//   currentStep: 2,
//   totalSteps: 6,
//   steps: [...],
//   provider: {...},
//   workspace: {...},
//   mcpServers: [...],
//   startedAt: Date,
// }

// Get current step
const step = wizard.getCurrentStep();
// { id: 'provider', name: 'AI Provider', ... }

// Get progress
const progress = wizard.getProgress(); // 33 (percentage)

// Check completion
const complete = wizard.isComplete(); // boolean

API Reference

See the OnboardingWizard API Reference for complete documentation.

Testing

bash
# Run onboarding module tests
npm test -- --grep "onboarding"

# Test count: 146 tests

Released under the MIT License.