|
| 1 | +# Install Cortex CLI from https://software.cortex.foundation |
| 2 | +# |
| 3 | +# Usage: |
| 4 | +# irm https://software.cortex.foundation/install.ps1 | iex |
| 5 | +# |
| 6 | +# Optional environment: |
| 7 | +# CORTEX_VERSION Pin a version (e.g. 0.1.2). Default: latest on the channel. |
| 8 | +# CORTEX_CHANNEL stable (default), beta, or nightly |
| 9 | +# CORTEX_INSTALL_DIR Prefix (default: $env:LOCALAPPDATA\Cortex). Binary in PREFIX\bin. |
| 10 | +# CORTEX_SOFTWARE_URL Override the distribution host (testing only). |
| 11 | +# |
| 12 | +# Downloads the matching zip, verifies SHA-256, then installs Cortex.exe. |
| 13 | +# Checksum verification is required; the script will not install an unverified file. |
| 14 | + |
| 15 | +Set-StrictMode -Version Latest |
| 16 | +$ErrorActionPreference = "Stop" |
| 17 | + |
| 18 | +$SoftwareUrl = if ($env:CORTEX_SOFTWARE_URL) { $env:CORTEX_SOFTWARE_URL.TrimEnd("/") } else { "https://software.cortex.foundation" } |
| 19 | +$Channel = if ($env:CORTEX_CHANNEL) { $env:CORTEX_CHANNEL } else { "stable" } |
| 20 | +$Prefix = if ($env:CORTEX_INSTALL_DIR) { $env:CORTEX_INSTALL_DIR } else { Join-Path $env:LOCALAPPDATA "Cortex" } |
| 21 | +$BinDir = Join-Path $Prefix "bin" |
| 22 | +$PinnedVersion = if ($env:CORTEX_VERSION) { $env:CORTEX_VERSION.TrimStart("v") } else { $null } |
| 23 | + |
| 24 | +if ($Channel -notin @("stable", "beta", "nightly")) { |
| 25 | + throw "install.ps1: invalid CORTEX_CHANNEL='$Channel' (use stable, beta, or nightly)" |
| 26 | +} |
| 27 | + |
| 28 | +$arch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture |
| 29 | +switch ($arch) { |
| 30 | + "X64" { $Platform = "windows-x86_64" } |
| 31 | + "Arm64" { throw "install.ps1: Windows ARM64 builds are not published yet. Use an x64 machine or the GitHub Release." } |
| 32 | + default { throw "install.ps1: unsupported architecture: $arch" } |
| 33 | +} |
| 34 | + |
| 35 | +function Get-Json($Url) { |
| 36 | + return Invoke-RestMethod -Uri $Url -Method Get |
| 37 | +} |
| 38 | + |
| 39 | +function Try-GetJson($Url) { |
| 40 | + try { |
| 41 | + return Invoke-RestMethod -Uri $Url -Method Get |
| 42 | + } catch { |
| 43 | + return $null |
| 44 | + } |
| 45 | +} |
| 46 | + |
| 47 | +Write-Host "Cortex CLI installer" |
| 48 | +Write-Host " host: $SoftwareUrl" |
| 49 | +Write-Host " platform: $Platform" |
| 50 | +Write-Host " prefix: $Prefix" |
| 51 | + |
| 52 | +$release = $null |
| 53 | +$version = $PinnedVersion |
| 54 | + |
| 55 | +if ($version) { |
| 56 | + $release = Try-GetJson "$SoftwareUrl/releases/$version.json" |
| 57 | + if (-not $release) { |
| 58 | + $release = Try-GetJson "$SoftwareUrl/v1/releases/$version.json" |
| 59 | + } |
| 60 | + if (-not $release) { |
| 61 | + throw "install.ps1: could not fetch release metadata for $version from $SoftwareUrl" |
| 62 | + } |
| 63 | +} else { |
| 64 | + $manifest = Try-GetJson "$SoftwareUrl/releases/manifest.json" |
| 65 | + if (-not $manifest) { |
| 66 | + $manifest = Try-GetJson "$SoftwareUrl/v1/releases/manifest.json" |
| 67 | + } |
| 68 | + if (-not $manifest) { |
| 69 | + throw "install.ps1: could not fetch $SoftwareUrl/releases/manifest.json" |
| 70 | + } |
| 71 | + $release = $manifest.$Channel |
| 72 | + if (-not $release) { |
| 73 | + throw "install.ps1: no $Channel release in manifest" |
| 74 | + } |
| 75 | + $version = $release.version |
| 76 | +} |
| 77 | + |
| 78 | +$asset = $release.assets.$Platform |
| 79 | +if (-not $asset) { |
| 80 | + throw "install.ps1: no asset for platform $Platform in version $version" |
| 81 | +} |
| 82 | + |
| 83 | +$expectedSha = ([string]$asset.sha256).Trim().ToLowerInvariant() |
| 84 | +if (-not $expectedSha) { |
| 85 | + throw "install.ps1: release JSON missing sha256 for $Platform" |
| 86 | +} |
| 87 | + |
| 88 | +Write-Host " version: $version" |
| 89 | +Write-Host " download: $($asset.url)" |
| 90 | + |
| 91 | +$tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("cortex-install-" + [guid]::NewGuid().ToString("N")) |
| 92 | +New-Item -ItemType Directory -Path $tempRoot | Out-Null |
| 93 | +try { |
| 94 | + $zipPath = Join-Path $tempRoot "cortex.zip" |
| 95 | + Invoke-WebRequest -Uri $asset.url -OutFile $zipPath -UseBasicParsing |
| 96 | + |
| 97 | + $actualSha = (Get-FileHash -Path $zipPath -Algorithm SHA256).Hash.ToLowerInvariant() |
| 98 | + if ($actualSha -ne $expectedSha) { |
| 99 | + throw "install.ps1: SHA-256 mismatch for cortex.zip: expected $expectedSha, got $actualSha" |
| 100 | + } |
| 101 | + Write-Host " checksum: ok" |
| 102 | + |
| 103 | + $extractDir = Join-Path $tempRoot "extract" |
| 104 | + Expand-Archive -Path $zipPath -DestinationPath $extractDir -Force |
| 105 | + |
| 106 | + $binary = Get-ChildItem -Path $extractDir -Recurse -File | |
| 107 | + Where-Object { $_.Name -in @("Cortex.exe", "cortex.exe") } | |
| 108 | + Select-Object -First 1 |
| 109 | + if (-not $binary) { |
| 110 | + throw "install.ps1: archive did not contain Cortex.exe" |
| 111 | + } |
| 112 | + |
| 113 | + New-Item -ItemType Directory -Path $BinDir -Force | Out-Null |
| 114 | + $dest = Join-Path $BinDir "Cortex.exe" |
| 115 | + Copy-Item -Path $binary.FullName -Destination $dest -Force |
| 116 | + |
| 117 | + $userPath = [Environment]::GetEnvironmentVariable("Path", "User") |
| 118 | + $pathParts = @() |
| 119 | + if ($userPath) { |
| 120 | + $pathParts = $userPath.Split(";", [System.StringSplitOptions]::RemoveEmptyEntries) |
| 121 | + } |
| 122 | + if ($pathParts -notcontains $BinDir) { |
| 123 | + $newPath = if ($userPath) { "$userPath;$BinDir" } else { $BinDir } |
| 124 | + [Environment]::SetEnvironmentVariable("Path", $newPath, "User") |
| 125 | + $env:Path = "$env:Path;$BinDir" |
| 126 | + Write-Host "Added $BinDir to the user PATH." |
| 127 | + } |
| 128 | + |
| 129 | + Write-Host "Installed Cortex CLI v$version to $dest" |
| 130 | + Write-Host "Restart the terminal, then run: cortex --version" |
| 131 | +} finally { |
| 132 | + Remove-Item -Recurse -Force $tempRoot -ErrorAction SilentlyContinue |
| 133 | +} |
0 commit comments