namespace ClaudeDo.Installer.Core; public sealed class InstallerService { private readonly IEnumerable _steps; public InstallerService(IEnumerable steps) => _steps = steps; public async Task> ExecuteAsync( InstallContext ctx, IProgress progress, CancellationToken ct) { var results = new List<(IInstallStep, StepResult)>(); foreach (var step in _steps) { ct.ThrowIfCancellationRequested(); progress.Report(new StepProgress(step.Name, StepStatus.Running)); var lineProgress = new Progress(msg => progress.Report(new StepProgress(step.Name, StepStatus.Running, msg))); try { var result = await step.ExecuteAsync(ctx, lineProgress, ct); var status = result.Success ? StepStatus.Done : StepStatus.Failed; progress.Report(new StepProgress(step.Name, status, result.ErrorMessage)); results.Add((step, result)); if (!result.Success) break; } catch (OperationCanceledException) { progress.Report(new StepProgress(step.Name, StepStatus.Failed, "Cancelled")); results.Add((step, StepResult.Fail("Cancelled"))); break; } catch (Exception ex) { progress.Report(new StepProgress(step.Name, StepStatus.Failed, ex.Message)); results.Add((step, StepResult.Fail(ex.Message))); break; } } return results; } }