From 6fa88c19ac1dedbecd9809873b8c2cbea9ae0522 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Wed, 7 Oct 2026 13:20:50 -0500 Subject: [PATCH] fix(desktop): lint missing-profile error and move its tests to a sibling file Keeps remote-lifecycle.test.ts under its code-health line cap and clears the curly/no-useless-escape errors from check:lint. --- .../remote-lifecycle-profile-missing.test.ts | 53 +++++++++++++++++++ .../desktop/electron/remote-lifecycle.test.ts | 17 ------ apps/desktop/electron/remote-lifecycle.ts | 17 ++++-- 3 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 apps/desktop/electron/remote-lifecycle-profile-missing.test.ts diff --git a/apps/desktop/electron/remote-lifecycle-profile-missing.test.ts b/apps/desktop/electron/remote-lifecycle-profile-missing.test.ts new file mode 100644 index 0000000000..a7ca937182 --- /dev/null +++ b/apps/desktop/electron/remote-lifecycle-profile-missing.test.ts @@ -0,0 +1,53 @@ +import assert from 'node:assert/strict' + +import { test } from 'vitest' + +import { scrapeReadyPort, spawnLogPath } from './remote-lifecycle' + +const OWNERSHIP_ID = '0123456789abcdef0123456789abcdef' +const SPAWN_NONCE = '0123456789abcdef' + +function logSsh(log: string) { + return { + async exec(cmd: string) { + return cmd.startsWith('cat ') ? log : '' + } + } +} + +test('scrapeReadyPort explains a missing remote profile', async () => { + const ssh = logSsh("Error: Profile 'operator' does not exist. Create it with: hermes profile create operator\n") + + await assert.rejects( + () => + scrapeReadyPort(ssh, spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE), { + timeoutMs: 1000, + isAlive: async () => false + }), + (err: any) => { + assert.equal(err.kind, 'remote-profile-missing') + assert.equal(err.profile, 'operator') + assert.match(err.message, /remote Hermes profile 'operator' does not exist/) + assert.match(err.message, /hermes profile create operator/) + + return true + } + ) +}) + +test('scrapeReadyPort keeps the generic spawn failure for other exits', async () => { + const ssh = logSsh('Traceback (most recent call last):\nRuntimeError: boom\n') + + await assert.rejects( + () => + scrapeReadyPort(ssh, spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE), { + timeoutMs: 1000, + isAlive: async () => false + }), + (err: any) => { + assert.equal(err.kind, 'spawn-failed') + + return true + } + ) +}) diff --git a/apps/desktop/electron/remote-lifecycle.test.ts b/apps/desktop/electron/remote-lifecycle.test.ts index f97c0a6451..bdd76274b0 100644 --- a/apps/desktop/electron/remote-lifecycle.test.ts +++ b/apps/desktop/electron/remote-lifecycle.test.ts @@ -1088,23 +1088,6 @@ test('scrapeReadyPort reads only the named spawn log', async () => { assert.ok(ssh.calls.every(call => !call.includes('desktop-ssh.log'))) }) -test('scrapeReadyPort explains a missing remote profile', async () => { - const ssh = fakeSsh([[/cat/, "Error: Profile 'operator' does not exist. Create it with: hermes profile create operator\n"]]) - - await assert.rejects( - () => scrapeReadyPort(ssh, spawnLogPath(OWNERSHIP_ID, SPAWN_NONCE), { - timeoutMs: 1000, - isAlive: async () => false - }), - (err: any) => { - assert.equal(err.kind, 'remote-profile-missing') - assert.match(err.message, /remote Hermes profile 'operator' does not exist/) - assert.match(err.message, /hermes profile create operator/) - return true - } - ) -}) - test('scrapeReadyPort times out and reports a dead spawn', async () => { // never emits a READY line const ssh = fakeSsh([[/cat .*\.log/, 'still starting...']]) diff --git a/apps/desktop/electron/remote-lifecycle.ts b/apps/desktop/electron/remote-lifecycle.ts index ff773eee78..cccb658ab5 100644 --- a/apps/desktop/electron/remote-lifecycle.ts +++ b/apps/desktop/electron/remote-lifecycle.ts @@ -1218,18 +1218,25 @@ async function remoteSupportsSshOwnership(ssh, hermesPath) { } function remoteProfileMissingError(output) { - const match = String(output || '').match(/Error: Profile ['\"]([^'\"]+)['\"] does not exist\.?(?: Create it with: ([^\n]+))?/i) + const match = String(output || '').match( + /Error: Profile ['"]([^'"]+)['"] does not exist\.?(?: Create it with: ([^\n]+))?/i + ) - if (!match) return null + if (!match) { + return null + } const profile = match[1] const createCommand = match[2]?.trim() + const err: any = new Error( `The remote Hermes profile '${profile}' does not exist. ` + `Select an existing remote profile${createCommand ? ` or create it with: ${createCommand}` : '.'}` ) + err.kind = 'remote-profile-missing' err.profile = profile + return err } @@ -1250,7 +1257,11 @@ async function scrapeReadyPort(ssh, logPath, { timeoutMs = resolveReadyTimeoutMs if (isAlive && !(await isAlive())) { const cause = remoteProfileMissingError(tail) - if (cause) throw cause + + if (cause) { + throw cause + } + const err: any = new Error('Remote dashboard process exited before announcing its port.') err.kind = 'spawn-failed' throw err