fix(install.ps1): drop UTF-8 BOM that breaks the irm | iex one-liner (#27397)#27419
fix(install.ps1): drop UTF-8 BOM that breaks the irm | iex one-liner (#27397)#27419xxxigm wants to merge 2 commits into
Conversation
The Windows one-line installer
irm https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.ps1 | iex
was failing on every fresh Windows 11 box with
The assignment expression is not valid. The input to an assignment
operator must be an object that is able to accept assignments, such
as a variable or a property.
at the `[string]$Branch = "main"` line of the `param()` block.
Root cause: `scripts/install.ps1` had accidentally picked up a leading
UTF-8 BOM (`EF BB BF`) at byte 0. PowerShell's *script-file* loader
strips that BOM, so `.\install.ps1` worked. But `irm | iex` decodes the
bytes into a .NET string, the BOM survives as U+FEFF at position 0,
and `[scriptblock]::Create()` does NOT strip it. With a stray U+FEFF in
front of `param(`, PowerShell stops recognising `param` as a keyword,
each line of the block parses as a bare assignment, and the whole
installer aborts before doing any work.
Fixes the issue by re-saving the file as pure ASCII (no BOM), exactly
matching the contract the in-file comment already claimed
("the file remains pure ASCII for PS 5.1 parser compatibility").
Also expands that comment into a loud "FILE ENCODING REQUIREMENT" block
at the top so a future editor save -- especially in a Windows editor
that defaults to "UTF-8 with signature" -- doesn't silently reintroduce
the regression.
Closes NousResearch#27397.
…bytes 8 regression tests that pin the on-disk byte invariants of scripts/install.ps1 so a future editor save can't silently bring back the NousResearch#27397 symptom: * TestInstallPs1ByteInvariants -- no UTF-8 BOM, no UTF-16 LE/BE BOM, pure ASCII, first line is `#` or `param`. * TestParamBlockStillPresent -- `param(` is the first executable line and the documented defaults ($Branch, $HermesHome, $InstallDir) are intact, so a future refactor doesn't drop them and reintroduce the symptom in a different shape. * TestSimulateIrmIexParsing -- byte 0 must be `#` and the first meaningful codepoint must be `#` or `p`. A surprise character there is exactly the class of bug that NousResearch#27397 hit. Verified by inverting the fix: temporarily prepending `EF BB BF` back onto scripts/install.ps1 makes 7 of 8 tests fail.
|
ddalggak review — not merge-ready due current CI, but targeted fix looks valid. Blocking first: current PR status still has the GitHub Evidence checked:
Scope assessment:
Conclusion: fix the failing test status or document it as unrelated baseline before readiness. |
0thernes
left a comment
There was a problem hiding this comment.
$u = 'https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.ps1'
$p = Join-Path $env:TEMP 'hermes-install.ps1'
Invoke-WebRequest -Uri $u -OutFile $p
powershell.exe -ExecutionPolicy Bypass -File $p
This works just fine.
|
Closing as superseded by #28169. Triage notes (high confidence): Thanks for the contribution — the underlying problem this PR addresses has been resolved by the linked PR on current main. If you believe this was closed in error, please comment and we'll reopen. (Bulk-closed during a CLI PR triage sweep.) |
What does this PR do?
Fixes the canonical Windows one-line installer
which was failing on every fresh Windows 11 box with
at the
[string]$Branch = "main"line inside theparam()block, before doing any work.Root cause
scripts/install.ps1had accidentally picked up a leading UTF-8 BOM (EF BB BF) at byte 0:.\install.ps1worked fine.irm | iexdecodes the body into a .NET string, the BOM survives asU+FEFFat position 0, and[scriptblock]::Create()does not strip it.U+FEFFin front ofparam(, PowerShell stops recognisingparamas a keyword. Each line of the block then parses as a bare assignment —[string]$Branch = "main"becomes type-cast-on-LHS = string-on-RHS, which is exactly the "invalid assignment expression" error in [Bug]: One Line Install not working #27397.The script's own comment even claimed "the file remains pure ASCII for PS 5.1 parser compatibility" — that contract was silently broken, almost certainly by an editor save defaulting to "UTF-8 with signature". The two other
.ps1files in the repo (acp_adapter/bootstrap/bootstrap_browser_tools.ps1,scripts/tests/test-install-ps1-stage-protocol.ps1) start with a plain#— only this one carried a BOM.The fix
scripts/install.ps1as pure ASCII (no BOM). After:filereportsASCII textand byte 0 is0x23(#).tests/scripts/test_install_ps1_encoding.pythat pins the byte invariants — no UTF-8 BOM, no UTF-16 BOM, pure ASCII, byte 0 is#,param(is the first executable line, and the documented defaults ($Branch,$HermesHome,$InstallDir) are intact.Related Issue
Closes #27397.
Type of Change
Changes Made
scripts/install.ps1— file re-saved as pure ASCII (no BOM); the 13-line "FILE ENCODING REQUIREMENT" block added at the top explains why and points future editors at the regression test. No behavioural code change — theparam()block, defaults, and 2138-line installer body are byte-identical to before, only the leading 3 BOM bytes were dropped and a comment block was added.tests/scripts/test_install_ps1_encoding.py— 8 new regression tests:TestInstallPs1ByteInvariants— 4 cases: no UTF-8 BOM (the exact [Bug]: One Line Install not working #27397 regression), no UTF-16 LE/BE BOM (the Set-Content default on PS 5.1, even worse foriex), pure ASCII (catches smart quotes / em dashes), first line is a comment orparam.TestParamBlockStillPresent— 2 cases:param(is the first executable line, and the documented defaults$Branch = "main",$HermesHome = "$env:LOCALAPPDATA\hermes",$InstallDir = "$env:LOCALAPPDATA\hermes\hermes-agent"are intact so a future refactor doesn't drop them and reintroduce the symptom in a different shape.TestSimulateIrmIexParsing— 2 cases: byte 0 must be#(0x23) and the first meaningful codepoint must be#orp— the class of guarantee thatirm | iexparsing relies on.How to Test
.venvis set up:python3 -m venv .venv && source .venv/bin/activate && pip install -e ".[all,dev]"UTF-8 BOM/expected '#' (0x23)messages.mainbranch):irm https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.ps1 | iexraisesThe assignment expression is not validat the[string]$Branch = "main"line.install.ps1served at the same URL: the param block parses cleanly and the installer proceeds normally.Checklist
Code
fix(install.ps1): ...,test(install.ps1): ...)scripts/run_tests.sh tests/scripts/test_install_ps1_encoding.pyand all tests passDocumentation & Housekeeping
scripts/install.ps1now carries a "FILE ENCODING REQUIREMENT" comment block at the top documenting the rule and pointing at the CI test)cli-config.yaml.exampleif I added/changed config keys — N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — N/A.\install.ps1direct invocation,pwsh7+, and Windows PS 5.1 all parse the BOM-less file identically; the regression only existed for the BOM +iex-decoded-string path. macOS / Linux don't run this file.Screenshots / Logs
Sensitivity check (BOM re-injected, then restored):