run method

Implementation

Future<BootstrapResult> run() async {
  final steps = _buildSteps();
  final progress = BootstrapProgress(steps: steps);
  progress.start();

  final warnings = <String>[];
  final errors = <String>[];
  ProjectInfo? projectInfo;
  List<MemoryFile> memoryFiles = [];
  String? shell;
  Map<String, dynamic> settings = {};

  for (int i = 0; i < steps.length; i++) {
    final step = steps[i];
    onProgress?.call(progress);

    if (config.shouldSkip(step.id)) {
      step.status = BootstrapStepStatus.skipped;
      _log('Skipping: ${step.name}');
      progress.advanceStep();
      continue;
    }

    step.status = BootstrapStepStatus.running;
    final sw = Stopwatch()..start();

    try {
      final result = await _executeStep(step.id).timeout(config.stepTimeout);
      sw.stop();
      step.duration = sw.elapsed;

      if (result is ProjectInfo) projectInfo = result;
      if (result is List<MemoryFile>) memoryFiles = result;
      if (result is String && step.id == 'detect_shell') shell = result;
      if (result is Map<String, dynamic> && step.id == 'load_settings') {
        settings = result;
      }
      if (result is String && result.startsWith('WARN:')) {
        step.warning = result.substring(5);
        warnings.add(step.warning!);
      }

      step.status = BootstrapStepStatus.completed;
      _log('Done: ${step.name} (${step.duration.inMilliseconds}ms)');
    } on TimeoutException {
      sw.stop();
      step.duration = sw.elapsed;
      step.status = BootstrapStepStatus.failed;
      step.error = 'Timed out after ${config.stepTimeout.inSeconds}s';
      errors.add('${step.name}: ${step.error}');
      _log('Timeout: ${step.name}');
    } catch (e) {
      sw.stop();
      step.duration = sw.elapsed;
      step.status = BootstrapStepStatus.failed;
      step.error = e.toString();
      errors.add('${step.name}: $e');
      _log('Failed: ${step.name}: $e');
    }

    progress.advanceStep();
  }

  progress.stop();

  final resultStatus = errors.isEmpty
      ? BootstrapResultStatus.success
      : warnings.isNotEmpty || progress.completedCount > progress.failedCount
      ? BootstrapResultStatus.partialSuccess
      : BootstrapResultStatus.failure;

  final result = BootstrapResult(
    status: resultStatus,
    steps: steps,
    warnings: warnings,
    errors: errors,
    projectInfo: projectInfo,
    memoryFiles: memoryFiles,
    totalDuration: progress.elapsed,
    shell: shell,
    settings: settings,
  );

  _log(result.formatReport());
  return result;
}