#Requires -Version 5.1 <# .SYNOPSIS agy.exe 존재를 확인하고, 없으면 공식 install.ps1 로 무인 설치한다. .DESCRIPTION 1순위: 공식 설치 스크립트 https://antigravity.google/cli/install.ps1 (SHA512 무결성 검증 내장, 이미 설치돼 있으면 아무 것도 하지 않고 종료 코드 0 으로 빠지는 멱등한 스크립트 — agy CLI SSOT §3.3 실측). 2순위: winget (1순위가 실패했을 때만 시도). 설치 여부와 별개로 "인증(로그인) 여부"도 가볍게 점검한다. agy 는 OAuth 토큰을 사용자 프로필 아래 평문 파일로 저장한다(agy CLI SSOT §4.2 실측: ~\.gemini\antigravity-cli\antigravity-oauth-token). 그 파일의 존재만 확인하고, 실제로 토큰이 유효한지 확인하는 헤드리스 왕복 호출은 하지 않는다 — 그 호출 자체가 수만 토큰 비용을 태우므로(SSOT §4.3 경고), 설치 스크립트 안에서 매번 돌릴 일이 아니다. 진짜 유효성 판정은 실제 작업 호출의 성공/실패로 한다(agy/client.py 의 책임). .PARAMETER Force 이미 정상 설치되어 있어도 재설치를 시도한다. .OUTPUTS 표준 출력에 사람이 읽을 진행 메시지, 마지막 줄에 "VERSION=<버전>" (설치가 확인됐을 때만) — GUI/CLI 가 파싱하고 싶으면 이 줄만 보면 된다. .EXITCODE 0 : 정상 — agy.exe 설치 확인 + 인증 토큰 파일 존재. 10 : 설치 필요 — agy.exe 를 (재)설치하지 못했다. 11 : 인증 필요 — agy.exe 는 설치돼 있지만 로그인 토큰 파일이 없다. `agy login` 을 사용자가 직접 수행해야 한다(대화형 브라우저 로그인이라 무인화할 수 없다 — agy CLI SSOT §4.1). .EXAMPLE powershell -ExecutionPolicy Bypass -File .\scripts\bootstrap_agy.ps1 #> [CmdletBinding()] param( [switch]$Force ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Continue' function Write-Step { param([string]$Message) Write-Host "[bootstrap_agy] $Message" } function Write-Warn { param([string]$Message) Write-Host "[bootstrap_agy] ! $Message" -ForegroundColor Yellow } function Write-Good { param([string]$Message) Write-Host "[bootstrap_agy] + $Message" -ForegroundColor Green } # 설치·점검 도중 백그라운드 self-update 가 끼어들면 바이너리가 교체돼 # 검증이 흔들린다. 이 프로세스 범위에서만 끈다(agy CLI SSOT §3.6). $env:AGY_CLI_DISABLE_AUTO_UPDATE = 'true' # 절대경로 고정 — where.exe 는 winget Links 심볼릭까지 잡아 두 경로가 # 나올 수 있으므로(agy CLI SSOT §3.2 실측) 신뢰하지 않는다. $agyExe = Join-Path $env:LOCALAPPDATA 'agy\bin\agy.exe' $agyToken = Join-Path $env:USERPROFILE '.gemini\antigravity-cli\antigravity-oauth-token' function Test-AgyOk { <# agy.exe 가 존재하고 실제로 실행되는지 확인한다. 0바이트 스텁·중단된 다운로드를 걸러낸다(실측 정상 크기 약 187MB). 성공하면 버전 문자열을, 실패하면 $null 을 돌려준다. #> if (-not (Test-Path -LiteralPath $agyExe)) { return $null } $item = Get-Item -LiteralPath $agyExe -ErrorAction SilentlyContinue if (-not $item -or $item.Length -lt 1MB) { return $null } try { $v = & $agyExe --version 2>$null } catch { return $null } if ($LASTEXITCODE -ne 0 -or -not $v) { return $null } return ($v | Select-Object -First 1).ToString().Trim() } function Test-AgyAuthenticated { <# 인증 여부의 가벼운(비용 없는) 근사치: 토큰 파일 존재 여부. 실제 유효성(만료 여부)까지는 확인하지 않는다 — §4.3 경고 참조. #> return (Test-Path -LiteralPath $agyToken) } Write-Step "확인 경로: $agyExe" $version = Test-AgyOk if ($version -and -not $Force) { Write-Good "이미 설치되어 있습니다. (버전 $version)" } else { if ($Force) { Write-Step '재설치를 요청받았습니다. 설치를 진행합니다.' } else { Write-Step '설치되어 있지 않거나 손상된 것으로 보입니다. 설치를 진행합니다.' } # ------------------------------------------------------------ 1순위: 공식 설치 스크립트 Write-Step '공식 설치 스크립트를 받는 중... (irm https://antigravity.google/cli/install.ps1 | iex)' try { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 } catch { Write-Warn 'TLS 1.2 강제 설정에 실패했습니다. 기본 프로토콜로 계속합니다.' } try { Invoke-Expression (Invoke-RestMethod -Uri 'https://antigravity.google/cli/install.ps1' -UseBasicParsing) } catch { Write-Warn "공식 설치 스크립트 실행 실패: $($_.Exception.Message)" } $version = Test-AgyOk if ($version) { Write-Good "설치 확인: 버전 $version" } else { # -------------------------------------------------------- 2순위: winget Write-Step '1순위 설치가 확인되지 않았습니다. winget 으로 다시 시도합니다...' $winget = Get-Command winget.exe -ErrorAction SilentlyContinue if ($winget) { try { & $winget.Source install --id Google.AntigravityCLI --silent ` --accept-package-agreements --accept-source-agreements | Out-Null } catch { Write-Warn "winget 설치 실패: $($_.Exception.Message)" } } else { Write-Warn 'winget 을 사용할 수 없습니다.' } $version = Test-AgyOk if ($version) { Write-Good "설치 확인: 버전 $version" } } } if (-not $version) { Write-Warn '설치에 실패했습니다. 네트워크 연결 또는 방화벽 설정을 확인해 주세요.' Write-Warn " 수동 설치: irm https://antigravity.google/cli/install.ps1 | iex" exit 10 } Write-Host "VERSION=$version" if (-not (Test-AgyAuthenticated)) { Write-Warn '로그인 토큰을 찾을 수 없습니다. 로그인이 필요합니다.' Write-Warn " 다음 명령을 배치를 돌릴 그 계정으로 실행하세요:" Write-Warn " & `"$agyExe`" login" exit 11 } Write-Good '설치와 로그인 토큰 확인이 모두 끝났습니다.' exit 0