Newer
Older
cortex-hub / agent-node / bootstrap_windows.ps1
param (
    [string]$NodeId = "",
    [string]$AuthToken = "",
    [string]$HubUrl = "",
    [string]$GrpcUrl = "",
    [switch]$RegisterService = $false,
    [switch]$ForceFirewall = $false,
    [switch]$AutoRun = $true
)

$ErrorActionPreference = "Stop"

Write-Host "==========================================" -ForegroundColor Cyan
Write-Host "   CORTEX AGENT WINDOWS BOOTSTRAP        " -ForegroundColor Cyan
Write-Host "==========================================" -ForegroundColor Cyan

# 1. Check Python installation (defensively avoid Microsoft Store alias)
$pythonValid = $false
try {
    # Check if python is in path and not the 0-byte executable from store
    $out = python --version 2>&1
    if ($out -like "*Python *") { $pythonValid = $true }
} catch { }

if (!$pythonValid) {
    Write-Host "[!] Python not found or invalid. Installing via winget..." -ForegroundColor Yellow
    winget install -e --id Python.Python.3.12 --accept-package-agreements --accept-source-agreements
    # Refresh PATH for the current session
    $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
}

# 2. Verify Python version
$pyVer = python --version
Write-Host "[*] Found $pyVer"

# 3. Create working directory
$workDir = "C:\CortexAgent"
if (!(Test-Path $workDir)) {
    New-Item -ItemType Directory -Path $workDir
}
Set-Location $workDir

# 4. Download agent code from Hub
if ((-not $HubUrl) -or (-not $AuthToken)) {
    Write-Host "[!] Hub details missing. Will prompt for them later after basic setup." -ForegroundColor Yellow
} else {
    Write-Host "[*] Fetching agent source from Hub..." -ForegroundColor Cyan
    $downloadUrl = "$HubUrl/api/v1/agent/download"

    $tarPath = Join-Path $workDir "agent.tar.gz"
    $headers = @{"X-Agent-Token" = $AuthToken}
    
    try {
        Invoke-WebRequest -Uri $downloadUrl -Headers $headers -OutFile $tarPath
        Write-Host "[+] Download complete. Extracting..." -ForegroundColor Green
        
        # Windows 10+ has tar.exe built-in.
        if (Get-Command tar -ErrorAction SilentlyContinue) {
            tar -xzf $tarPath --strip-components=1
        } else {
            Write-Warning "tar.exe not found. Attempting Expand-Archive (may only support .zip)."
            # Minimal fallback logic
        }
        Remove-Item $tarPath
    } catch {
        Write-Warning "Failed to download code directly: $_"
        Write-Host "[!] Please ensure agent-node source is manually placed at $workDir" -ForegroundColor Yellow
    }
}

# 5. Setup Virtual Environment
Write-Host "[*] Creating Virtual Environment..."
if (!(Test-Path "venv")) {
    python -m venv venv
}
$pythonExe = Join-Path $workDir "venv\Scripts\python.exe"

# 6. Install Dependencies
Write-Host "[*] Installing Dependencies..."
& $pythonExe -m pip install --upgrade pip
& $pythonExe -m pip install -r requirements.txt
& $pythonExe -m pip install pywinpty pypiwin32  # Windows-specific requirements

# 7. Environment Setup
Write-Host "------------------------------------------"
Write-Host " Enter Agent Configuration Details:"

if (-not $NodeId) { $NodeId = Read-Host " AGENT_NODE_ID (e.g. pc-node-1)" }
if (-not $AuthToken) { $AuthToken = Read-Host " AGENT_AUTH_TOKEN" }
if (-not $HubUrl) { $HubUrl = Read-Host " HUB_URL (e.g. http://192.168.68.140:8002)" }
if (-not $GrpcUrl) { $GrpcUrl = Read-Host " GRPC_ENDPOINT (e.g. 192.168.68.140:50051)" }

$envFile = @"
AGENT_NODE_ID=$NodeId
AGENT_AUTH_TOKEN=$AuthToken
AGENT_HUB_URL=$HubUrl
GRPC_ENDPOINT=$GrpcUrl
AGENT_TLS_ENABLED=false
PYTHONUTF8=1
"@
$envFile | Out-File -FilePath ".env" -Encoding ascii

# 8. Test Execution
Write-Host "[*] Bootstrap complete." -ForegroundColor Green
if ($AutoRun) {
    Write-Host "[⚡] Auto-starting Agent..." -ForegroundColor Cyan
    Start-Process -FilePath $pythonExe -ArgumentList "src\agent_node\main.py" -WorkingDirectory $workDir
} else {
    Write-Host "    To run manually: .\venv\Scripts\python.exe src\agent_node\main.py" -ForegroundColor Yellow
}

# 9. Optional Service Registration
if ($RegisterService) {
    Write-Host "[*] Registering Scheduled Task..."
    & $pythonExe install_service.py --name "CortexAgent" --run
} elseif ($NodeId -eq "" -or !$NodeId) {
    # Only ask if we are in interactive mode (no NodeId provided early)
    $ans = Read-Host "Would you like to register this as a startup task? (y/n)"
    if ($ans -eq "y") {
        & $pythonExe install_service.py --name "CortexAgent" --run
    }
}

# 10. Security & Firewall Check
Write-Host "------------------------------------------"
Write-Host "[*] Checking Windows Firewall status..." -ForegroundColor Cyan
$profiles = Get-NetFirewallProfile
$disabled = $profiles | Where-Object { $_.Enabled -eq "False" }

if ($disabled) {
    if ($ForceFirewall) {
        Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True
        Write-Host "[+] Windows Firewall enabled." -ForegroundColor Green
    } elseif ($NodeId -eq "" -or !$NodeId) {
        $ans = Read-Host "[!] Warning: Firewall disabled. Enable it now? (y/n)"
        if ($ans -eq "y") {
            Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True
        }
    }
}

# Add rule for Python communication
Write-Host "[*] Adding firewall exception for agent communication..."
if ($pythonExe -and (Test-Path $pythonExe)) {
    New-NetFirewallRule -DisplayName "Cortex Agent Communication" -Direction Outbound -Program $pythonExe -Action Allow -Description "Allows Cortex Agent to reach the Hub" -ErrorAction SilentlyContinue
    New-NetFirewallRule -DisplayName "Cortex Agent Communication" -Direction Inbound -Program $pythonExe -Action Allow -Description "Allows Cortex Agent Mesh Communication" -Profile Any -ErrorAction SilentlyContinue
}

Write-Host "=========================================="
Write-Host "   DONE! Check the Hub for node status.  " -ForegroundColor Cyan
Write-Host "=========================================="