Files
hermes-agent/apps/desktop/electron/hud-url.test.ts
T
Teknium 124aff0aa9 fix(desktop): open HUD mode on the focused conversation's profile (#82325)
* fix(desktop): open HUD mode on the focused conversation's profile

The HUD is a full app renderer that adopted the PRIMARY backend's
profile at boot, so toggling HUD mode from a conversation on any other
profile resolved the session id against the wrong backend — the lookup
missed and the HUD fell back to the default profile's last session
(#82285).

- openHud() resolves the target's owning profile (session's stamped
  owner, else the active gateway profile) and passes it through
  hermes:hud:open.
- hudUrl() carries the profile in the query string next to win=hud;
  the HUD renderer's gateway boot honors it as an override for both
  getConnection() and profile adoption, so the window dials and adopts
  the right backend from first paint.
- Retargeting a live HUD onto a session from a DIFFERENT profile
  respawns the window against that profile's backend (a renderer adopts
  its backend exactly once at boot; an in-place goto would repeat the
  wrong-backend lookup).

No profile in the URL means no override — ordinary windows and
single-profile users boot exactly as before.

* refactor(desktop): extract the HUD renderer URL so its contract is tested

hudUrl() built the query string inline in main.ts, where the part that
actually breaks — `?win=hud&profile=` must sit BEFORE the '#' or
HashRouter eats it as the route — had no coverage. Move it next to
buildSessionWindowUrl's split (pure piece out of the monolith, unit
tested) and pin the contract: flag order, profile encoding, trailing
slash on the dev server, empty profile omitted, packaged file URL.

Co-authored-by: rainbowgore <rainbowgore@users.noreply.github.com>

* refactor(desktop): resolve the HUD's target profile through the existing ladder

openHud() had its own copy of "stamped owner, else active gateway, else
default" — the same ladder rememberedSessionProfile() already owns for
the remembered-navigation key, down to sessionMatchesStoredId and the
default fallback. One resolver per policy, so the two can't drift.

---------

Co-authored-by: Brooklyn Nicholson <brooklyn.bb.nicholson@gmail.com>
Co-authored-by: rainbowgore <rainbowgore@users.noreply.github.com>
2026-08-09 09:10:59 +00:00

46 lines
1.9 KiB
TypeScript

import assert from 'node:assert/strict'
import { test } from 'vitest'
import { buildHudWindowUrl } from './hud-url'
test('buildHudWindowUrl puts win=hud before the hash route (dev server)', () => {
const url = buildHudWindowUrl('abc123', { devServer: 'http://localhost:5173' })
assert.equal(url, 'http://localhost:5173/?win=hud#/abc123')
assert.ok(url.indexOf('?win=hud') < url.indexOf('#'))
})
test('buildHudWindowUrl carries the handoff profile in the query before the hash', () => {
const url = buildHudWindowUrl('sess-1', { devServer: 'http://localhost:5173', profile: 'work' })
assert.equal(url, 'http://localhost:5173/?win=hud&profile=work#/sess-1')
assert.ok(url.indexOf('profile=work') < url.indexOf('#'))
})
test('buildHudWindowUrl encodes the profile and the session id', () => {
const url = buildHudWindowUrl('a b/c', { devServer: 'http://localhost:5173', profile: 'my profile' })
assert.equal(url, 'http://localhost:5173/?win=hud&profile=my%20profile#/a%20b%2Fc')
})
test('buildHudWindowUrl avoids a double slash when the dev server has a trailing slash', () => {
const url = buildHudWindowUrl('abc', { devServer: 'http://localhost:5173/', profile: 'work' })
assert.equal(url, 'http://localhost:5173/?win=hud&profile=work#/abc')
})
test('buildHudWindowUrl omits an empty profile — no override, legacy boot', () => {
assert.equal(
buildHudWindowUrl('abc', { devServer: 'http://localhost:5173', profile: ' ' }),
'http://localhost:5173/?win=hud#/abc'
)
assert.equal(buildHudWindowUrl(null, { devServer: 'http://localhost:5173' }), 'http://localhost:5173/?win=hud#/')
})
test('buildHudWindowUrl builds a packaged file URL with the flags before the hash', () => {
const url = buildHudWindowUrl('abc', { profile: 'coder', rendererIndexPath: '/opt/app/index.html' })
assert.match(url, /^file:\/\/.*index\.html\?win=hud&profile=coder#\/abc$/)
})