mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-13 09:01:54 +00:00
macOS Desktop backend processes can still miss Apple Silicon Homebrew paths even after adding Hermes-managed Node and venv bins. That leaves `/codex-runtime on` unable to find a Homebrew-installed `codex` binary at `/opt/homebrew/bin/codex`. Add a small testable backend env helper that builds the dashboard subprocess environment in one place. It prepends Hermes-managed Node and venv bins, appends missing POSIX sane PATH entries individually, preserves caller precedence without duplicates, and keeps Windows PATH casing/delimiters intact. Wire both source-checkout and active-install backend descriptors through the helper, and add Node regression coverage to the desktop platform test suite.
95 lines
3.5 KiB
JavaScript
95 lines
3.5 KiB
JavaScript
const test = require('node:test')
|
|
const assert = require('node:assert/strict')
|
|
const path = require('node:path')
|
|
|
|
const {
|
|
POSIX_SANE_PATH_ENTRIES,
|
|
appendUniquePathEntries,
|
|
buildDesktopBackendEnv,
|
|
buildDesktopBackendPath,
|
|
pathEnvKey
|
|
} = require('./backend-env.cjs')
|
|
|
|
test('desktop backend PATH adds Hermes-managed bins and missing POSIX sane entries', () => {
|
|
const result = buildDesktopBackendPath({
|
|
hermesHome: '/Users/test/.hermes',
|
|
venvRoot: '/Users/test/.hermes/hermes-agent/venv',
|
|
currentPath: '/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin',
|
|
platform: 'darwin',
|
|
pathModule: path.posix
|
|
})
|
|
|
|
const entries = result.split(':')
|
|
assert.equal(entries[0], '/Users/test/.hermes/node/bin')
|
|
assert.equal(entries[1], '/Users/test/.hermes/hermes-agent/venv/bin')
|
|
assert.ok(entries.includes('/opt/homebrew/bin'), 'Apple Silicon Homebrew bin is added')
|
|
assert.ok(entries.includes('/opt/homebrew/sbin'), 'Apple Silicon Homebrew sbin is added')
|
|
assert.ok(entries.includes('/usr/local/sbin'), 'missing standard sbin is added')
|
|
|
|
for (const expected of POSIX_SANE_PATH_ENTRIES) {
|
|
assert.ok(entries.includes(expected), `${expected} should be present`)
|
|
}
|
|
})
|
|
|
|
test('desktop backend PATH preserves first occurrence and avoids duplicates', () => {
|
|
const result = buildDesktopBackendPath({
|
|
hermesHome: '/Users/test/.hermes',
|
|
venvRoot: '/Users/test/.hermes/hermes-agent/venv',
|
|
currentPath: '/opt/homebrew/bin:/usr/bin:/opt/homebrew/bin:/bin',
|
|
platform: 'darwin',
|
|
pathModule: path.posix
|
|
})
|
|
|
|
const entries = result.split(':')
|
|
assert.equal(entries.filter(entry => entry === '/opt/homebrew/bin').length, 1)
|
|
assert.ok(
|
|
entries.indexOf('/opt/homebrew/bin') < entries.indexOf('/opt/homebrew/sbin'),
|
|
'existing Homebrew bin keeps its precedence over appended missing sane entries'
|
|
)
|
|
})
|
|
|
|
test('buildDesktopBackendEnv extends PYTHONPATH and backend PATH together', () => {
|
|
const env = buildDesktopBackendEnv({
|
|
hermesHome: '/Users/test/.hermes',
|
|
pythonPathEntries: ['/repo/hermes-agent'],
|
|
venvRoot: '/Users/test/.hermes/hermes-agent/venv',
|
|
currentEnv: {
|
|
PATH: '/usr/bin:/bin',
|
|
PYTHONPATH: '/existing/pythonpath'
|
|
},
|
|
platform: 'darwin',
|
|
pathModule: path.posix
|
|
})
|
|
|
|
assert.equal(env.PYTHONPATH, '/repo/hermes-agent:/existing/pythonpath')
|
|
assert.ok(env.PATH.startsWith('/Users/test/.hermes/node/bin:/Users/test/.hermes/hermes-agent/venv/bin:'))
|
|
assert.ok(env.PATH.includes('/opt/homebrew/bin'))
|
|
})
|
|
|
|
test('Windows PATH casing and delimiter are preserved without POSIX sane entries', () => {
|
|
const env = buildDesktopBackendEnv({
|
|
hermesHome: 'C:\\Users\\test\\AppData\\Local\\hermes',
|
|
pythonPathEntries: ['C:\\repo\\hermes-agent'],
|
|
venvRoot: 'C:\\Users\\test\\AppData\\Local\\hermes\\hermes-agent\\venv',
|
|
currentEnv: {
|
|
Path: 'C:\\Windows\\System32;C:\\Windows',
|
|
PYTHONPATH: 'C:\\existing\\pythonpath'
|
|
},
|
|
platform: 'win32',
|
|
pathModule: path.win32
|
|
})
|
|
|
|
assert.equal(pathEnvKey({ Path: 'x' }, 'win32'), 'Path')
|
|
assert.equal(env.PATH, undefined)
|
|
assert.ok(env.Path.startsWith('C:\\Users\\test\\AppData\\Local\\hermes\\node\\bin;'))
|
|
assert.ok(env.Path.includes('\\venv\\Scripts;'))
|
|
assert.ok(env.Path.includes(';C:\\Windows\\System32;C:\\Windows'))
|
|
assert.equal(env.Path.includes('/opt/homebrew/bin'), false)
|
|
})
|
|
|
|
test('appendUniquePathEntries drops empty entries and keeps first occurrence', () => {
|
|
assert.equal(
|
|
appendUniquePathEntries([':/a::/b', ['/a', '/c']], { delimiter: ':' }),
|
|
'/a:/b:/c'
|
|
)
|
|
})
|