Unified · Split
| @@ -2886,27 +2886,47 @@ function workEntryRawCommand( · 2885 unmodified lines | |||
| 2886 | function buildToolCallExpandedBody( | 2886 | function buildToolCallExpandedBody( |
| 2887 | workEntry: TimelineWorkEntry, | 2887 | workEntry: TimelineWorkEntry, |
| 2888 | workspaceRoot: string | undefined, | 2888 | workspaceRoot: string | undefined, |
| 2889 | visibleLabel: string, | ||
| 2890 | viewedImagePath: string | null, | ||
| 2889 | ): string | null { | 2891 | ): string | null { |
| 2890 | const blocks: string[] = []; | 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 | if (workEntry.itemType === "mcp_tool_call" && workEntry.toolData !== undefined) { | 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 | const raw = workEntryRawCommand(workEntry); | 2904 | const raw = workEntryRawCommand(workEntry); |
| 2895 | if (raw?.trim()) { | 2905 | if (command === visibleLabel.trim()) { |
| 2896 | blocks.push(raw.trim()); | 2906 | seen.add(command); |
| 2897 | } else if (workEntry.command?.trim()) { | 2907 | } else { |
| 2898 | blocks.push(workEntry.command.trim()); | 2908 | addBlock(raw ?? command); |
| 2899 | } | 2909 | } |
| 2900 | if (workEntry.detail?.trim()) { | 2910 | const detail = workEntry.detail?.trim(); |
| 2901 | blocks.push(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 | if (changedFiles.length > 0) { | 2928 | if (changedFiles.length > 0) { |
| 2905 | blocks.push( | 2929 | addBlock([...new Set(changedFiles)].join("\n")); |
| 2906 | changedFiles | ||
| 2907 | .map((filePath) => formatWorkspaceRelativePath(filePath, workspaceRoot)) | ||
| 2908 | .join("\n"), | ||
| 2909 | ); | ||
| 2910 | } | 2930 | } |
| 2911 | return blocks.length > 0 ? blocks.join("\n\n") : null; | 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 | ? "circle-alert" | 3112 | ? "circle-alert" |
| 3093 | : workEntryIconName(workEntry); | 3113 | : workEntryIconName(workEntry); |
| 3094 | const previewText = displayLabel ?? workEntryDisplayLabel(workEntry, workspaceRoot); | 3114 | const previewText = displayLabel ?? workEntryDisplayLabel(workEntry, workspaceRoot); |
| 3095 | const displayText = | ||
| 3096 | !toolPresentation && expanded && workEntry.command?.trim() ? "Command" : previewText; | ||
| 3097 | const viewedImagePath = workEntryViewedImagePath(workEntry); | 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 | const viewedImage = | 3116 | const viewedImage = |
| 3109 | viewedImagePath && threadRef | 3117 | viewedImagePath && threadRef |
| 3110 | ? resolveViewedImageAsset(viewedImagePath, { | 3118 | ? resolveViewedImageAsset(viewedImagePath, { |
| @@ -3112,6 +3120,24 @@ const PlainWorkEntryRow = memo(function PlainWorkEntryRow(props: { · 1 unmodified line | |||
| 3112 | workspaceRoot, | 3120 | workspaceRoot, |
| 3113 | }) | 3121 | }) |
| 3114 | : null; | 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 | const showDestructiveRowStyle = | 3141 | const showDestructiveRowStyle = |
| 3116 | showFailedIndicator && | 3142 | showFailedIndicator && |
| 3117 | (workEntrySignalsSevereFailure(workEntry) || !workLogEntryIsToolLike(workEntry)); | 3143 | (workEntrySignalsSevereFailure(workEntry) || !workLogEntryIsToolLike(workEntry)); |
| @@ -3183,7 +3209,19 @@ const PlainWorkEntryRow = memo(function PlainWorkEntryRow(props: { · 65 unmodified lines | |||
| 3183 | <div className="flex min-w-0 flex-1 items-center gap-1.5"> | 3209 | <div className="flex min-w-0 flex-1 items-center gap-1.5"> |
| 3184 | <div className="min-w-0 flex-1 overflow-hidden"> | 3210 | <div className="min-w-0 flex-1 overflow-hidden"> |
| 3185 | <p className="flex min-w-0 w-full items-baseline gap-1.5 text-sm leading-relaxed"> | 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 | </p> | 3225 | </p> |
| 3188 | </div> | 3226 | </div> |
| 3189 | {showFailedIndicator && hasSpecialToolIcon ? ( | 3227 | {showFailedIndicator && hasSpecialToolIcon ? ( |
| @@ -3224,7 +3262,7 @@ const PlainWorkEntryRow = memo(function PlainWorkEntryRow(props: { · 34 unmodified lines | |||
| 3224 | ) : null} | 3262 | ) : null} |
| 3225 | {expanded && canExpand && expandedBody ? ( | 3263 | {expanded && canExpand && expandedBody ? ( |
| 3226 | <div | 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 | onClick={stopRowToggle} | 3266 | onClick={stopRowToggle} |
| 3229 | onPointerDown={stopRowToggle} | 3267 | onPointerDown={stopRowToggle} |
| 3230 | > | 3268 | > |