# OpusGate - Claude Code auto-setup for Windows # Usage: # irm https://opusgate.dev/install.ps1 | iex # $env:OPUSGATE_KEY = "sk-og-..."; irm https://opusgate.dev/install.ps1 | iex $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" try { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 } catch {} Write-Host "" Write-Host "OpusGate - Claude Code setup" -ForegroundColor Cyan Write-Host "" # --- 1. API key --------------------------------------------------------- $key = $env:OPUSGATE_KEY if (-not $key) { $key = Read-Host "Paste your OpusGate API key (sk-og-..., from https://opusgate.dev/keys)" } $key = $key.Trim() if ($key -notlike "sk-og-*") { Write-Host "That doesn't look like an OpusGate key (expected sk-og-...). Aborting." -ForegroundColor Red return } # --- 2. Claude Code ----------------------------------------------------- $bin = Join-Path $env:USERPROFILE ".local\bin" $exe = Join-Path $bin "claude.exe" if (Get-Command claude -ErrorAction SilentlyContinue) { Write-Host "Claude Code already installed - skipping install." } elseif (Test-Path $exe) { # Installed but not on PATH yet (e.g. terminal not reopened after install). Write-Host "Claude Code found at $exe - skipping download, fixing PATH." $userPath = [Environment]::GetEnvironmentVariable("Path", "User") if (-not $userPath) { $userPath = "" } if (($userPath -split ";") -notcontains $bin) { [Environment]::SetEnvironmentVariable("Path", ($userPath.TrimEnd(";") + ";" + $bin), "User") } $env:PATH = "$env:PATH;$bin" } else { # Primary path: download the official binary straight from Anthropic's # distribution bucket. Same binary the claude.ai installer fetches, but the # bucket is reachable in regions where claude.ai itself is geo-blocked. $bucket = "https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases" $arch = if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { "win32-arm64" } else { "win32-x64" } $installed = $false try { $version = ([string](Invoke-RestMethod -TimeoutSec 30 "$bucket/stable")).Trim() $manifest = Invoke-RestMethod -TimeoutSec 30 "$bucket/$version/manifest.json" New-Item -ItemType Directory -Force -Path $bin | Out-Null Write-Host "Downloading Claude Code $version ($arch, ~220 MB)..." -ForegroundColor Yellow (New-Object Net.WebClient).DownloadFile("$bucket/$version/$arch/claude.exe", $exe) $expected = $manifest.platforms.$arch.checksum if ($expected) { $actual = (Get-FileHash $exe -Algorithm SHA256).Hash.ToLower() if ($actual -ne $expected.ToLower()) { Remove-Item $exe -Force throw "Checksum mismatch - corrupted download." } } $userPath = [Environment]::GetEnvironmentVariable("Path", "User") if (-not $userPath) { $userPath = "" } if (($userPath -split ";") -notcontains $bin) { [Environment]::SetEnvironmentVariable("Path", ($userPath.TrimEnd(";") + ";" + $bin), "User") } $env:PATH = "$env:PATH;$bin" $installed = $true Write-Host "Claude Code $version installed to $exe" -ForegroundColor Green } catch { Write-Host "Direct download failed: $($_.Exception.Message)" -ForegroundColor Yellow Write-Host "Trying the official installer (unavailable in some regions)..." try { irm https://claude.ai/install.ps1 | iex; $installed = $true } catch {} } if (-not $installed) { Write-Host "Could not install Claude Code automatically." -ForegroundColor Red Write-Host "If you have Node.js, run: npm install -g @anthropic-ai/claude-code - then re-run this script." return } } # --- 3. settings.json: merge into existing, or write fresh --------------- $dir = Join-Path $env:USERPROFILE ".claude" New-Item -ItemType Directory -Force -Path $dir | Out-Null $settings = Join-Path $dir "settings.json" $ogEnv = [ordered]@{ "ANTHROPIC_BASE_URL" = "https://api.opusgate.dev" "ANTHROPIC_AUTH_TOKEN" = $key "ANTHROPIC_DEFAULT_OPUS_MODEL" = "claude-opus-4.8" "ANTHROPIC_DEFAULT_SONNET_MODEL" = "claude-sonnet-4.6" "ANTHROPIC_DEFAULT_HAIKU_MODEL" = "claude-haiku-4.5" "DISABLE_TELEMETRY" = "1" "DISABLE_ERROR_REPORTING" = "1" } $written = $false if (Test-Path $settings) { Copy-Item $settings "$settings.bak" -Force Write-Host "Existing settings.json backed up to settings.json.bak" try { $json = Get-Content $settings -Raw | ConvertFrom-Json if ($null -eq $json) { throw "empty file" } if (-not ($json.PSObject.Properties.Name -contains "env") -or $null -eq $json.env) { $json | Add-Member -MemberType NoteProperty -Name "env" -Value (New-Object PSObject) -Force } foreach ($k in $ogEnv.Keys) { $json.env | Add-Member -MemberType NoteProperty -Name $k -Value $ogEnv[$k] -Force } [IO.File]::WriteAllText($settings, ($json | ConvertTo-Json -Depth 32)) $written = $true Write-Host "Merged OpusGate settings into your existing settings.json (other settings preserved)." } catch { Write-Host "Could not merge into existing settings.json - writing a fresh one (old file kept as .bak)." -ForegroundColor Yellow } } if (-not $written) { [IO.File]::WriteAllText($settings, @" { "env": { "ANTHROPIC_BASE_URL": "https://api.opusgate.dev", "ANTHROPIC_AUTH_TOKEN": "$key", "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4.8", "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-sonnet-4.6", "ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-haiku-4.5", "DISABLE_TELEMETRY": "1", "DISABLE_ERROR_REPORTING": "1" } } "@) } Write-Host "" Write-Host "Done. Open a NEW terminal and run: claude" -ForegroundColor Green Write-Host "Previously logged in with an Anthropic account? Run /logout inside claude once." Write-Host "Models: /model inside Claude Code. Balance: https://opusgate.dev/dashboard"