Merge pull request #55923 from NousResearch/bb/serve-headless-no-web-build

feat(cli): make hermes serve a real headless backend (no web UI build/mount, neutral ready sentinel)
This commit is contained in:
brooklyn! 2026-07-06 13:18:00 -05:00 committed by GitHub
commit 91c68bf834
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 93 additions and 16 deletions

View file

@ -1,6 +1,9 @@
const fs = require('node:fs')
const _READY_RE = /^HERMES_DASHBOARD_READY port=(\d+)/m
// `hermes serve` announces HERMES_BACKEND_READY; the legacy `hermes dashboard`
// backend announces HERMES_DASHBOARD_READY. Accept either so the desktop spawn
// works against both the headless backend and old/dashboard runtimes.
const _READY_RE = /^HERMES_(?:BACKEND|DASHBOARD)_READY port=(\d+)/m
// The announcement clock starts the instant the backend process is spawned —
// before uvicorn binds its socket. On a cold install the child must first
@ -30,8 +33,8 @@ function resolvePortAnnounceTimeoutMs(env = process.env) {
}
/**
* Watch a child process's stdout for the `HERMES_DASHBOARD_READY port=<N>`
* line that web_server.py prints after uvicorn binds its socket.
* Watch a child process's stdout for the `HERMES_(BACKEND|DASHBOARD)_READY
* port=<N>` line that web_server.py prints after uvicorn binds its socket.
*
* Returns the parsed port. Rejects if:
* - the child exits before emitting the line

View file

@ -86,6 +86,13 @@ test('resolves with the announced port', async () => {
assert.equal(await p, 54321)
})
test('resolves with a HERMES_BACKEND_READY port (headless `serve`)', async () => {
const child = makeFakeChild()
const p = waitForDashboardPort(child, 1000)
child.stdout.emit('data', 'HERMES_BACKEND_READY port=43210\n')
assert.equal(await p, 43210)
})
test('parses the port even when the line arrives split across chunks', async () => {
const child = makeFakeChild()
const p = waitForDashboardPort(child, 1000)