Files

193 lines
6.0 KiB
PowerShell

param(
[switch]$SkipWinget,
[switch]$SkipCliInstall,
[switch]$SkipScheduler,
[switch]$OnlinePip
)
$ErrorActionPreference = "Stop"
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$env:PYTHONUTF8 = "1"
$env:PYTHONIOENCODING = "utf-8"
$Project = Split-Path -Parent $PSScriptRoot
$VenvPython = Join-Path $Project ".venv\Scripts\python.exe"
$Requirements = Join-Path $Project "requirements.txt"
$Wheelhouse = Join-Path $Project "vendor\wheels"
function Write-Step {
param([string]$Message)
Write-Host ""
Write-Host "== $Message ==" -ForegroundColor Cyan
}
function Test-Admin {
$Identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$Principal = New-Object Security.Principal.WindowsPrincipal($Identity)
return $Principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Ensure-Directory {
param([string]$Path)
New-Item -ItemType Directory -Force -Path $Path | Out-Null
}
function Install-WingetPackage {
param(
[string]$Id,
[string]$CommandName
)
if ($SkipWinget) {
Write-Host "[skip] winget install disabled for $Id"
return
}
if ($CommandName -and (Get-Command $CommandName -ErrorAction SilentlyContinue)) {
Write-Host "[ok] $CommandName already available"
return
}
if (-not (Get-Command winget -ErrorAction SilentlyContinue)) {
Write-Host "[warn] winget not found. Install $Id manually if this step is needed." -ForegroundColor Yellow
return
}
Write-Host "[install] $Id"
winget install --id $Id -e --accept-package-agreements --accept-source-agreements
Refresh-ProcessPath
}
function Refresh-ProcessPath {
$MachinePath = [Environment]::GetEnvironmentVariable("Path", "Machine")
$UserPath = [Environment]::GetEnvironmentVariable("Path", "User")
$env:Path = "$MachinePath;$UserPath"
}
function Resolve-BasePython {
Refresh-ProcessPath
if (Get-Command py -ErrorAction SilentlyContinue) {
$Path = (& py -3.11 -c "import sys; print(sys.executable)" 2>$null)
if ($LASTEXITCODE -eq 0 -and $Path) {
return $Path.Trim()
}
}
if (Get-Command python -ErrorAction SilentlyContinue) {
$Version = (& python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>$null)
if ($LASTEXITCODE -eq 0 -and $Version.Trim() -eq "3.11") {
$Path = (& python -c "import sys; print(sys.executable)")
return $Path.Trim()
}
}
$KnownPaths = @(
(Join-Path $env:LOCALAPPDATA "Programs\Python\Python311\python.exe"),
"C:\Program Files\Python311\python.exe",
"C:\Program Files (x86)\Python311\python.exe"
)
foreach ($KnownPath in $KnownPaths) {
if (Test-Path $KnownPath) {
return $KnownPath
}
}
throw "Python 3.11 was not found. Re-run without -SkipWinget, or install Python 3.11 manually."
}
function Install-NodeCli {
if ($SkipCliInstall) {
Write-Host "[skip] CLI install disabled"
return
}
Refresh-ProcessPath
if (-not (Get-Command npm -ErrorAction SilentlyContinue)) {
Write-Host "[warn] npm not found. Claude/Codex CLI install skipped." -ForegroundColor Yellow
return
}
$HasClaude = (Get-Command claude.cmd -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $env:APPDATA "npm\claude.cmd"))
$HasCodex = (Get-Command codex.cmd -ErrorAction SilentlyContinue) -or (Test-Path (Join-Path $env:APPDATA "npm\codex.cmd"))
if (-not $HasClaude) {
Write-Host "[install] Claude Code CLI"
npm install -g @anthropic-ai/claude-code
} else {
Write-Host "[ok] Claude CLI already available"
}
if (-not $HasCodex) {
Write-Host "[install] Codex CLI"
npm install -g @openai/codex
} else {
Write-Host "[ok] Codex CLI already available"
}
}
if (-not (Test-Admin)) {
Write-Host "[warn] Not running as Administrator. Scheduler registration may fail." -ForegroundColor Yellow
}
Set-Location $Project
Write-Step "Project folders"
Ensure-Directory (Join-Path $Project "logs")
Ensure-Directory (Join-Path $Project "data")
Ensure-Directory (Join-Path $Project "models")
Ensure-Directory (Join-Path $Project "reports\daily")
Ensure-Directory (Join-Path $Project "reports\proposals")
if (-not (Test-Path (Join-Path $Project ".env"))) {
Write-Host "[warn] .env not found. Restore it from your backup before live API use." -ForegroundColor Yellow
}
Write-Step "System tools"
Refresh-ProcessPath
Install-WingetPackage -Id "Git.Git" -CommandName "git"
Install-WingetPackage -Id "OpenJS.NodeJS.LTS" -CommandName "node"
Install-WingetPackage -Id "Python.Python.3.11" -CommandName $null
Write-Step "Python virtual environment"
$BasePython = Resolve-BasePython
Write-Host "[ok] Python base: $BasePython"
if (-not (Test-Path $VenvPython)) {
& $BasePython -m venv (Join-Path $Project ".venv")
}
& $VenvPython -m ensurepip --upgrade
Write-Step "Python libraries"
if (-not (Test-Path $Requirements)) {
throw "requirements.txt not found: $Requirements"
}
if ((Test-Path $Wheelhouse) -and -not $OnlinePip) {
Write-Host "[install] using local wheelhouse: $Wheelhouse"
& $VenvPython -m pip install --no-index --find-links $Wheelhouse -r $Requirements
} else {
Write-Host "[install] using online package index"
& $VenvPython -m pip install -r $Requirements
}
Write-Step "Claude/Codex CLI"
Install-NodeCli
Write-Step "Sanity checks"
& $VenvPython -c "import aiohttp, pandas, sklearn, joblib, holidays; print('python deps ok')"
if (-not $SkipScheduler) {
Write-Step "Windows Task Scheduler"
& powershell.exe -NoProfile -ExecutionPolicy Bypass -File (Join-Path $Project "scripts\setup_scheduler.ps1")
} else {
Write-Host "[skip] scheduler registration disabled"
}
Write-Step "Done"
Write-Host "Restore complete. Reboot once if newly installed winget packages are not visible in new terminals." -ForegroundColor Green