Merge branch 'main' into bb/gui
This commit is contained in:
+160
-2
@@ -1,4 +1,4 @@
|
||||
# ============================================================================
|
||||
# ============================================================================
|
||||
# Hermes Agent Installer for Windows
|
||||
# ============================================================================
|
||||
# Installation script for Windows (PowerShell).
|
||||
@@ -35,7 +35,11 @@ param(
|
||||
[string]$Stage,
|
||||
[switch]$ProtocolVersion,
|
||||
[switch]$NonInteractive,
|
||||
[switch]$Json
|
||||
[switch]$Json,
|
||||
|
||||
# --- Ensure mode (dep_ensure.py entry point) ---
|
||||
[string]$Ensure = "",
|
||||
[switch]$PostInstall
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
@@ -115,6 +119,105 @@ function Write-Err {
|
||||
Write-Host "[X] $Message" -ForegroundColor Red
|
||||
}
|
||||
|
||||
# --- Ensure-mode helpers ---
|
||||
|
||||
function Resolve-NpmCmd {
|
||||
$npmCmd = Get-Command npm -ErrorAction SilentlyContinue
|
||||
if (-not $npmCmd) { return $null }
|
||||
$npmExe = $npmCmd.Source
|
||||
if ($npmExe -like "*.ps1") {
|
||||
$npmCmdSibling = Join-Path (Split-Path $npmExe -Parent) "npm.cmd"
|
||||
if (Test-Path $npmCmdSibling) { return $npmCmdSibling }
|
||||
}
|
||||
return $npmExe
|
||||
}
|
||||
|
||||
function Find-SystemBrowser {
|
||||
$candidates = @(
|
||||
"${env:ProgramFiles}\Google\Chrome\Application\chrome.exe",
|
||||
"${env:ProgramFiles(x86)}\Google\Chrome\Application\chrome.exe",
|
||||
"${env:LOCALAPPDATA}\Google\Chrome\Application\chrome.exe",
|
||||
"${env:ProgramFiles}\Microsoft\Edge\Application\msedge.exe",
|
||||
"${env:ProgramFiles(x86)}\Microsoft\Edge\Application\msedge.exe",
|
||||
"${env:ProgramFiles}\Chromium\Application\chrome.exe",
|
||||
"${env:LOCALAPPDATA}\Chromium\Application\chrome.exe"
|
||||
)
|
||||
foreach ($p in $candidates) {
|
||||
if (Test-Path $p) { return $p }
|
||||
}
|
||||
return $null
|
||||
}
|
||||
|
||||
function Write-BrowserEnv {
|
||||
param([string]$BrowserPath)
|
||||
if (-not (Test-Path $HermesHome)) {
|
||||
New-Item -ItemType Directory -Force -Path $HermesHome | Out-Null
|
||||
}
|
||||
$envFile = Join-Path $HermesHome ".env"
|
||||
if (-not (Test-Path $envFile)) {
|
||||
Set-Content -Path $envFile -Value "AGENT_BROWSER_EXECUTABLE_PATH=$BrowserPath" -Encoding UTF8
|
||||
return
|
||||
}
|
||||
$content = Get-Content $envFile -Raw -ErrorAction SilentlyContinue
|
||||
if ($content -and $content -match "AGENT_BROWSER_EXECUTABLE_PATH=") { return }
|
||||
Add-Content -Path $envFile -Value "AGENT_BROWSER_EXECUTABLE_PATH=$BrowserPath" -Encoding UTF8
|
||||
}
|
||||
|
||||
function Install-AgentBrowser {
|
||||
param([switch]$SkipChromium)
|
||||
$npm = Resolve-NpmCmd
|
||||
if (-not $npm) {
|
||||
Write-Err "npm not found -- install Node.js first"
|
||||
throw "npm not found"
|
||||
}
|
||||
|
||||
Write-Info "Installing agent-browser via npm -g --prefix..."
|
||||
$prefixDir = Join-Path $HermesHome "node"
|
||||
if (-not (Test-Path $prefixDir)) {
|
||||
New-Item -ItemType Directory -Path $prefixDir -Force | Out-Null
|
||||
}
|
||||
$npmLog = [System.IO.Path]::GetTempFileName()
|
||||
$prevEAP = $ErrorActionPreference
|
||||
$ErrorActionPreference = "Continue"
|
||||
& $npm install -g --prefix $prefixDir --silent --ignore-scripts "agent-browser@^0.26.0" "@askjo/camofox-browser@^1.5.2" 2>&1 | Tee-Object -FilePath $npmLog | Out-Null
|
||||
$npmExit = $LASTEXITCODE
|
||||
$ErrorActionPreference = $prevEAP
|
||||
if ($npmExit -ne 0) {
|
||||
$npmDetail = Get-Content $npmLog -Raw -ErrorAction SilentlyContinue
|
||||
Remove-Item $npmLog -Force -ErrorAction SilentlyContinue
|
||||
Write-Err "npm install -g failed (exit $npmExit): $npmDetail"
|
||||
throw "npm install failed"
|
||||
}
|
||||
Remove-Item $npmLog -Force -ErrorAction SilentlyContinue
|
||||
|
||||
if (-not $SkipChromium) {
|
||||
$sysBrowser = Find-SystemBrowser
|
||||
if ($sysBrowser) {
|
||||
Write-BrowserEnv -BrowserPath $sysBrowser
|
||||
Write-Info "System browser detected -- skipping Chromium download"
|
||||
} else {
|
||||
$abExe = Join-Path $prefixDir "agent-browser.cmd"
|
||||
if (Test-Path $abExe) {
|
||||
Write-Info "Installing Chromium via agent-browser install..."
|
||||
$abLog = [System.IO.Path]::GetTempFileName()
|
||||
$prevEAP = $ErrorActionPreference
|
||||
$ErrorActionPreference = "Continue"
|
||||
& $abExe install 2>&1 | Tee-Object -FilePath $abLog | Out-Null
|
||||
$abExit = $LASTEXITCODE
|
||||
$ErrorActionPreference = $prevEAP
|
||||
if ($abExit -ne 0) {
|
||||
$abDetail = Get-Content $abLog -Raw -ErrorAction SilentlyContinue
|
||||
Write-Warn "Chromium install failed (exit $abExit): $abDetail"
|
||||
}
|
||||
Remove-Item $abLog -Force -ErrorAction SilentlyContinue
|
||||
} else {
|
||||
Write-Warn "agent-browser.cmd not found at $abExe"
|
||||
}
|
||||
}
|
||||
}
|
||||
Write-Success "Agent-browser ready"
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Dependency checks
|
||||
# ============================================================================
|
||||
@@ -2115,6 +2218,48 @@ function Invoke-AllStages {
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-EnsureMode {
|
||||
param([string]$Deps)
|
||||
$depList = $Deps -split ","
|
||||
foreach ($dep in $depList) {
|
||||
$dep = $dep.Trim()
|
||||
switch ($dep) {
|
||||
"node" {
|
||||
[void](Test-Node)
|
||||
if (-not $script:HasNode) {
|
||||
Write-Err "Node.js could not be installed"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
"browser" {
|
||||
[void](Test-Node)
|
||||
if ($script:HasNode) {
|
||||
Install-AgentBrowser
|
||||
} else {
|
||||
Write-Err "Node.js is required for browser tools but could not be installed"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
"ripgrep" {
|
||||
Write-Info "ripgrep: install manually on Windows (scoop install ripgrep)"
|
||||
}
|
||||
"ffmpeg" {
|
||||
Write-Info "ffmpeg: install manually on Windows (scoop install ffmpeg)"
|
||||
}
|
||||
default {
|
||||
Write-Err "Unknown dependency: $dep"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Invoke-PostInstallMode {
|
||||
Write-Info "Running post-install setup..."
|
||||
Invoke-EnsureMode -Deps "node,browser"
|
||||
Write-Info "Post-install complete"
|
||||
}
|
||||
|
||||
function Main {
|
||||
Write-Banner
|
||||
Invoke-AllStages
|
||||
@@ -2134,6 +2279,19 @@ function Main {
|
||||
# structured JSON error frame instead of a bare exception.
|
||||
|
||||
try {
|
||||
if ($Ensure -ne "") {
|
||||
if ($PSBoundParameters.ContainsKey("Stage")) {
|
||||
Write-Err "Cannot use -Ensure and -Stage simultaneously"
|
||||
exit 1
|
||||
}
|
||||
Invoke-EnsureMode -Deps $Ensure
|
||||
exit 0
|
||||
}
|
||||
if ($PostInstall) {
|
||||
Invoke-PostInstallMode
|
||||
exit 0
|
||||
}
|
||||
|
||||
if ($ProtocolVersion) {
|
||||
Write-Output $InstallStageProtocolVersion
|
||||
exit 0
|
||||
|
||||
+88
-24
@@ -1512,6 +1512,17 @@ find_system_browser() {
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
for app in \
|
||||
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
|
||||
"/Applications/Chromium.app/Contents/MacOS/Chromium"; do
|
||||
if [ -x "$app" ]; then
|
||||
echo "$app"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
@@ -1534,10 +1545,15 @@ configure_browser_env_from_system_browser() {
|
||||
browser_path="$(find_system_browser 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
if [ -z "$browser_path" ] || [ ! -f "$env_file" ]; then
|
||||
if [ -z "$browser_path" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p "$HERMES_HOME"
|
||||
if [ ! -f "$env_file" ]; then
|
||||
touch "$env_file"
|
||||
fi
|
||||
|
||||
if grep -q '^AGENT_BROWSER_EXECUTABLE_PATH=' "$env_file" 2>/dev/null; then
|
||||
log_info "AGENT_BROWSER_EXECUTABLE_PATH already configured"
|
||||
return 0
|
||||
@@ -1888,6 +1904,73 @@ print_success() {
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_browser() {
|
||||
if ! command -v node >/dev/null 2>&1; then
|
||||
local node_bin="$HERMES_HOME/node/bin/node"
|
||||
if [ -x "$node_bin" ]; then
|
||||
export PATH="$HERMES_HOME/node/bin:$PATH"
|
||||
else
|
||||
log_error "Node.js not found. Run with --ensure node first."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
local npm_bin
|
||||
npm_bin="$(command -v npm 2>/dev/null || echo "$HERMES_HOME/node/bin/npm")"
|
||||
if [ ! -x "$npm_bin" ]; then
|
||||
log_error "npm not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Installing agent-browser..."
|
||||
local log_file
|
||||
log_file="$(mktemp)"
|
||||
if ! "$npm_bin" install -g --prefix "$HERMES_HOME/node" --silent --ignore-scripts \
|
||||
"agent-browser@^0.26.0" \
|
||||
"@askjo/camofox-browser@^1.5.2" \
|
||||
>"$log_file" 2>&1; then
|
||||
log_error "npm install failed:"
|
||||
cat "$log_file" >&2
|
||||
rm -f "$log_file"
|
||||
return 1
|
||||
fi
|
||||
rm -f "$log_file"
|
||||
export PATH="$HERMES_HOME/node/bin:$PATH"
|
||||
|
||||
local sys_browser
|
||||
sys_browser="$(find_system_browser 2>/dev/null || true)"
|
||||
if [ -n "$sys_browser" ]; then
|
||||
configure_browser_env_from_system_browser "$sys_browser"
|
||||
log_info "System browser detected -- skipping Chromium download"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log_info "Installing Chromium via agent-browser install..."
|
||||
local ab_bin="$HERMES_HOME/node/bin/agent-browser"
|
||||
if [ -x "$ab_bin" ]; then
|
||||
"$ab_bin" install 2>/dev/null || {
|
||||
log_warn "Chromium install failed. Browser tools may not work without a system browser."
|
||||
|
||||
# OS-specific hints (detect_os sets $DISTRO)
|
||||
case "${DISTRO:-unknown}" in
|
||||
ubuntu|debian)
|
||||
log_info "Try: sudo apt-get install -y chromium-browser"
|
||||
;;
|
||||
arch)
|
||||
log_info "Try: sudo pacman -S chromium"
|
||||
;;
|
||||
fedora|rhel|centos)
|
||||
log_info "Try: sudo dnf install -y chromium"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
else
|
||||
log_warn "agent-browser not found at $ab_bin"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
ensure_mode() {
|
||||
detect_os
|
||||
|
||||
@@ -1901,19 +1984,7 @@ ensure_mode() {
|
||||
browser)
|
||||
check_node
|
||||
if [ "$HAS_NODE" = true ]; then
|
||||
DETECTED_BROWSER_EXECUTABLE="$(find_system_browser 2>/dev/null || true)"
|
||||
if [ -z "$DETECTED_BROWSER_EXECUTABLE" ]; then
|
||||
log_info "Installing agent-browser + Chromium..."
|
||||
npm_bin="$(command -v npm 2>/dev/null || echo "")"
|
||||
if [ -n "$npm_bin" ]; then
|
||||
local agent_browser_dir="$HERMES_HOME/node_modules"
|
||||
mkdir -p "$agent_browser_dir"
|
||||
"$npm_bin" install --prefix "$HERMES_HOME" agent-browser 2>/dev/null || true
|
||||
npx playwright install chromium 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
log_success "System browser found: $DETECTED_BROWSER_EXECUTABLE"
|
||||
fi
|
||||
ensure_browser
|
||||
fi
|
||||
;;
|
||||
ripgrep)
|
||||
@@ -1948,16 +2019,7 @@ postinstall_mode() {
|
||||
install_system_packages
|
||||
|
||||
if [ "$HAS_NODE" = true ] && [ "$SKIP_BROWSER" = false ]; then
|
||||
DETECTED_BROWSER_EXECUTABLE="$(find_system_browser 2>/dev/null || true)"
|
||||
if [ -z "$DETECTED_BROWSER_EXECUTABLE" ]; then
|
||||
log_info "Installing browser engine..."
|
||||
npm_bin="$(command -v npm 2>/dev/null || echo "")"
|
||||
if [ -n "$npm_bin" ]; then
|
||||
npx playwright install chromium 2>/dev/null || true
|
||||
fi
|
||||
else
|
||||
log_success "System browser found: $DETECTED_BROWSER_EXECUTABLE"
|
||||
fi
|
||||
ensure_browser
|
||||
fi
|
||||
|
||||
HERMES_CMD="$(command -v hermes 2>/dev/null || echo "")"
|
||||
@@ -1996,6 +2058,8 @@ main() {
|
||||
maybe_start_gateway
|
||||
|
||||
print_success
|
||||
|
||||
echo "git" > "$HERMES_HOME/.install_method"
|
||||
}
|
||||
|
||||
if [ -n "$ENSURE_DEPS" ]; then
|
||||
|
||||
Reference in New Issue
Block a user