Files
Artemis-Eapil/scripts/download_config.ps1
T
chenmingxuan 2ddec53954
CI / Python 3.12 / ubuntu-latest (push) Canceled after 0s
CI / Python 3.12 / windows-latest (push) Canceled after 0s
CI / Frontend tests and production build (push) Canceled after 0s
CI / Build and smoke-test Python packages (push) Canceled after 0s
feat: add Chinese UI, Responses models, and mirrored Windows setup
Localize the web console and persist custom model and capability settings.
Use OpenAI Responses exclusively and move runtime limits into environment configuration.
Bootstrap uv and the virtual environment on Windows, support optional China mirrors,
and package source distributions without environments, build output, or credentials.

Update regression tests and repository quality checks for the new behavior.
2026-09-22 19:16:17 +08:00

104 lines
6.6 KiB
PowerShell

# Download settings are process-local; never edit global pip/npm/uv settings.
# Keep this file ASCII for Windows PowerShell 5.1.
function Initialize-ArtemisDownloads {
param([string]$ProjectRoot, [string]$Mode)
$path = Join-Path $ProjectRoot 'config\downloads.json'
$config = Get-Content -LiteralPath $path -Raw -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop
if (-not $Mode) { $Mode = $config.mode }
if ($Mode -notin @('Official', 'China')) { throw 'Download mode must be Official or China.' }
$timeout = 0
if (-not [int]::TryParse([string]$config.timeout_seconds, [ref]$timeout) -or $timeout -lt 10 -or $timeout -gt 3600) {
throw 'config/downloads.json: timeout_seconds must be between 10 and 3600.'
}
$values = @{
python_index = ''; python_download_mirror = ''; npm_registry = ''
node_mirror = 'https://nodejs.org/dist'
adb_url = 'https://dl.google.com/android/repository/platform-tools-latest-windows.zip'
scrcpy_url = 'https://github.com/Genymobile/scrcpy/releases/download/v4.1/scrcpy-win64-v4.1.zip'
uv_installer_url = 'https://astral.sh/uv/install.ps1'
}
foreach ($name in @($values.Keys)) {
if ($Mode -eq 'China' -and $config.china.$name) { $values[$name] = [string]$config.china.$name }
if ($config.overrides.$name) { $values[$name] = [string]$config.overrides.$name }
if ($values[$name]) {
$uri = $null
if (-not [Uri]::TryCreate($values[$name], [UriKind]::Absolute, [ref]$uri) -or $uri.Scheme -ne 'https') {
throw "config/downloads.json: $name must be an HTTPS URL."
}
}
}
# Explicit caller environment settings take priority over the selected preset.
if ($env:UV_DEFAULT_INDEX) { $values.python_index = $env:UV_DEFAULT_INDEX }
elseif ($env:UV_INDEX_URL) { $values.python_index = $env:UV_INDEX_URL }
if ($env:UV_PYTHON_INSTALL_MIRROR) { $values.python_download_mirror = $env:UV_PYTHON_INSTALL_MIRROR }
if ($env:npm_config_registry) { $values.npm_registry = $env:npm_config_registry }
if ($values.python_download_mirror) { $env:UV_PYTHON_INSTALL_MIRROR = $values.python_download_mirror }
if ($values.npm_registry) { $env:npm_config_registry = $values.npm_registry }
$env:UV_HTTP_TIMEOUT = [string]$timeout
$env:npm_config_fetch_timeout = [string]($timeout * 1000)
$values.mode = $Mode
$values.timeout_seconds = $timeout
$script:ArtemisDownloads = [pscustomobject]$values
Write-Host " [INFO] Download mode: $Mode (config/downloads.json)." -ForegroundColor Cyan
}
function Install-ArtemisUvFromIndex {
param([string]$IndexUrl, [string]$InstallDir = (Join-Path $env:USERPROFILE '.local\bin'))
# A uv wheel contains the standalone executable; no preinstalled Python is needed.
$work = Join-Path ([IO.Path]::GetTempPath()) ('artemis-uv-' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $work -ErrorAction Stop | Out-Null
try {
$index = $IndexUrl.TrimEnd('/') + '/uv/'
$page = Join-Path $work 'index.html'
if (-not (Invoke-DownloadFile -Uri $index -OutFile $page)) { throw 'Could not download the uv package index.' }
$platform = if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64' -or $env:PROCESSOR_ARCHITEW6432 -eq 'ARM64') { 'win_arm64' } else { 'win_amd64' }
$pattern = 'href=["''](?<link>[^"'']*uv-(?<version>\d+\.\d+\.\d+)-py3-none-' + $platform + '\.whl#sha256=(?<hash>[a-fA-F0-9]{64}))["'']'
$candidates = [regex]::Matches((Get-Content -LiteralPath $page -Raw), $pattern)
$candidate = $candidates | Sort-Object { [version]$_.Groups['version'].Value } -Descending | Select-Object -First 1
if (-not $candidate) { throw "No stable uv wheel for $platform was found on the selected index." }
$url = [Uri]::new([Uri]$index, [System.Net.WebUtility]::HtmlDecode($candidate.Groups['link'].Value))
if ($url.Scheme -ne 'https') { throw 'The uv download must use HTTPS.' }
$zip = Join-Path $work 'uv.zip'
if (-not (Invoke-DownloadFile -Uri $url.AbsoluteUri.Split('#')[0] -OutFile $zip)) { throw 'Could not download uv from the selected index.' }
$hasher = [Security.Cryptography.SHA256]::Create()
$stream = [IO.File]::OpenRead($zip)
try { $digest = [BitConverter]::ToString($hasher.ComputeHash($stream)).Replace('-', '') }
finally { $stream.Dispose(); $hasher.Dispose() }
if ($digest -ne $candidate.Groups['hash'].Value) {
throw 'The downloaded uv package failed SHA256 verification.'
}
$extract = Join-Path $work 'wheel'
Add-Type -AssemblyName System.IO.Compression.FileSystem
[IO.Compression.ZipFile]::ExtractToDirectory($zip, $extract)
$executable = Get-ChildItem -LiteralPath $extract -Filter uv.exe -Recurse -File | Select-Object -First 1
if (-not $executable) { throw 'The uv package did not contain uv.exe.' }
New-Item -ItemType Directory -Path $InstallDir -Force -ErrorAction Stop | Out-Null
Copy-Item -LiteralPath $executable.FullName -Destination (Join-Path $InstallDir 'uv.exe') -Force -ErrorAction Stop
$uvx = Join-Path $executable.DirectoryName 'uvx.exe'
if (Test-Path -LiteralPath $uvx) { Copy-Item -LiteralPath $uvx -Destination $InstallDir -Force -ErrorAction Stop }
$env:PATH = "$InstallDir;$env:PATH"
} finally {
$resolved = (Resolve-Path -LiteralPath $work).Path
$tempRoot = [IO.Path]::GetFullPath([IO.Path]::GetTempPath()).TrimEnd('\') + '\'
if ($resolved.StartsWith($tempRoot, [StringComparison]::OrdinalIgnoreCase) -and (Split-Path $resolved -Leaf) -like 'artemis-uv-*') {
Remove-Item -LiteralPath $resolved -Recurse -Force -ErrorAction SilentlyContinue
}
}
}
function Install-ArtemisLockedDependencies {
param([string]$PythonExe, [string]$IndexUrl)
# uv sync uses the original artifact URLs in uv.lock. Export exact versions and
# hashes, then let uv pip fetch those same artifacts through the chosen index.
$requirements = Join-Path ([IO.Path]::GetTempPath()) ('artemis-requirements-' + [guid]::NewGuid().ToString('N') + '.txt')
try {
& uv export --frozen --no-dev --format requirements-txt --output-file $requirements 1>$null
if ($LASTEXITCODE -ne 0) { throw 'Could not export the locked dependencies.' }
& uv pip install --python $PythonExe --index-url $IndexUrl --requirements $requirements | Out-Host
if ($LASTEXITCODE -ne 0) { throw 'Dependency installation failed. Check mirror availability or select another source in config/downloads.json.' }
} finally {
Remove-Item -LiteralPath $requirements -Force -ErrorAction SilentlyContinue
}
}