param( [string]$FlowusBaseUrl = $env:FLOWUS_CLI_RELEASE_BASE_URL, [string]$FlowusVersion = $env:FLOWUS_VERSION, [string]$FlowusInstallDir = $env:FLOWUS_INSTALL_DIR ) $ErrorActionPreference = 'Stop' if ([string]::IsNullOrWhiteSpace($FlowusBaseUrl)) { $FlowusBaseUrl = $env:FLOWUS_BASE_URL } if ([string]::IsNullOrWhiteSpace($FlowusBaseUrl)) { $FlowusBaseUrl = 'https://cdn2.flowus.cn/flowus-cli' } $FlowusBaseUrl = $FlowusBaseUrl.TrimEnd('/') if ([string]::IsNullOrWhiteSpace($FlowusVersion)) { $FlowusVersion = 'latest' } if ($FlowusVersion -ne 'latest' -and $FlowusVersion -notmatch '^v?\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?$') { throw "invalid version `"$FlowusVersion`" -- expected latest or a semver like 1.2.3 or v1.2.3" } function Write-Info { param([string]$Message) Write-Host "==> $Message" -ForegroundColor Cyan } function Get-InstallDir { if (-not [string]::IsNullOrWhiteSpace($FlowusInstallDir)) { return $FlowusInstallDir } $userBin = Join-Path $env:LOCALAPPDATA 'Programs\FlowUs\bin' if (-not [string]::IsNullOrWhiteSpace($env:LOCALAPPDATA)) { return $userBin } if (-not [string]::IsNullOrWhiteSpace($env:USERPROFILE)) { return (Join-Path $env:USERPROFILE '.flowus\bin') } throw 'could not find a writable install directory. Set FLOWUS_INSTALL_DIR and rerun the installer.' } function Invoke-Download { param( [string]$Url, [string]$OutFile ) $lastError = $null for ($attempt = 1; $attempt -le 3; $attempt++) { try { Invoke-WebRequest -Uri $Url -OutFile $OutFile -UseBasicParsing return } catch { $lastError = $_ if ($attempt -lt 3) { Start-Sleep -Seconds 2 } } } throw $lastError } function Resolve-Version { if ($FlowusVersion -eq 'latest') { $versionFile = Join-Path $TempDir 'version' Invoke-Download "$FlowusBaseUrl/latest/version" $versionFile return ((Get-Content -Raw $versionFile).Trim()) } if ($FlowusVersion.StartsWith('v')) { return $FlowusVersion } return "v$FlowusVersion" } function Test-PathEntry { param([string]$Directory) $normalized = [System.IO.Path]::GetFullPath($Directory).TrimEnd('\') $pathValue = '' if ($env:Path) { $pathValue = $env:Path } foreach ($entry in ($pathValue -split ';')) { if ([string]::IsNullOrWhiteSpace($entry)) { continue } try { if ([System.IO.Path]::GetFullPath($entry).TrimEnd('\') -ieq $normalized) { return $true } } catch { continue } } return $false } if ($env:PROCESSOR_ARCHITECTURE -notin @('AMD64', 'x86')) { throw "unsupported Windows architecture: $env:PROCESSOR_ARCHITECTURE" } $InstallDir = Get-InstallDir $TempDir = Join-Path ([System.IO.Path]::GetTempPath()) ([System.Guid]::NewGuid().ToString('n')) New-Item -ItemType Directory -Force -Path $TempDir | Out-Null try { $Version = Resolve-Version if ([string]::IsNullOrWhiteSpace($Version)) { throw "could not resolve version from $FlowusBaseUrl/latest/version" } $Artifact = 'flowus-windows-x64.zip' $ReleaseBase = "$FlowusBaseUrl/releases/$Version" $ArchiveUrl = "$ReleaseBase/$Artifact" $ChecksumUrl = "$ReleaseBase/SHA256SUMS" $ArchivePath = Join-Path $TempDir $Artifact $ChecksumPath = Join-Path $TempDir 'SHA256SUMS' $ExtractDir = Join-Path $TempDir 'extract' Write-Info "Downloading FlowUs CLI $Version for windows-x64" Invoke-Download $ArchiveUrl $ArchivePath Invoke-Download $ChecksumUrl $ChecksumPath $checksumLine = Get-Content $ChecksumPath | Where-Object { $_ -match "\s+$([regex]::Escape($Artifact))$" } | Select-Object -First 1 if (-not $checksumLine) { throw "missing checksum for $Artifact" } $expectedHash = ($checksumLine -split '\s+')[0].ToLowerInvariant() $actualHash = (Get-FileHash -Algorithm SHA256 $ArchivePath).Hash.ToLowerInvariant() if ($actualHash -ne $expectedHash) { throw "checksum mismatch for $Artifact" } New-Item -ItemType Directory -Force -Path $ExtractDir | Out-Null Expand-Archive -Path $ArchivePath -DestinationPath $ExtractDir -Force $BinaryPath = Join-Path $ExtractDir 'flowus.exe' if (-not (Test-Path $BinaryPath)) { throw 'downloaded archive did not contain flowus.exe' } New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null Copy-Item -Force $BinaryPath (Join-Path $InstallDir 'flowus.exe') Write-Host '' Write-Host ' FlowUs CLI' Write-Host '' Write-Host " Installed flowus $Version to $(Join-Path $InstallDir 'flowus.exe')" Write-Host '' if (-not (Test-PathEntry $InstallDir)) { Write-Host ' Add flowus to your PATH:' Write-Host '' Write-Host " [Environment]::SetEnvironmentVariable('Path', `$env:Path + ';$InstallDir', 'User')" Write-Host '' Write-Host ' Open a new PowerShell window after updating PATH.' Write-Host '' } Write-Host ' Get started:' Write-Host '' Write-Host ' flowus login' Write-Host ' flowus help' Write-Host '' } finally { Remove-Item -Recurse -Force $TempDir -ErrorAction SilentlyContinue }