diff --git a/download_cli.ps1 b/download_cli.ps1 new file mode 100644 index 00000000..57eca20f --- /dev/null +++ b/download_cli.ps1 @@ -0,0 +1,233 @@ +############################################################################## +# Goose CLI Install Script for Windows PowerShell +# +# This script downloads the latest stable 'goose' CLI binary from GitHub releases +# and installs it to your system. +# +# Supported OS: Windows +# Supported Architectures: x86_64 +# +# Usage: +# Invoke-WebRequest -Uri "https://github.com/block/goose/releases/download/stable/download_cli.ps1" -OutFile "download_cli.ps1"; .\download_cli.ps1 +# Or simply: .\download_cli.ps1 +# +# Environment variables: +# $env:GOOSE_BIN_DIR - Directory to which Goose will be installed (default: $env:USERPROFILE\.local\bin) +# $env:GOOSE_VERSION - Optional: specific version to install (e.g., "v1.0.25"). Can be in the format vX.Y.Z, vX.Y.Z-suffix, or X.Y.Z +# $env:GOOSE_PROVIDER - Optional: provider for goose +# $env:GOOSE_MODEL - Optional: model for goose +# $env:CANARY - Optional: if set to "true", downloads from canary release instead of stable +# $env:CONFIGURE - Optional: if set to "false", disables running goose configure interactively +############################################################################## + +# Set error action preference to stop on errors +$ErrorActionPreference = "Stop" + +# --- 1) Variables --- +$REPO = "block/goose" +$OUT_FILE = "goose.exe" + +# Set default bin directory if not specified +if (-not $env:GOOSE_BIN_DIR) { + $env:GOOSE_BIN_DIR = Join-Path $env:USERPROFILE ".local\bin" +} + +# Determine release type +$RELEASE = if ($env:CANARY -eq "true") { "true" } else { "false" } +$CONFIGURE = if ($env:CONFIGURE -eq "false") { "false" } else { "true" } + +# Determine release tag +if ($env:GOOSE_VERSION) { + # Validate version format + if ($env:GOOSE_VERSION -notmatch '^v?[0-9]+\.[0-9]+\.[0-9]+(-.*)?$') { + Write-Error "Invalid version '$env:GOOSE_VERSION'. Expected: semver format vX.Y.Z, vX.Y.Z-suffix, or X.Y.Z" + exit 1 + } + # Ensure version starts with 'v' + $RELEASE_TAG = if ($env:GOOSE_VERSION.StartsWith("v")) { $env:GOOSE_VERSION } else { "v$env:GOOSE_VERSION" } +} else { + # Use canary or stable based on RELEASE variable + $RELEASE_TAG = if ($RELEASE -eq "true") { "canary" } else { "stable" } +} + +# --- 2) Detect Architecture --- +$ARCH = $env:PROCESSOR_ARCHITECTURE +if ($ARCH -eq "AMD64") { + $ARCH = "x86_64" +} elseif ($ARCH -eq "ARM64") { + Write-Error "Windows ARM64 is not currently supported." + exit 1 +} else { + Write-Error "Unsupported architecture '$ARCH'. Only x86_64 is supported on Windows." + exit 1 +} + +# --- 3) Build download URL --- +$FILE = "goose-$ARCH-pc-windows-gnu.zip" +$DOWNLOAD_URL = "https://github.com/$REPO/releases/download/$RELEASE_TAG/$FILE" + +Write-Host "Downloading $RELEASE_TAG release: $FILE..." -ForegroundColor Green + +# --- 4) Download the file --- +try { + Invoke-WebRequest -Uri $DOWNLOAD_URL -OutFile $FILE -UseBasicParsing + Write-Host "Download completed successfully." -ForegroundColor Green +} catch { + Write-Error "Failed to download $DOWNLOAD_URL. Error: $($_.Exception.Message)" + exit 1 +} + +# --- 5) Create temporary directory for extraction --- +$TMP_DIR = Join-Path $env:TEMP "goose_install_$(Get-Random)" +try { + New-Item -ItemType Directory -Path $TMP_DIR -Force | Out-Null + Write-Host "Created temporary directory: $TMP_DIR" -ForegroundColor Yellow +} catch { + Write-Error "Could not create temporary extraction directory: $TMP_DIR" + exit 1 +} + +# --- 6) Extract the archive --- +Write-Host "Extracting $FILE to temporary directory..." -ForegroundColor Green +try { + Expand-Archive -Path $FILE -DestinationPath $TMP_DIR -Force + Write-Host "Extraction completed successfully." -ForegroundColor Green +} catch { + Write-Error "Failed to extract $FILE. Error: $($_.Exception.Message)" + Remove-Item -Path $TMP_DIR -Recurse -Force -ErrorAction SilentlyContinue + exit 1 +} + +# Clean up the downloaded archive +Remove-Item -Path $FILE -Force + +# --- 7) Determine extraction directory --- +$EXTRACT_DIR = $TMP_DIR +if (Test-Path (Join-Path $TMP_DIR "goose-package")) { + Write-Host "Found goose-package subdirectory, using that as extraction directory" -ForegroundColor Yellow + $EXTRACT_DIR = Join-Path $TMP_DIR "goose-package" +} + +# --- 8) Create bin directory if it doesn't exist --- +if (-not (Test-Path $env:GOOSE_BIN_DIR)) { + Write-Host "Creating directory: $env:GOOSE_BIN_DIR" -ForegroundColor Yellow + try { + New-Item -ItemType Directory -Path $env:GOOSE_BIN_DIR -Force | Out-Null + } catch { + Write-Error "Could not create directory: $env:GOOSE_BIN_DIR" + Remove-Item -Path $TMP_DIR -Recurse -Force -ErrorAction SilentlyContinue + exit 1 + } +} + +# --- 9) Install goose binary --- +$SOURCE_GOOSE = Join-Path $EXTRACT_DIR "goose.exe" +$DEST_GOOSE = Join-Path $env:GOOSE_BIN_DIR $OUT_FILE + +if (Test-Path $SOURCE_GOOSE) { + Write-Host "Moving goose to $DEST_GOOSE" -ForegroundColor Green + try { + # Remove existing file if it exists to avoid conflicts + if (Test-Path $DEST_GOOSE) { + Remove-Item -Path $DEST_GOOSE -Force + } + Move-Item -Path $SOURCE_GOOSE -Destination $DEST_GOOSE -Force + } catch { + Write-Error "Failed to move goose.exe to $DEST_GOOSE. Error: $($_.Exception.Message)" + Remove-Item -Path $TMP_DIR -Recurse -Force -ErrorAction SilentlyContinue + exit 1 + } +} else { + Write-Error "goose.exe not found in extracted files" + Remove-Item -Path $TMP_DIR -Recurse -Force -ErrorAction SilentlyContinue + exit 1 +} + +# --- 10) Install temporal-service if it exists --- +$SOURCE_TEMPORAL_SERVICE = Join-Path $EXTRACT_DIR "temporal-service.exe" +if (Test-Path $SOURCE_TEMPORAL_SERVICE) { + $DEST_TEMPORAL_SERVICE = Join-Path $env:GOOSE_BIN_DIR "temporal-service.exe" + Write-Host "Moving temporal-service to $DEST_TEMPORAL_SERVICE" -ForegroundColor Green + try { + # Remove existing file if it exists to avoid conflicts + if (Test-Path $DEST_TEMPORAL_SERVICE) { + Remove-Item -Path $DEST_TEMPORAL_SERVICE -Force + } + Move-Item -Path $SOURCE_TEMPORAL_SERVICE -Destination $DEST_TEMPORAL_SERVICE -Force + } catch { + Write-Warning "Failed to move temporal-service.exe: $($_.Exception.Message)" + } +} + +# --- 11) Install temporal CLI if it exists --- +$SOURCE_TEMPORAL = Join-Path $EXTRACT_DIR "temporal.exe" +if (Test-Path $SOURCE_TEMPORAL) { + $DEST_TEMPORAL = Join-Path $env:GOOSE_BIN_DIR "temporal.exe" + Write-Host "Moving temporal CLI to $DEST_TEMPORAL" -ForegroundColor Green + try { + # Remove existing file if it exists to avoid conflicts + if (Test-Path $DEST_TEMPORAL) { + Remove-Item -Path $DEST_TEMPORAL -Force + } + Move-Item -Path $SOURCE_TEMPORAL -Destination $DEST_TEMPORAL -Force + } catch { + Write-Warning "Failed to move temporal.exe: $($_.Exception.Message)" + } +} + +# --- 12) Copy Windows runtime DLLs if they exist --- +$DLL_FILES = Get-ChildItem -Path $EXTRACT_DIR -Filter "*.dll" -ErrorAction SilentlyContinue +foreach ($dll in $DLL_FILES) { + $DEST_DLL = Join-Path $env:GOOSE_BIN_DIR $dll.Name + Write-Host "Moving Windows runtime DLL: $($dll.Name)" -ForegroundColor Green + try { + # Remove existing file if it exists to avoid conflicts + if (Test-Path $DEST_DLL) { + Remove-Item -Path $DEST_DLL -Force + } + Move-Item -Path $dll.FullName -Destination $DEST_DLL -Force + } catch { + Write-Warning "Failed to move $($dll.Name): $($_.Exception.Message)" + } +} + +# --- 13) Clean up temporary directory --- +try { + Remove-Item -Path $TMP_DIR -Recurse -Force + Write-Host "Cleaned up temporary directory." -ForegroundColor Yellow +} catch { + Write-Warning "Could not clean up temporary directory: $TMP_DIR" +} + +# --- 14) Configure Goose (Optional) --- +if ($CONFIGURE -eq "true") { + Write-Host "" + Write-Host "Configuring Goose" -ForegroundColor Green + Write-Host "" + try { + & $DEST_GOOSE configure + } catch { + Write-Warning "Failed to run goose configure. You may need to run it manually later." + } +} else { + Write-Host "Skipping 'goose configure', you may need to run this manually later" -ForegroundColor Yellow +} + +# --- 15) Check PATH and give instructions if needed --- +$CURRENT_PATH = $env:PATH +if ($CURRENT_PATH -notlike "*$env:GOOSE_BIN_DIR*") { + Write-Host "" + Write-Host "Warning: Goose installed, but $env:GOOSE_BIN_DIR is not in your PATH." -ForegroundColor Yellow + Write-Host "To add it to your PATH permanently, run the following command as Administrator:" -ForegroundColor Yellow + Write-Host " [Environment]::SetEnvironmentVariable('PATH', `$env:PATH + ';$env:GOOSE_BIN_DIR', 'Machine')" -ForegroundColor Cyan + Write-Host "" + Write-Host "Or add it to your user PATH (no admin required):" -ForegroundColor Yellow + Write-Host " [Environment]::SetEnvironmentVariable('PATH', `$env:PATH + ';$env:GOOSE_BIN_DIR', 'User')" -ForegroundColor Cyan + Write-Host "" + Write-Host "For this session only, you can run:" -ForegroundColor Yellow + Write-Host " `$env:PATH += ';$env:GOOSE_BIN_DIR'" -ForegroundColor Cyan + Write-Host "" +} + +Write-Host "Goose CLI installation completed successfully!" -ForegroundColor Green +Write-Host "Goose is installed at: $DEST_GOOSE" -ForegroundColor Green