mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-09 13:21:42 +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.
126 lines
3.4 KiB
TypeScript
126 lines
3.4 KiB
TypeScript
import { normalize } from '@/lib/text'
|
|
|
|
const SOURCE_LABELS: Record<string, string> = {
|
|
api_server: 'API',
|
|
bluebubbles: 'iMessage',
|
|
cli: 'CLI',
|
|
codex: 'Codex',
|
|
desktop: 'Desktop',
|
|
discord: 'Discord',
|
|
email: 'Email',
|
|
gateway: 'Gateway',
|
|
local: 'Local',
|
|
matrix: 'Matrix',
|
|
mattermost: 'Mattermost',
|
|
qqbot: 'QQ',
|
|
signal: 'Signal',
|
|
slack: 'Slack',
|
|
sms: 'SMS',
|
|
telegram: 'Telegram',
|
|
tui: 'TUI',
|
|
webhook: 'Webhook',
|
|
weixin: 'WeChat',
|
|
whatsapp: 'WhatsApp',
|
|
yuanbao: 'Yuanbao'
|
|
}
|
|
|
|
const SOURCE_ALIASES: Record<string, string[]> = {
|
|
bluebubbles: ['apple messages', 'imessage'],
|
|
cli: ['terminal'],
|
|
desktop: ['app', 'gui'],
|
|
local: ['machine'],
|
|
qqbot: ['qq'],
|
|
telegram: ['tg'],
|
|
tui: ['terminal'],
|
|
weixin: ['wechat'],
|
|
whatsapp: ['wa']
|
|
}
|
|
|
|
// Sources that run on the local machine rather than an external messaging
|
|
// platform. A handoff *from* one of these isn't a platform origin worth a badge.
|
|
// Exported so the recents fetch can keep these in the main list while the
|
|
// messaging fetch excludes them.
|
|
export const LOCAL_SESSION_SOURCE_IDS = ['cli', 'codex', 'desktop', 'gateway', 'local', 'tui']
|
|
const LOCAL_SOURCE_IDS = new Set(LOCAL_SESSION_SOURCE_IDS)
|
|
|
|
// External messaging platforms that each get their own self-managed sidebar
|
|
// section (fetched separately from local recents). Mirrors the gateway platform
|
|
// adapters; keep in sync with PLATFORM_ICONS in app/messaging/platform-icon.tsx.
|
|
export const MESSAGING_SESSION_SOURCE_IDS = [
|
|
'telegram',
|
|
'discord',
|
|
'slack',
|
|
'mattermost',
|
|
'matrix',
|
|
'signal',
|
|
'whatsapp',
|
|
'bluebubbles',
|
|
'homeassistant',
|
|
'email',
|
|
'sms',
|
|
'webhook',
|
|
'api_server',
|
|
'weixin',
|
|
'wecom',
|
|
'qqbot',
|
|
'yuanbao',
|
|
'dingtalk',
|
|
'feishu'
|
|
]
|
|
const MESSAGING_SOURCE_IDS = new Set(MESSAGING_SESSION_SOURCE_IDS)
|
|
|
|
/** True when a source id is an external messaging platform (gets its own
|
|
* sidebar section) rather than a local/CLI/desktop session. */
|
|
export function isMessagingSource(source: null | string | undefined): boolean {
|
|
const id = normalizeSessionSource(source)
|
|
|
|
return id != null && MESSAGING_SOURCE_IDS.has(id)
|
|
}
|
|
|
|
export function normalizeSessionSource(source: null | string | undefined): string | null {
|
|
return normalize(source) || null
|
|
}
|
|
|
|
/**
|
|
* Resolve the origin messaging platform for a handed-off session. Returns the
|
|
* normalized platform id (e.g. 'telegram') when the session completed a handoff
|
|
* from a real messaging platform, otherwise null. After a handoff the live
|
|
* source is local, so this is what drives the row's origin-platform badge.
|
|
*/
|
|
export function handoffOriginSource(
|
|
handoffState: null | string | undefined,
|
|
handoffPlatform: null | string | undefined
|
|
): string | null {
|
|
if (handoffState !== 'completed') {
|
|
return null
|
|
}
|
|
|
|
const id = normalizeSessionSource(handoffPlatform)
|
|
|
|
if (!id || LOCAL_SOURCE_IDS.has(id)) {
|
|
return null
|
|
}
|
|
|
|
return id
|
|
}
|
|
|
|
export function sessionSourceLabel(source: null | string | undefined): string | null {
|
|
const id = normalizeSessionSource(source)
|
|
|
|
if (!id) {
|
|
return null
|
|
}
|
|
|
|
return SOURCE_LABELS[id] || id.replace(/[_-]+/g, ' ').replace(/\b\w/g, char => char.toUpperCase())
|
|
}
|
|
|
|
export function sessionSourceSearchTerms(source: null | string | undefined): string[] {
|
|
const id = normalizeSessionSource(source)
|
|
const label = sessionSourceLabel(id)
|
|
|
|
if (!id) {
|
|
return []
|
|
}
|
|
|
|
return [id, label ?? '', ...(SOURCE_ALIASES[id] ?? [])].filter(Boolean)
|
|
}
|