Files
orca/src/shared/terminal-title-display.ts
T
Jinjing 2af8fb886f Collapse Grok rotating working titles to stable label (#7863)
Grok Build's working OSC titles interpolate a rotating status or tool
phrase between the spinner and its name, causing tab and sidebar
titles to fluctuate rapidly. Collapse these working frames to a stable
"⠋ Grok" label, while leaving idle and session titles untouched.
2026-07-08 18:57:07 -07:00

109 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
AGY_AGENT_NAME_RE,
DROID_AGENT_NAME_RE,
HERMES_AGENT_NAME_RE,
titleHasAnyLegacyAgentName
} from './agent-name-token-match'
import {
GEMINI_IDLE,
GEMINI_PERMISSION,
GEMINI_SILENT_WORKING,
GEMINI_WORKING,
isGeminiTerminalTitle,
isGrokRotatingWorkingTitle,
isPiAgentTitle
} from './terminal-title-agent-type'
import {
detectAgentStatusFromTitle,
STRONG_WORKING_KEYWORDS_RE_GLOBAL
} from './terminal-title-status'
function containsAgentName(title: string): boolean {
return (
titleHasAnyLegacyAgentName(title) ||
AGY_AGENT_NAME_RE.test(title) ||
DROID_AGENT_NAME_RE.test(title) ||
HERMES_AGENT_NAME_RE.test(title)
)
}
/**
* Strip working-status indicators from a title so that
* `detectAgentStatusFromTitle` will no longer return 'working'.
* Used to clear stale titles when an agent exits without resetting its title.
*/
export function clearWorkingIndicators(title: string): string {
let cleaned = title
// Gemini working symbols
cleaned = cleaned.replace(GEMINI_WORKING, '')
cleaned = cleaned.replace(GEMINI_SILENT_WORKING, '')
// Braille spinner characters (U+2800–U+28FF)
// eslint-disable-next-line no-control-regex -- intentional unicode range
cleaned = cleaned.replace(/[\u2800-\u28FF]/g, '')
// Claude Code ". " working prefix
if (cleaned.startsWith('. ')) {
cleaned = cleaned.slice(2)
}
// Strip working keywords that detectAgentStatusFromTitle would pick up
// when the title also contains an agent name.
if (containsAgentName(cleaned)) {
cleaned = cleaned.replace(STRONG_WORKING_KEYWORDS_RE_GLOBAL, '')
}
// Collapse whitespace after removals
cleaned = cleaned.replace(/\s{2,}/g, ' ').trim()
return cleaned || title
}
/**
* Normalize high-churn agent titles into stable display labels before storing
* them in app state. Gemini CLI can emit per-keystroke title updates, which
* otherwise causes broad rerenders and visible flashing.
*/
export function normalizeTerminalTitle(title: string): string {
if (!title) {
return title
}
if (isGeminiTerminalTitle(title)) {
const status = detectAgentStatusFromTitle(title)
if (status === 'permission') {
return `${GEMINI_PERMISSION} Gemini CLI`
}
if (status === 'working') {
return `${GEMINI_WORKING} Gemini CLI`
}
if (status === 'idle') {
return `${GEMINI_IDLE} Gemini CLI`
}
}
// Why: Pi's titlebar extension animates every 80ms with different braille
// frames. Collapsing those frames into one stable label avoids renderer
// churn while preserving the working/idle transition Orca keys off.
if (isPiAgentTitle(title)) {
const status = detectAgentStatusFromTitle(title)
if (status === 'working') {
return '\u280b Pi'
}
if (status === 'idle') {
return 'Pi'
}
}
// Why: Grok Build interpolates a rotating status/tool phrase between the
// spinner and its name, so its working frames change the title many times per
// turn. Collapse them to one stable label; idle/session titles carry no
// spinner and pass through, so the meaningful final title still shows.
if (isGrokRotatingWorkingTitle(title)) {
return '\u280b Grok'
}
return title
}