mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-07 22:44:16 +00:00
* fix: add Arch Linux support to install.sh (GH#8051) * fix: handle PowerShell execution policy on Windows install (GH#24784)
330 lines
10 KiB
PowerShell
330 lines
10 KiB
PowerShell
# OpenClaw Installer for Windows (PowerShell)
|
|
# Usage: iwr -useb https://openclaw.ai/install.ps1 | iex
|
|
# Or: & ([scriptblock]::Create((iwr -useb https://openclaw.ai/install.ps1))) -NoOnboard
|
|
|
|
param(
|
|
[string]$InstallMethod = "npm",
|
|
[string]$Tag = "latest",
|
|
[string]$GitDir = "$env:USERPROFILE\openclaw",
|
|
[switch]$NoOnboard,
|
|
[switch]$NoGitUpdate,
|
|
[switch]$DryRun
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
# Colors
|
|
$ACCENT = "`e[38;2;255;77;77m" # coral-bright
|
|
$SUCCESS = "`e[38;2;0;229;204m" # cyan-bright
|
|
$WARN = "`e[38;2;255;176;32m" # amber
|
|
$ERROR = "`e[38;2;230;57;70m" # coral-mid
|
|
$MUTED = "`e[38;2;90;100;128m" # text-muted
|
|
$NC = "`e[0m" # No Color
|
|
|
|
function Write-Host {
|
|
param([string]$Message, [string]$Level = "info")
|
|
$msg = switch ($Level) {
|
|
"success" { "$SUCCESS✓$NC $Message" }
|
|
"warn" { "$WARN!$NC $Message" }
|
|
"error" { "$ERROR✗$NC $Message" }
|
|
default { "$MUTED·$NC $Message" }
|
|
}
|
|
Microsoft.PowerShell.Host\Write-Host $msg
|
|
}
|
|
|
|
function Write-Banner {
|
|
Write-Host ""
|
|
Write-Host "${ACCENT} 🦞 OpenClaw Installer$NC" -Level info
|
|
Write-Host "${MUTED} All your chats, one OpenClaw.$NC" -Level info
|
|
Write-Host ""
|
|
}
|
|
|
|
function Get-ExecutionPolicyStatus {
|
|
$policy = Get-ExecutionPolicy
|
|
if ($policy -eq "Restricted" -or $policy -eq "AllSigned") {
|
|
return @{ Blocked = $true; Policy = $policy }
|
|
}
|
|
return @{ Blocked = $false; Policy = $policy }
|
|
}
|
|
|
|
function Test-Admin {
|
|
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
|
|
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
}
|
|
|
|
function Ensure-ExecutionPolicy {
|
|
$status = Get-ExecutionPolicyStatus
|
|
if ($status.Blocked) {
|
|
Write-Host "PowerShell execution policy is set to: $($status.Policy)" -Level warn
|
|
Write-Host "This prevents scripts like npm.ps1 from running." -Level warn
|
|
Write-Host ""
|
|
|
|
# Try to set execution policy for current process
|
|
try {
|
|
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process -ErrorAction Stop
|
|
Write-Host "Set execution policy to RemoteSigned for current process" -Level success
|
|
return $true
|
|
} catch {
|
|
Write-Host "Could not automatically set execution policy" -Level error
|
|
Write-Host ""
|
|
Write-Host "To fix this, run:" -Level info
|
|
Write-Host " Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope Process" -Level info
|
|
Write-Host ""
|
|
Write-Host "Or run PowerShell as Administrator and execute:" -Level info
|
|
Write-Host " Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine" -Level info
|
|
return $false
|
|
}
|
|
}
|
|
return $true
|
|
}
|
|
|
|
function Get-NodeVersion {
|
|
try {
|
|
$version = node --version 2>$null
|
|
if ($version) {
|
|
return $version -replace '^v', ''
|
|
}
|
|
} catch { }
|
|
return $null
|
|
}
|
|
|
|
function Get-NpmVersion {
|
|
try {
|
|
$version = npm --version 2>$null
|
|
if ($version) {
|
|
return $version
|
|
}
|
|
} catch { }
|
|
return $null
|
|
}
|
|
|
|
function Install-Node {
|
|
Write-Host "Node.js not found" -Level info
|
|
Write-Host "Installing Node.js..." -Level info
|
|
|
|
# Try winget first
|
|
if (Get-Command winget -ErrorAction SilentlyContinue) {
|
|
Write-Host " Using winget..." -Level info
|
|
try {
|
|
winget install OpenJS.NodeJS.LTS --accept-package-agreements --accept-source-agreements 2>&1 | Out-Null
|
|
# Refresh PATH
|
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
|
Write-Host " Node.js installed via winget" -Level success
|
|
return $true
|
|
} catch {
|
|
Write-Host " Winget install failed: $_" -Level warn
|
|
}
|
|
}
|
|
|
|
# Try chocolatey
|
|
if (Get-Command choco -ErrorAction SilentlyContinue) {
|
|
Write-Host " Using chocolatey..." -Level info
|
|
try {
|
|
choco install nodejs-lts -y 2>&1 | Out-Null
|
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
|
Write-Host " Node.js installed via chocolatey" -Level success
|
|
return $true
|
|
} catch {
|
|
Write-Host " Chocolatey install failed: $_" -Level warn
|
|
}
|
|
}
|
|
|
|
# Try scoop
|
|
if (Get-Command scoop -ErrorAction SilentlyContinue) {
|
|
Write-Host " Using scoop..." -Level info
|
|
try {
|
|
scoop install nodejs-lts 2>&1 | Out-Null
|
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
|
Write-Host " Node.js installed via scoop" -Level success
|
|
return $true
|
|
} catch {
|
|
Write-Host " Scoop install failed: $_" -Level warn
|
|
}
|
|
}
|
|
|
|
Write-Host "Could not install Node.js automatically" -Level error
|
|
Write-Host "Please install Node.js 22+ manually from: https://nodejs.org" -Level info
|
|
return $false
|
|
}
|
|
|
|
function Ensure-Node {
|
|
$nodeVersion = Get-NodeVersion
|
|
if ($nodeVersion) {
|
|
$major = [int]($nodeVersion -split '\.')[0]
|
|
if ($major -ge 22) {
|
|
Write-Host "Node.js v$nodeVersion found" -Level success
|
|
return $true
|
|
}
|
|
Write-Host "Node.js v$nodeVersion found, but need v22+" -Level warn
|
|
}
|
|
return Install-Node
|
|
}
|
|
|
|
function Get-GitVersion {
|
|
try {
|
|
$version = git --version 2>$null
|
|
if ($version) {
|
|
return $version
|
|
}
|
|
} catch { }
|
|
return $null
|
|
}
|
|
|
|
function Install-Git {
|
|
Write-Host "Git not found" -Level info
|
|
|
|
if (Get-Command winget -ErrorAction SilentlyContinue) {
|
|
Write-Host " Installing Git via winget..." -Level info
|
|
try {
|
|
winget install Git.Git --accept-package-agreements --accept-source-agreements 2>&1 | Out-Null
|
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
|
Write-Host " Git installed" -Level success
|
|
return $true
|
|
} catch {
|
|
Write-Host " Winget install failed" -Level warn
|
|
}
|
|
}
|
|
|
|
Write-Host "Please install Git for Windows from: https://git-scm.com" -Level error
|
|
return $false
|
|
}
|
|
|
|
function Ensure-Git {
|
|
$gitVersion = Get-GitVersion
|
|
if ($gitVersion) {
|
|
Write-Host "$gitVersion found" -Level success
|
|
return $true
|
|
}
|
|
return Install-Git
|
|
}
|
|
|
|
function Install-OpenClawNpm {
|
|
param([string]$Version = "latest")
|
|
|
|
Write-Host "Installing OpenClaw (openclaw@$Version)..." -Level info
|
|
|
|
try {
|
|
# Use -ExecutionPolicy Bypass to handle restricted execution policy
|
|
npm install -g openclaw@$Version --no-fund --no-audit 2>&1
|
|
Write-Host "OpenClaw installed" -Level success
|
|
return $true
|
|
} catch {
|
|
Write-Host "npm install failed: $_" -Level error
|
|
return $false
|
|
}
|
|
}
|
|
|
|
function Install-OpenClawGit {
|
|
param([string]$RepoDir, [switch]$Update)
|
|
|
|
Write-Host "Installing OpenClaw from git..." -Level info
|
|
|
|
if (!(Test-Path $RepoDir)) {
|
|
Write-Host " Cloning repository..." -Level info
|
|
git clone https://github.com/openclaw/openclaw.git $RepoDir 2>&1
|
|
} elseif ($Update) {
|
|
Write-Host " Updating repository..." -Level info
|
|
git -C $RepoDir pull --rebase 2>&1
|
|
}
|
|
|
|
# Install pnpm if not present
|
|
if (!(Get-Command pnpm -ErrorAction SilentlyContinue)) {
|
|
Write-Host " Installing pnpm..." -Level info
|
|
npm install -g pnpm 2>&1
|
|
}
|
|
|
|
# Install dependencies
|
|
Write-Host " Installing dependencies..." -Level info
|
|
pnpm install --dir $RepoDir 2>&1
|
|
|
|
# Build
|
|
Write-Host " Building..." -Level info
|
|
pnpm --dir $RepoDir build 2>&1
|
|
|
|
# Create wrapper
|
|
$wrapperDir = "$env:USERPROFILE\.local\bin"
|
|
if (!(Test-Path $wrapperDir)) {
|
|
New-Item -ItemType Directory -Path $wrapperDir -Force | Out-Null
|
|
}
|
|
|
|
@"
|
|
@echo off
|
|
node "%~dp0..\openclaw\dist\entry.js" %*
|
|
"@ | Out-File -FilePath "$wrapperDir\openclaw.cmd" -Encoding ASCII -Force
|
|
|
|
Write-Host "OpenClaw installed" -Level success
|
|
return $true
|
|
}
|
|
|
|
function Add-ToPath {
|
|
param([string]$Path)
|
|
|
|
$currentPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
if ($currentPath -notlike "*$Path*") {
|
|
[Environment]::SetEnvironmentVariable("Path", "$currentPath;$Path", "User")
|
|
Write-Host "Added $Path to user PATH" -Level info
|
|
}
|
|
}
|
|
|
|
# Main
|
|
function Main {
|
|
Write-Banner
|
|
|
|
Write-Host "Windows detected" -Level success
|
|
|
|
# Check and handle execution policy FIRST, before any npm calls
|
|
if (!(Ensure-ExecutionPolicy)) {
|
|
Write-Host ""
|
|
Write-Host "Installation cannot continue due to execution policy restrictions" -Level error
|
|
exit 1
|
|
}
|
|
|
|
if (!(Ensure-Node)) {
|
|
exit 1
|
|
}
|
|
|
|
if ($InstallMethod -eq "git") {
|
|
if (!(Ensure-Git)) {
|
|
exit 1
|
|
}
|
|
|
|
if ($DryRun) {
|
|
Write-Host "[DRY RUN] Would install OpenClaw from git to $GitDir" -Level info
|
|
} else {
|
|
Install-OpenClawGit -RepoDir $GitDir -Update:(-not $NoGitUpdate)
|
|
}
|
|
} else {
|
|
# npm method
|
|
if (!(Ensure-Git)) {
|
|
Write-Host "Git is required for npm installs. Please install Git and try again." -Level warn
|
|
}
|
|
|
|
if ($DryRun) {
|
|
Write-Host "[DRY RUN] Would install OpenClaw via npm (tag: $Tag)" -Level info
|
|
} else {
|
|
if (!(Install-OpenClawNpm -Version $Tag)) {
|
|
exit 1
|
|
}
|
|
}
|
|
}
|
|
|
|
# Try to add npm global bin to PATH
|
|
try {
|
|
$npmPrefix = npm config get prefix 2>$null
|
|
if ($npmPrefix) {
|
|
Add-ToPath -Path "$npmPrefix"
|
|
}
|
|
} catch { }
|
|
|
|
if (!$NoOnboard -and !$DryRun) {
|
|
Write-Host ""
|
|
Write-Host "Run 'openclaw onboard' to complete setup" -Level info
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "🦞 OpenClaw installed successfully!" -Level success
|
|
}
|
|
|
|
Main
|