mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-29 06:31:32 +00:00
feat(install.ps1): strip BOM, add -Commit/-Tag pin params, harden git ops
Three install.ps1 improvements pulled from the thin-installer work on
bb/gui (PR #27822) that benefit the canonical CLI install flow on main:
1. Strip UTF-8 BOM from scripts/install.ps1.
The canonical 'irm <raw URL> | iex' install flow has been broken
since commit 4279da4db re-introduced a UTF-8 BOM that PR #27224
had explicitly stripped. PowerShell 5.1's 'irm' returns the
response body as a string with the BOM surviving as a leading
\ufeff character; 'iex' then evaluates that string and the parser
chokes on the invisible character before param(), surfacing as a
cascade of 'The assignment expression is not valid' errors at
every param default value.
File body is verified pure ASCII (no character above byte 127),
so PS 5.1 with no BOM falls back to Windows-1252 decoding which
is identical to ASCII for our content. Both install paths work:
- 'irm ... | iex' (canonical one-liner)
- 'powershell -File install.ps1' (programmatic / desktop bootstrap)
2. New -Commit and -Tag string params for reproducible pinning.
Higher-precedence variants of -Branch. When set, the repository
stage clones $Branch (fast partial fetch) and then 'git checkout's
the exact ref. Precedence: Commit > Tag > Branch. Honoured by all
three code paths:
- Update path (existing valid checkout): fetch + checkout
--detach <commit|tag> instead of checkout + pull.
- Fresh clone: clone --branch $Branch, then post-clone
'git checkout --detach' to the requested ref.
- ZIP fallback: pick archive URL for the most-specific ref
(commit -> archive/<sha>.zip, tag -> archive/refs/tags/
<tag>.zip, else archive/refs/heads/<branch>.zip).
Used by the Hermes desktop's first-launch bootstrap to pin the
.exe to the exact commit it was built against, so the cloned
Hermes Agent tree always matches what the .exe was tested with.
Also enables release-bundle pinning (e.g. Microsoft Store builds
pinning to a release tag) and CI reproducibility.
3. EAP=Continue wrap around the new pin-step git invocations.
'git fetch origin <commit>' writes the routine 'From <url>' info
line to stderr. Under the script's global $ErrorActionPreference
= 'Stop' that stderr line is wrapped as an ErrorRecord and
terminates the script even though fetch+checkout actually succeed.
Same EAP=Stop + native-stderr footgun we hit during the install.ps1
hardening pass in Install-Uv, Test-Python, _Run-NpmInstall.
Wrap both the update-path fetch/checkout block AND the post-clone
pin block in $ErrorActionPreference = 'Continue' (restored in
finally). Real failures still caught by $LASTEXITCODE checks.
This commit is contained in:
parent
457fa913b8
commit
a53e8ca733
1 changed files with 79 additions and 7 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# ============================================================================
|
||||
# ============================================================================
|
||||
# Hermes Agent Installer for Windows
|
||||
# ============================================================================
|
||||
# Installation script for Windows (PowerShell).
|
||||
|
|
@ -16,6 +16,13 @@ param(
|
|||
[switch]$NoVenv,
|
||||
[switch]$SkipSetup,
|
||||
[string]$Branch = "main",
|
||||
# -Commit and -Tag are higher-precedence variants of -Branch for users
|
||||
# who need reproducible installs (desktop installer pinning, CI, release
|
||||
# bundles). When set, the repository stage clones $Branch (faster than
|
||||
# cloning the full default-branch history) and then `git checkout`s the
|
||||
# exact ref. Precedence: Commit > Tag > Branch.
|
||||
[string]$Commit = "",
|
||||
[string]$Tag = "",
|
||||
[string]$HermesHome = "$env:LOCALAPPDATA\hermes",
|
||||
[string]$InstallDir = "$env:LOCALAPPDATA\hermes\hermes-agent",
|
||||
|
||||
|
|
@ -955,14 +962,36 @@ function Install-Repository {
|
|||
if ($repoValid) {
|
||||
Write-Info "Existing installation found, updating..."
|
||||
Push-Location $InstallDir
|
||||
# Wrap the entire fetch+checkout block in EAP=Continue so git's
|
||||
# routine stderr output (e.g. 'From <url>' info lines emitted by
|
||||
# `git fetch`) doesn't terminate the script under the global
|
||||
# EAP=Stop. We rely on $LASTEXITCODE for actual failures.
|
||||
$prevEAP = $ErrorActionPreference
|
||||
$ErrorActionPreference = "Continue"
|
||||
try {
|
||||
git -c windows.appendAtomically=false fetch origin
|
||||
if ($LASTEXITCODE -ne 0) { throw "git fetch failed (exit $LASTEXITCODE)" }
|
||||
git -c windows.appendAtomically=false checkout $Branch
|
||||
if ($LASTEXITCODE -ne 0) { throw "git checkout $Branch failed (exit $LASTEXITCODE)" }
|
||||
git -c windows.appendAtomically=false pull origin $Branch
|
||||
if ($LASTEXITCODE -ne 0) { throw "git pull failed (exit $LASTEXITCODE)" }
|
||||
# Precedence: Commit > Tag > Branch. Commit and Tag check
|
||||
# out as detached HEAD intentionally -- they're meant to be
|
||||
# reproducible pins, not branches the user pulls into.
|
||||
if ($Commit) {
|
||||
# Make sure we have the commit locally (a tag-less commit
|
||||
# SHA isn't always reachable from any one branch fetch).
|
||||
git -c windows.appendAtomically=false fetch origin $Commit
|
||||
git -c windows.appendAtomically=false checkout --detach $Commit
|
||||
if ($LASTEXITCODE -ne 0) { throw "git checkout $Commit failed (exit $LASTEXITCODE)" }
|
||||
} elseif ($Tag) {
|
||||
git -c windows.appendAtomically=false fetch origin "refs/tags/${Tag}:refs/tags/${Tag}"
|
||||
git -c windows.appendAtomically=false checkout --detach "refs/tags/$Tag"
|
||||
if ($LASTEXITCODE -ne 0) { throw "git checkout tag $Tag failed (exit $LASTEXITCODE)" }
|
||||
} else {
|
||||
git -c windows.appendAtomically=false checkout $Branch
|
||||
if ($LASTEXITCODE -ne 0) { throw "git checkout $Branch failed (exit $LASTEXITCODE)" }
|
||||
git -c windows.appendAtomically=false pull origin $Branch
|
||||
if ($LASTEXITCODE -ne 0) { throw "git pull failed (exit $LASTEXITCODE)" }
|
||||
}
|
||||
} finally {
|
||||
$ErrorActionPreference = $prevEAP
|
||||
Pop-Location
|
||||
}
|
||||
$didUpdate = $true
|
||||
|
|
@ -1020,8 +1049,20 @@ function Install-Repository {
|
|||
if (Test-Path $InstallDir) { Remove-Item -Recurse -Force $InstallDir -ErrorAction SilentlyContinue }
|
||||
Write-Warn "Git clone failed -- downloading ZIP archive instead..."
|
||||
try {
|
||||
$zipUrl = "https://github.com/NousResearch/hermes-agent/archive/refs/heads/$Branch.zip"
|
||||
$zipPath = "$env:TEMP\hermes-agent-$Branch.zip"
|
||||
# Pick the ZIP URL for the most-specific ref the caller asked
|
||||
# for. GitHub supports archive URLs for commits, tags, and
|
||||
# branches; we honour Commit > Tag > Branch.
|
||||
if ($Commit) {
|
||||
$zipUrl = "https://github.com/NousResearch/hermes-agent/archive/$Commit.zip"
|
||||
$zipLabel = $Commit
|
||||
} elseif ($Tag) {
|
||||
$zipUrl = "https://github.com/NousResearch/hermes-agent/archive/refs/tags/$Tag.zip"
|
||||
$zipLabel = $Tag
|
||||
} else {
|
||||
$zipUrl = "https://github.com/NousResearch/hermes-agent/archive/refs/heads/$Branch.zip"
|
||||
$zipLabel = $Branch
|
||||
}
|
||||
$zipPath = "$env:TEMP\hermes-agent-$zipLabel.zip"
|
||||
$extractPath = "$env:TEMP\hermes-agent-extract"
|
||||
|
||||
Invoke-WebRequest -Uri $zipUrl -OutFile $zipPath -UseBasicParsing
|
||||
|
|
@ -1063,6 +1104,37 @@ function Install-Repository {
|
|||
Push-Location $InstallDir
|
||||
git -c windows.appendAtomically=false config windows.appendAtomically false 2>$null
|
||||
|
||||
# Post-clone pin: when a clone (or ZIP-fallback init) just landed us on
|
||||
# $Branch's tip, honour the higher-precedence $Commit / $Tag by checking
|
||||
# the exact ref out as a detached HEAD. Skipped for the in-place update
|
||||
# path (above) since that already routed via the same precedence.
|
||||
if (-not $didUpdate) {
|
||||
# Same EAP=Continue wrap as the update path -- git fetch's 'From <url>'
|
||||
# info line goes to stderr and would terminate the script under the
|
||||
# global EAP=Stop otherwise. We check $LASTEXITCODE for real errors.
|
||||
$prevEAP = $ErrorActionPreference
|
||||
$ErrorActionPreference = "Continue"
|
||||
try {
|
||||
if ($Commit) {
|
||||
Write-Info "Pinning to commit $Commit..."
|
||||
git -c windows.appendAtomically=false fetch origin $Commit
|
||||
git -c windows.appendAtomically=false checkout --detach $Commit
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "git checkout $Commit failed (exit $LASTEXITCODE)"
|
||||
}
|
||||
} elseif ($Tag) {
|
||||
Write-Info "Pinning to tag $Tag..."
|
||||
git -c windows.appendAtomically=false fetch origin "refs/tags/${Tag}:refs/tags/${Tag}"
|
||||
git -c windows.appendAtomically=false checkout --detach "refs/tags/$Tag"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "git checkout tag $Tag failed (exit $LASTEXITCODE)"
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
$ErrorActionPreference = $prevEAP
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure submodules are initialized and updated
|
||||
Write-Info "Initializing submodules..."
|
||||
git -c windows.appendAtomically=false submodule update --init --recursive 2>$null
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue