From 665846445c8e44ff1acbe77f447c516aa95f79e2 Mon Sep 17 00:00:00 2001 From: "baseberry-uat[bot]" <227608112+baseberry-uat[bot]@users.noreply.github.com> Date: Wed, 5 Aug 2026 20:39:04 +0000 Subject: [PATCH] fix: preserve diagnostic context on API, WebSocket, and auth failure paths Co-authored-by: baseberry-uat[bot] <227608112+baseberry-uat[bot]@users.noreply.github.com> --- src/auth/refresh.ts | 3 ++- src/auth/resolver.ts | 8 ++++++-- src/client/http.ts | 10 +++++++--- src/client/thread-chat.ts | 8 ++++++-- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/auth/refresh.ts b/src/auth/refresh.ts index 8b004a6..3a686b6 100644 --- a/src/auth/refresh.ts +++ b/src/auth/refresh.ts @@ -30,8 +30,9 @@ export async function refreshToken( }); if (!res.ok) { + const body = await res.text().catch(() => ''); throw new CLIError( - `Token refresh failed: ${res.status}`, + `Token refresh failed: ${res.status} ${body}`.trim(), ExitCode.AUTH, 'Run `polylane auth login` to re-authenticate' ); diff --git a/src/auth/resolver.ts b/src/auth/resolver.ts index 632f57b..3f06994 100644 --- a/src/auth/resolver.ts +++ b/src/auth/resolver.ts @@ -19,8 +19,12 @@ export async function resolveCredential(config: Config): Promise { if (isTokenExpiringSoon(stored)) { try { return await refreshToken(config, stored); - } catch { - // Fall through + } catch (err) { + if (config.verbose) { + const msg = err instanceof Error ? err.message : String(err); + process.stderr.write(`Token refresh failed: ${msg} +`); + } } } else { return stored; diff --git a/src/client/http.ts b/src/client/http.ts index 85957d3..4136f3f 100644 --- a/src/client/http.ts +++ b/src/client/http.ts @@ -133,12 +133,16 @@ export async function requestJson(config: Config, opts: RequestOpts): Promise } let json: ApiEnvelope; + let bodyText = ''; try { - json = (await res.json()) as ApiEnvelope; + bodyText = await res.text(); + json = JSON.parse(bodyText) as ApiEnvelope; } catch { + const snippet = bodyText.slice(0, 500); throw new CLIError( - `Invalid JSON response from server (status ${res.status})`, - ExitCode.GENERAL + `Invalid JSON response from ${opts.method ?? 'GET'} ${opts.url} (status ${res.status}): ${snippet}`, + ExitCode.GENERAL, + `Check --domain=${config.domain} and your network` ); } diff --git a/src/client/thread-chat.ts b/src/client/thread-chat.ts index 6cf3c3d..3c303cd 100644 --- a/src/client/thread-chat.ts +++ b/src/client/thread-chat.ts @@ -227,12 +227,16 @@ export async function sendThreadMessage( rejectOnce(new CLIError(`WebSocket error: ${err.message}`, ExitCode.NETWORK)); }); - ws.on('close', () => { + ws.on('close', (code: number, reason: Buffer) => { if (!resolved) { if (blockOrder.length > 0) { finalize(); } else { - rejectOnce(new CLIError('WebSocket closed before reply', ExitCode.NETWORK)); + const reasonText = reason.toString('utf-8').trim(); + rejectOnce(new CLIError( + `WebSocket closed before reply (code ${code}${reasonText ? `, ${reasonText}` : ''})`, + ExitCode.NETWORK + )); } } });