Public/Initialize-LeadForge.ps1
|
function Initialize-LeadForge { <# .SYNOPSIS First-run setup and validation for LeadForge. .DESCRIPTION Walks the user through: 1. AI provider API key configuration check 2. Owner profile creation/selection 3. Optional search/enrichment API keys 4. Connectivity validation In non-interactive mode (-NonInteractive), returns a structured result suitable for CI/automation use. Throws on critical failures when -Strict. .EXAMPLE Initialize-LeadForge .EXAMPLE Initialize-LeadForge -SkipValidation .EXAMPLE Initialize-LeadForge -NonInteractive -Strict #> [CmdletBinding()] param( [switch]$SkipValidation, [switch]$NonInteractive, [switch]$Strict ) $moduleRoot = $PSScriptRoot | Split-Path -Parent $profilesDir = Join-Path $moduleRoot 'profiles' # --- Gather state (shared by interactive and non-interactive) --- $providers = @( @{ Name = 'OpenAI'; EnvVar = 'OPENAI_API_KEY'; SecretName = 'openai-api-key' } @{ Name = 'Anthropic'; EnvVar = 'ANTHROPIC_API_KEY'; SecretName = 'anthropic-api-key' } @{ Name = 'Gemini'; EnvVar = 'GEMINI_API_KEY'; SecretName = 'gemini-api-key' } ) $optionalApis = @( @{ Name = 'Brave Search'; EnvVar = 'BRAVE_SEARCH_API_KEY' } @{ Name = 'Firecrawl'; EnvVar = 'FIRECRAWL_API_KEY' } ) $configuredProviders = @() foreach ($p in $providers) { $hasKey = [bool][Environment]::GetEnvironmentVariable($p.EnvVar) if (-not $hasKey -and (Get-Command Get-PCSecret -ErrorAction SilentlyContinue)) { $hasKey = [bool](Get-PCSecret -Name $p.SecretName -ErrorAction SilentlyContinue) } if ($hasKey) { $configuredProviders += $p.Name } } $existingProfiles = @() if (Test-Path $profilesDir) { $existingProfiles = @(Get-ChildItem $profilesDir -Filter '*.json' | Select-Object -ExpandProperty BaseName) } $configuredSearchApis = @($optionalApis | Where-Object { [Environment]::GetEnvironmentVariable($_.EnvVar) } | ForEach-Object { $_.Name }) # --- Non-interactive: return result immediately --- if ($NonInteractive) { $result = [PSCustomObject]@{ Ready = ($configuredProviders.Count -gt 0 -and $existingProfiles.Count -gt 0) Providers = $configuredProviders Profiles = $existingProfiles SearchAPIs = $configuredSearchApis ValidationSkipped = [bool]$SkipValidation } if ($Strict -and -not $result.Ready) { throw "LeadForge not ready: $($configuredProviders.Count) providers, $($existingProfiles.Count) profiles" } return $result } # --- Interactive mode --- Write-Host "`n═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " LeadForge — First-Run Setup" -ForegroundColor Cyan Write-Host "═══════════════════════════════════════════════════════════════`n" -ForegroundColor Cyan # --- Step 1: AI Provider --- Write-Host " [1/4] AI Provider Configuration" -ForegroundColor White Write-Host " LeadForge needs an AI provider for email analysis and research." -ForegroundColor Gray Write-Host "" foreach ($p in $providers) { $hasKey = [bool][Environment]::GetEnvironmentVariable($p.EnvVar) if (-not $hasKey -and (Get-Command Get-PCSecret -ErrorAction SilentlyContinue)) { $hasKey = [bool](Get-PCSecret -Name $p.SecretName -ErrorAction SilentlyContinue) } $status = if ($hasKey) { '[OK]' } else { '[--]' } $color = if ($hasKey) { 'Green' } else { 'DarkGray' } Write-Host " $status $($p.Name)" -ForegroundColor $color } if ($configuredProviders.Count -eq 0) { Write-Host "" Write-Host " No AI provider configured!" -ForegroundColor Red Write-Host " Set at least one API key:" -ForegroundColor Yellow Write-Host ' $env:OPENAI_API_KEY = "sk-..."' -ForegroundColor Gray Write-Host ' $env:ANTHROPIC_API_KEY = "sk-ant-..."' -ForegroundColor Gray Write-Host ' $env:GEMINI_API_KEY = "AIza..."' -ForegroundColor Gray Write-Host "" Write-Host " Or use PowerCraft.Secrets:" -ForegroundColor Gray Write-Host " Set-PCSecret -Name 'openai-api-key' -Value 'sk-...'" -ForegroundColor Gray Write-Host "" } else { Write-Host " Providers ready: $($configuredProviders -join ', ')" -ForegroundColor Green } # --- Step 2: Owner Profile --- Write-Host "" Write-Host " [2/4] Owner Profile" -ForegroundColor White Write-Host " Profiles define your identity (domains to exclude) and scoring weights." -ForegroundColor Gray Write-Host "" if ($existingProfiles.Count -gt 0) { Write-Host " Available profiles:" -ForegroundColor Gray foreach ($prof in $existingProfiles) { Write-Host " - $prof" -ForegroundColor Cyan } } else { Write-Host " No profiles found. Create one at: $profilesDir\Default.json" -ForegroundColor Yellow } # --- Step 3: Search/Enrichment APIs (optional) --- Write-Host "" Write-Host " [3/4] Search & Enrichment APIs (optional)" -ForegroundColor White Write-Host " These enable contact research via web search and website scraping." -ForegroundColor Gray Write-Host "" foreach ($api in $optionalApis) { $hasKey = [bool][Environment]::GetEnvironmentVariable($api.EnvVar) $status = if ($hasKey) { '[OK]' } else { '[--]' } $color = if ($hasKey) { 'Green' } else { 'DarkGray' } Write-Host " $status $($api.Name)" -ForegroundColor $color } # --- Step 4: Validation --- Write-Host "" Write-Host " [4/4] Validation" -ForegroundColor White if (-not $SkipValidation -and $configuredProviders.Count -gt 0) { Write-Host " Testing provider connectivity..." -ForegroundColor Gray if (Get-Command Test-PCProvider -ErrorAction SilentlyContinue) { foreach ($name in $configuredProviders) { $providerKey = $name.ToLower() $ok = Test-PCProvider -Name $providerKey -WarningAction SilentlyContinue $status = if ($ok) { '[OK]' } else { '[!!]' } $color = if ($ok) { 'Green' } else { 'Red' } Write-Host " $status $name connectivity" -ForegroundColor $color } } else { Write-Host " (PowerCraft.AI not loaded — skipping live validation)" -ForegroundColor DarkGray } } elseif ($SkipValidation) { Write-Host " Skipped (-SkipValidation)" -ForegroundColor DarkGray } else { Write-Host " No providers to test" -ForegroundColor DarkGray } # --- Summary --- Write-Host "" Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " Setup Summary" -ForegroundColor Cyan Write-Host "═══════════════════════════════════════════════════════════════" -ForegroundColor Cyan Write-Host " AI Providers: $($configuredProviders.Count)/3 configured" -ForegroundColor $(if ($configuredProviders.Count -gt 0) { 'Green' } else { 'Red' }) Write-Host " Profiles: $($existingProfiles.Count) available" -ForegroundColor $(if ($existingProfiles.Count -gt 0) { 'Green' } else { 'Yellow' }) Write-Host " Search APIs: $(($optionalApis | Where-Object { [Environment]::GetEnvironmentVariable($_.EnvVar) }).Count)/2 configured" -ForegroundColor Gray Write-Host "" if ($configuredProviders.Count -gt 0 -and $existingProfiles.Count -gt 0) { Write-Host " Ready to run:" -ForegroundColor Green Write-Host ' Invoke-LeadForge -Path "./emails" -Profile Default' -ForegroundColor White } else { Write-Host " Action needed:" -ForegroundColor Yellow if ($configuredProviders.Count -eq 0) { Write-Host " - Configure at least one AI provider API key" -ForegroundColor Yellow } if ($existingProfiles.Count -eq 0) { Write-Host " - Create a scoring profile in $profilesDir" -ForegroundColor Yellow } } Write-Host "" if ($Strict -and $configuredProviders.Count -eq 0) { throw "LeadForge not ready: $($configuredProviders.Count) providers, $($existingProfiles.Count) profiles" } } |