# Rove native-first Windows installer $ErrorActionPreference = "Stop" Write-Host "===================================================================" -ForegroundColor Cyan Write-Host "Installing Rove native toolchain..." -ForegroundColor Cyan Write-Host "===================================================================" -ForegroundColor Cyan $InstallDir = if ($env:ROVE_INSTALL_DIR) { [System.IO.Path]::GetFullPath($env:ROVE_INSTALL_DIR) } elseif ($env:NYX_INSTALL_DIR) { [System.IO.Path]::GetFullPath($env:NYX_INSTALL_DIR) } else { Join-Path $HOME ".rove" } $BinDir = Join-Path $InstallDir "bin" $SrcDir = Join-Path $InstallDir "src" $CompilerDir = Join-Path $InstallDir "compiler" $ExtensionDir = Join-Path $InstallDir "vscode-extension" $NativeExe = Join-Path $BinDir "rovec.exe" $Repository = "justsomeone-e/RoveLang" $ReleaseTag = if ($env:ROVE_RELEASE_TAG) { $env:ROVE_RELEASE_TAG } else { $env:NYX_RELEASE_TAG } $NativeCompilerPath = if ($env:ROVE_NATIVE_COMPILER_PATH) { $env:ROVE_NATIVE_COMPILER_PATH } else { $env:NYX_NATIVE_COMPILER_PATH } $SkipPathUpdate = if ($env:ROVE_SKIP_PATH_UPDATE) { $env:ROVE_SKIP_PATH_UPDATE } else { $env:NYX_SKIP_PATH_UPDATE } $SkipEditorInstall = if ($env:ROVE_SKIP_EDITOR_INSTALL) { $env:ROVE_SKIP_EDITOR_INSTALL } else { $env:NYX_SKIP_EDITOR_INSTALL } $ExpectedVersion = $null if ($PSScriptRoot -and (Test-Path -LiteralPath (Join-Path $PSScriptRoot "VERSION") -PathType Leaf)) { $ExpectedVersion = (Get-Content -LiteralPath (Join-Path $PSScriptRoot "VERSION") -Raw).Trim() } function Find-RovePython { foreach ($name in @("python", "python3")) { $command = Get-Command $name -ErrorAction SilentlyContinue if ($command) { $commandPath = @($command.Path, $command.Definition, $command.Source) | Where-Object { $_ -and (Test-Path -LiteralPath $_ -PathType Leaf) } | Select-Object -First 1 if (-not $commandPath) { continue } try { & $commandPath -c "import sys; raise SystemExit(0 if sys.version_info >= (3, 10) else 1)" *> $null if ($LASTEXITCODE -eq 0) { return $commandPath } } catch { continue } } } return $null } function Test-RoveNativeCompiler([string]$Path) { if (-not (Test-Path -LiteralPath $Path -PathType Leaf)) { return $false } try { $versionOutput = (& $Path --version 2>&1 | Out-String).Trim() if ($LASTEXITCODE -ne 0 -or (-not $versionOutput.StartsWith("rovec ") -and -not $versionOutput.StartsWith("nyxc "))) { return $false } if ($ExpectedVersion) { return $versionOutput.StartsWith("rovec $ExpectedVersion ") -or $versionOutput.StartsWith("nyxc $ExpectedVersion ") } return $true } catch { return $false } } function Get-RoveRelease { try { $headers = @{ Accept = "application/vnd.github+json" "X-GitHub-Api-Version" = "2022-11-28" } if ($ReleaseTag) { $tag = [uri]::EscapeDataString($ReleaseTag) return Invoke-RestMethod -Uri "https://api.github.com/repos/$Repository/releases/tags/$tag" -Headers $headers } return $null } catch { Write-Host "[!] Release metadata unavailable; source bootstrap remains available." -ForegroundColor Yellow return $null } } New-Item -ItemType Directory -Path $BinDir, $SrcDir, $CompilerDir -Force | Out-Null $CurrentRoot = $PSScriptRoot $HasLocalSource = $CurrentRoot -and (Test-Path -LiteralPath (Join-Path $CurrentRoot "src") -PathType Container) $Release = if ($HasLocalSource -or -not $ReleaseTag) { $null } else { Get-RoveRelease } $SourceRoot = if ($HasLocalSource) { $CurrentRoot } else { $null } $TempRoot = $null try { if (-not $SourceRoot) { $TempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("rove_install_" + [guid]::NewGuid().ToString("N")) $TempArchive = Join-Path $TempRoot "rove-source.zip" $TempExtract = Join-Path $TempRoot "source" New-Item -ItemType Directory -Path $TempExtract -Force | Out-Null $SourceUrl = if ($Release -and $Release.zipball_url) { [string]$Release.zipball_url } else { "https://github.com/$Repository/archive/refs/heads/main.zip" } try { Write-Host "[*] Downloading Rove sources..." -ForegroundColor Cyan Invoke-WebRequest -Uri $SourceUrl -OutFile $TempArchive -UseBasicParsing Expand-Archive -LiteralPath $TempArchive -DestinationPath $TempExtract -Force $SourceRoot = Get-ChildItem -LiteralPath $TempExtract -Directory | Where-Object { Test-Path -LiteralPath (Join-Path $_.FullName "src") -PathType Container } | Select-Object -First 1 -ExpandProperty FullName if (-not $SourceRoot) { throw "Downloaded archive did not contain a Rove source root with src/." } } catch { Write-Host "[!] Source download or extraction failed: $($_.Exception.Message)" -ForegroundColor Yellow Write-Host "[!] Native core installation can still continue from a release binary." -ForegroundColor Yellow } } if ($SourceRoot) { $sourceVersionPath = Join-Path $SourceRoot "VERSION" if (Test-Path -LiteralPath $sourceVersionPath -PathType Leaf) { $ExpectedVersion = (Get-Content -LiteralPath $sourceVersionPath -Raw).Trim() } Write-Host "[*] Installing source and compiler support files..." -ForegroundColor Cyan Copy-Item -Path (Join-Path $SourceRoot "src\*") -Destination $SrcDir -Recurse -Force foreach ($legalFileName in @("VERSION", "LICENSE")) { $legalFile = Join-Path $SourceRoot $legalFileName if (Test-Path -LiteralPath $legalFile -PathType Leaf) { Copy-Item -LiteralPath $legalFile -Destination (Join-Path $InstallDir $legalFileName) -Force } } if (Test-Path -LiteralPath (Join-Path $SourceRoot "compiler") -PathType Container) { Copy-Item -Path (Join-Path $SourceRoot "compiler\*") -Destination $CompilerDir -Recurse -Force } if (Test-Path -LiteralPath (Join-Path $SourceRoot "vscode-extension") -PathType Container) { New-Item -ItemType Directory -Path $ExtensionDir -Force | Out-Null $ExtensionSource = Join-Path $SourceRoot "vscode-extension" foreach ($fileName in @( "package.json", "package-lock.json", "extension.js", "server_options.js", "rove_commands.js", "language-configuration.json", "language-surface.json", "README.md", "CHANGELOG.md", "LICENSE" )) { $sourceFile = Join-Path $ExtensionSource $fileName if (Test-Path -LiteralPath $sourceFile -PathType Leaf) { Copy-Item -LiteralPath $sourceFile -Destination (Join-Path $ExtensionDir $fileName) -Force } } foreach ($directoryName in @("images", "snippets", "syntaxes")) { $sourceDirectory = Join-Path $ExtensionSource $directoryName if (Test-Path -LiteralPath $sourceDirectory -PathType Container) { $destinationDirectory = Join-Path $ExtensionDir $directoryName New-Item -ItemType Directory -Path $destinationDirectory -Force | Out-Null Copy-Item -Path (Join-Path $sourceDirectory "*") -Destination $destinationDirectory -Recurse -Force } } } } $NativeInstalled = $false if ($NativeCompilerPath) { $OverridePath = [System.IO.Path]::GetFullPath($NativeCompilerPath) if (-not (Test-RoveNativeCompiler $OverridePath)) { throw "ROVE_NATIVE_COMPILER_PATH does not point to a working rovec executable: $OverridePath" } Copy-Item -LiteralPath $OverridePath -Destination $NativeExe -Force $NativeInstalled = $true Write-Host "[OK] Installed native compiler from ROVE_NATIVE_COMPILER_PATH." -ForegroundColor Green } if (-not $NativeInstalled -and $HasLocalSource) { foreach ($candidate in @( (Join-Path $CurrentRoot "build\self_host\rovec.exe"), (Join-Path $CurrentRoot "build\self_host\nyxc.exe"), (Join-Path $CurrentRoot "bin\rovec.exe"), (Join-Path $CurrentRoot "bin\nyxc.exe") )) { if (Test-RoveNativeCompiler $candidate) { Copy-Item -LiteralPath $candidate -Destination $NativeExe -Force $NativeInstalled = $true Write-Host "[OK] Installed existing local native compiler." -ForegroundColor Green break } } } if (-not $NativeInstalled -and $Release) { $runtimeArchitecture = [string][System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture if (-not $runtimeArchitecture) { $runtimeArchitecture = [string]$env:PROCESSOR_ARCHITECTURE } $architecture = $runtimeArchitecture.ToLowerInvariant() $assetArchitecture = switch ($architecture) { { $_ -in @("x64", "amd64") } { "x86_64"; break } "arm64" { "arm64" } default { $null } } if ($assetArchitecture) { $assetNames = @( "rovec-windows-$assetArchitecture.exe", "nyxc-windows-$assetArchitecture.exe" ) $asset = $Release.assets | Where-Object { $_.name -in $assetNames } | Sort-Object { [Array]::IndexOf($assetNames, $_.name) } | Select-Object -First 1 if ($asset) { $assetName = [string]$asset.name $TempNative = Join-Path $TempRoot $assetName Write-Host "[*] Downloading native compiler $assetName..." -ForegroundColor Cyan Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $TempNative -UseBasicParsing if ($asset.digest -and ([string]$asset.digest).StartsWith("sha256:")) { $expected = ([string]$asset.digest).Substring(7).ToLowerInvariant() $actual = (Get-FileHash -LiteralPath $TempNative -Algorithm SHA256).Hash.ToLowerInvariant() if ($actual -ne $expected) { throw "Native compiler SHA-256 verification failed." } } Copy-Item -LiteralPath $TempNative -Destination $NativeExe -Force $NativeInstalled = Test-RoveNativeCompiler $NativeExe if ($NativeInstalled) { Write-Host "[OK] Installed verified native release compiler." -ForegroundColor Green } } } } $PythonExe = Find-RovePython $SrcCli = Join-Path $SrcDir "cli.py" if (-not $NativeInstalled -and (Test-RoveNativeCompiler $NativeExe)) { $NativeInstalled = $true Write-Host "[OK] Reusing installed native compiler." -ForegroundColor Green } if (-not $NativeInstalled) { if (-not $PythonExe -or -not (Test-Path -LiteralPath $SrcCli -PathType Leaf)) { throw "No prebuilt rovec is available for this platform. Python 3.10+ and a C++20 compiler are required for the source-bootstrap fallback." } Write-Host "[*] No matching prebuilt binary; bootstrapping native rovec from source..." -ForegroundColor Cyan Push-Location $InstallDir try { & $PythonExe $SrcCli self-host build -o $NativeExe if ($LASTEXITCODE -ne 0) { throw "Native compiler source bootstrap failed." } } finally { Pop-Location } $NativeInstalled = Test-RoveNativeCompiler $NativeExe if (-not $NativeInstalled) { throw "Bootstrapped native compiler failed validation." } Write-Host "[OK] Native rovec bootstrap completed." -ForegroundColor Green } $NativeLiteral = $NativeExe.Replace("'", "''") $CliLiteral = $SrcCli.Replace("'", "''") $PythonLiteral = if ($PythonExe) { $PythonExe.Replace("'", "''") } else { "" } $Ps1Content = @' $native = '__ROVE_NATIVE__' $pythonCli = '__ROVE_CLI__' $preferredPython = '__ROVE_PYTHON__' $nativeCommands = @('check', 'compile', 'emit-cpp', 'version', '--version', '-v') if ($args.Count -gt 0 -and $nativeCommands -contains $args[0]) { & $native @args exit $LASTEXITCODE } if ($preferredPython -and (Test-Path -LiteralPath $preferredPython -PathType Leaf) -and (Test-Path -LiteralPath $pythonCli -PathType Leaf)) { & $preferredPython $pythonCli @args exit $LASTEXITCODE } $python = Get-Command python, python3 -ErrorAction SilentlyContinue | Select-Object -First 1 if ($python -and (Test-Path -LiteralPath $pythonCli -PathType Leaf)) { & $python.Source $pythonCli @args exit $LASTEXITCODE } if ($args.Count -eq 0) { & $native --help exit $LASTEXITCODE } Write-Error "This command still uses the optional Python orchestration layer. Install Python 3.10+, or use rovec check/compile/emit-cpp." exit 2 '@ $Ps1Content = $Ps1Content.Replace("__ROVE_NATIVE__", $NativeLiteral).Replace("__ROVE_CLI__", $CliLiteral).Replace("__ROVE_PYTHON__", $PythonLiteral) foreach ($name in @("rove.ps1", "nyx.ps1")) { Set-Content -LiteralPath (Join-Path $BinDir $name) -Value $Ps1Content -Encoding UTF8 } $BatchNative = $NativeExe.Replace("%", "%%") $BatchCli = $SrcCli.Replace("%", "%%") $BatchPython = if ($PythonExe) { $PythonExe.Replace("%", "%%") } else { "" } $BatContent = @" @echo off setlocal set "ROVE_NATIVE=$BatchNative" set "ROVE_PYCLI=$BatchCli" set "ROVE_PYTHON=$BatchPython" if "%~1"=="check" goto rove_native if "%~1"=="compile" goto rove_native if "%~1"=="emit-cpp" goto rove_native if "%~1"=="version" goto rove_native if "%~1"=="--version" goto rove_native if "%~1"=="-v" goto rove_native if exist "%ROVE_PYTHON%" ( "%ROVE_PYTHON%" "%ROVE_PYCLI%" %* exit /b %errorlevel% ) where python >nul 2>nul if not errorlevel 1 ( python "%ROVE_PYCLI%" %* exit /b %errorlevel% ) where python3 >nul 2>nul if not errorlevel 1 ( python3 "%ROVE_PYCLI%" %* exit /b %errorlevel% ) if "%~1"=="" ( "%ROVE_NATIVE%" --help exit /b %errorlevel% ) echo This command still uses the optional Python orchestration layer. Install Python 3.10+, or use rovec check/compile/emit-cpp. 1>&2 exit /b 2 :rove_native "%ROVE_NATIVE%" %* exit /b %errorlevel% "@ foreach ($name in @("rove.bat", "rove.cmd", "nyx.bat", "nyx.cmd")) { Set-Content -LiteralPath (Join-Path $BinDir $name) -Value $BatContent -Encoding ASCII } $ShContent = @' #!/usr/bin/env bash set -euo pipefail wrapper_dir="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)" install_dir="$(dirname -- "$wrapper_dir")" native="$wrapper_dir/rovec.exe" python_cli="$install_dir/src/cli.py" case "${1:-}" in check|compile|emit-cpp|version|--version|-v) exec "$native" "$@" ;; esac if command -v python3 >/dev/null 2>&1 && [ -f "$python_cli" ]; then exec python3 "$python_cli" "$@" fi if command -v python >/dev/null 2>&1 && [ -f "$python_cli" ]; then exec python "$python_cli" "$@" fi if [ "$#" -eq 0 ]; then exec "$native" --help fi echo "This command still uses the optional Python orchestration layer. Install Python 3.10+, or use rovec check/compile/emit-cpp." >&2 exit 2 '@ Set-Content -LiteralPath (Join-Path $BinDir "rove") -Value $ShContent -Encoding ASCII Set-Content -LiteralPath (Join-Path $BinDir "nyx") -Value $ShContent -Encoding ASCII if ($SkipPathUpdate -ne "1") { $UserPath = [Environment]::GetEnvironmentVariable("Path", "User") if (-not $UserPath) { $UserPath = "" } $PathEntries = @($UserPath -split ";" | Where-Object { $_ -and -not $_.Equals($BinDir, [System.StringComparison]::OrdinalIgnoreCase) }) $UpdatedPath = (@($BinDir) + $PathEntries) -join ";" if ($UpdatedPath -ne $UserPath) { [Environment]::SetEnvironmentVariable("Path", $UpdatedPath, "User") Write-Host "[OK] Prioritized $BinDir in User PATH." -ForegroundColor Green } $ProcessPathEntries = @($env:Path -split ";" | Where-Object { $_ -and -not $_.Equals($BinDir, [System.StringComparison]::OrdinalIgnoreCase) }) $env:Path = (@($BinDir) + $ProcessPathEntries) -join ";" } else { Write-Host "[*] PATH update skipped (ROVE_SKIP_PATH_UPDATE=1)." -ForegroundColor Yellow } $VsCodeExtDir = Join-Path $HOME ".vscode\extensions\rove-lang-support" if ($SkipEditorInstall -ne "1" -and (Test-Path -LiteralPath $ExtensionDir -PathType Container)) { # Prefer npm.cmd or npm.exe over npm.ps1 to avoid PowerShell script execution policy restrictions $NpmCandidate = Get-Command "npm.cmd", "npm.exe" -ErrorAction SilentlyContinue | Select-Object -First 1 if (-not $NpmCandidate) { $NpmCandidate = Get-Command "npm" -ErrorAction SilentlyContinue } $NpmPath = if ($NpmCandidate) { @($NpmCandidate.Path, $NpmCandidate.Source, $NpmCandidate.Definition) | Where-Object { $_ -and (Test-Path -LiteralPath $_ -PathType Leaf) } | Select-Object -First 1 } else { $null } if ($NpmPath) { Push-Location $ExtensionDir try { if ([System.IO.Path]::GetExtension($NpmPath) -ieq ".ps1") { cmd.exe /c npm ci --omit=dev --ignore-scripts | Out-Null } else { & $NpmPath ci --omit=dev --ignore-scripts | Out-Null } if ($LASTEXITCODE -eq 0) { New-Item -ItemType Directory -Path $VsCodeExtDir -Force | Out-Null Copy-Item -Path (Join-Path $ExtensionDir "*") -Destination $VsCodeExtDir -Recurse -Force Write-Host "[OK] Synced Rove VS Code extension to $VsCodeExtDir" -ForegroundColor Green } else { Write-Host "[!] npm ci failed; VS Code extension installation skipped." -ForegroundColor Yellow } } catch { Write-Host "[!] VS Code extension installation skipped ($($_.Exception.Message))." -ForegroundColor Yellow } finally { Pop-Location } } else { Write-Host "[!] npm not found; VS Code extension installation skipped." -ForegroundColor Yellow } } if (-not (Test-RoveNativeCompiler $NativeExe)) { throw "Installed native compiler failed final validation." } Copy-Item -LiteralPath $NativeExe -Destination (Join-Path $BinDir "nyxc.exe") -Force Write-Host "[OK] Native compiler validation passed." -ForegroundColor Green } finally { if ($TempRoot -and (Test-Path -LiteralPath $TempRoot)) { $ResolvedTemp = [System.IO.Path]::GetFullPath($TempRoot) $TempBase = [System.IO.Path]::GetFullPath([System.IO.Path]::GetTempPath()) if ($ResolvedTemp.StartsWith($TempBase, [System.StringComparison]::OrdinalIgnoreCase)) { Remove-Item -LiteralPath $ResolvedTemp -Recurse -Force -ErrorAction SilentlyContinue } } } Write-Host "===================================================================" -ForegroundColor Cyan Write-Host "[OK] Rove installed successfully at $InstallDir" -ForegroundColor Green Write-Host " Native core: rovec --help (legacy alias: nyxc)" -ForegroundColor Green Write-Host " Unified CLI: rove --help (legacy alias: nyx)" -ForegroundColor Green Write-Host "===================================================================" -ForegroundColor Cyan