Files
boshu2__agentops/scripts/install-ao.ps1
T
2026-04-12 23:40:17 -04:00

190 lines
5.5 KiB
PowerShell

# install-ao.ps1 - Install the ao CLI release binary on Windows.
#
# Usage:
# powershell -ExecutionPolicy Bypass -File .\scripts\install-ao.ps1
# irm https://raw.githubusercontent.com/boshu2/agentops/main/scripts/install-ao.ps1 | iex
[CmdletBinding()]
param(
[string]$Version = "latest",
[string]$InstallDir = (Join-Path $HOME "bin"),
[string]$GithubToken = $env:GITHUB_TOKEN,
[switch]$NoPathUpdate
)
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"
if ([string]::IsNullOrWhiteSpace($GithubToken) -and -not [string]::IsNullOrWhiteSpace($env:GH_TOKEN)) {
$GithubToken = $env:GH_TOKEN
}
function Write-Info {
param([string]$Message)
Write-Host "[agentops] $Message"
}
function Fail {
param([string]$Message)
throw "[agentops] $Message"
}
function Get-AOArch {
$arch = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE }
switch -Regex ($arch) {
"AMD64|x86_64" { return "amd64" }
"ARM64|AARCH64" { return "arm64" }
default { Fail "Unsupported Windows architecture: $arch" }
}
}
function Get-GitHubHeaders {
$headers = @{
"Accept" = "application/vnd.github+json"
"X-GitHub-Api-Version" = "2022-11-28"
}
if (-not [string]::IsNullOrWhiteSpace($GithubToken)) {
$headers["Authorization"] = "Bearer $GithubToken"
}
return $headers
}
function Resolve-Release {
param([string]$RequestedVersion)
if ($RequestedVersion -eq "latest") {
return Invoke-RestMethod -Uri "https://api.github.com/repos/boshu2/agentops/releases/latest" -Headers (Get-GitHubHeaders)
}
$tag = [Uri]::EscapeDataString($RequestedVersion)
return Invoke-RestMethod -Uri "https://api.github.com/repos/boshu2/agentops/releases/tags/$tag" -Headers (Get-GitHubHeaders)
}
function Get-ReleaseAsset {
param(
[object]$Release,
[string]$Name
)
$asset = $Release.assets | Where-Object { $_.name -eq $Name } | Select-Object -First 1
if (-not $asset) {
$names = ($Release.assets | ForEach-Object { $_.name }) -join ", "
Fail "Release $($Release.tag_name) does not include $Name. Available assets: $names"
}
return $asset
}
function Get-ExpectedChecksum {
param(
[string]$ChecksumPath,
[string]$AssetName
)
foreach ($line in Get-Content -Path $ChecksumPath) {
$trimmed = $line.Trim()
if (-not $trimmed) {
continue
}
$parts = $trimmed -split "\s+", 2
if ($parts.Count -eq 2 -and $parts[1] -ceq $AssetName) {
return $parts[0].ToLowerInvariant()
}
}
Fail "checksums.txt does not contain an entry for $AssetName"
}
function Add-UserPath {
param([string]$PathToAdd)
$resolved = [System.IO.Path]::GetFullPath($PathToAdd)
$current = [Environment]::GetEnvironmentVariable("Path", "User")
$parts = @()
if ($current) {
$parts = $current -split ";" | Where-Object { $_ }
}
$alreadyPresent = $false
foreach ($part in $parts) {
if ($part.TrimEnd("\") -ieq $resolved.TrimEnd("\")) {
$alreadyPresent = $true
break
}
}
if (-not $alreadyPresent) {
$newPath = if ($current) { "$current;$resolved" } else { $resolved }
[Environment]::SetEnvironmentVariable("Path", $newPath, "User")
Write-Info "Added $resolved to your user PATH"
}
$envParts = $env:Path -split ";" | Where-Object { $_ }
$inCurrentProcess = $false
foreach ($part in $envParts) {
if ($part.TrimEnd("\") -ieq $resolved.TrimEnd("\")) {
$inCurrentProcess = $true
break
}
}
if (-not $inCurrentProcess) {
$env:Path = "$env:Path;$resolved"
}
}
$tempDir = Join-Path ([System.IO.Path]::GetTempPath()) ("agentops-ao-" + [Guid]::NewGuid().ToString("N"))
try {
New-Item -ItemType Directory -Force -Path $tempDir | Out-Null
$release = Resolve-Release $Version
$arch = Get-AOArch
$assetName = "ao-windows-$arch.tar.gz"
$archiveAsset = Get-ReleaseAsset $release $assetName
$checksumsAsset = Get-ReleaseAsset $release "checksums.txt"
$archivePath = Join-Path $tempDir $assetName
$checksumsPath = Join-Path $tempDir "checksums.txt"
Write-Info "Downloading $assetName from AgentOps $($release.tag_name)"
Invoke-WebRequest -Uri $archiveAsset.browser_download_url -OutFile $archivePath -TimeoutSec 120
Invoke-WebRequest -Uri $checksumsAsset.browser_download_url -OutFile $checksumsPath -TimeoutSec 30
$expected = Get-ExpectedChecksum $checksumsPath $assetName
$actual = (Get-FileHash -Algorithm SHA256 -Path $archivePath).Hash.ToLowerInvariant()
if ($actual -ne $expected) {
Fail "Checksum mismatch for $assetName. Expected $expected, got $actual"
}
Write-Info "Verified SHA256 checksum"
$tar = Get-Command tar.exe -ErrorAction SilentlyContinue
if (-not $tar) {
Fail "tar.exe was not found on PATH. Install a current Windows build or extract $assetName manually."
}
$stageDir = Join-Path $tempDir "stage"
New-Item -ItemType Directory -Force -Path $stageDir | Out-Null
& $tar.Source -xzf $archivePath -C $stageDir ao.exe
$extractedBinary = Join-Path $stageDir "ao.exe"
if (-not (Test-Path -LiteralPath $extractedBinary)) {
Fail "ao.exe not found after extraction"
}
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
Copy-Item -LiteralPath $extractedBinary -Destination (Join-Path $InstallDir "ao.exe") -Force
if (-not $NoPathUpdate) {
Add-UserPath $InstallDir
}
$aoPath = Join-Path $InstallDir "ao.exe"
Write-Info "Installed $aoPath"
& $aoPath version
Write-Host "Open a new terminal if 'ao' is not immediately available on PATH."
}
finally {
if (Test-Path -LiteralPath $tempDir) {
Remove-Item -LiteralPath $tempDir -Recurse -Force
}
}