diff --git a/tui_gateway/server.py b/tui_gateway/server.py index 661b08bdb1b..7b9f286380c 100644 --- a/tui_gateway/server.py +++ b/tui_gateway/server.py @@ -1375,6 +1375,15 @@ def _probe_config_health(cfg: dict) -> str: return " ".join(warnings).strip() +def _current_profile_name() -> str: + try: + from hermes_cli.profiles import get_active_profile_name + + return get_active_profile_name() or "default" + except Exception: + return "default" + + def _session_info(agent) -> dict: reasoning_config = getattr(agent, "reasoning_config", None) reasoning_effort = "" @@ -1397,6 +1406,7 @@ def _session_info(agent) -> dict: "update_behind": None, "update_command": "", "usage": _get_usage(agent), + "profile_name": _current_profile_name(), } try: from hermes_cli import __version__, __release_date__ @@ -2154,6 +2164,7 @@ def _(rid, params: dict) -> dict: "skills": {}, "cwd": os.getenv("TERMINAL_CWD", os.getcwd()), "lazy": True, + "profile_name": _current_profile_name(), }, }, ) diff --git a/ui-tui/src/__tests__/prompt.test.ts b/ui-tui/src/__tests__/prompt.test.ts new file mode 100644 index 00000000000..7b923c79a40 --- /dev/null +++ b/ui-tui/src/__tests__/prompt.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from 'vitest' + +import { composerPromptText } from '../lib/prompt.js' + +describe('composerPromptText', () => { + it('returns shell prompt for ! commands', () => { + expect(composerPromptText('❯', 'coder', true)).toBe('$') + }) + + it('prefixes named profiles onto the normal prompt', () => { + expect(composerPromptText('❯', 'coder')).toBe('coder ❯') + }) + + it('does not prefix default or custom profiles', () => { + expect(composerPromptText('❯', 'default')).toBe('❯') + expect(composerPromptText('❯', 'custom')).toBe('❯') + expect(composerPromptText('❯')).toBe('❯') + }) +}) diff --git a/ui-tui/src/components/appLayout.tsx b/ui-tui/src/components/appLayout.tsx index 475ad237dc0..63b6c0a1b2e 100644 --- a/ui-tui/src/components/appLayout.tsx +++ b/ui-tui/src/components/appLayout.tsx @@ -16,6 +16,7 @@ import { stableComposerColumns } from '../lib/inputMetrics.js' import { PerfPane } from '../lib/perfPane.js' +import { composerPromptText } from '../lib/prompt.js' import { AgentsOverlay } from './agentsOverlay.js' import { GoodVibesHeart, StatusRule, StickyPromptTracker, TranscriptScrollbar } from './appChrome.js' @@ -170,7 +171,7 @@ const ComposerPane = memo(function ComposerPane({ const ui = useStore($uiState) const isBlocked = useStore($isBlocked) const sh = (composer.inputBuf[0] ?? composer.input).startsWith('!') - const promptText = sh ? '$' : ui.theme.brand.prompt + const promptText = composerPromptText(ui.theme.brand.prompt, ui.info?.profile_name, sh) const promptWidth = composerPromptWidth(promptText) const promptBlank = ' '.repeat(promptWidth) const inputColumns = stableComposerColumns(composer.cols, promptWidth) diff --git a/ui-tui/src/lib/prompt.ts b/ui-tui/src/lib/prompt.ts new file mode 100644 index 00000000000..15607b61362 --- /dev/null +++ b/ui-tui/src/lib/prompt.ts @@ -0,0 +1,11 @@ +export function composerPromptText(prompt: string, profileName?: null | string, shellMode = false): string { + if (shellMode) { + return '$' + } + + if (profileName && !['default', 'custom'].includes(profileName)) { + return `${profileName} ${prompt}` + } + + return prompt +} diff --git a/ui-tui/src/types.ts b/ui-tui/src/types.ts index 62f580090d2..f0651bef9c5 100644 --- a/ui-tui/src/types.ts +++ b/ui-tui/src/types.ts @@ -148,6 +148,7 @@ export interface SessionInfo { lazy?: boolean mcp_servers?: McpServerStatus[] model: string + profile_name?: string reasoning_effort?: string release_date?: string service_tier?: string