mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-13 14:02:16 +00:00
Route the app off its hand-rolled helpers onto lib/{text,time,format,json-format}
and the new primitives, plus assorted small tidy-ups:
- compactNumber for counts/tokens; normalize/capitalize/asText at the many
filter/label sites; shared Intl date/time formatters; row-hover + framed
editor adoption; scrollbar-gutter + padding parity on list surfaces.
- Messaging/Artifacts/Cron search hints + narrow-viewport tab dropdown;
floating-pet adopts useOnProfileSwitch; number formatting in statusbar,
command-center, agents.
- Electron: native overlay width + backend spawn tidy.
- Settings > Keys: credential fields read as plain subtext (all-unset) until
the group is focused or expanded, then take full input chrome with no
horizontal/vertical shift; inline Remove (trash) + Save mirror SearchField's
trailing-clear pattern instead of a floating hint that overlapped the card;
Esc still cancels. Drops the now-dead or/escToCancel i18n keys.
- Shared TabDropdown/ResponsiveTabs (components/ui): PageSearchShell and the
Command Center log file/level filters reuse the one narrow-width collapse.
- OverlayNav: data-driven pane nav — persistent rail on wide, a single dropdown
riding the titlebar strip on narrow; Settings and Command Center adopt it, and
the mobile dropdown carries the same section icons as the rail. Fixes narrow
vertical centering, redundant mobile section titles, gateway-status wrap, and
Panel master/detail stacking.
- OverlayIconButton is now the titlebar ghost button, matching the close X at
every size. Settings sub-view nav opens section + sub-view in one navigate so
API-keys/accounts actually open on narrow.
- Settings > Model: cube icon (was the {} namespace glyph) and a DOM-shaped
skeleton in place of the centered spinner.
- Command palette / session switcher clear the macOS traffic lights on small
screens.
- Prettier/eslint sweep across the touched files.
62 lines
2.4 KiB
JavaScript
62 lines
2.4 KiB
JavaScript
'use strict'
|
|
|
|
const test = require('node:test')
|
|
const assert = require('node:assert/strict')
|
|
const fs = require('node:fs')
|
|
const path = require('node:path')
|
|
|
|
const ELECTRON_DIR = __dirname
|
|
|
|
function readElectronFile(name) {
|
|
return fs.readFileSync(path.join(ELECTRON_DIR, name), 'utf8').replace(/\r\n/g, '\n')
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// prepareProfileDeleteRequest must return the torn-down profile name so the
|
|
// caller can skip ensureBackend for that profile (issue #52279).
|
|
// ---------------------------------------------------------------------------
|
|
|
|
test('prepareProfileDeleteRequest returns the torn-down profile name', () => {
|
|
const source = readElectronFile('main.cjs')
|
|
|
|
// Locate the function definition and its closing brace.
|
|
const fnStart = source.indexOf('async function prepareProfileDeleteRequest(')
|
|
assert.notEqual(fnStart, -1, 'prepareProfileDeleteRequest function not found')
|
|
|
|
// The function must contain "return profile" (pool and primary paths).
|
|
const fnBody = source.slice(fnStart, fnStart + 800)
|
|
const returnProfileCount = (fnBody.match(/return profile/g) || []).length
|
|
assert.ok(
|
|
returnProfileCount >= 2,
|
|
`expected at least 2 "return profile" statements (primary + pool paths), found ${returnProfileCount}`
|
|
)
|
|
|
|
// The early-exit guard must return null (not void/undefined).
|
|
assert.match(fnBody, /return null/, 'early-exit guard should return null, not undefined')
|
|
})
|
|
|
|
test('hermes:api handler routes profile-delete requests to the primary backend', () => {
|
|
const source = readElectronFile('main.cjs')
|
|
|
|
// The handler must capture prepareProfileDeleteRequest's return value.
|
|
assert.match(
|
|
source,
|
|
/const tornDownProfile = await prepareProfileDeleteRequest\(request\)/,
|
|
'handler should capture the return value of prepareProfileDeleteRequest'
|
|
)
|
|
|
|
// The handler must use the return value to skip ensureBackend for the
|
|
// torn-down profile, routing to the primary (null) instead.
|
|
assert.match(
|
|
source,
|
|
/const routeProfile = tornDownProfile \? null : profile/,
|
|
'handler should route to primary backend when a profile was just torn down'
|
|
)
|
|
|
|
// ensureBackend must be called with the conditional route profile.
|
|
assert.match(
|
|
source,
|
|
/const connection = await ensureBackend\(routeProfile\)/,
|
|
'handler should pass routeProfile (not raw profile) to ensureBackend'
|
|
)
|
|
})
|