diff --git a/scripts/install.ps1 b/scripts/install.ps1 index abe93a289a..6c52c72716 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -764,11 +764,14 @@ function Get-BootstrapPython { $lock = Get-Content (Join-Path $InstallDir "pm\lock.json") -Raw | ConvertFrom-Json $pyPin = $lock.packages.python $pyVersion = if ($pyPin) { ($pyPin.version -split '\+')[0] -replace '^(\d+\.\d+).*', '$1' } else { '3.14' } - $bootPy = (Invoke-Native { & $uv python find --managed-python --no-project $pyVersion 2>$null }) -join "`n" + # A bare version lets uv pick emulated x86_64 on Windows-on-ARM. + $pyArch = if ((Get-WindowsArch) -eq 'arm64') { 'aarch64' } else { 'x86_64' } + $pyRequest = "cpython-$pyVersion-windows-$pyArch-none" + $bootPy = (Invoke-Native { & $uv python find --managed-python --no-project $pyRequest 2>$null }) -join "`n" if ($LASTEXITCODE -or -not $bootPy) { - Invoke-Native { & $uv python install --no-bin --no-registry $pyVersion } | Out-Host + Invoke-Native { & $uv python install --no-bin --no-registry $pyRequest } | Out-Host if ($LASTEXITCODE) { Fail "bootstrap Python installation failed" } - $bootPy = (Invoke-Native { & $uv python find --managed-python --no-project $pyVersion }) -join "`n" + $bootPy = (Invoke-Native { & $uv python find --managed-python --no-project $pyRequest }) -join "`n" } if ($LASTEXITCODE -or -not $bootPy) { Fail "bootstrap Python lookup failed" } return $bootPy.Trim() diff --git a/scripts/tests/test-install-ps1-node-compatibility.ps1 b/scripts/tests/test-install-ps1-node-compatibility.ps1 index dbc2fa6674..c6f4ca32fe 100644 --- a/scripts/tests/test-install-ps1-node-compatibility.ps1 +++ b/scripts/tests/test-install-ps1-node-compatibility.ps1 @@ -51,7 +51,8 @@ exit /b 0 # cmd's `echo %* >> file` keeps the space before `>>` in the recorded line. $recorded = @(Get-Content -LiteralPath $argsFile | ForEach-Object { $_.Trim() }) Assert-True ($recorded.Count -eq 1) 'uv locates the available bootstrap Python without reinstalling it' - Assert-True ($recorded[0] -eq 'python find --managed-python --no-project 3.13') 'Python minor comes from the lockfile; lookup ignores ambient project discovery' + $pyArch = if ((Get-WindowsArch) -eq 'arm64') { 'aarch64' } else { 'x86_64' } + Assert-True ($recorded[0] -eq "python find --managed-python --no-project cpython-3.13-windows-$pyArch-none") 'Python minor comes from the lockfile, pinned to the machine architecture; lookup ignores ambient project discovery' Assert-True ((Get-Content -LiteralPath $pythonArgsFile -Raw).Trim() -eq '-m pm.cli install') 'Python launches PM without a uv parent' # The installer owns no node stage: tool and frontend provisioning belongs diff --git a/setup-hermes.ps1 b/setup-hermes.ps1 index 9ca6c5f249..b96b8bd77a 100644 --- a/setup-hermes.ps1 +++ b/setup-hermes.ps1 @@ -82,9 +82,11 @@ Write-Host '(first run on a fresh checkout can take 1-5 minutes)' Push-Location $repo try { # PM can replace its uv entry only after the bootstrap uv has exited. - & $uv python install --no-bin --no-registry $pyVersion + # A bare version lets uv pick emulated x86_64 on Windows-on-ARM. + $pyRequest = "cpython-$pyVersion-windows-$(if ($arch -eq 'arm64') { 'aarch64' } else { 'x86_64' })-none" + & $uv python install --no-bin --no-registry $pyRequest if ($LASTEXITCODE -ne 0) { throw 'bootstrap Python installation failed' } - $bootPy = (& $uv python find --managed-python $pyVersion) -join "`n" + $bootPy = (& $uv python find --managed-python $pyRequest) -join "`n" if ($LASTEXITCODE -ne 0 -or -not $bootPy) { throw 'bootstrap Python lookup failed' } & $bootPy.Trim() -m pm.cli install $(if ($RuntimeOnly) { '--trust-recorded' }) "--test-environment=$TestExtras" if ($LASTEXITCODE -ne 0) { throw 'pm install failed - see output above.' } diff --git a/setup-hermes.sh b/setup-hermes.sh index f1fbaf00ee..b169bedc09 100755 --- a/setup-hermes.sh +++ b/setup-hermes.sh @@ -164,8 +164,14 @@ fi echo -e "${CYAN}→${NC} Installing python + tools + dependencies via pm (hash-verified via uv.lock)..." echo -e "${CYAN}→${NC} (first run on a fresh checkout can take 1-5 minutes)" # PM can replace its uv entry only after the bootstrap uv has exited. -"$uv" python install --no-bin --no-registry "$py_version" -boot_py="$("$uv" python find --managed-python "$py_version")" +# A bare version lets uv pick emulated x86_64 on Windows-on-ARM. +py_request="$py_version" +if [ "$os" = win32 ]; then + case "$arch" in arm64) py_request="cpython-$py_version-windows-aarch64-none" ;; + *) py_request="cpython-$py_version-windows-x86_64-none" ;; esac +fi +"$uv" python install --no-bin --no-registry "$py_request" +boot_py="$("$uv" python find --managed-python "$py_request")" boot_py="${boot_py%$'\r'}" # Activation trusts the recorded tool digest; a direct setup re-checks it # (setup-hermes.ps1 draws the same line).