tags)
const ast = parse(content);
if (ast.length > 0) return ast;
// Fall back to legacy parser for old-format messages
const legacy = extractLegacyMentionTokens(content);
if (legacy.length === 0) return [{ type: 'text' as const, text: content }];
const parts: Node[] = [];
let cursor = 0;
for (const token of legacy) {
const idx = content.indexOf(token.full, cursor);
if (idx === -1) continue;
if (idx > cursor) {
parts.push({ type: 'text', text: content.slice(cursor, idx) });
}
parts.push({
type: 'mention',
mentionType: token.type as MentionMentionType,
id: '',
label: token.name,
});
cursor = idx + token.full.length;
}
if (cursor < content.length) {
parts.push({ type: 'text', text: content.slice(cursor) });
}
return parts;
}, [content]);
// Resolve ID → display name for each mention type
const resolveName = useCallback(
(type: string, id: string, label: string): string => {
if (type === 'user') {
const member = members.find((m) => m.user === id);
return member?.user_info?.username ?? member?.user ?? label;
}
if (type === 'repository') {
const repo = repos.find((r) => r.uid === id);
return repo?.repo_name ?? label;
}
if (type === 'ai') {
const cfg = aiConfigs.find((c) => c.model === id);
return cfg?.modelName ?? cfg?.model ?? label;
}
return label;
},
[members, repos, aiConfigs],
);
return (
{nodes.map((node, i) => renderNode(node, i, resolveName))}
);
});
/** Extract first mentioned user name from text */
export function extractMentionedUserUid(
text: string,
participants: Array<{ uid: string; name: string; is_ai: boolean }>,
): string | null {
const userName = extractFirstMentionName(text, 'user');
if (!userName) return null;
const user = participants.find((p) => !p.is_ai && p.name === userName);
return user ? user.uid : null;
}
/** Extract first mentioned AI name from text */
export function extractMentionedAiUid(
text: string,
participants: Array<{ uid: string; name: string; is_ai: boolean }>,
): string | null {
const aiName = extractFirstMentionName(text, 'ai');
if (!aiName) return null;
const ai = participants.find((p) => p.is_ai && p.name === aiName);
return ai ? ai.uid : null;
}