import { Fragment } from "react"; import { useTranslation } from "react-i18next"; import { CapabilityMentionToken, splitCapabilityMentionSegments, type CapabilityMentionSegment, } from "@/components/CliAppMentionText"; import { INLINE_TOKEN_HIGHLIGHT_COLOR, InlineTokenHighlight, } from "@/components/InlineTokenHighlight"; import type { CliAppInfo, McpPresetInfo, SessionMention } from "@/lib/types"; type SkillReferenceSegment = | { kind: "text"; text: string } | { kind: "skill"; text: string; name: string }; type UserMessageSegment = | CapabilityMentionSegment | { kind: "skill"; text: string; name: string }; function splitSkillReferenceSegments(value: string): SkillReferenceSegment[] { if (!value) return []; const segments: SkillReferenceSegment[] = []; const referenceRe = /\$([A-Za-z0-9_-]+)/g; let cursor = 0; let match: RegExpExecArray | null; while ((match = referenceRe.exec(value)) !== null) { const name = match[1] ?? ""; if (match.index > cursor) { segments.push({ kind: "text", text: value.slice(cursor, match.index) }); } segments.push({ kind: "skill", text: value.slice(match.index, referenceRe.lastIndex), name, }); cursor = referenceRe.lastIndex; } if (cursor < value.length) { segments.push({ kind: "text", text: value.slice(cursor) }); } return segments.length ? segments : [{ kind: "text", text: value }]; } function splitUserMessageSegments( value: string, cliApps: CliAppInfo[], mcpPresets: McpPresetInfo[], sessionMentions: SessionMention[], ): UserMessageSegment[] { const segments: UserMessageSegment[] = []; for (const segment of splitCapabilityMentionSegments( value, cliApps, mcpPresets, sessionMentions, )) { if (segment.kind === "text") { segments.push(...splitSkillReferenceSegments(segment.text)); } else { segments.push(segment); } } return segments; } export function UserMessageText({ text, cliApps, mcpPresets, sessionMentions = [], }: { text: string; cliApps: CliAppInfo[]; mcpPresets: McpPresetInfo[]; sessionMentions?: SessionMention[]; }) { const { t } = useTranslation(); const segments = splitUserMessageSegments(text, cliApps, mcpPresets, sessionMentions); return ( <> {segments.map((segment, index) => { if (segment.kind === "text") { return {segment.text}; } if (segment.kind === "skill") return ( {segment.name} ); return ( ); })} ); }