############################################################################## # 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