Skip to content

Commit ab2c3a0

Browse files
committed
feat: add review comment icons with severity-based coloring
Review comment MCP tools (review_comment, update_review_comment, list_review_comments) now show a MessageSquareText icon instead of the generic plug icon. Icon color reflects the comment severity extracted from the tool input JSON: - blocker → rose, issue → orange, suggestion → blue, info → muted
1 parent 1cc1c26 commit ab2c3a0

1 file changed

Lines changed: 54 additions & 3 deletions

File tree

apps/web/src/components/chat/MessagesTimeline.tsx

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ import {
2828
GlobeIcon,
2929
HammerIcon,
3030
Loader2Icon,
31+
ListIcon,
3132
type LucideIcon,
33+
MessageSquareTextIcon,
3234
PlugIcon,
3335
SearchIcon,
3436
SquarePenIcon,
@@ -839,7 +841,53 @@ function workEntryPreview(
839841
: `${shortenToolSummary(firstPath)} +${workEntry.changedFiles!.length - 1} more`;
840842
}
841843

844+
/** Check if a tool name refers to a review comment MCP tool. */
845+
function isReviewCommentTool(toolName?: string): boolean {
846+
if (!toolName) return false;
847+
const lower = toolName.toLowerCase();
848+
return lower.includes("review_comment") || lower.includes("review-comment");
849+
}
850+
851+
/** Extract review comment severity from the detail/command JSON preview. */
852+
function extractReviewSeverity(
853+
workEntry: Pick<TimelineWorkEntry, "detail" | "command">,
854+
): "info" | "suggestion" | "issue" | "blocker" | null {
855+
const text = workEntry.detail || workEntry.command || "";
856+
const match = text.match(/"severity"\s*:\s*"(info|suggestion|issue|blocker)"/);
857+
return (match?.[1] as "info" | "suggestion" | "issue" | "blocker") ?? null;
858+
}
859+
860+
/** Severity-based color class for review comment icons. */
861+
function reviewSeverityClass(severity: "info" | "suggestion" | "issue" | "blocker" | null): string {
862+
switch (severity) {
863+
case "blocker":
864+
return "text-rose-400";
865+
case "issue":
866+
return "text-orange-400";
867+
case "suggestion":
868+
return "text-blue-400";
869+
case "info":
870+
return "text-muted-foreground/60";
871+
default:
872+
return "text-muted-foreground/50";
873+
}
874+
}
875+
876+
function reviewCommentIcon(
877+
toolName?: string,
878+
): { icon: LucideIcon; isReview: true } | { isReview: false } {
879+
if (!isReviewCommentTool(toolName)) return { isReview: false };
880+
const lower = toolName!.toLowerCase();
881+
if (lower.includes("list")) return { icon: ListIcon, isReview: true };
882+
if (lower.includes("update")) return { icon: MessageSquareTextIcon, isReview: true };
883+
return { icon: MessageSquareTextIcon, isReview: true };
884+
}
885+
842886
function workEntryIcon(workEntry: TimelineWorkEntry): LucideIcon {
887+
// Review comment MCP tools get a dedicated icon
888+
const review = reviewCommentIcon(workEntry.toolName);
889+
if (review.isReview) return review.icon;
890+
843891
// Match by tool name first for precise icons
844892
switch (workEntry.toolName) {
845893
case "Bash":
@@ -1000,12 +1048,15 @@ const SimpleWorkEntryRow = memo(function SimpleWorkEntryRow(props: {
10001048
const hasChangedFiles = (workEntry.changedFiles?.length ?? 0) > 0;
10011049
const previewIsChangedFiles = hasChangedFiles && !workEntry.command && !workEntry.detail;
10021050

1051+
// Review comment tools get severity-based icon coloring
1052+
const isReview = isReviewCommentTool(workEntry.toolName);
1053+
const severity = isReview ? extractReviewSeverity(workEntry) : null;
1054+
const iconClassName = isReview ? reviewSeverityClass(severity) : iconConfig.className;
1055+
10031056
return (
10041057
<div className="rounded-lg px-1 py-1">
10051058
<div className="flex items-center gap-2 transition-[opacity,translate] duration-200">
1006-
<span
1007-
className={cn("flex size-5 shrink-0 items-center justify-center", iconConfig.className)}
1008-
>
1059+
<span className={cn("flex size-5 shrink-0 items-center justify-center", iconClassName)}>
10091060
<EntryIcon className="size-3" />
10101061
</span>
10111062
<div className="min-w-0 flex-1 overflow-hidden">

0 commit comments

Comments
 (0)