entry.psm1
|
# Entry module for Delta-Code # Provides entry point functionality as reusable module functions # Loads satellite, workspace, and workflow modules for extended commands # Resolve module dependencies from the sibling directory when available (repository # and flat-install layouts) and fall back to module-name resolution (PSGallery). foreach ($dependencyName in @('delta-code', 'satellite', 'workspace', 'workflow')) { $dependencyManifest = Join-Path $PSScriptRoot "$dependencyName.psd1" if (Test-Path -LiteralPath $dependencyManifest) { Import-Module $dependencyManifest -ErrorAction Stop -DisableNameChecking } else { Import-Module $dependencyName -ErrorAction Stop -DisableNameChecking } } Remove-Variable dependencyName, dependencyManifest -ErrorAction SilentlyContinue function Show-DeltaCodeUsage { [CmdletBinding()] param( [string]$ErrorMessage ) if ($ErrorMessage) { Write-Error $ErrorMessage Write-Host "" } Write-Host "Usage: delta-code [-h | --help] [--prj-dir=<path>] <command> [args...]" Write-Host "" Write-Host "Commands:" Write-Host " diff <from> <to> [options] Compare two paths" Write-Host " satellite <name> <cmd> [args] Invoke satellite command" Write-Host " satellites List registered satellites" Write-Host " workspace list List registered workspaces" Write-Host " workspace show Show active workspace" Write-Host " workspace use <name> Set active workspace" Write-Host " workspace register <name> <path> Register a workspace" Write-Host " workflow list List registered workflows" Write-Host " workflow show <name> Show workflow details" Write-Host " workflow run <name> [--dry-run] Execute workflow" Write-Host " workflow validate <name> Validate workflow" Write-Host " workflow history Show execution history" Write-Host " workflow metrics Show workflow metrics" Write-Host " workflow register <name> <workspace> <steps.json> Register workflow" Write-Host " profile list List automation profiles" Write-Host " profile show <name> Show profile details" Write-Host " profile run <name> [--dry-run] Run automation profile" Write-Host " profile register <name> <workflow> [options] Register profile" Write-Host " health [--root=<path>] [--json] Verify the installation" Write-Host " <npm script...> Forward to npm" Write-Host "" Write-Host "Options:" Write-Host " -h, --help Show this help message and exit." Write-Host " --prj-dir=<path> Project directory to run the command in (default: current directory)." Write-Host " --prj-dir <path> Space-separated form; use this for Windows paths." Write-Host "" Write-Host "Health options:" Write-Host " --root=<path> Installation or tree to check (default: this installation)." Write-Host " --root <path> Space-separated form; use this for Windows paths." Write-Host " --json Emit the report as JSON." Write-Host " --skip-module-load Do not import each module during the check." Write-Host " --skip-cli Do not run the launcher smoke test." Write-Host "" Write-Host "Examples:" Write-Host " delta-code diff . ../other" Write-Host " delta-code diff --from master --to feature/fix" Write-Host " delta-code satellite mysat build" Write-Host " delta-code satellites" Write-Host " delta-code workspace list" Write-Host " delta-code workspace use myproj" Write-Host " delta-code workspace register myproj C:\src\myproj" Write-Host " delta-code workflow list" Write-Host " delta-code workflow run build-and-diff" Write-Host " delta-code workflow run build-and-diff --dry-run" Write-Host " delta-code workflow validate build-and-diff" Write-Host " delta-code workflow history" Write-Host " delta-code workflow metrics" Write-Host " delta-code profile run nightly" Write-Host " delta-code profile register nightly build-and-diff --retry=2" Write-Host " delta-code --prj-dir=C:\src\project run dev" } function Show-DeltaCodeDiffUsage { [CmdletBinding()] param( [string]$ErrorMessage ) if ($ErrorMessage) { Write-Error $ErrorMessage Write-Host "" } Write-Host "Usage: delta-code diff <from> <to> [options]" Write-Host "" Write-Host "Options:" Write-Host " --from <path> Source path (base) to compare from." Write-Host " --to <path> Target path to compare against." Write-Host " --ignore-whitespace Ignore whitespace-only differences (default: true)." Write-Host " --format <table|json> Output format (default: table)." Write-Host " --recursive Recursively compare directories (default: true)." Write-Host " -h, --help Show this help message and exit." } function Parse-DeltaCodeArgs { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true)] [string[]]$Args ) $result = [PSCustomObject]@{ PrjDir = if ($env:DELTA_CODE_PRJ_DIR) { $env:DELTA_CODE_PRJ_DIR } else { "." } Command = $null DiffFrom = $null DiffTo = $null IgnoreWhitespace = $true Format = 'table' ForwardArgs = @() ShowHelp = $false ShowDiffHelp = $false Error = $null ListSatellites = $false SatelliteName = $null SatelliteCommand = $null SatelliteArgs = @() WorkspaceSubCommand = $null WorkspaceName = $null WorkspacePath = $null WorkspaceArgs = @() WorkflowSubCommand = $null WorkflowName = $null WorkflowArgs = @() WorkflowDryRun = $false WorkflowLimit = 50 ProfileSubCommand = $null ProfileName = $null ProfileWorkflow = $null ProfileArgs = @() ProfileDryRun = $false ProfileRetryCount = 0 ProfileContinueOnError = $false ProfileInputParams = @{} HealthRoot = $null HealthJson = $false HealthSkipCli = $false HealthSkipModuleLoad = $false HealthHelp = $false } $firstArg = $true for ($i = 0; $i -lt $Args.Count; $i++) { $arg = $Args[$i] if (($arg -eq '-h' -or $arg -eq '--help') -and $firstArg) { $result.ShowHelp = $true continue } $firstArg = $false if ($arg -like '--prj-dir=*') { $result.PrjDir = $arg.Substring('--prj-dir='.Length) continue } if ($arg -like '-prj-dir=*') { $result.PrjDir = $arg.Substring($arg.IndexOf('=') + 1) continue } # Space-separated form: `--prj-dir C:\path`. Required on Windows because # `pwsh -File` splits `--opt=C:\path` at the drive colon. if ($arg -eq '--prj-dir' -or $arg -eq '-prj-dir') { if ($i + 1 -lt $Args.Count) { $i++ $result.PrjDir = $Args[$i] } else { $result.Error = "--prj-dir requires a path" } continue } $result.ForwardArgs += $arg } if ($result.Error) { return $result } if ($result.ForwardArgs.Count -eq 0) { if (-not $result.ShowHelp) { $result.Error = "No command specified" } return $result } $result.Command = $result.ForwardArgs[0] if ($result.Command -eq 'diff') { $diffArgs = $result.ForwardArgs[1..($result.ForwardArgs.Count - 1)] for ($i = 0; $i -lt $diffArgs.Count; $i++) { switch ($diffArgs[$i]) { { $_ -eq '-h' -or $_ -eq '--help' } { $result.ShowDiffHelp = $true; break } { $_ -eq '--from' } { $result.DiffFrom = $diffArgs[++$i]; continue } { $_ -eq '--to' } { $result.DiffTo = $diffArgs[++$i]; continue } { $_ -eq '--ignore-whitespace' } { $result.IgnoreWhitespace = $true; continue } { $_ -eq '--no-ignore-whitespace' } { $result.IgnoreWhitespace = $false; continue } { $_ -eq '--format' } { $result.Format = $diffArgs[++$i]; continue } { $_ -eq '--recursive' } { continue } default { if (-not $result.DiffFrom) { $result.DiffFrom = $_ } elseif (-not $result.DiffTo) { $result.DiffTo = $_ } else { $result.Error = "Unexpected argument: $_" break } } } if ($result.Error -or $result.ShowDiffHelp) { break } } if (-not $result.ShowDiffHelp -and (-not $result.DiffFrom -or -not $result.DiffTo)) { $result.Error = "Both --from and --to are required for diff" } } elseif ($result.Command -eq 'satellite') { $satArgs = $result.ForwardArgs[1..($result.ForwardArgs.Count - 1)] if ($satArgs.Count -lt 2) { $result.Error = "satellite command requires <name> <cmd> [args...]" } else { $result.SatelliteName = $satArgs[0] $result.SatelliteCommand = $satArgs[1] # Assign explicitly: routing an empty array through an `if` expression # collapses it to $null, which then breaks callers expecting .Count. $result.SatelliteArgs = @() if ($satArgs.Count -gt 2) { $result.SatelliteArgs = @($satArgs[2..($satArgs.Count - 1)]) } } } elseif ($result.Command -eq 'satellites') { $result.ListSatellites = $true } elseif ($result.Command -eq 'workspace') { $wsArgs = $result.ForwardArgs[1..($result.ForwardArgs.Count - 1)] if ($wsArgs.Count -eq 0) { $result.Error = "workspace command requires <list|show|use|register> [args...]" } else { $result.WorkspaceSubCommand = $wsArgs[0] switch ($wsArgs[0]) { 'list' { } 'show' { } 'use' { if ($wsArgs.Count -lt 2) { $result.Error = "workspace use requires <name>" } else { $result.WorkspaceName = $wsArgs[1] } } 'register' { if ($wsArgs.Count -lt 3) { $result.Error = "workspace register requires <name> <path> [satellite]" } else { $result.WorkspaceName = $wsArgs[1] $result.WorkspacePath = $wsArgs[2] $result.WorkspaceArgs = if ($wsArgs.Count -gt 3) { $wsArgs[3..($wsArgs.Count - 1)] } else { @() } } } default { $result.Error = "Unknown workspace subcommand: $($wsArgs[0]). Valid: list, show, use, register" } } } } elseif ($result.Command -eq 'workflow') { $wfArgs = $result.ForwardArgs[1..($result.ForwardArgs.Count - 1)] if ($wfArgs.Count -eq 0) { $result.Error = "workflow command requires <list|show|run|register|validate|history|metrics> [args...]" } else { $result.WorkflowSubCommand = $wfArgs[0] switch ($wfArgs[0]) { 'list' { } 'show' { if ($wfArgs.Count -lt 2) { $result.Error = "workflow show requires <name>" } else { $result.WorkflowName = $wfArgs[1] } } 'run' { if ($wfArgs.Count -lt 2) { $result.Error = "workflow run requires <name>" } else { $result.WorkflowName = $wfArgs[1] $runArgs = if ($wfArgs.Count -gt 2) { $wfArgs[2..($wfArgs.Count - 1)] } else { @() } foreach ($arg in $runArgs) { if ($arg -eq '--dry-run' -or $arg -eq '-n') { $result.WorkflowDryRun = $true } else { $result.WorkflowArgs += $arg } } } } 'register' { if ($wfArgs.Count -lt 3) { $result.Error = "workflow register requires <name> <workspace> <steps.json>" } else { $result.WorkflowName = $wfArgs[1] $result.WorkspaceName = $wfArgs[2] $result.WorkflowArgs = if ($wfArgs.Count -gt 3) { $wfArgs[3..($wfArgs.Count - 1)] } else { @() } } } 'validate' { if ($wfArgs.Count -lt 2) { $result.Error = "workflow validate requires <name>" } else { $result.WorkflowName = $wfArgs[1] } } 'history' { $result.WorkflowLimit = 50 $histArgs = if ($wfArgs.Count -gt 1) { $wfArgs[1..($wfArgs.Count - 1)] } else { @() } foreach ($arg in $histArgs) { if ($arg -like '--workflow=*') { $result.WorkflowName = $arg.Substring('--workflow='.Length) } elseif ($arg -like '--workspace=*') { $result.WorkspaceName = $arg.Substring('--workspace='.Length) } elseif ($arg -like '--limit=*') { $result.WorkflowLimit = [int]$arg.Substring('--limit='.Length) } } } 'metrics' { $result.WorkflowLimit = 100 $histArgs = if ($wfArgs.Count -gt 1) { $wfArgs[1..($wfArgs.Count - 1)] } else { @() } foreach ($arg in $histArgs) { if ($arg -like '--workflow=*') { $result.WorkflowName = $arg.Substring('--workflow='.Length) } elseif ($arg -like '--workspace=*') { $result.WorkspaceName = $arg.Substring('--workspace='.Length) } elseif ($arg -like '--limit=*') { $result.WorkflowLimit = [int]$arg.Substring('--limit='.Length) } } } default { $result.Error = "Unknown workflow subcommand: $($wfArgs[0]). Valid: list, show, run, register, validate, history, metrics" } } } } elseif ($result.Command -eq 'profile') { $pfArgs = $result.ForwardArgs[1..($result.ForwardArgs.Count - 1)] if ($pfArgs.Count -eq 0) { $result.Error = "profile command requires <list|show|run|register> [args...]" } else { $result.ProfileSubCommand = $pfArgs[0] switch ($pfArgs[0]) { 'list' { } 'show' { if ($pfArgs.Count -lt 2) { $result.Error = "profile show requires <name>" } else { $result.ProfileName = $pfArgs[1] } } 'run' { if ($pfArgs.Count -lt 2) { $result.Error = "profile run requires <name>" } else { $result.ProfileName = $pfArgs[1] $runArgs = if ($pfArgs.Count -gt 2) { $pfArgs[2..($pfArgs.Count - 1)] } else { @() } foreach ($arg in $runArgs) { if ($arg -eq '--dry-run' -or $arg -eq '-n') { $result.ProfileDryRun = $true } else { $result.ProfileArgs += $arg } } } } 'register' { if ($pfArgs.Count -lt 2) { $result.Error = "profile register requires <name> <workflow> [--retry=N] [--continue-on-error] [--dry-run] [--param=key=value]" } else { $result.ProfileName = $pfArgs[1] $result.ProfileWorkflow = $pfArgs[2] $pfOpts = if ($pfArgs.Count -gt 3) { $pfArgs[3..($pfArgs.Count - 1)] } else { @() } foreach ($arg in $pfOpts) { if ($arg -like '--retry=*') { $result.ProfileRetryCount = [int]$arg.Substring('--retry='.Length) } elseif ($arg -eq '--continue-on-error') { $result.ProfileContinueOnError = $true } elseif ($arg -eq '--dry-run') { $result.ProfileDryRun = $true } elseif ($arg -like '--param=*') { $kv = $arg.Substring('--param='.Length) if ($kv -like '*=*') { $key = $kv.Substring(0, $kv.IndexOf('=')) $value = $kv.Substring($kv.IndexOf('=') + 1) $result.ProfileInputParams[$key] = $value } } } } } default { $result.Error = "Unknown profile subcommand: $($pfArgs[0]). Valid: list, show, run, register" } } } } elseif ($result.Command -eq 'health') { $healthArgs = @() if ($result.ForwardArgs.Count -gt 1) { $healthArgs = @($result.ForwardArgs[1..($result.ForwardArgs.Count - 1)]) } for ($i = 0; $i -lt $healthArgs.Count; $i++) { $arg = $healthArgs[$i] if ($arg -like '--root=*') { $result.HealthRoot = $arg.Substring('--root='.Length) } elseif ($arg -eq '--root') { # Space-separated form: see the `--prj-dir` note above. if ($i + 1 -lt $healthArgs.Count) { $i++ $result.HealthRoot = $healthArgs[$i] } else { $result.Error = "--root requires a path" } } elseif ($arg -eq '--json') { $result.HealthJson = $true } elseif ($arg -eq '--skip-cli') { $result.HealthSkipCli = $true } elseif ($arg -eq '--skip-module-load') { $result.HealthSkipModuleLoad = $true } elseif ($arg -eq '-h' -or $arg -eq '--help') { $result.HealthHelp = $true } else { $result.Error = "Unknown health option: $arg. Valid: --root=<path>, --json, --skip-cli, --skip-module-load" } } } return $result } function Invoke-DeltaCodeDiff { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$From, [Parameter(Mandatory = $true)] [string]$To, [bool]$IgnoreWhitespace = $true, [ValidateSet('table', 'json')] [string]$Format = 'table' ) Import-Module "$PSScriptRoot\..\modules\delta-code.psd1" -ErrorAction Stop $diff = Get-DeltaCodeDiff -From $From -To $To -IgnoreWhitespace $IgnoreWhitespace if ($Format -eq 'json') { $diff | ConvertTo-Json -Depth 5 } else { $diff | Format-List } } function Invoke-DeltaCodeNpm { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$PrjDir, [Parameter(Mandatory = $true)] [string[]]$ForwardArgs ) if ($PrjDir -ne ".") { Push-Location $PrjDir } try { & npm @ForwardArgs exit $LASTEXITCODE } finally { if ($PrjDir -ne ".") { Pop-Location } } } function Invoke-DeltaCodeSatellite { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [string]$Command, [string[]]$Args = @() ) Initialize-DeltaCodeSatellites Invoke-DeltaCodeSatellite -Name $Name -Command $Command -Args $Args } function Invoke-DeltaCodeListSatellites { [CmdletBinding()] param() Initialize-DeltaCodeSatellites $sats = Get-DeltaCodeSatellites if (-not $sats) { Write-Host "No satellites registered" return } $sats | Format-Table Name, Category, Path, Description } function Invoke-DeltaCodeWorkspaceList { [CmdletBinding()] param() Initialize-DeltaCodeWorkspaces $ws = Get-DeltaCodeWorkspaces if (-not $ws) { Write-Host "No workspaces registered" return } $ws | Format-Table Name, Root, Category, Satellite, Active } function Invoke-DeltaCodeWorkspaceShow { [CmdletBinding()] param() Initialize-DeltaCodeWorkspaces $active = Get-DeltaCodeActiveWorkspace if (-not $active) { Write-Host "No active workspace" return } $active | Format-List Name, Root, Category, Satellite, Description, Metadata, Active } function Invoke-DeltaCodeWorkspaceUse { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name ) Initialize-DeltaCodeWorkspaces $result = Set-DeltaCodeWorkspace -Name $Name if ($result) { Write-Host "Active workspace set to '$Name'" } else { Write-Error "Failed to set active workspace: $Name" } } function Invoke-DeltaCodeWorkspaceRegister { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [string]$Path, [string]$Satellite = $null, [string[]]$Args = @() ) Initialize-DeltaCodeWorkspaces $meta = @{} foreach ($arg in $Args) { if ($arg -like '--*=*') { $key = $arg.Substring(2, $arg.IndexOf('=') - 2) $value = $arg.Substring($arg.IndexOf('=') + 1) $meta[$key] = $value } } $result = Register-DeltaCodeWorkspace -Name $Name -Root $Path -Satellite $Satellite -Metadata $meta if ($result) { Write-Host "Workspace '$Name' registered at '$Path'" } else { Write-Error "Failed to register workspace: $Name" } } function Invoke-DeltaCodeWorkflowList { [CmdletBinding()] param() Initialize-DeltaCodeWorkflows $wfs = Get-DeltaCodeWorkflows if (-not $wfs) { Write-Host "No workflows registered" return } $wfs | Format-Table Name, Workspace, Category, Description, Steps } function Invoke-DeltaCodeWorkflowShow { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name ) Initialize-DeltaCodeWorkflows $wf = Get-DeltaCodeWorkflow -Name $Name if (-not $wf) { Write-Error "Workflow '$Name' not found" return } $wf | Format-List Name, Workspace, Category, Description, Steps, Metadata } function Invoke-DeltaCodeWorkflowRun { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name, [switch]$DryRun, [hashtable]$InputParams = @{} ) Initialize-DeltaCodeWorkflows $result = Invoke-DeltaCodeWorkflow -Name $Name -InputParams $InputParams -DryRun:$DryRun return $result } function Invoke-DeltaCodeWorkflowValidate { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name ) Initialize-DeltaCodeWorkflows $valid = Test-DeltaCodeWorkflow -Name $Name if ($valid) { Write-Host "Workflow '$Name' is valid" -ForegroundColor Green return $true } else { Write-Error "Workflow '$Name' validation failed" return $false } } function Invoke-DeltaCodeWorkflowHistory { [CmdletBinding()] param( [string]$Workflow, [string]$Workspace, [int]$Limit = 50 ) Initialize-DeltaCodeWorkflows $history = Get-DeltaCodeWorkflowHistory -Workflow $Workflow -Workspace $Workspace -Limit $Limit if (-not $history -or $history.Count -eq 0) { Write-Host "No execution history found" return } $history | Format-Table Started, Status, DurationMs, @{Name='Steps';Expression={($_.Steps | Measure-Object).Count}} } function Invoke-DeltaCodeWorkflowMetrics { [CmdletBinding()] param( [string]$Workflow, [string]$Workspace, [int]$Limit = 100 ) Initialize-DeltaCodeWorkflows $metrics = Get-DeltaCodeWorkflowMetrics -Workflow $Workflow -Workspace $Workspace -Limit $Limit $metrics | Format-List } function Invoke-DeltaCodeWorkflowRegister { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [string]$Workspace, [string[]]$Args = @() ) Initialize-DeltaCodeWorkflows Initialize-DeltaCodeWorkspaces if ($Args.Count -lt 1) { Write-Error "workflow register requires <steps.json> file path" return } $stepsPath = $Args[0] if (-not (Test-Path $stepsPath)) { Write-Error "Steps file not found: $stepsPath" return } $steps = Get-Content $stepsPath -Raw | ConvertFrom-Json $meta = @{} foreach ($arg in $Args[1..($Args.Count - 1)]) { if ($arg -like '--*=*') { $key = $arg.Substring(2, $arg.IndexOf('=') - 2) $value = $arg.Substring($arg.IndexOf('=') + 1) $meta[$key] = $value } } $result = Register-DeltaCodeWorkflow -Name $Name -Workspace $Workspace -Steps $steps -Metadata $meta if ($result) { Write-Host "Workflow '$Name' registered for workspace '$Workspace' with $($steps.Count) steps" } else { Write-Error "Failed to register workflow: $Name" } } function Invoke-DeltaCodeProfileList { [CmdletBinding()] param() Initialize-DeltaCodeWorkflows $profiles = Get-AutomationProfiles if (-not $profiles -or $profiles.Count -eq 0) { Write-Host "No automation profiles registered" return } $profiles | Format-Table Name, Workflow, DryRun, RetryCount, ContinueOnError } function Invoke-DeltaCodeProfileShow { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name ) Initialize-DeltaCodeWorkflows $profile = Get-AutomationProfile -Name $Name if (-not $profile) { Write-Error "Automation profile '$Name' not found" return } $profile | Format-List } function Invoke-DeltaCodeProfileRun { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name, [switch]$DryRun ) Initialize-DeltaCodeWorkflows $result = Invoke-DeltaCodeProfile -Name $Name -DryRun:$DryRun return $result } function Invoke-DeltaCodeProfileRegister { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Name, [Parameter(Mandatory = $true)] [string]$Workflow, [string[]]$Args = @() ) Initialize-DeltaCodeWorkflows $retry = 0 $continueOnError = $false $dryRun = $false $inputParams = @{} foreach ($arg in $Args) { if ($arg -like '--retry=*') { $retry = [int]$arg.Substring('--retry='.Length) } elseif ($arg -eq '--continue-on-error') { $continueOnError = $true } elseif ($arg -eq '--dry-run') { $dryRun = $true } elseif ($arg -like '--param=*') { $kv = $arg.Substring('--param='.Length) if ($kv -like '*=*') { $key = $kv.Substring(0, $kv.IndexOf('=')) $value = $kv.Substring($kv.IndexOf('=') + 1) $inputParams[$key] = $value } } } $result = Register-AutomationProfile -Name $Name -Workflow $Workflow -DryRun:$dryRun -RetryCount $retry -ContinueOnError:$continueOnError -InputParams $inputParams if ($result) { Write-Host "Automation profile '$Name' registered for workflow '$Workflow'" } else { Write-Error "Failed to register automation profile: $Name" } } function Show-DeltaCodeHealthUsage { [CmdletBinding()] param() Write-Host "Usage: delta-code health [options]" Write-Host "" Write-Host "Options:" Write-Host " --root=<path> Installation or tree to check (default: this installation)." Write-Host " --root <path> Space-separated form; use this for Windows paths." Write-Host " --json Emit the report as JSON." Write-Host " --skip-module-load Do not import each module during the check." Write-Host " --skip-cli Do not run the launcher smoke test." Write-Host "" Write-Host "Exits 0 when every check passes, 1 otherwise." Write-Host "" } function Invoke-DeltaCodeHealth { <# .SYNOPSIS Verifies a Delta-Code installation and returns the result object. .DESCRIPTION Delegates to the shared health module so the installer and the CLI can never validate differently. Returns the result object without printing; callers decide whether to render a table or JSON. #> [CmdletBinding()] param( [string]$Root, [switch]$SkipCli, [switch]$SkipModuleLoad ) # The health module is the single authoritative verification implementation. # Import it lazily so that other commands do not pay for it at startup. $healthManifest = Join-Path $PSScriptRoot 'health.psd1' if (Test-Path -LiteralPath $healthManifest) { Import-Module $healthManifest -Force -DisableNameChecking } else { Import-Module 'health' -ErrorAction Stop -DisableNameChecking } # Default to the root that contains this module: <root>\modules\entry.psm1 $targetRoot = Split-Path -Parent $PSScriptRoot if ($Root) { $targetRoot = $Root } return Test-DeltaCodeInstallation -RootPath $targetRoot -SkipCli:$SkipCli -SkipModuleLoad:$SkipModuleLoad } function Invoke-DeltaCodeEntry { [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromRemainingArguments = $true)] [string[]]$Args ) $parsed = Parse-DeltaCodeArgs -Args $Args # Help must win over "no command specified" so that `-h` exits 0. if ($parsed.ShowHelp) { Show-DeltaCodeUsage exit 0 } if ($parsed.ShowDiffHelp) { Show-DeltaCodeDiffUsage exit 0 } if ($parsed.Error) { Show-DeltaCodeUsage -ErrorMessage $parsed.Error exit 1 } if ($parsed.Command -eq 'diff') { Invoke-DeltaCodeDiff -From $parsed.DiffFrom -To $parsed.DiffTo -IgnoreWhitespace $parsed.IgnoreWhitespace -Format $parsed.Format exit 0 } elseif ($parsed.Command -eq 'satellite') { Invoke-DeltaCodeSatellite -Name $parsed.SatelliteName -Command $parsed.SatelliteCommand -Args $parsed.SatelliteArgs exit 0 } elseif ($parsed.ListSatellites) { Invoke-DeltaCodeListSatellites exit 0 } elseif ($parsed.Command -eq 'workspace') { switch ($parsed.WorkspaceSubCommand) { 'list' { Invoke-DeltaCodeWorkspaceList; exit 0 } 'show' { Invoke-DeltaCodeWorkspaceShow; exit 0 } 'use' { Invoke-DeltaCodeWorkspaceUse -Name $parsed.WorkspaceName; exit 0 } 'register' { $sat = if ($parsed.WorkspaceArgs.Count -gt 0) { $parsed.WorkspaceArgs[0] } else { $null } $metaArgs = if ($parsed.WorkspaceArgs.Count -gt 1) { $parsed.WorkspaceArgs[1..($parsed.WorkspaceArgs.Count - 1)] } else { @() } Invoke-DeltaCodeWorkspaceRegister -Name $parsed.WorkspaceName -Path $parsed.WorkspacePath -Satellite $sat -Args $metaArgs exit 0 } } } elseif ($parsed.Command -eq 'workflow') { switch ($parsed.WorkflowSubCommand) { 'list' { Invoke-DeltaCodeWorkflowList; exit 0 } 'show' { Invoke-DeltaCodeWorkflowShow -Name $parsed.WorkflowName; exit 0 } 'run' { Invoke-DeltaCodeWorkflowRun -Name $parsed.WorkflowName -DryRun:$parsed.WorkflowDryRun; exit 0 } 'register' { Invoke-DeltaCodeWorkflowRegister -Name $parsed.WorkflowName -Workspace $parsed.WorkspaceName -Args $parsed.WorkflowArgs exit 0 } 'validate' { Invoke-DeltaCodeWorkflowValidate -Name $parsed.WorkflowName; exit 0 } 'history' { Invoke-DeltaCodeWorkflowHistory -Workflow $parsed.WorkflowName -Workspace $parsed.WorkspaceName -Limit $parsed.WorkflowLimit; exit 0 } 'metrics' { Invoke-DeltaCodeWorkflowMetrics -Workflow $parsed.WorkflowName -Workspace $parsed.WorkspaceName -Limit $parsed.WorkflowLimit; exit 0 } } } elseif ($parsed.Command -eq 'profile') { switch ($parsed.ProfileSubCommand) { 'list' { Invoke-DeltaCodeProfileList; exit 0 } 'show' { Invoke-DeltaCodeProfileShow -Name $parsed.ProfileName; exit 0 } 'run' { Invoke-DeltaCodeProfileRun -Name $parsed.ProfileName -DryRun:$parsed.ProfileDryRun; exit 0 } 'register' { Invoke-DeltaCodeProfileRegister -Name $parsed.ProfileName -Workflow $parsed.ProfileWorkflow -Args $parsed.ProfileArgs exit 0 } } } elseif ($parsed.Command -eq 'health') { if ($parsed.HealthHelp) { Show-DeltaCodeHealthUsage exit 0 } $result = Invoke-DeltaCodeHealth -Root $parsed.HealthRoot -SkipCli:$parsed.HealthSkipCli -SkipModuleLoad:$parsed.HealthSkipModuleLoad if ($parsed.HealthJson) { $result | ConvertTo-Json -Depth 6 } else { Format-DeltaCodeHealthReport -Result $result } if ($result.Success) { exit 0 } exit 1 } # Forward to npm Invoke-DeltaCodeNpm -PrjDir $parsed.PrjDir -ForwardArgs $parsed.ForwardArgs } Export-ModuleMember -Function Show-DeltaCodeUsage, Show-DeltaCodeDiffUsage, Show-DeltaCodeHealthUsage, Parse-DeltaCodeArgs, Invoke-DeltaCodeDiff, Invoke-DeltaCodeNpm, Invoke-DeltaCodeHealth, Invoke-DeltaCodeEntry, Invoke-DeltaCodeSatellite, Invoke-DeltaCodeListSatellites, Invoke-DeltaCodeWorkspaceList, Invoke-DeltaCodeWorkspaceShow, Invoke-DeltaCodeWorkspaceUse, Invoke-DeltaCodeWorkspaceRegister, Invoke-DeltaCodeWorkflowList, Invoke-DeltaCodeWorkflowShow, Invoke-DeltaCodeWorkflowRun, Invoke-DeltaCodeWorkflowValidate, Invoke-DeltaCodeWorkflowHistory, Invoke-DeltaCodeWorkflowMetrics, Invoke-DeltaCodeWorkflowRegister, Invoke-DeltaCodeProfileList, Invoke-DeltaCodeProfileShow, Invoke-DeltaCodeProfileRun, Invoke-DeltaCodeProfileRegister |