rho-coding-agent 0.10.0

A lightweight agent harness inspired by Pi
$ErrorActionPreference = "Stop"

$Repo = "matthewyjiang/rho"
$BinName = "rho.exe"
$Version = if ($env:RHO_VERSION) { $env:RHO_VERSION } else { "latest" }
$IsWindowsHost = if (Get-Variable -Name IsWindows -ErrorAction SilentlyContinue) { $IsWindows } else { $true }
if (-not $IsWindowsHost) {
    throw "install.ps1 only supports Windows. On Linux or macOS, use scripts/install.sh instead."
}
$InstallDir = if ($env:RHO_INSTALL_DIR) { $env:RHO_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA "Programs\rho\bin" }
$Target = "x86_64-pc-windows-msvc"
$Asset = "rho-$Target.zip"

function Invoke-Download($Uri, $OutFile, $Required) {
    try {
        Invoke-WebRequest -Uri $Uri -OutFile $OutFile
        return $true
    } catch {
        if ($Required) {
            throw "failed to download $Uri. Check that the release exists and includes $Asset. Original error: $($_.Exception.Message)"
        }
        return $false
    }
}

function Invoke-GitHubApi($Uri) {
    try {
        return Invoke-RestMethod -Uri $Uri -Headers @{ "User-Agent" = "rho-installer" }
    } catch {
        throw "failed to query $Uri. Original error: $($_.Exception.Message)"
    }
}

function Get-ReleaseTag {
    if ($Version -eq "latest") {
        $Release = Invoke-GitHubApi "https://api.github.com/repos/$Repo/releases/latest"
        if ([string]::IsNullOrWhiteSpace($Release.tag_name)) {
            throw "failed to determine latest release tag from GitHub API"
        }
        return $Release.tag_name
    }
    if ($Version -like "rho-coding-agent-*") {
        return $Version
    }
    if ($Version -match "^\d+\.\d+\.\d+([+-].*)?$") {
        return "rho-coding-agent-v$Version"
    }
    return "rho-coding-agent-$Version"
}

function Get-AssetUrl {
    $ReleaseTag = Get-ReleaseTag
    return "https://github.com/$Repo/releases/download/$ReleaseTag/$Asset"
}

function Add-ToUserPath($Dir) {
    $UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
    $Parts = @()
    if ($UserPath) {
        $Parts = $UserPath -split ";" | Where-Object { $_ }
    }

    if ($Parts -contains $Dir) {
        return $false
    }

    $NewPath = if ($UserPath) { "$UserPath;$Dir" } else { $Dir }
    [Environment]::SetEnvironmentVariable("Path", $NewPath, "User")
    $env:Path = "$env:Path;$Dir"
    return $true
}

if (-not [Environment]::Is64BitOperatingSystem) {
    throw "rho prebuilt binaries currently require 64-bit Windows. Install with Cargo instead: cargo install rho-coding-agent"
}

$Url = Get-AssetUrl
$TempDir = Join-Path ([System.IO.Path]::GetTempPath()) "rho-install-$([System.Guid]::NewGuid())"
$Archive = Join-Path $TempDir $Asset
$Checksum = "$Archive.sha256"

New-Item -ItemType Directory -Force -Path $TempDir | Out-Null
try {
    Write-Host "downloading rho for $Target..."
    Invoke-Download $Url $Archive $true | Out-Null

    try {
        if (-not (Invoke-Download "$Url.sha256" $Checksum $false)) {
            throw "checksum file is unavailable"
        }
        $Expected = ((Get-Content $Checksum -Raw) -split "\s+")[0].Trim().ToLowerInvariant()
        $Actual = (Get-FileHash -Algorithm SHA256 $Archive).Hash.ToLowerInvariant()
        if ($Actual -ne $Expected) {
            throw "checksum verification failed"
        }
    } catch {
        if ($_.Exception.Message -eq "checksum verification failed") {
            throw
        }
        Write-Warning "checksum file is unavailable, skipping verification"
    }

    Expand-Archive -Path $Archive -DestinationPath $TempDir -Force
    New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
    Copy-Item -Path (Join-Path $TempDir $BinName) -Destination (Join-Path $InstallDir $BinName) -Force

    $PathChanged = Add-ToUserPath $InstallDir
    Write-Host "rho installed to $(Join-Path $InstallDir $BinName)"
    if ($PathChanged) {
        Write-Host "added $InstallDir to your user PATH. restart your terminal if rho is not found."
    }
} finally {
    Remove-Item -Recurse -Force $TempDir -ErrorAction SilentlyContinue
}