330 lines
13 KiB
PowerShell
330 lines
13 KiB
PowerShell
# OpenHarness Windows Installer (PowerShell)
|
|
# Usage: iex (Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/HKUDS/OpenHarness/main/scripts/install.ps1')
|
|
# or: powershell -ExecutionPolicy Bypass -File scripts/install.ps1
|
|
|
|
param(
|
|
[switch]$FromSource,
|
|
[switch]$WithChannels,
|
|
[switch]$Help
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helper functions
|
|
# ---------------------------------------------------------------------------
|
|
function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Cyan }
|
|
function Write-Success { Write-Host "[OK] $args" -ForegroundColor Green }
|
|
function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow }
|
|
function Write-Error { Write-Host "[ERROR] $args" -ForegroundColor Red }
|
|
function Write-Step { Write-Host ""; Write-Host "==>$args" -ForegroundColor Blue -BackgroundColor White }
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Banner
|
|
# ---------------------------------------------------------------------------
|
|
Write-Host ""
|
|
Write-Host " ==============================" -ForegroundColor Cyan
|
|
Write-Host " OpenHarness Installer" -ForegroundColor Cyan
|
|
Write-Host " Windows Native Setup" -ForegroundColor Cyan
|
|
Write-Host " ==============================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Parse arguments
|
|
# ---------------------------------------------------------------------------
|
|
if ($Help) {
|
|
Write-Host "Usage: .\install.ps1 [-FromSource] [-WithChannels]"
|
|
Write-Host ""
|
|
Write-Host " -FromSource Clone from GitHub and install in editable mode"
|
|
Write-Host " -WithChannels Deprecated compatibility flag (dependencies installed by default)"
|
|
exit 0
|
|
}
|
|
|
|
if ($WithChannels) {
|
|
Write-Warn "-WithChannels is no longer required; common IM channel dependencies are installed by default."
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 1: Check PowerShell version
|
|
# ---------------------------------------------------------------------------
|
|
Write-Step "Checking PowerShell version"
|
|
|
|
if ($PSVersionTable.PSVersion.Major -lt 5) {
|
|
Write-Error "PowerShell 5.1 or newer is required."
|
|
Write-Host " Please upgrade PowerShell or use PowerShell Core (pwsh):"
|
|
Write-Host " https://github.com/PowerShell/PowerShell"
|
|
exit 1
|
|
}
|
|
|
|
Write-Success "PowerShell $($PSVersionTable.PSVersion) detected"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 2: Check Python 3.10+
|
|
# ---------------------------------------------------------------------------
|
|
Write-Step "Checking Python version (3.10+ required)"
|
|
|
|
$PythonCmd = $null
|
|
$PythonCommands = @("python", "python3", "py")
|
|
|
|
foreach ($cmd in $PythonCommands) {
|
|
$pyPath = Get-Command $cmd -ErrorAction SilentlyContinue
|
|
if ($pyPath) {
|
|
$versionOutput = & $cmd --version 2>&1
|
|
$versionMatch = $versionOutput -match "Python (\d+)\.(\d+)"
|
|
if ($versionMatch) {
|
|
$major = [int]$matches[1]
|
|
$minor = [int]$matches[2]
|
|
if ($major -ge 3 -and $minor -ge 10) {
|
|
$PythonCmd = $cmd
|
|
break
|
|
} elseif ($major -eq 3 -and $minor -lt 10) {
|
|
Write-Warn "Python $major.$minor found but version 3.10+ is required"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (-not $PythonCmd) {
|
|
Write-Error "Python 3.10+ not found."
|
|
Write-Host ""
|
|
Write-Host " Please install Python 3.10 or newer:"
|
|
Write-Host " Download from: https://www.python.org/downloads/"
|
|
Write-Host " Or use winget: winget install Python.Python.3.12"
|
|
Write-Host ""
|
|
exit 1
|
|
}
|
|
|
|
$PyVersion = & $PythonCmd --version 2>&1
|
|
Write-Success "Found $PyVersion ($PythonCmd)"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 3: Check Node.js >= 18 (optional)
|
|
# ---------------------------------------------------------------------------
|
|
Write-Step "Checking Node.js version (>= 18 required for React TUI)"
|
|
|
|
$NodeOk = $false
|
|
$NodePath = Get-Command node -ErrorAction SilentlyContinue
|
|
if ($NodePath) {
|
|
$NodeVersionOutput = & node --version 2>&1
|
|
$NodeVersionMatch = $NodeVersionOutput -match "v(\d+)"
|
|
if ($NodeVersionMatch) {
|
|
$NodeMajor = [int]$matches[1]
|
|
if ($NodeMajor -ge 18) {
|
|
$NodeOk = $true
|
|
Write-Success "Found Node.js $NodeVersionOutput"
|
|
} else {
|
|
Write-Warn "Node.js $NodeVersionOutput is too old (need >= 18). React TUI will be skipped."
|
|
}
|
|
}
|
|
} else {
|
|
Write-Warn "Node.js not found. React TUI will be skipped."
|
|
Write-Host " To enable the React terminal UI, install Node.js 18+:"
|
|
Write-Host " Download from: https://nodejs.org/"
|
|
Write-Host " Or use winget: winget install OpenJS.NodeJS.LTS"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 4: Install OpenHarness
|
|
# ---------------------------------------------------------------------------
|
|
Write-Step "Installing OpenHarness"
|
|
|
|
$RepoUrl = "https://github.com/HKUDS/OpenHarness.git"
|
|
$InstallDir = "$env:USERPROFILE\.openharness-src"
|
|
$VenvDir = "$env:USERPROFILE\.openharness-venv"
|
|
|
|
# Create virtual environment
|
|
if (Test-Path $VenvDir) {
|
|
Write-Info "Virtual environment already exists at $VenvDir"
|
|
} else {
|
|
Write-Info "Creating virtual environment at $VenvDir..."
|
|
& $PythonCmd -m venv $VenvDir
|
|
if (-not (Test-Path $VenvDir)) {
|
|
Write-Error "Failed to create virtual environment"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# Activate the venv
|
|
$ActivateScript = "$VenvDir\Scripts\Activate.ps1"
|
|
if (-not (Test-Path $ActivateScript)) {
|
|
Write-Error "Virtual environment activation script not found: $ActivateScript"
|
|
exit 1
|
|
}
|
|
|
|
Write-Info "Activating virtual environment..."
|
|
& $ActivateScript
|
|
|
|
Write-Success "Virtual environment ready: $VenvDir"
|
|
|
|
# Install OpenHarness
|
|
if ($FromSource) {
|
|
Write-Info "Mode: -FromSource (git clone + pip install -e .)"
|
|
|
|
$GitPath = Get-Command git -ErrorAction SilentlyContinue
|
|
if (-not $GitPath) {
|
|
Write-Error "git is required for -FromSource installation."
|
|
Write-Host " Install git and retry:"
|
|
Write-Host " winget install Git.Git"
|
|
Write-Host " Or download from: https://git-scm.com/download/win"
|
|
exit 1
|
|
}
|
|
|
|
if (Test-Path "$InstallDir\.git") {
|
|
Write-Info "Source directory exists, pulling latest changes..."
|
|
Push-Location $InstallDir
|
|
git pull --ff-only
|
|
Pop-Location
|
|
} else {
|
|
Write-Info "Cloning OpenHarness into $InstallDir..."
|
|
git clone $RepoUrl $InstallDir
|
|
if (-not (Test-Path $InstallDir)) {
|
|
Write-Error "Failed to clone repository"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
Write-Info "Installing in editable mode (pip install -e .)..."
|
|
pip install -e $InstallDir --quiet
|
|
} else {
|
|
Write-Info "Mode: pip install openharness-ai"
|
|
pip install openharness-ai --quiet --upgrade
|
|
}
|
|
|
|
Write-Success "OpenHarness package installed"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 5: Install frontend/terminal npm dependencies
|
|
# ---------------------------------------------------------------------------
|
|
if ($NodeOk) {
|
|
if ($FromSource) {
|
|
$FrontendDir = "$InstallDir\frontend\terminal"
|
|
} else {
|
|
# Find installed package location
|
|
$PackageInfo = pip show openharness-ai 2>&1
|
|
$LocationMatch = $PackageInfo -match "Location: (.+)"
|
|
if ($LocationMatch) {
|
|
$PackageLocation = $matches[1].Trim()
|
|
$FrontendDir = "$PackageLocation\openharness\_frontend"
|
|
} else {
|
|
$FrontendDir = $null
|
|
}
|
|
}
|
|
|
|
if ($FrontendDir -and (Test-Path "$FrontendDir\package.json")) {
|
|
Write-Step "Installing React TUI dependencies"
|
|
Write-Info "Running npm install in $FrontendDir..."
|
|
Push-Location $FrontendDir
|
|
npm install --no-fund --no-audit --silent 2>&1 | Out-Null
|
|
Pop-Location
|
|
Write-Success "React TUI dependencies installed"
|
|
} else {
|
|
Write-Info "No frontend/terminal directory found - skipping npm install"
|
|
}
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 6: Create OpenHarness config directory
|
|
# ---------------------------------------------------------------------------
|
|
Write-Step "Setting up OpenHarness config directory"
|
|
|
|
$ConfigDir = "$env:USERPROFILE\.openharness"
|
|
$SkillsDir = "$ConfigDir\skills"
|
|
$PluginsDir = "$ConfigDir\plugins"
|
|
|
|
New-Item -ItemType Directory -Force -Path $ConfigDir | Out-Null
|
|
New-Item -ItemType Directory -Force -Path $SkillsDir | Out-Null
|
|
New-Item -ItemType Directory -Force -Path $PluginsDir | Out-Null
|
|
|
|
Write-Success "Config directory ready: ~/.openharness/"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 7: Add to PATH (Windows environment variable)
|
|
# ---------------------------------------------------------------------------
|
|
Write-Step "Setting up PATH integration"
|
|
|
|
$VenvBinDir = "$VenvDir\Scripts"
|
|
$CurrentPath = [Environment]::GetEnvironmentVariable("PATH", "User")
|
|
|
|
if ($CurrentPath -like "*$VenvBinDir*") {
|
|
Write-Info "PATH already contains $VenvBinDir"
|
|
} else {
|
|
Write-Info "Adding $VenvBinDir to user PATH..."
|
|
$NewPath = "$VenvBinDir;$CurrentPath"
|
|
[Environment]::SetEnvironmentVariable("PATH", $NewPath, "User")
|
|
Write-Success "Added $VenvBinDir to PATH"
|
|
Write-Warn "You may need to restart your terminal or log out/log in for PATH changes to take effect."
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Step 8: Verify installation
|
|
# ---------------------------------------------------------------------------
|
|
Write-Step "Verifying installation"
|
|
|
|
$OhPath = "$VenvBinDir\oh.exe"
|
|
$OpenhPath = "$VenvBinDir\openh.exe"
|
|
$OpenharnessPath = "$VenvBinDir\openharness.exe"
|
|
$OhmoPath = "$VenvBinDir\ohmo.exe"
|
|
|
|
# Pick the best available launcher. The 'openh' alias was added after v0.1.6,
|
|
# so PyPI installs of older releases won't have openh.exe. Prefer it when
|
|
# present, otherwise fall back to 'openharness', then 'oh' (which collides
|
|
# with PowerShell's Out-Host alias unless invoked as oh.exe).
|
|
$Launcher = $null
|
|
$LauncherExe = $null
|
|
if (Test-Path $OpenhPath) {
|
|
$Launcher = "openh"
|
|
$LauncherExe = $OpenhPath
|
|
} elseif (Test-Path $OpenharnessPath) {
|
|
$Launcher = "openharness"
|
|
$LauncherExe = $OpenharnessPath
|
|
} elseif (Test-Path $OhPath) {
|
|
$Launcher = "oh"
|
|
$LauncherExe = $OhPath
|
|
}
|
|
|
|
if ($LauncherExe -and (Test-Path $OhmoPath)) {
|
|
$OhVersion = & $LauncherExe --version 2>&1
|
|
Write-Success "Installation successful!"
|
|
Write-Host ""
|
|
Write-Host " $Launcher is ready: $OhVersion" -ForegroundColor Green
|
|
if ($Launcher -eq "oh") {
|
|
Write-Host " Note: 'oh' collides with PowerShell's built-in Out-Host alias." -ForegroundColor Yellow
|
|
Write-Host " Invoke it as 'oh.exe', or use 'openharness' instead." -ForegroundColor Yellow
|
|
} elseif (Test-Path $OhPath) {
|
|
Write-Host " 'oh' is also installed, but PowerShell may resolve it to Out-Host first." -ForegroundColor Yellow
|
|
}
|
|
Write-Host " ohmo is ready" -ForegroundColor Green
|
|
} else {
|
|
# Try module execution
|
|
$ModuleVersion = python -m openharness --version 2>&1
|
|
if ($ModuleVersion) {
|
|
Write-Warn "Launcher commands not yet available on PATH. Run via: python -m openharness"
|
|
Write-Host " Version: $ModuleVersion"
|
|
} else {
|
|
Write-Warn "Could not verify launcher commands. The package may need a PATH update."
|
|
Write-Host " Try: python -m openharness --version"
|
|
}
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Done
|
|
# ---------------------------------------------------------------------------
|
|
Write-Host ""
|
|
Write-Host "OpenHarness is installed!" -ForegroundColor Green -BackgroundColor White
|
|
Write-Host ""
|
|
Write-Host " Next steps:"
|
|
Write-Host " 1. Restart terminal, or run: refreshenv (if using Chocolatey)"
|
|
Write-Host " Or manually refresh: `$env:PATH = [System.Environment]::GetEnvironmentVariable('PATH','User')"
|
|
Write-Host " 2. Set your API key: `$env:ANTHROPIC_API_KEY = 'your_key'"
|
|
if ($Launcher -eq "openharness") {
|
|
Write-Host " 3. Launch (PowerShell): openharness"
|
|
Write-Host " ('openh' is not available on this release; 'oh' collides with PowerShell's Out-Host alias.)"
|
|
} elseif ($Launcher -eq "oh") {
|
|
Write-Host " 3. Launch (PowerShell): oh.exe"
|
|
Write-Host " ('oh' alone collides with PowerShell's Out-Host alias — use 'oh.exe' or 'openharness'.)"
|
|
} else {
|
|
Write-Host " 3. Launch (PowerShell): openh"
|
|
Write-Host " Note: 'oh' may collide with the built-in Out-Host alias in PowerShell."
|
|
}
|
|
Write-Host " 4. Launch ohmo: ohmo"
|
|
Write-Host " 5. Docs: https://github.com/HKUDS/OpenHarness"
|
|
Write-Host ""
|