fix(nous): force PYTHONUNBUFFERED=1 so device-code output surfaces

The sign-in sheet was stuck on the "Contacting Nous Portal…" spinner
even though hermes was running correctly. Root cause: Python
block-buffers stdout when it's a pipe instead of a TTY, and
`hermes auth add nous` enters a 15-minute polling loop after printing
the device-code block without ever calling `input()` — so nothing
flushes the buffer. Our readability handler never receives the URL +
user_code lines.

PKCE doesn't hit this because hermes calls `input("Authorization
code: ")`, which flushes stdout before blocking. Device-code has no
equivalent trigger.

Setting PYTHONUNBUFFERED=1 in the subprocess environment forces
line-buffered stdout for the duration of the flow — the device-code
block surfaces immediately, our regex extracts the URL and code, and
the sheet transitions into the waitingForApproval state as intended.

Local-only fix; remote SSH contexts get the remote's login env
untouched (the user's remote shell config owns buffering behavior
there).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alan Wizemann
2026-04-24 02:54:22 +02:00
parent 257772e2d1
commit 38226fea2c
+16 -1
View File
@@ -68,7 +68,22 @@ final class NousAuthFlow {
if !context.isRemote {
// Only enrich env locally remote ssh gets the remote login env
// naturally, and exporting our local keys into it would be wrong.
proc.environment = HermesFileService.enrichedEnvironment()
var env = HermesFileService.enrichedEnvironment()
// Python block-buffers stdout when it's a pipe (not a TTY). The
// device-code flow prints the verification URL + user code, then
// enters a ~15-minute polling loop that never hits `input()`
// so nothing flushes and our readability handler never sees the
// output. Users see the sheet spinning forever while hermes is
// actually waiting for approval.
//
// PKCE doesn't have this problem because `input("Authorization
// code: ")` flushes stdout before blocking, which is why
// OAuthFlowController works without this setting.
//
// PYTHONUNBUFFERED forces line-buffered stdout for the whole
// subprocess tiny perf cost, huge UX win for device-code.
env["PYTHONUNBUFFERED"] = "1"
proc.environment = env
}
let outPipe = Pipe()