# Python bootstrap shared by the Windows launcher and its isolated checks. # Keep this file ASCII for Windows PowerShell 5.1. function Initialize-ArtemisPython { param([Parameter(Mandatory=$true)][string]$ProjectRoot) $ProjectRoot = (Resolve-Path -LiteralPath $ProjectRoot -ErrorAction Stop).Path if (-not (Test-Path -LiteralPath (Join-Path $ProjectRoot 'pyproject.toml'))) { throw 'pyproject.toml is missing. Extract the complete source archive first.' } if (-not (Test-Path -LiteralPath (Join-Path $ProjectRoot 'uv.lock'))) { throw 'uv.lock is missing. Extract the complete source archive first.' } if (-not (Test-CommandExists 'uv')) { if ($ArtemisDownloads -and $ArtemisDownloads.python_index) { Write-Host ' [INSTALL] Installing uv from the selected Python mirror...' -ForegroundColor Cyan Install-ArtemisUvFromIndex -IndexUrl $ArtemisDownloads.python_index } else { Write-Host ' [INSTALL] uv was not found. Installing from the configured installer...' -ForegroundColor Cyan $installer = Join-Path ([IO.Path]::GetTempPath()) ('artemis-uv-' + [guid]::NewGuid().ToString('N') + '.ps1') try { $installerUrl = if ($ArtemisDownloads) { $ArtemisDownloads.uv_installer_url } else { 'https://astral.sh/uv/install.ps1' } if (-not (Invoke-DownloadFile -Uri $installerUrl -OutFile $installer)) { throw 'Could not download uv. Check your network/proxy and retry.' } & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $installer | Out-Host if ($LASTEXITCODE -ne 0) { throw "uv installation failed (exit $LASTEXITCODE)." } } finally { Remove-Item -LiteralPath $installer -Force -ErrorAction SilentlyContinue } } Update-EnvironmentPath } else { Write-Host ' [SKIP] uv is already installed.' -ForegroundColor Green } if (-not (Test-CommandExists 'uv')) { throw 'uv is still unavailable. Install it from https://astral.sh/uv/ and retry.' } & uv --version | Out-Host if ($LASTEXITCODE -ne 0) { throw 'The installed uv could not run. Repair its installation and retry.' } $venvDir = Join-Path $ProjectRoot '.venv' $pythonExe = Join-Path $venvDir 'Scripts\python.exe' $previousEnvironment = $env:UV_PROJECT_ENVIRONMENT $env:UV_PROJECT_ENVIRONMENT = $venvDir Push-Location -LiteralPath $ProjectRoot try { if (-not (Test-Path -LiteralPath $venvDir)) { Write-Host ' [INSTALL] Creating .venv with Python 3.12 (downloaded automatically if needed)...' -ForegroundColor Cyan & uv venv --python 3.12 $venvDir | Out-Host if ($LASTEXITCODE -ne 0) { throw 'Could not create .venv. Check the download errors above and retry.' } } else { Write-Host ' [SKIP] Reusing the existing project .venv.' -ForegroundColor Green } if (-not (Test-Path -LiteralPath $pythonExe)) { throw 'The existing .venv is incomplete. Rename it as a backup, then rerun start.bat.' } & $pythonExe -c 'import sys; sys.exit(0 if sys.version_info >= (3, 12) and sys.prefix != sys.base_prefix else 1)' | Out-Host if ($LASTEXITCODE -ne 0) { throw 'The existing .venv is unusable or older than Python 3.12. Rename it as a backup, then rerun start.bat.' } # A cheap check skips installation when the lock and installed packages agree. # --inexact preserves any optional development tools already installed. $lockOption = if ($ArtemisDownloads -and $ArtemisDownloads.python_index) { '--frozen' } else { '--locked' } & uv sync --check $lockOption --no-dev --inexact --quiet 2>$null | Out-Host if ($LASTEXITCODE -eq 0) { Write-Host ' [SKIP] Python dependencies are already ready.' -ForegroundColor Green } else { Write-Host ' [INSTALL] Synchronizing dependencies from uv.lock...' -ForegroundColor Cyan if ($ArtemisDownloads -and $ArtemisDownloads.python_index) { Install-ArtemisLockedDependencies -PythonExe $pythonExe -IndexUrl $ArtemisDownloads.python_index } else { & uv sync --locked --no-dev --inexact | Out-Host if ($LASTEXITCODE -ne 0) { throw 'Dependency installation failed. Fix the error above and rerun start.bat.' } } } & $pythonExe -c 'import artemis, uvicorn, fastapi, langchain_openai' | Out-Host if ($LASTEXITCODE -ne 0) { throw 'Python dependency verification failed. The UI will not be started.' } Write-Host ' [OK] Python environment is ready.' -ForegroundColor Green return $pythonExe } finally { Pop-Location $env:UV_PROJECT_ENVIRONMENT = $previousEnvironment } }