scripts/init/preflight.ps1
|
# Preflight + usage helpers for specrew-init.ps1 (extracted via Proposal 108 Slice 2) # # Depends on: scripts/init/_utilities.ps1 (Get-NativeExitCode used inside dependency probes) # # Functions: # - Test-PreFlightDependencies probe pwsh7/uv/node/npm/git/gh + collect outdated/missing # - Show-Usage print specrew init usage text Set-StrictMode -Version Latest function Test-PreFlightDependencies { param( [switch]$IncludeOptional ) $missingDeps = @() $outdatedDeps = @() # PowerShell 7+ if ($PSVersionTable.PSVersion.Major -lt 7) { $missingDeps += [pscustomobject]@{ Tool = 'PowerShell' Current = "$($PSVersionTable.PSVersion)" Required = '7.0+' Platform = if ($IsWindows) { 'Windows' } elseif ($IsLinux) { 'Linux' } elseif ($IsMacOS) { 'macOS' } else { 'Unknown' } InstallHint = if ($IsWindows) { 'Install from https://aka.ms/powershell-release?tag=stable or via winget: winget install Microsoft.PowerShell' } elseif ($IsLinux) { 'Install via package manager or from https://aka.ms/powershell-release?tag=stable' } elseif ($IsMacOS) { 'Install via Homebrew: brew install powershell' } else { 'Install from https://aka.ms/powershell-release?tag=stable' } } } # uv (required for Spec Kit) $uvCommand = Get-Command 'uv' -ErrorAction SilentlyContinue if (-not $uvCommand) { $missingDeps += [pscustomobject]@{ Tool = 'uv' Current = 'not installed' Required = 'any' Platform = if ($IsWindows) { 'Windows' } elseif ($IsLinux) { 'Linux' } elseif ($IsMacOS) { 'macOS' } else { 'Unknown' } InstallHint = if ($IsWindows) { 'Install via PowerShell: irm https://astral.sh/uv/install.ps1 | iex' } elseif ($IsLinux -or $IsMacOS) { 'Install via shell: curl -LsSf https://astral.sh/uv/install.sh | sh' } else { 'Install from https://docs.astral.sh/uv/getting-started/installation/' } } } # Node.js 24+ $nodeCommand = Get-Command 'node' -ErrorAction SilentlyContinue if (-not $nodeCommand) { $missingDeps += [pscustomobject]@{ Tool = 'Node.js' Current = 'not installed' Required = '24.0+' Platform = if ($IsWindows) { 'Windows' } elseif ($IsLinux) { 'Linux' } elseif ($IsMacOS) { 'macOS' } else { 'Unknown' } InstallHint = if ($IsWindows) { 'Install from https://nodejs.org/ or via winget: winget install OpenJS.NodeJS.LTS' } elseif ($IsLinux) { 'Install via package manager or from https://nodejs.org/' } elseif ($IsMacOS) { 'Install via Homebrew: brew install node' } else { 'Install from https://nodejs.org/' } } } else { try { $nodeVersion = & node --version 2>$null if ($nodeVersion -match 'v(\d+)\.') { $nodeMajor = [int]$Matches[1] if ($nodeMajor -lt 24) { $outdatedDeps += [pscustomobject]@{ Tool = 'Node.js' Current = $nodeVersion Required = '24.0+' Platform = if ($IsWindows) { 'Windows' } elseif ($IsLinux) { 'Linux' } elseif ($IsMacOS) { 'macOS' } else { 'Unknown' } InstallHint = 'Update from https://nodejs.org/' } } } } catch {} } # npm 10+ $npmCommand = Get-Command 'npm' -ErrorAction SilentlyContinue if (-not $npmCommand) { $missingDeps += [pscustomobject]@{ Tool = 'npm' Current = 'not installed' Required = '10.0+' Platform = if ($IsWindows) { 'Windows' } elseif ($IsLinux) { 'Linux' } elseif ($IsMacOS) { 'macOS' } else { 'Unknown' } InstallHint = 'Included with Node.js; install Node.js first' } } else { try { $npmVersion = & npm --version 2>$null if ($npmVersion -match '(\d+)\.') { $npmMajor = [int]$Matches[1] if ($npmMajor -lt 10) { $outdatedDeps += [pscustomobject]@{ Tool = 'npm' Current = $npmVersion Required = '10.0+' Platform = if ($IsWindows) { 'Windows' } elseif ($IsLinux) { 'Linux' } elseif ($IsMacOS) { 'macOS' } else { 'Unknown' } InstallHint = 'Update via: npm install -g npm@latest' } } } } catch {} } # git 2.30+ $gitCommand = Get-Command 'git' -ErrorAction SilentlyContinue if (-not $gitCommand) { $missingDeps += [pscustomobject]@{ Tool = 'git' Current = 'not installed' Required = '2.30+' Platform = if ($IsWindows) { 'Windows' } elseif ($IsLinux) { 'Linux' } elseif ($IsMacOS) { 'macOS' } else { 'Unknown' } InstallHint = if ($IsWindows) { 'Install from https://git-scm.com/ or via winget: winget install Git.Git' } elseif ($IsLinux) { 'Install via package manager (e.g., apt install git, yum install git)' } elseif ($IsMacOS) { 'Install via Homebrew: brew install git or Xcode Command Line Tools' } else { 'Install from https://git-scm.com/' } } } else { try { $gitVersion = & git --version 2>$null if ($gitVersion -match 'git version (\d+)\.(\d+)') { $gitMajor = [int]$Matches[1] $gitMinor = [int]$Matches[2] if ($gitMajor -lt 2 -or ($gitMajor -eq 2 -and $gitMinor -lt 30)) { $outdatedDeps += [pscustomobject]@{ Tool = 'git' Current = $gitVersion Required = '2.30+' Platform = if ($IsWindows) { 'Windows' } elseif ($IsLinux) { 'Linux' } elseif ($IsMacOS) { 'macOS' } else { 'Unknown' } InstallHint = 'Update from https://git-scm.com/ or your package manager' } } } } catch {} } # gh CLI (optional but recommended) if ($IncludeOptional) { $ghCommand = Get-Command 'gh' -ErrorAction SilentlyContinue if (-not $ghCommand) { $missingDeps += [pscustomobject]@{ Tool = 'gh' Current = 'not installed' Required = 'any (optional)' Platform = if ($IsWindows) { 'Windows' } elseif ($IsLinux) { 'Linux' } elseif ($IsMacOS) { 'macOS' } else { 'Unknown' } InstallHint = if ($IsWindows) { 'Optional: Install from https://cli.github.com/ or via winget: winget install GitHub.cli' } elseif ($IsLinux) { 'Optional: Install via package manager or from https://cli.github.com/' } elseif ($IsMacOS) { 'Optional: Install via Homebrew: brew install gh' } else { 'Optional: Install from https://cli.github.com/' } } } } return [pscustomobject]@{ MissingDeps = @($missingDeps) OutdatedDeps = @($outdatedDeps) AllOk = ($missingDeps.Count -eq 0 -and $outdatedDeps.Count -eq 0) } } function Show-Usage { @' specrew init [options] Options: -ProjectPath | --project-path <path> Target project directory (defaults to current directory) -DryRun | --dry-run Show planned changes without writing -Force | --force Skip interactive prompts and use default selections -SpecKitVersion | --speckit-version Minimum Spec Kit version (default: 0.8.4) -SquadVersion | --squad-version Minimum Squad version (default: 0.9.1) -Agents | --agents Optional DELEGATED agents (orthogonal to --host launch selection): claude | codex | comma list | all. The launch host stays as selected via `specrew start --host <kind>` (default: copilot) -NoAgents | --no-agents Disable optional delegated agents. The launch host stays as selected via `specrew start --host <kind>` -SkipUpdateCheck | --skip-update-check Skip the PSGallery latest-version check for this run -Help | --help Show usage '@ | Write-Host } |