Unified · Split
| @@ -2886,27 +2886,47 @@ function workEntryRawCommand( · 2885 unmodified lines | ||
| 2886 | 2886 | function buildToolCallExpandedBody( |
| 2887 | 2887 | workEntry: TimelineWorkEntry, |
| 2888 | 2888 | workspaceRoot: string | undefined, |
| 2889 | + visibleLabel: string, | |
| 2890 | + viewedImagePath: string | null, | |
| 2889 | 2891 | ): string | null { |
| 2890 | 2892 | const blocks: string[] = []; |
| 2893 | + const seen = new Set<string>(); | |
| 2894 | + const addBlock = (value: string | null | undefined) => { | |
| 2895 | + const text = value?.trim(); | |
| 2896 | + if (!text || seen.has(text)) return; | |
| 2897 | + seen.add(text); | |
| 2898 | + blocks.push(text); | |
| 2899 | + }; | |
| 2891 | 2900 | if (workEntry.itemType === "mcp_tool_call" && workEntry.toolData !== undefined) { |
| 2892 | − blocks.push(`MCP call\n${JSON.stringify(workEntry.toolData, null, 2)}`); | |
| 2901 | + addBlock(`MCP call\n${JSON.stringify(workEntry.toolData, null, 2)}`); | |
| 2893 | 2902 | } |
| 2903 | + const command = workEntry.command?.trim(); | |
| 2894 | 2904 | const raw = workEntryRawCommand(workEntry); |
| 2895 | − if (raw?.trim()) { | |
| 2896 | − blocks.push(raw.trim()); | |
| 2897 | − } else if (workEntry.command?.trim()) { | |
| 2898 | − blocks.push(workEntry.command.trim()); | |
| 2905 | + if (command === visibleLabel.trim()) { | |
| 2906 | + seen.add(command); | |
| 2907 | + } else { | |
| 2908 | + addBlock(raw ?? command); | |
| 2899 | 2909 | } |
| 2900 | − if (workEntry.detail?.trim()) { | |
| 2901 | − blocks.push(workEntry.detail.trim()); | |
| 2910 | + const detail = workEntry.detail?.trim(); | |
| 2911 | + if (detail !== viewedImagePath?.trim()) { | |
| 2912 | + addBlock(detail); | |
| 2902 | 2913 | } |
| 2903 | − const changedFiles = workEntry.changedFiles ?? []; | |
| 2914 | + const viewedImagePaths = new Set( | |
| 2915 | + viewedImagePath | |
| 2916 | + ? [viewedImagePath.trim(), formatWorkspaceRelativePath(viewedImagePath, workspaceRoot)] | |
| 2917 | + : [], | |
| 2918 | + ); | |
| 2919 | + const changedFiles = (workEntry.changedFiles ?? []).flatMap((filePath) => { | |
| 2920 | + const formattedPath = formatWorkspaceRelativePath(filePath, workspaceRoot); | |
| 2921 | + return viewedImagePaths.has(filePath) || | |
| 2922 | + viewedImagePaths.has(formattedPath) || | |
| 2923 | + filePath.trim() === detail || | |
| 2924 | + formattedPath === detail | |
| 2925 | + ? [] | |
| 2926 | + : [formattedPath]; | |
| 2927 | + }); | |
| 2904 | 2928 | if (changedFiles.length > 0) { |
| 2905 | − blocks.push( | |
| 2906 | − changedFiles | |
| 2907 | − .map((filePath) => formatWorkspaceRelativePath(filePath, workspaceRoot)) | |
| 2908 | − .join("\n"), | |
| 2909 | − ); | |
| 2929 | + addBlock([...new Set(changedFiles)].join("\n")); | |
| 2910 | 2930 | } |
| 2911 | 2931 | return blocks.length > 0 ? blocks.join("\n\n") : null; |
| 2912 | 2932 | } |
| @@ -3092,19 +3112,7 @@ const PlainWorkEntryRow = memo(function PlainWorkEntryRow(props: { · 179 unmodified lines | ||
| 3092 | 3112 | ? "circle-alert" |
| 3093 | 3113 | : workEntryIconName(workEntry); |
| 3094 | 3114 | const previewText = displayLabel ?? workEntryDisplayLabel(workEntry, workspaceRoot); |
| 3095 | − const displayText = | |
| 3096 | − !toolPresentation && expanded && workEntry.command?.trim() ? "Command" : previewText; | |
| 3097 | 3115 | const viewedImagePath = workEntryViewedImagePath(workEntry); |
| 3098 | − const canExpand = | |
| 3099 | − (workEntry.itemType === "mcp_tool_call" && workEntry.toolData !== undefined) || | |
| 3100 | − Boolean( | |
| 3101 | − workEntryRawCommand(workEntry) || | |
| 3102 | − workEntry.command?.trim() || | |
| 3103 | − workEntry.detail?.trim() || | |
| 3104 | − workEntry.changedFiles?.length || | |
| 3105 | − viewedImagePath, | |
| 3106 | − ); | |
| 3107 | − const expandedBody = expanded ? buildToolCallExpandedBody(workEntry, workspaceRoot) : null; | |
| 3108 | 3116 | const viewedImage = |
| 3109 | 3117 | viewedImagePath && threadRef |
| 3110 | 3118 | ? resolveViewedImageAsset(viewedImagePath, { |
| @@ -3112,6 +3120,24 @@ const PlainWorkEntryRow = memo(function PlainWorkEntryRow(props: { · 1 unmodified line | ||
| 3112 | 3120 | workspaceRoot, |
| 3113 | 3121 | }) |
| 3114 | 3122 | : null; |
| 3123 | + const commandMatchesVisibleLabel = workEntry.command?.trim() === previewText.trim(); | |
| 3124 | + const canExpand = | |
| 3125 | + (workEntry.itemType === "mcp_tool_call" && workEntry.toolData !== undefined) || | |
| 3126 | + Boolean( | |
| 3127 | + (!commandMatchesVisibleLabel && | |
| 3128 | + (workEntryRawCommand(workEntry) || workEntry.command?.trim())) || | |
| 3129 | + workEntry.detail?.trim() || | |
| 3130 | + workEntry.changedFiles?.length || | |
| 3131 | + viewedImage, | |
| 3132 | + ); | |
| 3133 | + const expandedBody = expanded | |
| 3134 | + ? buildToolCallExpandedBody( | |
| 3135 | + workEntry, | |
| 3136 | + workspaceRoot, | |
| 3137 | + previewText, | |
| 3138 | + viewedImage ? viewedImagePath : null, | |
| 3139 | + ) | |
| 3140 | + : null; | |
| 3115 | 3141 | const showDestructiveRowStyle = |
| 3116 | 3142 | showFailedIndicator && |
| 3117 | 3143 | (workEntrySignalsSevereFailure(workEntry) || !workLogEntryIsToolLike(workEntry)); |
| @@ -3183,7 +3209,19 @@ const PlainWorkEntryRow = memo(function PlainWorkEntryRow(props: { · 65 unmodified lines | ||
| 3183 | 3209 | <div className="flex min-w-0 flex-1 items-center gap-1.5"> |
| 3184 | 3210 | <div className="min-w-0 flex-1 overflow-hidden"> |
| 3185 | 3211 | <p className="flex min-w-0 w-full items-baseline gap-1.5 text-sm leading-relaxed"> |
| 3186 | − <span className={cn("min-w-0 flex-1 truncate", headingClass)}>{displayText}</span> | |
| 3212 | + <span | |
| 3213 | + className={cn( | |
| 3214 | + "min-w-0 flex-1", | |
| 3215 | + expanded || (commandMatchesVisibleLabel && !canExpand) | |
| 3216 | + ? "whitespace-pre-wrap break-words select-text" | |
| 3217 | + : "truncate", | |
| 3218 | + headingClass, | |
| 3219 | + )} | |
| 3220 | + onClick={expanded ? stopRowToggle : undefined} | |
| 3221 | + onPointerDown={expanded ? stopRowToggle : undefined} | |
| 3222 | + > | |
| 3223 | + {previewText} | |
| 3224 | + </span> | |
| 3187 | 3225 | </p> |
| 3188 | 3226 | </div> |
| 3189 | 3227 | {showFailedIndicator && hasSpecialToolIcon ? ( |
| @@ -3224,7 +3262,7 @@ const PlainWorkEntryRow = memo(function PlainWorkEntryRow(props: { · 34 unmodified lines | ||
| 3224 | 3262 | ) : null} |
| 3225 | 3263 | {expanded && canExpand && expandedBody ? ( |
| 3226 | 3264 | <div |
| 3227 | − className="mt-1 ms-7 cursor-default border-s border-border/45 ps-3 pt-0.5" | |
| 3265 | + className="mt-1 ms-7 cursor-default rounded-md bg-muted/40 px-3 py-2" | |
| 3228 | 3266 | onClick={stopRowToggle} |
| 3229 | 3267 | onPointerDown={stopRowToggle} |
| 3230 | 3268 | > |