# weave - live IT control plane CLI # One-liner installer for Windows (PowerShell 5.1+). # # irm https://weavewhatever.com/install.ps1 | iex # # Environment overrides: # $env:WEAVE_REPO Git URL to install from (default: https://github.com/andy-broyles/weavewhatever.git) # Must match the GitHub repo pattern below — arbitrary URLs are rejected. # $env:WEAVE_REF Branch/tag/sha to install. Overrides WEAVE_VERSION when set. # $env:WEAVE_VERSION Release to install (e.g. 0.2.0 -> tag v0.2.0). When unset and # WEAVE_REF is unset, uses the latest v* tag on WEAVE_REPO, else main. # $env:WEAVE_QUIET Set to "1" to suppress the banner # $env:UV_VERSION Pin Astral's uv to a specific version (default below). Best-effort: # Astral's installer reads UV_VERSION for older releases; if the # current upstream installer ignores it, uv will fall back to its # "install latest" behavior. See TODO(security) below. #Requires -Version 5.1 $ErrorActionPreference = 'Stop' $DefaultRepo = 'https://github.com/andy-broyles/weavewhatever.git' $DefaultRef = 'main' # TODO(security): pin uv to a known-good version. Astral's installer historically # honored $env:UV_VERSION, but the canonical way to lock the version is to # download a specific release artifact (https://github.com/astral-sh/uv/releases) # and verify its SHA256 before extracting. Until that's wired up, we set a # default UV_VERSION which the upstream installer *may* honor. $DefaultUvVersion = '0.5.11' $Repo = if ($env:WEAVE_REPO) { $env:WEAVE_REPO } else { $DefaultRepo } function Resolve-WeaveRef { if ($env:WEAVE_REF) { return $env:WEAVE_REF } if ($env:WEAVE_VERSION) { $v = $env:WEAVE_VERSION -replace '^v', '' return "v$v" } if (Get-Command git -ErrorAction SilentlyContinue) { try { $tags = git ls-remote --tags --refs $Repo 2>$null | ForEach-Object { ($_ -split '/')[2] } | Where-Object { $_ -match '^v\d+\.\d+\.\d+$' } | Sort-Object { [version]($_ -replace '^v', '') } | Select-Object -Last 1 if ($tags) { return $tags } } catch { } } return $DefaultRef } $UvVersion = if ($env:UV_VERSION) { $env:UV_VERSION } else { $DefaultUvVersion } $env:UV_VERSION = $UvVersion # --- input validation ---------------------------------------------------- # We refuse to install from arbitrary URLs or refs. This is defense in depth # against `irm … | iex` phishing attempts (especially via copy-pasted commands # that someone tampered with). The allow-list matches HTTPS or SSH GitHub URLs. $RepoRegex = '^(https://github\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(\.git)?|git@github\.com:[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(\.git)?)$' $RefRegex = '^[A-Za-z0-9_./-]+$' if ($Repo -notmatch $RepoRegex) { Write-Host "" Write-Host "ERROR: WEAVE_REPO=$Repo does not look like a GitHub repo URL." -ForegroundColor Red Write-Host "Refusing to install from arbitrary sources." -ForegroundColor Red Write-Host "Expected: https://github.com//(.git) or git@github.com:/(.git)" Write-Host "" exit 2 } if ($Ref -notmatch $RefRegex) { Write-Host "" Write-Host "ERROR: WEAVE_REF=$Ref contains characters outside the refspec allow-list." -ForegroundColor Red Write-Host "Allowed: letters, digits, dot, underscore, slash, hyphen." Write-Host "" exit 2 } function Write-Info ($msg) { Write-Host "* $msg" -ForegroundColor Blue } function Write-Ok ($msg) { Write-Host "+ $msg" -ForegroundColor Green } function Write-Warn ($msg) { Write-Host "! $msg" -ForegroundColor Yellow } function Write-Die ($msg) { Write-Host "x $msg" -ForegroundColor Red; exit 1 } function Show-Banner { if ($env:WEAVE_QUIET -eq '1') { return } Write-Host '' Write-Host ' weave' -NoNewline -ForegroundColor Cyan Write-Host ' - live IT control plane' Write-Host ' https://weavewhatever.com' -ForegroundColor DarkGray Write-Host '' } function Show-ResolvedTargets { Write-Host " Installing from: $Repo" Write-Host " Ref: $Ref" Write-Host " Pinned uv: $UvVersion" Write-Host '' } function Test-Cmd ([string]$Name) { return [bool](Get-Command $Name -ErrorAction SilentlyContinue) } function Ensure-Python { $py = $null foreach ($candidate in @('python', 'python3', 'py')) { if (Test-Cmd $candidate) { $py = $candidate; break } } if (-not $py) { Write-Die "Python 3.11+ is required but not found. Install from https://www.python.org/downloads/ and re-run." } & $py -c "import sys; sys.exit(0 if sys.version_info >= (3, 11) else 1)" 2>$null if ($LASTEXITCODE -ne 0) { $ver = (& $py --version) 2>&1 Write-Die "Python 3.11+ required (found $ver)." } $ver = & $py -c "import sys; print('%d.%d.%d' % sys.version_info[:3])" Write-Ok "Python $ver ready" } function Ensure-Uv { if (Test-Cmd 'uv') { $uvver = (uv --version) -split ' ' | Select-Object -Last 1 Write-Ok "uv $uvver already installed" return } Write-Info "Installing uv $UvVersion (fast Python package + tool manager)..." # $env:UV_VERSION is set above; the upstream installer reads it for # versions that support pinning. See TODO(security) at the top. try { Invoke-RestMethod https://astral.sh/uv/install.ps1 | Invoke-Expression } catch { Write-Die "uv installation failed: $($_.Exception.Message)" } # uv installs into %USERPROFILE%\.local\bin by default $uvBin = Join-Path $env:USERPROFILE '.local\bin' if (Test-Path $uvBin) { $env:Path = "$uvBin;$env:Path" } if (-not (Test-Cmd 'uv')) { Write-Die "uv install completed but 'uv' isn't on PATH. Open a new PowerShell and re-run." } Write-Ok "uv installed" } function Install-Weave { Write-Info "Installing weave from $Repo@$Ref..." $spec = "git+${Repo}@${Ref}" uv tool install --force --python ">=3.11" $spec if ($LASTEXITCODE -ne 0) { Write-Die "uv tool install failed (exit $LASTEXITCODE)." } Write-Ok "weave installed" } function Show-Next-Steps { Write-Host '' Write-Host '+ weave is ready.' -ForegroundColor Green Write-Host '' Write-Host ' Next step (required):' -ForegroundColor White Write-Host ' weave setup' -ForegroundColor Cyan Write-Host ' (weave init is the same)' -ForegroundColor DarkGray Write-Host '' Write-Host ' Then:' -ForegroundColor DarkGray Write-Host ' weave --help' -ForegroundColor DarkGray Write-Host '' Write-Host ' Developing locally? From the repo root run:' -ForegroundColor DarkGray Write-Host ' pip install -e .' -ForegroundColor DarkGray Write-Host ' Ensure your Python Scripts folder is on PATH (e.g. %LOCALAPPDATA%\Programs\Python\Python311\Scripts).' -ForegroundColor DarkGray Write-Host '' Write-Host " Docs: https://weavewhatever.com/getting-started.html" -ForegroundColor Blue Write-Host " Repo: $Repo" -ForegroundColor Blue Write-Host '' if (Test-Cmd 'weave') { $installed = (weave --version 2>&1 | Out-String).Trim() if (-not $installed) { $installed = (weave version 2>&1 | Out-String).Trim() } if ($installed) { Write-Ok "Installed: $installed" } } else { Write-Warn "weave was installed but isn't on PATH in this shell." Write-Host ' Open a new PowerShell window, or run:' -ForegroundColor DarkGray Write-Host ' $env:Path = "$env:USERPROFILE\.local\bin;$env:Path"' -ForegroundColor DarkGray Write-Host '' } } $Ref = Resolve-WeaveRef Show-Banner Show-ResolvedTargets Write-Info "Detected $([System.Runtime.InteropServices.RuntimeInformation]::OSDescription)" Ensure-Python Ensure-Uv Install-Weave Show-Next-Steps