import figures from 'figures' import * as React from 'react' import { useContext } from 'react' import { useQueuedMessage } from '../../context/QueuedMessageContext.js' import { Box, Text } from '../../ink.js' import { formatBriefTimestamp } from '../../utils/formatBriefTimestamp.js' import { findThinkingTriggerPositions, getRainbowColor, isUltrathinkEnabled, } from '../../utils/thinking.js' import { MessageActionsSelectedContext } from '../messageActions.js' type Props = { text: string useBriefLayout?: boolean timestamp?: string } export function HighlightedThinkingText({ text, useBriefLayout, timestamp, }: Props): React.ReactNode { // Brief/assistant mode: chat-style "You" label instead of the ❯ highlight. // Parent drops its backgroundColor when this is true, so no grey shows // through. No manual wrap needed — Ink wraps inside the parent Box. const isQueued = useQueuedMessage()?.isQueued ?? false const isSelected = useContext(MessageActionsSelectedContext) const pointerColor = isSelected ? 'suggestion' : 'subtle' if (useBriefLayout) { const ts = timestamp ? formatBriefTimestamp(timestamp) : '' return ( You {ts ? {ts} : null} {text} ) } const triggers = isUltrathinkEnabled() ? findThinkingTriggerPositions(text) : [] if (triggers.length === 0) { return ( {figures.pointer} {text} ) } // Static rainbow (no shimmer — transcript messages don't animate) const parts: React.ReactNode[] = [] let cursor = 0 for (const t of triggers) { if (t.start > cursor) { parts.push( {text.slice(cursor, t.start)} , ) } for (let i = t.start; i < t.end; i++) { parts.push( {text[i]} , ) } cursor = t.end } if (cursor < text.length) { parts.push( {text.slice(cursor)} , ) } return ( {figures.pointer} {parts} ) }