Public/Start-ParallelModuleExport.ps1

function Start-ParallelModuleExport {
    <#
    .SYNOPSIS
        Exports multiple modules in parallel for improved performance.
    .PARAMETER ModuleNames
        Array of module names to export.
    .PARAMETER OutputDirectory
        Directory where exports will be saved.
    .PARAMETER Format
        Export format (JSON, Markdown, XML).
    .PARAMETER MaxConcurrentModules
        Maximum number of modules to process simultaneously.
    #>

    param(
        [Parameter(Mandatory = $true)]
        [string[]]$ModuleNames,
        
        [Parameter(Mandatory = $true)]
        [string]$OutputDirectory,
        
        [Parameter(Mandatory = $false)]
        [ValidateSet("JSON", "Markdown", "XML")]
        [string]$Format = "JSON",
        
        [Parameter(Mandatory = $false)]
        [int]$MaxConcurrentModules = 3
    )
    
    # Add input validation
    if (-not $ModuleNames -or $ModuleNames.Count -eq 0) {
        throw "ModuleNames array cannot be null or empty"
    }
    
    if (-not (Test-Path $OutputDirectory) -and -not (New-Item -Path $OutputDirectory -ItemType Directory -Force -ErrorAction SilentlyContinue)) {
        throw "Cannot create output directory: $OutputDirectory"
    }
    
    $exportScript = {
        param($ModuleName, $OutputDirectory, $Format, $ModulePath)
        
        try {
            # Import the module containing Export-ModuleCommandsForLLM
            Import-Module $ModulePath -Force -ErrorAction Stop
            
            # Verify the function is available
            if (-not (Get-Command Export-ModuleCommandsForLLM -ErrorAction SilentlyContinue)) {
                throw "Export-ModuleCommandsForLLM function not found after importing module"
            }
            
            # Now call the export function with suppressed verbose output in jobs
            $VerbosePreference = 'SilentlyContinue'
            $exportPath = Export-ModuleCommandsForLLM -ModuleName $ModuleName -OutputDirectory $OutputDirectory -FileName "$ModuleName-Commands" -Format $Format -SkipProgressBar
            
            return [PSCustomObject]@{
                ModuleName = $ModuleName
                Success = $true
                ExportPath = $exportPath
                Error = $null
            }
        } catch {
            return [PSCustomObject]@{
                ModuleName = $ModuleName
                Success = $false
                ExportPath = $null
                Error = $_.Exception.Message
            }
        }
    }
    
    Write-Output "Starting parallel export of $($ModuleNames.Count) modules..."
    
    # Track execution time
    $stopwatch = [System.Diagnostics.Stopwatch]::StartNew()
    
    $results = @()
    $batches = for ($i = 0; $i -lt $ModuleNames.Count; $i += $MaxConcurrentModules) {
        $endIndex = [Math]::Min($i + $MaxConcurrentModules - 1, $ModuleNames.Count - 1)
        $ModuleNames[$i..$endIndex]
    }
    
    # Get the module path to pass to jobs
    $currentModulePath = $MyInvocation.MyCommand.Module.Path
    if (-not $currentModulePath) {
        # If module path is not available, try to find it
        $currentModule = Get-Module -Name "Export-ModuleInfoForLLM" -ErrorAction SilentlyContinue
        if ($currentModule) {
            $currentModulePath = $currentModule.Path
        } else {
            # Fallback to script path - look for the psm1 file
            $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
            $moduleFile = Join-Path $scriptDir "Export-ModuleInfoForLLM.psm1"
            if (Test-Path $moduleFile) {
                $currentModulePath = $moduleFile
            } else {
                # Last resort - use the current file
                $currentModulePath = $MyInvocation.MyCommand.Path
            }
        }
    }
    
    $jobCount = 0
    foreach ($batch in $batches) {
        $jobs = @()
        foreach ($moduleName in $batch) {
            Write-Verbose "Starting job for module: $moduleName" -Verbose
            $job = Start-Job -ScriptBlock $exportScript -ArgumentList $moduleName, $OutputDirectory, $Format, $currentModulePath -Name "Export-$moduleName"
            $jobs += $job
            $jobCount++
        }
        
        # Wait for batch completion with progress
        Write-Progress -Activity "Exporting Modules" -Status "Processing batch..." -PercentComplete (($jobCount / $ModuleNames.Count) * 100)
        Wait-Job -Job $jobs | Out-Null
        
        # Collect results
        foreach ($job in $jobs) {
            $jobOutput = Receive-Job -Job $job -ErrorAction SilentlyContinue
            # Filter out null or empty results
            if ($jobOutput) {
                # Handle both single results and arrays of results
                if ($jobOutput -is [array]) {
                    foreach ($result in $jobOutput) {
                        if ($result -and $result.ModuleName) {
                            $results += $result
                            if ($result.Success) {
                                Write-Verbose "Successfully exported: $($result.ModuleName)" -Verbose
                            } else {
                                Write-Warning "Failed to export: $($result.ModuleName) - $($result.Error)"
                            }
                        }
                    }
                } else {
                    if ($jobOutput.ModuleName) {
                        $results += $jobOutput
                        if ($jobOutput.Success) {
                            Write-Verbose "Successfully exported: $($jobOutput.ModuleName)" -Verbose
                        } else {
                            Write-Warning "Failed to export: $($jobOutput.ModuleName) - $($jobOutput.Error)"
                        }
                    }
                }
            }
            Remove-Job -Job $job -Force -ErrorAction SilentlyContinue
        }
    }
    
    Write-Progress -Activity "Exporting Modules" -Completed
    $stopwatch.Stop()
    
    # Filter results to remove any empty entries
    $results = $results | Where-Object { $_ -and $_.ModuleName }
    
    # Report results
    $successCount = ($results | Where-Object Success).Count
    Write-Output "Parallel export completed in $([Math]::Round($stopwatch.Elapsed.TotalSeconds, 2)) seconds"
    Write-Output "Successfully exported: $successCount of $($results.Count) modules"
    
    # Show any failures (only non-empty ones)
    $failures = $results | Where-Object { -not $_.Success -and $_.ModuleName }
    if ($failures) {
        $failures | ForEach-Object {
            Write-Warning "Failed to export $($_.ModuleName): $($_.Error)"
        }
    }
    
    return $results
}