mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-01 12:02:05 +00:00
Two Windows-only desktop boot bugs that caused spurious reinstall/repair loops: 1. findOnPath() searched the empty extension BEFORE PATHEXT, so an extensionless Git-Bash `hermes` shim shadowed the real hermes.cmd/.exe. The shim then failed the shell:false --version probe and the resolver fell through to bootstrap/repair even though a working CLI was on PATH. Fix: try PATHEXT extensions first, keep the empty entry LAST so callers that already include the extension (py.exe, pwsh.exe) still resolve. 2. handOffWindowsBootstrapRecovery() chose the destructive --repair over the gentle --update by checking only venv\Scripts\hermes.exe -- the setuptools console-script shim, written at the END of venv setup and absent in interrupted/quarantined states. Fix: take --update when ANY real-install signal is present (venv python, the shim, or .hermes-bootstrap-complete). Adds windows-hermes-resolution.test.cjs (source-assertion pattern, wired into test:desktop:platforms) guarding both regressions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
67 lines
2.6 KiB
JavaScript
67 lines
2.6 KiB
JavaScript
'use strict'
|
|
|
|
// Regression guards for Windows `hermes` resolution in main.cjs.
|
|
//
|
|
// main.cjs has no module.exports, so these follow the repo's source-assertion
|
|
// test pattern (see windows-child-process.test.cjs). They pin the two Windows
|
|
// resolution bugs that caused desktop reinstall loops:
|
|
// 1. findOnPath() tried the empty extension FIRST, so an extensionless
|
|
// Git-Bash `hermes` shim shadowed the real hermes.cmd/hermes.exe; the
|
|
// shim then failed the --version probe and the desktop fell through to a
|
|
// spurious bootstrap/repair.
|
|
// 2. handOffWindowsBootstrapRecovery() chose --update vs the destructive
|
|
// --repair by checking ONLY venv\Scripts\hermes.exe (the console-script
|
|
// shim, written at the END of venv setup and absent in interrupted
|
|
// states), so it escalated to a full venv recreate even on healthy
|
|
// installs.
|
|
|
|
const test = require('node:test')
|
|
const assert = require('node:assert/strict')
|
|
const fs = require('node:fs')
|
|
const path = require('node:path')
|
|
|
|
function readMain() {
|
|
return fs.readFileSync(path.join(__dirname, 'main.cjs'), 'utf8').replace(/\r\n/g, '\n')
|
|
}
|
|
|
|
test('findOnPath tries PATHEXT extensions before the bare (empty) name on Windows', () => {
|
|
const source = readMain()
|
|
// Fixed order: PATHEXT first, empty string LAST.
|
|
assert.match(
|
|
source,
|
|
/\(process\.env\.PATHEXT \|\| '\.COM;\.EXE;\.BAT;\.CMD'\)\.split\(';'\)\.filter\(Boolean\), ''\]/,
|
|
'extensions array must end with the empty string, not start with it'
|
|
)
|
|
// The buggy empty-first order must not return.
|
|
assert.doesNotMatch(
|
|
source,
|
|
/\['', \.\.\.\(process\.env\.PATHEXT/,
|
|
'empty-extension-first order regressed: an extensionless shim can shadow hermes.cmd/.exe'
|
|
)
|
|
})
|
|
|
|
test('Windows bootstrap recovery chooses --update when any real-install signal is present', () => {
|
|
const source = readMain()
|
|
assert.match(source, /const haveRealInstall =/, 'recovery must compute haveRealInstall')
|
|
assert.match(
|
|
source,
|
|
/fileExists\(venvPython\)/,
|
|
'recovery must accept the venv interpreter as a real-install signal'
|
|
)
|
|
assert.match(
|
|
source,
|
|
/\.hermes-bootstrap-complete/,
|
|
'recovery must accept the bootstrap-complete marker as a real-install signal'
|
|
)
|
|
assert.match(
|
|
source,
|
|
/updaterArgs = haveRealInstall \? \['--update'/,
|
|
'updaterArgs must gate on haveRealInstall'
|
|
)
|
|
// The old too-narrow check (only venv\Scripts\hermes.exe) must not return.
|
|
assert.doesNotMatch(
|
|
source,
|
|
/updaterArgs = fileExists\(venvHermes\) \?/,
|
|
'recovery regressed to gating only on the hermes.exe shim, which forces destructive --repair'
|
|
)
|
|
})
|